aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@cs.helsinki.fi>1993-10-25 22:33:27 +0000
committerNicolas Pitre <nico@cam.org>2007-08-19 14:19:20 -0400
commit04cb41e1214fd968f1f50d1ecbf30839c41e3efa (patch)
tree1b716d518cf163f369fce42ff70e425401d6bf4c
parent3a846f010d35ec39c41d7e455e4b8b775a8c0245 (diff)
downloadarchive-04cb41e1214fd968f1f50d1ecbf30839c41e3efa.tar.gz
ALPHA-pl13k
[ Committer's note: This is the only 0.99.13+ release that could be found. It is extracted from a private copy apparently from "aeb" and possibly non pristine. Its date must be approximate as well. ]
-rw-r--r--Makefile46
-rw-r--r--README4
-rw-r--r--boot/setup.S4
-rw-r--r--config.in61
-rw-r--r--drivers/FPU-emu/Makefile (renamed from kernel/FPU-emu/Makefile)8
-rw-r--r--drivers/FPU-emu/README (renamed from kernel/FPU-emu/README)0
-rw-r--r--drivers/FPU-emu/control_w.h (renamed from kernel/FPU-emu/control_w.h)0
-rw-r--r--drivers/FPU-emu/div_small.S (renamed from kernel/FPU-emu/div_small.S)0
-rw-r--r--drivers/FPU-emu/errors.c (renamed from kernel/FPU-emu/errors.c)0
-rw-r--r--drivers/FPU-emu/exception.h (renamed from kernel/FPU-emu/exception.h)0
-rw-r--r--drivers/FPU-emu/fpu_arith.c (renamed from kernel/FPU-emu/fpu_arith.c)0
-rw-r--r--drivers/FPU-emu/fpu_asm.h (renamed from kernel/FPU-emu/fpu_asm.h)0
-rw-r--r--drivers/FPU-emu/fpu_aux.c (renamed from kernel/FPU-emu/fpu_aux.c)0
-rw-r--r--drivers/FPU-emu/fpu_emu.h (renamed from kernel/FPU-emu/fpu_emu.h)0
-rw-r--r--drivers/FPU-emu/fpu_entry.c (renamed from kernel/FPU-emu/fpu_entry.c)19
-rw-r--r--drivers/FPU-emu/fpu_etc.c (renamed from kernel/FPU-emu/fpu_etc.c)0
-rw-r--r--drivers/FPU-emu/fpu_proto.h (renamed from kernel/FPU-emu/fpu_proto.h)0
-rw-r--r--drivers/FPU-emu/fpu_system.h (renamed from kernel/FPU-emu/fpu_system.h)0
-rw-r--r--drivers/FPU-emu/fpu_trig.c (renamed from kernel/FPU-emu/fpu_trig.c)0
-rw-r--r--drivers/FPU-emu/get_address.c (renamed from kernel/FPU-emu/get_address.c)0
-rw-r--r--drivers/FPU-emu/load_store.c (renamed from kernel/FPU-emu/load_store.c)0
-rw-r--r--drivers/FPU-emu/poly_2xm1.c (renamed from kernel/FPU-emu/poly_2xm1.c)0
-rw-r--r--drivers/FPU-emu/poly_atan.c (renamed from kernel/FPU-emu/poly_atan.c)0
-rw-r--r--drivers/FPU-emu/poly_div.S (renamed from kernel/FPU-emu/poly_div.S)0
-rw-r--r--drivers/FPU-emu/poly_l2.c (renamed from kernel/FPU-emu/poly_l2.c)0
-rw-r--r--drivers/FPU-emu/poly_mul64.S (renamed from kernel/FPU-emu/poly_mul64.S)2
-rw-r--r--drivers/FPU-emu/poly_sin.c (renamed from kernel/FPU-emu/poly_sin.c)0
-rw-r--r--drivers/FPU-emu/poly_tan.c (renamed from kernel/FPU-emu/poly_tan.c)0
-rw-r--r--drivers/FPU-emu/polynomial.S (renamed from kernel/FPU-emu/polynomial.S)36
-rw-r--r--drivers/FPU-emu/reg_add_sub.c (renamed from kernel/FPU-emu/reg_add_sub.c)0
-rw-r--r--drivers/FPU-emu/reg_compare.c (renamed from kernel/FPU-emu/reg_compare.c)0
-rw-r--r--drivers/FPU-emu/reg_constant.c (renamed from kernel/FPU-emu/reg_constant.c)0
-rw-r--r--drivers/FPU-emu/reg_constant.h (renamed from kernel/FPU-emu/reg_constant.h)0
-rw-r--r--drivers/FPU-emu/reg_div.S (renamed from kernel/FPU-emu/reg_div.S)66
-rw-r--r--drivers/FPU-emu/reg_ld_str.c (renamed from kernel/FPU-emu/reg_ld_str.c)0
-rw-r--r--drivers/FPU-emu/reg_mul.c (renamed from kernel/FPU-emu/reg_mul.c)0
-rw-r--r--drivers/FPU-emu/reg_norm.S (renamed from kernel/FPU-emu/reg_norm.S)30
-rw-r--r--drivers/FPU-emu/reg_round.S (renamed from kernel/FPU-emu/reg_round.S)200
-rw-r--r--drivers/FPU-emu/reg_u_add.S (renamed from kernel/FPU-emu/reg_u_add.S)20
-rw-r--r--drivers/FPU-emu/reg_u_div.S (renamed from kernel/FPU-emu/reg_u_div.S)44
-rw-r--r--drivers/FPU-emu/reg_u_mul.S (renamed from kernel/FPU-emu/reg_u_mul.S)8
-rw-r--r--drivers/FPU-emu/reg_u_sub.S (renamed from kernel/FPU-emu/reg_u_sub.S)38
-rw-r--r--drivers/FPU-emu/status_w.h (renamed from kernel/FPU-emu/status_w.h)0
-rw-r--r--drivers/FPU-emu/version.h (renamed from kernel/FPU-emu/version.h)0
-rw-r--r--drivers/FPU-emu/wm_shrx.S (renamed from kernel/FPU-emu/wm_shrx.S)32
-rw-r--r--drivers/FPU-emu/wm_sqrt.S (renamed from kernel/FPU-emu/wm_sqrt.S)182
-rw-r--r--drivers/Makefile (renamed from kernel/chr_drv/Makefile)35
-rw-r--r--drivers/block/Makefile68
-rw-r--r--drivers/block/blk.h (renamed from kernel/blk_drv/blk.h)0
-rw-r--r--drivers/block/cdu31a.c (renamed from kernel/blk_drv/cdu31a.c)3
-rw-r--r--drivers/block/floppy.c (renamed from kernel/blk_drv/floppy.c)0
-rw-r--r--drivers/block/genhd.c (renamed from kernel/blk_drv/genhd.c)0
-rw-r--r--drivers/block/hd.c (renamed from kernel/blk_drv/hd.c)4
-rw-r--r--drivers/block/ll_rw_blk.c (renamed from kernel/blk_drv/ll_rw_blk.c)7
-rw-r--r--drivers/block/mcd.c (renamed from kernel/blk_drv/mcd.c)4
-rw-r--r--drivers/block/ramdisk.c (renamed from kernel/blk_drv/ramdisk.c)3
-rw-r--r--drivers/block/xd.c (renamed from kernel/blk_drv/xd.c)128
-rw-r--r--drivers/char/Makefile94
-rw-r--r--drivers/char/atixlmouse.c (renamed from kernel/chr_drv/atixlmouse.c)0
-rw-r--r--drivers/char/busmouse.c (renamed from kernel/chr_drv/busmouse.c)0
-rw-r--r--drivers/char/console.c (renamed from kernel/chr_drv/console.c)10
-rw-r--r--drivers/char/defkeymap.c (renamed from kernel/chr_drv/defkeymap.c)184
-rw-r--r--drivers/char/defkeymap.map (renamed from kernel/chr_drv/defkeymap.map)22
-rw-r--r--drivers/char/keyboard.c (renamed from kernel/chr_drv/keyboard.c)445
-rw-r--r--drivers/char/lp.c (renamed from kernel/chr_drv/lp.c)1
-rw-r--r--drivers/char/mem.c (renamed from kernel/chr_drv/mem.c)103
-rw-r--r--drivers/char/mouse.c (renamed from kernel/chr_drv/mouse.c)0
-rw-r--r--drivers/char/msbusmouse.c (renamed from kernel/chr_drv/msbusmouse.c)0
-rw-r--r--drivers/char/psaux.c (renamed from kernel/chr_drv/psaux.c)0
-rw-r--r--drivers/char/pty.c (renamed from kernel/chr_drv/pty.c)0
-rw-r--r--drivers/char/serial.c (renamed from kernel/chr_drv/serial.c)7
-rw-r--r--drivers/char/tpqic02.c (renamed from kernel/chr_drv/tpqic02.c)0
-rw-r--r--drivers/char/tty_io.c (renamed from kernel/chr_drv/tty_io.c)16
-rw-r--r--drivers/char/tty_ioctl.c (renamed from kernel/chr_drv/tty_ioctl.c)55
-rw-r--r--drivers/char/vt.c (renamed from kernel/chr_drv/vt.c)36
-rw-r--r--drivers/char/vt_kern.h (renamed from kernel/chr_drv/vt_kern.h)0
-rw-r--r--drivers/net/3c501.c564
-rw-r--r--drivers/net/3c503.c (renamed from net/inet/el.c)212
-rw-r--r--drivers/net/3c503.h (renamed from net/inet/elreg.h)7
-rw-r--r--drivers/net/3c509.c (renamed from net/inet/3c509.c)93
-rw-r--r--drivers/net/8390.c757
-rw-r--r--drivers/net/8390.h (renamed from net/inet/8390.h)0
-rw-r--r--drivers/net/CONFIG (renamed from net/inet/CONFIG)6
-rw-r--r--drivers/net/LICENSE.SRC (renamed from net/inet/LICENSE.SRC)0
-rw-r--r--drivers/net/Makefile140
-rw-r--r--drivers/net/README.8390 (renamed from net/inet/README.8390)0
-rw-r--r--drivers/net/README.DLINK177
-rw-r--r--drivers/net/README1.PLIP (renamed from net/inet/README1.PLIP)0
-rw-r--r--drivers/net/README2.PLIP (renamed from net/inet/README2.PLIP)0
-rw-r--r--drivers/net/Space.c (renamed from net/inet/Space.c)4
-rw-r--r--drivers/net/auto_irq.c (renamed from net/inet/auto_irq.c)0
-rw-r--r--drivers/net/d_link.c (renamed from net/inet/d_link.c)711
-rw-r--r--drivers/net/eexpress.c1023
-rw-r--r--drivers/net/el2.c (renamed from net/inet/el2.c)0
-rw-r--r--drivers/net/el2reg.h (renamed from net/inet/el2reg.h)0
-rw-r--r--drivers/net/hp.c (renamed from net/inet/hp.c)13
-rw-r--r--drivers/net/iow.h (renamed from net/inet/iow.h)0
-rw-r--r--drivers/net/lance.c (renamed from net/inet/lance.c)274
-rw-r--r--drivers/net/ne.c (renamed from net/inet/ne.c)0
-rw-r--r--drivers/net/plip.c (renamed from net/inet/plip.c)32
-rw-r--r--drivers/net/skeleton.c511
-rw-r--r--drivers/net/slhc.c (renamed from net/inet/slhc.c)2
-rw-r--r--drivers/net/slhc.h (renamed from net/inet/slhc.h)0
-rw-r--r--drivers/net/slip.c (renamed from net/inet/slip.c)95
-rw-r--r--drivers/net/slip.h (renamed from net/inet/slip.h)5
-rw-r--r--drivers/net/smc-ultra.c260
-rw-r--r--drivers/net/wd.c (renamed from net/inet/wd.c)83
-rw-r--r--drivers/scsi/Makefile (renamed from kernel/blk_drv/scsi/Makefile)82
-rw-r--r--drivers/scsi/NCR5380.c2145
-rw-r--r--drivers/scsi/NCR5380.h257
-rw-r--r--drivers/scsi/aha152x.c2399
-rw-r--r--drivers/scsi/aha152x.h334
-rw-r--r--drivers/scsi/aha1542.c (renamed from kernel/blk_drv/scsi/aha1542.c)442
-rw-r--r--drivers/scsi/aha1542.h (renamed from kernel/blk_drv/scsi/aha1542.h)8
-rw-r--r--drivers/scsi/aha1740.c (renamed from kernel/blk_drv/scsi/aha1740.c)2
-rw-r--r--drivers/scsi/aha1740.h (renamed from kernel/blk_drv/scsi/aha1740.h)0
-rw-r--r--drivers/scsi/constants.c (renamed from kernel/blk_drv/scsi/constants.c)105
-rw-r--r--drivers/scsi/constants.h (renamed from kernel/blk_drv/scsi/constants.h)1
-rw-r--r--drivers/scsi/fdomain.c (renamed from kernel/blk_drv/scsi/fdomain.c)111
-rw-r--r--drivers/scsi/fdomain.h (renamed from kernel/blk_drv/scsi/fdomain.h)2
-rw-r--r--drivers/scsi/g_NCR5380.c179
-rw-r--r--drivers/scsi/g_NCR5380.h84
-rw-r--r--drivers/scsi/hosts.c304
-rw-r--r--drivers/scsi/hosts.h (renamed from kernel/blk_drv/scsi/hosts.h)93
-rw-r--r--drivers/scsi/pas16.c483
-rw-r--r--drivers/scsi/pas16.h191
-rw-r--r--drivers/scsi/scsi.c (renamed from kernel/blk_drv/scsi/scsi.c)370
-rw-r--r--drivers/scsi/scsi.h (renamed from kernel/blk_drv/scsi/scsi.h)28
-rw-r--r--drivers/scsi/scsi_debug.c (renamed from kernel/blk_drv/scsi/scsi_debug.c)2
-rw-r--r--drivers/scsi/scsi_debug.h (renamed from kernel/blk_drv/scsi/scsi_debug.h)0
-rw-r--r--drivers/scsi/scsi_ioctl.c (renamed from kernel/blk_drv/scsi/scsi_ioctl.c)41
-rw-r--r--drivers/scsi/scsi_ioctl.h (renamed from kernel/blk_drv/scsi/scsi_ioctl.h)0
-rw-r--r--drivers/scsi/sd.c (renamed from kernel/blk_drv/scsi/sd.c)32
-rw-r--r--drivers/scsi/sd.h (renamed from kernel/blk_drv/scsi/sd.h)0
-rw-r--r--drivers/scsi/sd_ioctl.c (renamed from kernel/blk_drv/scsi/sd_ioctl.c)11
-rw-r--r--drivers/scsi/seagate.c (renamed from kernel/blk_drv/scsi/seagate.c)94
-rw-r--r--drivers/scsi/seagate.h (renamed from kernel/blk_drv/scsi/seagate.h)0
-rw-r--r--drivers/scsi/sg.c337
-rw-r--r--drivers/scsi/sg.h33
-rw-r--r--drivers/scsi/sr.c (renamed from kernel/blk_drv/scsi/sr.c)33
-rw-r--r--drivers/scsi/sr.h (renamed from kernel/blk_drv/scsi/sr.h)0
-rw-r--r--drivers/scsi/sr_ioctl.c (renamed from kernel/blk_drv/scsi/sr_ioctl.c)54
-rw-r--r--drivers/scsi/st.c (renamed from kernel/blk_drv/scsi/st.c)2
-rw-r--r--drivers/scsi/st.h (renamed from kernel/blk_drv/scsi/st.h)0
-rw-r--r--drivers/scsi/t128.c391
-rw-r--r--drivers/scsi/t128.h167
-rw-r--r--drivers/scsi/ultrastor.c1120
-rw-r--r--drivers/scsi/ultrastor.h (renamed from kernel/blk_drv/scsi/ultrastor.h)54
-rw-r--r--drivers/scsi/wd7000.c (renamed from kernel/blk_drv/scsi/wd7000.c)4
-rw-r--r--drivers/scsi/wd7000.h (renamed from kernel/blk_drv/scsi/wd7000.h)0
-rw-r--r--drivers/sound/Makefile (renamed from kernel/chr_drv/sound/Makefile)0
-rw-r--r--drivers/sound/sound_stub.c (renamed from kernel/chr_drv/sound/sound_stub.c)0
-rw-r--r--fs/binfmt_elf.c106
-rw-r--r--fs/block_dev.c2
-rw-r--r--fs/buffer.c27
-rw-r--r--fs/exec.c54
-rw-r--r--fs/ext/file.c2
-rw-r--r--fs/ext2/dir.c8
-rw-r--r--fs/ext2/file.c5
-rw-r--r--fs/ext2/ialloc.c3
-rw-r--r--fs/ext2/namei.c1
-rw-r--r--fs/fifo.c8
-rw-r--r--fs/isofs/dir.c63
-rw-r--r--fs/isofs/file.c2
-rw-r--r--fs/isofs/inode.c168
-rw-r--r--fs/isofs/namei.c122
-rw-r--r--fs/isofs/rock.c31
-rw-r--r--fs/isofs/symlink.c1
-rw-r--r--fs/isofs/util.c6
-rw-r--r--fs/minix/file.c2
-rw-r--r--fs/minix/namei.c5
-rw-r--r--fs/namei.c16
-rw-r--r--fs/nfs/dir.c1
-rw-r--r--fs/nfs/file.c9
-rw-r--r--fs/nfs/mmap.c9
-rw-r--r--fs/nfs/proc.c1
-rw-r--r--fs/nfs/sock.c32
-rw-r--r--fs/nfs/symlink.c1
-rw-r--r--fs/pipe.c71
-rw-r--r--fs/proc/array.c121
-rw-r--r--fs/proc/base.c3
-rw-r--r--fs/proc/inode.c6
-rw-r--r--fs/proc/root.c1
-rw-r--r--fs/super.c2
-rw-r--r--fs/xiafs/file.c2
-rw-r--r--include/asm/irq.h4
-rw-r--r--include/linux/debugreg.h61
-rw-r--r--include/linux/fs.h17
-rw-r--r--include/linux/if.h11
-rw-r--r--include/linux/if_ether.h1
-rw-r--r--include/linux/kd.h1
-rw-r--r--include/linux/kernel.h35
-rw-r--r--include/linux/keyboard.h53
-rw-r--r--include/linux/malloc.h30
-rw-r--r--include/linux/mc146818rtc.h104
-rw-r--r--include/linux/mm.h15
-rw-r--r--include/linux/nfs.h1
-rw-r--r--include/linux/resource.h2
-rw-r--r--include/linux/sched.h26
-rw-r--r--include/linux/sockios.h2
-rw-r--r--include/linux/sys.h29
-rw-r--r--include/linux/timex.h187
-rw-r--r--include/linux/tty.h3
-rw-r--r--include/linux/unistd.h2
-rw-r--r--include/linux/user.h4
-rw-r--r--include/linux/xd.h24
-rw-r--r--init/main.c89
-rw-r--r--ipc/Makefile11
-rw-r--r--ipc/msg.c4
-rw-r--r--ipc/sem.c1
-rw-r--r--ipc/shm.c3
-rw-r--r--kernel/Makefile11
-rw-r--r--kernel/blk_drv/Makefile52
-rw-r--r--kernel/blk_drv/scsi/hosts.c192
-rw-r--r--kernel/blk_drv/scsi/ultrastor.c561
-rw-r--r--kernel/exit.c1
-rw-r--r--kernel/fork.c37
-rw-r--r--kernel/info.c2
-rw-r--r--kernel/panic.c6
-rw-r--r--kernel/printk.c85
-rw-r--r--kernel/ptrace.c73
-rw-r--r--kernel/sched.c215
-rw-r--r--kernel/sys.c161
-rw-r--r--kernel/sys_call.S20
-rw-r--r--kernel/time.c428
-rw-r--r--kernel/traps.c10
-rw-r--r--lib/malloc.c1
-rw-r--r--mm/Makefile2
-rw-r--r--mm/memory.c83
-rw-r--r--mm/mmap.c340
-rw-r--r--mm/swap.c136
-rw-r--r--mm/vmalloc.c164
-rw-r--r--net/Makefile7
-rw-r--r--net/Space.c2
-rw-r--r--net/drv/Makefile47
-rw-r--r--net/drv/README9
-rw-r--r--net/drv/slip/Makefile39
-rw-r--r--net/drv/slip/slip.c661
-rw-r--r--net/drv/slip/slip.h64
-rw-r--r--net/drv/we8003/Makefile42
-rw-r--r--net/drv/we8003/dp8390.h202
-rw-r--r--net/drv/we8003/handler.c681
-rw-r--r--net/drv/we8003/main.c179
-rw-r--r--net/drv/we8003/we8003.h33
-rw-r--r--net/inet/8390.c707
-rw-r--r--net/inet/INTRO.839062
-rw-r--r--net/inet/LICENSE.839015
-rw-r--r--net/inet/Makefile51
-rw-r--r--net/inet/README28
-rw-r--r--net/inet/README.DLINK258
-rw-r--r--net/inet/README.DRIVERS424
-rw-r--r--net/inet/README.TODO32
-rw-r--r--net/inet/arp.c134
-rw-r--r--net/inet/datagram.c141
-rw-r--r--net/inet/dev.c223
-rw-r--r--net/inet/dev.h6
-rw-r--r--net/inet/eth.c45
-rw-r--r--net/inet/icmp.c71
-rw-r--r--net/inet/inet.h2
-rw-r--r--net/inet/ip.c113
-rw-r--r--net/inet/packet.c117
-rw-r--r--net/inet/proc.c27
-rw-r--r--net/inet/protocol.c20
-rw-r--r--net/inet/protocol.h10
-rw-r--r--net/inet/raw.c141
-rw-r--r--net/inet/route.c38
-rw-r--r--net/inet/skbuff.c435
-rw-r--r--net/inet/skbuff.h34
-rw-r--r--net/inet/sock.c540
-rw-r--r--net/inet/sock.h23
-rw-r--r--net/inet/tcp.c323
-rw-r--r--net/inet/tcp.h10
-rw-r--r--net/inet/timer.c27
-rw-r--r--net/inet/udp.c230
-rw-r--r--net/inet/udp.h7
-rw-r--r--net/inet/utils.c11
-rw-r--r--net/socket.c3
-rw-r--r--net/unix/sock.c11
-rw-r--r--zBoot/head.S4
279 files changed, 19327 insertions, 8142 deletions
diff --git a/Makefile b/Makefile
index 6bdc597..fdf817c 100644
--- a/Makefile
+++ b/Makefile
@@ -1,3 +1,6 @@
+VERSION = 0.99
+PATCHLEVEL = 13
+ALPHA = k
all: Version zImage
@@ -41,7 +44,8 @@ ROOT_DEV = CURRENT
# The number is the same as you would ordinarily press at bootup.
#
-SVGA_MODE= -DSVGA_MODE=3
+# SVGA_MODE= -DSVGA_MODE=3
+SVGA_MODE= -DSVGA_MODE=NORMAL_VGA
# Special options.
#OPTS = -pro
@@ -50,7 +54,7 @@ SVGA_MODE= -DSVGA_MODE=3
# standard CFLAGS
#
-CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer # -x c++
+CFLAGS = -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -pipe # -x c++
ifdef CONFIG_M486
CFLAGS := $(CFLAGS) -m486
@@ -77,15 +81,27 @@ STRIP =strip
ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o ipc/ipc.o
FILESYSTEMS =fs/filesystems.a
-DRIVERS =kernel/blk_drv/blk_drv.a kernel/chr_drv/chr_drv.a \
- kernel/blk_drv/scsi/scsi.a kernel/chr_drv/sound/sound.a \
+DRIVERS =drivers/block/block.a \
+ drivers/char/char.a \
+ drivers/net/net.a \
ibcs/ibcs.o
-MATH =kernel/FPU-emu/math.a
LIBS =lib/lib.a
-SUBDIRS =kernel mm fs net ipc ibcs lib
+SUBDIRS =kernel drivers mm fs net ipc ibcs lib
KERNELHDRS =/usr/src/linux/include
+ifdef CONFIG_SCSI
+DRIVERS := $(DRIVERS) drivers/scsi/scsi.a
+endif
+
+ifdef CONFIG_SOUND
+DRIVERS := $(DRIVERS) drivers/sound/sound.a
+endif
+
+ifdef CONFIG_MATH_EMULATION
+DRIVERS := $(DRIVERS) drivers/FPU-emu/math.a
+endif
+
.c.s:
$(CC) $(CFLAGS) -S -o $*.s $<
.s.o:
@@ -102,7 +118,7 @@ config:
$(MAKE) soundconf
soundconf:
- cd kernel/chr_drv/sound;$(MAKE) config
+ cd drivers/sound;$(MAKE) config
linuxsubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
@@ -111,7 +127,7 @@ tools/./version.h: tools/version.h
tools/version.h: $(CONFIGURE) Makefile
@./makever.sh
- @echo \#define UTS_RELEASE \"0.99.13\" > tools/version.h
+ @echo \#define UTS_RELEASE \"$(VERSION).$(PATCHLEVEL)$(ALPHA)\" > tools/version.h
@echo \#define UTS_VERSION \"\#`cat .version` `date`\" >> tools/version.h
@echo \#define LINUX_COMPILE_TIME \"`date +%T`\" >> tools/version.h
@echo \#define LINUX_COMPILE_BY \"`whoami`\" >> tools/version.h
@@ -137,7 +153,6 @@ tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
- $(MATH) \
$(LIBS) \
-o tools/system > System.map
@@ -176,7 +191,6 @@ tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs
$(ARCHIVES) \
$(FILESYSTEMS) \
$(DRIVERS) \
- $(MATH) \
$(LIBS) \
-o tools/zSystem > zSystem.map
@@ -192,11 +206,15 @@ mm: dummy
kernel: dummy
$(MAKE) linuxsubdirs SUBDIRS=kernel
+drivers: dummy
+ $(MAKE) linuxsubdirs SUBDIRS=drivers
+
clean:
- rm -f zImage zSystem.map tools/zSystem
- rm -f Image System.map core boot/bootsect boot/setup \
+ rm -f core `find . -name '*.[oas]' -print`
+ rm -f zImage zSystem.map tools/zSystem tools/system
+ rm -f Image System.map boot/bootsect boot/setup \
boot/bootsect.s boot/setup.s boot/head.s init/main.s
- rm -f init/*.o tools/system tools/build boot/*.o tools/*.o
+ rm -f init/*.o tools/build boot/*.o tools/*.o
for i in zBoot $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
mrproper: clean
@@ -204,6 +222,8 @@ mrproper: clean
rm -f .version .config* config.old
rm -f .depend `find . -name .depend -print`
+distclean: mrproper
+
backup: mrproper
cd .. && tar cf - linux | gzip -9 > backup.gz
sync
diff --git a/README b/README
index c5d27ba..db5e525 100644
--- a/README
+++ b/README
@@ -75,8 +75,8 @@ CONFIGURING the kernel:
should probably answer 'n' to the questions for a "production"
kernel.
- - edit net/inet/CONFIG to configure the networking parts of the kernel.
- The comments should hopefully clarify it all.
+ - edit drivers/net/CONFIG to configure the networking parts of the
+ kernel. The comments should hopefully clarify it all.
- Check the top Makefile for further site-dependent configuration
(default SVGA mode etc).
diff --git a/boot/setup.S b/boot/setup.S
index 78c6095..c775ead 100644
--- a/boot/setup.S
+++ b/boot/setup.S
@@ -822,7 +822,7 @@ moparadise: .byte 0x04, 0x55, 0x54
motrident: .byte 0x09, 0x50, 0x51, 0x52, 0x57, 0x58, 0x59, 0x5a
motseng: .byte 0x07, 0x26, 0x2a, 0x23, 0x24, 0x22
movideo7: .byte 0x08, 0x40, 0x43, 0x44, 0x41, 0x42, 0x45
-mooakvga: .byte 0x07, 0x00, 0x07, 0x4f, 0x50, 0x51
+mooakvga: .byte 0x08, 0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51
mof1280: .byte 0x04, 0x54, 0x55
mounknown: .byte 0x02
@@ -840,7 +840,7 @@ dscparadise: .word 0x5032, 0x501c, 0x8419, 0x842b
dsctrident: .word 0x5032, 0x501c, 0x501e, 0x502b, 0x503c, 0x8419, 0x841e, 0x842b, 0x843c
dsctseng: .word 0x5032, 0x501c, 0x503c, 0x6428, 0x8419, 0x841c, 0x842c
dscvideo7: .word 0x5032, 0x501c, 0x502b, 0x503c, 0x643c, 0x8419, 0x842c, 0x841c
-dscoakvga: .word 0x5032, 0x501c, 0x2819, 0x5019, 0x843c, 0x8419, 0x842C
+dscoakvga: .word 0x5032, 0x501c, 0x2819, 0x5019, 0x503c, 0x843c, 0x8419, 0x842b
dscf1280: .word 0x5032, 0x501c, 0x842b, 0x8419
dsunknown: .word 0x5032, 0x501c
modesave: .word SVGA_MODE
diff --git a/config.in b/config.in
index 87788fa..0eb6046 100644
--- a/config.in
+++ b/config.in
@@ -5,11 +5,11 @@
*
* General setup
*
-bool 'Kernel math emulation' CONFIG_MATH_EMULATION y
+bool 'Kernel math emulation' CONFIG_MATH_EMULATION n
bool 'Normal harddisk support' CONFIG_BLK_DEV_HD y
bool 'XT harddisk support' CONFIG_BLK_DEV_XD n
bool 'TCP/IP networking' CONFIG_INET y
-bool 'Limit memory to low 16MB' CONFIG_MAX_16M n
+bool 'Limit memory to low 16MB' CONFIG_MAX_16M y
bool 'System V IPC' CONFIG_SYSVIPC y
bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y
*
@@ -28,23 +28,28 @@ else
*
* SCSI support type (disk, tape, CDrom)
*
-bool 'Scsi disk support' CONFIG_BLK_DEV_SD n
-bool 'Scsi tape support' CONFIG_BLK_DEV_ST n
-bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR n
+bool 'Scsi disk support' CONFIG_BLK_DEV_SD y
+bool 'Scsi tape support' CONFIG_CHR_DEV_ST y
+bool 'Scsi CDROM support' CONFIG_BLK_DEV_SR y
+bool 'Scsi generic support' CONFIG_CHR_DEV_SG y
*
* SCSI low-level drivers
*
-bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 n
-bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 n
-bool 'Future Domain SCSI support' CONFIG_SCSI_FUTURE_DOMAIN n
-bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE n
-bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR n
-bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST n
+bool 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X y
+bool 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 y
+bool 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 y
+bool 'Future Domain 16xx SCSI support' CONFIG_SCSI_FUTURE_DOMAIN y
+bool 'Generic NCR5380 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 y
+bool 'PAS16 SCSI support' CONFIG_SCSI_PAS16 y
+bool 'Seagate ST-02 and Future Domain TMC-8xx SCSI support' CONFIG_SCSI_SEAGATE y
+bool 'Trantor T128/T128F/T228 SCSI support' CONFIG_SCSI_T128 y
+bool 'UltraStor SCSI support' CONFIG_SCSI_ULTRASTOR y
+bool '7000FASST SCSI support' CONFIG_SCSI_7000FASST y
fi
*
* Network device support
*
-bool 'Network device support?' CONFIG_ETHERCARDS y
+bool 'Network device support?' CONFIG_ETHERCARDS n
if [ "$CONFIG_ETHERCARDS" = "n" ]
:
: Skipping ethercard configuration options...
@@ -52,17 +57,22 @@ if [ "$CONFIG_ETHERCARDS" = "n" ]
else
bool 'SLIP (serial line) support' CONFIG_SLIP n
bool 'PLIP (parallel port) support' CONFIG_PLIP n
-bool 'NE2000/NE1000 support' CONFIG_NE2000 y
+bool 'NE2000/NE1000 support' CONFIG_NE2000 n
bool 'WD80*3 support' CONFIG_WD80x3 y
-#bool '3c501 support' CONFIG_EL1 n
-bool '3c503 support' CONFIG_EL2 y
-#bool '3c509 support' CONFIG_EL3 n
-bool 'HP PCLAN support' CONFIG_HPLAN y
-bool 'AT1500 and NE2100 support' CONFIG_AT1500 y
+bool 'SMC Ultra support' CONFIG_ULTRA n
+bool '3c501 support' CONFIG_EL1 n
+bool '3c503 support' CONFIG_EL2 n
+#bool '3c507 support' CONFIG_EL16 n
+bool '3c509 support' CONFIG_EL3 n
+bool 'HP PCLAN support' CONFIG_HPLAN n
+bool 'AT1500 and NE2100 support' CONFIG_AT1500 n
+bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n
+#bool 'Zenith Z-Note support' CONFIG_ZNET n
+#bool 'EtherExpress support' CONFIG_EEXPRESS n
#bool 'DEPCA support' CONFIG_DEPCA n
-bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 y
+#bool 'NI52** support' CONFIG_NI52 n
+#bool 'NI65** support' CONFIG_NI65 n
#bool 'AT-LAN-TEC pocket adaptor support' CONFIG_ATP n
-#bool 'EtherExpress support' CONFIG_EEXPRESS n
fi
*
bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n
@@ -82,11 +92,12 @@ bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n
* character devices
*
bool 'Keyboard meta-key sends ESC-prefix' CONFIG_KBD_META y
-bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML y
-bool 'Logitech busmouse support' CONFIG_BUSMOUSE y
-bool 'QuickPort mouse support' CONFIG_QUICKPORT_MOUSE y
+bool 'Keyboard Num Lock on by default' CONFIG_KBD_NUML n
+bool 'Parallel printer support' CONFIG_PRINTER y
+bool 'Logitech busmouse support' CONFIG_BUSMOUSE n
+bool 'QuickPort mouse support' CONFIG_QUICKPORT_MOUSE n
if [ "$CONFIG_QUICKPORT_MOUSE" = "n" ]
-bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE n
+bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y
fi
bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n
bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n
@@ -102,5 +113,5 @@ bool 'Sound card support (distributed separately)' CONFIG_SOUND n
bool 'Debug kmalloc/kfree' CONFIG_DEBUG_MALLOC n
bool 'Kernel profiling support' CONFIG_PROFILE n
if [ "$CONFIG_SCSI" = "y" ]
-bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS n
+bool 'Verbose scsi error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS y
fi
diff --git a/kernel/FPU-emu/Makefile b/drivers/FPU-emu/Makefile
index fb09ed9..13f619c 100644
--- a/kernel/FPU-emu/Makefile
+++ b/drivers/FPU-emu/Makefile
@@ -15,11 +15,7 @@ CFLAGS := $(CFLAGS) -DPARANOID $(DEBUG) -fno-builtin
.s.o:
$(CC) -c $<
-OBJS = fpu_entry.o
-
-ifdef CONFIG_MATH_EMULATION
-
-OBJS := $(OBJS) div_small.o errors.o \
+OBJS = fpu_entry.o div_small.o errors.o \
fpu_arith.o fpu_aux.o fpu_etc.o fpu_trig.o \
load_store.o get_address.o \
poly_atan.o poly_l2.o poly_2xm1.o poly_sin.o poly_tan.o \
@@ -30,8 +26,6 @@ OBJS := $(OBJS) div_small.o errors.o \
reg_round.o \
wm_shrx.o wm_sqrt.o
-endif
-
math.a: $(OBJS)
rm -f math.a
$(AR) rcs math.a $(OBJS)
diff --git a/kernel/FPU-emu/README b/drivers/FPU-emu/README
index a000e4f..a000e4f 100644
--- a/kernel/FPU-emu/README
+++ b/drivers/FPU-emu/README
diff --git a/kernel/FPU-emu/control_w.h b/drivers/FPU-emu/control_w.h
index 42bb1bf..42bb1bf 100644
--- a/kernel/FPU-emu/control_w.h
+++ b/drivers/FPU-emu/control_w.h
diff --git a/kernel/FPU-emu/div_small.S b/drivers/FPU-emu/div_small.S
index 0e3b71e..0e3b71e 100644
--- a/kernel/FPU-emu/div_small.S
+++ b/drivers/FPU-emu/div_small.S
diff --git a/kernel/FPU-emu/errors.c b/drivers/FPU-emu/errors.c
index 444a8af..444a8af 100644
--- a/kernel/FPU-emu/errors.c
+++ b/drivers/FPU-emu/errors.c
diff --git a/kernel/FPU-emu/exception.h b/drivers/FPU-emu/exception.h
index 7f90ede..7f90ede 100644
--- a/kernel/FPU-emu/exception.h
+++ b/drivers/FPU-emu/exception.h
diff --git a/kernel/FPU-emu/fpu_arith.c b/drivers/FPU-emu/fpu_arith.c
index 471d2c6..471d2c6 100644
--- a/kernel/FPU-emu/fpu_arith.c
+++ b/drivers/FPU-emu/fpu_arith.c
diff --git a/kernel/FPU-emu/fpu_asm.h b/drivers/FPU-emu/fpu_asm.h
index b20a123..b20a123 100644
--- a/kernel/FPU-emu/fpu_asm.h
+++ b/drivers/FPU-emu/fpu_asm.h
diff --git a/kernel/FPU-emu/fpu_aux.c b/drivers/FPU-emu/fpu_aux.c
index 90301a4..90301a4 100644
--- a/kernel/FPU-emu/fpu_aux.c
+++ b/drivers/FPU-emu/fpu_aux.c
diff --git a/kernel/FPU-emu/fpu_emu.h b/drivers/FPU-emu/fpu_emu.h
index 7b871fd..7b871fd 100644
--- a/kernel/FPU-emu/fpu_emu.h
+++ b/drivers/FPU-emu/fpu_emu.h
diff --git a/kernel/FPU-emu/fpu_entry.c b/drivers/FPU-emu/fpu_entry.c
index 6bbe3c4..3ae0ff4 100644
--- a/kernel/FPU-emu/fpu_entry.c
+++ b/drivers/FPU-emu/fpu_entry.c
@@ -23,10 +23,6 @@
| math_emulate() is the sole entry point for wm-FPU-emu |
+---------------------------------------------------------------------------*/
-#include <linux/config.h>
-
-#ifdef CONFIG_MATH_EMULATION
-
#include <linux/signal.h>
#include <linux/segment.h>
@@ -607,18 +603,3 @@ void __math_abort(struct info * info, unsigned int signal)
printk("ERROR: wm-FPU-emu math_abort failed!\n");
#endif PARANOID
}
-
-#else /* no math emulation */
-
-#include <linux/signal.h>
-#include <linux/sched.h>
-
-asmlinkage void math_emulate(long arg)
-{
- printk("math-emulation not enabled and no coprocessor found.\n");
- printk("killing %s.\n",current->comm);
- send_sig(SIGFPE,current,1);
- schedule();
-}
-
-#endif /* CONFIG_MATH_EMULATION */
diff --git a/kernel/FPU-emu/fpu_etc.c b/drivers/FPU-emu/fpu_etc.c
index 7c4535f..7c4535f 100644
--- a/kernel/FPU-emu/fpu_etc.c
+++ b/drivers/FPU-emu/fpu_etc.c
diff --git a/kernel/FPU-emu/fpu_proto.h b/drivers/FPU-emu/fpu_proto.h
index b7e7032..b7e7032 100644
--- a/kernel/FPU-emu/fpu_proto.h
+++ b/drivers/FPU-emu/fpu_proto.h
diff --git a/kernel/FPU-emu/fpu_system.h b/drivers/FPU-emu/fpu_system.h
index be6b0bb..be6b0bb 100644
--- a/kernel/FPU-emu/fpu_system.h
+++ b/drivers/FPU-emu/fpu_system.h
diff --git a/kernel/FPU-emu/fpu_trig.c b/drivers/FPU-emu/fpu_trig.c
index d20c4db..d20c4db 100644
--- a/kernel/FPU-emu/fpu_trig.c
+++ b/drivers/FPU-emu/fpu_trig.c
diff --git a/kernel/FPU-emu/get_address.c b/drivers/FPU-emu/get_address.c
index 86ae753..86ae753 100644
--- a/kernel/FPU-emu/get_address.c
+++ b/drivers/FPU-emu/get_address.c
diff --git a/kernel/FPU-emu/load_store.c b/drivers/FPU-emu/load_store.c
index 6e4b3d9..6e4b3d9 100644
--- a/kernel/FPU-emu/load_store.c
+++ b/drivers/FPU-emu/load_store.c
diff --git a/kernel/FPU-emu/poly_2xm1.c b/drivers/FPU-emu/poly_2xm1.c
index 7e8aec7..7e8aec7 100644
--- a/kernel/FPU-emu/poly_2xm1.c
+++ b/drivers/FPU-emu/poly_2xm1.c
diff --git a/kernel/FPU-emu/poly_atan.c b/drivers/FPU-emu/poly_atan.c
index e0a0645..e0a0645 100644
--- a/kernel/FPU-emu/poly_atan.c
+++ b/drivers/FPU-emu/poly_atan.c
diff --git a/kernel/FPU-emu/poly_div.S b/drivers/FPU-emu/poly_div.S
index cab7d72..cab7d72 100644
--- a/kernel/FPU-emu/poly_div.S
+++ b/drivers/FPU-emu/poly_div.S
diff --git a/kernel/FPU-emu/poly_l2.c b/drivers/FPU-emu/poly_l2.c
index 49085a0..49085a0 100644
--- a/kernel/FPU-emu/poly_l2.c
+++ b/drivers/FPU-emu/poly_l2.c
diff --git a/kernel/FPU-emu/poly_mul64.S b/drivers/FPU-emu/poly_mul64.S
index 7434094..52fcee7 100644
--- a/kernel/FPU-emu/poly_mul64.S
+++ b/drivers/FPU-emu/poly_mul64.S
@@ -34,7 +34,7 @@ _mul64:
movl (%esi),%eax
mull (%ecx)
- movl %eax,-16(%ebp) // Not used
+ movl %eax,-16(%ebp) /* Not used */
movl %edx,-12(%ebp)
movl (%esi),%eax
diff --git a/kernel/FPU-emu/poly_sin.c b/drivers/FPU-emu/poly_sin.c
index 5076741..5076741 100644
--- a/kernel/FPU-emu/poly_sin.c
+++ b/drivers/FPU-emu/poly_sin.c
diff --git a/kernel/FPU-emu/poly_tan.c b/drivers/FPU-emu/poly_tan.c
index 4c8a41b..4c8a41b 100644
--- a/kernel/FPU-emu/poly_tan.c
+++ b/drivers/FPU-emu/poly_tan.c
diff --git a/kernel/FPU-emu/polynomial.S b/drivers/FPU-emu/polynomial.S
index 894eded..d3407ab 100644
--- a/kernel/FPU-emu/polynomial.S
+++ b/drivers/FPU-emu/polynomial.S
@@ -22,7 +22,7 @@
#include "fpu_asm.h"
-// #define EXTRA_PRECISE // Do not use: not complete
+/* #define EXTRA_PRECISE Do not use: not complete */
#define TERM_SIZE $8
#define SUM_MS -20(%ebp) /* sum ms long */
@@ -45,16 +45,16 @@ _polynomial:
pushl %edi
pushl %ebx
- movl PARAM2,%esi // x
- movl PARAM3,%edi // terms
+ movl PARAM2,%esi /* x */
+ movl PARAM3,%edi /* terms */
movl TERM_SIZE,%eax
- mull PARAM4 // n
+ mull PARAM4 /* n */
addl %eax,%edi
- movl 4(%edi),%edx // terms[n]
+ movl 4(%edi),%edx /* terms[n] */
movl %edx,SUM_MS
- movl (%edi),%edx // terms[n]
+ movl (%edi),%edx /* terms[n] */
movl %edx,SUM_MIDDLE
xor %eax,%eax
movl %eax,SUM_LS
@@ -69,41 +69,43 @@ L_accum_loop:
movl %eax,ACCUM_MIDDLE
movl SUM_MIDDLE,%eax
- mull (%esi) // x ls long
-// movl %eax,-16(%ebp) // Not needed
+ mull (%esi) /* x ls long */
+/* movl %eax,-16(%ebp) Not needed */
movl %edx,ACCUM_LS
movl SUM_MIDDLE,%eax
- mull 4(%esi) // x ms long
+ mull 4(%esi) /* x ms long */
addl %eax,ACCUM_LS
adcl %edx,ACCUM_MIDDLE
adcl $0,ACCUM_MS
movl SUM_MS,%eax
- mull (%esi) // x ls long
+ mull (%esi) /* x ls long */
addl %eax,ACCUM_LS
adcl %edx,ACCUM_MIDDLE
adcl $0,ACCUM_MS
movl SUM_MS,%eax
- mull 4(%esi) // x ms long
+ mull 4(%esi) /* x ms long */
addl %eax,ACCUM_MIDDLE
adcl %edx,ACCUM_MS
-// Now put the sum of next term and the accumulator
-// into the sum register
+/*
+ * Now put the sum of next term and the accumulator
+ * into the sum register
+ */
movl ACCUM_MIDDLE,%eax
- addl (%edi),%eax // term ls long
+ addl (%edi),%eax /* term ls long */
movl %eax,SUM_MIDDLE
movl ACCUM_MS,%eax
- adcl 4(%edi),%eax // term ms long
+ adcl 4(%edi),%eax /* term ms long */
movl %eax,SUM_MS
#ifdef EXTRA_PRECISE
movl ACCUM_LS,%eax
movl %eax,SUM_LS
#else
- testb $0x80,ACCUM_LS_HI // ms bit of ACCUM_LS
+ testb $0x80,ACCUM_LS_HI /* ms bit of ACCUM_LS */
je L_no_poly_round
addl $1,SUM_MIDDLE
@@ -126,7 +128,7 @@ L_accum_done:
#endif EXTRA_PRECISE
L_poly_done:
- movl PARAM1,%edi // accum
+ movl PARAM1,%edi /* accum */
movl SUM_MIDDLE,%eax
movl %eax,(%edi)
movl SUM_MS,%eax
diff --git a/kernel/FPU-emu/reg_add_sub.c b/drivers/FPU-emu/reg_add_sub.c
index 890484e..890484e 100644
--- a/kernel/FPU-emu/reg_add_sub.c
+++ b/drivers/FPU-emu/reg_add_sub.c
diff --git a/kernel/FPU-emu/reg_compare.c b/drivers/FPU-emu/reg_compare.c
index d1ec646..d1ec646 100644
--- a/kernel/FPU-emu/reg_compare.c
+++ b/drivers/FPU-emu/reg_compare.c
diff --git a/kernel/FPU-emu/reg_constant.c b/drivers/FPU-emu/reg_constant.c
index 1f63051..1f63051 100644
--- a/kernel/FPU-emu/reg_constant.c
+++ b/drivers/FPU-emu/reg_constant.c
diff --git a/kernel/FPU-emu/reg_constant.h b/drivers/FPU-emu/reg_constant.h
index 23ba06d..23ba06d 100644
--- a/kernel/FPU-emu/reg_constant.h
+++ b/drivers/FPU-emu/reg_constant.h
diff --git a/kernel/FPU-emu/reg_div.S b/drivers/FPU-emu/reg_div.S
index 9d65f60..24acaec 100644
--- a/kernel/FPU-emu/reg_div.S
+++ b/drivers/FPU-emu/reg_div.S
@@ -36,10 +36,10 @@ _reg_div:
movb TAG(%esi),%al
orb TAG(%ebx),%al
- jne L_div_special // Not (both numbers TW_Valid)
+ jne L_div_special /* Not (both numbers TW_Valid) */
#ifdef DENORM_OPERAND
-// Check for denormals
+/* Check for denormals */
cmpl EXP_UNDER,EXP(%esi)
jg xL_arg1_not_denormal
@@ -58,12 +58,12 @@ xL_arg1_not_denormal:
xL_arg2_not_denormal:
#endif DENORM_OPERAND
-// Both arguments are TW_Valid
+/* Both arguments are TW_Valid */
movb TW_Valid,TAG(%edi)
movb SIGN(%esi),%cl
cmpb %cl,SIGN(%ebx)
- setne (%edi) // Set the sign, requires SIGN_NEG=1, SIGN_POS=0
+ setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */
movl EXP(%esi),%edx
movl EXP(%ebx),%eax
@@ -76,27 +76,27 @@ xL_arg2_not_denormal:
/*-----------------------------------------------------------------------*/
L_div_special:
- cmpb TW_NaN,TAG(%esi) // A NaN with anything to give NaN
+ cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */
je L_arg1_NaN
- cmpb TW_NaN,TAG(%ebx) // A NaN with anything to give NaN
+ cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */
jne L_no_NaN_arg
-// Operations on NaNs
+/* Operations on NaNs */
L_arg1_NaN:
L_arg2_NaN:
- pushl %edi // Destination
-// pushl %ebx
+ pushl %edi /* Destination */
+/* pushl %ebx */
pushl %esi
- pushl %ebx // Ordering is important here
+ pushl %ebx /* Ordering is important here */
call _real_2op_NaN
jmp LDiv_exit
-// Invalid operations
+/* Invalid operations */
L_zero_zero:
L_inf_inf:
- pushl %edi // Destination
- call _arith_invalid // 0/0 or Infinity/Infinity
+ pushl %edi /* Destination */
+ call _arith_invalid /* 0/0 or Infinity/Infinity */
jmp LDiv_exit
L_no_NaN_arg:
@@ -104,50 +104,50 @@ L_no_NaN_arg:
jne L_arg1_not_inf
cmpb TW_Infinity,TAG(%ebx)
- je L_inf_inf // invalid operation
+ je L_inf_inf /* invalid operation */
cmpb TW_Valid,TAG(%ebx)
je L_inf_valid
#ifdef PARANOID
- // arg2 must be zero or valid
+ /* arg2 must be zero or valid */
cmpb TW_Zero,TAG(%ebx)
ja L_unknown_tags
#endif PARANOID
- // Note that p16-9 says that infinity/0 returns infinity
- jmp L_copy_arg1 // Answer is Inf
+ /* Note that p16-9 says that infinity/0 returns infinity */
+ jmp L_copy_arg1 /* Answer is Inf */
L_inf_valid:
#ifdef DENORM_OPERAND
cmpl EXP_UNDER,EXP(%ebx)
- jg L_copy_arg1 // Answer is Inf
+ jg L_copy_arg1 /* Answer is Inf */
call _denormal_operand
orl %eax,%eax
jnz FPU_Arith_exit
#endif DENORM_OPERAND
- jmp L_copy_arg1 // Answer is Inf
+ jmp L_copy_arg1 /* Answer is Inf */
L_arg1_not_inf:
- cmpb TW_Zero,TAG(%ebx) // Priority to div-by-zero error
+ cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */
jne L_arg2_not_zero
cmpb TW_Zero,TAG(%esi)
- je L_zero_zero // invalid operation
+ je L_zero_zero /* invalid operation */
#ifdef PARANOID
- // arg1 must be valid
+ /* arg1 must be valid */
cmpb TW_Valid,TAG(%esi)
ja L_unknown_tags
#endif PARANOID
-// Division by zero error
- pushl %edi // destination
+/* Division by zero error */
+ pushl %edi /* destination */
movb SIGN(%esi),%al
xorb SIGN(%ebx),%al
- pushl %eax // lower 8 bits have the sign
+ pushl %eax /* lower 8 bits have the sign */
call _divide_by_zero
jmp LDiv_exit
@@ -160,14 +160,14 @@ L_arg2_not_zero:
jne L_return_zero
cmpl EXP_UNDER,EXP(%esi)
- jg L_return_zero // Answer is zero
+ jg L_return_zero /* Answer is zero */
call _denormal_operand
orl %eax,%eax
jnz FPU_Arith_exit
#endif DENORM_OPERAND
- jmp L_return_zero // Answer is zero
+ jmp L_return_zero /* Answer is zero */
L_arg2_not_inf:
@@ -176,11 +176,11 @@ L_arg2_not_inf:
jne L_unknown_tags
#endif PARANOID
- // arg1 is zero, arg2 is not Infinity or a NaN
+ /* arg1 is zero, arg2 is not Infinity or a NaN */
#ifdef DENORM_OPERAND
cmpl EXP_UNDER,EXP(%ebx)
- jg L_copy_arg1 // Answer is zero
+ jg L_copy_arg1 /* Answer is zero */
call _denormal_operand
orl %eax,%eax
@@ -203,12 +203,12 @@ LDiv_set_result_sign:
jne LDiv_negative_result
movb SIGN_POS,SIGN(%edi)
- xorl %eax,%eax // Valid result
+ xorl %eax,%eax /* Valid result */
jmp LDiv_exit
LDiv_negative_result:
movb SIGN_NEG,SIGN(%edi)
- xorl %eax,%eax // Valid result
+ xorl %eax,%eax /* Valid result */
LDiv_exit:
leal -12(%ebp),%esp
@@ -233,12 +233,12 @@ L_unknown_tags:
push EX_INTERNAL | 0x208
call EXCEPTION
- // Generate a NaN for unknown tags
+ /* Generate a NaN for unknown tags */
movl _CONST_QNaN,%eax
movl %eax,(%edi)
movl _CONST_QNaN+4,%eax
movl %eax,SIGL(%edi)
movl _CONST_QNaN+8,%eax
movl %eax,SIGH(%edi)
- jmp LDiv_exit // %eax is nz
+ jmp LDiv_exit /* %eax is nz */
#endif PARANOID
diff --git a/kernel/FPU-emu/reg_ld_str.c b/drivers/FPU-emu/reg_ld_str.c
index d07c7bf..d07c7bf 100644
--- a/kernel/FPU-emu/reg_ld_str.c
+++ b/drivers/FPU-emu/reg_ld_str.c
diff --git a/kernel/FPU-emu/reg_mul.c b/drivers/FPU-emu/reg_mul.c
index a7d48ad..a7d48ad 100644
--- a/kernel/FPU-emu/reg_mul.c
+++ b/drivers/FPU-emu/reg_mul.c
diff --git a/kernel/FPU-emu/reg_norm.S b/drivers/FPU-emu/reg_norm.S
index 22fddfa..f63d74a 100644
--- a/kernel/FPU-emu/reg_norm.S
+++ b/drivers/FPU-emu/reg_norm.S
@@ -32,17 +32,17 @@ _normalize:
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
- orl %edx,%edx // ms bits
- js L_done // Already normalized
- jnz L_shift_1 // Shift left 1 - 31 bits
+ orl %edx,%edx /* ms bits */
+ js L_done /* Already normalized */
+ jnz L_shift_1 /* Shift left 1 - 31 bits */
orl %eax,%eax
- jz L_zero // The contents are zero
+ jz L_zero /* The contents are zero */
-// L_shift_32:
+/* L_shift_32: */
movl %eax,%edx
xorl %eax,%eax
- subl $32,EXP(%ebx) // This can cause an underflow
+ subl $32,EXP(%ebx) /* This can cause an underflow */
/* We need to shift left by 1 - 31 bits */
L_shift_1:
@@ -51,7 +51,7 @@ L_shift_1:
negl %ecx
shld %cl,%eax,%edx
shl %cl,%eax
- subl %ecx,EXP(%ebx) // This can cause an underflow
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
movl %edx,SIGH(%ebx)
movl %eax,SIGL(%ebx)
@@ -88,7 +88,7 @@ L_overflow:
-// Normalise without reporting underflow or overflow
+/* Normalise without reporting underflow or overflow */
.align 2,144
.globl _normalize_nuo
@@ -102,17 +102,17 @@ _normalize_nuo:
movl SIGH(%ebx),%edx
movl SIGL(%ebx),%eax
- orl %edx,%edx // ms bits
- js L_exit // Already normalized
- jnz L_nuo_shift_1 // Shift left 1 - 31 bits
+ orl %edx,%edx /* ms bits */
+ js L_exit /* Already normalized */
+ jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */
orl %eax,%eax
- jz L_zero // The contents are zero
+ jz L_zero /* The contents are zero */
-// L_nuo_shift_32:
+/* L_nuo_shift_32: */
movl %eax,%edx
xorl %eax,%eax
- subl $32,EXP(%ebx) // This can cause an underflow
+ subl $32,EXP(%ebx) /* This can cause an underflow */
/* We need to shift left by 1 - 31 bits */
L_nuo_shift_1:
@@ -121,7 +121,7 @@ L_nuo_shift_1:
negl %ecx
shld %cl,%eax,%edx
shl %cl,%eax
- subl %ecx,EXP(%ebx) // This can cause an underflow
+ subl %ecx,EXP(%ebx) /* This can cause an underflow */
movl %edx,SIGH(%ebx)
movl %eax,SIGL(%ebx)
diff --git a/kernel/FPU-emu/reg_round.S b/drivers/FPU-emu/reg_round.S
index 7c338c2..77a8a3a 100644
--- a/kernel/FPU-emu/reg_round.S
+++ b/drivers/FPU-emu/reg_round.S
@@ -95,7 +95,7 @@ FPU_denormal:
.globl FPU_Arith_exit
.globl _round_reg
-// Entry point when called from C
+/* Entry point when called from C */
_round_reg:
pushl %ebp
movl %esp,%ebp
@@ -110,24 +110,26 @@ _round_reg:
movl PARAM3,%ecx
jmp FPU_round_sqrt
-FPU_round: // Normal entry point
+FPU_round: /* Normal entry point */
movl PARAM4,%ecx
-FPU_round_sqrt: // Entry point from wm_sqrt.S
+FPU_round_sqrt: /* Entry point from wm_sqrt.S */
#ifdef PARANOID
-// Cannot use this here yet
-// orl %eax,%eax
-// jns L_entry_bugged
+/*
+ * Cannot use this here yet
+ * orl %eax,%eax
+ * jns L_entry_bugged
+ */
#endif PARANOID
cmpl EXP_UNDER,EXP(%edi)
- jle xMake_denorm // The number is a de-normal
+ jle xMake_denorm /* The number is a de-normal */
- movb $0,FPU_denormal // 0 -> not a de-normal
+ movb $0,FPU_denormal /* 0 -> not a de-normal */
xDenorm_done:
- movb $0,FPU_bits_lost // No bits yet lost in rounding
+ movb $0,FPU_bits_lost /* No bits yet lost in rounding */
movl %ecx,%esi
andl CW_PC,%ecx
@@ -141,11 +143,11 @@ xDenorm_done:
je LRound_To_24
#ifdef PARANOID
- jmp L_bugged // There is no bug, just a bad control word
+ jmp L_bugged /* There is no bug, just a bad control word */
#endif PARANOID
-// Round etc to 24 bit precision
+/* Round etc to 24 bit precision */
LRound_To_24:
movl %esi,%ecx
andl CW_RC,%ecx
@@ -155,10 +157,10 @@ LRound_To_24:
cmpl RC_CHOP,%ecx
je LCheck_truncate_24
- cmpl RC_UP,%ecx // Towards +infinity
+ cmpl RC_UP,%ecx /* Towards +infinity */
je LUp_24
- cmpl RC_DOWN,%ecx // Towards -infinity
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
je LDown_24
#ifdef PARANOID
@@ -167,13 +169,13 @@ LRound_To_24:
LUp_24:
cmpb SIGN_POS,SIGN(%edi)
- jne LCheck_truncate_24 // If negative then up==truncate
+ jne LCheck_truncate_24 /* If negative then up==truncate */
jmp LCheck_24_round_up
LDown_24:
cmpb SIGN_POS,SIGN(%edi)
- je LCheck_truncate_24 // If positive then down==truncate
+ je LCheck_truncate_24 /* If positive then down==truncate */
LCheck_24_round_up:
movl %eax,%ecx
@@ -184,28 +186,28 @@ LCheck_24_round_up:
jmp LRe_normalise
LRound_nearest_24:
- // Do rounding of the 24th bit if needed (nearest or even)
+ /* Do rounding of the 24th bit if needed (nearest or even) */
movl %eax,%ecx
andl $0x000000ff,%ecx
cmpl $0x00000080,%ecx
- jc LCheck_truncate_24 // less than half, no increment needed
+ jc LCheck_truncate_24 /* less than half, no increment needed */
- jne LGreater_Half_24 // greater than half, increment needed
+ jne LGreater_Half_24 /* greater than half, increment needed */
- // Possibly half, we need to check the ls bits
+ /* Possibly half, we need to check the ls bits */
orl %ebx,%ebx
- jnz LGreater_Half_24 // greater than half, increment needed
+ jnz LGreater_Half_24 /* greater than half, increment needed */
orl %edx,%edx
- jnz LGreater_Half_24 // greater than half, increment needed
+ jnz LGreater_Half_24 /* greater than half, increment needed */
- // Exactly half, increment only if 24th bit is 1 (round to even)
+ /* Exactly half, increment only if 24th bit is 1 (round to even) */
testl $0x00000100,%eax
jz LDo_truncate_24
-LGreater_Half_24: // Rounding: increment at the 24th bit
+LGreater_Half_24: /* Rounding: increment at the 24th bit */
LDo_24_round_up:
- andl $0xffffff00,%eax // Truncate to 24 bits
+ andl $0xffffff00,%eax /* Truncate to 24 bits */
xorl %ebx,%ebx
movb LOST_UP,FPU_bits_lost
addl $0x00000100,%eax
@@ -216,16 +218,16 @@ LCheck_truncate_24:
andl $0x000000ff,%ecx
orl %ebx,%ecx
orl %edx,%ecx
- jz LRe_normalise // No truncation needed
+ jz LRe_normalise /* No truncation needed */
LDo_truncate_24:
- andl $0xffffff00,%eax // Truncate to 24 bits
+ andl $0xffffff00,%eax /* Truncate to 24 bits */
xorl %ebx,%ebx
movb LOST_DOWN,FPU_bits_lost
jmp LRe_normalise
-// Round etc to 53 bit precision
+/* Round etc to 53 bit precision */
LRound_To_53:
movl %esi,%ecx
andl CW_RC,%ecx
@@ -235,10 +237,10 @@ LRound_To_53:
cmpl RC_CHOP,%ecx
je LCheck_truncate_53
- cmpl RC_UP,%ecx // Towards +infinity
+ cmpl RC_UP,%ecx /* Towards +infinity */
je LUp_53
- cmpl RC_DOWN,%ecx // Towards -infinity
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
je LDown_53
#ifdef PARANOID
@@ -247,13 +249,13 @@ LRound_To_53:
LUp_53:
cmpb SIGN_POS,SIGN(%edi)
- jne LCheck_truncate_53 // If negative then up==truncate
+ jne LCheck_truncate_53 /* If negative then up==truncate */
jmp LCheck_53_round_up
LDown_53:
cmpb SIGN_POS,SIGN(%edi)
- je LCheck_truncate_53 // If positive then down==truncate
+ je LCheck_truncate_53 /* If positive then down==truncate */
LCheck_53_round_up:
movl %ebx,%ecx
@@ -263,26 +265,26 @@ LCheck_53_round_up:
jmp LRe_normalise
LRound_nearest_53:
- // Do rounding of the 53rd bit if needed (nearest or even)
+ /* Do rounding of the 53rd bit if needed (nearest or even) */
movl %ebx,%ecx
andl $0x000007ff,%ecx
cmpl $0x00000400,%ecx
- jc LCheck_truncate_53 // less than half, no increment needed
+ jc LCheck_truncate_53 /* less than half, no increment needed */
- jnz LGreater_Half_53 // greater than half, increment needed
+ jnz LGreater_Half_53 /* greater than half, increment needed */
- // Possibly half, we need to check the ls bits
+ /* Possibly half, we need to check the ls bits */
orl %edx,%edx
- jnz LGreater_Half_53 // greater than half, increment needed
+ jnz LGreater_Half_53 /* greater than half, increment needed */
- // Exactly half, increment only if 53rd bit is 1 (round to even)
+ /* Exactly half, increment only if 53rd bit is 1 (round to even) */
testl $0x00000800,%ebx
jz LTruncate_53
-LGreater_Half_53: // Rounding: increment at the 53rd bit
+LGreater_Half_53: /* Rounding: increment at the 53rd bit */
LDo_53_round_up:
movb LOST_UP,FPU_bits_lost
- andl $0xfffff800,%ebx // Truncate to 53 bits
+ andl $0xfffff800,%ebx /* Truncate to 53 bits */
addl $0x00000800,%ebx
adcl $0,%eax
jmp LCheck_Round_Overflow
@@ -295,11 +297,11 @@ LCheck_truncate_53:
LTruncate_53:
movb LOST_DOWN,FPU_bits_lost
- andl $0xfffff800,%ebx // Truncate to 53 bits
+ andl $0xfffff800,%ebx /* Truncate to 53 bits */
jmp LRe_normalise
-// Round etc to 64 bit precision
+/* Round etc to 64 bit precision */
LRound_To_64:
movl %esi,%ecx
andl CW_RC,%ecx
@@ -309,10 +311,10 @@ LRound_To_64:
cmpl RC_CHOP,%ecx
je LCheck_truncate_64
- cmpl RC_UP,%ecx // Towards +infinity
+ cmpl RC_UP,%ecx /* Towards +infinity */
je LUp_64
- cmpl RC_DOWN,%ecx // Towards -infinity
+ cmpl RC_DOWN,%ecx /* Towards -infinity */
je LDown_64
#ifdef PARANOID
@@ -321,7 +323,7 @@ LRound_To_64:
LUp_64:
cmpb SIGN_POS,SIGN(%edi)
- jne LCheck_truncate_64 // If negative then up==truncate
+ jne LCheck_truncate_64 /* If negative then up==truncate */
orl %edx,%edx
jnz LDo_64_round_up
@@ -329,7 +331,7 @@ LUp_64:
LDown_64:
cmpb SIGN_POS,SIGN(%edi)
- je LCheck_truncate_64 // If positive then down==truncate
+ je LCheck_truncate_64 /* If positive then down==truncate */
orl %edx,%edx
jnz LDo_64_round_up
@@ -385,7 +387,7 @@ xL_Store_significand:
movl %eax,SIGH(%edi)
movl %ebx,SIGL(%edi)
- xorl %eax,%eax // No errors detected.
+ xorl %eax,%eax /* No errors detected. */
cmpl EXP_OVER,EXP(%edi)
jge L_overflow
@@ -398,16 +400,20 @@ FPU_Arith_exit:
ret
-// Set the FPU status flags to represent precision loss due to
-// round-up.
+/*
+ * Set the FPU status flags to represent precision loss due to
+ * round-up.
+ */
xL_precision_lost_up:
push %eax
call _set_precision_flag_up
popl %eax
jmp xL_no_precision_loss
-// Set the FPU status flags to represent precision loss due to
-// truncation.
+/*
+ * Set the FPU status flags to represent precision loss due to
+ * truncation.
+ */
xL_precision_lost_down:
push %eax
call _set_precision_flag_down
@@ -415,18 +421,20 @@ xL_precision_lost_down:
jmp xL_no_precision_loss
-// The number is a denormal (which might get rounded up to a normal)
-// Shift the number right the required number of bits, which will
-// have to be undone later...
+/*
+ * The number is a denormal (which might get rounded up to a normal)
+ * Shift the number right the required number of bits, which will
+ * have to be undone later...
+ */
xMake_denorm:
- // The action to be taken depends upon whether the underflow
- // exception is masked
- testb CW_Underflow,%cl // Underflow mask.
- jz xUnmasked_underflow // Do not make a denormal.
+ /* The action to be taken depends upon whether the underflow */
+ /* exception is masked */
+ testb CW_Underflow,%cl /* Underflow mask. */
+ jz xUnmasked_underflow /* Do not make a denormal. */
movb DENORMAL,FPU_denormal
- pushl %ecx // Save
+ pushl %ecx /* Save */
movl EXP_UNDER+1,%ecx
subl EXP(%edi),%ecx
@@ -436,12 +444,14 @@ xMake_denorm:
cmpl $32,%ecx /* shrd only works for 0..31 bits */
jnc xDenorm_shift_more_than_32
-// We got here without jumps by assuming that the most common requirement
-// is for a small de-normalising shift.
-// Shift by [1..31] bits
+/*
+ * We got here without jumps by assuming that the most common requirement
+ * is for a small de-normalising shift.
+ * Shift by [1..31] bits
+ */
addl %ecx,EXP(%edi)
- orl %edx,%edx // extension
- setne %ch // Save whether %edx is non-zero
+ orl %edx,%edx /* extension */
+ setne %ch /* Save whether %edx is non-zero */
xorl %edx,%edx
shrd %cl,%ebx,%edx
shrd %cl,%eax,%ebx
@@ -450,7 +460,7 @@ xMake_denorm:
popl %ecx
jmp xDenorm_done
-// Shift by [32..63] bits
+/* Shift by [32..63] bits */
xDenorm_shift_more_than_32:
addl %ecx,EXP(%edi)
subb $32,%cl
@@ -461,7 +471,7 @@ xDenorm_shift_more_than_32:
shrd %cl,%ebx,%edx
shrd %cl,%eax,%ebx
shr %cl,%eax
- orl %edx,%edx // test these 32 bits
+ orl %edx,%edx /* test these 32 bits */
setne %cl
orb %ch,%bl
orb %cl,%bl
@@ -471,12 +481,12 @@ xDenorm_shift_more_than_32:
popl %ecx
jmp xDenorm_done
-// Shift by [64..) bits
+/* Shift by [64..) bits */
xDenorm_shift_more_than_63:
cmpl $64,%ecx
jne xDenorm_shift_more_than_64
-// Exactly 64 bit shift
+/* Exactly 64 bit shift */
addl %ecx,EXP(%edi)
xorl %ecx,%ecx
orl %edx,%edx
@@ -493,7 +503,7 @@ xDenorm_shift_more_than_63:
xDenorm_shift_more_than_64:
movl EXP_UNDER+1,EXP(%edi)
-// This is easy, %eax must be non-zero, so..
+/* This is easy, %eax must be non-zero, so.. */
movl $1,%edx
xorl %eax,%eax
xorl %ebx,%ebx
@@ -506,38 +516,40 @@ xUnmasked_underflow:
jmp xDenorm_done
-// Undo the de-normalisation.
+/* Undo the de-normalisation. */
xNormalise_result:
cmpb UNMASKED_UNDERFLOW,FPU_denormal
je xSignal_underflow
-// The number must be a denormal if we got here.
+/* The number must be a denormal if we got here. */
#ifdef PARANOID
- // But check it... just in case.
+ /* But check it... just in case. */
cmpl EXP_UNDER+1,EXP(%edi)
jne L_norm_bugged
#endif PARANOID
#ifdef PECULIAR_486
- // This implements a special feature of 80486 behaviour.
- // Underflow will be signalled even if the number is
- // not a denormal after rounding.
- // This difference occurs only for masked underflow, and not
- // in the unmasked case.
- // Actual 80486 behaviour differs from this in some circumstances.
- orl %eax,%eax // ms bits
- js LNormalise_shift_done // Will be masked underflow
+ /*
+ * This implements a special feature of 80486 behaviour.
+ * Underflow will be signalled even if the number is
+ * not a denormal after rounding.
+ * This difference occurs only for masked underflow, and not
+ * in the unmasked case.
+ * Actual 80486 behaviour differs from this in some circumstances.
+ */
+ orl %eax,%eax /* ms bits */
+ js LNormalise_shift_done /* Will be masked underflow */
#endif PECULIAR_486
- orl %eax,%eax // ms bits
- js xL_Normalised // No longer a denormal
+ orl %eax,%eax /* ms bits */
+ js xL_Normalised /* No longer a denormal */
- jnz LNormalise_shift_up_to_31 // Shift left 0 - 31 bits
+ jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits */
orl %ebx,%ebx
- jz L_underflow_to_zero // The contents are zero
+ jz L_underflow_to_zero /* The contents are zero */
-// Shift left 32 - 63 bits
+/* Shift left 32 - 63 bits */
movl %ebx,%eax
xorl %ebx,%ebx
subl $32,EXP(%edi)
@@ -551,10 +563,10 @@ LNormalise_shift_up_to_31:
subl %ecx,EXP(%edi)
LNormalise_shift_done:
- testb $0xff,FPU_bits_lost // bits lost == underflow
+ testb $0xff,FPU_bits_lost /* bits lost == underflow */
jz xL_Normalised
- // There must be a masked underflow
+ /* There must be a masked underflow */
push %eax
pushl EX_Underflow
call _exception
@@ -563,8 +575,10 @@ LNormalise_shift_done:
jmp xL_Normalised
-// The operations resulted in a number too small to represent.
-// Masked response.
+/*
+ * The operations resulted in a number too small to represent.
+ * Masked response.
+ */
L_underflow_to_zero:
push %eax
call _set_precision_flag_down
@@ -576,13 +590,13 @@ L_underflow_to_zero:
popl %eax
popl %eax
-// Reduce the exponent to EXP_UNDER
+/* Reduce the exponent to EXP_UNDER */
movl EXP_UNDER,EXP(%edi)
movb TW_Zero,TAG(%edi)
jmp xL_Store_significand
-// The operations resulted in a number too large to represent.
+/* The operations resulted in a number too large to represent. */
L_overflow:
push %edi
call _arith_overflow
@@ -591,15 +605,15 @@ L_overflow:
xSignal_underflow:
- // The number may have been changed to a non-denormal
- // by the rounding operations.
+ /* The number may have been changed to a non-denormal */
+ /* by the rounding operations. */
cmpl EXP_UNDER,EXP(%edi)
jle xDo_unmasked_underflow
jmp xL_Normalised
xDo_unmasked_underflow:
- // Increase the exponent by the magic number
+ /* Increase the exponent by the magic number */
addl $(3*(1<<13)),EXP(%edi)
push %eax
pushl EX_Underflow
diff --git a/kernel/FPU-emu/reg_u_add.S b/drivers/FPU-emu/reg_u_add.S
index fbcffa3..5c42e8a 100644
--- a/kernel/FPU-emu/reg_u_add.S
+++ b/drivers/FPU-emu/reg_u_add.S
@@ -34,7 +34,7 @@
_reg_u_add:
pushl %ebp
movl %esp,%ebp
-// subl $16,%esp
+/* subl $16,%esp */
pushl %esi
pushl %edi
pushl %ebx
@@ -61,10 +61,10 @@ xOp1_not_denorm:
xOp2_not_denorm:
#endif DENORM_OPERAND
-// xorl %ecx,%ecx
+/* xorl %ecx,%ecx */
movl EXP(%esi),%ecx
subl EXP(%edi),%ecx /* exp1 - exp2 */
-// jnc L_arg1_larger
+/* jnc L_arg1_larger */
jge L_arg1_larger
/* num1 is smaller */
@@ -82,8 +82,8 @@ L_arg1_larger:
L_accum_loaded:
movl PARAM3,%edi /* destination */
-// movb SIGN(%esi),%dl
-// movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+/* movb SIGN(%esi),%dl */
+/* movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */
movl EXP(%esi),%edx
@@ -99,7 +99,7 @@ L_accum_loaded:
je L_bugged
#endif PARANOID
-// The number to be shifted is in %eax:%ebx:%edx
+/* The number to be shifted is in %eax:%ebx:%edx */
cmpw $32,%cx /* shrd only works for 0..31 bits */
jnc L_more_than_31
@@ -119,9 +119,9 @@ L_more_than_31:
shrd %cl,%eax,%edx
shr %cl,%eax
orl %ebx,%ebx
- jz L_more_31_no_low // none of the lowest bits is set
+ jz L_more_31_no_low /* none of the lowest bits is set */
- orl $1,%edx // record the fact in the extension
+ orl $1,%edx /* record the fact in the extension */
L_more_31_no_low:
movl %eax,%ebx
@@ -146,7 +146,7 @@ L_more_than_63:
jmp L_more_63_no_low
L_more_than_64:
- movl $1,%edx // The shifted nr always at least one '1'
+ movl $1,%edx /* The shifted nr always at least one '1' */
L_more_63_no_low:
xorl %ebx,%ebx
@@ -170,7 +170,7 @@ L_no_bit_lost:
incl EXP(%edi)
L_round_the_result:
- jmp FPU_round // Round the result
+ jmp FPU_round /* Round the result */
diff --git a/kernel/FPU-emu/reg_u_div.S b/drivers/FPU-emu/reg_u_div.S
index 2083bc5..49b1328 100644
--- a/kernel/FPU-emu/reg_u_div.S
+++ b/drivers/FPU-emu/reg_u_div.S
@@ -25,8 +25,8 @@
#include "control_w.h"
-// #define dSIGL(x) (x)
-// #define dSIGH(x) 4(x)
+/* #define dSIGL(x) (x) */
+/* #define dSIGH(x) 4(x) */
.data
@@ -94,9 +94,9 @@ xOp2_not_denorm:
_divide_kernel:
#ifdef PARANOID
-// testl $0x80000000, SIGH(%esi) // Dividend
-// je L_bugged
- testl $0x80000000, SIGH(%ebx) // Divisor
+/* testl $0x80000000, SIGH(%esi) // Dividend */
+/* je L_bugged */
+ testl $0x80000000, SIGH(%ebx) /* Divisor */
je L_bugged
#endif PARANOID
@@ -143,7 +143,7 @@ L_no_adjust:
rcrl %eax
L_no_overflow:
- jmp LRound_precision // Do the rounding as required
+ jmp LRound_precision /* Do the rounding as required */
/*---------------------------------------------------------------------------+
@@ -165,7 +165,7 @@ L_no_overflow:
L_Full_Division:
- // Save extended dividend in local register
+ /* Save extended dividend in local register */
movl SIGL(%esi),%eax
movl %eax,accum_2
movl SIGH(%esi),%eax
@@ -280,7 +280,7 @@ LPrevent_2nd_overflow:
#endif PARANOID
LDo_2nd_div:
- cmpl $0,%ecx // augmented denom msw
+ cmpl $0,%ecx /* augmented denom msw */
jnz LSecond_div_not_1
/* %ecx == 0, we are dividing by 1.0 */
@@ -348,11 +348,11 @@ LDo_3rd_32_bits:
movl accum_0,%eax
/* need to check for possible subsequent overflow */
- cmpl SIGH(%ebx),%edx // denom
+ cmpl SIGH(%ebx),%edx /* denom */
jb LRound_prep
ja LPrevent_3rd_overflow
- cmpl SIGL(%ebx),%eax // denom
+ cmpl SIGL(%ebx),%eax /* denom */
jb LRound_prep
LPrevent_3rd_overflow:
@@ -371,36 +371,38 @@ LPrevent_3rd_overflow:
movb $255,ovfl_flag /* Overflow -> 1.000 */
LRound_prep:
-// Prepare for rounding.
-// To test for rounding, we just need to compare 2*accum with the
-// denom.
+/*
+ * Prepare for rounding.
+ * To test for rounding, we just need to compare 2*accum with the
+ * denom.
+ */
movl accum_0,%ecx
movl accum_1,%edx
movl %ecx,%eax
orl %edx,%eax
- jz LRound_ovfl // The accumulator contains zero.
+ jz LRound_ovfl /* The accumulator contains zero. */
- // Multiply by 2
+ /* Multiply by 2 */
clc
rcll $1,%ecx
rcll $1,%edx
- jc LRound_large // No need to compare, denom smaller
+ jc LRound_large /* No need to compare, denom smaller */
subl SIGL(%ebx),%ecx
sbbl SIGH(%ebx),%edx
jnc LRound_not_small
- movl $0x70000000,%eax // Denom was larger
+ movl $0x70000000,%eax /* Denom was larger */
jmp LRound_ovfl
LRound_not_small:
jnz LRound_large
- movl $0x80000000,%eax // Remainder was exactly 1/2 denom
+ movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */
jmp LRound_ovfl
LRound_large:
- movl $0xff000000,%eax // Denom was smaller
+ movl $0xff000000,%eax /* Denom was smaller */
LRound_ovfl:
/* We are now ready to deal with rounding, but first we must get
@@ -411,12 +413,12 @@ LRound_ovfl:
incl EXP(%edi)
/* shift the mantissa right one bit */
- stc // Will set the ms bit
+ stc /* Will set the ms bit */
rcrl result_2
rcrl result_1
rcrl %eax
-// Round the result as required
+/* Round the result as required */
LRound_precision:
decl EXP(%edi) /* binary point between 1st & 2nd bits */
diff --git a/kernel/FPU-emu/reg_u_mul.S b/drivers/FPU-emu/reg_u_mul.S
index 5fa32a4..8824176 100644
--- a/kernel/FPU-emu/reg_u_mul.S
+++ b/drivers/FPU-emu/reg_u_mul.S
@@ -88,7 +88,7 @@ xOp2_not_denorm:
mull SIGH(%edi)
addl %eax,accum_1
adcl %edx,%ebx
-// adcl $0,%ecx // overflow here is not possible
+/* adcl $0,%ecx // overflow here is not possible */
movl SIGH(%esi),%eax
mull SIGL(%edi)
@@ -104,11 +104,11 @@ xOp2_not_denorm:
movl EXP(%esi),%eax /* Compute the exponent */
addl EXP(%edi),%eax
subl EXP_BIAS-1,%eax
-// Have now finished with the sources
- movl PARAM3,%edi // Point to the destination
+/* Have now finished with the sources */
+ movl PARAM3,%edi /* Point to the destination */
movl %eax,EXP(%edi)
-// Now make sure that the result is normalized
+/* Now make sure that the result is normalized */
testl $0x80000000,%ecx
jnz LResult_Normalised
diff --git a/kernel/FPU-emu/reg_u_sub.S b/drivers/FPU-emu/reg_u_sub.S
index 191f48a..a7b5d89 100644
--- a/kernel/FPU-emu/reg_u_sub.S
+++ b/drivers/FPU-emu/reg_u_sub.S
@@ -79,16 +79,16 @@ xOp2_not_denorm:
| Form a register holding the |
| smaller number |
+--------------------------------------*/
- movl SIGH(%edi),%eax // register ms word
- movl SIGL(%edi),%ebx // register ls word
+ movl SIGH(%edi),%eax /* register ms word */
+ movl SIGL(%edi),%ebx /* register ls word */
movl PARAM3,%edi /* destination */
movl EXP(%esi),%edx
movl %edx,EXP(%edi) /* Copy exponent to destination */
-// movb SIGN(%esi),%dl
-// movb %dl,SIGN(%edi) /* Copy the sign from the first arg */
+/* movb SIGN(%esi),%dl */
+/* movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */
- xorl %edx,%edx // register extension
+ xorl %edx,%edx /* register extension */
/*--------------------------------------+
| Shift the temporary register |
@@ -115,9 +115,9 @@ L_more_than_31:
shrd %cl,%eax,%edx
shr %cl,%eax
orl %ebx,%ebx
- jz L_more_31_no_low // none of the lowest bits is set
+ jz L_more_31_no_low /* none of the lowest bits is set */
- orl $1,%edx // record the fact in the extension
+ orl $1,%edx /* record the fact in the extension */
L_more_31_no_low:
movl %eax,%ebx
@@ -134,7 +134,7 @@ L_more_than_63:
cmpw $65,%cx
jnc L_more_than_64
- // Shift right by 64 bits
+ /* Shift right by 64 bits */
movl %eax,%edx
orl %ebx,%ebx
jz L_more_63_no_low
@@ -145,8 +145,8 @@ L_more_than_63:
L_more_than_64:
jne L_more_than_65
- // Shift right by 65 bits
- // Carry is clear if we get here
+ /* Shift right by 65 bits */
+ /* Carry is clear if we get here */
movl %eax,%edx
rcrl %edx
jnc L_shift_65_nc
@@ -162,7 +162,7 @@ L_shift_65_nc:
jmp L_more_63_no_low
L_more_than_65:
- movl $1,%edx // The shifted nr always at least one '1'
+ movl $1,%edx /* The shifted nr always at least one '1' */
L_more_63_no_low:
xorl %ebx,%ebx
@@ -200,11 +200,13 @@ L_subtr:
orl %ebx,%ebx
jnz L_shift_32 /* shift left 32 - 63 bits */
-// A rare case, the only one which is non-zero if we got here
-// is: 1000000 .... 0000
-// -0111111 .... 1111 1
-// --------------------
-// 0000000 .... 0000 1
+/*
+ * A rare case, the only one which is non-zero if we got here
+ * is: 1000000 .... 0000
+ * -0111111 .... 1111 1
+ * --------------------
+ * 0000000 .... 0000 1
+ */
cmpl $0x80000000,%edx
jnz L_must_be_zero
@@ -225,7 +227,7 @@ L_must_be_zero:
movl $0,EXP(%edi) /* exponent */
movl $0,SIGL(%edi)
movl $0,SIGH(%edi)
- jmp L_exit // %eax contains zero
+ jmp L_exit /* %eax contains zero */
L_shift_32:
movl %ebx,%eax
@@ -244,7 +246,7 @@ L_shift_1:
subl %ecx,EXP(%edi) /* Can get underflow here */
L_round:
- jmp FPU_round // Round the result
+ jmp FPU_round /* Round the result */
#ifdef PARANOID
diff --git a/kernel/FPU-emu/status_w.h b/drivers/FPU-emu/status_w.h
index 87521ff..87521ff 100644
--- a/kernel/FPU-emu/status_w.h
+++ b/drivers/FPU-emu/status_w.h
diff --git a/kernel/FPU-emu/version.h b/drivers/FPU-emu/version.h
index ce22bab..ce22bab 100644
--- a/kernel/FPU-emu/version.h
+++ b/drivers/FPU-emu/version.h
diff --git a/kernel/FPU-emu/wm_shrx.S b/drivers/FPU-emu/wm_shrx.S
index f0cd40f..59badea 100644
--- a/kernel/FPU-emu/wm_shrx.S
+++ b/drivers/FPU-emu/wm_shrx.S
@@ -46,9 +46,9 @@ _shrx:
/* less than 32 bits */
pushl %ebx
- movl (%esi),%ebx // lsl
- movl 4(%esi),%edx // msl
- xorl %eax,%eax // extension
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
shrd %cl,%ebx,%eax
shrd %cl,%edx,%ebx
shr %cl,%edx
@@ -64,8 +64,8 @@ L_more_than_31:
jnc L_more_than_63
subb $32,%cl
- movl (%esi),%eax // lsl
- movl 4(%esi),%edx // msl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
shrd %cl,%edx,%eax
shr %cl,%edx
movl %edx,(%esi)
@@ -79,7 +79,7 @@ L_more_than_63:
jnc L_more_than_95
subb $64,%cl
- movl 4(%esi),%eax // msl
+ movl 4(%esi),%eax /* msl */
shr %cl,%eax
xorl %edx,%edx
movl %edx,(%esi)
@@ -131,8 +131,8 @@ _shrxs:
is for small integers */
/* Shift by [32..63] bits */
subb $32,%cl
- movl (%esi),%eax // lsl
- movl 4(%esi),%edx // msl
+ movl (%esi),%eax /* lsl */
+ movl 4(%esi),%edx /* msl */
xorl %ebx,%ebx
shrd %cl,%eax,%ebx
shrd %cl,%edx,%eax
@@ -152,9 +152,9 @@ _shrxs:
/* Shift by [0..31] bits */
Ls_less_than_32:
- movl (%esi),%ebx // lsl
- movl 4(%esi),%edx // msl
- xorl %eax,%eax // extension
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%edx /* msl */
+ xorl %eax,%eax /* extension */
shrd %cl,%ebx,%eax
shrd %cl,%edx,%ebx
shr %cl,%edx
@@ -173,9 +173,9 @@ Ls_more_than_63:
jnc Ls_more_than_95
subb $64,%cl
- movl (%esi),%ebx // lsl
- movl 4(%esi),%eax // msl
- xorl %edx,%edx // extension
+ movl (%esi),%ebx /* lsl */
+ movl 4(%esi),%eax /* msl */
+ xorl %edx,%edx /* extension */
shrd %cl,%ebx,%edx
shrd %cl,%eax,%ebx
shr %cl,%eax
@@ -186,8 +186,8 @@ Ls_more_than_63:
orw %bx,%bx
setne %al
xorl %edx,%edx
- movl %edx,(%esi) // set to zero
- movl %edx,4(%esi) // set to zero
+ movl %edx,(%esi) /* set to zero */
+ movl %edx,4(%esi) /* set to zero */
popl %ebx
popl %esi
leave
diff --git a/kernel/FPU-emu/wm_sqrt.S b/drivers/FPU-emu/wm_sqrt.S
index 2f2d530..bc53aa5 100644
--- a/kernel/FPU-emu/wm_sqrt.S
+++ b/drivers/FPU-emu/wm_sqrt.S
@@ -35,7 +35,7 @@
*/
.align 4,0
accum_3:
- .long 0 // ms word
+ .long 0 /* ms word */
accum_2:
.long 0
accum_1:
@@ -43,16 +43,18 @@ accum_1:
accum_0:
.long 0
-// The de-normalised argument:
-// sq_2 sq_1 sq_0
-// b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
-// ^ binary point here
+/*
+ * The de-normalised argument:
+ * sq_2 sq_1 sq_0
+ * b b b b b b b ... b b b b b b .... b b b b 0 0 0 ... 0
+ * ^ binary point here
+ */
fsqrt_arg_2:
- .long 0 // ms word
+ .long 0 /* ms word */
fsqrt_arg_1:
.long 0
fsqrt_arg_0:
- .long 0 // ls word, at most the ms bit is set
+ .long 0 /* ls word, at most the ms bit is set */
.text
.align 2,144
@@ -72,7 +74,7 @@ _wm_sqrt:
movl SIGL(%esi),%ecx
xorl %edx,%edx
-// We use a rough linear estimate for the first guess..
+/* We use a rough linear estimate for the first guess.. */
cmpl EXP_BIAS,EXP(%esi)
jnz sqrt_arg_ge_2
@@ -82,14 +84,14 @@ _wm_sqrt:
rcrl $1,%edx
sqrt_arg_ge_2:
-// From here on, n is never accessed directly again until it is
-// replaced by the answer.
+/* From here on, n is never accessed directly again until it is */
+/* replaced by the answer. */
- movl %eax,fsqrt_arg_2 // ms word of n
+ movl %eax,fsqrt_arg_2 /* ms word of n */
movl %ecx,fsqrt_arg_1
movl %edx,fsqrt_arg_0
-// Make a linear first estimate
+/* Make a linear first estimate */
shrl $1,%eax
addl $0x40000000,%eax
movl $0xaaaaaaaa,%ecx
@@ -101,25 +103,27 @@ sqrt_arg_ge_2:
movl $0x80000000,%edx /* round up */
sqrt_prelim_no_adjust:
- movl %edx,%esi // Our first guess
+ movl %edx,%esi /* Our first guess */
/* We have now computed (approx) (2 + x) / 3, which forms the basis
for a few iterations of Newton's method */
- movl fsqrt_arg_2,%ecx // ms word
+ movl fsqrt_arg_2,%ecx /* ms word */
-// From our initial estimate, three iterations are enough to get us
-// to 30 bits or so. This will then allow two iterations at better
-// precision to complete the process.
+/*
+ * From our initial estimate, three iterations are enough to get us
+ * to 30 bits or so. This will then allow two iterations at better
+ * precision to complete the process.
+ */
-// Compute (g + n/g)/2 at each iteration (g is the guess).
- shrl %ecx // Doing this first will prevent a divide
- // overflow later.
+/* Compute (g + n/g)/2 at each iteration (g is the guess). */
+ shrl %ecx /* Doing this first will prevent a divide */
+ /* overflow later. */
- movl %ecx,%edx // msw of the arg / 2
- divl %esi // current estimate
- shrl %esi // divide by 2
- addl %eax,%esi // the new estimate
+ movl %ecx,%edx /* msw of the arg / 2 */
+ divl %esi /* current estimate */
+ shrl %esi /* divide by 2 */
+ addl %eax,%esi /* the new estimate */
movl %ecx,%edx
divl %esi
@@ -131,25 +135,27 @@ sqrt_prelim_no_adjust:
shrl %esi
addl %eax,%esi
-// Now that an estimate accurate to about 30 bits has been obtained (in %esi),
-// we improve it to 60 bits or so.
-
-// The strategy from now on is to compute new estimates from
-// guess := guess + (n - guess^2) / (2 * guess)
+/*
+ * Now that an estimate accurate to about 30 bits has been obtained (in %esi),
+ * we improve it to 60 bits or so.
+ *
+ * The strategy from now on is to compute new estimates from
+ * guess := guess + (n - guess^2) / (2 * guess)
+ */
-// First, find the square of the guess
+/* First, find the square of the guess */
movl %esi,%eax
mull %esi
-// guess^2 now in %edx:%eax
+/* guess^2 now in %edx:%eax */
movl fsqrt_arg_1,%ecx
subl %ecx,%eax
- movl fsqrt_arg_2,%ecx // ms word of normalized n
+ movl fsqrt_arg_2,%ecx /* ms word of normalized n */
sbbl %ecx,%edx
jnc sqrt_stage_2_positive
-// subtraction gives a negative result
-// negate the result before division
+/* subtraction gives a negative result */
+/* negate the result before division */
notl %edx
notl %eax
addl $1,%eax
@@ -175,22 +181,22 @@ sqrt_stage_2_positive:
adcl $0,%ecx
sqrt_stage_2_finish:
- sarl $1,%ecx // divide by 2
+ sarl $1,%ecx /* divide by 2 */
rcrl $1,%eax
- // Form the new estimate in %esi:%edi
+ /* Form the new estimate in %esi:%edi */
movl %eax,%edi
addl %ecx,%esi
- jnz sqrt_stage_2_done // result should be [1..2)
+ jnz sqrt_stage_2_done /* result should be [1..2) */
#ifdef PARANOID
-// It should be possible to get here only if the arg is ffff....ffff
+/* It should be possible to get here only if the arg is ffff....ffff */
cmp $0xffffffff,fsqrt_arg_1
jnz sqrt_stage_2_error
#endif PARANOID
-// The best rounded result.
+/* The best rounded result. */
xorl %eax,%eax
decl %eax
movl %eax,%edi
@@ -206,10 +212,10 @@ sqrt_stage_2_error:
sqrt_stage_2_done:
-// Now the square root has been computed to better than 60 bits
+/* Now the square root has been computed to better than 60 bits */
-// Find the square of the guess
- movl %edi,%eax // ls word of guess
+/* Find the square of the guess */
+ movl %edi,%eax /* ls word of guess */
mull %edi
movl %edx,accum_1
@@ -224,24 +230,24 @@ sqrt_stage_2_done:
adcl %edx,accum_2
adcl $0,accum_3
-// movl %esi,%eax
-// mull %edi
+/* movl %esi,%eax */
+/* mull %edi */
addl %eax,accum_1
adcl %edx,accum_2
adcl $0,accum_3
-// guess^2 now in accum_3:accum_2:accum_1
+/* guess^2 now in accum_3:accum_2:accum_1 */
- movl fsqrt_arg_0,%eax // get normalized n
+ movl fsqrt_arg_0,%eax /* get normalized n */
subl %eax,accum_1
movl fsqrt_arg_1,%eax
sbbl %eax,accum_2
- movl fsqrt_arg_2,%eax // ms word of normalized n
+ movl fsqrt_arg_2,%eax /* ms word of normalized n */
sbbl %eax,accum_3
jnc sqrt_stage_3_positive
-// subtraction gives a negative result
-// negate the result before division
+/* subtraction gives a negative result */
+/* negate the result before division */
notl accum_1
notl accum_2
notl accum_3
@@ -249,7 +255,7 @@ sqrt_stage_2_done:
adcl $0,accum_2
#ifdef PARANOID
- adcl $0,accum_3 // This must be zero
+ adcl $0,accum_3 /* This must be zero */
jz sqrt_stage_3_no_error
sqrt_stage_3_error:
@@ -267,10 +273,10 @@ sqrt_stage_3_no_error:
movl %edx,%eax
divl %esi
- sarl $1,%ecx // divide by 2
+ sarl $1,%ecx /* divide by 2 */
rcrl $1,%eax
- // prepare to round the result
+ /* prepare to round the result */
addl %ecx,%edi
adcl $0,%esi
@@ -286,15 +292,15 @@ sqrt_stage_3_positive:
movl %edx,%eax
divl %esi
- sarl $1,%ecx // divide by 2
+ sarl $1,%ecx /* divide by 2 */
rcrl $1,%eax
- // prepare to round the result
+ /* prepare to round the result */
- notl %eax // Negate the correction term
+ notl %eax /* Negate the correction term */
notl %ecx
addl $1,%eax
- adcl $0,%ecx // carry here ==> correction == 0
+ adcl $0,%ecx /* carry here ==> correction == 0 */
adcl $0xffffffff,%esi
addl %ecx,%edi
@@ -302,9 +308,11 @@ sqrt_stage_3_positive:
sqrt_stage_3_finished:
-// The result in %esi:%edi:%esi should be good to about 90 bits here,
-// and the rounding information here does not have sufficient accuracy
-// in a few rare cases.
+/*
+ * The result in %esi:%edi:%esi should be good to about 90 bits here,
+ * and the rounding information here does not have sufficient accuracy
+ * in a few rare cases.
+ */
cmpl $0xffffffe0,%eax
ja sqrt_near_exact_x
@@ -318,31 +326,33 @@ sqrt_stage_3_finished:
jb sqrt_get_more_precision
sqrt_round_result:
-// Set up for rounding operations
+/* Set up for rounding operations */
movl %eax,%edx
movl %esi,%eax
movl %edi,%ebx
movl PARAM1,%edi
- movl EXP_BIAS,EXP(%edi) // Result is in [1.0 .. 2.0)
+ movl EXP_BIAS,EXP(%edi) /* Result is in [1.0 .. 2.0) */
movl PARAM2,%ecx
jmp FPU_round_sqrt
sqrt_near_exact_x:
-// First, the estimate must be rounded up.
+/* First, the estimate must be rounded up. */
addl $1,%edi
adcl $0,%esi
sqrt_near_exact:
-// This is an easy case because x^1/2 is monotonic.
-// We need just find the square of our estimate, compare it
-// with the argument, and deduce whether our estimate is
-// above, below, or exact. We use the fact that the estimate
-// is known to be accurate to about 90 bits.
- movl %edi,%eax // ls word of guess
+/*
+ * This is an easy case because x^1/2 is monotonic.
+ * We need just find the square of our estimate, compare it
+ * with the argument, and deduce whether our estimate is
+ * above, below, or exact. We use the fact that the estimate
+ * is known to be accurate to about 90 bits.
+ */
+ movl %edi,%eax /* ls word of guess */
mull %edi
- movl %edx,%ebx // 2nd ls word of square
- movl %eax,%ecx // ls word of square
+ movl %edx,%ebx /* 2nd ls word of square */
+ movl %eax,%ecx /* ls word of square */
movl %edi,%eax
mull %esi
@@ -370,17 +380,17 @@ sqrt_near_exact_ok:
or %ebx,%edx
jnz sqrt_near_exact_large
-// Our estimate is exactly the right answer
+/* Our estimate is exactly the right answer */
xorl %eax,%eax
jmp sqrt_round_result
sqrt_near_exact_small:
-// Our estimate is too small
+/* Our estimate is too small */
movl $0x000000ff,%eax
jmp sqrt_round_result
sqrt_near_exact_large:
-// Our estimate is too large, we need to decrement it
+/* Our estimate is too large, we need to decrement it */
subl $1,%edi
sbbl $0,%esi
movl $0xffffff00,%eax
@@ -388,25 +398,25 @@ sqrt_near_exact_large:
sqrt_get_more_precision:
-// This case is almost the same as the above, except we start
-// with an extra bit of precision in the estimate.
- stc // The extra bit.
- rcll $1,%edi // Shift the estimate left one bit
+/* This case is almost the same as the above, except we start */
+/* with an extra bit of precision in the estimate. */
+ stc /* The extra bit. */
+ rcll $1,%edi /* Shift the estimate left one bit */
rcll $1,%esi
- movl %edi,%eax // ls word of guess
+ movl %edi,%eax /* ls word of guess */
mull %edi
- movl %edx,%ebx // 2nd ls word of square
- movl %eax,%ecx // ls word of square
+ movl %edx,%ebx /* 2nd ls word of square */
+ movl %eax,%ecx /* ls word of square */
movl %edi,%eax
mull %esi
addl %eax,%ebx
addl %eax,%ebx
-// Put our estimate back to its original value
- stc // The ms bit.
- rcrl $1,%esi // Shift the estimate left one bit
+/* Put our estimate back to its original value */
+ stc /* The ms bit. */
+ rcrl $1,%esi /* Shift the estimate left one bit */
rcrl $1,%edi
#ifdef PARANOID
@@ -430,16 +440,16 @@ sqrt_more_prec_ok:
or %ebx,%ecx
jnz sqrt_more_prec_large
-// Our estimate is exactly the right answer
+/* Our estimate is exactly the right answer */
movl $0x80000000,%eax
jmp sqrt_round_result
sqrt_more_prec_small:
-// Our estimate is too small
+/* Our estimate is too small */
movl $0x800000ff,%eax
jmp sqrt_round_result
sqrt_more_prec_large:
-// Our estimate is too large
+/* Our estimate is too large */
movl $0x7fffff00,%eax
jmp sqrt_round_result
diff --git a/kernel/chr_drv/Makefile b/drivers/Makefile
index d864667..fdb28d2 100644
--- a/kernel/chr_drv/Makefile
+++ b/drivers/Makefile
@@ -1,14 +1,14 @@
#
-# Makefile for the kernel character device drivers.
+# Makefile for the linux kernel 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).
#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
+# Note 2! The CFLAGS definitions are now in the main makefile...
+.S.s:
+ $(CPP) -traditional $< -o $*.s
.c.s:
$(CC) $(CFLAGS) -S $<
.s.o:
@@ -16,28 +16,30 @@
.c.o:
$(CC) $(CFLAGS) -c $<
-SUBDIRS= sound
+SUBDIRS = block char net
+
+ifdef CONFIG_MATH_EMULATION
+SUBDIRS := $(SUBDIRS) FPU-emu
+endif
-OBJS = tty_io.o console.o keyboard.o serial.o \
- tty_ioctl.o pty.o lp.o vt.o mem.o mouse.o \
- busmouse.o psaux.o msbusmouse.o atixlmouse.o \
- tpqic02.o defkeymap.o
+ifdef CONFIG_SCSI
+SUBDIRS := $(SUBDIRS) scsi
+endif
-all: chr_drv.a subdirs
+ifdef CONFIG_SOUND
+SUBDIRS := $(SUBDIRS) sound
+endif
-chr_drv.a: $(OBJS)
- $(AR) rcs chr_drv.a $(OBJS)
- sync
+all: driversubdirs
-subdirs: dummy
+driversubdirs: dummy
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
clean:
rm -f core *.o *.a *.s
- for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean) || exit; done
+ for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
dep:
- $(CPP) -M *.c > .depend
for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
dummy:
@@ -48,3 +50,4 @@ dummy:
ifeq (.depend,$(wildcard .depend))
include .depend
endif
+
diff --git a/drivers/block/Makefile b/drivers/block/Makefile
new file mode 100644
index 0000000..ab80be1
--- /dev/null
+++ b/drivers/block/Makefile
@@ -0,0 +1,68 @@
+#
+# Makefile for the 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).
+#
+# Note 2! The CFLAGS definition is now inherited from the
+# parent makefile.
+#
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+#
+# Note : at this point, these files are compiled on all systems.
+# In the future, some of these should be built conditionally.
+#
+
+OBJS := ll_rw_blk.o floppy.o ramdisk.o genhd.o
+SRCS := ll_rw_blk.c floppy.c ramdisk.c genhd.c
+
+ifdef CONFIG_CDU31A
+OBJS := $(OBJS) cdu31a.o
+SRCS := $(SRCS) cdu31a.c
+endif
+
+ifdef CONFIG_MCD
+OBJS := $(OBJS) mcd.o
+SRCS := $(SRCS) mcd.c
+endif
+
+ifdef CONFIG_BLK_DEV_HD
+OBJS := $(OBJS) hd.o
+SRCS := $(SRCS) hd.c
+endif
+
+ifdef CONFIG_BLK_DEV_XD
+OBJS := $(OBJS) xd.o
+SRCS := $(SRCS) xd.c
+endif
+
+all: block.a
+
+block.a: $(OBJS)
+ rm -f block.a
+ $(AR) rcs block.a $(OBJS)
+ sync
+
+clean:
+ rm -f core *.o *.a *.s
+ for i in $(ALL_SUBDIRS); do (cd $$i && $(MAKE) clean); done
+
+dep:
+ $(CPP) -M $(SRCS) > .depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/kernel/blk_drv/blk.h b/drivers/block/blk.h
index 0f5cb8f..0f5cb8f 100644
--- a/kernel/blk_drv/blk.h
+++ b/drivers/block/blk.h
diff --git a/kernel/blk_drv/cdu31a.c b/drivers/block/cdu31a.c
index 0267039..64d90fc 100644
--- a/kernel/blk_drv/cdu31a.c
+++ b/drivers/block/cdu31a.c
@@ -59,8 +59,6 @@
*/
-#include <linux/config.h>
-#ifdef CONFIG_CDU31A
#include <linux/errno.h>
#include <linux/signal.h>
@@ -1702,4 +1700,3 @@ cdu31a_init(unsigned long mem_start, unsigned long mem_end)
return mem_start;
}
-#endif
diff --git a/kernel/blk_drv/floppy.c b/drivers/block/floppy.c
index 493571e..493571e 100644
--- a/kernel/blk_drv/floppy.c
+++ b/drivers/block/floppy.c
diff --git a/kernel/blk_drv/genhd.c b/drivers/block/genhd.c
index 1681d2b..1681d2b 100644
--- a/kernel/blk_drv/genhd.c
+++ b/drivers/block/genhd.c
diff --git a/kernel/blk_drv/hd.c b/drivers/block/hd.c
index 9858b32..5651176 100644
--- a/kernel/blk_drv/hd.c
+++ b/drivers/block/hd.c
@@ -16,8 +16,6 @@
* in the early extended-partition checks and added DM partitions
*/
-#include <linux/config.h>
-#ifdef CONFIG_BLK_DEV_HD
#define HD_IRQ 14
@@ -29,6 +27,7 @@
#include <linux/kernel.h>
#include <linux/hdreg.h>
#include <linux/genhd.h>
+#include <linux/config.h>
#define REALLY_SLOW_IO
#include <asm/system.h>
@@ -803,4 +802,3 @@ static int revalidate_hddisk(int dev, int maxusage)
return 0;
}
-#endif
diff --git a/kernel/blk_drv/ll_rw_blk.c b/drivers/block/ll_rw_blk.c
index 4920317..7ffcd76 100644
--- a/kernel/blk_drv/ll_rw_blk.c
+++ b/drivers/block/ll_rw_blk.c
@@ -258,8 +258,8 @@ void ll_rw_page(int rw, int dev, int page, char * buffer)
printk("Can't page to read-only device 0x%X\n",dev);
return;
}
- cli();
repeat:
+ cli();
req = request+NR_REQUEST;
while (--req >= request)
if (req->dev<0)
@@ -268,9 +268,9 @@ repeat:
sleep_on(&wait_for_request);
goto repeat;
}
- sti();
/* fill up the request-info, and add it to the queue */
req->dev = dev;
+ sti();
req->cmd = rw;
req->errors = 0;
req->sector = page<<3;
@@ -391,6 +391,7 @@ void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf)
for (i=0; i<nb; i++, buf += buffersize)
{
repeat:
+ cli();
req = request+NR_REQUEST;
while (--req >= request)
if (req->dev<0)
@@ -399,8 +400,8 @@ repeat:
sleep_on(&wait_for_request);
goto repeat;
}
-
req->dev = dev;
+ sti();
req->cmd = rw;
req->errors = 0;
req->sector = (b[i] * buffersize) >> 9;
diff --git a/kernel/blk_drv/mcd.c b/drivers/block/mcd.c
index d05c872..e6a6206 100644
--- a/kernel/blk_drv/mcd.c
+++ b/drivers/block/mcd.c
@@ -30,8 +30,6 @@
(Jon Tombs <jon@robots.ox.ac.uk>)
*/
-#include <linux/config.h>
-#ifdef CONFIG_MCD
#include <linux/errno.h>
#include <linux/signal.h>
@@ -522,6 +520,7 @@ do_mcd_request(void)
unsigned int nsect;
repeat:
+ if (!(CURRENT) || CURRENT->dev < 0) return;
INIT_REQUEST;
dev = MINOR(CURRENT->dev);
block = CURRENT->sector;
@@ -1193,4 +1192,3 @@ Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame);
return limit > 0 ? 0 : -1;
}
-#endif
diff --git a/kernel/blk_drv/ramdisk.c b/drivers/block/ramdisk.c
index 49b1302..2fd4343 100644
--- a/kernel/blk_drv/ramdisk.c
+++ b/drivers/block/ramdisk.c
@@ -139,7 +139,8 @@ void rd_load(void)
*((struct minix_super_block *) bh->b_data);
brelse(bh);
nblocks = s.s_nzones << s.s_log_zone_size;
- if (s.s_magic != MINIX_SUPER_MAGIC) {
+ if (s.s_magic != MINIX_SUPER_MAGIC &&
+ s.s_magic != MINIX_SUPER_MAGIC2) {
printk("RAMDISK: trying old-style RAM image.\n");
continue;
}
diff --git a/kernel/blk_drv/xd.c b/drivers/block/xd.c
index a8532f0..a2fe529 100644
--- a/kernel/blk_drv/xd.c
+++ b/drivers/block/xd.c
@@ -10,8 +10,6 @@
* Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst.
*/
-#include <linux/config.h>
-#ifdef CONFIG_BLK_DEV_XD
#include <linux/errno.h>
#include <linux/sched.h>
@@ -49,21 +47,26 @@ XD_INFO xd_info[XD_MAXDRIVES];
The controllers directly supported at the moment are: DTC 5150x, WD 1004A27X, ST11M/R and override. If your controller is
made by the same manufacturer as one of these, try using the same init routines as they do. If that doesn't work, your
best bet is to use the "override" routines. These routines use a "portable" method of getting the disk's geometry, and
- may work with your card. If none of these seem to work, try sending me some email and I'll see what I can do <grin>. */
+ may work with your card. If none of these seem to work, try sending me some email and I'll see what I can do <grin>.
+
+ NOTE: You can now specify your XT controller's parameters from the command line in the form xd=TYPE,IRQ,IO,DMA. The driver
+ should be able to detect your drive's geometry from this info. (eg: xd=0,5,0x320,3 is the "standard"). */
static XD_SIGNATURE xd_sigs[] = {
- { 0x0000,"Override geometry handler",xd_override_init_controller,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
-#ifndef XD_OVERRIDE
- { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc5150x_init_controller,xd_dtc5150x_init_drive," DTC 5150X" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
- { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd1004a27x_init_controller,xd_wd1004a27x_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
- { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd1004a27x_init_controller,xd_wd1004a27x_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
- { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate11_init_controller,xd_seagate11_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
- { 0x0010,"ST11R BIOS",xd_seagate11_init_controller,xd_seagate11_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
-#endif XD_OVERRIDE
+ { 0x0000,"Override geometry handler",NULL,xd_override_init_drive,"n unknown" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
+ { 0x000B,"CXD23A Not an IBM ROM (C)Copyright Data Technology Corp 12/03/88",xd_dtc_init_controller,xd_dtc_init_drive," DTC 5150X" }, /* Pat Mackinlay, smackinla@cc.curtin.edu.au (pat@gu.uwa.edu.au) */
+ { 0x0008,"07/15/86 (C) Copyright 1986 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1002AWX1" }, /* Ian Justman, citrus!ianj@csusac.ecs.csus.edu */
+ { 0x0008,"06/24/88 (C) Copyright 1988 Western Digital Corp",xd_wd_init_controller,xd_wd_init_drive," Western Digital 1004A27X" }, /* Dave Thaler, thalerd@engin.umich.edu */
+ { 0x0008,"06/24/88(C) Copyright 1988 Western Digital Corp.",xd_wd_init_controller,xd_wd_init_drive," Western Digital WDXT-GEN2" }, /* Dan Newcombe, newcombe@aa.csc.peachnet.edu */
+ { 0x0015,"SEAGATE ST11 BIOS REVISION",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Salvador Abreu, spa@fct.unl.pt */
+ { 0x0010,"ST11R BIOS",xd_seagate_init_controller,xd_seagate_init_drive," Seagate ST11M/R" }, /* Risto Kankkunen, risto.kankkunen@cs.helsinki.fi */
+};
+static u_char *xd_bases[] =
+{
+ (u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xCC000,
+ (u_char *) 0xCE000,(u_char *) 0xD0000,(u_char *) 0xD8000,
+ (u_char *) 0xE0000
};
-#ifndef XD_OVERRIDE
-static u_char *xd_bases[] = { (u_char *) 0xC8000,(u_char *) 0xCA000,(u_char *) 0xD0000,(u_char *) 0xD8000,(u_char *) 0xE0000 };
-#endif XD_OVERRIDE
static struct hd_struct xd[XD_MAXDRIVES << 6];
static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 };
@@ -73,8 +76,8 @@ static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,
static struct wait_queue *xd_wait_int = NULL,*xd_wait_open = NULL;
static u_char xd_valid[XD_MAXDRIVES] = { 0,0 };
-static u_char xd_drives = 0,xd_irq,xd_dma,xd_maxsectors;
-static u_short xd_iobase;
+static u_char xd_drives = 0,xd_irq = 0,xd_dma = 0,xd_maxsectors,xd_override = 0,xd_type = 0;
+static u_short xd_iobase = 0;
/* xd_init: grab the IRQ and DMA channel and initialise the drives */
u_long xd_init (u_long mem_start,u_long mem_end)
@@ -93,7 +96,8 @@ u_long xd_init (u_long mem_start,u_long mem_end)
if (xd_detect(&controller,&address)) {
printk("xd_init: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,controller,address);
- xd_sigs[controller].init_controller(address);
+ if (controller)
+ xd_sigs[controller].init_controller(address);
xd_drives = xd_initdrives(xd_sigs[controller].init_drive);
printk("xd_init: detected %d hard drive%s (using IRQ%d & DMA%d)\n",xd_drives,xd_drives == 1 ? "" : "s",xd_irq,xd_dma);
@@ -115,9 +119,15 @@ u_long xd_init (u_long mem_start,u_long mem_end)
/* xd_detect: scan the possible BIOS ROM locations for the signature strings */
static u_char xd_detect (u_char *controller,u_char **address)
{
-#ifndef XD_OVERRIDE
u_char i,j,found = 0;
+ if (xd_override)
+ {
+ *controller = xd_type;
+ *address = NULL;
+ return(1);
+ }
+
for (i = 0; i < (sizeof(xd_bases) / sizeof(xd_bases[0])) && !found; i++)
for (j = 1; j < (sizeof(xd_sigs) / sizeof(xd_sigs[0])) && !found; j++)
if (!memcmp(xd_bases[i] + xd_sigs[j].offset,xd_sigs[j].string,strlen(xd_sigs[j].string))) {
@@ -126,11 +136,6 @@ static u_char xd_detect (u_char *controller,u_char **address)
found++;
}
return (found);
-#else
- *controller = 0;
- *address = NULL;
- return (1);
-#endif XD_OVERRIDE
}
/* xd_geninit: set up the "raw" device entries in the table */
@@ -278,7 +283,7 @@ static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,
#ifdef DEBUG_READWRITE
printk("xd_readwrite: operation = %s, drive = %d, buffer = 0x%X, block = %d, count = %d\n",operation == READ ? "read" : "write",drive,buffer,block,count);
-#endif DEBUG_READWRITE
+#endif /* DEBUG_READWRITE */
control = xd_info[drive].control;
while (count) {
@@ -291,7 +296,7 @@ static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,
#ifdef DEBUG_READWRITE
printk("xd_readwrite: drive = %d, head = %d, cylinder = %d, sector = %d, count = %d\n",drive,head,cylinder,sector,temp);
-#endif DEBUG_READWRITE
+#endif /* DEBUG_READWRITE */
mode = xd_setup_dma(operation == READ ? DMA_MODE_READ : DMA_MODE_WRITE,(u_char *)buffer,temp * 0x200);
xd_build(cmdblk,operation == READ ? CMD_READ : CMD_WRITE,drive,head,cylinder,sector,temp & 0xFF,control);
@@ -331,7 +336,7 @@ static void xd_interrupt_handler (int unused)
if (inb(XD_STATUS) & STAT_INTERRUPT) { /* check if it was our device */
#ifdef DEBUG_OTHER
printk("xd_interrupt_handler: interrupt detected\n");
-#endif DEBUG_OTHER
+#endif /* DEBUG_OTHER */
outb(0,XD_CONTROL); /* acknowledge interrupt */
wake_up(&xd_wait_int); /* and wake up sleeping processes */
}
@@ -346,7 +351,7 @@ static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
if (((u_int) buffer & 0xFFFF0000) != ((u_int) buffer + count) & 0xFFFF0000) {
#ifdef DEBUG_OTHER
printk("xd_setup_dma: using PIO, transfer overlaps 64k boundary\n");
-#endif DEBUG_OTHER
+#endif /* DEBUG_OTHER */
return (PIO_MODE);
}
disable_dma(xd_dma);
@@ -359,7 +364,7 @@ static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count)
}
#ifdef DEBUG_OTHER
printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n");
-#endif DEBUG_OTHER
+#endif /* DEBUG_OTHER */
return (PIO_MODE);
}
@@ -394,7 +399,7 @@ static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outd
#ifdef DEBUG_COMMAND
printk("xd_command: command = 0x%X, mode = 0x%X, indata = 0x%X, outdata = 0x%X, sense = 0x%X\n",command,mode,indata,outdata,sense);
-#endif DEBUG_COMMAND
+#endif /* DEBUG_COMMAND */
outb(0,XD_SELECT);
outb(mode,XD_CONTROL);
@@ -443,7 +448,7 @@ static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outd
#ifdef DEBUG_COMMAND
printk("xd_command: completed with csb = 0x%X\n",csb);
-#endif DEBUG_COMMAND
+#endif /* DEBUG_COMMAND */
return (csb & CSB_ERROR);
}
@@ -462,12 +467,13 @@ static u_char xd_initdrives (void (*init_drive)(u_char drive))
return (count);
}
-#ifndef XD_OVERRIDE
-static void xd_dtc5150x_init_controller (u_char *address)
+static void xd_dtc_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xCA000: xd_iobase = 0x324; break;
+ default: printk("xd_dtc_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
}
xd_irq = 5; /* the IRQ _can_ be changed on this card, but requires a hardware mod */
xd_dma = 3;
@@ -476,7 +482,7 @@ static void xd_dtc5150x_init_controller (u_char *address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_dtc5150x_init_drive (u_char drive)
+static void xd_dtc_init_drive (u_char drive)
{
u_char cmdblk[6],buf[64];
@@ -489,34 +495,38 @@ static void xd_dtc5150x_init_drive (u_char drive)
xd_info[drive].rwrite = ((u_short *) (buf + 1))[0x05]; /* reduced write */
xd_info[drive].precomp = ((u_short *) (buf + 1))[0x06]; /* write precomp */
xd_info[drive].ecc = buf[0x0F]; /* ecc length */
-#endif 0
+#endif /* 0 */
xd_info[drive].control = 0; /* control byte */
xd_setparam(CMD_DTCSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf + 1))[0x05],((u_short *) (buf + 1))[0x06],buf[0x0F]);
xd_build(cmdblk,CMD_DTCSETSTEP,drive,0,0,0,0,7);
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
- printk("xd_dtc5150x_init_drive: error setting step rate for drive %d\n",drive);
+ printk("xd_dtc_init_drive: error setting step rate for drive %d\n",drive);
}
else
- printk("xd_dtc5150x_init_drive: error reading geometry for drive %d\n",drive);
+ printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive);
}
-static void xd_wd1004a27x_init_controller (u_char *address)
+static void xd_wd_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xCA000: xd_iobase = 0x324; break;
+ case 0xCC000: xd_iobase = 0x328; break;
+ case 0xCE000: xd_iobase = 0x32C; break;
case 0xD0000: xd_iobase = 0x328; break;
case 0xD8000: xd_iobase = 0x32C; break;
+ default: printk("xd_wd_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
}
xd_irq = 5; /* don't know how to auto-detect this yet */
xd_dma = 3;
xd_maxsectors = 0x01; /* this one doesn't wrap properly either... */
- outb(0,XD_RESET); /* reset the controller */
+ /* outb(0,XD_RESET); */ /* reset the controller */
}
-static void xd_wd1004a27x_init_drive (u_char drive)
+static void xd_wd_init_drive (u_char drive)
{
u_char cmdblk[6],buf[0x200];
@@ -529,22 +539,24 @@ static void xd_wd1004a27x_init_drive (u_char drive)
xd_info[drive].rwrite = ((u_short *) (buf))[0xD8]; /* reduced write */
xd_info[drive].wprecomp = ((u_short *) (buf))[0xDA]; /* write precomp */
xd_info[drive].ecc = buf[0x1B4]; /* ecc length */
-#endif 0
+#endif /* 0 */
xd_info[drive].control = buf[0x1B5]; /* control byte */
xd_setparam(CMD_WDSETPARAM,drive,xd_info[drive].heads,xd_info[drive].cylinders,((u_short *) (buf))[0xD8],((u_short *) (buf))[0xDA],buf[0x1B4]);
}
else
- printk("xd_wd1004a27x_init_drive: error reading geometry for drive %d\n",drive);
+ printk("xd_wd_init_drive: error reading geometry for drive %d\n",drive);
}
-static void xd_seagate11_init_controller (u_char *address)
+static void xd_seagate_init_controller (u_char *address)
{
switch ((u_long) address) {
case 0xC8000: xd_iobase = 0x320; break;
case 0xD0000: xd_iobase = 0x324; break;
case 0xD8000: xd_iobase = 0x328; break;
case 0xE0000: xd_iobase = 0x32C; break;
+ default: printk("xd_seagate_init_controller: unsupported BIOS address %p\n",address);
+ xd_iobase = 0x320; break;
}
xd_irq = 5; /* the IRQ and DMA channel are fixed on the Seagate controllers */
xd_dma = 3;
@@ -553,7 +565,7 @@ static void xd_seagate11_init_controller (u_char *address)
outb(0,XD_RESET); /* reset the controller */
}
-static void xd_seagate11_init_drive (u_char drive)
+static void xd_seagate_init_drive (u_char drive)
{
u_char cmdblk[6],buf[0x200];
@@ -565,19 +577,7 @@ static void xd_seagate11_init_drive (u_char drive)
xd_info[drive].control = 0; /* control byte */
}
else
- printk("xd_seagate11_init_drive: error reading geometry from drive %d\n",drive);
-}
-#endif XD_OVERRIDE
-
-/* xd_override_init_controller: sets appropriate values for unknown controllers. */
-static void xd_override_init_controller (u_char *address)
-{
- xd_iobase = 0x320; /* standard setting */
- xd_irq = 5; /* ditto */
- xd_dma = 3; /* ditto */
- xd_maxsectors = 0x01;
-
- outb(0,XD_RESET); /* reset the controller */
+ printk("xd_seagate_init_drive: error reading geometry from drive %d\n",drive);
}
/* xd_override_init_drive: this finds disk geometry in a "binary search" style, narrowing in on the "correct" number of heads
@@ -604,7 +604,19 @@ static void xd_override_init_drive (u_char drive)
xd_info[drive].control = 0;
}
-#ifndef XD_OVERRIDE
+/* xd_setup: initialise from command line parameters */
+void xd_setup (char *command,int *integers)
+{
+ xd_override = 1;
+
+ xd_type = integers[1];
+ xd_irq = integers[2];
+ xd_iobase = integers[3];
+ xd_dma = integers[4];
+
+ xd_maxsectors = 0x01;
+}
+
/* xd_setparam: set the drive characteristics */
static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc)
{
@@ -623,6 +635,4 @@ static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylind
if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2))
printk("xd_setparam: error setting characteristics for drive %d\n",drive);
}
-#endif XD_OVERRIDE
-#endif CONFIG_BLK_DEV_XD
diff --git a/drivers/char/Makefile b/drivers/char/Makefile
new file mode 100644
index 0000000..52651bb
--- /dev/null
+++ b/drivers/char/Makefile
@@ -0,0 +1,94 @@
+#
+# Makefile for the kernel character 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).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+#
+
+.c.s:
+ $(CC) $(CFLAGS) -S $<
+.s.o:
+ $(AS) -c -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c $<
+
+OBJS = tty_io.o console.o keyboard.o serial.o \
+ tty_ioctl.o pty.o vt.o mem.o \
+ defkeymap.o
+
+SRCS = tty_io.c console.c keyboard.c serial.c \
+ tty_ioctl.c pty.c vt.c mem.c \
+ defkeymap.c
+
+
+ifdef CONFIG_ATIXL_BUSMOUSE
+M = y
+OBJS := $(OBJS) atixlmouse.o
+SRCS := $(SRCS) atixlmouse.c
+endif
+
+ifdef CONFIG_BUSMOUSE
+M = y
+OBJS := $(OBJS) busmouse.o
+SRCS := $(SRCS) busmouse.c
+endif
+
+ifdef CONFIG_PRINTER
+OBJS := $(OBJS) lp.o
+SRCS := $(SRCS) lp.c
+endif
+
+ifdef CONFIG_MS_BUSMOUSE
+M = y
+OBJS := $(OBJS) msbusmouse.o
+SRCS := $(SRCS) msbusmouse.c
+endif
+
+ifdef CONFIG_QUICKPORT_MOUSE
+CONFIG_PSMOUSE = CONFIG_PSMOUSE
+endif
+
+ifdef CONFIG_PSMOUSE
+M = y
+OBJS := $(OBJS) psaux.o
+SRCS := $(SRCS) psaux.c
+endif
+
+ifdef CONFIG_TAPE_QIC02
+OBJS := $(OBJS) tpqic02.o
+SRCS := $(SRCS) tpqic02.c
+endif
+
+ifdef M
+OBJS := $(OBJS) mouse.o
+SRCS := $(SRCS) mouse.c
+endif
+
+all: char.a
+
+char.a: $(OBJS)
+ $(AR) rcs char.a $(OBJS)
+ sync
+
+defkeymap.c: defkeymap.map
+ ./loadkeys defkeymap.map
+ ./mktable > defkeymap.c
+
+clean:
+ rm -f core *.o *.a *.s
+
+dep:
+ $(CPP) -M $(SRCS) > .depend
+
+dummy:
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/kernel/chr_drv/atixlmouse.c b/drivers/char/atixlmouse.c
index 350e557..350e557 100644
--- a/kernel/chr_drv/atixlmouse.c
+++ b/drivers/char/atixlmouse.c
diff --git a/kernel/chr_drv/busmouse.c b/drivers/char/busmouse.c
index 79703b4..79703b4 100644
--- a/kernel/chr_drv/busmouse.c
+++ b/drivers/char/busmouse.c
diff --git a/kernel/chr_drv/console.c b/drivers/char/console.c
index cd8523c..cfe6b66 100644
--- a/kernel/chr_drv/console.c
+++ b/drivers/char/console.c
@@ -73,6 +73,7 @@ static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' };
extern void vt_init(void);
extern void register_console(void (*proc)(const char *));
+extern void compute_shiftstate(void);
unsigned long video_num_columns; /* Number of text columns */
unsigned long video_num_lines; /* Number of test lines */
@@ -224,9 +225,9 @@ static unsigned char * translations[] = {
"\040\255\233\234\376\235\174\025\376\376\246\256\252\055\376\376"
"\370\361\375\376\376\346\024\371\376\376\247\257\254\253\376\250"
"\376\376\376\376\216\217\222\200\376\220\376\376\376\376\376\376"
- "\376\245\376\376\376\376\231\376\235\376\376\376\232\376\376\341"
+ "\376\245\376\376\376\376\231\376\350\376\376\376\232\376\376\341"
"\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213"
- "\376\244\225\242\223\376\224\366\233\227\243\226\201\376\376\230",
+ "\376\244\225\242\223\376\224\366\355\227\243\226\201\376\376\230",
/* vt100 graphics */
(unsigned char *)
"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"
@@ -1511,6 +1512,7 @@ void update_screen(int new_console)
set_origin(fg_console);
set_cursor(new_console);
set_leds();
+ compute_shiftstate();
lock = 0;
}
@@ -1525,7 +1527,7 @@ int do_screendump(int arg)
if (l)
return l;
currcons = get_fs_byte(buf+1);
- if ((currcons<0) || (currcons>=NR_CONSOLES))
+ if ((currcons<0) || (currcons>NR_CONSOLES))
return -EIO;
put_fs_byte((char)(video_num_lines),buf++);
put_fs_byte((char)(video_num_columns),buf++);
@@ -1708,7 +1710,7 @@ int set_selection(const int arg)
if (obp != bp)
{
bp = obp;
- *bp++ = '\n';
+ *bp++ = '\r';
}
obp = bp;
}
diff --git a/kernel/chr_drv/defkeymap.c b/drivers/char/defkeymap.c
index 3193e1f..0596fab 100644
--- a/kernel/chr_drv/defkeymap.c
+++ b/drivers/char/defkeymap.c
@@ -20,7 +20,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
@@ -37,41 +37,41 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
- 0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200,
- 0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x007e, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
- 0x0703, 0x0200, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
+ 0x0200, 0x001b, 0x0031, 0x0040, 0x0033, 0x0024, 0x0035, 0x0036,
+ 0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x003d, 0x007f, 0x0009,
+ 0x0071, 0x0077, 0x0065, 0x0072, 0x0074, 0x0079, 0x0075, 0x0069,
+ 0x006f, 0x0070, 0x005b, 0x007e, 0x0201, 0x0702, 0x0061, 0x0073,
+ 0x0064, 0x0066, 0x0067, 0x0068, 0x006a, 0x006b, 0x006c, 0x003b,
+ 0x0027, 0x0060, 0x0700, 0x005c, 0x007a, 0x0078, 0x0063, 0x0076,
+ 0x0062, 0x006e, 0x006d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c,
+ 0x0703, 0x0020, 0x0207, 0x050c, 0x050d, 0x050e, 0x050f, 0x0510,
0x0511, 0x0512, 0x0513, 0x0514, 0x0515, 0x0208, 0x0202, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x007c, 0x0516,
0x0517, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
+ 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
- 0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
+ 0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e,
+ 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009,
+ 0x0051, 0x0057, 0x0045, 0x0052, 0x0054, 0x0059, 0x0055, 0x0049,
+ 0x004f, 0x0050, 0x007b, 0x007d, 0x0201, 0x0702, 0x0041, 0x0053,
+ 0x0044, 0x0046, 0x0047, 0x0048, 0x004a, 0x004b, 0x004c, 0x003a,
+ 0x0022, 0x007e, 0x0700, 0x007c, 0x005a, 0x0058, 0x0043, 0x0056,
+ 0x0042, 0x004e, 0x004d, 0x003c, 0x003e, 0x003f, 0x0700, 0x030c,
+ 0x0703, 0x0020, 0x0207, 0x010a, 0x010b, 0x010c, 0x010d, 0x010e,
+ 0x010f, 0x0110, 0x0111, 0x0112, 0x0113, 0x0208, 0x0203, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
- 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003e, 0x010a,
+ 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e,
@@ -80,7 +80,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x000f, 0x0010, 0x001b, 0x001d, 0x0201, 0x0702, 0x0001, 0x0013,
0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
0x0007, 0x0000, 0x0700, 0x001c, 0x001a, 0x0018, 0x0003, 0x0016,
- 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x007f, 0x0700, 0x030c,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x020e, 0x007f, 0x0700, 0x030c,
0x0703, 0x0000, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104,
0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0204, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -88,16 +88,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0200, 0x0200, 0x0200, 0x0000, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0200, 0x0200, 0x0200, 0x0200, 0x001f, 0x0200, 0x0200, 0x0200,
+ 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
+ 0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
+ 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -105,16 +105,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
+ 0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
+ 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -122,16 +122,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009,
+ 0x000f, 0x0010, 0x0200, 0x0200, 0x0201, 0x0702, 0x0001, 0x0013,
+ 0x0004, 0x0006, 0x0007, 0x0008, 0x000a, 0x000b, 0x000c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x001a, 0x0018, 0x0003, 0x0016,
+ 0x0002, 0x000e, 0x000d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -139,7 +139,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x081b, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836,
@@ -156,16 +156,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x050b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0851, 0x0857, 0x0845, 0x0852, 0x0854, 0x0859, 0x0855, 0x0849,
+ 0x084f, 0x0850, 0x0200, 0x0200, 0x0201, 0x0702, 0x0841, 0x0853,
+ 0x0844, 0x0846, 0x0847, 0x0848, 0x084a, 0x084b, 0x084c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x085a, 0x0858, 0x0843, 0x0856,
+ 0x0842, 0x084e, 0x084d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -173,16 +173,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0871, 0x0877, 0x0865, 0x0872, 0x0874, 0x0879, 0x0875, 0x0869,
+ 0x086f, 0x0870, 0x0200, 0x0200, 0x0201, 0x0702, 0x0861, 0x0873,
+ 0x0864, 0x0866, 0x0867, 0x0868, 0x086a, 0x086b, 0x086c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x087a, 0x0878, 0x0863, 0x0876,
+ 0x0862, 0x086e, 0x086d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -190,16 +190,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0851, 0x0857, 0x0845, 0x0852, 0x0854, 0x0859, 0x0855, 0x0849,
+ 0x084f, 0x0850, 0x0200, 0x0200, 0x0201, 0x0702, 0x0841, 0x0853,
+ 0x0844, 0x0846, 0x0847, 0x0848, 0x084a, 0x084b, 0x084c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x085a, 0x0858, 0x0843, 0x0856,
+ 0x0842, 0x084e, 0x084d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -207,16 +207,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -224,16 +224,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -241,16 +241,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -258,16 +258,16 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
}, {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0201, 0x0702, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0700, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
+ 0x0811, 0x0817, 0x0805, 0x0812, 0x0814, 0x0819, 0x0815, 0x0809,
+ 0x080f, 0x0810, 0x0200, 0x0200, 0x0201, 0x0702, 0x0801, 0x0813,
+ 0x0804, 0x0806, 0x0807, 0x0808, 0x080a, 0x080b, 0x080c, 0x0200,
+ 0x0200, 0x0200, 0x0700, 0x0200, 0x081a, 0x0818, 0x0803, 0x0816,
+ 0x0802, 0x080e, 0x080d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c,
0x0703, 0x0200, 0x0207, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0208, 0x0200, 0x0307,
0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301,
@@ -275,7 +275,7 @@ u_short key_map[NR_KEYMAPS][NR_KEYS] = {
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603,
0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116,
- 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
+ 0x0122, 0x010c, 0x010d, 0x0120, 0x0121, 0x0110, 0x0311, 0x0200,
0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200,
},
};
@@ -313,6 +313,9 @@ char func_buf[FUNC_BUFSIZE] = {
0,
0,
0,
+ 0,
+ 0,
+ '\033', '[', 'M', 0,
};
char *func_table[NR_FUNC] = {
@@ -348,4 +351,7 @@ char *func_table[NR_FUNC] = {
func_buf + 148,
func_buf + 149,
func_buf + 150,
+ func_buf + 151,
+ func_buf + 152,
+ func_buf + 153,
};
diff --git a/kernel/chr_drv/defkeymap.map b/drivers/char/defkeymap.map
index cf43e69..bb4c368 100644
--- a/kernel/chr_drv/defkeymap.map
+++ b/drivers/char/defkeymap.map
@@ -5,6 +5,7 @@ keycode 2 = one exclam
alt keycode 2 = Meta_one
keycode 3 = two at at
control keycode 3 = nul
+ shift control keycode 3 = nul
alt keycode 3 = Meta_two
keycode 4 = three numbersign
control keycode 4 = Escape
@@ -30,6 +31,7 @@ keycode 11 = zero parenright braceright
alt keycode 11 = Meta_zero
keycode 12 = minus underscore backslash
control keycode 12 = Control_underscore
+ shift control keycode 12 = Control_underscore
alt keycode 12 = Meta_minus
keycode 13 = equal plus
alt keycode 13 = Meta_equal
@@ -54,7 +56,7 @@ keycode 27 = bracketright braceright asciitilde
control keycode 27 = Control_bracketright
alt keycode 27 = Meta_bracketright
keycode 28 = Return
- alt keycode 28 = 0x080d
+ alt keycode 28 = Meta_Control_m
keycode 29 = Control
keycode 30 = a
keycode 31 = s
@@ -87,6 +89,7 @@ keycode 50 = m
keycode 51 = comma less
alt keycode 51 = Meta_comma
keycode 52 = period greater
+ control keycode 52 = Dead_Key_Next
alt keycode 52 = Meta_period
keycode 53 = slash question
control keycode 53 = Delete
@@ -196,13 +199,13 @@ keycode 110 = Insert
keycode 111 = Remove
altgr control keycode 111 = Boot
control alt keycode 111 = Boot
-keycode 112 =
-keycode 113 =
-keycode 114 =
-keycode 115 =
-keycode 116 =
-keycode 117 =
-keycode 118 =
+keycode 112 = Macro
+keycode 113 = F13
+keycode 114 = F14
+keycode 115 = Help
+keycode 116 = Do
+keycode 117 = F17
+keycode 118 = KP_MinPlus
keycode 119 =
keycode 120 =
keycode 121 =
@@ -244,3 +247,6 @@ string F23 = ""
string F24 = ""
string F25 = ""
string F26 = ""
+string Macro = "\033[M"
+string Help = ""
+string Do = ""
diff --git a/kernel/chr_drv/keyboard.c b/drivers/char/keyboard.c
index fdf5684..7fcc884 100644
--- a/kernel/chr_drv/keyboard.c
+++ b/drivers/char/keyboard.c
@@ -7,8 +7,8 @@
* the assembly version by Linus (with diacriticals added)
*
* Some additional features added by Christoph Niemann (ChN), March 1993
- *
* Loadable keymaps by Risto Kankkunen, May 1993
+ * Diacriticals redone & other small changes, aeb@cwi.nl, June 1993
*/
#define KEYBOARD_IRQ 1
@@ -25,6 +25,8 @@
#include <asm/bitops.h>
+#define SIZE(x) (sizeof(x)/sizeof((x)[0]))
+
#ifndef KBD_DEFFLAGS
#ifdef CONFIG_KBD_META
@@ -64,8 +66,11 @@ __asm__ __volatile__("int $0x21")
unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */
-unsigned long kbd_dead_keys = 0;
-unsigned long kbd_prev_dead_keys = 0;
+/*
+ * global state includes the following, and various static variables
+ * in this module: prev_scancode, shift_state, diacr, npadch,
+ * dead_key_next, last_console
+ */
/* shift state counters.. */
static unsigned char k_down[NR_SHIFT] = {0, };
@@ -74,6 +79,10 @@ static unsigned long key_down[8] = { 0, };
static int want_console = -1;
static int last_console = 0; /* last used VC */
+static int dead_key_next = 0;
+static int shift_state = 0;
+static int npadch = -1; /* -1 or number assembled on pad */
+static unsigned char diacr = 0;
static char rep = 0; /* flag telling character repeat */
struct kbd_struct kbd_table[NR_CONSOLES];
static struct kbd_struct * kbd = kbd_table;
@@ -94,33 +103,26 @@ static void do_cur(unsigned char value, char up_flag);
static void do_shift(unsigned char value, char up_flag);
static void do_meta(unsigned char value, char up_flag);
static void do_ascii(unsigned char value, char up_flag);
+static void do_lock(unsigned char value, char up_flag);
static k_hand key_handler[] = {
do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift,
- do_meta, do_ascii
+ do_meta, do_ascii, do_lock
};
/* maximum values each key_handler can handle */
const int max_vals[] = {
- 255, NR_FUNC - 1, 13, 16, 4, 255, 3, NR_SHIFT,
- 255, 9
+ 255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT,
+ 255, 9, 3
};
-const int NR_TYPES = (sizeof(max_vals) / sizeof(int));
-
-#define E0_BASE 96
-
-static int shift_state = 0;
-static int diacr = -1;
-static int npadch = 0;
+const int NR_TYPES = SIZE(max_vals);
static void put_queue(int);
-static unsigned int handle_diacr(unsigned int);
+static unsigned char handle_diacr(unsigned char);
static struct pt_regs * pt_regs;
-static inline void translate(unsigned char scancode);
-
static inline void kb_wait(void)
{
int i;
@@ -130,15 +132,65 @@ static inline void kb_wait(void)
break;
}
+/*
+ * Translation of escaped scancodes to keysyms.
+ * This should be user-settable.
+ */
+#define E0_BASE 96
+
+#define E0_KPENTER (E0_BASE+0)
+#define E0_RCTRL (E0_BASE+1)
+#define E0_KPSLASH (E0_BASE+2)
+#define E0_PRSCR (E0_BASE+3)
+#define E0_RALT (E0_BASE+4)
+#define E0_BREAK (E0_BASE+5) /* (control-pause) */
+#define E0_HOME (E0_BASE+6)
+#define E0_UP (E0_BASE+7)
+#define E0_PGUP (E0_BASE+8)
+#define E0_LEFT (E0_BASE+9)
+#define E0_RIGHT (E0_BASE+10)
+#define E0_END (E0_BASE+11)
+#define E0_DOWN (E0_BASE+12)
+#define E0_PGDN (E0_BASE+13)
+#define E0_INS (E0_BASE+14)
+#define E0_DEL (E0_BASE+15)
+/* BTC */
+#define E0_MACRO (E0_BASE+16)
+/* LK450 */
+#define E0_F13 (E0_BASE+17)
+#define E0_F14 (E0_BASE+18)
+#define E0_HELP (E0_BASE+19)
+#define E0_DO (E0_BASE+20)
+#define E0_F17 (E0_BASE+21)
+#define E0_KPMINPLUS (E0_BASE+22)
+
+static unsigned char e0_keys[128] = {
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x00-0x07 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x08-0x0f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x10-0x17 */
+ 0, 0, 0, 0, E0_KPENTER, E0_RCTRL, 0, 0, /* 0x18-0x1f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x20-0x27 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x28-0x2f */
+ 0, 0, 0, 0, 0, E0_KPSLASH, 0, E0_PRSCR, /* 0x30-0x37 */
+ E0_RALT, 0, 0, 0, 0, E0_F13, E0_F14, E0_HELP, /* 0x38-0x3f */
+ E0_DO, E0_F17, 0, 0, 0, 0, E0_BREAK, E0_HOME, /* 0x40-0x47 */
+ E0_UP, E0_PGUP, 0, E0_LEFT, 0, E0_RIGHT, E0_KPMINPLUS, E0_END, /* 0x48-0x4f */
+ E0_DOWN, E0_PGDN, E0_INS, E0_DEL, 0, 0, 0, 0, /* 0x50-0x57 */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x58-0x5f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x60-0x67 */
+ 0, 0, 0, 0, 0, 0, 0, E0_MACRO, /* 0x68-0x6f */
+ 0, 0, 0, 0, 0, 0, 0, 0, /* 0x70-0x77 */
+ 0, 0, 0, 0, 0, 0, 0, 0 /* 0x78-0x7f */
+};
+
static void keyboard_interrupt(int int_pt_regs)
{
unsigned char scancode;
+ static unsigned char prev_scancode = 0; /* remember E0, E1 */
+ char up_flag;
+ char raw_mode;
pt_regs = (struct pt_regs *) int_pt_regs;
- kbd_prev_dead_keys |= kbd_dead_keys;
- if (!kbd_dead_keys)
- kbd_prev_dead_keys = 0;
- kbd_dead_keys = 0;
kb_wait();
if ((inb_p(0x64) & kbd_read_mask) != 0x01)
goto end_kbd_intr;
@@ -153,99 +205,84 @@ static void keyboard_interrupt(int int_pt_regs)
}
tty = TTY_TABLE(0);
kbd = kbd_table + fg_console;
- if (vc_kbd_flag(kbd,VC_RAW)) {
- memset(k_down, 0, sizeof(k_down));
- memset(key_down, 0, sizeof(key_down));
+ if ((raw_mode = vc_kbd_flag(kbd,VC_RAW))) {
put_queue(scancode);
- goto end_kbd_intr;
- } else
- translate(scancode);
-end_kbd_intr:
- return;
-}
-
-static inline void translate(unsigned char scancode)
-{
- char break_flag;
- static unsigned char e0_keys[] = {
- 0x1c, /* keypad enter */
- 0x1d, /* right control */
- 0x35, /* keypad slash */
- 0x37, /* print screen */
- 0x38, /* right alt */
- 0x46, /* break (control-pause) */
- 0x47, /* editpad home */
- 0x48, /* editpad up */
- 0x49, /* editpad pgup */
- 0x4b, /* editpad left */
- 0x4d, /* editpad right */
- 0x4f, /* editpad end */
- 0x50, /* editpad dn */
- 0x51, /* editpad pgdn */
- 0x52, /* editpad ins */
- 0x53, /* editpad del */
-#ifdef LK450
- 0x3d, /* f13 */
- 0x3e, /* f14 */
- 0x3f, /* help */
- 0x40, /* do */
- 0x41, /* f17 */
- 0x4e /* keypad minus/plus */
-#endif
- };
-
- if (scancode == 0xe0) {
- set_kbd_dead(KGD_E0);
- return;
+ /* we do not return yet, because we want to maintain
+ the key_down array, so that we have the correct
+ values when finishing RAW mode or when changing VT's */
}
- if (scancode == 0xe1) {
- set_kbd_dead(KGD_E1);
- return;
+ if (scancode == 0xe0 || scancode == 0xe1) {
+ prev_scancode = scancode;
+ goto end_kbd_intr;
}
+
/*
- * The keyboard maintains its own internal caps lock and num lock
- * statuses. In caps lock mode E0 AA precedes make code and E0 2A
- * follows break code. In num lock mode, E0 2A precedes make
- * code and E0 AA follows break code. We do our own book-keeping,
- * so we will just ignore these.
+ * Convert scancode to keysym, using prev_scancode.
*/
- if (kbd_dead(KGD_E0) && (scancode == 0x2a || scancode == 0xaa ||
- scancode == 0x36 || scancode == 0xb6))
- return;
-
- /* map two byte scancodes into one byte id's */
-
- break_flag = scancode > 0x7f;
+ up_flag = scancode > 0x7f;
scancode &= 0x7f;
- if (scancode >= E0_BASE) {
-#if 0
- printk("keyboard: scancode (%02x) not in range 00 - %2x\n", scancode, E0_BASE - 1);
-#endif
- return;
- }
- if (kbd_dead(KGD_E0)) {
- int i;
- for (i = 0; i < sizeof(e0_keys); i++)
- if (scancode == e0_keys[i]) {
- scancode = E0_BASE + i;
- i = -1;
- break;
- }
- if (i != -1) {
-#if 0
- printk("keyboard: unknown scancode e0 %02x\n", scancode);
-#endif
- return;
- }
+ if (prev_scancode == 0xe0) {
+ prev_scancode = 0;
+ /*
+ * The keyboard maintains its own internal caps lock and num lock
+ * statuses. In caps lock mode E0 AA precedes make code and E0 2A
+ * follows break code. In num lock mode, E0 2A precedes make
+ * code and E0 AA follows break code. We do our own book-keeping,
+ * so we will just ignore these.
+ */
+ /*
+ * For my keyboard there is no caps lock mode, but there are
+ * both Shift-L and Shift-R modes. The former mode generates
+ * E0 2A / E0 AA pairs, the latter E0 B6 / E0 36 pairs.
+ * So, we should also ignore the latter. - aeb@cwi.nl
+ */
+ if (scancode == 0x2a || scancode == 0x36)
+ goto end_kbd_intr;
+
+ if (e0_keys[scancode])
+ scancode = e0_keys[scancode];
+ else if (!raw_mode) {
+ printk("keyboard: unknown scancode e0 %02x\n", scancode);
+ goto end_kbd_intr;
+ }
+ } else if (scancode >= E0_BASE && !raw_mode) {
+ printk("keyboard: scancode (%02x) not in range 00 - %2x\n",
+ scancode, E0_BASE - 1);
+ goto end_kbd_intr;
}
- rep = 0;
- if (break_flag)
+ /*
+ * At this point the variable `scancode' contains the keysym.
+ * We keep track of the up/down status of the key, and
+ * return the keysym if in MEDIUMRAW mode.
+ * Note that the present code requires the application to keep
+ * track of the up/down status as well - it would probably be
+ * better to put_queue(scancode + (up_flag ? 0200 : 0)) .
+ */
+
+ if (up_flag) {
clear_bit(scancode, key_down);
- else
+ rep = 0;
+ } else
rep = set_bit(scancode, key_down);
+ if (raw_mode)
+ goto end_kbd_intr;
+
+ if (vc_kbd_flag(kbd, VC_MEDIUMRAW)) {
+ put_queue(scancode);
+ goto end_kbd_intr;
+ }
+
+ /*
+ * Small change in philosophy: earlier we defined repetition by
+ * rep = scancode == prev_keysym;
+ * prev_keysym = scancode;
+ * but now by the fact that the depressed key was down already.
+ * Does this ever make a difference?
+ */
+
/*
* Repeat a key only if the input buffers are empty or the
* characters get echoed locally. This makes key repeat usable
@@ -253,12 +290,15 @@ static inline void translate(unsigned char scancode)
*/
if (!rep ||
(vc_kbd_flag(kbd,VC_REPEAT) && tty &&
- (L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q))))) {
+ (L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q)))))
+ {
u_short key_code;
key_code = key_map[shift_state][scancode];
- (*key_handler[key_code >> 8])(key_code & 0xff, break_flag);
+ (*key_handler[key_code >> 8])(key_code & 0xff, up_flag);
}
+
+end_kbd_intr:
}
static void put_queue(int ch)
@@ -353,7 +393,7 @@ static void hold(void)
/* pressing srcoll lock 2nd time sends ^Q, ChN */
put_queue(START_CHAR(tty));
else
- /* pressing srcoll lock 1st time sends ^S, ChN */
+ /* pressing scroll lock 1st time sends ^S, ChN */
put_queue(STOP_CHAR(tty));
chg_vc_kbd_flag(kbd,VC_SCROLLOCK);
}
@@ -402,6 +442,10 @@ static void boot_it(void)
ctrl_alt_del();
}
+static void dead_next(void)
+{
+ dead_key_next = 1;
+}
static void do_spec(unsigned char value, char up_flag)
{
@@ -410,13 +454,13 @@ static void do_spec(unsigned char value, char up_flag)
NULL, enter, show_ptregs, show_mem,
show_state, send_intr, lastcons, caps_toggle,
num, hold, scrll_forw, scrll_back,
- boot_it, caps_on
+ boot_it, caps_on, dead_next
};
- if (value >= sizeof(fn_table)/sizeof(fnp))
- return;
if (up_flag)
return;
+ if (value >= SIZE(fn_table))
+ return;
if (!fn_table[value])
return;
fn_table[value]();
@@ -427,7 +471,14 @@ static void do_self(unsigned char value, char up_flag)
if (up_flag)
return; /* no action, if this is a key release */
- value = handle_diacr(value);
+ if (diacr)
+ value = handle_diacr(value);
+
+ if (dead_key_next) {
+ dead_key_next = 0;
+ diacr = value;
+ return;
+ }
/* kludge... but works for ISO 8859-1 */
if (vc_kbd_flag(kbd,VC_CAPSLOCK))
@@ -439,8 +490,13 @@ static void do_self(unsigned char value, char up_flag)
put_queue(value);
}
+#define A_GRAVE '`'
+#define A_ACUTE '\''
+#define A_CFLEX '^'
+#define A_TILDE '~'
+#define A_DIAER '"'
static unsigned char ret_diacr[] =
- {'`', '\'', '^', '~', '"' }; /* Must not end with 0 */
+ {A_GRAVE, A_ACUTE, A_CFLEX, A_TILDE, A_DIAER };
/* If a dead key pressed twice, output a character corresponding to it, */
/* otherwise just remember the dead key. */
@@ -450,11 +506,12 @@ static void do_dead(unsigned char value, char up_flag)
if (up_flag)
return;
- if (diacr == value) { /* pressed twice */
- diacr = -1;
- put_queue(ret_diacr[value]);
- return;
- }
+ value = ret_diacr[value];
+ if (diacr == value) { /* pressed twice */
+ diacr = 0;
+ put_queue(value);
+ return;
+ }
diacr = value;
}
@@ -462,40 +519,59 @@ static void do_dead(unsigned char value, char up_flag)
/* if space if pressed, return a character corresponding the pending */
/* dead key, otherwise try to combine the two. */
-unsigned int handle_diacr(unsigned int ch)
-{
- static 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\372vwx\375z{|}~", /* accent acute */
-
- " \302BCD\312FGH\316JKLMN\324PQRST\333VWXYZ[\\]^_"
- "`\342bcd\352fgh\356jklmn\364pqrst\373vwxyz{|}~", /* circumflex */
-
- " \303BCDEFGHIJKLM\321\325PQRSTUVWXYZ[\\]^_"
- "`\343bcdefghijklm\361\365pqrstuvwxyz{|}~", /* tilde */
-
- " \304BCD\313FGH\317JKLMN\326PQRST\334VWXYZ[\\]^_"
- "`\344bcd\353fgh\357jklmn\366pqrst\374vwx\377z{|}~" /* dieresis */
- };
- int d = diacr, e;
-
- if (diacr == -1)
- return ch;
-
- diacr = -1;
- if (ch == ' ')
- return ret_diacr[d];
-
- if (ch >= 64 && ch <= 122) {
- e = accent_table[d][ch - 64];
- if (e != ch)
- return e;
- }
- put_queue(ret_diacr[d]);
- return ch;
+unsigned char handle_diacr(unsigned char ch)
+{
+ static struct {
+ unsigned char diacr, base, result;
+ } accent_table[] = {
+ {A_GRAVE, 'A', '\300'}, {A_GRAVE, 'a', '\340'},
+ {A_ACUTE, 'A', '\301'}, {A_ACUTE, 'a', '\341'},
+ {A_CFLEX, 'A', '\302'}, {A_CFLEX, 'a', '\342'},
+ {A_TILDE, 'A', '\303'}, {A_TILDE, 'a', '\343'},
+ {A_DIAER, 'A', '\304'}, {A_DIAER, 'a', '\344'},
+ {'O', 'A', '\305'}, {'o', 'a', '\345'},
+ {'0', 'A', '\305'}, {'0', 'a', '\345'},
+ {'A', 'A', '\305'}, {'a', 'a', '\345'},
+ {'A', 'E', '\306'}, {'a', 'e', '\346'},
+ {',', 'C', '\307'}, {',', 'c', '\347'},
+ {A_GRAVE, 'E', '\310'}, {A_GRAVE, 'e', '\350'},
+ {A_ACUTE, 'E', '\311'}, {A_ACUTE, 'e', '\351'},
+ {A_CFLEX, 'E', '\312'}, {A_CFLEX, 'e', '\352'},
+ {A_DIAER, 'E', '\313'}, {A_DIAER, 'e', '\353'},
+ {A_GRAVE, 'I', '\314'}, {A_GRAVE, 'i', '\354'},
+ {A_ACUTE, 'I', '\315'}, {A_ACUTE, 'i', '\355'},
+ {A_CFLEX, 'I', '\316'}, {A_CFLEX, 'i', '\356'},
+ {A_DIAER, 'I', '\317'}, {A_DIAER, 'i', '\357'},
+ {'-', 'D', '\320'}, {'-', 'd', '\360'}, /* eth */
+ {A_TILDE, 'N', '\321'}, {A_TILDE, 'n', '\361'},
+ {A_GRAVE, 'O', '\322'}, {A_GRAVE, 'o', '\362'},
+ {A_ACUTE, 'O', '\323'}, {A_ACUTE, 'o', '\363'},
+ {A_CFLEX, 'O', '\324'}, {A_CFLEX, 'o', '\364'},
+ {A_TILDE, 'O', '\325'}, {A_TILDE, 'o', '\365'},
+ {A_DIAER, 'O', '\326'}, {A_DIAER, 'o', '\366'},
+ {'/', 'O', '\330'}, {'/', 'o', '\370'},
+ {A_GRAVE, 'U', '\331'}, {A_GRAVE, 'u', '\371'},
+ {A_ACUTE, 'U', '\332'}, {A_ACUTE, 'u', '\372'},
+ {A_CFLEX, 'U', '\333'}, {A_CFLEX, 'u', '\373'},
+ {A_DIAER, 'U', '\334'}, {A_DIAER, 'u', '\374'},
+ {A_ACUTE, 'Y', '\335'}, {A_ACUTE, 'y', '\375'},
+ {'T', 'H', '\336'}, {'t', 'h', '\376'}, /* thorn */
+ {'s', 's', '\337'}, {A_DIAER, 'y', '\377'},
+ {'s', 'z', '\337'}, {'i', 'j', '\377'}
+ };
+ int d = diacr;
+ int i;
+
+ diacr = 0;
+ if (ch == ' ')
+ return d;
+
+ for (i = 0; i < SIZE(accent_table); i++)
+ if(accent_table[i].diacr == d && accent_table[i].base == ch)
+ return accent_table[i].result;
+
+ put_queue(d);
+ return ch;
}
static void do_cons(unsigned char value, char up_flag)
@@ -509,13 +585,16 @@ static void do_fn(unsigned char value, char up_flag)
{
if (up_flag)
return;
- puts_queue(func_table[value]);
+ if (value < SIZE(func_table))
+ puts_queue(func_table[value]);
+ else
+ printk("do_fn called with value=%d\n", value);
}
static void do_pad(unsigned char value, char up_flag)
{
- static char *pad_chars = "0123456789+-*/\015,.";
- static char *app_map = "pqrstuvwxylSRQMnn";
+ static char *pad_chars = "0123456789+-*/\015,.?";
+ static char *app_map = "pqrstuvwxylSRQMnn?";
if (up_flag)
return; /* no action, if this is a key release */
@@ -590,10 +669,10 @@ static void do_shift(unsigned char value, char up_flag)
value = KVAL(K_SHIFT);
clr_vc_kbd_flag(kbd, VC_CAPSLOCK);
}
- if (value > 3)
- return;
if (up_flag) {
+ /* handle the case that two shift or control
+ keys are depressed simultaneously */
if (k_down[value])
k_down[value]--;
} else
@@ -605,12 +684,37 @@ static void do_shift(unsigned char value, char up_flag)
shift_state &= ~ (1 << value);
/* kludge */
- if (up_flag && shift_state != old_state && npadch != 0) {
+ if (up_flag && shift_state != old_state && npadch != -1) {
put_queue(npadch);
- npadch = 0;
+ npadch = -1;
}
}
+/* called after returning from RAW mode or when changing consoles -
+ recompute k_down[] and shift_state from key_down[] */
+void compute_shiftstate(void)
+{
+ int i, j, k, sym, val;
+
+ shift_state = 0;
+ for(i=0; i < SIZE(k_down); i++)
+ k_down[i] = 0;
+
+ for(i=0; i < SIZE(key_down); i++)
+ if(key_down[i]) { /* skip this word if not a single bit on */
+ k = (i<<5);
+ for(j=0; j<32; j++,k++)
+ if(test_bit(k, key_down)) {
+ sym = key_map[0][k];
+ if(KTYP(sym) == KT_SHIFT) {
+ val = KVAL(sym);
+ k_down[val]++;
+ shift_state |= (1<<val);
+ }
+ }
+ }
+}
+
static void do_meta(unsigned char value, char up_flag)
{
if (up_flag)
@@ -628,7 +732,36 @@ static void do_ascii(unsigned char value, char up_flag)
if (up_flag)
return;
- npadch = (npadch * 10 + value) % 1000;
+ if (npadch == -1)
+ npadch = value;
+ else
+ npadch = (npadch * 10 + value) % 1000;
+}
+
+/* done stupidly to avoid coding in any dependencies of
+lock values, shift values and kbd flags bit positions */
+static void do_lock(unsigned char value, char up_flag)
+{
+ if (up_flag || rep)
+ return;
+ switch (value) {
+ case KVAL(K_SHIFTLOCK):
+ chg_vc_kbd_flag(kbd, VC_SHIFTLOCK);
+ do_shift(KG_SHIFT, !vc_kbd_flag(kbd, VC_SHIFTLOCK));
+ break;
+ case KVAL(K_CTRLLOCK):
+ chg_vc_kbd_flag(kbd, VC_CTRLLOCK);
+ do_shift(KG_CTRL, !vc_kbd_flag(kbd, VC_CTRLLOCK));
+ break;
+ case KVAL(K_ALTLOCK):
+ chg_vc_kbd_flag(kbd, VC_ALTLOCK);
+ do_shift(KG_ALT, !vc_kbd_flag(kbd, VC_ALTLOCK));
+ break;
+ case KVAL(K_ALTGRLOCK):
+ chg_vc_kbd_flag(kbd, VC_ALTGRLOCK);
+ do_shift(KG_ALTGR, !vc_kbd_flag(kbd, VC_ALTGRLOCK));
+ break;
+ }
}
/*
diff --git a/kernel/chr_drv/lp.c b/drivers/char/lp.c
index c74ebb7..ce0d63d 100644
--- a/kernel/chr_drv/lp.c
+++ b/drivers/char/lp.c
@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/lp.h>
+#include <linux/malloc.h>
#include <asm/io.h>
#include <asm/segment.h>
diff --git a/kernel/chr_drv/mem.c b/drivers/char/mem.c
index c2ebb38..7dbcaa2 100644
--- a/kernel/chr_drv/mem.c
+++ b/drivers/char/mem.c
@@ -4,6 +4,7 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/sched.h>
@@ -11,15 +12,15 @@
#include <linux/tty.h>
#include <linux/mouse.h>
#include <linux/tpqic02.h>
-
-#include <linux/user.h>
-#include <linux/a.out.h>
-#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/mman.h>
#include <asm/segment.h>
#include <asm/io.h>
+#ifdef CONFIG_SOUND
extern long soundcard_init(long mem_start);
+#endif
static int read_ram(struct inode * inode, struct file * file,char * buf, int count)
{
@@ -31,51 +32,6 @@ static int write_ram(struct inode * inode, struct file * file,char * buf, int co
return -EIO;
}
-static int read_core(struct inode * inode, struct file * file,char * buf, int count)
-{
- unsigned long p = file->f_pos;
- int read;
- int count1;
- char * pnt;
- struct user dump;
-
- memset(&dump, 0, sizeof(struct user));
- dump.magic = CMAGIC;
- dump.u_dsize = high_memory >> 12;
-
- if (count < 0)
- return -EINVAL;
- if (p >= high_memory)
- return 0;
- if (count > high_memory - p)
- count = high_memory - p;
- read = 0;
-
- if (p < sizeof(struct user) && count > 0) {
- count1 = count;
- if (p + count1 > sizeof(struct user))
- count1 = sizeof(struct user)-p;
- pnt = (char *) &dump + p;
- memcpy_tofs(buf,(void *) pnt, count1);
- buf += count1;
- p += count1;
- count -= count1;
- read += count1;
- }
-
- while (p < 2*PAGE_SIZE && count > 0) {
- put_fs_byte(0,buf);
- buf++;
- p++;
- count--;
- read++;
- }
- memcpy_tofs(buf,(void *) (p - PAGE_SIZE),count);
- read += count;
- file->f_pos += read;
- return read;
-}
-
static int read_mem(struct inode * inode, struct file * file,char * buf, int count)
{
unsigned long p = file->f_pos;
@@ -149,8 +105,8 @@ static int mmap_mem(struct inode * inode, struct file * file,
inode->i_count++;
mpnt->vm_offset = off;
mpnt->vm_ops = NULL;
- mpnt->vm_next = current->mmap;
- current->mmap = mpnt;
+ insert_vm_struct(current, mpnt);
+ merge_segments(current->mmap, NULL, NULL);
return 0;
}
@@ -206,10 +162,31 @@ static int read_zero(struct inode * node,struct file * file,char * buf,int count
static int mmap_zero(struct inode * inode, struct file * file,
unsigned long addr, size_t len, int prot, unsigned long off)
{
+ struct vm_area_struct *mpnt;
+
if (prot & PAGE_RW)
return -EINVAL;
if (zeromap_page_range(addr, len, prot))
return -EAGAIN;
+ /*
+ * try to create a dummy vmm-structure so that the
+ * rest of the kernel knows we are here
+ */
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+ if (!mpnt)
+ return 0;
+
+ mpnt->vm_task = current;
+ mpnt->vm_start = addr;
+ mpnt->vm_end = addr + len;
+ mpnt->vm_page_prot = prot;
+ mpnt->vm_share = NULL;
+ mpnt->vm_inode = inode;
+ inode->i_count++;
+ mpnt->vm_offset = off;
+ mpnt->vm_ops = NULL;
+ insert_vm_struct(current, mpnt);
+ merge_segments(current->mmap, ignoff_mergep, inode);
return 0;
}
@@ -330,19 +307,6 @@ static struct file_operations zero_fops = {
NULL /* no special release code */
};
-static struct file_operations core_fops = {
- memory_lseek,
- read_core,
- NULL,
- NULL, /* zero_readdir */
- NULL, /* zero_select */
- NULL, /* zero_ioctl */
- NULL, /* zero_mmap */
- NULL, /* no special open code */
- NULL, /* no special release code */
- NULL /* fsync */
-};
-
static int memory_open(struct inode * inode, struct file * filp)
{
switch (MINOR(inode->i_rdev)) {
@@ -364,9 +328,6 @@ static int memory_open(struct inode * inode, struct file * filp)
case 5:
filp->f_op = &zero_fops;
break;
- case 6:
- filp->f_op = &core_fops;
- break;
default:
return -ENODEV;
}
@@ -393,9 +354,17 @@ long chr_dev_init(long mem_start, long mem_end)
if (register_chrdev(1,"mem",&memory_fops))
printk("unable to get major 1 for memory devs\n");
mem_start = tty_init(mem_start);
+#ifdef CONFIG_PRINTER
mem_start = lp_init(mem_start);
+#endif
+#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_QUICKPORT_MOUSE) || \
+ defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \
+ defined (CONFIG_ATIXL_BUSMOUSE)
mem_start = mouse_init(mem_start);
+#endif
+#ifdef CONFIG_SOUND
mem_start = soundcard_init(mem_start);
+#endif
#if CONFIG_TAPE_QIC02
mem_start = tape_qic02_init(mem_start);
#endif
diff --git a/kernel/chr_drv/mouse.c b/drivers/char/mouse.c
index 3ea9c47..3ea9c47 100644
--- a/kernel/chr_drv/mouse.c
+++ b/drivers/char/mouse.c
diff --git a/kernel/chr_drv/msbusmouse.c b/drivers/char/msbusmouse.c
index 0fd252d..0fd252d 100644
--- a/kernel/chr_drv/msbusmouse.c
+++ b/drivers/char/msbusmouse.c
diff --git a/kernel/chr_drv/psaux.c b/drivers/char/psaux.c
index e313633..e313633 100644
--- a/kernel/chr_drv/psaux.c
+++ b/drivers/char/psaux.c
diff --git a/kernel/chr_drv/pty.c b/drivers/char/pty.c
index 4cbecab..4cbecab 100644
--- a/kernel/chr_drv/pty.c
+++ b/drivers/char/pty.c
diff --git a/kernel/chr_drv/serial.c b/drivers/char/serial.c
index 204cca5..9ad20f9 100644
--- a/kernel/chr_drv/serial.c
+++ b/drivers/char/serial.c
@@ -1195,7 +1195,7 @@ static int set_modem_info(struct async_struct * info, unsigned int cmd,
control &= ~UART_MCR_DTR;
break;
case TIOCMSET:
- control = (control & ~0x03)
+ control = (control & ~(UART_MCR_RTS | UART_MCR_DTR))
| ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0)
| ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0);
break;
@@ -1328,7 +1328,7 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
send_break(info, arg ? arg*(HZ/10) : HZ/4);
return 0;
case TIOCGSOFTCAR:
- error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(unsigned int *));
+ error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long));
if (error)
return error;
put_fs_long(C_LOCAL(tty) ? 1 : 0,
@@ -1341,7 +1341,8 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file,
(arg ? CLOCAL : 0));
return 0;
case TIOCMGET:
- error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(unsigned int *));
+ error = verify_area(VERIFY_WRITE, (void *) arg,
+ sizeof(unsigned int));
if (error)
return error;
return get_modem_info(info, (unsigned int *) arg);
diff --git a/kernel/chr_drv/tpqic02.c b/drivers/char/tpqic02.c
index 5283f42..5283f42 100644
--- a/kernel/chr_drv/tpqic02.c
+++ b/drivers/char/tpqic02.c
diff --git a/kernel/chr_drv/tty_io.c b/drivers/char/tty_io.c
index dd6c81e..160eb64 100644
--- a/kernel/chr_drv/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -46,6 +46,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/keyboard.h>
+#include <linux/malloc.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -620,6 +621,8 @@ void copy_to_cooked(struct tty_struct * tty)
if (c == STOP_CHAR(tty)) {
tty->ctrl_status &= ~(TIOCPKT_START);
tty->ctrl_status |= TIOCPKT_STOP;
+ if (tty->link)
+ wake_up_interruptible(&tty->link->except_q);
tty->stopped=1;
if (tty->stop)
(tty->stop)(tty);
@@ -634,6 +637,8 @@ void copy_to_cooked(struct tty_struct * tty)
tty->ctrl_status &= ~(TIOCPKT_STOP);
tty->ctrl_status |= TIOCPKT_START;
tty->stopped=0;
+ if (tty->link)
+ wake_up_interruptible(&tty->link->except_q);
if (tty->start)
(tty->start)(tty);
if (IS_A_CONSOLE(tty->line)) {
@@ -1318,6 +1323,9 @@ static int tty_open(struct inode * inode, struct file * filp)
* process opens up a tty in packet mode, all the packet
* variables get cleared. Come to think of it, is anything
* using the packet mode at all??? - Ted, 1/27/93
+ *
+ * Not to worry, a pty master can only be opened once.
+ * And rlogind and telnetd both use packet mode. -- jrs
*/
tty->ctrl_status = 0;
tty->packet = 0;
@@ -1400,8 +1408,7 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se
}
/* see if the status byte can be read. */
- if (tty->packet && tty->link &&
- tty->link->status_changed)
+ if (tty->packet && tty->link && tty->link->ctrl_status)
return 1;
select_wait(&tty->secondary.proc_list, wait);
@@ -1417,11 +1424,15 @@ static int tty_select(struct inode * inode, struct file * filp, int sel_type, se
if ((tty->flags & (1 << TTY_SLAVE_OPENED))
&& tty->link->count <= 1)
return 1;
+ if (tty->packet
+ && tty->link->ctrl_status)
+ return 1;
} else {
if (!tty->link->count)
return 1;
}
}
+ select_wait(&tty->except_q, wait);
return 0;
}
return 0;
@@ -1591,6 +1602,7 @@ static void initialize_tty_struct(int line, struct tty_struct *tty)
} else if IS_A_PTY(line) {
tty->open = pty_open;
}
+ tty->except_q = NULL;
}
static void initialize_termios(int line, struct termios * tp)
diff --git a/kernel/chr_drv/tty_ioctl.c b/drivers/char/tty_ioctl.c
index c50215d..df5d35d 100644
--- a/kernel/chr_drv/tty_ioctl.c
+++ b/drivers/char/tty_ioctl.c
@@ -52,6 +52,8 @@ static void flush(struct tty_queue * queue)
void flush_input(struct tty_struct * tty)
{
tty->ctrl_status |= TIOCPKT_FLUSHREAD;
+ if (tty->link)
+ wake_up_interruptible(&tty->link->except_q);
flush(&tty->read_q);
wake_up_interruptible(&tty->read_q.proc_list);
flush(&tty->secondary);
@@ -66,6 +68,8 @@ void flush_input(struct tty_struct * tty)
void flush_output(struct tty_struct * tty)
{
tty->ctrl_status |= TIOCPKT_FLUSHWRITE;
+ if (tty->link)
+ wake_up_interruptible(&tty->link->except_q);
flush(&tty->write_q);
wake_up_interruptible(&tty->write_q.proc_list);
if ((tty = tty->link) != NULL) {
@@ -202,17 +206,23 @@ static int set_termios(struct tty_struct * tty, struct termios * termios,
(tty->termios->c_cc[VSTART] == '\021');
if (old_flow != new_flow) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
- if (new_flow)
- tty->ctrl_status |= TIOCPKT_DOSTOP;
- else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
+ tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
+ if (new_flow)
+ tty->ctrl_status |= TIOCPKT_DOSTOP;
+ else
+ tty->ctrl_status |= TIOCPKT_NOSTOP;
+ if (tty->link)
+ wake_up_interruptible(&tty->link->except_q);
}
+#if 0
/* puting mpty's into echo mode is very bad, and I think under
some situations can cause the kernel to do nothing but
copy characters back and forth. -RAB */
+ /* This can no longer happen because a set_termios is redirected
+ to the pty slave. -- jrs */
if (IS_A_PTY_MASTER(channel)) tty->termios->c_lflag &= ~ECHO;
+#endif
unset_locked_termios(tty->termios, &old_termios,
termios_locked[tty->line]);
@@ -283,14 +293,15 @@ static int set_termio(struct tty_struct * tty, struct termio * termio,
(tty->termios->c_cc[VSTART] == '\021');
if (old_flow != new_flow) {
- tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
- if (new_flow)
- tty->ctrl_status |= TIOCPKT_DOSTOP;
- else
- tty->ctrl_status |= TIOCPKT_NOSTOP;
+ tty->ctrl_status &= ~(TIOCPKT_DOSTOP|TIOCPKT_NOSTOP);
+ if (new_flow)
+ tty->ctrl_status |= TIOCPKT_DOSTOP;
+ else
+ tty->ctrl_status |= TIOCPKT_NOSTOP;
+ if (tty->link)
+ wake_up_interruptible(&tty->link->except_q);
}
-
unset_locked_termios(tty->termios, &old_termios,
termios_locked[tty->line]);
@@ -611,20 +622,14 @@ int tty_ioctl(struct inode * inode, struct file * file,
return set_lcktrmios(tty, (struct termios *) arg,
termios_dev);
case TIOCPKT:
- {
- int on;
- if (!IS_A_PTY_MASTER(dev))
- return -EINVAL;
- retval = verify_area(VERIFY_READ, (unsigned long *)arg, sizeof (int));
- if (retval)
- return retval;
- on=get_fs_long ((unsigned long *)arg);
- if (on )
- tty->packet = 1;
- else
- tty->packet = 0;
- return (0);
- }
+ if (!IS_A_PTY_MASTER(dev))
+ return -EINVAL;
+ retval = verify_area(VERIFY_READ,
+ (unsigned long *)arg, sizeof (unsigned long));
+ if (retval)
+ return retval;
+ tty->packet = (get_fs_long ((unsigned long *)arg) != 0);
+ return 0;
case TCSBRK: case TCSBRKP:
wait_until_sent(tty);
if (!tty->ioctl)
diff --git a/kernel/chr_drv/vt.c b/drivers/char/vt.c
index 124bd9a..deb1662 100644
--- a/kernel/chr_drv/vt.c
+++ b/drivers/char/vt.c
@@ -37,6 +37,7 @@ struct vt_cons vt_cons[NR_CONSOLES];
asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int on);
+extern void compute_shiftstate(void);
extern void change_console(unsigned int new_console);
extern void complete_change_console(unsigned int new_console);
extern int vt_waitactive(void);
@@ -208,10 +209,15 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSKBMODE:
if (arg == K_RAW) {
set_vc_kbd_flag(kbd, VC_RAW);
+ clr_vc_kbd_flag(kbd, VC_MEDIUMRAW);
} else if (arg == K_XLATE) {
clr_vc_kbd_flag(kbd, VC_RAW);
- }
- else
+ clr_vc_kbd_flag(kbd, VC_MEDIUMRAW);
+ compute_shiftstate();
+ } else if (arg == K_MEDIUMRAW) {
+ clr_vc_kbd_flag(kbd, VC_RAW);
+ set_vc_kbd_flag(kbd, VC_MEDIUMRAW);
+ } else
return -EINVAL;
flush_input(tty);
return 0;
@@ -220,17 +226,22 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned long));
if (!i) {
ucval = vc_kbd_flag(kbd, VC_RAW);
- put_fs_long(ucval ? K_RAW : K_XLATE, (unsigned long *) arg);
+ if (vc_kbd_flag(kbd, VC_MEDIUMRAW))
+ put_fs_long(K_MEDIUMRAW, (unsigned long *) arg);
+ else
+ put_fs_long(ucval ? K_RAW : K_XLATE,
+ (unsigned long *) arg);
}
return i;
case KDGKBENT:
{
struct kbentry * const a = (struct kbentry *)arg;
- u_char i;
u_char s;
- verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
+ i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
+ if (i)
+ return i;
if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
return -EINVAL;
if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS)
@@ -242,11 +253,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDSKBENT:
{
const struct kbentry * a = (struct kbentry *)arg;
- u_char i;
u_char s;
u_short v;
- verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
+ i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbentry));
+ if (i)
+ return i;
if ((i = get_fs_byte((char *) &a->kb_index)) >= NR_KEYS)
return -EINVAL;
if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS)
@@ -262,11 +274,12 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
case KDGKBSENT:
{
const struct kbsentry *a = (struct kbsentry *)arg;
- u_char i;
char *p;
u_char *q;
- verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
+ i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry));
+ if (i)
+ return i;
if ((i = get_fs_byte(&a->kb_func)) >= NR_FUNC)
return -EINVAL;
q = a->kb_string;
@@ -281,12 +294,13 @@ int vt_ioctl(struct tty_struct *tty, struct file * file,
struct kbsentry * const a = (struct kbsentry *)arg;
int delta;
char *first_free;
- u_char i;
int k;
u_char *p;
char *q;
- verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
+ i = verify_area(VERIFY_READ, (void *)a, sizeof(struct kbsentry));
+ if (i)
+ return i;
if ((i = get_fs_byte(&a->kb_func)) >= NR_FUNC)
return -EINVAL;
delta = -strlen(func_table[i]);
diff --git a/kernel/chr_drv/vt_kern.h b/drivers/char/vt_kern.h
index 6341140..6341140 100644
--- a/kernel/chr_drv/vt_kern.h
+++ b/drivers/char/vt_kern.h
diff --git a/drivers/net/3c501.c b/drivers/net/3c501.c
new file mode 100644
index 0000000..043010c
--- /dev/null
+++ b/drivers/net/3c501.c
@@ -0,0 +1,564 @@
+/* 3c501.c: A 3Com 3c501 ethernet driver for linux. */
+/*
+ Copyright (C) 1992,1993 Donald Becker
+
+ This is alpha test code. No redistribution is permitted.
+
+ If this code is distributed, it will carry the following:
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency. This software may be used and
+ distributed according to the terms of the GNU Public License,
+ incorporated herein by reference.
+
+ This is a device driver for the 3Com Etherlink 3c501.
+ Do not purchase this card, even as a joke. It's performance is horrible,
+ and it breaks in many ways.
+
+ The Author may be reached as becker@super.org or
+ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+ I'll only accept bug fixes, not reports, for the 3c501 driver.
+*/
+
+static char *version =
+ "3c501.c:v13.13 1993 Donald Becker (becker@super.org).\n";
+
+/*
+ Braindamage remaining:
+ The 3c501 board.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/ptrace.h>
+#include <linux/fcntl.h>
+#include <linux/ioport.h>
+#include <linux/interrupt.h>
+#include <linux/malloc.h>
+#include <linux/ioport.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <errno.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c, should be in a *.h file. */
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+extern struct device *irq2dev_map[16];
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(addr, size) kfree_s(addr,size);
+#endif
+
+
+/* Index to functions. */
+int el1_probe(struct device *dev);
+static int el_open(struct device *dev);
+static int el_start_xmit(struct sk_buff *skb, struct device *dev);
+static void el_interrupt(int reg_ptr);
+static void el_receive(struct device *dev);
+static void el_reset(struct device *dev);
+static int el1_close(struct device *dev);
+static struct enet_statistics *el1_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+#define EL_NAME "EtherLink 3c501"
+
+#ifndef EL_DEBUG
+#define EL_DEBUG 2 /* use 0 for production, 1 for devel., >2 for debug */
+#endif /* Anything above 5 is wordy death! */
+static int el_debug = EL_DEBUG;
+static int el_base;
+static struct device *eldev; /* Only for consistency checking. */
+
+/* We could easily have this struct kmalloc()ed per-board, but
+ who would want more than one 3c501?. */
+static struct {
+ struct enet_statistics stats;
+ int tx_pkt_start; /* The length of the current Tx packet. */
+ int collisions; /* Tx collisions this packet */
+} el_status; /* This should be stored per-board */
+
+
+#define RX_STATUS (el_base + 0x06)
+#define RX_CMD RX_STATUS
+#define TX_STATUS (el_base + 0x07)
+#define TX_CMD TX_STATUS
+#define GP_LOW (el_base + 0x08)
+#define GP_HIGH (el_base + 0x09)
+#define RX_BUF_CLR (el_base + 0x0A)
+#define RX_LOW (el_base + 0x0A)
+#define RX_HIGH (el_base + 0x0B)
+#define SAPROM (el_base + 0x0C)
+#define AX_STATUS (el_base + 0x0E)
+#define AX_CMD AX_STATUS
+#define DATAPORT (el_base + 0x0F)
+#define TX_RDY 0x08 /* In TX_STATUS */
+
+#define EL1_DATAPTR 0x08
+#define EL1_RXPTR 0x0A
+#define EL1_SAPROM 0x0C
+#define EL1_DATAPORT 0x0f
+
+/* Writes to the ax command register. */
+#define AX_OFF 0x00 /* Irq off, buffer access on */
+#define AX_SYS 0x40 /* Load the buffer */
+#define AX_XMIT 0x44 /* Transmit a packet */
+#define AX_RX 0x48 /* Receive a packet */
+#define AX_LOOP 0x0C /* Loopback mode */
+#define AX_RESET 0x80
+
+/* Normal receive mode written to RX_STATUS. We must intr on short packets
+ to avoid bogus rx lockups. */
+#define RX_NORM 0xA8 /* 0x68 == all addrs, 0xA8 only to me. */
+#define RX_PROM 0x68 /* Senior Prom, uhmm promiscuous mode. */
+#define RX_MULT 0xE8 /* Accept multicast packets. */
+#define TX_NORM 0x0A /* Interrupt on everything that might hang the chip */
+
+/* TX_STATUS register. */
+#define TX_COLLISION 0x02
+#define TX_16COLLISIONS 0x04
+#define TX_READY 0x08
+
+#define RX_RUNT 0x08
+#define RX_MISSED 0x01 /* Missed a packet due to 3c501 braindamage. */
+#define RX_GOOD 0x30 /* Good packet 0x20, or simple overflow 0x10. */
+
+
+int
+el1_probe(struct device *dev)
+{
+ int i;
+ int ioaddr;
+ unsigned char station_addr[6];
+ int autoirq = 0;
+
+ eldev = dev; /* Store for debugging. */
+ el_base = dev->base_addr;
+
+ if (el_base < 0x40) /* Invalid? Probe for it. */
+ el_base = 0x280;
+
+ ioaddr = el_base;
+
+ /* Read the station address PROM data from the special port. */
+ for (i = 0; i < 6; i++) {
+ outw(i, ioaddr + EL1_DATAPTR);
+ station_addr[i] = inb(ioaddr + EL1_SAPROM);
+ }
+ /* Check the first three octets of the S.A. for 3Com's code. */
+ if (station_addr[0] != 0x02 || station_addr[1] != 0x60
+ || station_addr[2] != 0x8c) {
+ return ENODEV;
+ }
+
+#ifdef HAVE_PORTRESERVE
+ /* Grab the region so we can find the another board if autoIRQ fails. */
+ snarf_region(ioaddr, 16);
+#endif
+
+ /* We auto-IRQ by shutting off the interrupt line and letting it float
+ high. */
+ if (dev->irq < 2) {
+
+ autoirq_setup(2);
+
+ inb(RX_STATUS); /* Clear pending interrupts. */
+ inb(TX_STATUS);
+ outb(AX_LOOP + 1, AX_CMD);
+
+ outb(0x00, AX_CMD);
+
+ autoirq = autoirq_report(1);
+
+ if (autoirq == 0) {
+ printk("%s: 3c501 probe failed to detect IRQ line.\n", dev->name);
+ return EAGAIN;
+ }
+ dev->irq = autoirq;
+ }
+
+ outb(AX_RESET+AX_LOOP, AX_CMD); /* Loopback mode. */
+
+ dev->base_addr = el_base;
+ memcpy(dev->dev_addr, station_addr, ETH_ALEN);
+ if (dev->mem_start & 0xf)
+ el_debug = dev->mem_start & 0x7;
+
+ printk("%s: 3c501 EtherLink at %#x, using %sIRQ %d, melting ethernet.\n",
+ dev->name, dev->base_addr, autoirq ? "auto":"assigned ", dev->irq);
+
+ if (el_debug)
+ printk("%s", version);
+
+ /* The EL1-specific entries in the device structure. */
+ dev->open = &el_open;
+ dev->hard_start_xmit = &el_start_xmit;
+ dev->stop = &el1_close;
+ dev->get_stats = &el1_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
+
+ /* Fill in the generic field of the device structure. */
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ dev->buffs[i] = NULL;
+
+ dev->hard_header = eth_header;
+ dev->add_arp = eth_add_arp;
+ dev->queue_xmit = dev_queue_xmit;
+ dev->rebuild_header = eth_rebuild_header;
+ dev->type_trans = eth_type_trans;
+
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_len = ETH_HLEN;
+ dev->mtu = 1500; /* eth_mtu */
+ dev->addr_len = ETH_ALEN;
+ for (i = 0; i < ETH_ALEN; i++) {
+ dev->broadcast[i]=0xff;
+ }
+
+ /* New-style flags. */
+ dev->flags = IFF_BROADCAST;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = sizeof(unsigned long);
+
+ return 0;
+}
+
+/* Open/initialize the board. */
+static int
+el_open(struct device *dev)
+{
+
+ if (el_debug > 2)
+ printk("%s: Doing el_open()...", dev->name);
+
+ if (request_irq(dev->irq, &el_interrupt)) {
+ if (el_debug > 2)
+ printk("interrupt busy, exiting el_open().\n");
+ return -EAGAIN;
+ }
+ irq2dev_map[dev->irq] = dev;
+
+ el_reset(dev);
+
+ dev->start = 1;
+
+ outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
+ if (el_debug > 2)
+ printk("finished el_open().\n");
+ return (0);
+}
+
+static int
+el_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+
+ if (dev->tbusy) {
+ if (jiffies - dev->trans_start < 20) {
+ if (el_debug > 2)
+ printk(" transmitter busy, deferred.\n");
+ return 1;
+ }
+ if (el_debug)
+ printk ("%s: transmit timed out, txsr %#2x axsr=%02x rxsr=%02x.\n",
+ dev->name, inb(TX_STATUS), inb(AX_STATUS), inb(RX_STATUS));
+ el_status.stats.tx_errors++;
+#ifdef oldway
+ el_reset(dev);
+#else
+ outb(TX_NORM, TX_CMD);
+ outb(RX_NORM, RX_CMD);
+ outb(AX_OFF, AX_CMD); /* Just trigger a false interrupt. */
+#endif
+ outb(AX_RX, AX_CMD); /* Aux control, irq and receive enabled */
+ dev->tbusy = 0;
+ dev->trans_start = jiffies;
+ }
+
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
+ }
+
+ /* Fill in the ethernet header. */
+ if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
+ skb->dev = dev;
+ arp_queue (skb);
+ return 0;
+ }
+ skb->arp=1;
+
+ if (skb->len <= 0)
+ return 0;
+
+ if (el_debug > 2)
+ printk("%s: el_start_xmit(%d)...", dev->name, skb->len);
+
+ /* Avoid timer-based retransmission conflicts. */
+ if (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else {
+ int gp_start = 0x800 - (ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN);
+ unsigned char *buf = (void *)(skb+1);
+
+ el_status.tx_pkt_start = gp_start;
+ el_status.collisions = 0;
+
+ outb(AX_SYS, AX_CMD);
+ inb(RX_STATUS);
+ inb(TX_STATUS);
+ outb(0x00, RX_BUF_CLR); /* Set rx packet area to 0. */
+ outw(gp_start, GP_LOW);
+ port_write_b(DATAPORT,buf,skb->len);
+ outw(gp_start, GP_LOW);
+ outb(AX_XMIT, AX_CMD); /* Trigger xmit. */
+ dev->trans_start = jiffies;
+ }
+
+ if (el_debug > 2)
+ printk(" queued xmit.\n");
+ if (skb->free)
+ kfree_skb (skb, FREE_WRITE);
+ return 0;
+}
+
+
+/* The typical workload of the driver:
+ Handle the ether interface interrupts. */
+static void
+el_interrupt(int reg_ptr)
+{
+ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+ /*struct device *dev = (struct device *)(irq2dev_map[irq]);*/
+ struct device *dev = eldev;
+ int axsr; /* Aux. status reg. */
+ short ioaddr;
+
+ if (eldev->irq != irq) {
+ printk (EL_NAME ": irq %d for unknown device\n", irq);
+ return;
+ }
+
+ ioaddr = dev->base_addr;
+
+ axsr = inb(AX_STATUS);
+
+ if (el_debug > 3)
+ printk("%s: el_interrupt() aux=%#02x", dev->name, axsr);
+ if (dev->interrupt)
+ printk("%s: Reentering the interrupt driver!\n", dev->name);
+ dev->interrupt = 1;
+
+ if (dev->tbusy) {
+ int txsr = inb(TX_STATUS);
+
+ if (el_debug > 6)
+ printk(" txsr=%02x gp=%04x rp=%04x", txsr, inw(GP_LOW),
+ inw(RX_LOW));
+
+ if ((axsr & 0x80) && (txsr & TX_READY) == 0) {
+ printk("%s: Unusual interrupt during Tx, txsr=%02x axsr=%02x"
+ " gp=%03x rp=%03x.\n", dev->name, txsr, axsr,
+ inw(ioaddr + EL1_DATAPTR), inw(ioaddr + EL1_RXPTR));
+ dev->tbusy = 0;
+ mark_bh(INET_BH);
+ } else if (txsr & TX_16COLLISIONS) {
+ if (el_debug)
+ printk("%s: Transmit failed 16 times, ethernet jammed?\n",
+ dev->name);
+ outb(AX_SYS, AX_CMD);
+ el_status.stats.tx_aborted_errors++;
+ } else if (txsr & TX_COLLISION) { /* Retrigger xmit. */
+ if (el_debug > 6)
+ printk(" retransmitting after a collision.\n");
+ outb(AX_SYS, AX_CMD);
+ outw(el_status.tx_pkt_start, GP_LOW);
+ outb(AX_XMIT, AX_CMD);
+ el_status.stats.collisions++;
+ dev->interrupt = 0;
+ return;
+ } else {
+ el_status.stats.tx_packets++;
+ if (el_debug > 6)
+ printk(" Tx succeeded %s\n",
+ (txsr & TX_RDY) ? "." : "but tx is busy!");
+ dev->tbusy = 0;
+ mark_bh(INET_BH);
+ }
+ } else {
+ int rxsr = inb(RX_STATUS);
+ if (el_debug > 5)
+ printk(" rxsr=%02x txsr=%02x rp=%04x", rxsr, inb(TX_STATUS),
+ inw(RX_LOW));
+
+ /* Just reading rx_status fixes most errors. */
+ if (rxsr & RX_MISSED)
+ el_status.stats.rx_missed_errors++;
+ if (rxsr & RX_RUNT) { /* Handled to avoid board lock-up. */
+ el_status.stats.rx_length_errors++;
+ if (el_debug > 5) printk(" runt.\n");
+ } else if (rxsr & RX_GOOD) {
+ el_receive(eldev);
+ } else { /* Nothing? Something is broken! */
+ if (el_debug > 2)
+ printk("%s: No packet seen, rxsr=%02x **resetting 3c501***\n",
+ dev->name, rxsr);
+ el_reset(eldev);
+ }
+ if (el_debug > 3)
+ printk(".\n");
+ }
+
+ outb(AX_RX, AX_CMD);
+ outb(0x00, RX_BUF_CLR);
+ inb(RX_STATUS); /* Be certain that interrupts are cleared. */
+ inb(TX_STATUS);
+ dev->interrupt = 0;
+ return;
+}
+
+
+/* We have a good packet. Well, not really "good", just mostly not broken.
+ We must check everything to see if it is good. */
+static void
+el_receive(struct device *dev)
+{
+ int sksize, pkt_len;
+ struct sk_buff *skb;
+
+ pkt_len = inw(RX_LOW);
+
+ if (el_debug > 4)
+ printk(" el_receive %d.\n", pkt_len);
+
+ if ((pkt_len < 60) || (pkt_len > 1536)) {
+ if (el_debug)
+ printk("%s: bogus packet, length=%d\n", dev->name, pkt_len);
+ el_status.stats.rx_over_errors++;
+ return;
+ }
+ outb(AX_SYS, AX_CMD);
+
+ sksize = sizeof(struct sk_buff) + pkt_len;
+ skb = alloc_skb(sksize, GFP_ATOMIC);
+ outw(0x00, GP_LOW);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ el_status.stats.rx_dropped++;
+ return;
+ } else {
+ skb->mem_len = sksize;
+ skb->mem_addr = skb;
+ skb->len = pkt_len;
+ skb->dev = dev;
+
+ port_read_b(DATAPORT, (void *)(skb+1), pkt_len);
+
+#ifdef HAVE_NETIF_RX
+ netif_rx(skb);
+#else
+ skb->lock = 0;
+ if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+ kfree_skbmem(skb, sksize);
+ lp->stats.rx_dropped++;
+ break;
+ }
+#endif
+ el_status.stats.rx_packets++;
+ }
+ return;
+}
+
+static void
+el_reset(struct device *dev)
+{
+ if (el_debug> 2)
+ printk("3c501 reset...");
+ outb(AX_RESET, AX_CMD); /* Reset the chip */
+ outb(AX_LOOP, AX_CMD); /* Aux control, irq and loopback enabled */
+ {
+ int i;
+ for (i = 0; i < 6; i++) /* Set the station address. */
+ outb(dev->dev_addr[i], el_base + i);
+ }
+
+ outb(0, RX_BUF_CLR); /* Set rx packet area to 0. */
+ cli(); /* Avoid glitch on writes to CMD regs */
+ outb(TX_NORM, TX_CMD); /* tx irq on done, collision */
+ outb(RX_NORM, RX_CMD); /* Set Rx commands. */
+ inb(RX_STATUS); /* Clear status. */
+ inb(TX_STATUS);
+ dev->interrupt = 0;
+ dev->tbusy = 0;
+ sti();
+}
+
+static int
+el1_close(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ if (el_debug > 2)
+ printk("%s: Shutting down ethercard at %#x.\n", dev->name, ioaddr);
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ /* Free and disable the IRQ. */
+ free_irq(dev->irq);
+ outb(AX_RESET, AX_CMD); /* Reset the chip */
+ irq2dev_map[dev->irq] = 0;
+
+ return 0;
+}
+
+static struct enet_statistics *
+el1_get_stats(struct device *dev)
+{
+ return &el_status.stats;
+}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ if (num_addrs > 0) {
+ outb(RX_MULT, RX_CMD);
+ inb(RX_STATUS); /* Clear status. */
+ } else if (num_addrs < 0) {
+ outb(RX_PROM, RX_CMD);
+ inb(RX_STATUS);
+ } else {
+ outb(RX_NORM, RX_CMD);
+ inb(RX_STATUS);
+ }
+}
+#endif
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer -m486 -c -o 3c501.o 3c501.c"
+ * kept-new-versions: 5
+ * End:
+ */
diff --git a/net/inet/el.c b/drivers/net/3c503.c
index 2155f63..e310156 100644
--- a/net/inet/el.c
+++ b/drivers/net/3c503.c
@@ -1,19 +1,22 @@
-/* el.c: A shared-memory NS8390 ethernet driver for linux. */
+/* el2.c: A shared-memory NS8390 ethernet driver for linux. */
/*
- Written 1992,1993 by Donald Becker. This is alpha test code.
+ Written 1992,1993 by Donald Becker.
+
Copyright 1993 United States Government as represented by the
Director, National Security Agency. This software may be used and
distributed according to the terms of the GNU Public License,
incorporated herein by reference.
- This driver should work with the 3c503 and 3c503/16. It must be used
- in shared memory mode.
+ This driver should work with the 3c503 and 3c503/16. It should be used
+ in shared memory mode for best performance, although it may also work
+ in programmed-I/O mode.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
-static char *version = "el.c:v0.99-10 5/28/93 Donald Becker (becker@super.org)\n";
+static char *version =
+ "el2.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
@@ -25,15 +28,14 @@ static char *version = "el.c:v0.99-10 5/28/93 Donald Becker (becker@super.org)\n
#include "dev.h"
#include "8390.h"
-#include "elreg.h"
-
-extern void NS8390_init(struct device *dev, int startp);
-extern int ei_debug;
-extern struct sigaction ei_sigaction;
+#include "3c503.h"
-int el2autoprobe(int ioaddr, struct device *dev);
-int el2probe(int ioaddr, struct device *dev);
+int el2_probe(struct device *dev);
+int el2_pio_autoprobe(struct device *dev);
+int el2probe1(int ioaddr, struct device *dev);
+static int el2_open(struct device *dev);
+static int el2_close(struct device *dev);
static void el2_reset_8390(struct device *dev);
static void el2_init_card(struct device *dev);
static void el2_block_output(struct device *dev, int count,
@@ -42,19 +44,27 @@ static int el2_block_input(struct device *dev, int count, char *buf,
int ring_offset);
+/* This routine probes for a memory-mapped 3c503 board by looking for
+ the "location register" at the end of the jumpered boot PROM space.
+ This works even if a PROM isn't there.
+
+ If the ethercard isn't found there is an optional probe for
+ ethercard jumpered to programmed-I/O mode.
+ */
+
+static int ports[] = {0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
+
int
-el2autoprobe(int ioaddr, struct device *dev)
+el2_probe(struct device *dev)
{
int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0};
- int ports[] = {0x300,0x310,0x330,0x350,0x250,0x280,0x2a0,0x2e0,0};
+ short ioaddr = dev->base_addr;
- /* Non-autoprobe case first: */
+ if (ioaddr < 0)
+ return ENXIO; /* Don't probe at all. */
if (ioaddr > 0)
- return el2probe(ioaddr, dev);
+ return ! el2probe1(ioaddr, dev);
- /* We check for a memory-mapped 3c503 board by looking at the
- port location bitmap at the end of the jumpered boot PROM space.
- This works even if a PROM isn't there. */
for (addr = addrs; *addr; addr++) {
int i;
unsigned int base_bits = *(unsigned char *)*addr;
@@ -62,29 +72,48 @@ el2autoprobe(int ioaddr, struct device *dev)
for(i = 7; i >= 0; i--, base_bits >>= 1)
if (base_bits & 0x1)
break;
- if (base_bits == 1 && el2probe(ports[i], dev))
- return dev->base_addr;
+ if (base_bits != 1)
+ continue;
+#ifdef HAVE_PORTRESERVE
+ if (check_region(ports[i], 16))
+ continue;
+#endif
+ if (el2probe1(ports[i], dev))
+ return 0;
}
-#ifndef ignore_nonshared_memory
- /* It's not memory mapped, bummer. Try all of the locations
- that aren't obviously empty. */
- { int i;
- for (i = 0; i < 8; i++) {
- inb_p(ports[i] + 0x40F); /* Reset any lurking NE2000 */
- if (inb(ports[i] + 0x403) == (0x80 >> i) /* Preliminary check */
- && el2probe(ports[i], dev))
- return dev->base_addr;
- }
+#ifndef no_probe_nonshared_memory
+ return el2_pio_autoprobe(dev);
+#else
+ return ENODEV;
+#endif
+}
+
+/* Try all of the locations that aren't obviously empty. This touches
+ a lot of locations, and is much riskier than the code above. */
+int
+el2_pio_autoprobe(struct device *dev)
+{
+ int i;
+ for (i = 0; i < 8; i++) {
+#ifdef HAVE_PORTRESERVE
+ if (check_region(ports[i], 16))
+ continue;
+#endif
+ /* Reset and/or avoid any lurking NE2000 */
+ if (inb_p(ports[i] + 0x408) == 0xff)
+ continue;
+ if (inb(ports[i] + 0x403) == (0x80 >> i) /* Preliminary check */
+ && el2probe1(ports[i], dev))
+ return 0;
}
-#endif /* probe_nonshared_memory */
- return 0;
+ return ENODEV;
}
/* Probe for the Etherlink II card at I/O port base IOADDR,
returning non-zero on sucess. If found, set the station
address and memory parameters in DEVICE. */
int
-el2probe(int ioaddr, struct device *dev)
+el2probe1(int ioaddr, struct device *dev)
{
int i, iobase_reg, membase_reg, saved_406;
unsigned char *station_addr = dev->dev_addr;
@@ -113,15 +142,32 @@ el2probe(int ioaddr, struct device *dev)
|| station_addr[2] != 0x8c) {
printk(" 3C503 not found.\n");
/* Restore the register we frobbed. */
- outb_p(saved_406, ioaddr + 0x406);
+ outb(saved_406, ioaddr + 0x406);
return 0;
}
+
+#ifdef HAVE_PORTRESERVE
+ snarf_region(ioaddr, 16);
+#endif
+ ethdev_init(dev);
+
/* Map the 8390 back into the window. */
outb(ECNTRL_THIN, ioaddr + 0x406);
dev->base_addr = ioaddr;
/* Probe for, turn on and clear the board's shared memory. */
if (ei_debug > 2) printk(" memory jumpers %2.2x ", membase_reg);
outb(EGACFR_NORM, ioaddr + 0x405); /* Enable RAM */
+
+ /* This should be probed for (or set via an ioctl()) at run-time.
+ Right now we use a sleazy hack to pass in the interface number
+ at boot-time via the low bits of the mem_end field. That value is
+ unused, and the low bits would be discarded even if it was used. */
+#if defined(EI8390_THICK) || defined(EL2_AUI)
+ ei_status.interface_num = 1;
+#else
+ ei_status.interface_num = dev->mem_end & 0xf;
+#endif
+
if ((membase_reg & 0xf0) == 0) {
dev->mem_start = 0;
} else {
@@ -166,62 +212,77 @@ el2probe(int ioaddr, struct device *dev)
ei_status.reset_8390 = &el2_reset_8390;
ei_status.block_input = &el2_block_input;
ei_status.block_output = &el2_block_output;
-/* This should be probed for (or set via an ioctl()) at run-time someday. */
-#if defined(EI8390_THICK) || defined(EL2_AUI)
- ei_status.interface_num = 1;
-#else
- ei_status.interface_num = 0;
-#endif
+
+ if (dev->irq == 2)
+ dev->irq = 9;
+ else if (dev->irq > 5 && dev->irq != 9) {
+ printk("\n3c503: configured interrupt %d invalid, using autoIRQ.\n",
+ dev->irq);
+ dev->irq = 0;
+ }
+
+ ei_status.saved_irq = dev->irq;
+
+ dev->start = 0;
+ dev->open = &el2_open;
+ dev->stop = &el2_close;
+
+ if (dev->mem_start)
+ printk("\n%s: %s with shared memory at %#6x-%#6x,\n",
+ dev->name, ei_status.name, dev->mem_start, dev->mem_end-1);
+ else
+ printk("\n%s: %s using programmed I/O (REJUMPER for SHARED MEMORY).\n",
+ dev->name, ei_status.name);
+ if (ei_debug > 1)
+ printk(version);
+
+ return ioaddr;
+}
+
+static int
+el2_open(struct device *dev)
+{
if (dev->irq < 2) {
int irqlist[] = {5, 9, 3, 4, 0};
int *irqp = irqlist;
+
+ outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */
do {
- if (request_irq (dev->irq = *irqp, NULL) != -EBUSY) {
+ if (request_irq (*irqp, NULL) != -EBUSY) {
/* Twinkle the interrupt, and check if it's seen. */
autoirq_setup(0);
- outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR);
+ outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR);
outb_p(0x00, E33G_IDCFR);
- if (dev->irq == autoirq_report(0) /* It's a good IRQ line! */
- && request_irq (dev->irq, &ei_interrupt) == 0) {
- printk(" got IRQ %d", dev->irq);
+ if (*irqp == autoirq_report(0) /* It's a good IRQ line! */
+ && request_irq (dev->irq = *irqp, &ei_interrupt) == 0)
break;
- } else
- printk(" IRQ%d busy..", dev->irq);
}
} while (*++irqp);
if (*irqp == 0) {
- printk(" unable to find an free IRQ line.\n");
- return 0;
+ outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */
+ return -EAGAIN;
}
} else {
- if (dev->irq == 2)
- dev->irq = 9;
- else if (dev->irq > 5 && dev->irq != 9) {
- printk("\n3c503: configured interrupt number %d out of range.\n",
- dev->irq);
- return 0;
- }
if (request_irq(dev->irq, &ei_interrupt)) {
- printk (" unable to get IRQ%d.\n", dev->irq);
- return 0;
+ return -EAGAIN;
}
}
-
- dev->start = 0;
el2_init_card(dev);
+ return ei_open(dev);
+}
- if (dev->mem_start)
- printk("\n%s: %s using IRQ %d with shared memory at %#6x-%#6x,\n",
- dev->name, ei_status.name, dev->irq,
- dev->mem_start, dev->mem_end-1);
- else
- printk("\n%s: %s using IRQ %d with programmed I/O.\n",
- dev->name, ei_status.name, dev->irq);
- if (ei_debug > 1)
- printk(version);
+static int
+el2_close(struct device *dev)
+{
+ free_irq(dev->irq);
+ dev->irq = ei_status.saved_irq;
+ irq2dev_map[dev->irq] = NULL;
+ outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */
- return ioaddr;
+ NS8390_init(dev, 0);
+
+ return 0;
}
/* This is called whenever we have a unrecoverable failure:
@@ -290,10 +351,10 @@ el2_block_output(struct device *dev, int count,
memcpy(dest_addr, buf, count);
if (ei_debug > 2 && memcmp(dest_addr, buf, count))
printk("%s: 3c503 send_packet() bad memory copy @ %#5x.\n",
- dev->name, dest_addr);
+ dev->name, (int) dest_addr);
else if (ei_debug > 4)
printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n",
- dev->name, dest_addr);
+ dev->name, (int) dest_addr);
return;
}
/* No shared memory, put the packet out the slow way. */
@@ -337,7 +398,7 @@ el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
if (ei_debug > 4)
printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
dev->name, dev->mem_start, ring_offset,
- (char *)dev->mem_start + ring_offset);
+ dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
@@ -346,7 +407,7 @@ el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
if (ei_debug > 4)
printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n",
dev->name, dev->mem_start, ring_offset,
- (char *)dev->mem_start + ring_offset);
+ dev->mem_start + ring_offset);
memcpy(buf, (char *)dev->mem_start + ring_offset, count);
return ring_offset + count;
}
@@ -375,7 +436,6 @@ el2_block_input(struct device *dev, int count, char *buf, int ring_offset)
/*
* Local variables:
- * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c 3c503.c"
* version-control: t
* kept-new-versions: 5
* End:
diff --git a/net/inet/elreg.h b/drivers/net/3c503.h
index a1c8575..f469a92 100644
--- a/net/inet/elreg.h
+++ b/drivers/net/3c503.h
@@ -1,6 +1,7 @@
/* Definitions for the 3Com 3c503 Etherlink 2. */
/* This file is distributed under the GPL.
- Some of these names and comments are from the Crynwr packet drivers. */
+ Many of these names and comments are directly from the Crynwr packet
+ drivers, which are released under the GPL. */
#define EL2H (dev->base_addr + 0x400)
#define EL2L (dev->base_addr)
@@ -11,8 +12,8 @@
#define EL2SM_STOP_PG (0x40) /* Last page +1 of RX ring */
/* 3Com 3c503 ASIC registers */
-#define E33G_STARTPG (EL2H+0) /* Start page, must match EN0_STARTPG */
-#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
+#define E33G_STARTPG (EL2H+0) /* Start page, matching EN0_STARTPG */
+#define E33G_STOPPG (EL2H+1) /* Stop page, must match EN0_STOPPG */
#define E33G_DRQCNT (EL2H+2) /* DMA burst count */
#define E33G_IOBASE (EL2H+3) /* Read of I/O base jumpers. */
/* (non-useful, but it also appears at the end of EPROM space) */
diff --git a/net/inet/3c509.c b/drivers/net/3c509.c
index 172921f..5fb51f3 100644
--- a/net/inet/3c509.c
+++ b/drivers/net/3c509.c
@@ -13,7 +13,7 @@
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
-static char *version = "3c509.c: v0.06 9/3/93 becker@super.org\n";
+static char *version = "3c509.c:pl14 10/18/93 becker@super.org\n";
#include <linux/config.h>
#include <linux/kernel.h>
@@ -23,30 +23,18 @@ static char *version = "3c509.c: v0.06 9/3/93 becker@super.org\n";
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/in.h>
-
-#ifndef PRE_PL13
+#include <linux/malloc.h>
#include <linux/ioport.h>
-#else
-#define snarf_region(base,extent) do {;}while(0)
-#define check_region(base,extent) (0)
-#endif
-
-/*#include <asm/system.h>*/
+#include <asm/bitops.h>
#include <asm/io.h>
-#ifndef port_read
-#include "iow.h"
-#endif
#include "dev.h"
#include "eth.h"
#include "skbuff.h"
#include "arp.h"
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c, should be in a *.h file. */
-extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
-extern struct device *irq2dev_map[16];
+#ifndef port_read
+#include "iow.h"
#endif
/* These should be in <asm/io.h>. */
@@ -55,6 +43,11 @@ __asm__("cld;rep;insl": :"d" (port),"D" (buf),"c" (nr):"cx","di")
#define port_write_l(port,buf,nr) \
__asm__("cld;rep;outsl": :"d" (port),"S" (buf),"c" (nr):"cx","si")
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skb(buff,size) kfree_s(buff,size)
+#endif
+
#ifdef EL3_DEBUG
int el3_debug = EL3_DEBUG;
@@ -96,6 +89,9 @@ static void update_stats(int addr, struct device *dev);
static struct enet_statistics *el3_get_stats(struct device *dev);
static int el3_rx(struct device *dev);
static int el3_close(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
@@ -184,8 +180,11 @@ int el3_probe(struct device *dev)
dev->hard_start_xmit = &el3_start_xmit;
dev->stop = &el3_close;
dev->get_stats = &el3_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
- /* Fill in the generic field of the device structure. */
+ /* Fill in the generic fields of the device structure. */
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
@@ -328,6 +327,7 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
arp_queue (skb);
return 0;
}
+ skb->arp=1;
if (skb->len <= 0)
return 0;
@@ -347,27 +347,26 @@ el3_start_xmit(struct sk_buff *skb, struct device *dev)
}
/* Avoid timer-based retransmission conflicts. */
- dev->tbusy=1;
-
- /* Put out the doubleword header... */
- outw(skb->len, ioaddr + TX_FIFO);
- outw(0x00, ioaddr + TX_FIFO);
- /* ... and the packet rounded to a doubleword. */
- port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
+ if (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else {
+ /* Put out the doubleword header... */
+ outw(skb->len, ioaddr + TX_FIFO);
+ outw(0x00, ioaddr + TX_FIFO);
+ /* ... and the packet rounded to a doubleword. */
+ port_write_l(ioaddr + TX_FIFO, (void *)(skb+1), (skb->len + 3) >> 2);
- dev->trans_start = jiffies;
+ dev->trans_start = jiffies;
+ if (inw(ioaddr + TX_FREE) > 1536) {
+ dev->tbusy=0;
+ } else
+ /* Interrupt us when the FIFO has room for max-sized packet. */
+ outw(0x9000 + 1536, ioaddr + EL3_CMD);
+ }
+
if (skb->free)
kfree_skb (skb, FREE_WRITE);
-
- if (inw(ioaddr + TX_FREE) > 1536) {
- dev->tbusy=0;
- } else
- /* Interrupt us when the FIFO has room for max-sized packet. */
- outw(0x9000 + 1536, ioaddr + EL3_CMD);
- if (el3_debug > 4)
- printk(" Finished queueing packet, FIFO room remaining %d.\n",
- inw(ioaddr + TX_FREE));
/* Clear the Tx status stack. */
{
short tx_status;
@@ -515,8 +514,8 @@ el3_rx(struct device *dev)
short pkt_len = rx_status & 0x7ff;
int sksize = sizeof(struct sk_buff) + pkt_len + 3;
struct sk_buff *skb;
- skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
+ skb = alloc_skb(sksize, GFP_ATOMIC);
if (el3_debug > 4)
printk(" Receiving packet size %d status %4.4x.\n",
pkt_len, rx_status);
@@ -551,7 +550,7 @@ el3_rx(struct device *dev)
continue;
} else {
printk("%s: receive buffers full.\n", dev->name);
- kfree_s(skb, sksize);
+ kfree_skbmem(skb, sksize);
}
#endif
} else if (el3_debug)
@@ -572,6 +571,26 @@ el3_rx(struct device *dev)
return 0;
}
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ short ioaddr = dev->base_addr;
+ if (num_addrs > 0) {
+ outw(0x8007, ioaddr + EL3_CMD);
+ } else if (num_addrs < 0) {
+ outw(0x8008, ioaddr + EL3_CMD);
+ } else
+ outw(0x8005, ioaddr + EL3_CMD);
+}
+#endif
+
static int
el3_close(struct device *dev)
{
diff --git a/drivers/net/8390.c b/drivers/net/8390.c
new file mode 100644
index 0000000..f4f5641
--- /dev/null
+++ b/drivers/net/8390.c
@@ -0,0 +1,757 @@
+/* 8390.c: A general NS8390 ethernet driver core for linux. */
+/*
+ Written 1992,1993 by Donald Becker.
+
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency. This software may be used and
+ distributed according to the terms of the GNU Public License,
+ incorporated herein by reference.
+
+ This is the chip-specific code for many 8390-based ethernet adaptors.
+
+ The Author may be reached as becker@super.org or
+ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+ */
+
+static char *version =
+ "8390.c:v0.99-13f 10/18/93 Donald Becker (becker@super.org)\n";
+#include <linux/config.h>
+
+/*
+ Braindamage remaining:
+
+ Ethernet devices should use a chr_drv device interface, with ioctl()s to
+ configure the card, bring the interface up or down, allow access to
+ statistics, and maybe read() and write() access to raw packets.
+ This won't be done until after Linux 1.00.
+
+ Sources:
+ The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
+ The NE* programming info came from the Crynwr packet driver, and figuring
+ out that the those boards are similar to the NatSemi evaluation board
+ described in AN-729. Thanks NS, no thanks to Novell/Eagle.
+ */
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/fs.h>
+#include <linux/tty.h>
+#include <linux/types.h>
+#include <linux/ptrace.h>
+#include <linux/string.h>
+#include <asm/system.h>
+#include <asm/segment.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <errno.h>
+#include <linux/fcntl.h>
+#include <linux/in.h>
+#include <linux/interrupt.h>
+
+#include "dev.h"
+#include "eth.h"
+#include "ip.h"
+#include "protocol.h"
+#include "tcp.h"
+#include "skbuff.h"
+#include "sock.h"
+#include "arp.h"
+
+#include "8390.h"
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(addr, size) kfree_s(addr,size)
+#endif
+
+#define ei_reset_8390 (ei_local->reset_8390)
+#define ei_block_output (ei_local->block_output)
+#define ei_block_input (ei_local->block_input)
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifdef EI_DEBUG
+int ei_debug = EI_DEBUG;
+#else
+int ei_debug = 1;
+#endif
+
+/* Max number of packets received at one Intr. */
+/*static int high_water_mark = 0;*/
+
+/* Index to functions. */
+/* Put in the device structure. */
+int ei_open(struct device *dev);
+/* Dispatch from interrupts. */
+void ei_interrupt(int reg_ptr);
+static void ei_tx_intr(struct device *dev);
+static void ei_receive(struct device *dev);
+static void ei_rx_overrun(struct device *dev);
+
+/* Routines generic to NS8390-based boards. */
+void NS8390_init(struct device *dev, int startp);
+static void NS8390_trigger_send(struct device *dev, unsigned int length,
+ int start_page);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
+
+/* Open/initialize the board. This routine goes all-out, setting everything
+ up anew at each open, even though many of these registers should only
+ need to be set once at boot.
+ */
+int ei_open(struct device *dev)
+{
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ if ( ! ei_local) {
+ printk("%s: Opening a non-existent physical device\n", dev->name);
+ return 1; /* ENXIO would be more accurate. */
+ }
+
+ irq2dev_map[dev->irq] = dev;
+ NS8390_init(dev, 1);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ /* The old local flags... */
+ ei_local->txing = 0;
+ /* ... are now global. */
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+ ei_local->irqlock = 0;
+ return 0;
+}
+
+static int ei_start_xmit(struct sk_buff *skb, struct device *dev)
+{
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int length, send_length;
+ int tmp_tbusy; /* we must lock dev_tint in dev.c with dev->t_busy =1 */
+ /* because on a slow pc a quasi endless loop can appear */
+
+ if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
+ int txsr = inb(e8390_base+EN0_TSR), isr;
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
+ return 1;
+ }
+ isr = inb(e8390_base+EN0_ISR);
+ printk("%s: transmit timed out, TX status %#2x, ISR %#2x.\n",
+ dev->name, txsr, isr);
+ /* It's possible to check for an IRQ conflict here.
+ I may have to do that someday. */
+ if (isr)
+ printk("%s: Possible IRQ conflict on IRQ%d?", dev->name, dev->irq);
+ else
+ printk("%s: Possible network cable problem?\n", dev->name);
+ /* It futile, but try to restart it anyway. */
+ ei_reset_8390(dev);
+ NS8390_init(dev, 1);
+ printk("\n");
+ }
+
+ /* This is new: it means some higher layer thinks we've missed an
+ tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
+ itself. */
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
+ }
+ /* Fill in the ethernet header. */
+ if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
+ skb->dev = dev;
+ arp_queue (skb);
+ return 0;
+ }
+ skb->arp=1;
+
+ if (skb->len <= 0)
+ return 0;
+ length = skb->len;
+ send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
+ /* Turn off interrupts so that we can put the packet out safely. */
+ cli();
+ if (dev->interrupt || ei_local->irqlock) {
+ /* We should never get here during an interrupt after 0.99.4. */
+ sti();
+ if (ei_debug > 2)
+ printk("%s: Attempt to reenter critical zone%s.\n",
+ dev->name, ei_local->irqlock ? " during interrupt" : "");
+ return 1;
+ }
+ /* Mask interrupts from the ethercard. */
+ outb(0x00, e8390_base + EN0_IMR);
+
+ /* Atomically lock out dev.c:dev_tint(). */
+ tmp_tbusy = set_bit(0, (void*)&dev->tbusy);
+
+ ei_local->irqlock = 1;
+ sti();
+ if (ei_local->pingpong) {
+ int output_page;
+ if (ei_local->tx1 == 0) {
+ output_page = ei_local->tx_start_page;
+ ei_local->tx1 = send_length;
+ if (ei_debug && ei_local->tx2 > 0)
+ printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx2, ei_local->lasttx,
+ ei_local->txing);
+ } else if (ei_local->tx2 == 0) {
+ output_page = ei_local->tx_start_page + 6;
+ ei_local->tx2 = send_length;
+ if (ei_debug && ei_local->tx1 > 0)
+ printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
+ dev->name, ei_local->tx1, ei_local->lasttx,
+ ei_local->txing);
+ } else {
+ /* We can get to here if we get an rx interrupt and queued
+ a tx packet just before masking 8390 irqs above. */
+ if (ei_debug > 2)
+ printk("%s: No packet buffer space for ping-pong use.\n",
+ dev->name);
+ cli();
+ ei_local->irqlock = 0;
+ dev->tbusy = tmp_tbusy;
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ sti();
+ return 1;
+ }
+ dev->trans_start = jiffies;
+ ei_block_output(dev, length, (unsigned char *)(skb+1), output_page);
+ if (! ei_local->txing) {
+ NS8390_trigger_send(dev, send_length, output_page);
+ if (output_page == ei_local->tx_start_page)
+ ei_local->tx1 = -1, ei_local->lasttx = -1;
+ else
+ ei_local->tx2 = -1, ei_local->lasttx = -2;
+ ei_local->txing = 1;
+ } else
+ ei_local->txqueue++;
+ if (ei_local->tx1 && ei_local->tx2)
+ tmp_tbusy = 1;
+ } else {
+ dev->trans_start = jiffies;
+ ei_block_output(dev, length, (unsigned char *)(skb+1),
+ ei_local->tx_start_page);
+ NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
+ tmp_tbusy = 1;
+ } /* PINGPONG */
+
+ if (skb->free)
+ kfree_skb (skb, FREE_WRITE);
+
+ /* Turn 8390 interrupts back on. */
+ cli();
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ ei_local->irqlock = 0;
+ dev->tbusy=tmp_tbusy;
+ sti();
+ return 0;
+}
+
+/* The typical workload of the driver:
+ Handle the ether interface interrupts. */
+void ei_interrupt(int reg_ptr)
+{
+ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ int e8390_base;
+ int interrupts, boguscount = 0;
+ struct ei_device *ei_local;
+
+ if (dev == NULL) {
+ printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ e8390_base = dev->base_addr;
+ ei_local = (struct ei_device *) dev->priv;
+ if (dev->interrupt || ei_local->irqlock) {
+ /* The "irqlock" check is only for testing. */
+ sti();
+ printk(ei_local->irqlock
+ ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
+ : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
+ dev->name, inb_p(e8390_base + EN0_ISR),
+ inb_p(e8390_base + EN0_IMR));
+ return;
+ }
+
+ dev->interrupt = 1;
+ sti(); /* Allow other interrupts. */
+
+ /* Change to page 0 and read the intr status reg. */
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+ if (ei_debug > 3)
+ printk("%s: interrupt(isr=%#2.2x).\n", dev->name,
+ inb_p(e8390_base + EN0_ISR));
+
+ /* !!Assumption!! -- we stay in page 0. Don't break this. */
+ while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
+ && ++boguscount < 20) {
+ if (interrupts & ENISR_RDC) {
+ /* Ack meaningless DMA complete. */
+ outb_p(ENISR_RDC, e8390_base + EN0_ISR);
+ }
+ if (interrupts & ENISR_OVER) {
+ ei_rx_overrun(dev);
+ } else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
+ /* Got a good (?) packet. */
+ ei_receive(dev);
+ }
+ /* Push the next to-transmit packet through. */
+ if (interrupts & ENISR_TX) {
+ ei_tx_intr(dev);
+ } else if (interrupts & ENISR_COUNTERS) {
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
+ ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1);
+ ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
+ outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
+ }
+
+ /* Ignore the transmit errs and reset intr for now. */
+ if (interrupts & ENISR_TX_ERR) {
+ outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
+ }
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ }
+
+ if (interrupts && ei_debug) {
+ printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
+ outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
+ }
+ dev->interrupt = 0;
+ return;
+}
+
+/* We have finished a transmit: check for errors and then trigger the next
+ packet to be sent. */
+static void ei_tx_intr(struct device *dev)
+{
+ int e8390_base = dev->base_addr;
+ int status = inb(e8390_base + EN0_TSR);
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
+
+ if (ei_local->pingpong) {
+ ei_local->txqueue--;
+ if (ei_local->tx1 < 0) {
+ if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
+ printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx1);
+ ei_local->tx1 = 0;
+ dev->tbusy = 0;
+ if (ei_local->tx2 > 0) {
+ NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
+ dev->trans_start = jiffies;
+ ei_local->txing = 1;
+ ei_local->tx2 = -1,
+ ei_local->lasttx = 2;
+ } else
+ ei_local->lasttx = 20, ei_local->txing = 0;
+ } else if (ei_local->tx2 < 0) {
+ if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
+ printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
+ ei_local->name, ei_local->lasttx, ei_local->tx2);
+ ei_local->tx2 = 0;
+ dev->tbusy = 0;
+ if (ei_local->tx1 > 0) {
+ NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
+ dev->trans_start = jiffies;
+ ei_local->txing = 1;
+ ei_local->tx1 = -1;
+ ei_local->lasttx = 1;
+ } else
+ ei_local->lasttx = 10, ei_local->txing = 0;
+ } else
+ printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
+ dev->name, ei_local->lasttx);
+ } else {
+ ei_local->txing = 0;
+ dev->tbusy = 0;
+ }
+
+ /* Do the statistics _after_ we start the next TX. */
+ if (status & ENTSR_PTX)
+ ei_local->stat.tx_packets++;
+ else
+ ei_local->stat.tx_errors++;
+ if (status & ENTSR_COL)
+ ei_local->stat.collisions++;
+ if (status & ENTSR_ABT)
+ ei_local->stat.tx_aborted_errors++;
+ if (status & ENTSR_CRS)
+ ei_local->stat.tx_carrier_errors++;
+ if (status & ENTSR_FU)
+ ei_local->stat.tx_fifo_errors++;
+ if (status & ENTSR_CDH)
+ ei_local->stat.tx_heartbeat_errors++;
+ if (status & ENTSR_OWC)
+ ei_local->stat.tx_window_errors++;
+
+ mark_bh (INET_BH);
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+
+static void ei_receive(struct device *dev)
+{
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int rxing_page, this_frame, next_frame, current_offset;
+ int boguscount = 0;
+ struct e8390_pkt_hdr rx_frame;
+ int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
+
+ while (++boguscount < 10) {
+ int pkt_len;
+
+ /* Get the rx page (incoming packet pointer). */
+ outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
+ rxing_page = inb_p(e8390_base + EN1_CURPAG);
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
+
+ /* Remove one frame from the ring. Boundary is alway a page behind. */
+ this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
+ if (this_frame >= ei_local->stop_page)
+ this_frame = ei_local->rx_start_page;
+
+ /* Someday we'll omit the previous step, iff we never get this message.*/
+ if (ei_debug > 0 && this_frame != ei_local->current_page)
+ printk("%s: mismatched read page pointers %2x vs %2x.\n",
+ dev->name, this_frame, ei_local->current_page);
+
+ if (this_frame == rxing_page) /* Read all the frames? */
+ break; /* Done for now */
+
+ current_offset = this_frame << 8;
+ ei_block_input(dev, sizeof(rx_frame), (char *)&rx_frame,
+ current_offset);
+
+ pkt_len = rx_frame.count - sizeof(rx_frame);
+
+ next_frame = this_frame + 1 + ((pkt_len+4)>>8);
+
+ /* Check for bogosity warned by 3c503 book: the status byte is never
+ written. This happened a lot during testing! This code should be
+ cleaned up someday. */
+ if ( rx_frame.next != next_frame
+ && rx_frame.next != next_frame + 1
+ && rx_frame.next != next_frame - num_rx_pages
+ && rx_frame.next != next_frame + 1 - num_rx_pages) {
+#ifndef EI_DEBUG
+ ei_local->current_page = rxing_page;
+ outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+ continue;
+#else
+ static int last_rx_bogosity = -1;
+ printk("%s: bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n",
+ dev->name, rx_frame.status, rx_frame.next, rx_frame.count,
+ current_offset);
+
+ if (ei_local->stat.rx_packets != last_rx_bogosity) {
+ /* Maybe we can avoid resetting the chip... empty the packet ring. */
+ ei_local->current_page = rxing_page;
+ printk("%s: setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n",
+ dev->name, ei_local->current_page, next_frame,
+ rx_frame.next, rx_frame.status);
+ last_rx_bogosity = ei_local->stat.rx_packets;
+ outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
+ continue;
+ } else {
+ /* Oh no Mr Bill! Last ditch error recovery. */
+ printk("%s: recovery failed, resetting at packet #%d..",
+ dev->name, ei_local->stat.rx_packets);
+ sti();
+ ei_reset_8390(dev);
+ NS8390_init(dev, 1);
+ printk("restarting.\n");
+ return;
+ }
+#endif /* EI8390_NOCHECK */
+ }
+
+ if ((pkt_len < 46 || pkt_len > 1535) && ei_debug)
+ printk("%s: bogus packet size, status=%#2x nxpg=%#2x size=%#x\n",
+ dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
+ if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
+ int sksize = sizeof(struct sk_buff) + pkt_len;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sksize, GFP_ATOMIC);
+ if (skb == NULL) {
+ if (ei_debug)
+ printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+ dev->name, sksize);
+ ei_local->stat.rx_dropped++;
+ break;
+ } else {
+ skb->mem_len = sksize;
+ skb->mem_addr = skb;
+ skb->len = pkt_len;
+ skb->dev = dev;
+
+ /* 'skb+1' points to the start of sk_buff data area. */
+ ei_block_input(dev, pkt_len, (char *)(skb+1),
+ current_offset + sizeof(rx_frame));
+#ifdef HAVE_NETIF_RX
+ netif_rx(skb);
+#else
+ skb->lock = 0;
+ if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev)) {
+ kfree_skbmem(skb, sksize);
+ lp->stats.rx_dropped++;
+ break;
+ }
+#endif
+ ei_local->stat.rx_packets++;
+ }
+ } else {
+ int errs = rx_frame.status;
+ if (ei_debug)
+ printk("%s: bogus packet, status=%#2x nxpg=%#2x size=%d\n",
+ dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
+ if (errs & ENRSR_FO)
+ ei_local->stat.rx_fifo_errors++;
+ }
+ next_frame = rx_frame.next;
+
+ /* This should never happen, it's here for debugging. */
+ if (next_frame >= ei_local->stop_page) {
+ printk("%s: next frame inconsistency, %#2x..", dev->name, next_frame);
+ next_frame = ei_local->rx_start_page;
+ }
+ ei_local->current_page += 1 + ((pkt_len+4)>>8);
+ ei_local->current_page = next_frame;
+ outb(next_frame-1, e8390_base+EN0_BOUNDARY);
+ }
+ /* If any worth-while packets have been received, dev_rint()
+ has done a mark_bh(INET_BH) for us and will work on them
+ when we get to the bottom-half routine. */
+
+ /* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */
+ outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR);
+ return;
+}
+
+/* We have a receiver overrun: we have to kick the 8390 to get it started
+ again.*/
+static void ei_rx_overrun(struct device *dev)
+{
+ int e8390_base = dev->base_addr;
+ int reset_start_time = jiffies;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ /* We should already be stopped and in page0. Remove after testing. */
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
+
+ if (ei_debug)
+ printk("%s: Receiver overrun.\n", dev->name);
+ ei_local->stat.rx_over_errors++;
+
+ /* The we.c driver does dummy = inb_p( RBCR[01] ); at this point.
+ It might mean something -- magic to speed up a reset? A 8390 bug?*/
+
+ /* Wait for reset in case the NIC is doing a tx or rx. This could take up to
+ 1.5msec, but we have no way of timing something in that range. The 'jiffies'
+ are just a sanity check. */
+ while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0)
+ if (jiffies - reset_start_time > 1) {
+ printk("%s: reset did not complete at ei_rx_overrun.\n",
+ dev->name);
+ NS8390_init(dev, 1);
+ return;
+ };
+
+ /* Remove packets right away. */
+ ei_receive(dev);
+
+ outb_p(0xff, e8390_base+EN0_ISR);
+ /* Generic 8390 insns to start up again, same as in open_8390(). */
+ outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
+ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+}
+
+static struct enet_statistics *get_stats(struct device *dev)
+{
+ short ioaddr = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+
+ /* Read the counter registers, assuming we are in page 0. */
+ ei_local->stat.rx_frame_errors += inb_p(ioaddr + EN0_COUNTER0);
+ ei_local->stat.rx_crc_errors += inb_p(ioaddr + EN0_COUNTER1);
+ ei_local->stat.rx_missed_errors+= inb_p(ioaddr + EN0_COUNTER2);
+
+ return &ei_local->stat;
+}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ . best-effort filtering.
+ */
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ short ioaddr = dev->base_addr;
+
+ if (num_addrs > 0) {
+ /* The multicast-accept list is initialized to accept-all, and we
+ rely on higher-level filtering for now. */
+ outb_p(E8390_RXCONFIG | 0x08, ioaddr + EN0_RXCR);
+ } else if (num_addrs < 0)
+ outb_p(E8390_RXCONFIG | 0x10, ioaddr + EN0_RXCR);
+ else
+ outb_p(E8390_RXCONFIG, ioaddr + EN0_RXCR);
+}
+#endif
+
+/* Initialize the rest of the 8390 device structure. */
+int ethdev_init(struct device *dev)
+{
+ int i;
+
+ if (ei_debug > 1)
+ printk(version);
+
+ if (dev->priv == NULL) {
+ struct ei_device *ei_local;
+
+ dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct ei_device));
+ ei_local = (struct ei_device *)dev->priv;
+#ifndef NO_PINGPONG
+ ei_local->pingpong = 1;
+#endif
+ }
+
+ /* The open call may be overridden by the card-specific code. */
+ if (dev->open == NULL)
+ dev->open = &ei_open;
+ /* We should have a dev->stop entry also. */
+ dev->hard_start_xmit = &ei_start_xmit;
+ dev->get_stats = get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
+
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ dev->buffs[i] = NULL;
+
+ dev->hard_header = eth_header;
+ dev->add_arp = eth_add_arp;
+ dev->queue_xmit = dev_queue_xmit;
+ dev->rebuild_header = eth_rebuild_header;
+ dev->type_trans = eth_type_trans;
+
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_len = ETH_HLEN;
+ dev->mtu = 1500; /* eth_mtu */
+ dev->addr_len = ETH_ALEN;
+ for (i = 0; i < ETH_ALEN; i++) {
+ dev->broadcast[i]=0xff;
+ }
+
+ /* New-style flags. */
+ dev->flags = IFF_BROADCAST;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = sizeof(unsigned long);
+
+ return 0;
+}
+
+
+/* This page of functions should be 8390 generic */
+/* Follow National Semi's recommendations for initializing the "NIC". */
+void NS8390_init(struct device *dev, int startp)
+{
+ int e8390_base = dev->base_addr;
+ struct ei_device *ei_local = (struct ei_device *) dev->priv;
+ int i;
+ int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
+
+ /* Follow National Semi's recommendations for initing the DP83902. */
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
+ outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
+ /* Clear the remote byte count registers. */
+ outb_p(0x00, e8390_base + EN0_RCNTLO);
+ outb_p(0x00, e8390_base + EN0_RCNTHI);
+ /* Set to monitor and loopback mode -- this is vital!. */
+ outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
+ outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
+ /* Set the transmit page and receive ring. */
+ outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
+ ei_local->tx1 = ei_local->tx2 = 0;
+ outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
+ outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
+ ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
+ outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
+ /* Clear the pending interrupts and mask. */
+ outb_p(0xFF, e8390_base + EN0_ISR);
+ outb_p(0x00, e8390_base + EN0_IMR);
+
+ /* Copy the station address into the DS8390 registers,
+ and set the multicast hash bitmap to receive all multicasts. */
+ cli();
+ outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
+ for(i = 0; i < 6; i++) {
+ outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
+ }
+ /* Initialize the multicast list to accept-all. If we enable multicast
+ the higher levels can do the filtering. */
+ for(i = 0; i < 8; i++)
+ outb_p(0xff, e8390_base + EN1_MULT + i);
+
+ outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
+ sti();
+ if (startp) {
+ outb_p(0xff, e8390_base + EN0_ISR);
+ outb_p(ENISR_ALL, e8390_base + EN0_IMR);
+ outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
+ outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
+ /* 3c503 TechMan says rxconfig only after the NIC is started. */
+ outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
+ }
+ return;
+}
+
+/* Trigger a transmit start, assuming the length is valid. */
+static void NS8390_trigger_send(struct device *dev, unsigned int length,
+ int start_page)
+{
+ int e8390_base = dev->base_addr;
+
+ ei_status.txing = 1;
+ outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
+
+ if (inb_p(e8390_base) & E8390_TRANS) {
+ printk("%s: trigger_send() called with the transmitter busy.\n",
+ dev->name);
+ return;
+ }
+ outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
+ outb_p(length >> 8, e8390_base + EN0_TCNTHI);
+ outb_p(start_page, e8390_base + EN0_TPSR);
+ outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
+ return;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 8390.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * tab-width: 4
+ * End:
+ */
diff --git a/net/inet/8390.h b/drivers/net/8390.h
index 08e763e..08e763e 100644
--- a/net/inet/8390.h
+++ b/drivers/net/8390.h
diff --git a/net/inet/CONFIG b/drivers/net/CONFIG
index 694fc0d..2ec4be3 100644
--- a/net/inet/CONFIG
+++ b/drivers/net/CONFIG
@@ -36,10 +36,6 @@
# D_LINK_DEBUG Enable or disable D-Link debugging
#
-# This is at the top level with 'make config'
-CARDS =
-
-
OPTS = #-DEI8390=0 -DEI8390_IRQ=0
WD_OPTS = #-DWD_SHMEM=0
EL2_OPTS = #-UEL2_AUI
@@ -47,5 +43,5 @@ NE_OPTS =
HP_OPTS =
PLIP_OPTS =
SLIP_OPTS = -DSL_DUMP -DSL_COMPRESSED
-DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
+DL_OPTS = # -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG
AT_OPTS = # -DLANCE_DMA=5
diff --git a/net/inet/LICENSE.SRC b/drivers/net/LICENSE.SRC
index 500940a..500940a 100644
--- a/net/inet/LICENSE.SRC
+++ b/drivers/net/LICENSE.SRC
diff --git a/drivers/net/Makefile b/drivers/net/Makefile
new file mode 100644
index 0000000..c473451
--- /dev/null
+++ b/drivers/net/Makefile
@@ -0,0 +1,140 @@
+# File: net/drv/Makefile
+#
+# Makefile for the Linux network (ethercard) 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).
+#
+# Note 2! The CFLAGS definition is now in the main makefile...
+
+include CONFIG
+
+.c.s:
+ $(CC) $(CFLAGS) -S -o $*.s $<
+.s.o:
+ $(AS) -o $*.o $<
+.c.o:
+ $(CC) $(CFLAGS) -c -o $*.o $<
+
+NETDRV_OBJS := Space.o auto_irq.o
+CFLAGS := $(CFLAGS) -I../../net/inet
+CPP := $(CPP) -I../../net/inet
+
+# The point of the makefile...
+all: net.a
+
+Space.o: Space.c /usr/include/linux/autoconf.h
+ $(CC) $(CFLAGS) $(OPTS) $(DL_OPTS) -c $< -o $@
+
+ifdef CONFIG_WD80x3
+NETDRV_OBJS := $(NETDRV_OBJS) wd.o
+CONFIG_8390 = CONFIG_8390
+wd.o: wd.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c wd.c
+endif
+
+ifdef CONFIG_EL2
+NETDRV_OBJS := $(NETDRV_OBJS) 3c503.o
+CONFIG_8390 = CONFIG_8390
+3c503.o: 3c503.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c 3c503.c
+endif
+
+ifdef CONFIG_NE2000
+NETDRV_OBJS := $(NETDRV_OBJS) ne.o
+CONFIG_8390 = CONFIG_8390
+ne.o: ne.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c ne.c
+endif
+
+ifdef CONFIG_HPLAN
+NETDRV_OBJS := $(NETDRV_OBJS) hp.o
+CONFIG_8390 = CONFIG_8390
+hp.o: hp.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c hp.c
+endif
+
+ifdef CONFIG_ULTRA
+NETDRV_OBJS := $(NETDRV_OBJS) smc-ultra.o
+CONFIG_8390 = CONFIG_8390
+endif
+
+ifdef CONFIG_8390
+NETDRV_OBJS := $(NETDRV_OBJS) 8390.o
+endif
+
+ifdef CONFIG_PLIP
+NETDRV_OBJS := $(NETDRV_OBJS) plip.o
+plip.o: plip.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c plip.c
+endif
+
+ifdef CONFIG_SLIP
+NETDRV_OBJS := $(NETDRV_OBJS) slip.o slhc.o
+slip.o: slip.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(SLIP_OPTS) -c slip.c
+endif
+
+ifdef CONFIG_DE600
+NETDRV_OBJS := $(NETDRV_OBJS) d_link.o
+d_link.o: d_link.c CONFIG
+ $(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c d_link.c
+endif
+
+ifdef CONFIG_AT1500
+NETDRV_OBJS := $(NETDRV_OBJS) lance.o
+endif
+
+ifdef CONFIG_EL3
+NETDRV_OBJS := $(NETDRV_OBJS) 3c509.o
+endif
+
+ifdef CONFIG_ZNET
+NETDRV_OBJS := $(NETDRV_OBJS) znet.o
+endif
+ifdef CONFIG_EEXPRESS
+NETDRV_OBJS := $(NETDRV_OBJS) eexpress.o
+endif
+ifdef CONFIG_EL1
+NETDRV_OBJS := $(NETDRV_OBJS) 3c501.o
+endif
+ifdef CONFIG_EL16
+NETDRV_OBJS := $(NETDRV_OBJS) 3c507.o
+endif
+ifdef CONFIG_DEPCA
+NETDRV_OBJS := $(NETDRV_OBJS) depca.o
+endif
+ifdef CONFIG_ATP
+NETDRV_OBJS := $(NETDRV_OBJS) atlantec.o
+endif
+ifdef CONFIG_NI52
+NETDRV_OBJS := $(NETDRV_OBJS) ni52.o
+endif
+ifdef CONFIG_NI65
+NETDRV_OBJS := $(NETDRV_OBJS) ni65.o
+endif
+
+ifdef CONFIG_IP_DEFRAG
+NETDRV_OBJS := $(NETDRV_OBJS) ip-frag.o
+endif
+
+net.a: $(NETDRV_OBJS)
+ rm -f $@
+ $(AR) rcs $@ $^
+
+clean:
+ rm -f core *.o *.a *.s
+
+dep:
+ $(CPP) -M *.c > .depend
+
+tar:
+ tar -cvf /dev/f1 .
+
+#
+# include a dependency file if one exists
+#
+ifeq (.depend,$(wildcard .depend))
+include .depend
+endif
diff --git a/net/inet/README.8390 b/drivers/net/README.8390
index 87af97b..87af97b 100644
--- a/net/inet/README.8390
+++ b/drivers/net/README.8390
diff --git a/drivers/net/README.DLINK b/drivers/net/README.DLINK
new file mode 100644
index 0000000..192d4bd
--- /dev/null
+++ b/drivers/net/README.DLINK
@@ -0,0 +1,177 @@
+This is version 0.32
+
+ CONTENTS:
+
+ 1. Introduction.
+ 2. License.
+ 3. Files in this release.
+ 4. Installation.
+ 5. Problems and tuning.
+ 6. Acknowledgments.
+
+
+ 1. INTRODUCTION.
+
+ This is an Ethernet driver for the D-Link DE-600 Ethernet pocket
+ adapter for the parallel port, used with Linux on a laptop.
+ Some improvements over the 0.2X releases include:
+ o driver code trying to send packets end to end,
+ o a more solid interrupt handler,
+ o a fix that modifies the tcp protocol so that
+ the DE-600 won't choke as easily on receives.
+
+ This is a beta release, i.e. it ought to work! (:-)
+
+ I have used this driver for NFS, ftp, telnet and X-clients on
+ remote machines. Transmissions with ftp seems to work as
+ good as can be expected (i.e. > 80k bytes/sec) from a
+ parallel port...:-)
+ The speed limit is now in the upper protocols,
+ at least for a 386SX-25 :-)
+
+ All comments/fixes to Bjorn Ekwall (bj0rn@blox.se).
+
+ (No, I have _not_ included any support for the DE-620 yet
+ since I have _no_ official documentation on how to program
+ that beast. There are some code modifications in place
+ already in case I get some _real_ info..., c'mon D-Link!)
+
+
+ 2. LICENSE.
+
+ This program is free software; you can redistribute it
+ and/or modify it under the terms of the GNU General Public
+ License as published by the Free Software Foundation; either
+ version 2, or (at your option) any later version.
+
+ This program is distributed in the hope that it will be
+ useful, but WITHOUT ANY WARRANTY; without even the implied
+ warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
+ PURPOSE. See the GNU General Public License for more
+ details.
+
+ You should have received a copy of the GNU General Public
+ License along with this program; if not, write to the Free
+ Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
+ 02139, USA.
+
+
+ 3. FILES IN THIS RELEASE.
+
+ README.DLINK This file.
+ d_link.c The Source (,may it be with You :-).
+
+
+ 4. INSTALLATION.
+
+ o Get the latest net binaries (those referring to /conf/net).
+
+ o Read the NET-2 and Ethernet HOWTO's and modify your setup.
+
+ o To include networking and the DE600 in your kernel, do:
+ # cd /linux
+ # make config (answer yes on net and DE600)
+ # make clean
+ # make depend
+ # make zImage (or whatever magic you usually do)
+
+ o I use lilo to boot multiple kernels, so that I at least
+ can have one working kernel :-). If you do too, append
+ these lines to /etc/lilo/config:
+
+ image = /usr/src/linux/zImage
+ label = newlinux
+ root = /dev/hda2 (or whatever YOU have...)
+
+ # /etc/lilo/install
+
+ o Do "sync" and reboot the new kernel with a D-Link pocket
+ adapter connected.
+
+ Now, watch for any fireworks (try to ignore (or live with)
+ the smoke... :-) or:
+
+ do
+ read NET-FAQ and all info in /conf/net
+ if fix in code needed...
+ vi /linux/net/inet/d_link.c
+ cd /linux
+ make zImage
+ /etc/lilo/install
+ sync
+ reboot
+ endif
+ try it...
+ until satisfied
+
+
+ 5. "PROBLEMS" AND TUNING,
+
+ o Some machines have trouble handling the parallel port and
+ the adapter at high speed. If you experience problems:
+
+ - The adapter is not recognized at boot, i.e. an Ethernet
+ adress of 00:80:c8:... is not shown, try to add another
+ "; SLOW_DOWN_IO"
+ at D_LINK_SLOW_DOWN near line 43. As a last resort, uncomment:
+ "#define REALLY_SLOW_IO"
+ near line 48 (see <asm/io.h> for hints).
+
+ - You experience "timeout" messages: first try to add
+ another "; SLOW_DOWN_IO" at D_LINK_SLOW_DOWN near line 22,
+ _then_ try to increase the value (original value: 5)
+ at "if (tickssofar < 5)" near line 424.
+
+ - The adapter _is_ recognized at boot but you get
+ messages about "Network Unreachable": The problem
+ is probably _not_ with the d_link driver.
+ Check your net configuration instead (ifconfig and route)
+ in "rc.inet1".
+
+ o There might be some temporary "slowdowns" when communicating
+ with other systems when receiving through the TCP layer.
+ A "fix" for this is made lastly in the source, in the function
+ "d_link_rspace()" that is used to modify TCP if there is
+ a DE-600 in use (see comments around lines 320 and 730).
+
+ The aim of this fix is to reduce the possibility of more
+ than two packets arriving adressed to the adapter within
+ the timespan it takes to copy one packet from the adapter.
+
+ Transfers with ftp with a packetsize of >= 1k will be taken
+ care of with this "fix", but telnet with many small packets
+ might run into problems sometimes. The "slowdown" will usually
+ take care of itself, especially if there are some larger packets
+ arriving now and then...
+
+ There is some room for "tuning" by changing (decreasing) the
+ values for "D_LINK_MAX_WINDOW" and "D_LINK_MIN_WINDOW"
+ defined near the end of the file (around line 726).
+ UDP (i.e. NFS) does not suffer from the same problem.
+
+ o The code inside d_link_interrupt() is somewhat of a
+ (educated) guesswork since my only source of information
+ is the asm-source (:-), though I have tried to improve on it.
+
+ o There is some rudimentary support for debugging, see
+ the source. Use "-DD_LINK_DEBUG=3" when compiling.
+
+
+ 6. ACKNOWLEDGMENTS.
+
+ This driver wouldn't have been done without the base
+ (and support) from Ross Biro (bir7@leland.stanford.edu).
+ The driver also relies upon GPL-ed source from D-Link Inc.
+ and from Russel Nelson at Crynwr Software (nelson@crynwr.com).
+ Additional input also from Donald Becker (becker@super.org).
+ Alpha release primary victim^H^H^H^H^H^Htester:
+ Erik Proper (erikp@cs.kun.nl).
+ Good input also from several users, most notably Mark Burton
+ <markb@ordern.demon.co.uk>.
+ Lastly, Fred van Kempen deserves all thanks for keeping up
+ the good work which will give us all a _great_ net package!
+
+
+ Happy hacking!
+
+ Bjorn Ekwall == bj0rn@blox.se
diff --git a/net/inet/README1.PLIP b/drivers/net/README1.PLIP
index d68745b..d68745b 100644
--- a/net/inet/README1.PLIP
+++ b/drivers/net/README1.PLIP
diff --git a/net/inet/README2.PLIP b/drivers/net/README2.PLIP
index 63b4754..63b4754 100644
--- a/net/inet/README2.PLIP
+++ b/drivers/net/README2.PLIP
diff --git a/net/inet/Space.c b/drivers/net/Space.c
index b63db1f..64d8bb4 100644
--- a/net/inet/Space.c
+++ b/drivers/net/Space.c
@@ -37,6 +37,7 @@
ethernet adaptor have the name "eth[0123...]".
*/
+extern int ultra_probe(struct device *dev);
extern int wd_probe(struct device *dev);
extern int el2_probe(struct device *dev);
extern int ne_probe(struct device *dev);
@@ -58,6 +59,9 @@ ethif_probe(struct device *dev)
return 1; /* ENXIO */
if (1
+#if defined(CONFIG_ULTRA)
+ && ultra_probe(dev)
+#endif
#if defined(CONFIG_WD80x3) || defined(WD80x3)
&& wd_probe(dev)
#endif
diff --git a/net/inet/auto_irq.c b/drivers/net/auto_irq.c
index e3be4cb..e3be4cb 100644
--- a/net/inet/auto_irq.c
+++ b/drivers/net/auto_irq.c
diff --git a/net/inet/d_link.c b/drivers/net/d_link.c
index 22d6248..a8e7972 100644
--- a/net/inet/d_link.c
+++ b/drivers/net/d_link.c
@@ -1,66 +1,29 @@
+static char *version =
+ "d_link.c: $Revision: 0.32 $, Bjorn Ekwall (bj0rn@blox.se)\n";
/*
* d_link.c
*
+ * Linux driver for the D-Link DE-600 Ethernet pocket adapter.
+ *
* Portions (C) Copyright 1993 by Bjorn Ekwall
* The Author may be reached as bj0rn@blox.se
*
- * Linux driver for the D-Link Ethernet pocket adapter.
- * Based on sources from linux 0.99pl5
- * and on a sample network driver core for linux.
- *
- * Sample driver written 1993 by Donald Becker <becker@super.org>
- * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
- *
- * compile-command:
- * "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -c d_link.c"
- */
-/*************************************************************
- * If you have trouble reading/writing to the adapter,
- * uncomment the following "#define":
-#define REALLY_SLOW_IO
- */
-
-/* $Id: d_link.c,v 0.21 1993/06/02 19:41:00 waltje Exp $ */
-/* $Log: d_link.c,v $
- * Revision 0.21 1993/06/02 19:41:00 waltje
- * Applied multi-IRQ fix from Bjorn Ekwall and increaded version
- * number to 0.21.
- *
- * Revision 0.20 1993/03/26 11:43:53 root
- * Changed version number to indicate "alpha+" (almost beta :-)
- *
- * Revision 0.16 1993/03/26 11:26:46 root
- * Last ALPHA-minus version.
- * REALLY_SLOW_IO choice included (at line 20)
- * SLOW_DOWN_IO added anyway in convenience macros/functions
- * Test of D_LINK_FIFO included (not completely debugged)
- *
- * Revision 0.15 1993/03/24 14:00:49 root
- * Modified the interrupt handling considerably.
- * (The .asm source had me fooled in how it _really_ works :-)
- *
- * Revision 0.14 1993/03/21 01:57:25 root
- * Modified the interrupthandler for more robustness (hopefully :-)
- *
- * Revision 0.13 1993/03/19 11:45:09 root
- * Re-write of ALPHA release using Don Beckers skeleton (still works, kind of ...:-)
- *
- * Revision 0.12 1993/03/16 13:22:21 root
- * working ALPHA-release
- *
- */
-
-static char *version =
- "d_link.c: $Revision: 0.21 $, Bjorn Ekwall (bj0rn@blox.se)\n";
-
-/*
* Based on adapter information gathered from DE600.ASM by D-Link Inc.,
* as included on disk C in the v.2.11 of PC/TCP from FTP Software.
- *
* For DE600.asm:
* Portions (C) Copyright 1990 D-Link, Inc.
* Copyright, 1988-1992, Russell Nelson, Crynwr Software
*
+ * Adapted to the sample network driver core for linux,
+ * written by: Donald Becker <becker@super.org>
+ * C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+ *
+ * compile-command:
+ * "gcc -D__KERNEL__ -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer \
+ * -m486 -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG -S d_link.c
+ *
+ **************************************************************/
+/*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
@@ -75,8 +38,31 @@ static char *version =
* along with this program; if not, write to the Free Software
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*
+ **************************************************************/
+/* Add another "; SLOW_DOWN_IO" here if your adapter won't work OK: */
+#define D_LINK_SLOW_DOWN SLOW_DOWN_IO; SLOW_DOWN_IO; SLOW_DOWN_IO
+
+ /*
+ * If you still have trouble reading/writing to the adapter,
+ * modify the following "#define": (see <asm/io.h> for more info)
+#define REALLY_SLOW_IO
*/
+#define SLOW_IO_BY_JUMPING /* Looks "better" than dummy write to port 0x80 :-) */
+/*
+ * For fix to TCP "slowdown", take a look at the "#define D_LINK_MAX_WINDOW"
+ * near the end of the file...
+ */
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifdef D_LINK_DEBUG
+#define PRINTK(x) if (d_link_debug >= 2) printk x
+#else
+#define D_LINK_DEBUG 0
+#define PRINTK(x) /**/
+#endif
+static unsigned int d_link_debug = D_LINK_DEBUG;
+
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
@@ -101,17 +87,10 @@ static char *version =
#include "sock.h"
#include "arp.h"
+#define netstats enet_statistics
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef D_LINK_DEBUG
-#define D_LINK_DEBUG 0
-#endif
-static unsigned int d_link_debug = D_LINK_DEBUG;
-
-#ifdef D_LINK_DEBUG
-#define PRINTK(x) if (d_link_debug >= 2) printk x
-#else
-#define PRINTK(x) /**/
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size,pri) (struct sk_buff *)kmalloc(size,pri)
#endif
/**************************************************
@@ -122,9 +101,34 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
/*
* D-Link Ethernet pocket adapter ports
*/
+/*
+ * OK, so I'm cheating, but there are an awful lot of
+ * reads and writes in order to get anything in and out
+ * of the DE-600 with 4 bits at a time in the parallel port,
+ * so every saved instruction really helps :-)
+ *
+ * That is, I don't care what the device struct says
+ * but hope that Space.c will keep the rest of the drivers happy.
+ */
+#ifndef D_LINK_IO
+#define D_LINK_IO 0x378
+#endif
+
+#define DATA_PORT (D_LINK_IO)
+#define STATUS_PORT (D_LINK_IO + 1)
+#define COMMAND_PORT (D_LINK_IO + 2)
+
+#ifndef D_LINK_IRQ
+#define D_LINK_IRQ 7
+#endif
+/*
+ * It really should look like this, and autoprobing as well...
+ *
#define DATA_PORT (dev->base_addr + 0)
#define STATUS_PORT (dev->base_addr + 1)
#define COMMAND_PORT (dev->base_addr + 2)
+#define D_LINK_IRQ dev->irq
+ */
/*
* D-Link COMMAND_PORT commands
@@ -137,10 +141,10 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
/*
* D-Link STATUS_PORT
*/
-#define TX_INTR 0x88
-#define RX_INTR 0x40
-
-#define OTHER_INTR 0x00 /* dummy, always false */
+#define RX_BUSY 0x80
+#define RX_GOOD 0x40
+#define TX_FAILED16 0x10
+#define TX_BUSY 0x08
/*
* D-Link DATA_PORT commands
@@ -160,12 +164,11 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
or-ed with rest of command */
/*
- * command register, (I don't know all about these bits...)
- * accessed through DATA_PORT with low bits = COMMAND
+ * command register, accessed through DATA_PORT with low bits = COMMAND
*/
-#define RX_ALL 0x01 /* bit 0,1 = 01 */
-#define RX_BP 0x02 /* bit 0,1 = 10 */
-#define RX_MBP 0x03 /* bit 0,1 = 11 */
+#define RX_ALL 0x01 /* PROMISCIOUS */
+#define RX_BP 0x02 /* default: BROADCAST & PHYSICAL ADRESS */
+#define RX_MBP 0x03 /* MULTICAST, BROADCAST & PHYSICAL ADRESS */
#define TX_ENABLE 0x04 /* bit 2 */
#define RX_ENABLE 0x08 /* bit 3 */
@@ -181,9 +184,6 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
#define RX_BASE_PAGE 0x20 /* bit 5, always set when specifying RX_ADDR */
#define FLIP_IRQ 0x40 /* bit 6 */
-/* Convenience definition, transmitter page 2 */
-#define TX_PAGE2_SELECT 0x02
-
/*
* D-Link adapter internal memory:
*
@@ -197,9 +197,10 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
*/
#define MEM_2K 0x0800 /* 2048 */
#define MEM_4K 0x1000 /* 4096 */
+#define MEM_6K 0x1800 /* 6144 */
#define NODE_ADDRESS 0x2000 /* 8192 */
-#define RUNT 64 /*56*/ /* Too small Ethernet packet */
+#define RUNT 60 /* Too small Ethernet packet */
/**************************************************
* *
@@ -207,137 +208,105 @@ static unsigned int d_link_debug = D_LINK_DEBUG;
* *
**************************************************/
-/* Common network statistics -- these will be in *.h someday. */
-struct netstats {
- int tx_packets;
- int rx_packets;
- int tx_errors;
- int rx_errors;
- int missed_packets;
- int soft_tx_errors;
- int soft_rx_errors;
- int soft_trx_err_bits;
-};
-static struct netstats *localstats;
-
/*
* Index to functions, as function prototypes.
*/
-/* Routines used internally. (See "convenience macros" also) */
+/* For tricking tcp.c to announce a small max window (max 2 fast packets please :-) */
+static unsigned long d_link_rspace(struct sock *sk);
+
+/* Routines used internally. (See "convenience macros") */
static int d_link_read_status(struct device *dev);
-static unsigned char d_link_read_byte(int type, struct device *dev);
+static unsigned char d_link_read_byte(unsigned char type, struct device *dev);
/* Put in the device structure. */
static int d_link_open(struct device *dev);
static int d_link_close(struct device *dev);
+static struct netstats *get_stats(struct device *dev);
static int d_link_start_xmit(struct sk_buff *skb, struct device *dev);
/* Dispatch from interrupts. */
static void d_link_interrupt(int reg_ptr);
-static void d_link_tx_intr(struct device *dev);
+static int d_link_tx_intr(struct device *dev, int irq_status);
static void d_link_rx_intr(struct device *dev);
/* Initialization */
+static void trigger_interrupt(struct device *dev);
int d_link_init(struct device *dev);
-static void adapter_init(struct device *dev, int startp);
-
-/* Passed to sigaction() to register the interrupt handler. */
-static struct sigaction d_link_sigaction = {
- &d_link_interrupt,
- 0,
- 0,
- NULL,
- };
+static void adapter_init(struct device *dev);
/*
* D-Link driver variables:
*/
+extern struct device *irq2dev_map[16];
static volatile int rx_page = 0;
-static struct device *realdev;
-#ifdef D_LINK_FIFO
-static volatile int free_tx_page = 0x03; /* 2 pages = 0000 0011 */
-static volatile unsigned int busy_tx_page = 0x00; /* 2 pages = 0000 0000 */
-static volatile int transmit_next_from;
-#endif
+
+#define TX_PAGES 2
+static volatile int tx_fifo[TX_PAGES];
+static volatile int tx_fifo_in = 0;
+static volatile int tx_fifo_out = 0;
+static volatile int free_tx_pages = TX_PAGES;
/*
* Convenience macros/functions for D-Link adapter
- *
- * If you are having trouble reading/writing correctly,
- * try to uncomment the line "#define REALLY_SLOW_IO" (near line 20)
*/
-#define select_prn() \
- outb_p(SELECT_PRN, COMMAND_PORT)
-
-#define select_nic() \
- outb_p(SELECT_NIC, COMMAND_PORT)
+#define select_prn() outb_p(SELECT_PRN, COMMAND_PORT); D_LINK_SLOW_DOWN
+#define select_nic() outb_p(SELECT_NIC, COMMAND_PORT); D_LINK_SLOW_DOWN
-#define d_link_put_byte(data) \
- outb_p(((data) << 4) | WRITE_DATA , DATA_PORT); \
- outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT)
+/* Thanks for hints from Mark Burton <markb@ordern.demon.co.uk> */
+#define d_link_put_byte(data) ( \
+ outb_p(((data) << 4) | WRITE_DATA , DATA_PORT), \
+ outb_p(((data) & 0xf0) | WRITE_DATA | HI_NIBBLE, DATA_PORT))
/*
* The first two outb_p()'s below could perhaps be deleted if there
* would be more delay in the last two. Not certain about it yet...
*/
-#define d_link_put_command(cmd) \
- outb_p(( rx_page << 4) | COMMAND , DATA_PORT); \
- outb_p(( rx_page & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT); \
- outb_p(((rx_page | cmd) << 4) | COMMAND , DATA_PORT); \
- outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT)
-
-#define d_link_setup_address(addr,type) \
- outb_p((((addr) << 4) & 0xf0) | type , DATA_PORT); \
- outb_p(( (addr) & 0xf0) | type | HI_NIBBLE, DATA_PORT); \
- outb_p((((addr) >> 4) & 0xf0) | type , DATA_PORT); \
- outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT)
+#define d_link_put_command(cmd) ( \
+ outb_p(( rx_page << 4) | COMMAND , DATA_PORT), \
+ outb_p(( rx_page & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT), \
+ outb_p(((rx_page | cmd) << 4) | COMMAND , DATA_PORT), \
+ outb_p(((rx_page | cmd) & 0xf0) | COMMAND | HI_NIBBLE, DATA_PORT))
-static int
+#define d_link_setup_address(addr,type) ( \
+ outb_p((((addr) << 4) & 0xf0) | type , DATA_PORT), \
+ outb_p(( (addr) & 0xf0) | type | HI_NIBBLE, DATA_PORT), \
+ outb_p((((addr) >> 4) & 0xf0) | type , DATA_PORT), \
+ outb_p((((addr) >> 8) & 0xf0) | type | HI_NIBBLE, DATA_PORT))
+
+#define rx_page_adr() ((rx_page & RX_PAGE2_SELECT)?(MEM_6K):(MEM_4K))
+
+/* Flip bit, only 2 pages */
+#define next_rx_page() (rx_page ^= RX_PAGE2_SELECT)
+
+#define tx_page_adr(a) (((a) + 1) * MEM_2K)
+
+static inline int
d_link_read_status(struct device *dev)
{
int status;
- select_nic();
outb_p(STATUS, DATA_PORT);
- SLOW_DOWN_IO; /* See comment line 20 */
- status = inb_p(STATUS_PORT);
- outb_p(NULL_COMMAND, DATA_PORT);
+ status = inb(STATUS_PORT);
outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT);
return status;
}
-static unsigned char
-d_link_read_byte(int type, struct device *dev) { /* dev used by macros */
+static inline unsigned char
+d_link_read_byte(unsigned char type, struct device *dev) { /* dev used by macros */
unsigned char lo;
- outb_p((type), DATA_PORT);
- SLOW_DOWN_IO; /* See comment line 20 */
- lo = inb_p(STATUS_PORT);
- outb_p((type) | HI_NIBBLE, DATA_PORT);
- SLOW_DOWN_IO; /* See comment line 20 */
- return ((lo & 0xf0) >> 4) | (inb_p(STATUS_PORT) & 0xf0);
+ (void)outb_p((type), DATA_PORT);
+ lo = ((unsigned char)inb(STATUS_PORT)) >> 4;
+ (void)outb_p((type) | HI_NIBBLE, DATA_PORT);
+ return ((unsigned char)inb(STATUS_PORT) & (unsigned char)0xf0) | lo;
}
-
-#ifdef D_LINK_FIFO
- /* Handle a "fifo" in an int (= busy_tx_page) */
-# define AT_FIFO_OUTPUT (busy_tx_page & 0x0f)
-# define ANY_QUEUED_IN_FIFO (busy_tx_page & 0xf0)
-
-# define PULL_FROM_FIFO { busy_tx_page >>= 4;}
-# define PUSH_INTO_FIFO(page) { \
- if (busy_tx_page) /* there already is a transmit in progress */ \
- busy_tx_page |= (page << 4); \
- else \
- busy_tx_page = page; \
- }
-#endif
/*
* Open/initialize the board. This is called (in the current kernel)
- * sometime after booting when the 'config <dev->name>' program is run.
+ * after booting when 'ifconfig <dev->name> $IP_ADDR' is run (in rc.inet1).
*
* This routine should set everything up anew at each open, even
* registers that "should" only need to be set once at boot, so that
@@ -346,10 +315,27 @@ d_link_read_byte(int type, struct device *dev) { /* dev used by macros */
static int
d_link_open(struct device *dev)
{
- adapter_init(dev, 1);
- dev->tbusy = 0; /* Transmit busy... */
- dev->interrupt = 0;
- dev->start = 1;
+ extern struct proto tcp_prot;
+
+ if (request_irq(D_LINK_IRQ, d_link_interrupt)) {
+ printk ("%s: unable to get IRQ %d\n", dev->name, D_LINK_IRQ);
+ return 1;
+ }
+ irq2dev_map[D_LINK_IRQ] = dev;
+
+ adapter_init(dev);
+
+ /*
+ * Yes, I know!
+ * This is really not nice, but since a machine that uses DE-600
+ * rarely uses any other TCP/IP connection device simultaneously,
+ * this hack shouldn't really slow anything up.
+ * (I don't know about slip though... but it won't break it)
+ *
+ * This fix is better than changing in tcp.h IMHO
+ */
+ tcp_prot.rspace = d_link_rspace; /* was: sock_rspace */
+
return 0;
}
@@ -359,13 +345,35 @@ d_link_open(struct device *dev)
static int
d_link_close(struct device *dev)
{
+ select_nic();
+ rx_page = 0;
+ d_link_put_command(RESET);
+ d_link_put_command(STOP_RESET);
+ d_link_put_command(0);
+ select_prn();
+
+ free_irq(D_LINK_IRQ);
+ irq2dev_map[D_LINK_IRQ] = NULL;
dev->start = 0;
+ tcp_prot.rspace = sock_rspace; /* see comment above! */
- adapter_init(dev, 0);
+ return 0;
+}
- irqaction(dev->irq, NULL);
+static struct netstats *
+get_stats(struct device *dev)
+{
+ return (struct netstats *)(dev->priv);
+}
- return 0;
+static inline void
+trigger_interrupt(struct device *dev)
+{
+ d_link_put_command(FLIP_IRQ);
+ select_prn();
+ D_LINK_SLOW_DOWN;
+ select_nic();
+ d_link_put_command(0);
}
/*
@@ -375,7 +383,6 @@ d_link_close(struct device *dev)
static int
d_link_start_xmit(struct sk_buff *skb, struct device *dev)
{
- static int tx_page = 0;
int transmit_from;
int len;
int tickssofar;
@@ -383,7 +390,7 @@ d_link_start_xmit(struct sk_buff *skb, struct device *dev)
/*
* If some higher layer thinks we've missed a
- * tx-done interrupt * we are passed NULL.
+ * tx-done interrupt we are passed NULL.
* Caution: dev_tint() handles the cli()/sti() itself.
*/
@@ -393,22 +400,19 @@ d_link_start_xmit(struct sk_buff *skb, struct device *dev)
}
/* For ethernet, fill in the header (hardware addresses) with an arp. */
- if (!skb->arp && dev->rebuild_header(skb + 1, dev)) {
- skb->dev = dev;
- arp_queue (skb);
- return 0;
- }
+ if (!skb->arp)
+ if(dev->rebuild_header(skb + 1, dev)) {
+ skb->dev = dev;
+ arp_queue (skb);
+ return 0;
+ }
+ skb->arp = 1;
-#ifdef D_LINK_FIFO
- if (free_tx_page == 0) { /* Do timeouts, to avoid hangs. */
-#else
- if (dev->tbusy) { /* Do timeouts, to avoid hangs. */
-#endif
+ if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */
tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5) {
+ if (tickssofar < 5)
return 1;
- }
/* else */
printk("%s: transmit timed out (%d), %s?\n",
@@ -416,62 +420,42 @@ d_link_start_xmit(struct sk_buff *skb, struct device *dev)
tickssofar,
"network cable problem"
);
- /* Try to restart the adapter. */
- /* Maybe in next release... :-)
- adapter_init(dev, 1);
- */
+ /* Restart the adapter. */
+ adapter_init(dev);
}
/* Start real output */
- PRINTK(("d_link_start_xmit:len=%d\n", skb->len));
- cli();
- select_nic();
+ PRINTK(("d_link_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages));
-#ifdef D_LINK_FIFO
- /* magic code selects the least significant bit in free_tx_page */
- tx_page = free_tx_page & (-free_tx_page);
-
- free_tx_page &= ~tx_page;
- dev->tbusy = !free_tx_page; /* any more free pages? */
-
- PUSH_INTO_FIFO(tx_page);
-#else
- tx_page ^= TX_PAGE2_SELECT; /* Flip page, only 2 pages */
-#endif
-
- if ((len = skb->len) < RUNT) /*&& Hmm...? */
+ if ((len = skb->len) < RUNT)
len = RUNT;
- if (tx_page & TX_PAGE2_SELECT)
- transmit_from = MEM_4K - len;
- else
- transmit_from = MEM_2K - len;
+ cli();
+ select_nic();
+
+ tx_fifo[tx_fifo_in] = transmit_from = tx_page_adr(tx_fifo_in) - len;
+ tx_fifo_in = (tx_fifo_in + 1) % TX_PAGES; /* Next free tx page */
d_link_setup_address(transmit_from, RW_ADDR);
+ for ( ; len > 0; --len, ++buffer)
+ d_link_put_byte(*buffer);
- for ( ; len > 0; --len, ++buffer) {
- d_link_put_byte(*buffer); /* macro! watch out for side effects! */
- }
-
-#ifdef D_LINK_FIFO
- if (ANY_QUEUED_IN_FIFO == 0) { /* there is no transmit in progress */
+ if (free_tx_pages-- == TX_PAGES) { /* No transmission going on */
+ dev->trans_start = jiffies;
+ dev->tbusy = 0; /* allow more packets into adapter */
+ /* Send page and generate an interrupt */
d_link_setup_address(transmit_from, TX_ADDR);
d_link_put_command(TX_ENABLE);
- dev->trans_start = jiffies;
- } else {
- transmit_next_from = transmit_from;
}
-#else
- d_link_setup_address(transmit_from, TX_ADDR);
- d_link_put_command(TX_ENABLE);
- dev->trans_start = jiffies;
-#endif
-
+ else {
+ dev->tbusy = !free_tx_pages;
+ select_prn();
+ }
+
sti(); /* interrupts back on */
- if (skb->free) {
+ if (skb->free)
kfree_skb (skb, FREE_WRITE);
- }
return 0;
}
@@ -484,139 +468,121 @@ static void
d_link_interrupt(int reg_ptr)
{
int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
- struct device *dev = realdev;
- int interrupts;
-
- /* Get corresponding device */
-/*
- for (dev = dev_base; dev != NULL; dev = dev->next) {
- if (dev->irq == irq)
- break;
- }
-*/
- if (dev == NULL) {
- printk ("d_link_interrupt(): irq %d for unknown device.\n", irq);
+ struct device *dev = irq2dev_map[irq];
+ unsigned char irq_status;
+ int retrig = 0;
+ int boguscount = 0;
+
+ /* This might just as well be deleted now, no crummy drivers present :-) */
+ if ((dev == NULL) || (dev->start == 0) || (D_LINK_IRQ != irq)) {
+ printk("%s: bogus interrupt %d\n", dev?dev->name:"DE-600", irq);
return;
}
- if (dev->start == 0) {
- return; /*&& bogus interrupt at boot!?!?!? */
- }
-
- cli();
dev->interrupt = 1;
- sti(); /* Allow other interrupts. */
-
- localstats = (struct netstats*) dev->priv;
+ select_nic();
+ irq_status = d_link_read_status(dev);
- interrupts = d_link_read_status(dev);
+ do {
+ PRINTK(("d_link_interrupt (%2.2X)\n", irq_status));
- PRINTK(("d_link_interrupt (%2.2X)\n", interrupts));
+ if (irq_status & RX_GOOD)
+ d_link_rx_intr(dev);
+ else if (!(irq_status & RX_BUSY))
+ d_link_put_command(RX_ENABLE);
- /*
- * Interrupts have been observed to be:
- *
- * Value My interpretation
- * ----- -----------------
- * 0x47 Normal receive interrupt
- * 0x4F Receive AND transmit interrupt simultaneously
- * 0x87 Normal transmit interrupt (? I treat it as such...)
- * 0x8F Normal transmit interrupt
- */
+ /* Any transmission in progress? */
+ if (free_tx_pages < TX_PAGES)
+ retrig = d_link_tx_intr(dev, irq_status);
+ else
+ retrig = 0;
+ irq_status = d_link_read_status(dev);
+ } while ( (irq_status & RX_GOOD) || ((++boguscount < 10) && retrig) );
/*
- * Take care of TX interrupts first, in case there is an extra
- * page to transmit (keep the adapter busy while we work).
+ * Yeah, it _looks_ like busy waiting, smells like busy waiting
+ * and I know it's not PC, but please, it will only occur once
+ * in a while and then only for a loop or so (< 1ms for sure!)
*/
- if (interrupts & TX_INTR) { /* 1xxx 1xxx */
- d_link_tx_intr(dev);
- }
-
- if (interrupts & RX_INTR) { /* x1xx xxxx */
- d_link_rx_intr(dev);
- }
-
- /* I'm not sure if there are any other interrupts from D-Link... */
- if (d_link_debug && (interrupts & OTHER_INTR)) {
- printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
- }
-
- /* Check comment near line 20! */
- if ( (interrupts != 0x47) &&
- (interrupts != 0x87) &&
- (interrupts != 0x4F) &&
- (interrupts != 0x8F)
- )
- printk("Strange d_link_interrupt: <%2.2X>\n", interrupts);
-
- cli();
- dev->interrupt = 0;
/* Enable adapter interrupts */
+ dev->interrupt = 0;
select_prn();
+
+ if (retrig)
+ trigger_interrupt(dev);
+
+ sti();
return;
}
-/*
- * Do internal handshake: Transmitter done (of this page).
- * Also handle the case of a pending transmit page.
- */
-static void
-d_link_tx_intr(struct device *dev)
+static int
+d_link_tx_intr(struct device *dev, int irq_status)
{
- localstats->tx_packets++;
+ /*
+ * Returns 1 if tx still not done
+ */
- cli();
- dev->tbusy = 0;
+ mark_bh(INET_BH);
+ /* Check if current transmission is done yet */
+ if (irq_status & TX_BUSY)
+ return 1; /* tx not done, try again */
-#ifdef D_LINK_FIFO
- free_tx_page |= AT_FIFO_OUTPUT;
- PULL_FROM_FIFO;
+ /* else */
+ /* If last transmission OK then bump fifo index */
+ if (!(irq_status & TX_FAILED16)) {
+ tx_fifo_out = (tx_fifo_out + 1) % TX_PAGES;
+ ++free_tx_pages;
+ ((struct netstats *)(dev->priv))->tx_packets++;
+ dev->tbusy = 0;
+ }
- if (AT_FIFO_OUTPUT != 0) { /* more in queue! */
- d_link_setup_address(transmit_next_from, TX_ADDR);
- d_link_put_command(TX_ENABLE);
+ /* More to send, or resend last packet? */
+ if ((free_tx_pages < TX_PAGES) || (irq_status & TX_FAILED16)) {
dev->trans_start = jiffies;
+ d_link_setup_address(tx_fifo[tx_fifo_out], TX_ADDR);
+ d_link_put_command(TX_ENABLE);
+ return 1;
}
-#endif
+ /* else */
- mark_bh(INET_BH);
- sti();
+ return 0;
}
/*
- * We have a good packet(s), get it/them out of the buffers.
+ * We have a good packet, get it out of the adapter.
*/
static void
d_link_rx_intr(struct device *dev)
{
struct sk_buff *skb;
int i;
+ int read_from;
int size;
int sksize;
- unsigned char *buffer;
+ register unsigned char *buffer;
+ cli();
/* Get size of received packet */
- /* Ignore trailing 4 CRC-bytes */
- size = d_link_read_byte(RX_LEN, dev); /* low byte */
- size = size + (d_link_read_byte(RX_LEN, dev) << 8) - 4;
+ size = d_link_read_byte(RX_LEN, dev); /* low byte */
+ size += (d_link_read_byte(RX_LEN, dev) << 8); /* high byte */
+ size -= 4; /* Ignore trailing 4 CRC-bytes */
/* Tell adapter where to store next incoming packet, enable receiver */
- rx_page ^= RX_PAGE2_SELECT; /* Flip bit, only 2 pages */
+ read_from = rx_page_adr();
+ next_rx_page();
d_link_put_command(RX_ENABLE);
+ sti();
- if (size == 0) /* Read all the frames? */
- return; /* Done for now */
-
- if ((size < 32 || size > 1535) && d_link_debug)
+ if ((size < 32) || (size > 1535))
printk("%s: Bogus packet size %d.\n", dev->name, size);
sksize = sizeof(struct sk_buff) + size;
- if ((skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC)) == NULL) {
- if (d_link_debug) {
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, sksize);
- }
+ skb = alloc_skb(sksize, GFP_ATOMIC);
+ sti();
+ if (skb == NULL) {
+ printk("%s: Couldn't allocate a sk_buff of size %d.\n",
+ dev->name, sksize);
return;
}
/* else */
@@ -627,33 +593,20 @@ d_link_rx_intr(struct device *dev)
/* 'skb + 1' points to the start of sk_buff data area. */
buffer = (unsigned char *)(skb + 1);
- /* Get packet */
-
- /* Tell adapter from where we want to read this packet */
- if (rx_page & RX_PAGE2_SELECT) {
- d_link_setup_address(MEM_4K, RW_ADDR);
- } else {
- d_link_setup_address(MEM_4K + MEM_2K, RW_ADDR);
- }
-
/* copy the packet into the buffer */
- for (i = size; i > 0; --i) {
- *buffer++ = d_link_read_byte(READ_DATA, dev);
- }
+ d_link_setup_address(read_from, RW_ADDR);
+ for (i = size; i > 0; --i, ++buffer)
+ *buffer = d_link_read_byte(READ_DATA, dev);
- localstats->rx_packets++; /* count all receives */
+ ((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */
- if(dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev)) {
+ if (dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev))
printk("%s: receive buffers full.\n", dev->name);
- return;
- }
-
/*
* If any worth-while packets have been received, dev_rint()
* has done a mark_bh(INET_BH) for us and will work on them
* when we get to the bottom-half routine.
*/
- return;
}
int
@@ -661,24 +614,25 @@ d_link_init(struct device *dev)
{
int i;
- printk("%s: D-Link pocket adapter", dev->name);
+ printk("%s: D-Link DE-600 pocket adapter", dev->name);
/* Alpha testers must have the version number to report bugs. */
if (d_link_debug > 1)
printk(version);
/* probe for adapter */
rx_page = 0;
+ select_nic();
(void)d_link_read_status(dev);
d_link_put_command(RESET);
d_link_put_command(STOP_RESET);
if (d_link_read_status(dev) & 0xf0) {
- printk(": probe failed at %#3x.\n", dev->base_addr);
+ printk(": not at I/O %#3x.\n", DATA_PORT);
return ENODEV;
}
/*
* Maybe we found one,
- * have to check if it is a D-Link adapter...
+ * have to check if it is a D-Link DE-600 adapter...
*/
/* Get the adapter ethernet address from the ROM */
@@ -697,10 +651,15 @@ d_link_init(struct device *dev)
dev->dev_addr[3] &= 0x0f;
dev->dev_addr[3] |= 0x70;
} else {
- printk(", not found in printer port!\n");
+ printk(" not identified in the printer port\n");
return ENODEV;
}
+ printk(", Ethernet Address: %2.2X", dev->dev_addr[0]);
+ for (i = 1; i < ETH_ALEN; i++)
+ printk(":%2.2X",dev->dev_addr[i]);
+ printk("\n");
+
/* Initialize the device structure. */
dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL);
memset(dev->priv, 0, sizeof(struct netstats));
@@ -708,14 +667,15 @@ d_link_init(struct device *dev)
for (i = 0; i < DEV_NUMBUFFS; i++)
dev->buffs[i] = NULL;
+ dev->get_stats = get_stats;
dev->hard_header = eth_header;
dev->add_arp = eth_add_arp;
dev->queue_xmit = dev_queue_xmit;
dev->rebuild_header = eth_rebuild_header;
dev->type_trans = eth_type_trans;
- dev->open = &d_link_open;
- dev->stop = &d_link_close;
+ dev->open = d_link_open;
+ dev->stop = d_link_close;
dev->hard_start_xmit = &d_link_start_xmit;
/* These are ethernet specific. */
@@ -732,54 +692,75 @@ d_link_init(struct device *dev)
dev->pa_mask = 0;
dev->pa_alen = sizeof(unsigned long);
- if (irqaction (dev->irq, &d_link_sigaction)) {
- printk (": unable to get IRQ %d\n", dev->irq);
- return 0;
- }
-
- printk(", Ethernet Address: %2.2X", dev->dev_addr[0]);
- for (i = 1; i < ETH_ALEN; i++)
- printk(":%2.2X",dev->dev_addr[i]);
- printk("\n");
-
+ select_prn();
return 0;
}
static void
-adapter_init(struct device *dev, int startp)
+adapter_init(struct device *dev)
{
int i;
- cli(); /* no interrupts yet, please */
+ cli();
+ dev->tbusy = 0; /* Transmit busy... */
+ dev->interrupt = 0;
+ dev->start = 1;
select_nic();
- rx_page = 0;
+ rx_page = 0; /* used by RESET */
d_link_put_command(RESET);
d_link_put_command(STOP_RESET);
- if (startp) {
- irqaction (dev->irq, &d_link_sigaction);
- realdev = dev;
-#ifdef D_LINK_FIFO
- free_tx_page = 0x03; /* 2 pages = 0000 0011 */
- busy_tx_page = 0x00; /* 2 pages = 0000 0000 */
-#endif
- /* set the ether address. */
- d_link_setup_address(NODE_ADDRESS, RW_ADDR);
- for (i = 0; i < ETH_ALEN; i++) {
- d_link_put_byte(dev->dev_addr[i]);
- }
+ tx_fifo_in = 0;
+ tx_fifo_out = 0;
+ free_tx_pages = TX_PAGES;
- /* where to start saving incoming packets */
- rx_page = 0 | RX_BP | RX_BASE_PAGE;
- d_link_setup_address(MEM_4K, RW_ADDR);
- /* Enable receiver */
- d_link_put_command(RX_ENABLE);
- }
- else
- d_link_put_command(0);
+ /* set the ether address. */
+ d_link_setup_address(NODE_ADDRESS, RW_ADDR);
+ for (i = 0; i < ETH_ALEN; i++)
+ d_link_put_byte(dev->dev_addr[i]);
+ /* where to start saving incoming packets */
+ rx_page = RX_BP | RX_BASE_PAGE;
+ d_link_setup_address(MEM_4K, RW_ADDR);
+ /* Enable receiver */
+ d_link_put_command(RX_ENABLE);
select_prn();
-
sti();
}
+
+#define D_LINK_MIN_WINDOW 1024
+#define D_LINK_MAX_WINDOW 2048
+#define D_LINK_TCP_WINDOW_DIFF 1024
+/*
+ * Copied from sock.c
+ *
+ * Sets a lower max receive window in order to achieve <= 2
+ * packets arriving at the adapter in fast succession.
+ * (No way that a DE-600 can cope with an ethernet saturated with its packets :-)
+ *
+ * Since there are only 2 receive buffers in the DE-600
+ * and it takes some time to copy from the adapter,
+ * this is absolutely necessary for any TCP performance whatsoever!
+ *
+ */
+#define min(a,b) ((a)<(b)?(a):(b))
+static unsigned long
+d_link_rspace(struct sock *sk)
+{
+ int amt;
+
+ if (sk != NULL) {
+/*
+ * Hack! You might want to play with commenting away the following line,
+ * if you know what you do!
+ */
+ sk->max_unacked = D_LINK_MAX_WINDOW - D_LINK_TCP_WINDOW_DIFF;
+
+ if (sk->rmem_alloc >= SK_RMEM_MAX-2*D_LINK_MIN_WINDOW) return(0);
+ amt = min((SK_RMEM_MAX-sk->rmem_alloc)/2-D_LINK_MIN_WINDOW, D_LINK_MAX_WINDOW);
+ if (amt < 0) return(0);
+ return(amt);
+ }
+ return(0);
+}
diff --git a/drivers/net/eexpress.c b/drivers/net/eexpress.c
new file mode 100644
index 0000000..53c61bb
--- /dev/null
+++ b/drivers/net/eexpress.c
@@ -0,0 +1,1023 @@
+/* eexpress.c: Intel EtherExpress device driver for Linux. */
+/*
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and distributed
+ according to the terms of the GNU Public License as modified by SRC,
+ incorported herein by reference.
+
+ The author may be reached as becker@super.org or
+ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+ Things remaining to do:
+ Check that the 586 and ASIC are reset/unreset at the right times.
+ Check tx and rx buffer setup.
+ The current Tx is single-buffer-only.
+ Move the theory of operation and memory map documentation.
+ Rework the board error reset
+ The statistics need to be updated correctly.
+*/
+
+static char *version =
+ "eexpress.c:v0.04 10/18/93 Donald Becker (becker@super.org)\n";
+
+#include <linux/config.h>
+
+/*
+ Sources:
+ This driver wouldn't have been written with the availability of the
+ Crynwr driver source code. It provided a known-working implementation
+ that filled in the gaping holes of the Intel documention. Three cheers
+ for Russ Nelson.
+
+ Intel Microcommunications Databook, Vol. 1, 1990. It provides just enough
+ info that the casual reader might think that it documents the i82586.
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+#include <memory.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif
+
+/* use 0 for production, 1 for verification, 2..7 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/*
+ Details of the i82586.
+
+ You'll really need the databook to understand the details of this part,
+ but the outline is that the i82586 has two seperate processing units.
+
+ The Rx unit uses a list of frame descriptors and a list of data buffer
+ descriptors. We use full-sized (1518 byte) data buffers, so there is
+ a one-to-one pairing of frame descriptors to buffer descriptors.
+
+ The Tx ("command") unit executes a list of commands that look like:
+ Status word Written by the 82586 when the command is done.
+ Command word Command in lower 3 bits, post-command action in upper 3
+ Link word The address of the next command.
+ Parameters (as needed).
+
+ Some definitions related to the Command Word are:
+ */
+#define CMD_EOL 0x8000 /* The last command of the list, stop. */
+#define CMD_SUSP 0x4000 /* Suspend after doing cmd. */
+#define CMD_INTR 0x2000 /* Interrupt after doing cmd. */
+
+enum commands {
+ CmdNOp = 0, CmdSASetup = 1, CmdConfigure = 2, CmdMulticastList = 3,
+ CmdTx = 4, CmdTDR = 5, CmdDump = 6, CmdDiagnose = 7};
+
+/* Information that need to be kept for each board. */
+struct net_local {
+ struct enet_statistics stats;
+ int last_restart;
+ short rx_head;
+ short rx_tail;
+ short tx_head;
+ short tx_cmd_link;
+ short tx_reap;
+};
+
+/*
+ Details of the EtherExpress Implementation
+ The EtherExpress takes an unusual approach to host access to packet buffer
+ memory. The host can use either the Dataport, with independent
+ autoincrementing read and write pointers, or it can I/O map 32 bytes of the
+ memory using the "Shadow Memory Pointer" (SMB) as follows:
+ ioaddr Normal EtherExpress registers
+ ioaddr+0x4000...0x400f Buffer Memory at SMB...SMB+15
+ ioaddr+0x8000...0x800f Buffer Memory at SMB+16...SMB+31
+ ioaddr+0xC000...0xC007 "" SMB+16...SMB+23 (hardware flaw?)
+ ioaddr+0xC008...0xC00f Buffer Memory at 0x0008...0x000f
+ The last I/O map set is useful if you put the i82586 System Command Block
+ (the command mailbox) exactly at 0x0008. (There seems to be some
+ undocumented init structure at 0x0000-7, so I had to use the Crywnr memory
+ setup verbatim for those four words anyway.)
+
+ A problem with using either one of these mechanisms is that you must run
+ single-threaded, or the interrupt handler must restore a changed value of
+ the read, write, or SMB pointers.
+
+ Unlike the Crynwr driver, my driver mostly ignores the I/O mapped "feature"
+ and relies heavily on the dataport for buffer memory access. To minimize
+ switching, the read_pointer is dedicated to the Rx interrupt handler, and
+ the write_pointer is used by the send_packet() routine (it's carefully saved
+ and restored when it's needed by the interrupt handler).
+ */
+
+/* Offsets from the base I/O address. */
+#define DATAPORT 0 /* Data Transfer Register. */
+#define WRITE_PTR 2 /* Write Address Pointer. */
+#define READ_PTR 4 /* Read Address Pointer. */
+#define SIGNAL_CA 6 /* Frob the 82586 Channel Attention line. */
+#define SET_IRQ 7 /* IRQ Select. */
+#define SHADOW_PTR 8 /* Shadow Memory Bank Pointer. */
+#define MEM_Ctrl 11
+#define MEM_Page_Ctrl 12
+#define Config 13
+#define EEPROM_Ctrl 14
+#define ID_PORT 15
+
+/* EEPROM_Ctrl bits. */
+
+#define EE_SHIFT_CLK 0x01 /* EEPROM shift clock. */
+#define EE_CS 0x02 /* EEPROM chip select. */
+#define EE_DATA_WRITE 0x04 /* EEPROM chip data in. */
+#define EE_DATA_READ 0x08 /* EEPROM chip data out. */
+#define EE_CTRL_BITS (EE_SHIFT_CLK | EE_CS | EE_DATA_WRITE | EE_DATA_READ)
+#define ASIC_RESET 0x40
+#define _586_RESET 0x80
+
+/* Offsets into the System Control Block structure. */
+#define SCB_STATUS 0xc008
+#define SCB_CMD 0xc00A
+#define CUC_START 0x0100
+#define CUC_RESUME 0x0200
+#define CUC_SUSPEND 0x0300
+#define RX_START 0x0010
+#define RX_RESUME 0x0020
+#define RX_SUSPEND 0x0030
+#define SCB_CBL 0xc00C /* Command BLock offset. */
+#define SCB_RFA 0xc00E /* Rx Frame Area offset. */
+
+/*
+ What follows in 'init_words[]' is the "program" that is downloaded to the
+ 82586 memory. It's mostly tables and command blocks, and starts at the
+ reset address 0xfffff6.
+
+ Even with the additional "don't care" values, doing it this way takes less
+ program space than initializing the individual tables, and I feel it's much
+ cleaner.
+
+ The databook is particularly useless for the first two structures, I had
+ to use the Crynwr driver as an example.
+
+ The memory setup is as follows:
+ */
+
+#define CONFIG_CMD 0x0018
+#define SET_SA_CMD 0x0024
+#define SA_OFFSET 0x002A
+#define IDLELOOP 0x30
+#define TDR_CMD 0x38
+#define TDR_TIME 0x3C
+#define DUMP_CMD 0x40
+#define DIAG_CMD 0x48
+#define SET_MC_CMD 0x4E
+#define DUMP_DATA 0x56 /* A 170 byte buffer for dump and Set-MC into. */
+
+#define TX_BUF_START 0x0100
+#define NUM_TX_BUFS 4
+#define TX_BUF_SIZE (1518+14+20+16) /* packet+header+TBD */
+
+#define RX_BUF_START 0x2000
+#define RX_BUF_SIZE (0x640) /* packet+header+RBD+extra */
+#define RX_BUF_END 0x8000
+
+/*
+ That's it: only 86 bytes to set up the beast, including every extra
+ command available. The 170 byte buffer at DUMP_DATA is shared between the
+ Dump command (called only by the diagnostic program) and the SetMulticastList
+ command.
+
+ To complete the memory setup you only have to write the station address at
+ SA_OFFSET and create the Tx & Rx buffer lists.
+
+ The Tx command chain and buffer list is setup as follows:
+ A Tx command table, with the data buffer pointing to...
+ A Tx data buffer descriptor. The packet is in a single buffer, rather than
+ chaining together several smaller buffers.
+ A NoOp command, which initially points to itself,
+ And the packet data.
+
+ A transmit is done by filling in the Tx command table and data buffer,
+ re-writing the NoOp command, and finally changing the offset of the last
+ command to point to the current Tx command. When the Tx command is finished,
+ it jumps to the NoOp, when it loops until the next Tx command changes the
+ "link offset" in the NoOp. This way the 82586 never has to go through the
+ slow restart sequence.
+
+ The Rx buffer list is set up in the obvious ring structure. We have enough
+ memory (and low enough interrupt latency) that we can avoid the complicated
+ Rx buffer linked lists by alway associating a full-size Rx data buffer with
+ each Rx data frame.
+
+ I current use four transmit buffers starting at TX_BUF_START (0x0100), and
+ use the rest of memory, from RX_BUF_START to RX_BUF_END, for Rx buffers.
+
+ */
+
+short init_words[] = {
+ 0x0000, /* Set bus size to 16 bits. */
+ 0x0000,0x0000, /* Set control mailbox (SCB) addr. */
+ 0,0, /* pad to 0x000000. */
+ 0x0001, /* Status word that's cleared when init is done. */
+ 0x0008,0,0, /* SCB offset, (skip, skip) */
+
+ 0,0xf000|RX_START|CUC_START, /* SCB status and cmd. */
+ CONFIG_CMD, /* Command list pointer, points to Configure. */
+ RX_BUF_START, /* Rx block list. */
+ 0,0,0,0, /* Error count: CRC, align, buffer, overrun. */
+
+ /* 0x0018: Configure command. Change to put MAC data with packet. */
+ 0, CmdConfigure, /* Status, command. */
+ SET_SA_CMD, /* Next command is Set Station Addr. */
+ 0x0804, /* "4" bytes of config data, 8 byte FIFO. */
+ 0x2e40, /* Magic values, including MAC data location. */
+ 0, /* Unused pad word. */
+
+ /* 0x0024: Setup station address command. */
+ 0, CmdSASetup,
+ SET_MC_CMD, /* Next command. */
+ 0xaa00,0xb000,0x0bad, /* Station address (to be filled in) */
+
+ /* 0x0030: NOP, looping back to itself. Point to first Tx buffer to Tx. */
+ 0, CmdNOp, IDLELOOP, 0 /* pad */,
+
+ /* 0x0038: A unused Time-Domain Reflectometer command. */
+ 0, CmdTDR, IDLELOOP, 0,
+
+ /* 0x0040: An unused Dump State command. */
+ 0, CmdDump, IDLELOOP, DUMP_DATA,
+
+ /* 0x0048: An unused Diagnose command. */
+ 0, CmdDiagnose, IDLELOOP,
+
+ /* 0x004E: An empty set-multicast-list command. */
+#ifdef initial_text_tx
+ 0, CmdMulticastList, DUMP_DATA, 0,
+#else
+ 0, CmdMulticastList, IDLELOOP, 0,
+#endif
+
+ /* 0x0056: A continuous transmit command, only here for testing. */
+ 0, CmdTx, DUMP_DATA, DUMP_DATA+8, 0x803ff, -1, DUMP_DATA, 0,
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int express_probe(struct device *dev); /* Called from Space.c */
+
+static int eexp_probe1(struct device *dev, short ioaddr);
+static int eexp_open(struct device *dev);
+static int eexp_send_packet(struct sk_buff *skb, struct device *dev);
+static void eexp_interrupt(int reg_ptr);
+static void eexp_rx(struct device *dev);
+static int eexp_close(struct device *dev);
+static struct enet_statistics *eexp_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+static int read_eeprom(int ioaddr, int location);
+static void hardware_send_packet(struct device *dev, void *buf, short length);
+static void init_82586_mem(struct device *dev);
+static void init_rx_bufs(struct device *dev);
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+ If dev->base_addr == 2, (detachable devices only) alloate space for the
+ device and return success.
+ */
+int
+express_probe(struct device *dev)
+{
+ /* Don't probe all settable addresses, 0x[23][0-7]0, just common ones. */
+ int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0};
+ int base_addr = dev->base_addr;
+
+ if (base_addr > 0x1ff) /* Check a single specified location. */
+ return eexp_probe1(dev, base_addr);
+ else if (base_addr > 0)
+ return ENXIO; /* Don't probe at all. */
+
+ for (port = &ports[0]; *port; port++) {
+ short id_addr = *port + ID_PORT;
+ unsigned short sum = 0;
+ int i;
+#ifdef notdef
+ for (i = 16; i > 0; i--)
+ sum += inb(id_addr);
+#else
+ for (i = 4; i > 0; i--) {
+ short id_val = inb(id_addr);
+ sum |= (id_val >> 4) << ((id_val & 3) << 2);
+ }
+#endif
+ if (sum == 0xbaba
+ && eexp_probe1(dev, *port) == 0)
+ return 0;
+ }
+
+ return ENODEV; /* ENODEV would be more accurate. */
+}
+
+int eexp_probe1(struct device *dev, short ioaddr)
+{
+ unsigned short station_addr[3];
+ int i;
+
+ printk("%s: EtherExpress at %#x,", dev->name, ioaddr);
+
+ /* The station address is stored !backwards! in the EEPROM, reverse
+ after reading. (Hmmm, a little brain-damage there at Intel, eh?) */
+ station_addr[0] = read_eeprom(ioaddr, 2);
+ station_addr[1] = read_eeprom(ioaddr, 3);
+ station_addr[2] = read_eeprom(ioaddr, 4);
+
+ /* Check the first three octets of the S.A. for the manufactor's code. */
+ if (station_addr[2] != 0x00aa || (station_addr[1] & 0xff00) != 0x0000) {
+ printk(" rejected (invalid address %04x%04x%04x).\n",
+ station_addr[2], station_addr[1], station_addr[0]);
+ return ENODEV;
+ }
+
+ /* We've committed to using the board, and can start filling in *dev. */
+ snarf_region(ioaddr, 16);
+ dev->base_addr = ioaddr;
+
+ outb(ASIC_RESET, ioaddr + EEPROM_Ctrl);
+
+ for (i = 0; i < 6; i++) {
+ dev->dev_addr[i] = ((unsigned char*)station_addr)[5-i];
+ printk(" %02x", dev->dev_addr[i]);
+ }
+
+ /* There is no reason for the driver to care, but I print out the
+ interface to minimize bogus bug reports. */
+ {
+ char irqmap[] = {0, 9, 3, 4, 5, 10, 11, 0};
+ char *ifmap[] = {"AUI", "BNC", "10baseT"};
+ enum iftype {AUI=0, BNC=1, TP=2};
+ unsigned short setupval = read_eeprom(ioaddr, 0);
+
+ dev->irq = irqmap[setupval >> 13];
+ dev->if_port = (setupval & 0x1000) == 0 ? AUI :
+ read_eeprom(ioaddr, 5) & 0x1 ? TP : BNC;
+ printk(", IRQ %d, Interface %s.\n", dev->irq, ifmap[dev->if_port]);
+ /* Release the IRQ line so that it can be shared if we don't use the
+ ethercard. */
+ outb(0x00, ioaddr + SET_IRQ);
+ }
+
+ if ((dev->mem_start & 0xf) > 0)
+ net_debug = dev->mem_start & 7;
+
+ if (net_debug)
+ printk(version);
+
+ /* Initialize the device structure. */
+ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct net_local));
+
+ dev->open = eexp_open;
+ dev->stop = eexp_close;
+ dev->hard_start_xmit = eexp_send_packet;
+ dev->get_stats = eexp_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
+
+ /* Fill in the fields of the device structure with ethernet-generic values.
+ This should be in a common file instead of per-driver. */
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ dev->buffs[i] = NULL;
+
+ dev->hard_header = eth_header;
+ dev->add_arp = eth_add_arp;
+ dev->queue_xmit = dev_queue_xmit;
+ dev->rebuild_header = eth_rebuild_header;
+ dev->type_trans = eth_type_trans;
+
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_len = ETH_HLEN;
+ dev->mtu = 1500; /* eth_mtu */
+ dev->addr_len = ETH_ALEN;
+ for (i = 0; i < ETH_ALEN; i++) {
+ dev->broadcast[i]=0xff;
+ }
+
+ /* New-style flags. */
+ dev->flags = IFF_BROADCAST;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = sizeof(unsigned long);
+
+ return 0;
+}
+
+
+/* Reverse IRQ map: the value to put in the SET_IRQ reg. for IRQ<index>. */
+static char irqrmap[]={0,0,1,2,3,4,0,0,0,1,5,6,0,0,0,0};
+
+static int
+eexp_open(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ if (dev->irq == 0 || irqrmap[dev->irq] == 0)
+ return -ENXIO;
+ if (request_irq(dev->irq, &eexp_interrupt)) {
+ return -EAGAIN;
+ }
+
+ irq2dev_map[dev->irq] = dev;
+
+ /* Initialize the 82586 memory and start it. */
+ init_82586_mem(dev);
+
+ /* Enable the interrupt line. */
+ outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ);
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+ return 0;
+}
+
+static int
+eexp_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if (dev->tbusy) {
+ /* If we get here, some higher level has decided we are broken.
+ There should really be a "kick me" function call instead. */
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ if (net_debug > 1)
+ printk("%s: transmit timed out, %s? ", dev->name,
+ inw(ioaddr+SCB_STATUS) & 0x8000 ? "IRQ conflict" :
+ "network cable problem");
+ lp->stats.tx_errors++;
+ /* Try to restart the adaptor. */
+ if (lp->last_restart == lp->stats.tx_packets) {
+ if (net_debug > 1) printk("Resetting board.\n");
+ /* Completely reset the adaptor. */
+ init_82586_mem(dev);
+ } else {
+ /* Issue the channel attention signal and hope it "gets better". */
+ if (net_debug > 1) printk("Kicking board.\n");
+ outw(0xf000|CUC_START|RX_START, ioaddr + SCB_CMD);
+ outb(0, ioaddr + SIGNAL_CA);
+ lp->last_restart = lp->stats.tx_packets;
+ }
+ dev->tbusy=0;
+ dev->trans_start = jiffies;
+ }
+
+ /* If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself. */
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
+ }
+
+ /* For ethernet, fill in the header. This should really be done by a
+ higher level, rather than duplicated for each ethernet adaptor. */
+ if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
+ skb->dev = dev;
+ arp_queue (skb);
+ return 0;
+ }
+ skb->arp=1;
+
+ /* Block a timer-based transmit from overlapping. */
+ if (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else {
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = (void *)(skb+1);
+
+ /* Disable the 82586's input to the interrupt line. */
+ outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
+ hardware_send_packet(dev, buf, length);
+ dev->trans_start = jiffies;
+ /* Enable the 82586 interrupt input. */
+ outb(0x08 | irqrmap[dev->irq], ioaddr + SET_IRQ);
+ }
+
+ if (skb->free)
+ kfree_skb (skb, FREE_WRITE);
+
+ /* You might need to clean up and record Tx statistics here. */
+ lp->stats.tx_aborted_errors++;
+
+ return 0;
+}
+
+/* The typical workload of the driver:
+ Handle the network interface interrupts. */
+static void
+eexp_interrupt(int reg_ptr)
+{
+ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ struct net_local *lp;
+ int ioaddr, status, boguscount = 0;
+ short ack_cmd = 0;
+
+ if (dev == NULL) {
+ printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ lp = (struct net_local *)dev->priv;
+
+ status = inw(ioaddr + SCB_STATUS);
+
+ if (net_debug > 4) {
+ printk("%s: EExp interrupt, status %4.4x.\n", dev->name, status);
+ }
+
+ /* Disable the 82586's input to the interrupt line. */
+ outb(irqrmap[dev->irq], ioaddr + SET_IRQ);
+
+ /* Reap the Tx packet buffers. */
+ while (lp->tx_reap != lp->tx_head) { /* if (status & 0x8000) */
+ unsigned short tx_status;
+ outw(lp->tx_reap, ioaddr + READ_PTR);
+ tx_status = inw(ioaddr);
+ if (tx_status == 0) {
+ if (net_debug > 5) printk("Couldn't reap %#x.\n", lp->tx_reap);
+ break;
+ }
+ if (tx_status & 0x2000) {
+ lp->stats.tx_packets++;
+ lp->stats.collisions += tx_status & 0xf;
+ dev->tbusy = 0;
+ mark_bh(INET_BH); /* Inform upper layers. */
+ } else {
+ lp->stats.tx_errors++;
+ if (tx_status & 0x0600) lp->stats.tx_carrier_errors++;
+ if (tx_status & 0x0100) lp->stats.tx_fifo_errors++;
+ if (!(tx_status & 0x0040)) lp->stats.tx_heartbeat_errors++;
+ if (tx_status & 0x0020) lp->stats.tx_aborted_errors++;
+ }
+ if (net_debug > 5)
+ printk("Reaped %x, Tx status %04x.\n" , lp->tx_reap, tx_status);
+ lp->tx_reap += TX_BUF_SIZE;
+ if (lp->tx_reap > RX_BUF_START - TX_BUF_SIZE)
+ lp->tx_reap = TX_BUF_START;
+ if (++boguscount > 4)
+ break;
+ }
+
+ if (status & 0x4000) { /* Packet received. */
+ if (net_debug > 5)
+ printk("Received packet, rx_head %04x.\n", lp->rx_head);
+ eexp_rx(dev);
+ }
+
+ /* Acknowledge the interrupt sources. */
+ ack_cmd = status & 0xf000;
+
+ if ((status & 0x0700) != 0x0200 && dev->start) {
+ if (net_debug)
+ printk("%s: Command unit stopped, status %04x, restarting.\n",
+ dev->name, status);
+ /* If this ever occurs we should really re-write the idle loop, reset
+ the Tx list, and do a complete restart of the command unit.
+ For now we rely on the Tx timeout if the resume doesn't work. */
+ ack_cmd |= CUC_RESUME;
+ }
+
+ if ((status & 0x0070) != 0x0040 && dev->start) {
+ short saved_write_ptr = inw(ioaddr + WRITE_PTR);
+ /* The Rx unit is not ready, it must be hung. Restart the receiver by
+ initializing the rx buffers, and issuing an Rx start command. */
+ if (net_debug)
+ printk("%s: Rx unit stopped, status %04x, restarting.\n",
+ dev->name, status);
+ init_rx_bufs(dev);
+ outw(RX_BUF_START, SCB_RFA);
+ outw(saved_write_ptr, ioaddr + WRITE_PTR);
+ ack_cmd |= RX_START;
+ }
+
+ outw(ack_cmd, ioaddr + SCB_CMD);
+ outb(0, ioaddr + SIGNAL_CA);
+
+ if (net_debug > 5) {
+ printk("%s: EExp exiting interrupt, status %4.4x.\n", dev->name,
+ inw(ioaddr + SCB_CMD));
+ }
+ /* Enable the 82586's input to the interrupt line. */
+ outb(irqrmap[dev->irq] | 0x08, ioaddr + SET_IRQ);
+ return;
+}
+
+static int
+eexp_close(struct device *dev)
+{
+ int ioaddr = dev->base_addr;
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ /* Flush the Tx and disable Rx. */
+ outw(RX_SUSPEND | CUC_SUSPEND, ioaddr + SCB_CMD);
+ outb(0, ioaddr + SIGNAL_CA);
+
+ /* Disable the physical interrupt line. */
+ outb(0, ioaddr + SET_IRQ);
+
+ free_irq(dev->irq);
+
+ irq2dev_map[dev->irq] = 0;
+
+ /* Update the statistics here. */
+
+ return 0;
+}
+
+/* Get the current statistics. This may be called with the card open or
+ closed. */
+static struct enet_statistics *
+eexp_get_stats(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+
+ /* ToDo: decide if there are any useful statistics from the SCB. */
+
+ return &lp->stats;
+}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ short ioaddr = dev->base_addr;
+ if (num_addrs < 0) {
+ /* Not written yet, this requires expanding the init_words config
+ cmd. */
+ } else if (num_addrs > 0) {
+ /* Fill in the SET_MC_CMD with the number of address bytes, followed
+ by the list of multicast addresses to be accepted. */
+ outw(SET_MC_CMD + 6, ioaddr + WRITE_PTR);
+ outw(num_addrs * 6, ioaddr);
+ port_write(ioaddr, addrs, num_addrs*3); /* 3 = addr len in words */
+ /* We must trigger a whole 586 reset due to a bug. */
+ } else {
+ /* Not written yet, this requires expanding the init_words config
+ cmd. */
+ outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */
+ }
+}
+#endif
+
+/* The horrible routine to read a word from the serial EEPROM. */
+
+/* The delay between EEPROM clock transitions. */
+#define eeprom_delay() { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }}
+#define EE_READ_CMD (6 << 6)
+
+int
+read_eeprom(int ioaddr, int location)
+{
+ int i;
+ unsigned short retval = 0;
+ short ee_addr = ioaddr + EEPROM_Ctrl;
+ int read_cmd = location | EE_READ_CMD;
+ short ctrl_val = EE_CS | _586_RESET;
+
+ outb(ctrl_val, ee_addr);
+
+ /* Shift the read command bits out. */
+ for (i = 8; i >= 0; i--) {
+ short outval = (read_cmd & (1 << i)) ? ctrl_val | EE_DATA_WRITE
+ : ctrl_val;
+ outb(outval, ee_addr);
+ outb(outval | EE_SHIFT_CLK, ee_addr); /* EEPROM clock tick. */
+ eeprom_delay();
+ outb(outval, ee_addr); /* Finish EEPROM a clock tick. */
+ eeprom_delay();
+ }
+ outb(ctrl_val, ee_addr);
+
+ for (i = 16; i > 0; i--) {
+ outb(ctrl_val | EE_SHIFT_CLK, ee_addr); eeprom_delay();
+ retval = (retval << 1) | ((inb(ee_addr) & EE_DATA_READ) ? 1 : 0);
+ outb(ctrl_val, ee_addr); eeprom_delay();
+ }
+
+ /* Terminate the EEPROM access. */
+ ctrl_val &= ~EE_CS;
+ outb(ctrl_val | EE_SHIFT_CLK, ee_addr);
+ eeprom_delay();
+ outb(ctrl_val, ee_addr);
+ eeprom_delay();
+ return retval;
+}
+
+static void
+init_82586_mem(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short ioaddr = dev->base_addr;
+
+ /* Enable loopback to protect the wire while starting up.
+ This is Superstition From Crynwr. */
+ outb(inb(ioaddr + Config) | 0x02, ioaddr + Config);
+
+ /* Hold the 586 in reset during the memory initialization. */
+ outb(_586_RESET, ioaddr + EEPROM_Ctrl);
+
+ /* Place the write pointer at 0xfff6 (address-aliased to 0xfffff6). */
+ outw(0xfff6, ioaddr + WRITE_PTR);
+ port_write(ioaddr, init_words, sizeof(init_words)>>1);
+
+ /* Fill in the station address. */
+ outw(SA_OFFSET, ioaddr + WRITE_PTR);
+ port_write(ioaddr, dev->dev_addr, 3);
+
+ /* The Tx-block list is written as needed. We just set up the values. */
+#ifdef initial_text_tx
+ lp->tx_cmd_link = DUMP_DATA + 4;
+#else
+ lp->tx_cmd_link = IDLELOOP + 4;
+#endif
+ lp->tx_head = lp->tx_reap = TX_BUF_START;
+
+ init_rx_bufs(dev);
+
+ /* Start the 586 by releasing the reset line. */
+ outb(0x00, ioaddr + EEPROM_Ctrl);
+
+ /* This was time consuming to track down: you need to give two channel
+ attention signals to reliably start up the i82586. */
+ outb(0, ioaddr + SIGNAL_CA);
+
+ {
+ int boguscnt = 50;
+ while (inw(ioaddr + SCB_STATUS) == 0)
+ if (--boguscnt == 0) {
+ printk("%s: i82586 initialization timed out with status %04x, cmd %04x.\n",
+ dev->name, inw(ioaddr + SCB_STATUS), inw(ioaddr + SCB_CMD));
+ break;
+ }
+ /* Issue channel-attn -- the 82586 won't start without it. */
+ outb(0, ioaddr + SIGNAL_CA);
+ }
+
+ /* Disable loopback. */
+ outb(inb(ioaddr + Config) & ~0x02, ioaddr + Config);
+ if (net_debug > 4)
+ printk("%s: Initialized 82586, status %04x.\n", dev->name,
+ inw(ioaddr + SCB_STATUS));
+ return;
+}
+
+/* Initialize the Rx-block list. */
+static void
+init_rx_bufs(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short ioaddr = dev->base_addr;
+
+ int cur_rxbuf = lp->rx_head = RX_BUF_START;
+
+ /* Initialize each Rx frame + data buffer. */
+ do { /* While there is room for one more. */
+ outw(cur_rxbuf, ioaddr + WRITE_PTR);
+ outw(0x0000, ioaddr); /* Status */
+ outw(0x0000, ioaddr); /* Command */
+ outw(cur_rxbuf + RX_BUF_SIZE, ioaddr); /* Link */
+ outw(cur_rxbuf + 22, ioaddr); /* Buffer offset */
+ outw(0x0000, ioaddr); /* Pad for dest addr. */
+ outw(0x0000, ioaddr);
+ outw(0x0000, ioaddr);
+ outw(0x0000, ioaddr); /* Pad for source addr. */
+ outw(0x0000, ioaddr);
+ outw(0x0000, ioaddr);
+ outw(0x0000, ioaddr); /* Pad for protocol. */
+
+ outw(0x0000, ioaddr); /* Buffer: Actual count */
+ outw(-1, ioaddr); /* Buffer: Next (none). */
+ outw(cur_rxbuf + 0x20, ioaddr); /* Buffer: Address low */
+ outw(0x0000, ioaddr);
+ /* Finally, the number of bytes in the buffer. */
+ outw(0x8000 + RX_BUF_SIZE-0x20, ioaddr);
+
+ lp->rx_tail = cur_rxbuf;
+ cur_rxbuf += RX_BUF_SIZE;
+ } while (cur_rxbuf <= RX_BUF_END - RX_BUF_SIZE);
+
+ /* Terminate the list by setting the EOL bit, and wrap the pointer to make
+ the list a ring. */
+ outw(lp->rx_tail + 2, ioaddr + WRITE_PTR);
+ outw(0xC000, ioaddr); /* Command, mark as last. */
+ outw(lp->rx_head, ioaddr); /* Link */
+}
+
+static void
+hardware_send_packet(struct device *dev, void *buf, short length)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short ioaddr = dev->base_addr;
+ short tx_block = lp->tx_head;
+
+ /* Set the write pointer to the Tx block, and put out the header. */
+ outw(tx_block, ioaddr + WRITE_PTR);
+ outw(0x0000, ioaddr); /* Tx status */
+ outw(CMD_INTR|CmdTx, ioaddr); /* Tx command */
+ outw(tx_block+16, ioaddr); /* Next command is a NoOp. */
+ outw(tx_block+8, ioaddr); /* Data Buffer offset. */
+
+ /* Output the data buffer descriptor. */
+ outw(length | 0x8000, ioaddr); /* Byte count parameter. */
+ outw(-1, ioaddr); /* No next data buffer. */
+ outw(tx_block+22, ioaddr); /* Buffer follows the NoOp command. */
+ outw(0x0000, ioaddr); /* Buffer address high bits (always zero). */
+
+ /* Output the Loop-back NoOp command. */
+ outw(0x0000, ioaddr); /* Tx status */
+ outw(CmdNOp, ioaddr); /* Tx command */
+ outw(tx_block+16, ioaddr); /* Next is myself. */
+
+ /* Output the packet using the write pointer.
+ Hmmm, it feels a little like a 3c501! */
+ port_write(ioaddr + DATAPORT, buf, (length + 1) >> 1);
+
+ /* Set the old command link pointing to this send packet. */
+ outw(lp->tx_cmd_link, ioaddr + WRITE_PTR);
+ outw(tx_block, ioaddr);
+ lp->tx_cmd_link = tx_block + 20;
+
+ /* Set the next free tx region. */
+ lp->tx_head = tx_block + TX_BUF_SIZE;
+ if (lp->tx_head > RX_BUF_START - TX_BUF_SIZE)
+ lp->tx_head = TX_BUF_START;
+
+ if (net_debug > 4) {
+ printk("%s: EExp @%x send length = %d, tx_block %3x, next %3x, "
+ "reap %4x status %4.4x.\n", dev->name, ioaddr, length,
+ tx_block, lp->tx_head, lp->tx_reap, inw(ioaddr + SCB_STATUS));
+ }
+
+ if (lp->tx_head != lp->tx_reap)
+ dev->tbusy = 0;
+}
+
+static void
+eexp_rx(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short ioaddr = dev->base_addr;
+ short saved_write_ptr = inw(ioaddr + WRITE_PTR);
+ short rx_head = lp->rx_head;
+ short rx_tail = lp->rx_tail;
+ short boguscount = 10;
+ short frame_status;
+
+ /* Set the read pointer to the Rx frame. */
+ outw(rx_head, ioaddr + READ_PTR);
+ while ((frame_status = inw(ioaddr)) < 0) { /* Command complete */
+ short rfd_cmd = inw(ioaddr);
+ short next_rx_frame = inw(ioaddr);
+ short data_buffer_addr = inw(ioaddr);
+ short pkt_len;
+
+ /* Set the read pointer the data buffer. */
+ outw(data_buffer_addr, ioaddr + READ_PTR);
+ pkt_len = inw(ioaddr);
+
+ if (rfd_cmd != 0 || data_buffer_addr != rx_head + 22
+ || pkt_len & 0xC000 != 0xC000) {
+ printk("%s: Rx frame at %#x corrupted, status %04x cmd %04x"
+ "next %04x data-buf @%04x %04x.\n", dev->name, rx_head,
+ frame_status, rfd_cmd, next_rx_frame, data_buffer_addr,
+ pkt_len);
+ } else if ((frame_status & 0x2000) == 0) {
+ /* Frame Rxed, but with error. */
+ lp->stats.rx_errors++;
+ if (frame_status & 0x0800) lp->stats.rx_crc_errors++;
+ if (frame_status & 0x0400) lp->stats.rx_frame_errors++;
+ if (frame_status & 0x0200) lp->stats.rx_fifo_errors++;
+ if (frame_status & 0x0100) lp->stats.rx_over_errors++;
+ if (frame_status & 0x0080) lp->stats.rx_length_errors++;
+ } else {
+ /* Malloc up new buffer. */
+ int sksize;
+ struct sk_buff *skb;
+
+ pkt_len &= 0x3fff;
+ sksize = sizeof(struct sk_buff) + pkt_len;
+ skb = alloc_skb(sksize, GFP_ATOMIC);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ lp->stats.rx_dropped++;
+ break;
+ }
+ skb->mem_len = sksize;
+ skb->mem_addr = skb;
+ skb->len = pkt_len;
+ skb->dev = dev;
+
+ outw(data_buffer_addr + 10, ioaddr + READ_PTR);
+
+ port_read(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
+
+#ifdef HAVE_NETIF_RX
+ netif_rx(skb);
+#else
+ skb->lock = 0;
+ if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+ kfree_skbmem(skb, sksize);
+ lp->stats.rx_dropped++;
+ break;
+ }
+#endif
+ lp->stats.rx_packets++;
+ }
+
+ /* Clear the status word and set End-of-List on the rx frame. */
+ outw(rx_head, ioaddr + WRITE_PTR);
+ outw(0x0000, ioaddr);
+ outw(0xC000, ioaddr);
+#ifndef final_version
+ if (next_rx_frame != rx_head + RX_BUF_SIZE
+ && next_rx_frame != RX_BUF_START) {
+ printk("%s: Rx next frame at %#x is %#x instead of %#x.\n", dev->name,
+ rx_head, next_rx_frame, rx_head + RX_BUF_SIZE);
+ next_rx_frame = rx_head + RX_BUF_SIZE;
+ if (next_rx_frame >= RX_BUF_END - RX_BUF_SIZE)
+ next_rx_frame = RX_BUF_START;
+ }
+#endif
+ outw(rx_tail+2, ioaddr + WRITE_PTR);
+ outw(0x0000, ioaddr); /* Clear the end-of-list on the prev. RFD. */
+
+#ifndef final_version
+ outw(rx_tail+4, ioaddr + READ_PTR);
+ if (inw(ioaddr) != rx_head) {
+ printk("%s: Rx buf link mismatch, at %04x link %04x instead of %04x.\n",
+ dev->name, rx_tail, (outw(rx_tail+4, ioaddr + READ_PTR),inw(ioaddr)),
+ rx_head);
+ outw(rx_head, ioaddr);
+ }
+#endif
+
+ rx_tail = rx_head;
+ rx_head = next_rx_frame;
+ if (--boguscount == 0)
+ break;
+ outw(rx_head, ioaddr + READ_PTR);
+ }
+
+ lp->rx_head = rx_head;
+ lp->rx_tail = rx_tail;
+
+ /* Restore the original write pointer. */
+ outw(saved_write_ptr, ioaddr + WRITE_PTR);
+}
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -I/usr/src/linux/drivers/net -Wall -Wstrict-prototypes -O6 -m486 -c eexpress.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * tab-width: 4
+ * End:
+ */
diff --git a/net/inet/el2.c b/drivers/net/el2.c
index 4ff9e31..4ff9e31 100644
--- a/net/inet/el2.c
+++ b/drivers/net/el2.c
diff --git a/net/inet/el2reg.h b/drivers/net/el2reg.h
index a1c8575..a1c8575 100644
--- a/net/inet/el2reg.h
+++ b/drivers/net/el2reg.h
diff --git a/net/inet/hp.c b/drivers/net/hp.c
index 9ffbff4..f6304f1 100644
--- a/net/inet/hp.c
+++ b/drivers/net/hp.c
@@ -13,12 +13,13 @@
*/
static char *version =
- "hp.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n";
+ "hp.c:v0.99.13f 10/16/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/errno.h>
+#include <linux/ioport.h>
#include <asm/system.h>
#include <asm/io.h>
#ifndef port_read
@@ -64,10 +65,10 @@ int hp_probe(struct device *dev)
int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
short ioaddr = dev->base_addr;
- if (ioaddr < 0)
- return ENXIO; /* Don't probe at all. */
- if (ioaddr > 0x100)
+ if (ioaddr > 0x1ff) /* Check a single specified location. */
return ! hpprobe1(ioaddr, dev);
+ else if (ioaddr > 0) /* Don't probe at all. */
+ return ENXIO;
for (port = &ports[0]; *port; port++) {
#ifdef HAVE_PORTRESERVE
@@ -93,8 +94,8 @@ int hpprobe1(int ioaddr, struct device *dev)
|| inb(ioaddr+1) != 0x00
|| inb(ioaddr+2) != 0x09)
return 0;
+ /* This really isn't good enough, we may pick up HP LANCE boards also! */
- /* Good enough, we will assume everything works. */
ethdev_init(dev);
ei_status.tx_start_page = HP_START_PG;
@@ -307,7 +308,7 @@ hp_init_card(struct device *dev)
/*
* Local variables:
- * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c hp.c"
+ * compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c hp.c"
* version-control: t
* kept-new-versions: 5
* End:
diff --git a/net/inet/iow.h b/drivers/net/iow.h
index e186c45..e186c45 100644
--- a/net/inet/iow.h
+++ b/drivers/net/iow.h
diff --git a/net/inet/lance.c b/drivers/net/lance.c
index eca3d20..3022808 100644
--- a/net/inet/lance.c
+++ b/drivers/net/lance.c
@@ -7,26 +7,26 @@
distributed according to the terms of the GNU Public License,
incorporated herein by reference.
- This driver is for the Allied Telesis AT1500, and should work with
- NE2100 clones.
+ This driver is for the Allied Telesis AT1500 and HP J2405A, and should work
+ with most other LANCE-based bus-master (NE2100 clone) ethercards.
The author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
*/
-static char *version = "lance.c:v0.12 9/3/93 becker@super.org\n";
+static char *version = "lance.c:v0.13f 10/18/93 becker@super.org\n";
#include <linux/config.h>
#include <linux/kernel.h>
#include <linux/sched.h>
#include <linux/string.h>
-/*#include <linux/interrupt.h>*/
#include <linux/ptrace.h>
#include <linux/errno.h>
#include <linux/ioport.h>
+#include <linux/malloc.h>
+#include <asm/bitops.h>
#include <asm/io.h>
#include <asm/dma.h>
-/*#include <asm/system.h>*/
#include "dev.h"
#include "iow.h"
@@ -34,28 +34,31 @@ static char *version = "lance.c:v0.12 9/3/93 becker@super.org\n";
#include "skbuff.h"
#include "arp.h"
-#ifndef HAVE_AUTOIRQ
-/* From auto_irq.c, should be in a *.h file. */
-extern void autoirq_setup(int waittime);
-extern int autoirq_report(int waittime);
-extern struct device *irq2dev_map[16];
-#endif
-
#ifdef LANCE_DEBUG
int lance_debug = LANCE_DEBUG;
#else
int lance_debug = 1;
#endif
-#ifndef DEFAULT_DMA
-#define DEFAULT_DMA 5
+#ifndef LANCE_DMA
+#define LANCE_DMA 5
#endif
-/* Bitfield in the high bits of init block ring buffer. */
-#define RING_LEN_BITS 0x80000000
-#define RING_MOD_MASK 0x0f
+/* Set the number of Tx and Rx buffers. */
+#ifndef LANCE_BUFFER_LOG_SZ
#define RING_SIZE 16
+#define RING_MOD_MASK 0x0f
+#define RING_LEN_BITS 0x80000000
+#else
+#define RING_SIZE (1 << (LANCE_BUFFERS_LOG_SZ))
+#define RING_MOD_MASK (RING_SIZE - 1)
+#define RING_LEN_BITS (LANCE_BUFFER_LOG_SZ << 13)
+#endif
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff,size)
+#endif
/* Offsets from base I/O address. */
#define LANCE_DATA 0x10
@@ -88,14 +91,17 @@ struct lance_init {
};
struct lance_private {
+ char devname[8];
/* These must aligned on 8-byte boundaries. */
struct lance_rx_head rx_ring[RING_SIZE];
struct lance_tx_head tx_ring[RING_SIZE];
struct lance_init init_block;
+ long dma_buffs; /* Address of Rx and Tx buffers. */
int cur_rx, cur_tx; /* The next free ring entry */
int dirty_rx, dirty_tx; /* The ring entries to be free()ed. */
int dma;
struct enet_statistics stats;
+ char old_lance;
int pad0, pad1; /* Used for alignment */
};
@@ -104,10 +110,13 @@ struct lance_private {
temporary solution to the lack of one, but it limits us to a single
AT1500 and <16M. Bummer. */
-#define PKT_BUF_SZ 1550
+#define PKT_BUF_SZ 1544
+
+#ifndef MEM_START_ALLOC
static char rx_buffs[PKT_BUF_SZ][RING_SIZE];
+#endif
-int at1500_probe1(struct device *dev);
+static int lance_probe1(struct device *dev, short ioaddr);
static int lance_open(struct device *dev);
static void lance_init_ring(struct device *dev);
static int lance_start_xmit(struct sk_buff *skb, struct device *dev);
@@ -115,9 +124,8 @@ static int lance_rx(struct device *dev);
static void lance_interrupt(int reg_ptr);
static int lance_close(struct device *dev);
static struct enet_statistics *lance_get_stats(struct device *dev);
-
-#ifdef notdef
-static struct sigaction lance_sigaction = { &lance_interrupt, 0, 0, NULL, };
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
#endif
@@ -127,35 +135,26 @@ int at1500_probe(struct device *dev)
int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0};
int base_addr = dev->base_addr;
- if (base_addr < 0)
- return ENXIO; /* Don't probe at all. */
- if (base_addr > 0x100) /* Check a single specified location. */
- return at1500_probe1(dev);
+ if (base_addr > 0x1ff) /* Check a single specified location. */
+ return lance_probe1(dev, base_addr);
+ else if (base_addr > 0) /* Don't probe at all. */
+ return ENXIO;
/* First probe for the ethercard ID, 0x57, and then look for a LANCE
chip. */
for (port = &ports[0]; *port; port++) {
- int probe_addr = *port;
- short temp;
+ int ioaddr = *port;
#ifdef HAVE_PORTRESERVE
- if (check_region(probe_addr, LANCE_TOTAL_SIZE))
+ if (check_region(ioaddr, LANCE_TOTAL_SIZE))
continue;
#endif
- if (inb(probe_addr + 14) != 0x57
- || inb(probe_addr + 15) != 0x57)
+ if (inb(ioaddr + 14) != 0x57
+ || inb(ioaddr + 15) != 0x57)
continue;
- /* Reset the LANCE. Un-Reset needed only for the real NE2100. */
- temp = inw(probe_addr+LANCE_RESET); /* Reset the LANCE */
- outw(temp, probe_addr+LANCE_RESET); /* "Un-reset" */
-
- outw(0x0000, probe_addr+LANCE_ADDR); /* Switch to window 0 */
- if (inw(probe_addr+LANCE_DATA) != 0x0004)
- continue;
- dev->base_addr = probe_addr;
- if (at1500_probe1(dev) == 0)
+ if (lance_probe1(dev, ioaddr) == 0)
return 0;
}
@@ -163,25 +162,48 @@ int at1500_probe(struct device *dev)
return ENODEV; /* ENODEV would be more accurate. */
}
-int
-at1500_probe1(struct device *dev)
+static int
+lance_probe1(struct device *dev, short ioaddr)
{
struct lance_private *lp;
- short ioaddr = dev->base_addr;
+ int hpJ2405A = 0;
+ int i, reset_val;
- int i;
+ hpJ2405A = (inb(ioaddr) == 0x08 && inb(ioaddr+1) == 0x00
+ && inb(ioaddr+2) == 0x09);
+
+ /* Reset the LANCE. */
+ reset_val = inw(ioaddr+LANCE_RESET); /* Reset the LANCE */
+
+ /* The Un-Reset needed is only needed for the real NE2100, and will
+ confuse the HP board. */
+ if (!hpJ2405A)
+ outw(reset_val, ioaddr+LANCE_RESET);
+
+ outw(0x0000, ioaddr+LANCE_ADDR); /* Switch to window 0 */
+ if (inw(ioaddr+LANCE_DATA) != 0x0004)
+ return ENXIO;
- printk("%s: LANCE at %#3x, address", dev->name, ioaddr);
+ printk("%s: LANCE at %#3x,", dev->name, ioaddr);
/* There is a 16 byte station address PROM at the base address.
The first six bytes are the station address. */
for (i = 0; i < 6; i++)
printk(" %2.2x", dev->dev_addr[i] = inb(ioaddr + i));
- /* Reset the LANCE */
- inw(ioaddr+LANCE_RESET);
+ dev->base_addr = ioaddr;
+#ifdef HAVE_PORTRESERVE
+ snarf_region(ioaddr, LANCE_TOTAL_SIZE);
+#endif
/* Make up a LANCE-specific-data structure. */
+#ifdef MEM_START_ALLOC
+ dev->priv = (void *)((mem_start + 7) & ~7);
+ mem_start += (long)dev->priv + sizeof(struct lance_private);
+ lp = (struct lance_private *)dev->priv;
+ lp->dma_buffs = mem_start;
+ mem_start += PKT_BUF_SZ * RING_SIZE;
+#else
dev->priv = kmalloc(sizeof(struct lance_private), GFP_KERNEL);
/* Align on 8-byte boundary. */
dev->priv = (void *)(((int)dev->priv + 7) & ~0x07);
@@ -190,16 +212,26 @@ at1500_probe1(struct device *dev)
printk(" disabled (buff %#x > 16M).\n", (int)rx_buffs);
return -ENOMEM;
}
-
memset(dev->priv, 0, sizeof(struct lance_private));
lp = (struct lance_private *)dev->priv;
+ lp->dma_buffs = (long)rx_buffs;
+#endif
- if ((int)(lp->rx_ring) & 0x07)
- printk("%s: LANCE Rx and Tx rings not on even boundary.\n",
- dev->name);
+#ifndef final_version
+ /* This should never happen. */
+ if ((int)(lp->rx_ring) & 0x07) {
+ printk(" **ERROR** LANCE Rx and Tx rings not on even boundary.\n");
+ return -ENXIO;
+ }
+#endif
- /* Un-Reset the LANCE, needed only for the NE2100. */
- outw(0, ioaddr+LANCE_RESET);
+ outw(88, ioaddr+LANCE_ADDR);
+ lp->old_lance = (inw(ioaddr+LANCE_DATA) != 0x3003);
+
+#ifdef notdef
+ printk(lp->old_lance ? " original LANCE (%04x)" : " PCnet-ISA LANCE (%04x)",
+ inw(ioaddr+LANCE_DATA));
+#endif
lp->init_block.mode = 0x0003; /* Disable Rx and Tx. */
for (i = 0; i < 6; i++)
@@ -215,37 +247,42 @@ at1500_probe1(struct device *dev)
outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA);
outw(0x0000, ioaddr+LANCE_ADDR);
- /* To auto-IRQ we enable the initialization-done and DMA err,
- interrupts. For now we will always get a DMA error. */
- if (dev->irq < 2) {
- autoirq_setup(0);
-
- /* Trigger an initialization just for the interrupt. */
- outw(0x0041, ioaddr+LANCE_DATA);
-
- dev->irq = autoirq_report(1);
- if (dev->irq)
- printk(", using IRQ %d.\n", dev->irq);
- else {
- printk(", failed to detect IRQ line.\n");
- return -EAGAIN;
- }
- } else
- printk(" assigned IRQ %d.\n", dev->irq);
-
- /* The DMA channel may be passed in on this parameter. */
- dev->dma = dev->mem_start & 0x07;
-
-#ifndef NE2100 /* The NE2100 might not understand */
- /* Turn on auto-select of media (10baseT or BNC) so that the user
- can watch the LEDs even if the board isn't opened. */
- outw(0x0002, ioaddr+LANCE_ADDR);
- outw(0x0002, ioaddr+LANCE_BUS_IF);
-#endif
+ if (hpJ2405A) {
+ char dma_tbl[4] = {3, 5, 6, 7};
+ char irq_tbl[8] = {3, 4, 5, 9, 10, 11, 12, 15};
+ short reset_val = inw(ioaddr+LANCE_RESET);
+ dev->dma = dma_tbl[(reset_val >> 2) & 3];
+ dev->irq = irq_tbl[(reset_val >> 4) & 7];
+ printk(" HP J2405A IRQ %d DMA %d.\n", dev->irq, dev->dma);
+ } else {
+ /* The DMA channel may be passed in on this parameter. */
+ dev->dma = dev->mem_start & 0x07;
+
+ /* To auto-IRQ we enable the initialization-done and DMA err,
+ interrupts. For now we will always get a DMA error. */
+ if (dev->irq < 2) {
+ autoirq_setup(0);
+
+ /* Trigger an initialization just for the interrupt. */
+ outw(0x0041, ioaddr+LANCE_DATA);
+
+ dev->irq = autoirq_report(1);
+ if (dev->irq)
+ printk(", probed IRQ %d, fixed at DMA %d.\n", dev->irq, dev->dma);
+ else {
+ printk(", failed to detect IRQ line.\n");
+ return -EAGAIN;
+ }
+ } else
+ printk(" assigned IRQ %d DMA %d.\n", dev->irq, dev->dma);
+ }
-#ifdef HAVE_PORTRESERVE
- snarf_region(ioaddr, LANCE_TOTAL_SIZE);
-#endif
+ if (! lp->old_lance) {
+ /* Turn on auto-select of media (10baseT or BNC) so that the user
+ can watch the LEDs even if the board isn't opened. */
+ outw(0x0002, ioaddr+LANCE_ADDR);
+ outw(0x0002, ioaddr+LANCE_BUS_IF);
+ }
if (lance_debug > 0)
printk(version);
@@ -255,6 +292,9 @@ at1500_probe1(struct device *dev)
dev->hard_start_xmit = &lance_start_xmit;
dev->stop = &lance_close;
dev->get_stats = &lance_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
dev->mem_start = 0;
@@ -299,7 +339,7 @@ lance_open(struct device *dev)
return -EAGAIN;
}
- lp->dma = dev->dma ? dev->dma : DEFAULT_DMA;
+ lp->dma = dev->dma ? dev->dma : LANCE_DMA;
if (request_dma(lp->dma)) {
free_irq(dev->irq);
@@ -315,14 +355,14 @@ lance_open(struct device *dev)
set_dma_mode(lp->dma, DMA_MODE_CASCADE);
/* Un-Reset the LANCE, needed only for the NE2100. */
- outw(0, ioaddr+LANCE_RESET);
+ if (lp->old_lance)
+ outw(0, ioaddr+LANCE_RESET);
-#ifndef NE2100
- /* This is really 79C960-specific, NE2100 might not understand */
- /* Turn on auto-select of media (10baseT or BNC). */
- outw(0x0002, ioaddr+LANCE_ADDR);
- outw(0x0002, ioaddr+LANCE_BUS_IF);
-#endif
+ if (! lp->old_lance) {
+ /* This is 79C960-specific: Turn on auto-select of media (AUI, BNC). */
+ outw(0x0002, ioaddr+LANCE_ADDR);
+ outw(0x0002, ioaddr+LANCE_BUS_IF);
+ }
if (lance_debug > 1)
printk("%s: lance_open() irq %d dma %d tx/rx rings %#x/%#x init %#x.\n",
@@ -369,7 +409,7 @@ lance_init_ring(struct device *dev)
lp->dirty_rx = lp->dirty_tx = 0;
for (i = 0; i < RING_SIZE; i++) {
- lp->rx_ring[i].base = (int) rx_buffs | (0x80000000 + i*PKT_BUF_SZ);
+ lp->rx_ring[i].base = (lp->dma_buffs + i*PKT_BUF_SZ) | 0x80000000;
lp->rx_ring[i].buf_length = -PKT_BUF_SZ;
lp->tx_ring[i].base = 0;
}
@@ -418,6 +458,7 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
arp_queue (skb);
return 0;
}
+ skb->arp=1;
if (skb->len <= 0)
return 0;
@@ -429,8 +470,10 @@ lance_start_xmit(struct sk_buff *skb, struct device *dev)
outw(0x0000, ioaddr+LANCE_DATA);
}
- /* Avoid timer-based retransmission conflicts. */
- dev->tbusy=1;
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ if (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
/* This code is broken for >16M RAM systems.
There are two ways to fix it:
@@ -585,7 +628,8 @@ lance_rx(struct device *dev)
short pkt_len = lp->rx_ring[entry].msg_length;
int sksize = sizeof(struct sk_buff) + pkt_len;
struct sk_buff *skb;
- skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
+
+ skb = alloc_skb(sksize, GFP_ATOMIC);
if (skb == NULL) {
printk("%s: Memory squeeze, deferring packet.\n", dev->name);
lp->stats.rx_dropped++; /* Really, deferred. */
@@ -603,7 +647,7 @@ lance_rx(struct device *dev)
#else
skb->lock = 0;
if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
- kfree_s(skb, sksize);
+ kfree_skbmem(skb, sksize);
lp->stats.rx_dropped++;
break;
}
@@ -671,9 +715,45 @@ lance_get_stats(struct device *dev)
return &lp->stats;
}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ short ioaddr = dev->base_addr;
+
+ /* We take the simple way out and always enable promiscuous mode. */
+ outw(0, ioaddr+LANCE_ADDR);
+ outw(0x0004, ioaddr+LANCE_DATA); /* Temporarily stop the lance. */
+
+ outw(15, ioaddr+LANCE_ADDR);
+ if (num_addrs >= 0) {
+ short multicast_table[4];
+ int i;
+ /* We don't use the multicast table, but rely on upper-layer filtering. */
+ memset(multicast_table, (num_addrs == 0) ? 0 : -1, sizeof(multicast_table));
+ for (i = 0; i < 4; i++) {
+ outw(8 + i, ioaddr+LANCE_ADDR);
+ outw(multicast_table[i], ioaddr+LANCE_DATA);
+ }
+ outw(0x0000, ioaddr+LANCE_DATA); /* Unset promiscuous mode */
+ } else {
+ outw(0x8000, ioaddr+LANCE_DATA); /* Set promiscuous mode */
+ }
+
+ outw(0, ioaddr+LANCE_ADDR);
+ outw(0x0142, ioaddr+LANCE_DATA); /* Resume normal operation. */
+}
+#endif
/*
* Local variables:
- * compile-command: "gcc -D__KERNEL__ -Wall -O6 -x c++ -c lance.c"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c"
* End:
*/
diff --git a/net/inet/ne.c b/drivers/net/ne.c
index 86cfec2..86cfec2 100644
--- a/net/inet/ne.c
+++ b/drivers/net/ne.c
diff --git a/net/inet/plip.c b/drivers/net/plip.c
index 48cc7c8..a676cfc 100644
--- a/net/inet/plip.c
+++ b/drivers/net/plip.c
@@ -22,10 +22,24 @@
Recent versions were debugged and maintained by TANABE Hiroyasu.
Updated for 0.99pl12 by Donald Becker.
+
+ Changes even more Alan Cox <iiitac@pyr.swan.ac.uk>
+ Fixed: sets skb->arp=1, always claims success like ethernet, doesn't
+ free skb and then claim fail. Incorrect brackets causing reset problem
+ Attempting to make it work (works for me - email me if it does work)
+
+ Bugs:
+ Should be timer oriented state machine.
+ Should never use jiffies for timeouts.
+ Protocol is buggy when broadcasts occur (Must ask Russ Nelson)
+ Can hang forever on collisions (tough - you fix it!).
+ I get 15K/second NFS throughput (about 20-25K second IP).
+ Change the protocol back.
+
*/
static char *version =
- "plip.c:v0.15 for 0.99pl12+, 8/11/93\n";
+ "Net2Debugged PLIP 1.01 (from plip.c:v0.15 for 0.99pl12+, 8/11/93)\n";
#include <linux/config.h>
@@ -216,12 +230,15 @@ plip_open(struct device *dev)
{
if (dev->irq == 0)
dev->irq = 7;
+ cli();
if (request_irq(dev->irq , &plip_interrupt) != 0) {
+ sti();
PRINTK(("%s: couldn't get IRQ %d.\n", dev->name, dev->irq));
return -EAGAIN;
}
irq2dev_map[dev->irq] = dev;
+ sti();
plip_device_clear(dev);
dev->tbusy = 0;
dev->interrupt = 0;
@@ -235,8 +252,10 @@ plip_close(struct device *dev)
{
dev->tbusy = 1;
dev->start = 0;
+ cli();
free_irq(dev->irq);
irq2dev_map[dev->irq] = NULL;
+ sti();
outb(0x00, dev->base_addr); /* Release the interrupt. */
return 0;
}
@@ -271,6 +290,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
arp_queue (skb);
return 0;
}
+ skb->arp=1;
dev->trans_start = jiffies;
ret_val = plip_send_packet(dev, (unsigned char *)(skb+1), skb->len);
@@ -278,7 +298,7 @@ plip_tx_packet(struct sk_buff *skb, struct device *dev)
kfree_skb (skb, FREE_WRITE);
dev->tbusy = 0;
mark_bh (INET_BH);
- return ret_val;
+ return 0/*ret_val*/;
}
static int
@@ -451,7 +471,7 @@ plip_receive_packet(struct device *dev)
*/
int sksize;
sksize = sizeof(struct sk_buff) + length;
- skb = (struct sk_buff *)kmalloc(sksize, GFP_ATOMIC);
+ skb = alloc_skb(sksize, GFP_ATOMIC);
if (skb == NULL) {
PRINTK(("%s: Couldn't allocate a sk_buff of size %d.\n",
dev->name, sksize));
@@ -497,7 +517,7 @@ plip_receive_packet(struct device *dev)
while ( (inb(dev->base_addr + PAR_STATUS) & 0xf8) != 0x80 ) {
if (timeout < jiffies ) {
double_timeoutfactor();
- PRINTK(("remote end is not reseted.\n"));
+ PRINTK(("Remote has not reset.\n"));
break;
}
}
@@ -699,11 +719,11 @@ plip_send_packet(struct device *dev, unsigned char *buf, int length)
outb(0x00, dev->base_addr + PAR_DATA);
/* Wait for the remote end to reset. */
- timeout = (jiffies + length * timeoutfactor) >> 4;
+ timeout = jiffies + ((length * timeoutfactor) >> 4);
while ((inb(dev->base_addr + PAR_STATUS) & 0xe8) != 0x80) {
if (timeout < jiffies ) {
double_timeoutfactor();
- PRINTK(("remote end is not reseted.\n"));
+ PRINTK(("Remote end has not reset.\n"));
error++;
break;
}
diff --git a/drivers/net/skeleton.c b/drivers/net/skeleton.c
new file mode 100644
index 0000000..b6440d8
--- /dev/null
+++ b/drivers/net/skeleton.c
@@ -0,0 +1,511 @@
+/* skeleton.c: A sample network driver core for linux. */
+/*
+ Written 1993 by Donald Becker.
+ Copyright 1993 United States Government as represented by the Director,
+ National Security Agency. This software may only be used and distributed
+ according to the terms of the GNU Public License as modified by SRC,
+ incorported herein by reference.
+
+ The author may be reached as becker@super.org or
+ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+ This file is an outline for writing a network device driver for the
+ the Linux operating system.
+
+ To write (or understand) a driver, have a look at the "loopback.c" file to
+ get a feel of what is going on, and then use the code below as a skeleton
+ for the new driver.
+
+*/
+
+static char *version =
+ "skeleton.c:v0.04 10/17/93 Donald Becker (becker@super.org)\n";
+
+/* Always include 'config.h' first in case the user wants to turn on
+ or override something. */
+#include <linux/config.h>
+
+/*
+ Sources:
+ List your sources of programming information to document that
+ the driver is your own creation, and give due credit to others
+ that contributed to the work. Remember that GNU project code
+ cannot use proprietary or trade secret information. Interface
+ definitions are generally considered non-copyrightable to the
+ extent that the same names and structures must be used to be
+ compatible.
+
+ Finally, keep in mind that the Linux kernel is has an API, not
+ ABI. Proprietary object-code-only distributions are not permitted
+ under the GPL.
+*/
+
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/fcntl.h>
+#include <linux/interrupt.h>
+#include <linux/ptrace.h>
+#include <linux/ioport.h>
+#include <linux/in.h>
+#include <linux/malloc.h>
+#include <asm/system.h>
+#include <asm/bitops.h>
+#include <asm/io.h>
+#include <asm/dma.h>
+#include <errno.h>
+#include <memory.h>
+
+#include "dev.h"
+#include "iow.h"
+#include "eth.h"
+#include "skbuff.h"
+#include "arp.h"
+
+#ifndef HAVE_AUTOIRQ
+/* From auto_irq.c, in ioport.h for later versions. */
+extern void autoirq_setup(int waittime);
+extern int autoirq_report(int waittime);
+/* The map from IRQ number (as passed to the interrupt handler) to
+ 'struct device'. */
+extern struct device *irq2dev_map[16];
+#endif
+
+#ifndef HAVE_ALLOC_SKB
+#define alloc_skb(size, priority) (struct sk_buff *) kmalloc(size,priority)
+#define kfree_skbmem(buff, size) kfree_s(buff, size);
+#endif
+
+/* use 0 for production, 1 for verification, >2 for debug */
+#ifndef NET_DEBUG
+#define NET_DEBUG 2
+#endif
+static unsigned int net_debug = NET_DEBUG;
+
+/* Information that need to be kept for each board. */
+struct net_local {
+ struct enet_statistics stats;
+ long open_time; /* Useless example local info. */
+};
+
+/* Index to functions, as function prototypes. */
+
+extern int netcard_probe(struct device *dev);
+
+static int netcard_probe1(struct device *dev, short ioaddr);
+static int net_open(struct device *dev);
+static int net_send_packet(struct sk_buff *skb, struct device *dev);
+static void net_interrupt(int reg_ptr);
+static void net_rx(struct device *dev);
+static int net_close(struct device *dev);
+static struct enet_statistics *net_get_stats(struct device *dev);
+#ifdef HAVE_MULTICAST
+static void set_multicast_list(struct device *dev, int num_addrs, void *addrs);
+#endif
+
+/* Example routines you must write ;->. */
+#define tx_done(dev) 1
+extern void hardware_send_packet(short ioaddr, char *buf, int length);
+extern void chipset_init(struct device *dev, int startp);
+
+
+/* Check for a network adaptor of this type, and return '0' iff one exists.
+ If dev->base_addr == 0, probe all likely locations.
+ If dev->base_addr == 1, always return failure.
+ If dev->base_addr == 2, alloate space for the device and return success
+ (detachable devices only).
+ */
+int
+netcard_probe(struct device *dev)
+{
+ int *port, ports[] = {0x300, 0x280, 0};
+ int base_addr = dev->base_addr;
+
+ if (base_addr > 0x1ff) /* Check a single specified location. */
+ return netcard_probe1(dev, base_addr);
+ else if (base_addr > 0) /* Don't probe at all. */
+ return ENXIO;
+
+ for (port = &ports[0]; *port; port++) {
+ int ioaddr = *port;
+#ifdef HAVE_PORTRESERVE
+ if (check_region(ioaddr, 1 /* ETHERCARD_TOTAL_SIZE */))
+ continue;
+#endif
+ if (inb(ioaddr) != 0x57)
+ continue;
+ dev->base_addr = ioaddr;
+ if (netcard_probe1(dev, ioaddr) == 0)
+ return 0;
+ }
+
+ dev->base_addr = base_addr;
+ return ENODEV; /* ENODEV would be more accurate. */
+}
+
+int netcard_probe1(struct device *dev, short ioaddr)
+{
+ unsigned char station_addr[6];
+ int i;
+
+ /* Read the station address PROM. */
+ for (i = 0; i < 6; i++) {
+ station_addr[i] = inb(ioaddr + i);
+ }
+ /* Check the first three octets of the S.A. for the manufactor's code. */
+ if (station_addr[0] != 0x42 || station_addr[1] != 0x42 || station_addr[2] != 0x42) {
+ return ENODEV;
+ }
+
+ printk("%s: %s found at %#3x, IRQ %d.\n", dev->name,
+ "network card", dev->base_addr, dev->irq);
+
+#ifdef jumpered_interrupts
+ /* If this board has jumpered interrupts, snarf the interrupt vector
+ now. There is no point in waiting since no other device can use
+ the interrupt, and this marks the 'irqaction' as busy. */
+
+ if (dev->irq == -1)
+ ; /* Do nothing: a user-level program will set it. */
+ else if (dev->irq < 2) { /* "Auto-IRQ" */
+ autoirq_setup(0);
+ /* Trigger an interrupt here. */
+
+ dev->irq = autoirq_report(0);
+ if (net_debug >= 2)
+ printk(" autoirq is %d", dev->irq);
+ } else if (dev->irq == 2)
+ /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
+ or don't know which one to set. */
+ dev->irq = 9;
+
+ { int irqval = request_irq(dev->irq, &net_interrupt);
+ if (irqval) {
+ printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
+ dev->irq, irqval);
+ return EAGAIN;
+ }
+ }
+#endif /* jumpered interrupt */
+
+#ifdef HAVE_PORTRESERVE
+ /* Grab the region so we can find another board if autoIRQ fails. */
+ snarf_region(ioaddr, 16);
+#endif
+
+ if (net_debug)
+ printk(version);
+
+ /* Initialize the device structure. */
+ dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL);
+ memset(dev->priv, 0, sizeof(struct net_local));
+
+ dev->open = net_open;
+ dev->stop = net_close;
+ dev->hard_start_xmit = net_send_packet;
+ dev->get_stats = net_get_stats;
+#ifdef HAVE_MULTICAST
+ dev->set_multicast_list = &set_multicast_list;
+#endif
+
+ /* Fill in the fields of the device structure with ethernet-generic values.
+ This should be in a common file instead of per-driver. */
+ for (i = 0; i < DEV_NUMBUFFS; i++)
+ dev->buffs[i] = NULL;
+
+ dev->hard_header = eth_header;
+ dev->add_arp = eth_add_arp;
+ dev->queue_xmit = dev_queue_xmit;
+ dev->rebuild_header = eth_rebuild_header;
+ dev->type_trans = eth_type_trans;
+
+ dev->type = ARPHRD_ETHER;
+ dev->hard_header_len = ETH_HLEN;
+ dev->mtu = 1500; /* eth_mtu */
+ dev->addr_len = ETH_ALEN;
+ for (i = 0; i < ETH_ALEN; i++) {
+ dev->broadcast[i]=0xff;
+ }
+
+ /* New-style flags. */
+ dev->flags = IFF_BROADCAST;
+ dev->family = AF_INET;
+ dev->pa_addr = 0;
+ dev->pa_brdaddr = 0;
+ dev->pa_mask = 0;
+ dev->pa_alen = sizeof(unsigned long);
+
+ return 0;
+}
+
+
+/* Open/initialize the board. This is called (in the current kernel)
+ sometime after booting when the 'ifconfig' program is run.
+
+ This routine should set everything up anew at each open, even
+ registers that "should" only need to be set once at boot, so that
+ there is non-reboot way to recover if something goes wrong.
+ */
+static int
+net_open(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ /* This is used if the interrupt line can turned off (shared).
+ See 3c503.c for an example of selecting the IRQ at config-time. */
+ if (request_irq(dev->irq, &net_interrupt)) {
+ return -EAGAIN;
+ }
+
+
+ /* Always snarf a DMA channel after the IRQ. */
+ if (request_dma(dev->dma)) {
+ free_irq(dev->irq);
+ return -EAGAIN;
+ }
+ irq2dev_map[dev->irq] = dev;
+
+ /* Reset the hardware here. */
+ /*chipset_init(dev, 1);*/
+ outb(0x00, ioaddr);
+ lp->open_time = jiffies;
+
+ dev->tbusy = 0;
+ dev->interrupt = 0;
+ dev->start = 1;
+ return 0;
+}
+
+static int
+net_send_packet(struct sk_buff *skb, struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ if (dev->tbusy) {
+ /* If we get here, some higher level has decided we are broken.
+ There should really be a "kick me" function call instead. */
+ int tickssofar = jiffies - dev->trans_start;
+ if (tickssofar < 5)
+ return 1;
+ printk("%s: transmit timed out, %s?\n", dev->name,
+ tx_done(dev) ? "IRQ conflict" : "network cable problem");
+ /* Try to restart the adaptor. */
+ chipset_init(dev, 1);
+ dev->tbusy=0;
+ dev->trans_start = jiffies;
+ }
+
+ /* If some higher layer thinks we've missed an tx-done interrupt
+ we are passed NULL. Caution: dev_tint() handles the cli()/sti()
+ itself. */
+ if (skb == NULL) {
+ dev_tint(dev);
+ return 0;
+ }
+
+ /* For ethernet, fill in the header. This should really be done by a
+ higher level, rather than duplicated for each ethernet adaptor. */
+ if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
+ skb->dev = dev;
+ arp_queue (skb);
+ return 0;
+ }
+ skb->arp=1;
+
+ /* Block a timer-based transmit from overlapping. This could better be
+ done with atomic_swap(1, dev->tbusy), but set_bit() works as well. */
+ if (set_bit(0, (void*)&dev->tbusy) != 0)
+ printk("%s: Transmitter access conflict.\n", dev->name);
+ else {
+ short length = ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN;
+ unsigned char *buf = (void *)(skb+1);
+
+ hardware_send_packet(ioaddr, buf, length);
+ dev->trans_start = jiffies;
+ }
+ if (skb->free)
+ kfree_skb (skb, FREE_WRITE);
+
+ /* You might need to clean up and record Tx statistics here. */
+ if (inw(ioaddr) == /*RU*/81)
+ lp->stats.tx_aborted_errors++;
+
+ return 0;
+}
+
+/* The typical workload of the driver:
+ Handle the network interface interrupts. */
+static void
+net_interrupt(int reg_ptr)
+{
+ int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
+ struct device *dev = (struct device *)(irq2dev_map[irq]);
+ struct net_local *lp;
+ int ioaddr, status, boguscount = 0;
+
+ if (dev == NULL) {
+ printk ("net_interrupt(): irq %d for unknown device.\n", irq);
+ return;
+ }
+ dev->interrupt = 1;
+
+ ioaddr = dev->base_addr;
+ lp = (struct net_local *)dev->priv;
+ status = inw(ioaddr + 0);
+
+ do {
+ if (status /*& RX_INTR*/) {
+ /* Got a packet(s). */
+ net_rx(dev);
+ }
+ if (status /*& TX_INTR*/) {
+ lp->stats.tx_packets++;
+ dev->tbusy = 0;
+ mark_bh(INET_BH); /* Inform upper layers. */
+ }
+ if (status /*& COUNTERS_INTR*/) {
+ /* Increment the appropriate 'localstats' field. */
+ lp->stats.tx_window_errors++;
+ }
+ } while (++boguscount < 20) ;
+
+ return;
+}
+
+/* We have a good packet(s), get it/them out of the buffers. */
+static void
+net_rx(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+ int boguscount = 10;
+
+ do {
+ int status = inw(ioaddr);
+ int pkt_len = inw(ioaddr);
+
+ if (pkt_len == 0) /* Read all the frames? */
+ break; /* Done for now */
+
+ if (status & 0x40) { /* There was an error. */
+ lp->stats.rx_errors++;
+ if (status & 0x20) lp->stats.rx_frame_errors++;
+ if (status & 0x10) lp->stats.rx_over_errors++;
+ if (status & 0x08) lp->stats.rx_crc_errors++;
+ if (status & 0x04) lp->stats.rx_fifo_errors++;
+ } else {
+ /* Malloc up new buffer. */
+ int sksize = sizeof(struct sk_buff) + pkt_len;
+ struct sk_buff *skb;
+
+ skb = alloc_skb(sksize, GFP_ATOMIC);
+ if (skb == NULL) {
+ printk("%s: Memory squeeze, dropping packet.\n", dev->name);
+ lp->stats.rx_dropped++;
+ break;
+ }
+ skb->mem_len = sksize;
+ skb->mem_addr = skb;
+ skb->len = pkt_len;
+ skb->dev = dev;
+
+ /* 'skb+1' points to the start of sk_buff data area. */
+ memcpy((unsigned char *) (skb + 1), (void*)dev->rmem_start,
+ pkt_len);
+ /* or */
+ port_read(ioaddr, (void *)(skb+1), (pkt_len + 1) >> 1);
+
+#ifdef HAVE_NETIF_RX
+ netif_rx(skb);
+#else
+ skb->lock = 0;
+ if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) {
+ kfree_skbmem(skb, sksize);
+ lp->stats.rx_dropped++;
+ break;
+ }
+#endif
+ lp->stats.rx_packets++;
+ }
+ } while (--boguscount);
+
+ /* If any worth-while packets have been received, dev_rint()
+ has done a mark_bh(INET_BH) for us and will work on them
+ when we get to the bottom-half routine. */
+ return;
+}
+
+/* The inverse routine to net_open(). */
+static int
+net_close(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ int ioaddr = dev->base_addr;
+
+ lp->open_time = 0;
+
+ dev->tbusy = 1;
+ dev->start = 0;
+
+ /* Flush the Tx and disable Rx here. */
+
+ disable_dma(dev->dma);
+
+ /* If not IRQ or DMA jumpered, free up the line. */
+ outw(0x00, ioaddr+0); /* Release the physical interrupt line. */
+
+ free_irq(dev->irq);
+ free_dma(dev->dma);
+
+ irq2dev_map[dev->irq] = 0;
+
+ /* Update the statistics here. */
+
+ return 0;
+
+}
+
+/* Get the current statistics. This may be called with the card open or
+ closed. */
+static struct enet_statistics *
+net_get_stats(struct device *dev)
+{
+ struct net_local *lp = (struct net_local *)dev->priv;
+ short ioaddr = dev->base_addr;
+
+ cli();
+ /* Update the statistics from the device registers. */
+ lp->stats.rx_missed_errors = inw(ioaddr+1);
+ sti();
+
+ return &lp->stats;
+}
+
+#ifdef HAVE_MULTICAST
+/* Set or clear the multicast filter for this adaptor.
+ num_addrs == -1 Promiscuous mode, receive all packets
+ num_addrs == 0 Normal mode, clear multicast list
+ num_addrs > 0 Multicast mode, receive normal and MC packets, and do
+ best-effort filtering.
+ */
+static void
+set_multicast_list(struct device *dev, int num_addrs, void *addrs)
+{
+ short ioaddr = dev->base_addr;
+ if (num_addrs) {
+ outw(69, ioaddr); /* Enable promiscuous mode */
+ } else
+ outw(99, ioaddr); /* Disable promiscuous mode, use normal mode */
+}
+#endif
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c skeleton.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * tab-width: 4
+ * End:
+ */
diff --git a/net/inet/slhc.c b/drivers/net/slhc.c
index 10931c3..32e10d3 100644
--- a/net/inet/slhc.c
+++ b/drivers/net/slhc.c
@@ -610,6 +610,8 @@ slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize)
cp += ((ip->ihl) - 5) * 4;
}
+ ((struct iphdr *)icp)->check = ip_csum((struct iphdr*)icp);
+
memcpy(cp, thp, 20);
cp += 20;
diff --git a/net/inet/slhc.h b/drivers/net/slhc.h
index 0044b02..0044b02 100644
--- a/net/inet/slhc.h
+++ b/drivers/net/slhc.h
diff --git a/net/inet/slip.c b/drivers/net/slip.c
index 148baf2..85a14ad 100644
--- a/net/inet/slip.c
+++ b/drivers/net/slip.c
@@ -7,6 +7,13 @@
*
* Authors: Laurence Culhane, <loz@holmes.demon.co.uk>
* Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
+ *
+ * Fixes:
+ * Alan Cox : Sanity checks and avoid tx overruns.
+ * Has a new sl->mtu field.
+ * Alan Cox : Found cause of overrun. ifconfig sl0 mtu upwards.
+ * Driver now spots this and grows/shrinks its buffers(hack!).
+ * Memory leak if you run out of memory setting up a slip driver fixed.
*/
#include <asm/segment.h>
#include <asm/system.h>
@@ -192,6 +199,71 @@ sl_free(struct slip *sl)
}
}
+/* MTU has been changed by the IP layer. Unfortunately we are not told about this, but
+ we spot it ourselves and fix things up. We could be in an upcall from the tty
+ driver, or in an ip packet queue. */
+
+static void sl_changedmtu(struct slip *sl)
+{
+ struct device *dev=sl->dev;
+ unsigned char *tb,*rb,*cb,*tf,*rf,*cf;
+ int l;
+ int omtu=sl->mtu;
+
+ sl->mtu=dev->mtu;
+ l=(dev->mtu *2);
+
+ DPRINTF((DBG_SLIP,"SLIP: mtu changed!\n"));
+
+ tb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
+ rb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
+ cb= (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
+
+ if(tb==NULL || rb==NULL || cb==NULL)
+ {
+ printk("Unable to grow slip buffers. MTU change cancelled.\n");
+ sl->mtu=omtu;
+ dev->mtu=omtu;
+ if(tb!=NULL)
+ kfree(tb);
+ if(rb!=NULL)
+ kfree(rb);
+ if(cb!=NULL)
+ kfree(cb);
+ return;
+ }
+
+ cli();
+
+ tf=(unsigned char *)sl->dev->mem_start;
+ sl->dev->mem_start=(unsigned long)tb;
+ sl->dev->mem_end=(unsigned long) (sl->dev->mem_start + l);
+ rf=(unsigned char *)sl->dev->rmem_start;
+ sl->dev->rmem_start=(unsigned long)rb;
+ sl->dev->rmem_end=(unsigned long) (sl->dev->rmem_start + l);
+
+ sl->xbuff = (unsigned char *) sl->dev->mem_start;
+ sl->rbuff = (unsigned char *) sl->dev->rmem_start;
+ sl->rend = (unsigned char *) sl->dev->rmem_end;
+ sl->rhead = sl->rbuff;
+
+ cf=sl->cbuff;
+ sl->cbuff=cb;
+
+ sl->escape=0;
+ sl->sending=0;
+ sl->rcount=0;
+
+ sti();
+
+ if(rf!=NULL)
+ kfree(rf);
+ if(tf!=NULL)
+ kfree(tf);
+ if(cf!=NULL)
+ kfree(cf);
+}
+
/* Stuff one byte into a SLIP receiver buffer. */
static inline void
@@ -330,7 +402,17 @@ sl_encaps(struct slip *sl, unsigned char *icp, int len)
DPRINTF((DBG_SLIP, "SLIP: sl_encaps(0x%X, %d) called\n", icp, len));
DPRINTF((DBG_SLIP, ">> \"%s\" sent:\r\n", sl->dev->name));
+
ip_dump(icp, len);
+
+ if(sl->mtu != sl->dev->mtu) /* Someone has been ifconfigging */
+ sl_changedmtu(sl);
+
+ if(len>=sl->mtu) /* Sigh, shouldn't occur BUT ... */
+ {
+ len=sl->mtu-1;
+ printk("slip: truncating oversized transmit packet!\n");
+ }
p = icp;
#ifdef SL_COMPRESSED
@@ -478,6 +560,8 @@ sl_open(struct device *dev)
DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP XMIT buffer!\n"));
return(-ENOMEM);
}
+
+ sl->mtu = dev->mtu;
sl->dev->mem_start = (unsigned long) p;
sl->dev->mem_end = (unsigned long) (sl->dev->mem_start + l);
@@ -500,6 +584,7 @@ sl_open(struct device *dev)
p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL);
if (p == NULL) {
+ kfree((unsigned char *)sl->dev->mem_start);
DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP COMPRESS buffer!\n"));
return(-ENOMEM);
}
@@ -507,6 +592,9 @@ sl_open(struct device *dev)
sl->slcomp = slhc_init(16, 16);
if (sl->slcomp == NULL) {
+ kfree((unsigned char *)sl->dev->mem_start);
+ kfree((unsigned char *)sl->dev->rmem_start);
+ kfree(sl->cbuff);
DPRINTF((DBG_SLIP, "SLIP: no memory for SLCOMP!\n"));
return(-ENOMEM);
}
@@ -559,6 +647,9 @@ slip_recv(struct tty_struct *tty)
DPRINTF((DBG_SLIP, "SLIP: slip_recv(%d) called\n", tty->line));
if ((sl = sl_find(tty)) == NULL) return; /* not connected */
+ if(sl->mtu!=sl->dev->mtu) /* Argh! mtu change time! - costs us the packet part received at the change */
+ sl_changedmtu(sl);
+
/* Suck the bytes out of the TTY queues. */
do {
count = tty_read_raw_data(tty, buff, 128);
@@ -686,9 +777,9 @@ slip_init(struct device *dev)
sl = &sl_ctrl[dev->base_addr];
if (already++ == 0) {
- printk("SLIP: version %s (%d channels): ",
+ printk("SLIP: version %s (%d channels)\n",
SLIP_VERSION, SL_NRUNIT);
- printk("CSLIP code copyright 1989 Regents of the University of California\n");
+ printk("CSLIP: code copyright 1989 Regents of the University of California\n");
/* Fill in our LDISC request block. */
sl_ldisc.flags = 0;
sl_ldisc.open = slip_open;
diff --git a/net/inet/slip.h b/drivers/net/slip.h
index eb19031..cd81d60 100644
--- a/net/inet/slip.h
+++ b/drivers/net/slip.h
@@ -6,6 +6,9 @@
*
* Version: @(#)slip.h 1.2.0 03/28/93
*
+ * Fixes:
+ * Alan Cox : Added slip mtu field.
+ *
* Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
*/
#ifndef _LINUX_SLIP_H
@@ -51,6 +54,8 @@ struct slip {
unsigned long spacket; /* outbound frames counter */
unsigned long sbusy; /* "transmitter busy" counter */
unsigned long errors; /* error count */
+
+ int mtu; /* Our mtu (to spot changes!) */
};
diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c
new file mode 100644
index 0000000..2947f96
--- /dev/null
+++ b/drivers/net/smc-ultra.c
@@ -0,0 +1,260 @@
+/* smc-ultra.c: A SMC Ultra ethernet driver for linux. */
+/*
+ Written 1993 by Donald Becker. If released, this code will be
+ Copyright 1993 United States Government as represented by the
+ Director, National Security Agency. This software may be used and
+ distributed according to the terms of the GNU Public License,
+ incorporated herein by reference.
+
+ This is a driver for the SMC Ultra ethercard.
+
+ The Author may be reached as becker@super.org or
+ C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
+
+*/
+
+static char *version =
+ "smc-ultra.c:v0.02 10/8/93 Donald Becker (becker@super.org)\n";
+
+#include <linux/config.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <asm/io.h>
+#include <asm/system.h>
+#include <memory.h>
+
+#include "dev.h"
+#include "8390.h"
+
+int ultraprobe(int ioaddr, struct device *dev);
+int ultraprobe1(int ioaddr, struct device *dev);
+
+static int ultra_open(struct device *dev);
+static void ultra_reset_8390(struct device *dev);
+static int ultra_block_input(struct device *dev, int count,
+ char *buf, int ring_offset);
+static void ultra_block_output(struct device *dev, int count,
+ const unsigned char *buf, const start_page);
+static int ultra_close_card(struct device *dev);
+
+
+#define START_PG 0x00 /* First page of TX buffer */
+
+#define ULTRA_CMDREG 0 /* Offset to ASIC command register. */
+#define ULTRA_RESET 0x80 /* Board reset, in ULTRA_CMDREG. */
+#define ULTRA_MEMENB 0x40 /* Enable the shared memory. */
+#define ULTRA_NIC_OFFSET 16 /* NIC register offset from the base_addr. */
+
+/* Probe for the Ultra. This looks like a 8013 with the station
+ address PROM at I/O ports <base>+8 to <base>+13, with a checksum
+ following.
+*/
+
+int ultra_probe(struct device *dev)
+{
+ int *port, ports[] = {0x300, 0x280, 0x380, 0x240, 0};
+ short ioaddr = dev->base_addr;
+
+ if (ioaddr < 0)
+ return ENXIO; /* Don't probe at all. */
+ if (ioaddr > 0x100)
+ return ! ultraprobe1(ioaddr, dev);
+
+ for (port = &ports[0]; *port; port++) {
+#ifdef HAVE_PORTRESERVE
+ if (check_region(*port, 32))
+ continue;
+#endif
+ if ((inb(*port + 7) & 0xF0) == 0x20
+ && ultraprobe1(*port, dev) == 0)
+ return 0;
+ }
+ dev->base_addr = ioaddr;
+ return ENODEV;
+}
+
+int ultraprobe1(int ioaddr, struct device *dev)
+{
+ int i;
+ unsigned char *station_addr = dev->dev_addr;
+ int checksum = 0;
+ char *model_name;
+ int num_pages;
+
+ outb(0x7f & inb(ioaddr + 4), ioaddr + 4);
+
+ for (i = 0; i < 8; i++)
+ checksum += inb(ioaddr + 8 + i);
+ if ((checksum & 0xff) != 0xFF)
+ return ENODEV;
+
+ printk("%s: SMC Ultra at %#3x,", dev->name, ioaddr);
+ for (i = 0; i < 6; i++)
+ printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i));
+
+ outb(0x80 | inb(ioaddr + 4), ioaddr + 4);
+
+ model_name = "SMC Ultra";
+
+ if (dev->irq < 2) {
+ int irq;
+ /* Datasheet doesn't specify the IRQ line mapping -> always autoIRQ. */
+
+ outb(0x05, ioaddr + 6);
+ autoirq_setup(0);
+
+ /* Trigger an interrupt, then release. */
+ outb_p(0x09, ioaddr + 6);
+ outb(0x00, ioaddr + 6);
+
+ irq = autoirq_report(1);
+ if (irq)
+ printk(", using IRQ %d", irq);
+ else {
+ printk(", failed to detect IRQ line.\n");
+ return -EAGAIN;
+ }
+ dev->irq = irq;
+ } else
+ printk(" assigned IRQ %d.\n", dev->irq);
+
+
+ /* OK, were are certain this is going to work. Setup the device. */
+#ifdef HAVE_PORTRESERVE
+ snarf_region(ioaddr, 32);
+#endif
+
+ /* The 8390 isn't at the base address, so fake the offset */
+ dev->base_addr = ioaddr+ULTRA_NIC_OFFSET;
+
+ {
+ int addr = inb(ioaddr + 0xb);
+ int addr_tbl[4] = {0x0C0000, 0x0D0000, 0xFC0000, 0xFD0000};
+ short num_pages_tbl[4] = {0x20, 0x40, 0x80, 0xff};
+
+ dev->mem_start = ((addr & 0x0f) << 13) + addr_tbl[(addr >> 6) & 3] ;
+ num_pages = num_pages_tbl[(addr >> 4) & 3];
+ }
+
+ ethdev_init(dev);
+
+ ei_status.name = model_name;
+ ei_status.word16 = 1;
+ ei_status.tx_start_page = START_PG;
+ ei_status.rx_start_page = START_PG + TX_PAGES;
+ ei_status.stop_page = num_pages;
+
+ dev->rmem_start = dev->mem_start + TX_PAGES*256;
+ dev->mem_end = dev->rmem_end
+ = dev->mem_start + (ei_status.stop_page - START_PG)*256;
+
+ printk(", shared memory at %#x-%#x.\n", dev->mem_start, dev->mem_end-1);
+ if (ei_debug > 0)
+ printk(version);
+
+ ei_status.reset_8390 = &ultra_reset_8390;
+ ei_status.block_input = &ultra_block_input;
+ ei_status.block_output = &ultra_block_output;
+ dev->open = &ultra_open;
+ dev->stop = &ultra_close_card;
+ NS8390_init(dev, 0);
+
+ return 0;
+}
+
+static int
+ultra_open(struct device *dev)
+{
+ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC addr */
+
+ if (irqaction(dev->irq, &ei_sigaction))
+ return -EAGAIN;
+
+ /* Enabled FINE16 mode. */
+ outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c);
+ outb(ULTRA_MEMENB, ioaddr); /* Enable memory, 16 bit mode. */
+ outb(0x80, ioaddr + 5);
+ outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */
+ return ei_open(dev);
+}
+
+static void
+ultra_reset_8390(struct device *dev)
+{
+ int cmd_port = dev->base_addr - ULTRA_NIC_OFFSET; /* ASIC base addr */
+
+ outb(ULTRA_RESET, cmd_port);
+ if (ei_debug > 1) printk("resetting Ultra, t=%d...", jiffies);
+ ei_status.txing = 0;
+
+ outb(ULTRA_MEMENB, cmd_port);
+
+ if (ei_debug > 1) printk("reset done\n");
+ return;
+}
+
+/* Block input and output are easy on shared memory ethercards, the only
+ complication is when the ring buffer wraps. */
+
+static int
+ultra_block_input(struct device *dev, int count, char *buf, int ring_offset)
+{
+ void *xfer_start = (void *)(dev->mem_start + ring_offset
+ - (START_PG<<8));
+
+ if (xfer_start + count > (void*) dev->rmem_end) {
+ /* We must wrap the input move. */
+ int semi_count = (void*)dev->rmem_end - xfer_start;
+ memcpy(buf, xfer_start, semi_count);
+ count -= semi_count;
+ memcpy(buf + semi_count, (char *)dev->rmem_start, count);
+ return dev->rmem_start + count;
+ }
+ memcpy(buf, xfer_start, count);
+
+ return ring_offset + count;
+}
+
+static void
+ultra_block_output(struct device *dev, int count, const unsigned char *buf,
+ int start_page)
+{
+ unsigned char *shmem
+ = (unsigned char *)dev->mem_start + ((start_page - START_PG)<<8);
+
+ memcpy(shmem, buf, count);
+
+}
+
+static int
+ultra_close_card(struct device *dev)
+{
+ int ioaddr = dev->base_addr - ULTRA_NIC_OFFSET; /* CMDREG */
+
+ dev->start = 0;
+ dev->tbusy = 1;
+
+ if (ei_debug > 1)
+ printk("%s: Shutting down ethercard.\n", dev->name);
+
+ outb(0x00, ioaddr + 6); /* Disable interrupts. */
+ free_irq(dev->irq);
+ irq2dev_map[dev->irq] = 0;
+
+ NS8390_init(dev, 0);
+
+ /* We should someday disable shared memory and change to 8-bit mode
+ "just in case"... */
+
+ return 0;
+}
+
+
+/*
+ * Local variables:
+ * compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/inet -c smc-ultra.c"
+ * version-control: t
+ * kept-new-versions: 5
+ * End:
+ */
diff --git a/net/inet/wd.c b/drivers/net/wd.c
index 154450c..ea1244e 100644
--- a/net/inet/wd.c
+++ b/drivers/net/wd.c
@@ -6,7 +6,7 @@
distributed according to the terms of the GNU Public License,
incorporated herein by reference.
- This is a driver for the WD8003 and WD8013 ethercards.
+ This is a driver for WD8003 and WD8013 "compatible" ethercards.
The Author may be reached as becker@super.org or
C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
@@ -15,7 +15,7 @@
*/
static char *version =
- "wd.c:v0.99-13 8/30/93 Donald Becker (becker@super.org)\n";
+ "wd.c:v0.99-14 10/13/93 Donald Becker (becker@super.org)\n";
#include <linux/config.h>
#include <linux/kernel.h>
@@ -185,7 +185,7 @@ int wdprobe1(int ioaddr, struct device *dev)
int irqmap[] = {9,3,5,7,10,11,15,4};
int reg1 = inb(ioaddr+1);
int reg4 = inb(ioaddr+4);
- if (reg1 == 0xff) /* Ack!! No way to read the IRQ! */
+ if (ancient || reg1 == 0xff) /* Ack!! No way to read the IRQ! */
dev->irq = word16 ? 10 : 5;
else
dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)];
@@ -254,56 +254,39 @@ static void
wd_reset_8390(struct device *dev)
{
int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
- int reset_start_time = jiffies;
outb(WD_RESET, wd_cmd_port);
if (ei_debug > 1) printk("resetting the WD80x3 t=%d...", jiffies);
ei_status.txing = 0;
- sti();
- /* We shouldn't use the boguscount for timing, but this hasn't been
- checked yet, and you could hang your machine if jiffies break... */
- {
- int boguscount = 150000;
- while(jiffies - reset_start_time < 2)
- if (boguscount-- < 0) {
- printk("jiffy failure (t=%d)...", jiffies);
- break;
- }
- }
-
/* Set up the ASIC registers, just in case something changed them. */
- if (ei_status.word16)
- outb(NIC16 | ((dev->mem_start>>19) & 0x1f),
- wd_cmd_port+WD_CMDREG5);
outb((((dev->mem_start>>13) & 0x3f)|WD_MEMENB), wd_cmd_port);
+ if (ei_status.word16)
+ outb(NIC16 | ((dev->mem_start>>19) & 0x1f), wd_cmd_port+WD_CMDREG5);
- while ((inb(dev->base_addr+EN0_ISR) & ENISR_RESET) == 0)
- if (jiffies - reset_start_time > 2) {
- printk("%s: wd_reset_8390() did not complete.\n", dev->name);
- break;
- }
+ if (ei_debug > 1) printk("reset done\n");
return;
}
/* Block input and output are easy on shared memory ethercards, and trivial
on the Western digital card where there is no choice of how to do it.
- The only complication is if the ring buffer wraps. */
+ The only complications are that the ring buffer wraps, and need to map
+ switch between 8- and 16-bit modes. */
static int
wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
{
+ int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
void *xfer_start = (void *)(dev->mem_start + ring_offset
- (WD_START_PG<<8));
- /* This mapout isn't necessary if wd_close_card is called. */
-#if !defined(WD_no_mapout)
- int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
-
- if (ei_status.word16)
- outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
- outb(ei_status.reg0, wd_cmdreg); /* WD_CMDREG */
-#endif
+ /* We'll always get a 4 byte header read first. */
+ if (count == 4) {
+ if (ei_status.word16)
+ outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
+ ((int*)buf)[0] = ((int*)xfer_start)[0];
+ return 0;
+ }
if (xfer_start + count > (void*) dev->rmem_end) {
/* We must wrap the input move. */
@@ -311,43 +294,35 @@ wd_block_input(struct device *dev, int count, char *buf, int ring_offset)
memcpy(buf, xfer_start, semi_count);
count -= semi_count;
memcpy(buf + semi_count, (char *)dev->rmem_start, count);
- return dev->rmem_start + count;
- }
- memcpy(buf, xfer_start, count);
+ } else
+ memcpy(buf, xfer_start, count);
-#if !defined(WD_no_mapout)
- /* Turn off 16 bit access so that reboot works. */
+ /* Turn off 16 bit access so that reboot works. ISA brain-damage */
if (ei_status.word16)
outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-#endif
- return ring_offset + count;
+
+ return 0;
}
static void
wd_block_output(struct device *dev, int count, const unsigned char *buf,
int start_page)
{
+ int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
unsigned char *shmem
= (unsigned char *)dev->mem_start + ((start_page - WD_START_PG)<<8);
-#if !defined(WD_no_mapout)
- int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */
- if (ei_status.word16)
+ if (ei_status.word16) {
+ /* Turn on and off 16 bit access so that reboot works. */
outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5);
- outb(ei_status.reg0, wd_cmdreg); /* WD_CMDREG */
-#endif
-
- memcpy(shmem, buf, count);
-
-#if !defined(WD_no_mapout)
- /* Turn off 16 bit access so that reboot works. */
- if (ei_status.word16)
+ memcpy(shmem, buf, count);
outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5);
-#endif
+ } else
+ memcpy(shmem, buf, count);
}
-/* This function resets the ethercard if something screws up. */
+
static int
wd_close_card(struct device *dev)
{
@@ -369,7 +344,7 @@ wd_close_card(struct device *dev)
/*
* Local variables:
- * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c wd.c"
+ * compile-command: "gcc -D__KERNEL__ -Wall -O6 -I/usr/src/linux/net/tcp -c wd.c"
* version-control: t
* kept-new-versions: 5
* End:
diff --git a/kernel/blk_drv/scsi/Makefile b/drivers/scsi/Makefile
index aecb001..2144533 100644
--- a/kernel/blk_drv/scsi/Makefile
+++ b/drivers/scsi/Makefile
@@ -6,61 +6,116 @@
# unless its something special (ie not a .c file).
#
-SCSI_OBJS :=
+#AHA152X = -DDEBUG -DAUTOCONF -DIRQ=11 -DSCSI_ID=7 -DRECONNECT=0 \
+# -DPORTBASE=0x340 -DSKIP_BIOSTEST -DDONT_SNARF
+
+AHA152X = -DDEBUG -DAUTOCONF
+
+SCSI_OBJS =
+SCSI_SRCS =
ifdef CONFIG_SCSI
SCSI_OBJS := hosts.o scsi.o scsi_ioctl.o constants.o
+SCSI_SRCS := hosts.c scsi.c scsi_ioctl.c constants.c
-ifdef CONFIG_BLK_DEV_ST
+ifdef CONFIG_CHR_DEV_ST
SCSI_OBJS := $(SCSI_OBJS) st.o
+SCSI_SRCS := $(SCSI_SRCS) st.c
endif
ifdef CONFIG_BLK_DEV_SD
SCSI_OBJS := $(SCSI_OBJS) sd.o sd_ioctl.o
+SCSI_SRCS := $(SCSI_SRCS) sd.c sd_ioctl.c
endif
ifdef CONFIG_BLK_DEV_SR
SCSI_OBJS := $(SCSI_OBJS) sr.o sr_ioctl.o
+SCSI_SRCS := $(SCSI_SRCS) sr.c sr_ioctl.c
+endif
+
+ifdef CONFIG_CHR_DEV_SG
+SCSI_OBJS := $(SCSI_OBJS) sg.o
+SCSI_SRCS := $(SCSI_SRCS) sg.c
+endif
+
+ifdef CONFIG_SCSI_AHA152X
+SCSI_OBJS := $(SCSI_OBJS) aha152x.o
+SCSI_SRCS := $(SCSI_SRCS) aha152x.c
endif
ifdef CONFIG_SCSI_AHA1542
SCSI_OBJS := $(SCSI_OBJS) aha1542.o
+SCSI_SRCS := $(SCSI_SRCS) aha1542.c
endif
ifdef CONFIG_SCSI_AHA1740
SCSI_OBJS := $(SCSI_OBJS) aha1740.o
+SCSI_SRCS := $(SCSI_SRCS) aha1740.c
+endif
+
+ifdef CONFIG_SCSI_DEBUG
+SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
+SCSI_SRCS := $(SCSI_SRCS) scsi_debug.c
endif
ifdef CONFIG_SCSI_FUTURE_DOMAIN
SCSI_OBJS := $(SCSI_OBJS) fdomain.o
+SCSI_SRCS := $(SCSI_SRCS) fdomain.c
endif
-ifdef CONFIG_SCSI_ULTRASTOR
-SCSI_OBJS := $(SCSI_OBJS) ultrastor.o
+ifdef CONFIG_SCSI_GENERIC_NCR5380
+SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o
+SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c
endif
-ifdef CONFIG_SCSI_7000FASST
-SCSI_OBJS := $(SCSI_OBJS) wd7000.o
+ifdef CONFIG_SCSI_PAS16
+SCSI_OBJS := $(SCSI_OBJS) pas16.o
+SCSI_SRCS := $(SCSI_SRCS) pas16.c
endif
ifdef CONFIG_SCSI_SEAGATE
SCSI_OBJS := $(SCSI_OBJS) seagate.o
+SCSI_SRCS := $(SCSI_SRCS) seagate.c
else
-ifdef CONFIG_SCSI_FD_88x
+ifdef CONFIG_SCSI_FD_8xx
SCSI_OBJS := $(SCSI_OBJS) seagate.o
+SCSI_SRCS := $(SCSI_SRCS) seagate.c
endif
endif
-ifdef CONFIG_SCSI_DEBUG
-SCSI_OBJS := $(SCSI_OBJS) scsi_debug.o
+ifdef CONFIG_SCSI_7000FASST
+SCSI_OBJS := $(SCSI_OBJS) wd7000.o
+SCSI_SRCS := $(SCSI_SRCS) wd7000.c
+endif
+
+ifdef CONFIG_SCSI_T128
+SCSI_OBJS := $(SCSI_OBJS) t128.o
+SCSI_SRCS := $(SCSI_SRCS) t128.c
endif
+ifdef CONFIG_SCSI_ULTRASTOR
+SCSI_OBJS := $(SCSI_OBJS) ultrastor.o
+SCSI_SRCS := $(SCSI_SRCS) ultrastor.c
+endif
+
+
+
scsi.a: $(SCSI_OBJS)
rm -f scsi.a
$(AR) rcs scsi.a $(SCSI_OBJS)
sync
+aha152x.o: aha152x.c
+ $(CC) $(CFLAGS) $(AHA152X) -c aha152x.c
+
+
+seagate.o: seagate.c
+ $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c
+
+dep:
+ $(CPP) -M $(AHA152X) $(SCSI_SRCS) > .depend
+
else
scsi.a:
@@ -68,19 +123,14 @@ scsi.a:
@echo No SCSI drivers configured
$(AR) rcs scsi.a
-endif
+dep:
-seagate.o: seagate.c
- $(CC) $(CFLAGS) -DARBITRATE -DSLOW_HANDSHAKE -DFAST32 -c seagate.c
+endif
-constants.o: constants.c
- $(CC) $(CFLAGS) -c constants.c
clean:
rm -f core *.o *.a *.s
-dep:
- $(CPP) -M *.c > .depend
#
# include a dependency file if one exists
diff --git a/drivers/scsi/NCR5380.c b/drivers/scsi/NCR5380.c
new file mode 100644
index 0000000..caa0c5a
--- /dev/null
+++ b/drivers/scsi/NCR5380.c
@@ -0,0 +1,2145 @@
+/*
+ * NCR 5380 generic driver routines. These should make it *trivial*
+ * to implement 5380 SCSI drivers under Linux with a non-trantor
+ * architecture.
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
+ *
+ * DISTRIBUTION REALEASE 3.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: NCR5380.c,v $
+ */
+
+/*
+ * Furthur development / testing that should be done :
+ * 1. Test USLEEP code
+ * 2. Test SCSI-II tagged queueing (I have no devices which support
+ * tagged queueing)
+ * 3. Flesh out REAL_DMA code (my sample board doesn't support this)
+ * Perhaps some of the 680x0 porting crew can help out here?
+ * 4. Test linked command handling code after Eric is ready with
+ * the high level code.
+ * 5. Tie instance handling into Eric's multi-host patches
+ */
+
+#ifndef notyet
+#undef LINKED
+#undef USLEEP
+#undef REAL_DMA
+#endif
+
+/*
+ * Design
+ * Issues :
+ *
+ * The other Linux SCSI drivers were written when Linux was Intel PC-only,
+ * and specifically for each board rather than each chip. This makes their
+ * adaptation to platforms like the Mac (Some of which use NCR5380's)
+ * more difficult than it has to be.
+ *
+ * Also, many of the SCSI drivers were written before the command queing
+ * routines were implemented, meaning their implementations of queued
+ * commands were hacked on rather than designed in from the start.
+ *
+ * When I designed the Linux SCSI drivers I figured that
+ * while having two different SCSI boards in a system might be useful
+ * for debugging things, two of the same type wouldn't be used.
+ * Well, I was wrong and a number of users have mailed me about running
+ * multiple high-performance SCSI boards in a server.
+ *
+ * Finally, when I get questions from users, I have no idea what
+ * revision of my driver they are running.
+ *
+ * This driver attempts to address these problems :
+ * This is a generic 5380 driver. To use it on a different platform,
+ * one simply writes appropriate system specific macros (ie, data
+ * transfer - some PC's will use the I/O bus, 68K's must use
+ * memory mapped) and drops this file in their 'C' wrapper.
+ *
+ * As far as command queueing, two queues are maintained for
+ * each 5380 in the system - commands that haven't been issued yet,
+ * and commands that are currently executing. This means that an
+ * unlimited number of commands may be queued, letting
+ * more commands propogate from the higher driver levels giving higher
+ * througput. Note that both I_T_L and I_T_L_Q nexuses are supported,
+ * allowing multiple commands to propogate all the way to a SCSI-II device
+ * while a command is allready executing.
+ *
+ * To solve the multiple-boards-in-the-same-system problem,
+ * there is a separate instance structure for each instance
+ * of a 5380 in the system. So, mutliple NCR5380 drivers will
+ * be able to coexist with appropriate changes to the high level
+ * SCSI code.
+ *
+ * A NCR5380_PUBLIC_REVISION macro is provided, with the release
+ * number (updated for each public release) printed by the
+ * NCR5380_print_options command, which should be called from the
+ * wrapper detect function, so that I know what release of the driver
+ * users are using.
+ *
+ * Issues specific to the NCR5380 :
+ *
+ * When used in a PIO or pseudo-dma mode, the NCR5380 is a braindead
+ * piece of hardware that requires you to sit in a loop polling for
+ * the REQ signal as long as you are connected. Some devices are
+ * brain dead (ie, many TEXEL CD ROM drives) and won't disconnect
+ * while doing long seek operations.
+ *
+ * The workarround for this is to keep track of devices that have
+ * disconnected. If the device hasn't disconnected, for commands that
+ * should disconnect, we do something like
+ *
+ * while (!REQ is asserted) { sleep for N usecs; poll for M usecs }
+ *
+ * Some tweaking of N and M needs to be done. An algorithm based
+ * on "time to data" would give the best results as long as short time
+ * to datas (ie, on the same track) were considered, however these
+ * broken devices are the exception rather than the rule and I'd rather
+ * spend my time optomizing for the normal case.
+ *
+ * Architecture :
+ *
+ * At the heart of the design is a corroutine, NCR5380_main,
+ * which is started when not running by the interrupt handler,
+ * timer, and queue command function. It attempts to establish
+ * I_T_L or I_T_L_Q nexuses by removing the commands from the
+ * issue queue and calling NCR5380_select() if a nexus
+ * is not established.
+ *
+ * Once a nexus is established, the NCR5380_information_transfer()
+ * phase goes through the various phases as instructed by the target.
+ * if the target goes into MSG IN and sends a DISCONNECT message,
+ * the command structure is placed into the per instance disconnected
+ * queue, and NCR5380_main tries to find more work. If USLEEP
+ * was defined, and the target is idle for too long, the system
+ * will try to sleep.
+ *
+ * If a command has disconnected, eventually an interrupt will trigger,
+ * calling NCR5380_intr() which will inturn call NCR5380_reselect
+ * to restablish a nexus. This will run main if necessary.
+ *
+ * On command termination, the done function will be called as
+ * appropriate.
+ *
+ * SCSI pointers are maintained in the SCp field of SCSI command
+ * structures, being initialized after the command is connected
+ * in NCR5380_select, and set as appropriate in NCR5380_information_transfer.
+ * Note that in violation of the standard, an implicit SAVE POINTERS operation
+ * is done, since some BROKEN disks fail to issue an explicit SAVE POINTERS.
+ */
+
+/*
+ * Using this file :
+ * This file a skeleton Linux SCSI driver for the NCR 5380 series
+ * of chips. To use it, you write a architecture specific functions
+ * and macros and include this file in your driver.
+ *
+ * These macros control options :
+ * AUTOPROBE_IRQ - if defined, the NCR5380_probe_irq() function will be
+ * defined.
+ *
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ * for commands that return with a CHECK CONDITION status.
+ *
+ * DIFFERENTIAL - if defined, NCR53c81 chips will use external differential
+ * tracievers.
+ *
+ * LINKED - if defined, linked commands are supported.
+ *
+ * PSEUDO_DMA - if defined, PSEUDO DMA is used during the data transfer phases.
+ *
+ * REAL_DMA - if defined, REAL DMA is used during the data transfer phases.
+ *
+ * SCSI2 - if defined, SCSI-2 tagged queing is used where possible
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
+ * only really want to use this if you're having a problem with
+ * dropped characters during high speed communications, and even
+ * then, you're going to be better off twiddling with transfersize
+ * in the high level code.
+ *
+ * USLEEP - if defined, on devices that aren't disconnecting from the
+ * bus, we will go to sleep so that the CPU can get real work done
+ * when we run a command that won't complete immediately.
+ *
+ * Note that if USLEEP is defined, NCR5380_TIMER *must* also be
+ * defined.
+ *
+ * Defaults for these will be provided if USLEEP is defined, although
+ * the user may want to adjust these to allocate CPU resources to
+ * the SCSI driver or "real" code.
+ *
+ * USLEEP_SLEEP - amount of time, in jiffies, to sleep
+ *
+ * USLEEP_POLL - amount of time, in jiffies, to poll
+ *
+ * These macros MUST be defined :
+ * NCR5380_local_declare() - declare any local variables needed for your transfer
+ * routines.
+ *
+ * NCR5380_setup(instance) - initialize any local variables needed from a given
+ * instance of the host adapter for NCR5380_{read,write,pread,pwrite}
+ *
+ * NCR5380_read(register) - read from the specified register
+ *
+ * NCR5380_write(register, value) - write to the specific register
+ *
+ * NCR5380_implementation_fields - additional fields needed for this
+ * specific implementation of the NCR5380
+ *
+ * Either real DMA *or* pseudo DMA may be implemented
+ * REAL functions :
+ * NCR5380_REAL_DMA should be defined if real DMA is to be used.
+ * NCR5380_dma_write_setup(instance, src, count) - initialize
+ * NCR5380_dma_read_setup(instance, dst, count) - initialize
+ * NCR5380_dma_residual(); - residual count
+ *
+ * PSEUDO functions :
+ * NCR5380_pwrite(instance, src, count)
+ * NCR5380_pread(instance, dst, count);
+ *
+ * If nothing specific to this implementation needs doing (ie, with external
+ * hardware), you must also define
+ *
+ * NCR5380_queue_command
+ * NCR5380_reset
+ * NCR5380_abort
+ *
+ * to be the global entry points into the specific driver, ie
+ * #define NCR5380_queue_command t128_queue_command.
+ *
+ * If this is not done, the routines will be defined as static functions
+ * with the NCR5380* names and the user must provide a globally
+ * accessable wrapper function.
+ *
+ * The generic driver is initialized by calling NCR5380_init(instance),
+ * after setting the appropriate host specific fields and ID. If the
+ * driver wishes to autoprobe for an IRQ line, the NCR5380_probe_irq(instance,
+ * possible) function may be used. Before the specific driver initialization
+ * code finishes, NCR5380_print_options should be called.
+ */
+
+static struct Scsi_Host *first_instance = NULL;
+static Scsi_Host_Template *the_template = NULL;
+
+/*
+ * Function : void initialize_SCp(Scsi_Cmnd *cmd)
+ *
+ * Purpose : initialize the saved data pointers for cmd to point to the
+ * start of the buffer.
+ *
+ * Inputs : cmd - Scsi_Cmnd structure to have pointers reset.
+ */
+
+static __inline__ void initialize_SCp(Scsi_Cmnd *cmd) {
+ /*
+ * Initialize the Scsi Pointer field so that all of the commands in the
+ * various queues are valid.
+ */
+
+ if (cmd->use_sg) {
+ cmd->SCp.buffer = (struct scatterlist *) cmd->buffer;
+ cmd->SCp.buffers_residual = cmd->use_sg - 1;
+ cmd->SCp.ptr = (char *) cmd->SCp.buffer->address;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ } else {
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ cmd->SCp.ptr = (char *) cmd->request_buffer;
+ cmd->SCp.this_residual = cmd->request_bufflen;
+ }
+}
+
+#include <linux/delay.h>
+
+#ifdef NDEBUG
+static struct {
+ unsigned char mask;
+ char * name;}
+signals[] = {{ SR_DBP, "PARITY"}, { SR_RST, "RST" }, { SR_BSY, "BSY" },
+ { SR_REQ, "REQ" }, { SR_MSG, "MSG" }, { SR_CD, "CD" }, { SR_IO, "IO" },
+ { SR_SEL, "SEL" }, {0, NULL}},
+basrs[] = {{BASR_ATN, "ATN"}, {BASR_ACK, "ACK"}, {0, NULL}},
+icrs[] = {{ICR_ASSERT_RST, "ASSERT RST"},{ICR_ASSERT_ACK, "ASSERT ACK"},
+ {ICR_ASSERT_BSY, "ASSERT BSY"}, {ICR_ASSERT_SEL, "ASSERT SEL"},
+ {ICR_ASSERT_ATN, "ASSERT ATN"}, {ICR_ASSERT_DATA, "ASSERT DATA"},
+ {0, NULL}},
+mrs[] = {{MR_BLOCK_DMA_MODE, "MODE BLOCK DMA"}, {MR_TARGET, "MODE TARGET"},
+ {MR_ENABLE_PAR_CHECK, "MODE PARITY CHECK"}, {MR_ENABLE_PAR_INTR,
+ "MODE PARITY INTR"}, {MR_MONITOR_BSY, "MODE MONITOR BSY"},
+ {MR_DMA_MODE, "MODE DMA"}, {MR_ARBITRATE, "MODE ARBITRATION"},
+ {0, NULL}};
+
+/*
+ * Function : void NCR5380_print(struct Scsi_Host *instance)
+ *
+ * Purpose : print the SCSI bus signals for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print(struct Scsi_Host *instance) {
+ NCR5380_local_declare();
+ unsigned char status, data, basr, mr, icr, i;
+ NCR5380_setup(instance);
+ cli();
+ data = NCR5380_read(CURRENT_SCSI_DATA_REG);
+ status = NCR5380_read(STATUS_REG);
+ mr = NCR5380_read(MODE_REG);
+ icr = NCR5380_read(INITIATOR_COMMAND_REG);
+ basr = NCR5380_read(BUS_AND_STATUS_REG);
+ sti();
+ for (i = 0; signals[i].mask ; ++i)
+ if (status & signals[i].mask)
+ printk(" %s", signals[i].name);
+ for (i = 0; basrs[i].mask ; ++i)
+ if (basr & basrs[i].mask)
+ printk(" %s", basrs[i].name);
+ for (i = 0; icrs[i].mask; ++i)
+ if (icr & icrs[i].mask)
+ printk(" %s", icrs[i].name);
+ for (i = 0; mrs[i].mask; ++i)
+ if (mr & mrs[i].mask)
+ printk(" %s", mrs[i].name);
+ printk("\n");
+}
+
+static struct {
+ unsigned char value;
+ char *name;
+} phases[] = {
+{PHASE_DATAOUT, "DATAOUT"}, {PHASE_DATAIN, "DATAIN"}, {PHASE_CMDOUT, "CMDOUT"},
+{PHASE_STATIN, "STATIN"}, {PHASE_MSGOUT, "MSGOUT"}, {PHASE_MSGIN, "MSGIN"},
+{PHASE_UNKNOWN, "UNKNOWN"}};
+
+/*
+ * Function : void NCR5380_print_phase(struct Scsi_Host *instance)
+ *
+ * Purpose : print the current SCSI phase for debugging purposes
+ *
+ * Input : instance - which NCR5380
+ */
+
+static void NCR5380_print_phase(struct Scsi_Host *instance) {
+ NCR5380_local_declare();
+ unsigned char status;
+ int i;
+ NCR5380_setup(instance);
+
+ status = NCR5380_read(STATUS_REG);
+ if (!(status & SR_REQ))
+ printk("scsi%d : REQ not asserted, phase unknown.\n",
+ instance->host_no);
+ else {
+ for (i = 0; (phases[i].value != PHASE_UNKNOWN) &&
+ (phases[i].value != (status & PHASE_MASK)); ++i);
+ printk("scsi%d : phase %s\n", instance->host_no, phases[i].name);
+ }
+}
+#endif
+
+/*
+ * We need to have our corroutine active given these constraints :
+ * 1. The mutex flag, main_running, can only be set when the main
+ * routine can actually process data, otherwise SCSI commands
+ * will never get issued.
+ *
+ * 2. NCR5380_main() shouldn't be called before it has exited, because
+ * other drivers have had kernel stack overflows in similar
+ * situations.
+ *
+ * 3. We don't want to inline NCR5380_main() because of space concerns,
+ * even though it is only called in two places.
+ *
+ * So, the solution is to set the mutex in an inline wrapper for the
+ * main corroutine, and have the main corroutine exit with interrupts
+ * disabled after the final search through the queues so that no race
+ * conditions are possible.
+ */
+
+static volatile int main_running = 0;
+
+/*
+ * Function : run_main(void)
+ *
+ * Purpose : insure that the coroutine is running and will process our
+ * request. main_running is checked/set here (in an inline function)
+ * rather than in NCR5380_main itself to reduce the chances of stack
+ * overflow.
+ *
+ */
+
+static __inline__ void run_main(void) {
+ cli();
+ if (!main_running) {
+ main_running = 1;
+ NCR5380_main();
+ /*
+ * main_running is cleared in NCR5380_main once it can't do
+ * more work, and NCR5380_main exits with interrupts disabled.
+ */
+ sti();
+ } else
+ sti();
+}
+
+#ifdef USLEEP
+#ifndef NCR5380_TIMER
+#error "NCR5380_TIMER must be defined so that this type of NCR5380 driver gets a unique timer."
+#endif
+
+/*
+ * These need tweaking, and would probably work best as per-device
+ * flags initialized differently for disk, tape, cd, etc devices.
+ * People with broken devices are free to experiment as to what gives
+ * the best results for them.
+ *
+ * USLEEP_SLEEP should be a minimum seek time.
+ *
+ * USLEEP_POLL should be a maximum rotational latency.
+ */
+#ifndef USLEEP_SLEEP
+/* 20 ms (reasonable hard disk speed) */
+#define USLEEP_SLEEP 2
+#endif
+/* 300 RPM (floppy speed) */
+#ifndef USLEEP_POLL
+#define USLEEP_POLL 20
+#endif
+
+static struct Scsi_Host * expires_first = NULL;
+
+/*
+ * Function : int should_disconnect (unsigned char cmd)
+ *
+ * Purpose : decide weather a commmand would normally disconnect or
+ * not, since if it won't disconnect we should go to sleep.
+ *
+ * Input : cmd - opcode of SCSI command
+ *
+ * Returns : DISCONNECT_LONG if we should disconnect for a really long
+ * time (ie always, sleep, look for REQ active, sleep),
+ * DISCONNECT_TIME_TO_DATA if we would only disconnect for a normal
+ * time-to-data dealy, DISCONNECT_NONE if this command would return
+ * immediately.
+ *
+ * Future sleep algorithms based on time to data can exploit
+ * something like this so they can differentiate between "normal"
+ * (ie, read, write, seek) and unusual commands (ie, * format).
+ *
+ * Note : We don't deal with commands that handle an immediate disconnect,
+ *
+ */
+
+static int should_disconnect (unsigned char cmd) {
+ switch (cmd) {
+ case READ_6:
+ case WRITE_6:
+ case SEEK_6:
+ case READ_10:
+ case WRITE_10:
+ case SEEK_10:
+ return DISCONNECT_TIME_TO_DATA;
+ case FORMAT_UNIT:
+ case SEARCH_HIGH:
+ case SEARCH_LOW:
+ case SEARCH_EQUAL:
+ return DISCONNECT_LONG;
+ default:
+ return DISCONNECT_NONE;
+ }
+}
+
+/*
+ * Assumes instance->time_expires has been set in higher level code.
+ */
+
+static int NCR5380_set_timer (struct Scsi_Host *instance) {
+ struct Scsi_Host *tmp, **prev;
+
+ cli();
+ if (((struct NCR5380_hostdata *) (instance->host_data))->next_timer) {
+ sti();
+ return -1;
+ }
+
+ for (prev = &expires_first, tmp = expires_first; tmp;
+ prev = &(((struct NCR5380_hostdata *) tmp->host_data)->next_timer),
+ tmp = ((struct NCR5380_hostdata *) tmp->host_data)->next_timer)
+ if (instance->time_expires < tmp->time_expires)
+ break;
+
+ instance->next_timer = tmp;
+ *prev = instance;
+ timer_table[NCR5380_TIMER].expires = expires_first->time_expires;
+ timer_active |= 1 << NCR5380_TIMER;
+ sti;
+ return 0;
+}
+
+/* Doing something about unwanted rentrancy here might be useful */
+void NCR5380_timer_fn(void) {
+ struct Scsi_Host *instance;
+ cli();
+ for (; expires_first && expires_first->time_expires >= jiffies; ) {
+ instance = ((NCR5380_hostdata *) expires_first->host_data)->
+ expires_next;
+ ((NCR5380_hostdata *) expires_first->host_data)->expires_next =
+ NULL;
+ ((NCR5380_hostdata *) expires_first->host_data)->time_expires =
+ 0;
+ expires_first = instance;
+ }
+
+ if (expires_first) {
+ timer_table[NCR5380_TIMER].expires = ((NCR5380_hostdata *)
+ expires_first->host_data)->time_expires;
+ timer_active |= (1 << NCR5380_TIMER);
+ } else {
+ timer_table[NCR5380_TIMER].expires = 0;
+ timer_active &= ~(1 << MCR5380_TIMER);
+ }
+ sti();
+
+ run_main();
+}
+#endif /* def USLEEP */
+
+static void NCR5380_all_init (void) {
+ static int done = 0;
+ if (!done) {
+#if (NDEBUG & NDEBUG_INIT)
+ printk("scsi : NCR5380_all_init()\n");
+#endif
+ done = 1;
+#ifdef USLEEP
+ timer_table[NCR5380_TIMER].expires = 0;
+ timer_table[NCR5380_TIMER].fn = NCR5380_timer_fn;
+#endif
+ }
+}
+
+#ifdef AUTOPROBE_IRQ
+/*
+ * Function : int NCR5380_probe_irq (struct Scsi_Host *instance, int possible)
+ *
+ * Purpose : autoprobe for the IRQ line used by the NCR5380.
+ *
+ * Inputs : instance - pointer to this instance of the NCR5380 driver,
+ * possible - bitmask of permissable interrupts.
+ *
+ * Returns : number of the IRQ selected, IRQ_NONE if no interrupt fired.
+ *
+ * XXX no effort is made to deal with spurious interrupts.
+ */
+
+
+static int probe_irq;
+static void probe_intr (int sig) {
+ probe_irq = sig;
+};
+static struct sigaction probe_sigaction = { probe_intr, 0, SA_INTERRUPT,
+ NULL};
+
+static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible) {
+ NCR5380_local_declare();
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+ instance->hostdata;
+ unsigned long timeout;
+ int trying_irqs, i, mask;
+ NCR5380_setup(instance);
+
+ for (trying_irqs = i = 0, mask = 1; i < 16; ++i, mask <<= 1)
+ if ((mask & possible) && (irqaction (i, &probe_sigaction)
+ == 0))
+ trying_irqs |= mask;
+
+ timeout = jiffies + 25;
+ probe_irq = IRQ_NONE;
+
+/*
+ * A interrupt is triggered whenever BSY = false, SEL = true
+ * and a bit set in the SELECT_ENABLE_REG is asserted on the
+ * SCSI bus.
+ *
+ * Note that the bus is only driven when the phase control signals
+ * (I/O, C/D, and MSG) match those in the TCR, so we must reset that
+ * to zero.
+ */
+
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_SEL);
+
+ while (probe_irq == IRQ_NONE && jiffies < timeout);
+
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ for (i = 0, mask = 1; i < 16; ++i, mask <<= 1)
+ if (trying_irqs & mask)
+ free_irq(i);
+
+ return probe_irq;
+}
+#endif /* AUTOPROBE_IRQ */
+
+/*
+ * Function : void NCR58380_print_options (struct Scsi_Host *instance)
+ *
+ * Purpose : called by probe code indicating the NCR5380 driver
+ * options that were selected.
+ *
+ * Inputs : instance, pointer to this instance. Unused.
+ */
+
+static void NCR5380_print_options (struct Scsi_Host *instance) {
+ printk(" generic options"
+#ifdef AUTOPROBE_IRQ
+ " AUTOPROBE_IRQ"
+#endif
+#ifdef AUTOSENSE
+ " AUTOSENSE"
+#endif
+#ifdef DIFFERENTIAL
+ " DIFFERENTIAL"
+#endif
+#ifdef REALDMA
+ " REAL DMA"
+#endif
+#ifdef PARITY
+ " PARITY"
+#endif
+#ifdef PSEUDO_DMA
+ " PSEUDO DMA"
+#endif
+#ifdef SCSI2
+ " SCSI-2"
+#endif
+#ifdef UNSAFE
+ " UNSAFE "
+#endif
+ );
+#ifdef USLEEP
+ printk(" USLEEP, USLEEP_POLL=%d USLEEP_SLEEP=%d", USLEEP_POLL, USLEEP_SLEEP);
+#endif
+ printk(" generic release=%d", NCR5380_PUBLIC_RELEASE);
+}
+
+
+/*
+ * Function : void NCR5380_init (struct Scsi_Host *instance)
+ *
+ * Purpose : initializies *instance and corresponding 5380 chip.
+ *
+ * Inputs : instance - instantiation of the 5380 driver.
+ *
+ * Notes : I assume that the host, hostno, and id bits have been
+ * set correctly. I don't care about the irq and other fields.
+ *
+ */
+
+static void NCR5380_init (struct Scsi_Host *instance) {
+ NCR5380_local_declare();
+ int i;
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+ instance->hostdata;
+ NCR5380_setup(instance);
+
+ NCR5380_all_init();
+
+ hostdata->id_mask = 1 << instance->this_id;
+ for (i = hostdata->id_mask; i <= 0x80; i <<= 1)
+ if (i > hostdata->id_mask)
+ hostdata->id_higher_mask |= i;
+ for (i = 0; i < 8; ++i)
+ hostdata->busy[i] = 0;
+#ifdef REAL_DMA
+ hostdata->dmalen = 0;
+#endif
+ hostdata->connected = NULL;
+ hostdata->issue_queue = NULL;
+ hostdata->disconnected_queue = NULL;
+
+ if (!the_template) {
+ the_template = instance->hostt;
+ first_instance = instance;
+ }
+
+
+#ifdef USLEEP
+ hostdata->time_expires = 0;
+ hostdata->next_timer = NULL;
+#endif
+
+#ifndef AUTOSENSE
+ if ((instance->cmd_per_lun > 1) || instance->can_queue > 1))
+ printk("scsi%d : WARNING : support for multiple outstanding commands enabled\n"
+ " without AUTOSENSE option, contigent alligence conditions may\n"
+ " be incorrectly cleared.\n", instance->host_no);
+#endif /* def AUTOSENSE */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+}
+
+/*
+ * Function : int NCR5380_queue_command (Scsi_Cmnd *cmd,
+ * void (*done)(Scsi_Cmnd *))
+ *
+ * Purpose : enqueues a SCSI command
+ *
+ * Inputs : cmd - SCSI command, done - function called on completion, with
+ * a pointer to the command descriptor.
+ *
+ * Returns : 0
+ *
+ * Side effects :
+ * cmd is added to the per instance issue_queue, with minor
+ * twiddling done to the host specific fields of cmd. If the
+ * main coroutine is not running, it is restarted.
+ *
+ */
+
+/* Only make static if a wrapper function is used */
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) {
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+ cmd->host->hostdata;
+ Scsi_Cmnd *tmp;
+
+#if (NDEBUG & NDEBUG_NO_WRITE)
+ switch (cmd->cmnd[0]) {
+ case WRITE:
+ case WRITE_10:
+ printk("scsi%d : WRITE attempted with NO_WRITE debugging flag set\n",
+ instance->host_no);
+ cmd->result = (DID_ERROR << 16);
+ done(cmd);
+ return 0;
+ }
+#endif /* (NDEBUG & NDEBUG_NO_WRITE) */
+
+
+ /*
+ * We use the host_scribble field as a pointer to the next command
+ * in a queue
+ */
+
+ cmd->host_scribble = NULL;
+ cmd->scsi_done = done;
+
+ cmd->result = 0;
+
+
+ /*
+ * Insert the cmd into the issue queue. Note that REQUEST SENSE
+ * commands are added to the head of the queue since any command will
+ * clear the contingent allegience condition that exists and the
+ * sense data is only guranteed to be valid while the condition exists.
+ */
+
+ cli();
+ if (!(hostdata->issue_queue) || (cmd->cmnd[0] == REQUEST_SENSE)) {
+ cmd->host_scribble = (unsigned char *) hostdata->issue_queue;
+ hostdata->issue_queue = cmd;
+ } else {
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue; tmp->host_scribble;
+ tmp = (Scsi_Cmnd *) tmp->host_scribble);
+ tmp->host_scribble = (unsigned char *) cmd;
+ }
+#if (NDEBUG & NDEBUG_QUEUES)
+ printk("scsi%d : command added to %s of queue\n", instance->host_no,
+ (cmd->cmnd[0] == REQUEST_SENSE) ? "head" : "tail");
+#endif
+
+/* Run the coroutine if it isn't allready running. */
+ run_main();
+ return 0;
+}
+
+/*
+ * Function : NCR5380_main (void)
+ *
+ * Purpose : NCR5380_main is a corroutine that runs as long as more work can
+ * be done on the NCR5380 host adapters in a system. Both
+ * NCR5380_queue_command() and NCR5380_intr() will try to start it
+ * in case it is not running.
+ *
+ * NOTE : NCR5380_main exits with interrupts *disabled*, the caller should
+ * reenable them. This prevents rentrancy and kernel stack overflow.
+ */
+
+static void NCR5380_main (void) {
+ Scsi_Cmnd *tmp, *prev;
+ struct Scsi_Host *instance;
+ struct NCR5380_hostdata *hostdata;
+ int done;
+
+ /*
+ * We run (with interrupts disabled) until we're sure that none of
+ * the host adapters have anything that can be done, at which point
+ * we set main_running to 0 and exit.
+ *
+ * Interrupts are enabled before doing various other internal
+ * instructions, after we've decided that we need to run through
+ * the loop again.
+ *
+ * this should prevent any race conditions.
+ */
+
+ do {
+ cli(); /* Freeze request queues */
+ done = 1;
+ for (instance = first_instance; instance && instance->hostt == the_template;
+ instance=instance->next) {
+ hostdata = (struct NCR5380_hostdata *) instance->hostdata;
+ cli();
+ if (!hostdata->connected) {
+#if (NDEBUG & NDEBUG_MAIN)
+ printk("scsi%d : not connected\n", instance->host_no);
+#endif
+ /*
+ * Search through the issue_queue for a command destined
+ * for a target that's not busy.
+ */
+ for (tmp = (Scsi_Cmnd *) hostdata->issue_queue,
+ prev = NULL; tmp; prev = tmp, tmp = (Scsi_Cmnd *)
+ tmp->host_scribble)
+
+ /* When we find one, remove it from the issue queue. */
+ if (!(hostdata->busy[tmp->target] & (1 << tmp->lun))) {
+ if (prev)
+ prev->host_scribble = tmp->host_scribble;
+ else
+ hostdata->issue_queue = (Scsi_Cmnd *) tmp->host_scribble;
+ tmp->host_scribble = NULL;
+
+ /* renable interrupts after finding one */
+ sti();
+
+ /*
+ * Attempt to establish an I_T_L nexus here.
+ * On success, instance->hostdata->connected is set.
+ * On failure, we must add the command back to the
+ * issue queue so we can keep trying.
+ */
+#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
+ printk("scsi%d : main() : command for target %d lun %d removed from issue_queue\n",
+ instance->host_no, tmp->target, tmp->lun);
+#endif
+ /*
+ * REQUEST SENSE commands are issued without tagged
+ * queueing, even on SCSI-II devices because the
+ * contingent alligence condition exists for the
+ * entire unit.
+ */
+
+ if (!NCR5380_select(instance, tmp,
+ (tmp->cmnd[0] == REQUEST_SENSE) ? TAG_NONE :
+ TAG_NEXT)) {
+ break;
+ } else {
+ cli();
+ tmp->host_scribble = (unsigned char *)
+ hostdata->issue_queue;
+ hostdata->issue_queue = tmp;
+ sti();
+#if (NDEBUG & (NDEBUG_MAIN | NDEBUG_QUEUES))
+ printk("scsi%d : main(): select() failed, returned to issue_queue\n",
+ instance->host_no);
+#endif
+ }
+ } /* if target/lun is not busy */
+ } /* if (!hostdata->connected) */
+
+ if (hostdata->connected
+#ifdef REAL_DMA
+ && !hostdata->dmalen
+#endif
+#ifdef USLEEP
+ && (!hostdata->time_expires || hostdata->time_expires >= jiffies)
+#endif
+ ) {
+ sti();
+#if (NDEBUG & NDEBUG_MAIN)
+ printk("scsi%d : main() : performing information transfer\n",
+ instance->host_no);
+#endif
+ NCR5380_information_transfer(instance);
+#if (NDEBUG & NDEBUG_MAIN)
+ printk("scsi%d : main() : done set false\n", instance->host_no);
+#endif
+ done = 0;
+ } else
+ break;
+ } /* for instance */
+ } while (!done);
+ main_running = 0;
+}
+
+/*
+ * Function : void NCR5380_intr (int irq)
+ *
+ * Purpose : handle interrupts, restablishing I_T_L or I_T_L_Q nexuses
+ * from the disconnected queue, and restarting NCR5380_main()
+ * as required.
+ *
+ * Inputs : int irq, irq that caused this interrupt.
+ *
+ */
+
+static void NCR5380_intr (int irq) {
+ NCR5380_local_declare();
+ struct Scsi_Host *instance;
+ int done;
+#if (NDEBUG & NDEBUG_INTR)
+ printk("scsi : NCR5380 irq %d triggered\n", irq);
+#endif
+ do {
+ done = 1;
+ for (instance = first_instance; instance && (instance->hostt ==
+ the_template); instance = instance->next)
+ if (instance->irq == irq) {
+
+ /* Look for pending interrupts */
+ NCR5380_setup(instance);
+ /* XXX dispatch to appropriate routine if found and done=0 */
+ if (NCR5380_read(BUS_AND_STATUS_REG) & BASR_IRQ) {
+#if (NDEBUG & NDEBUG_INTR)
+ NCR5380_print(instance);
+#endif
+ if ((NCR5380_read(STATUS_REG) & (SR_SEL | SR_IO)) ==
+ (SR_SEL | SR_IO)) {
+ done = 0;
+ sti();
+#if (NDEBUG & NDEBUG_INTR)
+ printk("scsi%d : SEL interrupt\n", instance->host_no);
+#endif
+ NCR5380_reselect(instance);
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else if (NCR5380_read(BUS_AND_STATUS_REG) &
+ BASR_PARITY_ERROR) {
+#if (NDEBUG & NDEBUG_INTR)
+ printk("scsi%d : PARITY interrupt\n", instance->host_no);
+#endif
+ (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG);
+ } else {
+/*
+ * XXX the rest of the interrupt conditions should *only* occur during a
+ * DMA transfer, which I haven't gotten arround to fixing yet.
+ */
+
+#if defined(REAL_DMA)
+#else
+#if (NDEBUG & NDEBUG_INTR)
+ printk("scsi : unknown interrupt\n");
+#endif
+#endif
+ }
+ } /* if BASR_IRQ */
+ if (!done)
+ run_main();
+ } /* if (instance->irq == irq) */
+ } while (!done);
+}
+
+/*
+ * Function : int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+ * int tag);
+ *
+ * Purpose : establishes I_T_L or I_T_L_Q nexus for new or existing command,
+ * including ARBITRATION, SELECTION, and initial message out for
+ * IDENTIFY and queue messages.
+ *
+ * Inputs : instance - instantiation of the 5380 driver on which this
+ * target lives, cmd - SCSI command to execute, tag - set to TAG_NEXT for
+ * new tag, TAG_NONE for untagged queueing, otherwise set to the tag for
+ * the command that is presently connected.
+ *
+ * Returns : -1 if selection could not execute for some reason,
+ * 0 if selection succeeeded or failed because the target
+ * did not respond.
+ *
+ * Side effects :
+ * If bus busy, arbitration failed, etc, NCR5380_select() will exit
+ * with registers as they should have been on entry - ie
+ * SELECT_ENABLE will be set appropriately, the NCR5380
+ * will cease to drive any SCSI bus signals.
+ *
+ * If successful : I_T_L or I_T_L_Q nexus will be established,
+ * instance->connected will be set to cmd.
+ * SELECT interrupt will be disabled.
+ *
+ * If failed (no target) : cmd->scsi_done() will be called, and the
+ * cmd->result host byte set to DID_BAD_TARGET.
+ */
+
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd,
+ int tag) {
+ NCR5380_local_declare();
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata*)
+ instance->hostdata;
+ unsigned char tmp[3], phase;
+ unsigned char *data;
+ int len;
+ unsigned long timeout;
+ NCR5380_setup(instance);
+
+#if defined (NDEBUG) && (NDEBUG & NDEBUG_ARBITRATION)
+ NCR5380_print(instance);
+ printk("scsi%d : starting arbitration, id = %d\n", instance->host_no,
+ instance->this_id);
+#endif
+
+ /*
+ * Set the phase bits to 0, otherwise the NCR5380 won't drive the
+ * data bus during SELECTION.
+ */
+
+ NCR5380_write(TARGET_COMMAND_REG, 0);
+
+ /* Start arbitration */
+ NCR5380_write(OUTPUT_DATA_REG, hostdata->id_mask);
+ NCR5380_write(MODE_REG, MR_ARBITRATE);
+
+ /* Wait for arbitration logic to complete */
+ while (!(NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_PROGRESS));
+
+#if (NDEBUG & NDEBUG_ARBITRATION)
+ printk("scsi%d : arbitration complete\n", instance->host_no);
+/* Avoid GCC 2.4.5 asm needs to many reloads error */
+ __asm__("nop");
+#endif
+
+ /*
+ * The arbitration delay is 2.2us, but this is a minimum and there is
+ * no maximum so we can safely sleep for ceil(2.2) usecs to accomodate
+ * the integral nature of udelay().
+ *
+ */
+
+ udelay(3);
+
+ /* Check for lost arbitration */
+ if ((NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) ||
+ (NCR5380_read(CURRENT_SCSI_DATA_REG) & hostdata->id_higher_mask) ||
+ (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST)) {
+ NCR5380_write(MODE_REG, MR_BASE);
+#if (NDEBUG & NDEBUG_ARBITRATION)
+ printk("scsi%d : lost arbitration, deasserting MR_ARBITRATE\n",
+ instance->host_no);
+#endif
+ return -1;
+ }
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_SEL);
+
+ if (NCR5380_read(INITIATOR_COMMAND_REG) & ICR_ARBITRATION_LOST) {
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+#if (NDEBUG & NDEBUG_ARBITRATION)
+ printk("scsi%d : lost arbitration, deasserting ICR_ASSERT_SEL\n",
+ instance->host_no);
+#endif
+ return -1;
+ }
+
+ /*
+ * Again, bus clear + bus settle time is 1.2us, however, this is
+ * a minimum so we'll udelay ceil(1.2)
+ */
+
+ udelay(2);
+
+#if (NDEBUG & NDEBUG_ARBITRATION)
+ printk("scsi%d : won arbitration\n", instance->host_no);
+#endif
+
+ /*
+ * Now that we have won arbitration, start Selection process, asserting
+ * the host and target ID's on the SCSI bus.
+ */
+
+ NCR5380_write(OUTPUT_DATA_REG, (hostdata->id_mask | (1 << cmd->target)));
+
+ /*
+ * Raise ATN while SEL is true before BSY goes false from arbitration,
+ * since this is the only way to gurantee that we'll get a MESSAGE OUT
+ * phase immediately after selection.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_BSY |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_SEL ));
+ NCR5380_write(MODE_REG, MR_BASE);
+
+ /*
+ * Reselect interrupts must be turned off prior to the dropping of BSY,
+ * otherwise we will trigger an interrupt.
+ */
+ NCR5380_write(SELECT_ENABLE_REG, 0);
+
+ /* Reset BSY */
+ NCR5380_write(INITIATOR_COMMAND_REG, (ICR_BASE | ICR_ASSERT_DATA |
+ ICR_ASSERT_ATN | ICR_ASSERT_SEL));
+
+ /*
+ * Something wierd happens when we cease to drive BSY - looks
+ * like the board/chip is letting us do another read before the
+ * appropriate propogation delay has expired, and we're confusing
+ * a BSY signal from ourselves as the target's response to SELECTION.
+ *
+ * A small delay (the 'C++' frontend breaks the pipeline with an
+ * unecessary jump, making it work on my 386-33/Trantor T128, the
+ * tighter 'C' code breaks and requires this) solves the problem -
+ * the 1 us delay is arbitrary, and only used because this delay will
+ * be the same on other platforms and since it works here, it should
+ * work there.
+ */
+
+ udelay(1);
+
+#if (NDEBUG & NDEBUG_SELECTION)
+ printk("scsi%d : selecting target %d\n", instance->host_no, cmd->target);
+#endif
+
+ /*
+ * The SCSI specification calls for a 250 ms timeout for the actual
+ * selection.
+ */
+
+ timeout = jiffies + 25;
+
+ /*
+ * XXX very interesting - we're seeing a bounce where the BSY we
+ * asserted is being reflected / still asserted (propogation delay?)
+ * and it's detecting as true. Sigh.
+ */
+
+ while ((jiffies < timeout) && !(NCR5380_read(STATUS_REG) & SR_BSY));
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+
+ if (!(NCR5380_read(STATUS_REG) & SR_BSY)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ cmd->result = DID_BAD_TARGET << 16;
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+#if (NDEBUG & NDEBUG_SELECTION)
+ printk("scsi%d : target did not respond within 250ms\n",
+ instance->host_no);
+#endif
+ return 0;
+ }
+
+ /*
+ * Since we followed the SCSI spec, and raised ATN while SEL
+ * was true but before BSY was false during selection, the information
+ * transfer phase should be a MESSAGE OUT phase so that we can send the
+ * IDENTIFY message.
+ *
+ * If SCSI-II tagged queing is enabled, we also send a SIMPLE_QUEUE_TAG
+ * message (2 bytes) with a tag ID that we increment with every command
+ * until it wraps back to 0.
+ *
+ * XXX - it turns out that there are some broken SCSI-II devices,
+ * which claim to support tagged queing but fail when more than
+ * some number of commands are issued at once.
+ */
+
+ /* Wait for start of REQ/ACK handshake */
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+#if (NDEBUG & NDEBUG_SELECTION)
+ printk("scsi%d : target %d selected, going into MESSAGE OUT phase.\n",
+ instance->host_no, cmd->target);
+#endif
+ tmp[0] = IDENTIFY(((instance->irq == IRQ_NONE) ? 0 : 1), cmd->lun);
+#ifdef SCSI2
+ if (scsi_devices[cmd->index].tagged_queue && (tag != TAG_NONE)) {
+ tmp[1] = SIMPLE_QUEUE_TAG;
+ if (tag == TAG_NEXT) {
+ /* 0 is TAG_NONE, used to imply no tag for this command */
+ if (scsi_devices[cmd->index].current_tag == 0)
+ scsi_devices[cmd->index].current_tag = 1;
+
+ cmd->tag = scsi_devices[cmd->index].current_tag;
+ scsi_devices[cmd->index].current_tag++;
+ } else
+ cmd->tag = (unsigned char) tag;
+
+ tmp[2] = cmd->tag;
+ hostdata->last_message = SIMPLE_QUEUE_TAG;
+ len = 3;
+ } else
+#endif /* def SCSI2 */
+ {
+ len = 1;
+ cmd->tag=0;
+ }
+
+ /* Send message(s) */
+ data = tmp;
+ phase = PHASE_MSGOUT;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+#if (NDEBUG & NDEBUG_SELECTION)
+ printk("scsi%d : nexus established.\n", instance->host_no);
+#endif
+ /* XXX need to handle errors here */
+ hostdata->connected = cmd;
+#ifdef SCSI2
+ if (!scsi_devices[cmd->index].tagged_queue)
+#endif
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+
+ initialize_SCp(cmd);
+
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using polled I/O
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
+ * Returns : -1 when different phase is enterred without transfering
+ * maximum number of bytes, 0 if all bytes or transfered or exit
+ * is in same phase.
+ *
+ * Also, *phase, *count, *data are modified in place.
+ *
+ * XXX Note : handling for bus free may be useful.
+ */
+
+/*
+ * Note : this code is not as quick as it could be, however it
+ * IS 100% reliable, and for the actual data transfer where speed
+ * counts, we will always do a pseudo DMA or DMA transfer.
+ */
+
+static int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ unsigned char *phase, int *count, unsigned char **data) {
+ NCR5380_local_declare();
+ register unsigned char p = *phase, tmp;
+ register int c = *count;
+ register unsigned char *d = *data;
+ NCR5380_setup(instance);
+
+ /*
+ * The NCR5380 chip will only drive the SCSI bus when the
+ * phase specified in the appropriate bits of the TARGET COMMAND
+ * REGISTER match the STATUS REGISTER
+ */
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+ do {
+ /*
+ * Wait for assertion of REQ, after which the phase bits will be
+ * valid
+ */
+ while (!((tmp = NCR5380_read(STATUS_REG)) & SR_REQ));
+
+#if (NDEBUG & NDEBUG_HANDSHAKE)
+ printk("scsi%d : REQ detected\n", instance->host_no);
+#endif
+
+ /* Check for phase mismatch */
+ if ((tmp & PHASE_MASK) != p) {
+#if (NDEBUG & NDEBUG_PIO)
+ printk("scsi%d : phase mismatch\n", instance->host_no);
+ NCR5380_print_phase(instance);
+#endif
+ break;
+ }
+
+ /* Do actual transfer from SCSI bus to / from memory */
+ if (!(p & SR_IO))
+ NCR5380_write(OUTPUT_DATA_REG, *d);
+ else
+ *d = NCR5380_read(CURRENT_SCSI_DATA_REG);
+
+ ++d;
+
+ /*
+ * The SCSI standard suggests that in MSGOUT phase, the initiator
+ * should drop ATN on the last byte of the message phase
+ * after REQ has been asserted for the handshake but before
+ * the initiator raises ACK.
+ */
+
+ if (!(p & SR_IO)) {
+ if (!((p & SR_MSG) && c > 1)) {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA);
+#if (NDEBUG & NDEBUG_PIO)
+ NCR5380_print(instance);
+#endif
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ACK);
+ } else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN);
+#if (NDEBUG & NDEBUG_PIO)
+ NCR5380_print(instance);
+#endif
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_DATA | ICR_ASSERT_ATN | ICR_ASSERT_ACK);
+ }
+ } else {
+#if (NDEBUG & NDEBUG_PIO)
+ NCR5380_print(instance);
+#endif
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ACK);
+ }
+
+ while (NCR5380_read(STATUS_REG) & SR_REQ);
+
+#if (NDEBUG & NDEBUG_HANDSHAKE)
+ printk("scsi%d : req false, handshake complete\n", instance->host_no);
+#endif
+
+ if (!(p == PHASE_MSGOUT && c > 1))
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ else
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ } while (--c);
+
+#if (NDEBUG & NDEBUG_PIO)
+ printk("scsi%d : residual %d\n", instance->host_no, c);
+#endif
+
+ *count = c;
+ *data = d;
+ tmp = NCR5380_read(STATUS_REG);
+ if (tmp & SR_REQ)
+ *phase = tmp & PHASE_MASK;
+ else
+ *phase = PHASE_UNKNOWN;
+
+ if (!c || (*phase == p))
+ return 0;
+ else
+ return -1;
+}
+
+#if defined(REAL_DMA) | defined(PSEUDO_DMA)
+/*
+ * Function : int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ * unsigned char *phase, int *count, unsigned char **data)
+ *
+ * Purpose : transfers data in given phase using either real
+ * or pseudo DMA.
+ *
+ * Inputs : instance - instance of driver, *phase - pointer to
+ * what phase is expected, *count - pointer to number of
+ * bytes to transfer, **data - pointer to data pointer.
+ *
+ * Returns : -1 when different phase is enterred without transfering
+ * maximum number of bytes, 0 if all bytes or transfered or exit
+ * is in same phase.
+ *
+ * Also, *phase, *count, *data are modified in place.
+ *
+ */
+
+
+static int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ unsigned char *phase, int *count, unsigned char **data) {
+ NCR5380_local_declare();
+ register int c = *count;
+ register unsigned char p = *phase;
+ register unsigned char *d = *data;
+ unsigned char tmp;
+ int foo;
+ NCR5380_setup(instance);
+
+#ifdef REAL_DMA
+ instance->dmalen = c;
+ if (p & SR_IO)
+ NCR5380_dma_read_setup(d, c);
+ else
+ NCR5380_dma_write_setup(d, c);
+#endif
+
+
+ if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) {
+ *phase = tmp;
+ return -1;
+ }
+
+ NCR5380_write(TARGET_COMMAND_REG, PHASE_SR_TO_TCR(p));
+
+#ifdef REAL_DMA
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE | MR_ENABLE_EOP_INTR | MR_MONITOR_BSY);
+#else
+ /*
+ * Note : on my sample board, watch-dog timeouts occured when interrupts
+ * were not disabled for the duration of a single DMA transfer, from
+ * before the setting of DMA mode to after transfer of the last byte.
+ */
+
+#ifndef UNSAFE
+ cli();
+#endif
+ NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE);
+#endif
+
+ if (p & SR_IO)
+ NCR5380_write(START_DMA_INITIATOR_RECIEVE_REG, 0);
+ else {
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_DATA);
+ NCR5380_write(START_DMA_SEND_REG, 0);
+ }
+
+#ifdef REAL_DMA
+ return 0;
+#else
+ foo = ((p & SR_IO) ? NCR5380_pread(instance, d, c) :
+ NCR5380_pwrite(instance, d, c));
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ *data = d + c;
+ *count = 0;
+ *phase = (NCR5380_read(STATUS_REG & PHASE_MASK));
+#ifndef UNSAFE
+ sti();
+#endif
+ return foo;
+#endif /* def REAL_DMA */
+}
+#endif /* defined(REAL_DMA) | defined(PSEUDO_DMA) */
+
+/*
+ * Function : NCR5380_information_transfer (struct Scsi_Host *instance)
+ *
+ * Purpose : run through the various SCSI phases and do as the target
+ * directs us to. Operates on the currently connected command,
+ * instance->connected.
+ *
+ * Inputs : instance, instance for which we are doing commands
+ *
+ * Side effects : SCSI things happen, the disconnected queue will be
+ * modified if a command disconnects, *instance->connected will
+ * change.
+ *
+ * XXX Note : we need to watch for bus free or a reset condition here
+ * to recover from an unexpected bus free condition.
+ */
+
+static void NCR5380_information_transfer (struct Scsi_Host *instance) {
+ NCR5380_local_declare();
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+ instance->hostdata;
+ unsigned char msgout = NOP;
+ int len;
+ unsigned char *data;
+ unsigned char phase, tmp, old_phase=0xff;
+ Scsi_Cmnd *cmd = (Scsi_Cmnd *) hostdata->connected;
+ NCR5380_setup(instance);
+
+ while (1) {
+ tmp = NCR5380_read(STATUS_REG);
+ /* We only have a valid SCSI phase when REQ is asserted */
+ if (tmp & SR_REQ) {
+ phase = (tmp & PHASE_MASK);
+ if (phase != old_phase) {
+ old_phase = phase;
+#if (NDEBUG & NDEBUG_INFORMATION)
+ NCR5380_print_phase(instance);
+#endif
+ }
+ switch (phase) {
+ case PHASE_DATAIN:
+ case PHASE_DATAOUT:
+#if (NDEBUG & NDEBUG_NO_DATAOUT)
+ printk("scsi%d : NDEBUG_NO_DATAOUT set, attempted DATAOUT aborted\n",
+ instance->host_no);
+ msgout = ABORT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ break;
+#endif
+ /*
+ * If there is no room left in the current buffer in the
+ * scatter-gather list, move onto the next one.
+ */
+
+ if (!cmd->SCp.this_residual && cmd->SCp.buffers_residual) {
+ ++cmd->SCp.buffer;
+ --cmd->SCp.buffers_residual;
+ cmd->SCp.this_residual = cmd->SCp.buffer->length;
+ cmd->SCp.ptr = cmd->SCp.buffer->address;
+#if (NDEBUG & NDEBUG_INFORMATION)
+ printk("scsi%d : %d bytes and %d buffers left\n",
+ instance->host_no, cmd->SCp.this_residual,
+ cmd->SCp.buffers_residual);
+#endif
+ }
+
+ /*
+ * The preffered transfer method is going to be
+ * PSEUDO-DMA for systems that are strictly PIO,
+ * since we can let the hardware do the handshaking.
+ *
+ * For this to work, we need to know the transfersize
+ * ahead of time, since the pseudo-DMA code will sit
+ * in an unconditional loop.
+ */
+
+#if (defined(PSEUDO_DMA))
+ if (!scsi_devices[cmd->index].borken && cmd->transfersize &&
+ cmd->SCp.this_residual && !(cmd->SCp.this_residual %
+ cmd->transfersize)) {
+ len = cmd->transfersize;
+ if (NCR5380_transfer_dma(instance, &phase,
+ &len, (unsigned char **) &cmd->SCp.ptr)) {
+ /*
+ * If the watchdog timer fires, all future accesses to this
+ * device will use the polled-IO.
+ */
+ printk("scsi%d : switching target %d lun %d to slow handshake\n",
+ instance->host_no, cmd->target, cmd->lun);
+ scsi_devices[cmd->index].borken = 1;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ msgout = ABORT;
+ } else
+ cmd->SCp.this_residual -= cmd->transfersize;
+ } else
+#endif /* (defined(REAL_DMA) || defined(PSEUDO_DMA)) */
+ NCR5380_transfer_pio(instance, &phase,
+ (int *) &cmd->SCp.this_residual, (unsigned char **)
+ &cmd->SCp.ptr);
+ break;
+ case PHASE_MSGIN:
+ /*
+ * XXX - we don't handle multi-byte messages here, since we
+ * shouldn't get them after the I_T_L_Q nexus is established
+ * for tagged queuing, and the host should initiate any
+ * negotiations for sync. SCSI, etc.
+ */
+
+ len = 1;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Message = tmp;
+
+ switch (tmp) {
+ /*
+ * Linking lets us reduce the time required to get the
+ * next command out to the device, hopefully this will
+ * mean we don't waste another revolution due to the delays
+ * required by ARBITRATION and another SELECTION.
+ *
+ * In the current implementation proposal, low level drivers
+ * merely have to start the next command, pointed to by
+ * next_link, done() is called as with unlinked commands.
+ */
+#ifdef LINKED
+ case LINKED_CMD_COMPLETE:
+ case LINKED_FLG_CMD_COMPLETE:
+#if (NDEBUG & NDEBUG_LINKED)
+ printk("scsi%d : target %d lun %d linked command complete.\n",
+ instance->host_no, cmd->target, cmd->lun);
+#endif
+ /*
+ * Sanity check : A linked command should only terminate with
+ * one of these messages if there are more linked commands
+ * available.
+ */
+
+ if (!cmd->next_link) {
+ printk("scsi%d : target %d lun %d linked command complete, no next_link\n"
+ instance->host_no, cmd->target, cmd->lun);
+ msgout = ABORT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+ break;
+ }
+
+ initialize_SCp(cmd->next_link);
+ /* The next command is still part of this process */
+ cmd->next_link->tag = cmd->tag;
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+#if (NDEBUG & NDEBUG_LINKED)
+ printk("scsi%d : target %d lun %d linked request done, calling scsi_done().\n",
+ instance->host_no, cmd->target, cmd->lun);
+#endif
+ cmd->scsi_done(cmd);
+ cmd = hostdata->connected;
+ break;
+#endif /* def LINKED */
+ case ABORT:
+ case COMMAND_COMPLETE:
+ hostdata->connected = NULL;
+#if (NDEBUG & NDEBUG_QUEUES)
+ printk("scsi%d : command for target %d, lun %d completed\n",
+ instance->host_no, cmd->target, cmd->lun);
+#endif
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+
+ /*
+ * Use the status and message bytes from the original
+ * command.
+ */
+
+ if (cmd->cmnd[0] != REQUEST_SENSE)
+ cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8);
+ else if (cmd->SCp.Status != GOOD)
+ cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16);
+#ifdef AUTOSENSE
+ if ((cmd->cmnd[0] != REQUEST_SENSE) &&
+ (cmd->SCp.Status == CHECK_CONDITION)) {
+#if (NDEBUG & NDEBUG_AUTOSENSE)
+ printk("scsi%d : performing request sense\n",
+ instance->host_no);
+#endif
+ cmd->cmnd[0] = REQUEST_SENSE;
+ cmd->cmnd[1] &= 0xe0;
+ cmd->cmnd[2] = 0;
+ cmd->cmnd[3] = 0;
+ cmd->cmnd[4] = sizeof(cmd->sense_buffer);
+ cmd->cmnd[5] = 0;
+
+ cmd->SCp.buffer = NULL;
+ cmd->SCp.buffers_residual = 0;
+ cmd->SCp.ptr = (char *) cmd->sense_buffer;
+ cmd->SCp.this_residual = sizeof(cmd->sense_buffer);
+
+ cli();
+ cmd->host_scribble = (unsigned char *)
+ hostdata->issue_queue;
+ hostdata->issue_queue = (Scsi_Cmnd *) cmd;
+ sti();
+#if (NDEBUG & NDEBUG_QUEUES)
+ printk("scsi%d : REQUEST SENSE added to head of issue queue\n");
+#endif
+ } else
+#endif /* def AUTOSENSE */
+ cmd->scsi_done(cmd);
+
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ case MESSAGE_REJECT:
+ switch (hostdata->last_message) {
+ case HEAD_OF_QUEUE_TAG:
+ case ORDERED_QUEUE_TAG:
+ case SIMPLE_QUEUE_TAG:
+ scsi_devices[cmd->index].tagged_queue = 0;
+ hostdata->busy[cmd->target] |= (1 << cmd->lun);
+ break;
+ default:
+ break;
+ }
+ case DISCONNECT:
+ scsi_devices[cmd->index].disconnect = 1;
+ cli();
+ cmd->host_scribble = (unsigned char *)
+ hostdata->disconnected_queue;
+ hostdata->connected = NULL;
+ hostdata->disconnected_queue = cmd;
+ sti();
+#if (NDEBUG & NDEBUG_QUEUES)
+ printk("scsi%d : command for target %d lun %d was moved from connected to"
+ " the disconnected_queue\n", instance->host_no,
+ cmd->target, cmd->lun);
+#endif
+
+ /* Enable reselect interupts */
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ /*
+ * The SCSI data pointer is *IMPLICITLY* saved on a disconnect
+ * operation, in violation of the SCSI spec so we can safely
+ * ignore SAVE/RESTORE pointers calls.
+ *
+ * Unfortunately, some disks violate the SCSI spec and
+ * don't issue the required SAVE_POINTERS message before
+ * disconnecting, and we have to break spec to remain
+ * compatable.
+ */
+ case SAVE_POINTERS:
+ case RESTORE_POINTERS:
+ break;
+ default:
+/*
+ * XXX rejected messages should be handled in the pio data transfer phase,
+ * since ATN should be raised before ACK goes false when we reject a message
+ */
+
+#ifdef notyet
+ /*
+ * If we get something wierd that we aren't expecting,
+ * reject it.
+ */
+ msgout = MESSAGE_REJECT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE |
+ ICR_ASSERT_ATN);
+#endif
+ break;
+ } /* switch (tmp) */
+ break;
+ case PHASE_MSGOUT:
+ len = 1;
+ data = &msgout;
+ hostdata->last_message = msgout;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ if (msgout == ABORT) {
+ hostdata->busy[cmd->target] &= ~(1 << cmd->lun);
+ hostdata->connected = NULL;
+ cmd->result = DID_ERROR << 16;
+ cmd->scsi_done(cmd);
+ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask);
+ return;
+ }
+ msgout = NOP;
+ break;
+ case PHASE_CMDOUT:
+ len = COMMAND_SIZE(cmd->cmnd[0]);
+ data = cmd->cmnd;
+ /*
+ * XXX for performance reasons, on machines with a
+ * PSEUDO-DMA architecture we should probably
+ * use the dma transfer function.
+ */
+ NCR5380_transfer_pio(instance, &phase, &len,
+ &data);
+#ifdef USLEEP
+ if (!disconnect && should_disconnect(cmd->cmnd[0])) {
+ hostdata->time_expires = jiffies + USLEEP_SLEEP;
+#if (NDEBUG & NDEBUG_USLEEP)
+ printk("scsi%d : issued command, sleeping until %ul\n", instance->host_no,
+ hostdata->time_expires);
+#endif
+ NCR5380_set_timer (instance);
+ return;
+ }
+#endif /* def USLEEP */
+ break;
+ case PHASE_STATIN:
+ len = 1;
+ data = &tmp;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ cmd->SCp.Status = tmp;
+ break;
+ default:
+ printk("scsi%d : unknown phase\n", instance->host_no);
+#ifdef NDEBUG
+ NCR5380_print(instance);
+#endif
+ } /* switch(phase) */
+ } /* if (tmp * SR_REQ) */
+#ifdef USLEEP
+ else {
+ if (!disconnect && hostdata->time_expires && jiffies >
+ hostdata->time_expires) {
+ hostdata->time_expires = jiffies + USLEEP_SLEEP;
+#if (NDEBUG & NDEBUG_USLEEP)
+ printk("scsi%d : poll timed out, sleeping until %ul\n", instance->host_no,
+ hostdata->time_expires);
+#endif
+ NCR5380_set_timer (instance);
+ return;
+ }
+ }
+#endif
+ } /* while (1) */
+}
+
+/*
+ * Function : void NCR5380_reselect (struct Scsi_Host *instance)
+ *
+ * Purpose : does reselection, initializing the instance->connected
+ * field to point to the Scsi_Cmnd for which the I_T_L or I_T_L_Q
+ * nexus has been restablished,
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ */
+
+
+static void NCR5380_reselect (struct Scsi_Host *instance) {
+ NCR5380_local_declare();
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+ instance->hostdata;
+ unsigned char target_mask;
+ unsigned char lun, phase;
+ int len;
+#ifdef SCSI2
+ unsigned char tag;
+#endif
+ unsigned char msg[3];
+ unsigned char *data;
+ Scsi_Cmnd *tmp = NULL, *prev;
+ int abort = 0;
+ NCR5380_setup(instance);
+
+ target_mask = NCR5380_read(CURRENT_SCSI_DATA_REG) & ~(hostdata->id_mask);
+
+#if (NDEBUG & NDEBUG_RESELECTION)
+ printk("scsi%d : reselect\n", instance->host_no);
+#endif
+
+ /*
+ * At this point, we have detected that our SCSI ID is on the bus,
+ * SEL is true and BSY was false for at least one bus settle delay
+ * (400 ns).
+ *
+ * We must assert BSY ourselves, until the target drops the SEL
+ * signal.
+ */
+
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_BSY);
+ while (NCR5380_read(STATUS_REG) & SR_SEL);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ /*
+ * Wait for target to go into MSGIN.
+ */
+
+ while (!(NCR5380_read(STATUS_REG) & SR_REQ));
+
+ len = 3;
+ data = msg;
+ phase = PHASE_MSGIN;
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+
+#ifdef SCSI2
+ /*
+ * If there was no residual from the attempt to transfer three bytes, then
+ * the target sent the one byte IDENTIFY message followed by a two byte
+ * queue message.
+ *
+ * If there were two bytes of residual, we got the IDENTIFY message
+ * only.
+ *
+ * If there was one byte of residual, we got the IDENTIFY message
+ * followed by a RESTORE pointers message (which was ignored -
+ * see MSGIN phase of the NCR5380_information_transfer() function.
+ */
+
+ if (!len)
+ tag = msg[2];
+ else
+ tag = 0;
+#endif
+
+ if (!msg[0] & 0x80) {
+ printk("scsi%d : expecting IDENTIFY message, got ",
+ instance->host_no);
+ print_msg(msg);
+ abort = 1;
+ } else {
+
+ lun = (msg[0] & 0x07);
+
+ /*
+ * Find the command corresponding to the I_T_L or I_T_L_Q nexus we
+ * just restablished, and remove it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue, prev = NULL;
+ tmp; prev = tmp, tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ if ((target_mask == (1 << tmp->target)) && (lun == tmp->lun)
+#ifdef SCSI2
+ && (tag == tmp->tag)
+#endif
+) {
+ if (prev)
+ prev->host_scribble = tmp->host_scribble;
+ else
+ hostdata->disconnected_queue = (Scsi_Cmnd *) tmp->host_scribble;
+ tmp->host_scribble = NULL;
+ break;
+ }
+
+ if (!tmp) {
+#ifdef SCSI2
+ printk("scsi%d : warning : target bitmask %02x lun %d tag %d not in disconnect_queue.\n",
+ instance->host_no, target_mask, lun, tag);
+#else
+ printk("scsi%d : warning : target bitmask %02x lun %d not in disconnect_queue.\n",
+ instance->host_no, target_mask, lun);
+#endif
+ /*
+ * Since we have an established nexus that we can't do anything with,
+ * we must abort it.
+ */
+ abort = 1;
+ }
+ }
+
+ if (abort) {
+ msg[0] = ABORT;
+ len = 1;
+ data = msg;
+ phase = PHASE_MSGOUT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ NCR5380_transfer_pio(instance, &phase, &len, &data);
+ } else {
+ hostdata->connected = tmp;
+#if (NDEBUG & NDEBUG_RESELECTION)
+ printk"scsi%d : nexus established, target = %d, lun = %d, tag = %d\n",
+ instance->host_no, cmd->target, cmd->lun, cmd->tag);
+#endif
+ }
+}
+
+/*
+ * Function : void NCR5380_dma_complete (struct Scsi_Host *instance)
+ *
+ * Purpose : called by interrupt handler when DMA finishes or a phase
+ * mismatch occurs (which would finish the DMA transfer).
+ *
+ * Inputs : instance - this instance of the NCR5380.
+ *
+ * Returns : pointer to the Scsi_Cmnd structure for which the I_T_L
+ * nexus has been restablished, on failure NULL is returned.
+ */
+
+#ifdef REAL_DMA
+static void NCR5380_dma_complete (NCR5380_instance *instance) {
+ NCR5380_local_declare();
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *
+ instance->hostdata);
+ int transferred;
+ NCR5380_setup(instance);
+
+ /*
+ * XXX this might not be right.
+ *
+ * Wait for final byte to transfer, ie wait for ACK to go false.
+ *
+ * We should use the Last Byte Sent bit, unfortunately this is
+ * not available on the 5380/5381 (only the various CMOS chips)
+ */
+
+ while (NCR5380_read(STATUS_REG) & SR_ACK);
+
+ NCR5380_write(MODE_REG, MR_BASE);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+
+ /*
+ * The only places we should see a phase mismatch and have to send
+ * data from the same set of pointers will be the data transfer
+ * phases. So, residual, requested length are only important here.
+ */
+
+ if (!(hostdata->connected->SCp.phase & SR_CD)) {
+ transferred = instance->dma_len - NCR5380_dma_residual();
+ hostdata->connected->SCp.this_residual -= transferred;
+ hostdata->connected->SCp.ptr += transferred;
+ }
+}
+#endif /* def REAL_DMA */
+
+/*
+ * Function : int NCR5380_abort (Scsi_Cmnd *cmd, int code)
+ *
+ * Purpose : abort a command
+ *
+ * Inputs : cmd - the Scsi_Cmnd to abort, code - code to set the
+ * host byte of the result field to, if zero DID_ABORTED is
+ * used.
+ *
+ * Returns : 0 - success, -1 on failure.
+ *
+ * XXX - there is no way to abort the command that is currently
+ * connected, you have to wait for it to complete. If this is
+ * a problem, we could implement longjmp() / setjmp(), setjmp()
+ * called where the loop started in NCR5380_main().
+ */
+
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd, int code) {
+ NCR5380_local_declare();
+ struct Scsi_Host *instance = cmd->host;
+ struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *)
+ instance->hostdata;
+ Scsi_Cmnd *tmp, **prev;
+ unsigned char msg, phase, *msgptr;
+ int len;
+
+ cli();
+ NCR5380_setup(instance);
+
+#if (NDEBUG & NDEBUG_ABORT)
+ printk("scsi%d : abort called\n", instance->host_no);
+#endif
+/*
+ * Case 1 : If the command hasn't been issued yet, we simply remove it
+ * from the issue queue.
+ */
+ for (prev = (Scsi_Cmnd **) &(hostdata->issue_queue),
+ tmp = (Scsi_Cmnd *) hostdata->issue_queue;
+ tmp; prev = (Scsi_Cmnd **) &(tmp->host_scribble), tmp =
+ (Scsi_Cmnd *) tmp->host_scribble)
+ if (cmd == tmp) {
+ (*prev) = (Scsi_Cmnd *) tmp->host_scribble;
+ tmp->host_scribble = NULL;
+ tmp->result = (code ? code : DID_ABORT) << 16;
+ sti();
+#if (NDEBUG & NDEBUG_ABORT)
+ printk("scsi%d : abort removed command from issue queue.\n",
+ instance->host_no);
+#endif
+ tmp->done(tmp);
+ return 0;
+ }
+
+/*
+ * Case 2 : If any commands are connected, we're going to fail the abort
+ * and let the high level SCSI driver retry at a later time or
+ * issue a reset.
+ *
+ * Timeouts, and therefore aborted commands, will be highly unlikely
+ * and handling them cleanly in this situation would make the common
+ * case of noresets less efficient, and would pollute our code. So,
+ * we fail.
+ */
+
+ if (hostdata->connected) {
+ sti();
+#if (NDEBUG & NDEBUG_ABORT)
+ printk("scsi%d : abort failed, command connected.\n", instance->host_no);
+#endif
+ return -1;
+ }
+
+/*
+ * Case 3: If the command is currently disconnected from the bus, and
+ * there are no connected commands, we reconnect the I_T_L or
+ * I_T_L_Q nexus associated with it, go into message out, and send
+ * an abort message.
+ *
+ * This case is especially ugly. In order to resetablish the nexus, we
+ * need to call NCR5380_select(). The easiest way to implement this
+ * function was to abort if the bus was busy, and let the interrupt
+ * handler triggered on the SEL for reselect take care of lost arbitrations
+ * where necessary, meaning interrupts need to be enabled.
+ *
+ * When interrupts are enabled, the queues may change - so we
+ * can't remove it from the disconnected queue before selecting it
+ * because that could cause a failure in hashing the nexus if that
+ * device reselected.
+ *
+ * Since the queues may change, we can't use the pointers from when we
+ * first locate it.
+ *
+ * So, we must first locate the command, and if NCR5380_select()
+ * succeeds, then issue the abort, relocate the command and remove
+ * it from the disconnected queue.
+ */
+
+ for (tmp = (Scsi_Cmnd *) hostdata->disconnected_queue; tmp;
+ tmp = (Scsi_Cmnd *) tmp->host_scribble)
+ if (cmd == tmp) {
+ sti();
+#if (NDEBUG & NDEBUG_ABORT)
+ printk("scsi%d : aborting disconnected command.\n", instance->host_no);
+#endif
+
+ if (NCR5380_select (instance, cmd, (int) cmd->tag))
+ return 1;
+
+#if (NDEBUG & NDEBUG_ABORT)
+ printk("scsi%d : nexus restablished.\n", instance->host_no);
+#endif
+
+ msg = ABORT;
+ msgptr = &msg;
+ len = 1;
+ phase = PHASE_MSGOUT;
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_ATN);
+ NCR5380_transfer_pio (instance, &phase, &len, &msgptr);
+
+ cli();
+ for (prev = (Scsi_Cmnd **) &(hostdata->disconnected_queue),
+ tmp = (Scsi_Cmnd *) hostdata->disconnected_queue;
+ tmp; prev = (Scsi_Cmnd **) &(tmp->host_scribble), tmp =
+ (Scsi_Cmnd *) tmp->host_scribble)
+ if (cmd == tmp) {
+ *prev = (Scsi_Cmnd *) tmp->host_scribble;
+ tmp->host_scribble = NULL;
+ tmp->result = (code ? code : DID_ABORT) << 16;
+ sti();
+ tmp->done(tmp);
+ return 0;
+ }
+ }
+
+/*
+ * Case 4 : If we reached this point, the command was not found in any of
+ * the queues.
+ *
+ * We probably reached this point because of an unlikely race condition
+ * between the command completing successfully and the abortion code,
+ * so we won't panic, but we will notify the user in case somethign really
+ * broke.
+ */
+
+ sti();
+ printk("scsi%d : warning : SCSI command probably completed successfully\n"
+ " before abortion\n", instance->host_no);
+ return 0;
+}
+
+
+/*
+ * Function : int NCR5380_reset (void)
+ *
+ * Purpose : reset the SCSI bus.
+ *
+ * Returns : 0
+ *
+ * XXX we really need to add some sort of a per instance field here so that
+ * we only do a SCSI bus reset on the host adapter for which the reset command
+ * was called.
+ */
+
+#ifndef NCR5380_reset
+static
+#endif
+int NCR5380_reset (void) {
+ NCR5380_local_declare();
+ struct Scsi_Host *instance;
+ cli();
+ for (instance = first_instance; instance; instance = instance->next) {
+ NCR5380_setup(instance);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST);
+ udelay(1);
+ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE);
+ }
+ return 0;
+}
diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h
new file mode 100644
index 0000000..c230a50
--- /dev/null
+++ b/drivers/scsi/NCR5380.h
@@ -0,0 +1,257 @@
+/*
+ * NCR 5380 defines
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 3
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: NCR5380.h,v $
+ */
+
+#ifndef NCR5380_H
+#define NCR5380_H
+
+#define NCR5380_PUBLIC_RELEASE 3
+
+#define NDEBUG_ARBITRATION 0x1
+#define NDEBUG_AUTOSENSE 0x2
+#define NDEBUG_DMA 0x4
+#define NDEBUG_HANDSHAKE 0x8
+#define NDEBUG_INFORMATION 0x10
+#define NDEBUG_INIT 0x20
+#define NDEBUG_INTR 0x40
+#define NDEBUG_LINKED 0x80
+#define NDEBUG_MAIN 0x100
+#define NDEBUG_NO_DATAOUT 0x200
+#define NDEBUG_NO_WRITE 0x400
+#define NDEBUG_PIO 0x800
+#define NDEBUG_PSEUDO_DMA 0x1000
+#define NDEBUG_QUEUES 0x2000
+#define NDEBUG_RESELECTION 0x4000
+#define NDEBUG_SELECTION 0x8000
+#define NDEBUG_USLEEP 0x10000
+
+/*
+ * The contents of the OUTPUT DATA register are asserted on the bus when
+ * either arbitration is occuring or the phase-indicating signals (
+ * IO, CD, MSG) in the TARGET COMMAND register and the ASSERT DATA
+ * bit in the INTITIATOR COMMAND register is set.
+ */
+
+#define OUTPUT_DATA_REG 0 /* wo DATA lines on SCSI bus */
+#define CURRENT_SCSI_DATA_REG 0 /* ro same */
+
+#define INITIATOR_COMMAND_REG 1 /* rw */
+#define ICR_ASSERT_RST 0x80 /* rw Set to assert RST */
+#define ICR_ARBITRATION_PROGRESS 0x40 /* ro Indicates arbitration complete */
+#define ICR_TRI_STATE 0x40 /* wo Set to tri-state drivers */
+#define ICR_ARBITRATION_LOST 0x20 /* ro Indicates arbitration lost */
+#define ICR_DIFF_ENABLE 0x20 /* wo Set to enable diff. drivers */
+#define ICR_ASSERT_ACK 0x10 /* rw ini Set to assert ACK */
+#define ICR_ASSERT_BSY 0x08 /* rw Set to assert BSY */
+#define ICR_ASSERT_SEL 0x04 /* rw Set to assert SEL */
+#define ICR_ASSERT_ATN 0x02 /* rw Set to assert ATN */
+#define ICR_ASSERT_DATA 0x01 /* rw SCSI_DATA_REG is asserted */
+
+#ifdef DIFFERENTIAL
+#define ICR_BASE ICR_DIFF_ENABLE
+#else
+#define ICR_BASE 0
+#endif
+
+#define MODE_REG 2
+/*
+ * Note : BLOCK_DMA code will keep DRQ asserted for the duration of the
+ * transfer, causing the chip to hog the bus. You probably don't want
+ * this.
+ */
+#define MR_BLOCK_DMA_MODE 0x80 /* rw block mode DMA */
+#define MR_TARGET 0x40 /* rw target mode */
+#define MR_ENABLE_PAR_CHECK 0x20 /* rw enable parity checking */
+#define MR_ENABLE_PAR_INTR 0x10 /* rw enable bad parity interrupt */
+#define MR_ENABLE_EOP_INTR 0x08 /* rw enabble eop interrupt */
+#define MR_MONITOR_BSY 0x04 /* rw enable int on unexpected bsy fail */
+#define MR_DMA_MODE 0x02 /* rw DMA / pseudo DMA mode */
+#define MR_ARBITRATE 0x01 /* rw start arbitration */
+
+#ifdef PARITY
+#define MR_BASE MR_ENABLE_PAR_CHECK
+#else
+#define MR_BASE 0
+#endif
+
+#define TARGET_COMMAND_REG 3
+#define TCR_LAST_BYTE_SENT 0x80 /* ro DMA done */
+#define TCR_ASSERT_REQ 0x08 /* tgt rw assert REQ */
+#define TCR_ASSERT_MSG 0x04 /* tgt rw assert MSG */
+#define TCR_ASSERT_CD 0x02 /* tgt rw assert CD */
+#define TCR_ASSERT_IO 0x01 /* tgt rw assert IO */
+
+#define STATUS_REG 4 /* ro */
+/*
+ * Note : a set bit indicates an active signal, driven by us or another
+ * device.
+ */
+#define SR_RST 0x80
+#define SR_BSY 0x40
+#define SR_REQ 0x20
+#define SR_MSG 0x10
+#define SR_CD 0x08
+#define SR_IO 0x04
+#define SR_SEL 0x02
+#define SR_DBP 0x01
+
+/*
+ * Setting a bit in this register will cause an interrupt to be generated when
+ * BSY is false and SEL true and this bit is asserted on the bus.
+ */
+#define SELECT_ENABLE_REG 4 /* wo */
+
+#define BUS_AND_STATUS_REG 5 /* ro */
+#define BASR_END_DMA_TRANSFER 0x80 /* ro set on end of transfer */
+#define BASR_DRQ 0x40 /* ro mirror of DRQ pin */
+#define BASR_PARITY_ERROR 0x20 /* ro parity error detected */
+#define BASR_IRQ 0x10 /* ro mirror of IRQ pin */
+#define BASR_PHASE_MATCH 0x08 /* ro Set when MSG CD IO match TCR */
+#define BASR_BUSY_ERROR 0x04 /* ro Unexpected change to inactive state */
+#define BASR_ATN 0x02 /* ro BUS status */
+#define BASR_ACK 0x01 /* ro BUS status */
+
+/* Write any value to this register to start a DMA send */
+#define START_DMA_SEND_REG 5 /* wo */
+
+/*
+ * Used in DMA transfer mode, data is latched from the SCSI bus on
+ * the falling edge of REQ (ini) or ACK (tgt)
+ */
+#define INPUT_DATA_REGISTER 6 /* ro */
+
+/* Write any value to this register to start a DMA recieve */
+#define START_DMA_TARGET_RECIEVE_REG 6 /* wo */
+
+/* Read this register to clear interrupt conditions */
+#define RESET_PARITY_INTERRUPT_REG 7 /* ro */
+
+/* Write any value to this register to start an ini mode DMA recieve */
+#define START_DMA_INITIATOR_RECIEVE_REG 7 /* wo */
+
+/* Note : PHASE_* macros are based on the values of the STATUS register */
+#define PHASE_MASK (SR_MSG | SR_CD | SR_IO)
+
+#define PHASE_DATAOUT 0
+#define PHASE_DATAIN SR_IO
+#define PHASE_CMDOUT SR_CD
+#define PHASE_STATIN (SR_CD | SR_IO)
+#define PHASE_MSGOUT (SR_MSG | SR_CD)
+#define PHASE_MSGIN (SR_MSG | SR_CD | SR_IO)
+#define PHASE_UNKNOWN 0xff
+
+/*
+ * Convert status register phase to something we can use to set phase in
+ * the target register so we can get phase mismatch interrupts on DMA
+ * transfers.
+ */
+
+#define PHASE_SR_TO_TCR(phase) ((phase) >> 2)
+
+/*
+ * The internal should_disconnect() function returns these based on the
+ * expected length of a disconnect if a device supports disconnect/
+ * reconnect.
+ */
+
+#define DISCONNECT_NONE 0
+#define DISCONNECT_TIME_TO_DATA 1
+#define DISCONNECT_LONG 2
+
+/*
+ * These are "special" values for the tag parameter passed to NCR5380_select.
+ */
+
+#define TAG_NEXT -1 /* Use next free tag */
+#define TAG_NONE -2 /*
+ * Establish I_T_L nexus instead of I_T_L_Q
+ * even on SCSI-II devices.
+ */
+
+/*
+ * These are "special" values for the irq field of the instance structure
+ * and returns from NCR5380_probe_irq.
+ */
+
+#define IRQ_NONE 255
+#define IRQ_AUTO 254
+
+
+#ifndef ASM
+struct NCR5380_hostdata {
+ NCR5380_implementation_fields; /* implmenentation specific */
+ unsigned char id_mask, id_higher_mask; /* 1 << id, all bits greater */
+ volatile unsigned char busy[8]; /* index = target, bit = lun */
+#ifdef REAL_DMA
+ volatile int dma_len; /* requested length of DMA */
+#endif
+ volatile unsigned char last_message; /* last message OUT */
+ volatile Scsi_Cmnd *connected; /* currently connected command */
+ volatile Scsi_Cmnd *issue_queue; /* waiting to be issued */
+ volatile Scsi_Cmnd *disconnected_queue; /* waiting for reconnect */
+#ifdef USLEEP
+ unsigned long time_expires; /* in jiffies, set prior to sleeping */
+ struct Scsi_Host *next_timer;
+#endif
+};
+
+#ifdef __KERNEL__
+static struct Scsi_Host *first_instance; /* linked list of 5380's */
+
+#if defined(AUTOPROBE_IRQ)
+static int NCR5380_probe_irq (struct Scsi_Host *instance, int possible);
+#endif
+static void NCR5380_init (struct Scsi_Host *instance);
+static void NCR5380_information_transfer (struct Scsi_Host *instance);
+static void NCR5380_intr (int irq);
+static void NCR5380_main (void);
+static void NCR5380_print_options (struct Scsi_Host *instance);
+#ifndef NCR5380_abort
+static
+#endif
+int NCR5380_abort (Scsi_Cmnd *cmd, int code);
+#ifndef NCR5380_reset
+static
+#endif
+int NCR5380_reset (void);
+#ifndef NCR5380_queue_command
+static
+#endif
+int NCR5380_queue_command (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *));
+
+
+static void NCR5380_reselect (struct Scsi_Host *instance);
+static int NCR5380_select (struct Scsi_Host *instance, Scsi_Cmnd *cmd, int tag);
+#if defined(PSEUDO_DMA) || defined(REAL_DMA)
+static int NCR5380_transfer_dma (struct Scsi_Host *instance,
+ unsigned char *phase, int *count, unsigned char **data);
+#endif
+static int NCR5380_transfer_pio (struct Scsi_Host *instance,
+ unsigned char *phase, int *count, unsigned char **data);
+
+#endif __KERNEL_
+#endif /* ndef ASM */
+#endif /* NCR5380_H */
diff --git a/drivers/scsi/aha152x.c b/drivers/scsi/aha152x.c
new file mode 100644
index 0000000..eedefdb
--- /dev/null
+++ b/drivers/scsi/aha152x.c
@@ -0,0 +1,2399 @@
+/* aha152x.c -- Adaptec AHA-152x driver
+ * Author: Juergen E. Fischer, fischer@server.et-inf.fho-emden.de
+ * Copyright 1993 Juergen E. Fischer
+ *
+ *
+ * This driver is based on
+ * fdomain.c -- Future Domain TMC-16x0 driver
+ * which is
+ * Copyright 1992, 1993 Rickard E. Faith (faith@cs.unc.edu)
+ *
+
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2, or (at your option) any
+ * later version.
+
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+
+ *
+ * $Id: aha152x.c,v 0.97 1993/10/09 18:53:53 root Exp $
+ *
+
+ * $Log: aha152x.c,v $
+ * Revision 0.97 1993/10/09 18:53:53 root
+ * - DATA IN fixed. Rarely left data in the fifo.
+ *
+ * Revision 0.96 1993/10/03 00:53:59 root
+ * - minor changes on DATA IN
+ *
+ * Revision 0.95 1993/09/24 10:36:01 root
+ * - change handling of MSGI after reselection
+ * - fixed sti/cli
+ * - minor changes
+ *
+ * Revision 0.94 1993/09/18 14:08:22 root
+ * - fixed bug in multiple outstanding command code
+ * - changed detection
+ * - support for kernel command line configuration
+ * - reset corrected
+ * - changed message handling
+ *
+ * Revision 0.93 1993/09/15 20:41:19 root
+ * - fixed bugs with multiple outstanding commands
+ *
+ * Revision 0.92 1993/09/13 02:46:33 root
+ * - multiple outstanding commands work (no problems with IBM drive)
+ *
+ * Revision 0.91 1993/09/12 20:51:46 root
+ * added multiple outstanding commands
+ * (some problem with this $%&? IBM device remain)
+ *
+ * Revision 0.9 1993/09/12 11:11:22 root
+ * - corrected auto-configuration
+ * - changed the auto-configuration (added some '#define's)
+ * - added support for dis-/reconnection
+ *
+ * Revision 0.8 1993/09/06 23:09:39 root
+ * - added support for the drive activity light
+ * - minor changes
+ *
+ * Revision 0.7 1993/09/05 14:30:15 root
+ * - improved phase detection
+ * - now using the new snarf_region code of 0.99pl13
+ *
+ * Revision 0.6 1993/09/02 11:01:38 root
+ * first public release; added some signatures and biosparam()
+ *
+ * Revision 0.5 1993/08/30 10:23:30 root
+ * fixed timing problems with my IBM drive
+ *
+ * Revision 0.4 1993/08/29 14:06:52 root
+ * fixed some problems with timeouts due incomplete commands
+ *
+ * Revision 0.3 1993/08/28 15:55:03 root
+ * writing data works too. mounted and worked on a dos partition
+ *
+ * Revision 0.2 1993/08/27 22:42:07 root
+ * reading data works. Mounted a msdos partition.
+ *
+ * Revision 0.1 1993/08/25 13:38:30 root
+ * first "damn thing doesn't work" version
+ *
+ * Revision 0.0 1993/08/14 19:54:25 root
+ * empty function bodies; detect() works.
+ *
+
+ **************************************************************************
+
+
+
+ DESCRIPTION:
+
+ This is the Linux low-level SCSI driver for Adaptec AHA-1520/1522
+ SCSI host adapters.
+
+
+ PER-DEFINE CONFIGURABLE OPTIONS:
+
+ AUTOCONF : use configuration the controller reports (only 152x)
+ IRQ : override interrupt channel (9,10,11 or 12) (default 11)
+ SCSI_ID : override scsiid of AIC-6260 (0-7) (default 7)
+ RECONNECT : override target dis-/reconnection/multiple outstanding commands
+ SKIP_BIOSTEST : Don't test for BIOS signature (AHA-1510 or disabled BIOS)
+ PORTBASE : Force port base. Don't try to probe
+
+
+ LILO COMMAND LINE OPTIONS:
+
+ aha152x=<PORTBASE>,<IRQ>,<SCSI-ID>,<RECONNECT>
+
+ The normal configuration can be overridden by specifying a command line.
+ When you do this, the BIOS test is skipped. Entered values have to be
+ valid (known). Don't use values that aren't support under normal operation.
+ If you think that you need other value: contact me.
+
+
+ REFERENCES USED:
+
+ "AIC-6260 SCSI Chip Specification", Adaptec Corporation.
+
+ "SCSI COMPUTER SYSTEM INTERFACE - 2 (SCSI-2)", X3T9.2/86-109 rev. 10h
+
+ "Writing a SCSI device driver for Linux", Rik Faith (faith@cs.unc.edu)
+
+ "Kernel Hacker's Guide", Michael K. Johnson (johnsonm@sunsite.unc.edu)
+
+ "Adaptec 1520/1522 User's Guide", Adaptec Corporation.
+
+ Michael K. Johnson (johnsonm@sunsite.unc.edu)
+
+ Drew Eckhardt (drew@cs.colorado.edu)
+
+ Eric Youngdale (eric@tantalus.nrl.navy.mil)
+
+ special thanks to Eric Youngdale for the free(!) supplying the
+ documentation on the chip.
+
+ **************************************************************************/
+
+#include "aha152x.h"
+
+#include <linux/sched.h>
+#include <asm/io.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "constants.h"
+#include <asm/system.h>
+#include <linux/errno.h>
+#include <linux/string.h>
+#include <linux/wait.h>
+#include <linux/ioport.h>
+
+/* DEFINES */
+
+
+/* If auto configuration is disabled, IRQ, SCSI_ID and RECONNECT have to
+ be predefined */
+#if !defined(AUTOCONF)
+#if !defined(IRQ)
+#error undefined IRQ; define AUTOCONF or IRQ
+#endif
+#if !defined(SCSI_ID)
+#error undefined SCSI_ID; define AUTOCONF or SCSI_ID
+#endif
+#if !defined(RECONNECT)
+#error undefined RECONNECT; define AUTOCONF or RECONNECT
+#endif
+#endif
+
+/* I use this when I'm looking for weird bugs */
+#define DEBUG_TIMING
+
+#if defined(DEBUG)
+
+#undef SKIP_PORTS /* don't display ports */
+
+#undef DEBUG_QUEUE /* debug queue() */
+#undef DEBUG_RESET /* debug reset() */
+#undef DEBUG_INTR /* debug intr() */
+#undef DEBUG_SELECTION /* debug selection part in intr() */
+#undef DEBUG_MSGO /* debug message out phase in intr() */
+#undef DEBUG_MSGI /* debug message in phase in intr() */
+#undef DEBUG_STATUS /* debug status phase in intr() */
+#undef DEBUG_CMD /* debug command phase in intr() */
+#undef DEBUG_DATAI /* debug data in phase in intr() */
+#undef DEBUG_DATAO /* debug data out phase in intr() */
+#undef DEBUG_ABORT /* debug abort() */
+#undef DEBUG_DONE /* debug done() */
+#undef DEBUG_BIOSPARAM /* debug biosparam() */
+
+#undef DEBUG_RACE /* debug race conditions */
+#undef DEBUG_PHASES /* debug phases (useful to trace) */
+#undef DEBUG_QUEUES /* debug reselection */
+
+/* recently used for debugging */
+#if 0
+#define DEBUG_PHASES
+#define DEBUG_DATAI
+#endif
+
+#endif
+
+#define DEBUG_BIOSPARAM /* warn when biosparam is invoked */
+#define DEBUG_RESET /* resets should be rare */
+#define DEBUG_ABORT /* aborts too */
+
+/* END OF DEFINES */
+
+char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.97 $\n";
+
+static int port_base = 0;
+static int this_host = 0;
+static int can_disconnect = 0;
+static int commands = 0;
+
+/* set by aha152x_setup according to the command line */
+static int setup_called = 0;
+static int setup_portbase = 0;
+static int setup_irq = 0;
+static int setup_scsiid = 0;
+static int setup_reconnect = 0;
+
+static char *setup_str = (char *)NULL;
+
+enum {
+ not_issued = 0x01,
+ in_selection = 0x02,
+ disconnected = 0x04,
+ aborted = 0x08,
+ sent_ident = 0x10,
+ in_other = 0x20,
+};
+
+/*
+ * Command queues:
+ * issue_SC : commands that are queued to be issued
+ * current_SC : command that's currently using the bus
+ * disconnected_SC : commands that that have been disconnected
+ */
+static Scsi_Cmnd *issue_SC = NULL;
+static Scsi_Cmnd *current_SC = NULL;
+static Scsi_Cmnd *disconnected_SC = NULL;
+
+static struct wait_queue *abortion_complete;
+static int abort_result;
+
+void aha152x_intr( int irqno );
+void aha152x_done( int error );
+void aha152x_setup( char *str, int *ints );
+
+static void aha152x_reset_ports(void);
+static void aha152x_panic(char *msg);
+
+static void disp_ports(void);
+static void show_command(Scsi_Cmnd *ptr);
+static void show_queues(void);
+static void disp_enintr(void);
+
+#if defined(DEBUG_RACE)
+static void enter_driver(const char *);
+static void leave_driver(const char *);
+#endif
+
+/* possible locations for the Adaptec BIOS */
+static void *addresses[] =
+{
+ (void *) 0xdc000, /* default first */
+ (void *) 0xc8000,
+ (void *) 0xcc000,
+ (void *) 0xd0000,
+ (void *) 0xd4000,
+ (void *) 0xd8000,
+ (void *) 0xe0000,
+ (void *) 0xf0000,
+};
+#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned ))
+
+/* possible i/o adresses for the AIC-6260 */
+static unsigned short ports[] =
+{
+ 0x340, /* default first */
+ 0x140
+};
+#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short ))
+
+/* possible interrupt channels */
+static unsigned short ints[] = { 9, 10, 11, 12 };
+
+/* signatures for various AIC-6260 based controllers */
+static struct signature {
+ char *signature;
+ int sig_offset;
+ int sig_length;
+} signatures[] =
+{
+ {
+ "Adaptec AHA-1520 BIOS\r\n\0\
+Version 1.4 \r\n\0\
+Copyright 1990 Adaptec, Inc.\r\n\
+All Rights Reserved\r\n \r\n \r\n", 0x102e, 101
+ }, /* Adaptec 152x */
+ {
+ "Adaptec ASW-B626 BIOS\r\n\0\
+Version 1.0 \r\n\0\
+Copyright 1990 Adaptec, Inc.\r\n\
+All Rights Reserved\r\n\0 \r\n \r\n", 0x1029, 102
+ }, /* on-board controller */
+ { "Adaptec BIOS: ASW-B626", 0x0F, 22}, /* on-board controller */
+ { "Adaptec ASW-B626 S2 BIOS", 0x2e6c, 24}, /* on-board controller */
+};
+#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
+
+
+/* These defines are copied from kernel/blk_drv/hd.c */
+
+#define insw( buf, count, port ) \
+ __asm__ volatile \
+ ("cld;rep;insw": :"d" (port),"D" (buf),"c" (count):"cx","di" )
+
+#define outsw( buf, count, port ) \
+ __asm__ volatile \
+ ("cld;rep;outsw": :"d" (port),"S" (buf),"c" (count):"cx","si")
+
+
+static void do_pause( unsigned amount ) /* Pause for amount*10 milliseconds */
+{
+ unsigned long the_time = jiffies + amount; /* 0.01 seconds per jiffy */
+
+ while (jiffies < the_time)
+ ;
+}
+
+/*
+ * queue services:
+ */
+static inline void append_SC( Scsi_Cmnd **SC, Scsi_Cmnd *new_SC)
+{
+ Scsi_Cmnd *end;
+
+ new_SC->host_scribble = (unsigned char *) NULL;
+ if(!*SC)
+ *SC=new_SC;
+ else
+ {
+ for( end=*SC;
+ end->host_scribble;
+ end = (Scsi_Cmnd *) end->host_scribble )
+ ;
+ end->host_scribble = (unsigned char *) new_SC;
+ }
+}
+
+static inline Scsi_Cmnd *remove_first_SC( Scsi_Cmnd **SC )
+{
+ Scsi_Cmnd *ptr;
+
+ ptr=*SC;
+ if(ptr)
+ *SC= (Scsi_Cmnd *) (*SC)->host_scribble;
+ return ptr;
+}
+
+static inline Scsi_Cmnd *remove_SC( Scsi_Cmnd **SC, int target, int lun )
+{
+ Scsi_Cmnd *ptr, *prev;
+
+ for( ptr=*SC, prev=NULL;
+ ptr && ((ptr->target!=target) || (ptr->lun!=lun));
+ prev = ptr, ptr = (Scsi_Cmnd *) ptr->host_scribble )
+ ;
+
+ if(ptr)
+ if(prev)
+ prev->host_scribble = ptr->host_scribble;
+ else
+ *SC= (Scsi_Cmnd *) ptr->host_scribble;
+ return ptr;
+}
+
+/*
+ * read inbound byte and wait for ACK to get low
+ */
+static void make_acklow(void)
+{
+ SETPORT( SXFRCTL0, CH1|SPIOEN );
+ GETPORT(SCSIDAT);
+ SETPORT( SXFRCTL0, CH1 );
+
+ while( TESTHI( SCSISIG, ACKI ) )
+ ;
+}
+
+/*
+ * detect current phase more reliable:
+ * phase is valid, when the target asserts REQ after we've deasserted ACK.
+ *
+ * return value is a valid phase or an error code.
+ *
+ * errorcodes:
+ * 1 BUS FREE phase detected
+ * 2 RESET IN detected
+ * 3 parity error in DATA phase
+ */
+static int getphase(void)
+{
+ int phase, sstat1;
+
+ while( 1 )
+ {
+ do
+ {
+ while( !( ( sstat1 = GETPORT( SSTAT1 ) ) & (BUSFREE|SCSIRSTI|REQINIT ) ) )
+ ;
+ if( sstat1 & BUSFREE )
+ return 1;
+ if( sstat1 & SCSIRSTI )
+ {
+ /* IBM drive responds with RSTI to RSTO */
+ printk("aha152x: RESET IN\n");
+ SETPORT( SSTAT1, SCSIRSTI );
+ }
+ }
+ while( TESTHI( SCSISIG, ACKI ) || TESTLO( SSTAT1, REQINIT ) );
+
+ SETPORT( SSTAT1, CLRSCSIPERR );
+
+ phase = GETPORT( SCSISIG ) & P_MASK ;
+
+ if( TESTHI( SSTAT1, SCSIPERR ) )
+ {
+ if( (phase & (CDO|MSGO))==0 ) /* DATA phase */
+ {
+ return 3;
+ }
+
+ SETPORT( SCSISIG, phase );
+ make_acklow();
+ }
+ else
+ {
+ SETPORT( SCSISIG, phase );
+ return phase;
+ }
+ }
+}
+
+/* called from init/main.c */
+void aha152x_setup( char *str, int *ints)
+{
+ if(setup_called)
+ panic("aha152x: aha152x_setup called twice.\n");
+
+ setup_called=ints[0];
+ setup_str=str;
+
+ if(ints[0] != 4)
+ return;
+
+ setup_portbase = ints[1];
+ setup_irq = ints[2];
+ setup_scsiid = ints[3];
+ setup_reconnect = ints[4];
+}
+
+/*
+ Test, if port_base is valid.
+ */
+static int aha152x_porttest(int port_base)
+{
+ int i;
+
+ if(check_region(port_base, TEST-SCSISEQ))
+ return 0;
+
+ SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */
+ for(i=0; i<16; i++)
+ SETPORT( STACK, i );
+
+ SETPORT( DMACNTRL1, 0 ); /* reset stack pointer */
+ for(i=0; i<16 && GETPORT(STACK)==i; i++)
+ ;
+
+ return(i==16);
+}
+
+int aha152x_detect(int hostno)
+{
+ int i, j, ok;
+ aha152x_config conf;
+ struct sigaction sa;
+ int interrupt_level;
+
+#if defined(DEBUG_RACE)
+ enter_driver("detect");
+#endif
+
+ printk("aha152x: Probing: ");
+
+ if(setup_called)
+ {
+ printk("processing commandline: ");
+
+ if(setup_called!=4)
+ {
+ printk("\naha152x: %s\n", setup_str );
+ printk("aha152x: usage: aha152x=<PORTBASE>,<IRQ>,<SCSI ID>,<RECONNECT>\n");
+ panic("aha152x panics in line %d", __LINE__);
+ }
+
+ port_base = setup_portbase;
+ interrupt_level = setup_irq;
+ this_host = setup_scsiid;
+ can_disconnect = setup_reconnect;
+
+ for( i=0; i<PORT_COUNT && (port_base != ports[i]); i++)
+ ;
+
+ if(i==PORT_COUNT)
+ {
+ printk("unknown portbase 0x%03x\n", port_base);
+ panic("aha152x panics in line %d", __LINE__);
+ }
+
+ if(!aha152x_porttest(port_base))
+ {
+ printk("portbase 0x%03x fails probe\n", port_base);
+ panic("aha152x panics in line %d", __LINE__);
+ }
+
+ i=0;
+ while(ints[i] && (interrupt_level!=ints[i]))
+ i++;
+ if(!ints[i])
+ {
+ printk("illegal IRQ %d\n", interrupt_level);
+ panic("aha152x panics in line %d", __LINE__);
+ }
+
+ if( (this_host < 0) || (this_host > 7) )
+ {
+ printk("illegal SCSI ID %d\n", this_host);
+ panic("aha152x panics in line %d", __LINE__);
+ }
+
+ if( (can_disconnect < 0) || (can_disconnect > 1) )
+ {
+ printk("reconnect %d should be 0 or 1\n", can_disconnect);
+ panic("aha152x panics in line %d", __LINE__);
+ }
+ printk("ok, ");
+ }
+ else
+ {
+#if !defined(SKIP_BIOSTEST)
+ printk("BIOS test: ");
+ ok=0;
+ for( i=0; i < ADDRESS_COUNT && !ok; i++)
+ for( j=0; (j < SIGNATURE_COUNT) && !ok; j++)
+ ok=!memcmp((void *) addresses[i]+signatures[j].sig_offset,
+ (void *) signatures[j].signature,
+ (int) signatures[j].sig_length);
+
+ if(!ok)
+ {
+#if defined(DEBUG_RACE)
+ leave_driver("(1) detect");
+#endif
+ printk("failed\n");
+ return 0;
+ }
+ printk("ok, ");
+#endif /* !SKIP_BIOSTEST */
+
+#if !defined(PORTBASE)
+ printk("porttest: ");
+ for( i=0; i<PORT_COUNT && !aha152x_porttest(ports[i]); i++)
+ ;
+
+ if(i==PORT_COUNT)
+ {
+ printk("failed\n");
+#if defined(DEBUG_RACE)
+ leave_driver("(2) detect");
+#endif
+ return 0;
+ }
+ else
+ port_base=ports[i];
+ printk("ok, ");
+#else
+ port_base=PORTBASE;
+#endif /* !PORTBASE */
+
+#if defined(AUTOCONF)
+
+ conf.cf_port = (GETPORT(PORTA)<<8) + GETPORT(PORTB);
+
+ interrupt_level = ints[conf.cf_irq];
+ this_host = conf.cf_id;
+ can_disconnect = conf.cf_tardisc;
+
+ printk("auto configuration: ok, ");
+
+#endif /* AUTOCONF */
+
+#if defined(IRQ)
+ interrupt_level = IRQ;
+#endif
+
+#if defined(SCSI_ID)
+ this_host = SCSI_ID;
+#endif
+
+#if defined(RECONNECT)
+ can_disconnect=RECONNECT;
+#endif
+ }
+
+ printk("detection complete\n");
+
+ sa.sa_handler = aha152x_intr;
+ sa.sa_flags = SA_INTERRUPT;
+ sa.sa_mask = 0;
+ sa.sa_restorer = NULL;
+
+ ok = irqaction( interrupt_level, &sa);
+
+ if(ok<0)
+ {
+ if(ok == -EINVAL)
+ {
+ printk("aha152x: bad IRQ %d.\n", interrupt_level);
+ printk(" Contact author.\n");
+ }
+ else
+ if( ok == -EBUSY)
+ printk( "aha152x: IRQ %d already in use. Configure another.\n",
+ interrupt_level);
+ else
+ {
+ printk( "\naha152x: Unexpected error code on requesting IRQ %d.\n",
+ interrupt_level);
+ printk(" Contact author.\n");
+ }
+ panic("aha152x: driver needs an IRQ.\n");
+ }
+
+ SETPORT( SCSIID, this_host << 4 );
+ scsi_hosts[hostno].this_id=this_host;
+
+ if(can_disconnect)
+ scsi_hosts[hostno].can_queue=AHA152X_MAXQUEUE;
+
+ /* RESET OUT */
+ SETBITS(SCSISEQ, SCSIRSTO );
+ do_pause(5);
+ CLRBITS(SCSISEQ, SCSIRSTO );
+
+ aha152x_reset();
+
+ printk("aha152x: vital data: PORTBASE=0x%03x, IRQ=%d, SCSI ID=%d, reconnect=%s, parity=enabled\n",
+ port_base, interrupt_level, this_host, can_disconnect ? "enabled" : "disabled" );
+
+ snarf_region(port_base, TEST-SCSISEQ); /* Register */
+
+ /* not expecting any interrupts */
+ SETPORT(SIMODE0, 0);
+ SETPORT(SIMODE1, 0);
+
+#if defined(DEBUG_RACE)
+ leave_driver("(3) detect");
+#endif
+
+ SETBITS( DMACNTRL0, INTEN);
+ return 1;
+}
+
+/*
+ * return the name of the thing
+ */
+const char *aha152x_info(void)
+{
+#if defined(DEBUG_RACE)
+ enter_driver("info");
+ leave_driver("info");
+#else
+#if defined(DEBUG_INFO)
+ printk("\naha152x: info()\n");
+#endif
+#endif
+ return(aha152x_id);
+}
+
+/*
+ * Queue a command and setup interrupts for a free bus.
+ */
+int aha152x_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
+{
+#if defined(DEBUG_RACE)
+ enter_driver("queue");
+#else
+#if defined(DEBUG_QUEUE)
+ printk("aha152x: queue(), ");
+#endif
+#endif
+
+
+#if defined(DEBUG_QUEUE)
+ printk( "SCpnt (target = %d lun = %d cmnd = 0x%02x pieces = %d size = %u), ",
+ SCpnt->target,
+ SCpnt->lun,
+ *(unsigned char *)SCpnt->cmnd,
+ SCpnt->use_sg,
+ SCpnt->request_bufflen );
+ disp_ports();
+#endif
+
+ /* Turn led on, when this is the first command. */
+ cli();
+ commands++;
+ if(commands==1)
+ SETPORT( PORTA, 1 );
+
+ SCpnt->scsi_done = done;
+ SCpnt->SCp.phase = not_issued;
+
+#if defined(DEBUG_QUEUES)
+ printk("i+ (%d), ", commands );
+#endif
+ append_SC( &issue_SC, SCpnt);
+
+ /* Enable bus free interrupt, when we aren't currently on the bus */
+ if(!current_SC)
+ {
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ }
+ sti();
+
+ return 0;
+}
+
+/*
+ * We only support command in interrupt-driven fashion
+ */
+int aha152x_command( Scsi_Cmnd *SCpnt )
+{
+ printk( "aha152x: interrupt driven driver; use aha152x_queue()\n" );
+ return -1;
+}
+
+/*
+ * Abort a queued command
+ * (commands that are on the bus can't be aborted easily)
+ */
+int aha152x_abort( Scsi_Cmnd *SCpnt, int code )
+{
+ Scsi_Cmnd *ptr, *prev;
+
+ cli();
+
+#if defined(DEBUG_ABORT)
+ printk("aha152x: abort(), SCpnt=0x%08x, ", (unsigned long) SCpnt );
+#endif
+
+ show_queues();
+
+ /* look for command in issue queue */
+ for( ptr=issue_SC, prev=NULL;
+ ptr && ptr!=SCpnt;
+ prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
+ ;
+
+ if(ptr)
+ {
+ /* dequeue */
+ if(prev)
+ prev->host_scribble = ptr->host_scribble;
+ else
+ issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ sti();
+
+ ptr->host_scribble = NULL;
+ ptr->result = (code ? code : DID_ABORT ) << 16;
+ ptr->done(ptr);
+ return 0;
+ }
+
+ /* Fail abortion, if we're on the bus */
+ if (current_SC)
+ {
+ sti();
+ return -1;
+ }
+
+ /* look for command in disconnected queue */
+ for( ptr=disconnected_SC, prev=NULL;
+ ptr && ptr!=SCpnt;
+ prev=ptr, ptr=(Scsi_Cmnd *) ptr->host_scribble)
+ ;
+
+ if(ptr && TESTLO(SSTAT1, BUSFREE) )
+ printk("bus busy but no current command, ");
+
+ if(ptr && TESTHI(SSTAT1, BUSFREE) )
+ {
+ /* dequeue */
+ if(prev)
+ prev->host_scribble = ptr->host_scribble;
+ else
+ issue_SC = (Scsi_Cmnd *) ptr->host_scribble;
+
+ /* set command current and initiate selection,
+ let the interrupt routine take care of the abortion */
+ current_SC = ptr;
+ ptr->SCp.phase = in_selection|aborted;
+ SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+
+ /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+ SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+ SETPORT( SIMODE1, ENSELTIMO );
+
+ /* Enable SELECTION OUT sequence */
+ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+
+ SETBITS( DMACNTRL0, INTEN );
+ abort_result=0;
+ sti();
+
+ /* sleep until the abortion is complete */
+ sleep_on( &abortion_complete );
+ return abort_result;
+ }
+ else
+ printk("aha152x: bus busy but no current command\n");
+
+ /* command wasn't found */
+ sti();
+ return 0;
+}
+
+/*
+ * Restore default values to the AIC-6260 registers and reset the fifos
+ */
+static void aha152x_reset_ports(void)
+{
+ /* disable interrupts */
+ SETPORT(DMACNTRL0, RSTFIFO);
+
+ SETPORT(SCSISEQ, 0);
+
+ SETPORT(SXFRCTL1, 0);
+ SETPORT( SCSISIG, 0);
+ SETPORT(SCSIRATE, 0);
+
+ /* clear all interrupt conditions */
+ SETPORT(SSTAT0, 0x7f);
+ SETPORT(SSTAT1, 0xef);
+
+ SETPORT(SSTAT4, SYNCERR|FWERR|FRERR);
+
+ SETPORT(DMACNTRL0, 0);
+ SETPORT(DMACNTRL1, 0);
+
+ SETPORT(BRSTCNTRL, 0xf1);
+
+ /* clear channel 0 and transfer count */
+ SETPORT(SXFRCTL0, CH1|CLRCH1|CLRSTCNT);
+ SETPORT(SXFRCTL0, CH1);
+
+ /* enable interrupts */
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+}
+
+/*
+ * Reset registers, reset a hanging bus and
+ * kill active and disconnected commands
+ */
+int aha152x_reset(void)
+{
+ Scsi_Cmnd *ptr;
+
+ aha152x_reset_ports();
+
+ /* Reset, if bus hangs */
+ if( TESTLO( SSTAT1, BUSFREE ) )
+ {
+ CLRBITS( DMACNTRL0, INTEN );
+
+#if defined( DEBUG_RESET )
+ printk("aha152x: reset(), bus not free: SCSI RESET OUT\n");
+#endif
+
+ show_queues();
+
+ if(current_SC)
+ {
+ current_SC->host_scribble = NULL;
+ current_SC->result = DID_RESET << 16;
+ current_SC->done(current_SC);
+ current_SC=NULL;
+ }
+
+ while(disconnected_SC)
+ {
+ ptr = disconnected_SC;
+ disconnected_SC = (Scsi_Cmnd *) ptr->host_scribble;
+ ptr->host_scribble = NULL;
+ ptr->result = DID_RESET << 16;
+ ptr->done(ptr);
+ }
+
+ /* RESET OUT */
+ SETPORT(SCSISEQ, SCSIRSTO);
+ do_pause(5);
+ SETPORT(SCSISEQ, 0);
+
+ SETPORT(SIMODE0, 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+
+ SETPORT( DMACNTRL0, INTEN );
+ }
+
+ return 0;
+}
+
+/*
+ * Return the "logical geometry"
+ */
+int aha152x_biosparam( int size, int dev, int *info_array )
+{
+#if defined(DEBUG_RACE)
+ enter_driver("biosparam");
+#else
+#if defined(DEBUG_BIOSPARAM)
+ printk("\naha152x: biosparam(), ");
+#endif
+#endif
+
+#if defined(DEBUG_BIOSPARAM)
+ printk("dev=%x, size=%d, ", dev, size);
+#endif
+
+/* I took this from other SCSI drivers, since it provides
+ the correct data for my devices. */
+ info_array[0]=64;
+ info_array[1]=32;
+ info_array[2]=size>>11;
+
+#if defined(DEBUG_BIOSPARAM)
+ printk("bios geometry: head=%d, sec=%d, cyl=%d\n",
+ info_array[0], info_array[1], info_array[2]);
+ printk("WARNING: check, if the bios geometry is correct.\n");
+#endif
+
+#if defined(DEBUG_RACE)
+ leave_driver("biosparam");
+#endif
+ return 0;
+}
+
+/*
+ * Internal done function
+ */
+void aha152x_done( int error )
+{
+ Scsi_Cmnd *done_SC;
+
+#if defined(DEBUG_DONE)
+ printk("\naha152x: done(), ");
+ disp_ports();
+#endif
+
+ if (current_SC)
+ {
+#if defined(DEBUG_DONE)
+ printk("done(%x), ", error);
+#endif
+
+ cli();
+
+ done_SC = current_SC;
+ current_SC = NULL;
+
+ /* turn led off, when no commands are in the driver */
+ commands--;
+ if(!commands)
+ SETPORT( PORTA, 0 ); /* turn led off */
+
+#if defined(DEBUG_QUEUES)
+ printk("ok (%d), ", commands);
+#endif
+ sti();
+
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+
+#if defined(DEBUG_PHASES)
+ printk("BUS FREE loop, ");
+#endif
+ while( TESTLO( SSTAT1, BUSFREE ) )
+ ;
+#if defined(DEBUG_PHASES)
+ printk("BUS FREE\n");
+#endif
+
+ done_SC->result = error;
+ if(done_SC->scsi_done)
+ {
+#if defined(DEBUG_DONE)
+ printk("calling scsi_done, ");
+#endif
+ done_SC->scsi_done( done_SC );
+#if defined(DEBUG_DONE)
+ printk("done returned, ");
+#endif
+ }
+ else
+ panic( "aha152x: current_SC->scsi_done() == NULL" );
+ }
+ else
+ aha152x_panic( "done() called outside of command" );
+}
+
+/*
+ * Interrupts handler (main routine of the driver)
+ */
+void aha152x_intr( int irqno )
+{
+ int done=0, phase;
+
+#if defined(DEBUG_RACE)
+ enter_driver("intr");
+#else
+#if defined(DEBUG_INTR)
+ printk("\naha152x: intr(), ");
+#endif
+#endif
+
+ /* no more interrupts from the controller, while we busy.
+ INTEN has to be restored, when we're ready to leave
+ intr(). To avoid race conditions we have to return
+ immediately afterwards. */
+ CLRBITS( DMACNTRL0, INTEN);
+ sti();
+
+ /* disconnected target is trying to reconnect.
+ Only possible, if we have disconnected nexuses and
+ nothing is occuping the bus.
+ */
+ if( TESTHI( SSTAT0, SELDI ) &&
+ disconnected_SC &&
+ ( !current_SC || ( current_SC->SCp.phase & in_selection ) )
+ )
+ {
+ int identify_msg, target, i;
+
+ /* Avoid conflicts when a target reconnects
+ while we are trying to connect to another. */
+ if(current_SC)
+ {
+#if defined(DEBUG_QUEUES)
+ printk("i+, ");
+#endif
+ cli();
+ append_SC( &issue_SC, current_SC);
+ current_SC=NULL;
+ sti();
+ }
+
+ /* disable sequences */
+ SETPORT( SCSISEQ, 0 );
+ SETPORT( SSTAT0, CLRSELDI );
+ SETPORT( SSTAT1, CLRBUSFREE );
+
+#if defined(DEBUG_QUEUES) || defined(DEBUG_PHASES)
+ printk("reselected, ");
+#endif
+
+ i = GETPORT(SELID) & ~(1 << this_host);
+ target=0;
+ if(i)
+ for( ; (i & 1)==0; target++, i>>=1)
+ ;
+ else
+ aha152x_panic("reconnecting target unknown");
+
+#if defined(DEBUG_QUEUES)
+ printk("SELID=%02x, target=%d, ", GETPORT(SELID), target );
+#endif
+ SETPORT( SCSIID, (this_host << OID_) | target );
+ SETPORT( SCSISEQ, ENRESELI );
+
+ if(TESTLO( SSTAT0, SELDI ))
+ aha152x_panic("RESELI failed");
+
+ SETPORT( SCSISIG, P_MSGI );
+
+ /* Get identify message */
+ if((i=getphase())!=P_MSGI)
+ {
+ printk("target doesn't enter MSGI to identify (phase=%02x)\n", i);
+ aha152x_panic("unknown lun");
+ }
+ SETPORT( SCSISEQ, 0 );
+
+ SETPORT( SXFRCTL0, CH1);
+
+ identify_msg = GETPORT(SCSIBUS);
+
+ if(!(identify_msg & IDENTIFY_BASE))
+ {
+ printk("target=%d, inbound message (%02x) != IDENTIFY\n",
+ target, identify_msg);
+ aha152x_panic("unknown lun");
+ }
+
+ make_acklow();
+ getphase();
+
+ SETPORT(SCSISIG, P_MSGI);
+
+#if defined(DEBUG_QUEUES)
+ printk("identify=%02x, lun=%d, ", identify_msg, identify_msg & 0x3f );
+#endif
+
+ cli();
+#if defined(DEBUG_QUEUES)
+ printk("d-, ");
+#endif
+ current_SC = remove_SC( &disconnected_SC,
+ target,
+ identify_msg & 0x3f );
+
+ if(!current_SC)
+ {
+ printk("lun=%d, ", identify_msg & 0x3f );
+ aha152x_panic("no disconnected command for that lun");
+ }
+
+ current_SC->SCp.phase &= ~disconnected;
+ sti();
+
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS );
+#if defined(DEBUG_RACE)
+ leave_driver("(reselected) intr");
+#endif
+ SETBITS( DMACNTRL0, INTEN);
+ return;
+ }
+
+ /* Check, if we aren't busy with a command */
+ if(!current_SC)
+ {
+ /* bus is free to issue a queued command */
+ if(TESTHI( SSTAT1, BUSFREE) && issue_SC)
+ {
+ cli();
+#if defined(DEBUG_QUEUES)
+ printk("i-, ");
+#endif
+ current_SC = remove_first_SC( &issue_SC );
+ sti();
+
+#if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
+ printk("issuing command, ");
+#endif
+
+ /* setup SCSI pointers
+ SCp.ptr : buffer pointer
+ SCp.this_residual : buffer length
+ SCp.buffer : next buffer
+ SCp.buffers_residual : left buffers in list */
+ if (current_SC->use_sg)
+ {
+ current_SC->SCp.buffer =
+ (struct scatterlist *)current_SC->request_buffer;
+ current_SC->SCp.ptr = current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+ current_SC->SCp.buffers_residual = current_SC->use_sg - 1;
+ }
+ else
+ {
+ current_SC->SCp.ptr = (char *)current_SC->request_buffer;
+ current_SC->SCp.this_residual = current_SC->request_bufflen;
+ current_SC->SCp.buffer = NULL;
+ current_SC->SCp.buffers_residual = 0;
+ }
+
+ current_SC->SCp.Status = CHECK_CONDITION;
+ current_SC->SCp.Message = 0;
+ current_SC->SCp.have_data_in = 0;
+ current_SC->SCp.sent_command = 0;
+ current_SC->SCp.phase = in_selection;
+
+ #if defined(DEBUG_INTR) || defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
+ printk("selecting %d, ", current_SC->target);
+ #endif
+ SETPORT( SCSIID, (this_host << OID_) | current_SC->target );
+
+ /* Enable interrupts for SELECTION OUT DONE and SELECTION OUT INITIATED */
+ SETPORT( SXFRCTL1, ENSPCHK|ENSTIMER);
+
+ /* enable interrupts for SELECTION OUT DONE and SELECTION TIME OUT */
+ SETPORT( SIMODE0, ENSELDO | (disconnected_SC ? ENSELDI : 0) );
+ SETPORT( SIMODE1, ENSELTIMO );
+
+ /* Enable SELECTION OUT sequence */
+ SETBITS(SCSISEQ, ENSELO | ENAUTOATNO );
+
+ #if defined(DEBUG_RACE)
+ leave_driver("(selecting) intr");
+ #endif
+ SETBITS( DMACNTRL0, INTEN );
+ return;
+ }
+
+ /* No command we are busy with and no new to issue */
+ printk("aha152x: ignoring spurious interrupt, nothing to do\n");
+ return;
+ }
+
+ /* the bus is busy with something */
+
+#if defined(DEBUG_INTR)
+ disp_ports();
+#endif
+
+ /* we are waiting for the result of a selection attempt */
+ if(current_SC->SCp.phase & in_selection)
+ {
+ if( TESTLO( SSTAT1, SELTO ) )
+ /* no timeout */
+ if( TESTHI( SSTAT0, SELDO ) )
+ {
+ /* clear BUS FREE interrupt */
+ SETPORT( SSTAT1, CLRBUSFREE);
+
+ /* Disable SELECTION OUT sequence */
+ CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO );
+
+ /* Disable SELECTION OUT DONE interrupt */
+ CLRBITS(SIMODE0, ENSELDO);
+ CLRBITS(SIMODE1, ENSELTIMO);
+
+ if( TESTLO(SSTAT0, SELDO) )
+ {
+ printk("aha152x: passing bus free condition\n");
+
+#if defined(DEBUG_RACE)
+ leave_driver("(passing bus free) intr");
+#endif
+ SETBITS( DMACNTRL0, INTEN);
+
+ if(current_SC->SCp.phase & aborted)
+ {
+ abort_result=1;
+ wake_up( &abortion_complete );
+ }
+
+ aha152x_done( DID_NO_CONNECT << 16 );
+ return;
+ }
+#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
+ printk("SELDO (SELID=%x), ", GETPORT(SELID));
+#endif
+
+ /* selection was done */
+ SETPORT( SSTAT0, CLRSELDO );
+
+#if defined(DEBUG_ABORT)
+ if(current_SC->SCp.phase & aborted)
+ printk("(ABORT) target selected, ");
+#endif
+
+ current_SC->SCp.phase &= ~in_selection;
+ current_SC->SCp.phase |= in_other;
+
+#if defined(DEBUG_RACE)
+ leave_driver("(SELDO) intr");
+#endif
+
+ SETPORT( SCSISIG, P_MSGO );
+
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENREQINIT );
+ SETBITS( DMACNTRL0, INTEN);
+ return;
+ }
+ else
+ aha152x_panic("neither timeout nor selection\007");
+ else
+ {
+#if defined(DEBUG_SELECTION) || defined(DEBUG_PHASES)
+ printk("SELTO, ");
+#endif
+ /* timeout */
+ SETPORT( SSTAT1, CLRSELTIMO );
+
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETBITS( DMACNTRL0, INTEN );
+#if defined(DEBUG_RACE)
+ leave_driver("(SELTO) intr");
+#endif
+
+ if(current_SC->SCp.phase & aborted)
+ {
+#if defined(DEBUG_ABORT)
+ printk("(ABORT) selection timeout, ");
+#endif
+ abort_result=1;
+ wake_up( &abortion_complete );
+ }
+
+ if( TESTLO( SSTAT0, SELINGO ) )
+ /* ARBITRATION not won */
+ aha152x_done( DID_BUS_BUSY << 16 );
+ else
+ /* ARBITRATION won, but SELECTION failed */
+ aha152x_done( DID_NO_CONNECT << 16 );
+ return;
+ }
+ }
+
+ /* enable interrupt, when target leaves current phase */
+ phase = getphase();
+ SETPORT(SSTAT1, CLRPHASECHG);
+ current_SC->SCp.phase =
+ (current_SC->SCp.phase & ~((P_MASK|1)<<16)) | (phase << 16 );
+
+ /* information transfer phase */
+ switch( phase )
+ {
+ case P_MSGO: /* MESSAGE OUT */
+ {
+ unsigned char message;
+
+#if defined(DEBUG_INTR) || defined(DEBUG_MSGO) || defined(DEBUG_PHASES)
+ printk("MESSAGE OUT, ");
+#endif
+
+ if( current_SC->SCp.phase & aborted )
+ {
+#if defined(DEBUG_MSGO) || defined(DEBUG_ABORT)
+ printk("ABORT, ");
+#endif
+ message=ABORT;
+ }
+ else
+ /* If we didn't identify yet, do it. Otherwise there's nothing to do,
+ but reject (perhaps one could do as NOP as well) */
+ if( !(current_SC->SCp.phase & sent_ident))
+ {
+ message=IDENTIFY(can_disconnect,current_SC->lun);
+#if defined(DEBUG_MSGO)
+ printk("IDENTIFY (reconnect=%s;lun=%d), ",
+ can_disconnect ? "enabled" : "disabled", current_SC->lun);
+#endif
+ }
+ else
+ {
+ message=MESSAGE_REJECT;
+#if defined(DEBUG_MSGO)
+ printk("REJECT, ");
+#endif
+ }
+
+ CLRSETBITS( SXFRCTL0, ENDMA, SPIOEN);
+
+ SETPORT( SIMODE0, ENSPIORDY );
+ SETPORT( SIMODE1, ENPHASEMIS );
+
+ /* wait for data latch to become ready or a phase change */
+ while( TESTLO( DMASTAT, INTSTAT ) )
+ ;
+
+ if( TESTLO( SSTAT0, SPIORDY ) )
+ aha152x_panic("couldn't send message");
+
+ /* Leave MESSAGE OUT after transfer */
+ SETPORT( SSTAT1, CLRATNO);
+
+ SETPORT( SCSIDAT, message );
+ CLRBITS( SXFRCTL0, SPIOEN);
+
+ if(message==IDENTIFY(can_disconnect,current_SC->lun))
+ current_SC->SCp.phase |= sent_ident;
+
+ if(message==ABORT)
+ {
+ /* revive abort(); abort() enables interrupts */
+ abort_result=0;
+ wake_up( &abortion_complete );
+
+ current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+
+ /* exit */
+ SETBITS( DMACNTRL0, INTEN );
+#if defined(DEBUG_RACE)
+ leave_driver("(ABORT) intr");
+#endif
+ aha152x_done(DID_ABORT<<16);
+ return;
+ }
+ }
+ break;
+
+ case P_CMD: /* COMMAND phase */
+#if defined(DEBUG_INTR) || defined(DEBUG_CMD) || defined(DEBUG_PHASES)
+ printk("COMMAND, ");
+#endif
+ if( !(current_SC->SCp.sent_command) )
+ {
+ if(GETPORT(FIFOSTAT))
+ {
+ int i;
+
+ printk("aha152x: %d bytes left in FIFO, resetting\n",
+ GETPORT(FIFOSTAT));
+ disp_ports();
+ printk("contents ( ");
+ SETPORT( SXFRCTL0, CH1|SPIOEN );
+ for(i=0; i<GETPORT(FIFOSTAT); i++)
+ printk("%02x ", GETPORT(SCSIDAT));
+ SETPORT( SXFRCTL0, CH1 );
+ printk(")\n");
+ }
+
+ SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+ SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+ SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS );
+
+#if defined(DEBUG_CMD)
+ printk("waiting, ");
+#endif
+ /* wait for FIFO to get empty */
+ while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+ ;
+
+ if( TESTHI( SSTAT1, PHASEMIS ) )
+ aha152x_panic("target left COMMAND phase");
+
+#if defined(DEBUG_CMD)
+ printk("DFIFOEMP, outsw (%d words), ",
+ COMMAND_SIZE(current_SC->cmnd[0])>>1);
+ disp_ports();
+#endif
+
+ outsw( &current_SC->cmnd,
+ COMMAND_SIZE(current_SC->cmnd[0])>>1,
+ DATAPORT );
+
+#if defined(DEBUG_CMD)
+ printk("FCNT=%d, STCNT=%d, ", GETPORT(FIFOSTAT), GETSTCNT() );
+ disp_ports();
+#endif
+
+ /* wait for SCSI FIFO to get empty.
+ very important to send complete commands. */
+ while( TESTLO ( SSTAT2, SEMPTY ) )
+ ;
+
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+ /* transfer can be considered ended, when SCSIEN reads back zero */
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
+
+ CLRBITS(DMACNTRL0, ENDMA);
+
+#if defined(DEBUG_CMD) || defined(DEBUG_INTR)
+ printk("sent %d/%d command bytes, ", GETSTCNT(),
+ COMMAND_SIZE(current_SC->cmnd[0]));
+#endif
+
+ }
+ else
+ aha152x_panic("Nothing to sent while in COMMAND OUT");
+ break;
+
+ case P_MSGI: /* MESSAGE IN phase */
+#if defined(DEBUG_INTR) || defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
+ printk("MESSAGE IN, ");
+#endif
+ SETPORT( SXFRCTL0, CH1);
+
+ SETPORT( SIMODE0, 0);
+ SETPORT( SIMODE1, ENBUSFREE);
+
+ while( phase == P_MSGI )
+ {
+ current_SC->SCp.Message = GETPORT( SCSIBUS );
+ switch(current_SC->SCp.Message)
+ {
+ case DISCONNECT:
+#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
+ printk("target disconnected, ");
+#endif
+ current_SC->SCp.Message = 0;
+ current_SC->SCp.phase |= disconnected;
+ if(!can_disconnect)
+ aha152x_panic("target was not allowed to disconnect");
+ break;
+
+ case COMMAND_COMPLETE:
+#if defined(DEBUG_MSGI) || defined(DEBUG_PHASES)
+ printk("inbound message ( COMMAND COMPLETE ), ");
+#endif
+ done++;
+ break;
+
+ case MESSAGE_REJECT:
+#if defined(DEBUG_MSGI)
+ printk("inbound message ( MESSAGE REJECT ), ");
+#endif
+ break;
+
+ case SAVE_POINTERS:
+#if defined(DEBUG_MSGI)
+ printk("inbound message ( SAVE DATA POINTERS ), ");
+#endif
+ break;
+
+/* my IBM drive responds to the first command with an extended message.
+ I just ignore it... */
+ case EXTENDED_MESSAGE:
+ {
+ int i, code;
+
+#if defined(DEBUG_MSGI)
+ printk("inbound message ( EXTENDED MESSAGE ), ");
+#endif
+ make_acklow();
+ if(getphase()!=P_MSGI)
+ break;
+
+ i=GETPORT(SCSIDAT);
+
+#if defined(DEBUG_MSGI)
+ printk("length (%d), ", i);
+#endif
+
+ make_acklow();
+ if(getphase()!=P_MSGI)
+ break;
+
+#if defined(DEBUG_MSGI)
+ printk("code ( ");
+#endif
+
+ code = GETPORT(SCSIDAT);
+
+#if defined(DEBUG_MSGI)
+ switch( code )
+ {
+ case 0x00:
+ printk("MODIFY DATA POINTER ");
+ break;
+ case 0x01:
+ printk("SYNCHRONOUS DATA TRANSFER REQUEST ");
+ break;
+ case 0x02:
+ printk("EXTENDED IDENTIFY ");
+ break;
+ case 0x03:
+ printk("WIDE DATA TRANSFER REQUEST ");
+ break;
+ default:
+ if( code & 0x80 )
+ printk("reserved (%d) ", code );
+ else
+ printk("vendor specific (%d) ", code);
+ break;
+ }
+ printk(" ), data ( ");
+#endif
+
+ while( --i && (make_acklow(), getphase()==P_MSGI))
+ {
+#if defined(DEBUG_MSGI)
+ printk("%x ", GETPORT(SCSIDAT) );
+#else
+ GETPORT(SCSIDAT);
+#endif
+ }
+#if defined(DEBUG_MSGI)
+ printk(" ), ");
+#endif
+ }
+ break;
+
+ default:
+ printk("unsupported inbound message %x, ", current_SC->SCp.Message);
+ break;
+
+ }
+
+ make_acklow();
+ phase=getphase();
+ }
+
+ SETPORT( SCSISIG, P_MSGI );
+
+ if(current_SC->SCp.phase & disconnected)
+ {
+ cli();
+#if defined(DEBUG_QUEUES)
+ printk("d+, ");
+#endif
+ append_SC( &disconnected_SC, current_SC);
+ current_SC = NULL;
+ sti();
+
+ SETBITS( SCSISEQ, ENRESELI );
+
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+
+ SETBITS( DMACNTRL0, INTEN );
+ return;
+ }
+
+ break;
+
+ case P_STATUS: /* STATUS IN phase */
+#if defined(DEBUG_STATUS) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
+ printk("STATUS, ");
+#endif
+ SETPORT( SXFRCTL0, CH1|SPIOEN);
+
+ SETPORT( SIMODE0, ENSPIORDY );
+ SETPORT( SIMODE1, ENPHASEMIS );
+
+ SETBITS( SXFRCTL0, SCSIEN );
+#if defined(DEBUG_STATUS)
+ printk("waiting for status, ");
+#endif
+#if defined(DEBUG_STATUS)
+ disp_ports();
+#endif
+ while( TESTLO( DMASTAT, INTSTAT ) )
+ ;
+
+ if(TESTLO( SSTAT0, SPIORDY ) )
+ aha152x_panic("passing STATUS phase");
+
+ current_SC->SCp.Status = GETPORT( SCSIDAT );
+#if defined(DEBUG_STATUS)
+ printk("inbound status ");
+ print_status( current_SC->SCp.Status );
+ printk(", ");
+#endif
+ CLRBITS( SXFRCTL0, SCSIEN );
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
+
+ CLRBITS( SXFRCTL0, SPIOEN);
+ break;
+
+ case P_DATAI: /* DATA IN phase */
+ {
+ int fifodata, data_count, done;
+
+#if defined(DEBUG_DATAI) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
+ printk("DATA IN, ");
+#endif
+
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE );
+
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+ CLRSETBITS(SXFRCTL0, CLRSTCNT, SCSIEN|DMAEN|CH1);
+
+ SETBITS(DMACNTRL0, RSTFIFO);
+ CLRSETBITS(DMACNTRL0, WRITE_READ, ENDMA);
+
+
+ /* done is set when the FIFO is empty after the target left DATA IN */
+ done=0;
+
+ /* while the target stays in DATA to transfer data */
+ while ( !done )
+ {
+#if defined(DEBUG_DATAI)
+ printk("expecting data, ");
+#endif
+ /* wait for PHASEMIS or full FIFO */
+ while( TESTLO ( DMASTAT, DFIFOFULL|INTSTAT ) )
+ ;
+
+ if( TESTHI( DMASTAT, DFIFOFULL ) )
+ fifodata=132;
+ else
+ {
+ /* wait for SCSI fifo to get empty */
+ while( TESTLO( SSTAT2, SEMPTY ) )
+ ;
+
+ /* rest of data in FIFO */
+ fifodata=GETPORT(FIFOSTAT);
+#if defined(DEBUG_DATAI)
+ printk("last transfer, ");
+#endif
+ done=1;
+ }
+
+#if defined(DEBUG_DATAI)
+ printk("fifodata=%d, ", fifodata);
+#endif
+
+ /* I don't know yet why, but rarely I get empty
+ buffers here, so I've to advance to the next buffer
+ before I enter the loop */
+ if(!current_SC->SCp.this_residual &&
+ current_SC->SCp.buffers_residual)
+ {
+ /* advance to next buffer */
+ current_SC->SCp.buffers_residual--;
+ current_SC->SCp.buffer++;
+ current_SC->SCp.ptr = current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual = current_SC->SCp.buffer->length;
+ }
+
+ while( fifodata && current_SC->SCp.this_residual )
+ {
+ data_count=fifodata;
+
+ /* limit data transfer to size of first sg buffer */
+ if (data_count > current_SC->SCp.this_residual)
+ data_count = current_SC->SCp.this_residual;
+
+ fifodata -= data_count;
+
+#if defined(DEBUG_DATAI)
+ printk("data_count=%d, ", data_count);
+#endif
+
+ if(data_count == 1)
+ {
+ /* get a single byte in byte mode */
+ SETBITS(DMACNTRL0, _8BIT );
+ *current_SC->SCp.ptr++ = GETPORT( DATAPORT );
+ current_SC->SCp.this_residual--;
+ }
+ else
+ {
+ CLRBITS(DMACNTRL0, _8BIT );
+ data_count >>= 1; /* Number of words */
+ insw( current_SC->SCp.ptr, data_count, DATAPORT );
+#if defined(DEBUG_DATAI)
+/* show what comes with the last transfer */
+ if(done)
+ {
+ int i;
+ unsigned char *data;
+
+ printk("data on last transfer (%d bytes: ",
+ 2*data_count);
+ data = (unsigned char *) current_SC->SCp.ptr;
+ for( i=0; i<2*data_count; i++)
+ printk("%2x ", *data++);
+ printk("), ");
+ }
+#endif
+ current_SC->SCp.ptr += 2 * data_count;
+ current_SC->SCp.this_residual -= 2 * data_count;
+ }
+
+ /* if this buffer is full and there are more buffers left */
+ if (!current_SC->SCp.this_residual &&
+ current_SC->SCp.buffers_residual)
+ {
+ /* advance to next buffer */
+ current_SC->SCp.buffers_residual--;
+ current_SC->SCp.buffer++;
+ current_SC->SCp.ptr =
+ current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual =
+ current_SC->SCp.buffer->length;
+ }
+ }
+
+ /* rare (but possible) status bytes (probably also DISCONNECT
+ messages) get transfered in the data phase, so I assume 1
+ additional byte is ok */
+ if(fifodata>1)
+ printk("aha152x: more data than expected (%d bytes)\n",
+ GETPORT(FIFOSTAT));
+
+#if defined(DEBUG_DATAI)
+ if(!fifodata)
+ printk("fifo empty, ");
+ else
+ printk("something left in fifo, ");
+#endif
+ }
+
+#if defined(DEBUG_DATAI)
+ if(current_SC->SCp.buffers_residual || current_SC->SCp.this_residual)
+ printk("left buffers (buffers=%d, bytes=%d), ",
+ current_SC->SCp.buffers_residual,
+ current_SC->SCp.this_residual);
+#endif
+
+ /* transfer can be considered ended, when SCSIEN reads back zero */
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
+ CLRBITS(DMACNTRL0, ENDMA );
+
+#if defined(DEBUG_DATAI) || defined(DEBUG_INTR)
+ printk("got %d bytes, ", GETSTCNT());
+#endif
+
+ current_SC->SCp.have_data_in++;
+ }
+ break;
+
+ case P_DATAO: /* DATA OUT phase */
+ {
+ int data_count;
+
+#if defined(DEBUG_DATAO) || defined(DEBUG_INTR) || defined(DEBUG_PHASES)
+ printk("DATA OUT, ");
+#endif
+#if defined(DEBUG_DATAO)
+ printk("got data to send (bytes=%d, buffers=%d), ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual );
+#endif
+
+ if(GETPORT(FIFOSTAT))
+ {
+ printk("%d left in FIFO, ", GETPORT(FIFOSTAT));
+ aha152x_panic("FIFO should be empty");
+ }
+
+ SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+ SETPORT(DMACNTRL0, ENDMA|WRITE_READ);
+
+ SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 );
+ SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1);
+
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS );
+
+ /* while current buffer is not empty or
+ there are more buffers to transfer */
+ while( TESTLO( SSTAT1, PHASEMIS ) &&
+ (current_SC->SCp.this_residual ||
+ current_SC->SCp.buffers_residual) )
+ {
+#if defined(DEBUG_DATAO)
+ printk("sending data (left: bytes=%d, buffers=%d), waiting, ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual);
+#endif
+ /* transfer rest of buffer, but max. 128 byte */
+ data_count = current_SC->SCp.this_residual > 128 ?
+ 128 : current_SC->SCp.this_residual ;
+
+#if defined(DEBUG_DATAO)
+ printk("data_count=%d, ", data_count);
+#endif
+
+ if(data_count == 1)
+ {
+ /* put a single byte in byte mode */
+ SETBITS(DMACNTRL0, _8BIT );
+ SETPORT(DATAPORT, *current_SC->SCp.ptr++);
+ current_SC->SCp.this_residual--;
+ }
+ else
+ {
+ CLRBITS(DMACNTRL0, _8BIT );
+ data_count >>= 1; /* Number of words */
+ outsw( current_SC->SCp.ptr, data_count, DATAPORT );
+ current_SC->SCp.ptr += 2 * data_count;
+ current_SC->SCp.this_residual -= 2 * data_count;
+ }
+
+ /* wait for FIFO to get empty */
+ while( TESTLO ( DMASTAT, DFIFOEMP|INTSTAT ) )
+ ;
+
+#if defined(DEBUG_DATAO)
+ printk("fifo (%d bytes), transfered (%d bytes), ",
+ GETPORT(FIFOSTAT), GETSTCNT() );
+#endif
+
+ /* if this buffer is empty and there are more buffers left */
+ if ( TESTLO( SSTAT1, PHASEMIS ) &&
+ !current_SC->SCp.this_residual &&
+ current_SC->SCp.buffers_residual)
+ {
+ /* advance to next buffer */
+ current_SC->SCp.buffers_residual--;
+ current_SC->SCp.buffer++;
+ current_SC->SCp.ptr =
+ current_SC->SCp.buffer->address;
+ current_SC->SCp.this_residual =
+ current_SC->SCp.buffer->length;
+ }
+ }
+
+ if ( current_SC->SCp.this_residual ||
+ current_SC->SCp.buffers_residual )
+ {
+ /* target leaves DATA OUT for an other phase
+ (perhaps disconnect) */
+
+ /* data in fifos has to be resend */
+ data_count = GETPORT(SSTAT2);
+ if( (data_count & SFCNT) == 0)
+ data_count = (data_count & SEMPTY) ? 0 : 8 ;
+ else
+ data_count &= SFCNT;
+
+#if defined(DEBUG_DATAO)
+ printk("\ntarget left DATA OUT, fifo=%d, scsififo=%d, ",
+ GETPORT(FIFOSTAT), data_count ) ;
+#endif
+
+ data_count += GETPORT(FIFOSTAT) ;
+ current_SC->SCp.ptr -= data_count;
+ current_SC->SCp.this_residual += data_count;
+#if defined(DEBUG_DATAO)
+ printk("left data (bytes=%d, buffers=%d), fifos (bytes=%d), transfer incomplete, resetting fifo, ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual,
+ data_count );
+#endif
+ SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO);
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+ CLRBITS(DMACNTRL0, ENDMA);
+ }
+ else
+ {
+#if defined(DEBUG_DATAO)
+ printk("waiting for SCSI fifo to get empty, ");
+#endif
+ /* wait for SCSI fifo to get empty */
+ while( TESTLO( SSTAT2, SEMPTY ) )
+ ;
+#if defined(DEBUG_DATAO)
+ printk("ok, ");
+#endif
+
+#if defined(DEBUG_DATAO)
+ printk("left data (bytes=%d, buffers=%d) ",
+ current_SC->SCp.this_residual,
+ current_SC->SCp.buffers_residual);
+#endif
+ CLRBITS(SXFRCTL0, SCSIEN|DMAEN);
+
+ /* transfer can be considered ended, when SCSIEN reads back zero */
+ while( TESTHI( SXFRCTL0, SCSIEN ) )
+ ;
+
+ CLRBITS(DMACNTRL0, ENDMA);
+ }
+
+#if defined(DEBUG_DATAO) || defined(DEBUG_INTR)
+ printk("sent %d data bytes, ", GETSTCNT() );
+#endif
+ }
+ break;
+
+ case 1: /* BUSFREE */
+#if defined(DEBUG_RACE)
+ leave_driver("(BUSFREE) intr");
+#endif
+#if defined(DEBUG_PHASES)
+ printk("unexpected BUS FREE, ");
+#endif
+ current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+
+ aha152x_done( DID_ERROR << 16 ); /* Don't know any better */
+ return;
+ break;
+
+ case 3: /* parity error in DATA phase */
+#if defined(DEBUG_RACE)
+ leave_driver("(DID_PARITY) intr");
+#endif
+ printk("PARITY error in DATA phase, ");
+
+ current_SC->SCp.phase = (current_SC->SCp.phase & ~(P_MASK<<16));
+
+ SETBITS( DMACNTRL0, INTEN );
+ aha152x_done( DID_PARITY << 16 );
+ return;
+ break;
+
+ default:
+#if defined(DEBUG_INTR)
+ printk("unexpected phase, ");
+#endif
+ break;
+ }
+
+ if(done)
+ {
+#if defined(DEBUG_INTR)
+ printk("command done.\n");
+#endif
+#if defined(DEBUG_RACE)
+ leave_driver("(done) intr");
+#endif
+
+ SETPORT(SIMODE0, disconnected_SC ? ENSELDI : 0 );
+ SETPORT(SIMODE1, issue_SC ? ENBUSFREE : 0);
+ SETPORT( SCSISEQ, disconnected_SC ? ENRESELI : 0 );
+
+ SETBITS( DMACNTRL0, INTEN );
+
+ aha152x_done( (current_SC->SCp.Status & 0xff)
+ | ( (current_SC->SCp.Message & 0xff) << 8)
+ | ( DID_OK << 16) );
+
+#if defined(DEBUG_RACE)
+ printk("done returned (DID_OK: Status=%x; Message=%x).\n",
+ current_SC->SCp.Status, current_SC->SCp.Message);
+#endif
+ return;
+ }
+
+ if(current_SC)
+ current_SC->SCp.phase |= 1<<16 ;
+
+ SETPORT( SIMODE0, 0 );
+ SETPORT( SIMODE1, ENPHASEMIS );
+#if defined(DEBUG_INTR)
+ disp_enintr();
+#endif
+#if defined(DEBUG_RACE)
+ leave_driver("(PHASEEND) intr");
+#endif
+
+ SETBITS( DMACNTRL0, INTEN);
+ return;
+}
+
+/*
+ * Dump the current driver status and panic...
+ */
+static void aha152x_panic(char *msg)
+{
+ printk("\naha152x_panic: %s\n", msg);
+ show_queues();
+ panic("aha152x panic");
+}
+
+/*
+ * Display registers of AIC-6260
+ */
+static void disp_ports(void)
+{
+#if !defined(SKIP_PORTS)
+ int s;
+
+ printk("\n%s: ", current_SC ? "on bus" : "waiting");
+
+ s=GETPORT(SCSISEQ);
+ printk("SCSISEQ ( ");
+ if( s & TEMODEO ) printk("TARGET MODE ");
+ if( s & ENSELO ) printk("SELO ");
+ if( s & ENSELI ) printk("SELI ");
+ if( s & ENRESELI ) printk("RESELI ");
+ if( s & ENAUTOATNO ) printk("AUTOATNO ");
+ if( s & ENAUTOATNI ) printk("AUTOATNI ");
+ if( s & ENAUTOATNP ) printk("AUTOATNP ");
+ if( s & SCSIRSTO ) printk("SCSIRSTO ");
+ printk(");");
+
+ printk(" SCSISIG ( ");
+ s=GETPORT(SCSISIG);
+ switch(s & P_MASK)
+ {
+ case P_DATAO:
+ printk("DATA OUT");
+ break;
+ case P_DATAI:
+ printk("DATA IN");
+ break;
+ case P_CMD:
+ printk("COMMAND");
+ break;
+ case P_STATUS:
+ printk("STATUS");
+ break;
+ case P_MSGO:
+ printk("MESSAGE OUT");
+ break;
+ case P_MSGI:
+ printk("MESSAGE IN");
+ break;
+ default:
+ printk("*illegal*");
+ break;
+ }
+
+ printk(" ); ");
+
+ printk("INTSTAT ( %s ); ", TESTHI(DMASTAT, INTSTAT) ? "hi" : "lo");
+
+ printk("SSTAT ( ");
+ s=GETPORT(SSTAT0);
+ if( s & TARGET ) printk("TARGET ");
+ if( s & SELDO ) printk("SELDO ");
+ if( s & SELDI ) printk("SELDI ");
+ if( s & SELINGO ) printk("SELINGO ");
+ if( s & SWRAP ) printk("SWRAP ");
+ if( s & SDONE ) printk("SDONE ");
+ if( s & SPIORDY ) printk("SPIORDY ");
+ if( s & DMADONE ) printk("DMADONE ");
+
+ s=GETPORT(SSTAT1);
+ if( s & SELTO ) printk("SELTO ");
+ if( s & ATNTARG ) printk("ATNTARG ");
+ if( s & SCSIRSTI ) printk("SCSIRSTI ");
+ if( s & PHASEMIS ) printk("PHASEMIS ");
+ if( s & BUSFREE ) printk("BUSFREE ");
+ if( s & SCSIPERR ) printk("SCSIPERR ");
+ if( s & PHASECHG ) printk("PHASECHG ");
+ if( s & REQINIT ) printk("REQINIT ");
+ printk("); ");
+
+
+ printk("SSTAT ( ");
+
+ s=GETPORT(SSTAT0) & GETPORT(SIMODE0);
+
+ if( s & TARGET ) printk("TARGET ");
+ if( s & SELDO ) printk("SELDO ");
+ if( s & SELDI ) printk("SELDI ");
+ if( s & SELINGO ) printk("SELINGO ");
+ if( s & SWRAP ) printk("SWRAP ");
+ if( s & SDONE ) printk("SDONE ");
+ if( s & SPIORDY ) printk("SPIORDY ");
+ if( s & DMADONE ) printk("DMADONE ");
+
+ s=GETPORT(SSTAT1) & GETPORT(SIMODE1);
+
+ if( s & SELTO ) printk("SELTO ");
+ if( s & ATNTARG ) printk("ATNTARG ");
+ if( s & SCSIRSTI ) printk("SCSIRSTI ");
+ if( s & PHASEMIS ) printk("PHASEMIS ");
+ if( s & BUSFREE ) printk("BUSFREE ");
+ if( s & SCSIPERR ) printk("SCSIPERR ");
+ if( s & PHASECHG ) printk("PHASECHG ");
+ if( s & REQINIT ) printk("REQINIT ");
+ printk("); ");
+
+ printk("SXFRCTL0 ( ");
+
+ s=GETPORT(SXFRCTL0);
+ if( s & SCSIEN ) printk("SCSIEN ");
+ if( s & DMAEN ) printk("DMAEN ");
+ if( s & CH1 ) printk("CH1 ");
+ if( s & CLRSTCNT ) printk("CLRSTCNT ");
+ if( s & SPIOEN ) printk("SPIOEN ");
+ if( s & CLRCH1 ) printk("CLRCH1 ");
+ printk("); ");
+
+ printk("SIGNAL ( ");
+
+ s=GETPORT(SCSISIG);
+ if( s & ATNI ) printk("ATNI ");
+ if( s & SELI ) printk("SELI ");
+ if( s & BSYI ) printk("BSYI ");
+ if( s & REQI ) printk("REQI ");
+ if( s & ACKI ) printk("ACKI ");
+ printk("); ");
+
+ printk("SELID ( %02x ), ", GETPORT(SELID) );
+
+ printk("SSTAT2 ( ");
+
+ s=GETPORT(SSTAT2);
+ if( s & SOFFSET) printk("SOFFSET ");
+ if( s & SEMPTY) printk("SEMPTY ");
+ if( s & SFULL) printk("SFULL ");
+ printk("); ");
+
+
+ if(s & SFCNT)
+ s &= SFCNT;
+ else
+ s = (s & SEMPTY) ? 0 : 8;
+ printk("SFCNT ( %d ); ", s );
+
+#if 0
+ printk("SSTAT4 ( ");
+ s=GETPORT(SSTAT4);
+ if( s & SYNCERR) printk("SYNCERR ");
+ if( s & FWERR) printk("FWERR ");
+ if( s & FRERR) printk("FRERR ");
+ printk("); ");
+#endif
+
+ printk("FCNT ( %d ); ", GETPORT(FIFOSTAT) );
+
+ printk("DMACNTRL0 ( ");
+ s=GETPORT(DMACNTRL0);
+ printk( "%s ", s & _8BIT ? "8BIT" : "16BIT" );
+ printk( "%s ", s & DMA ? "DMA" : "PIO" );
+ printk( "%s ", s & WRITE_READ ? "WRITE" : "READ" );
+ if( s & ENDMA ) printk("ENDMA ");
+ if( s & INTEN ) printk("INTEN ");
+ if( s & RSTFIFO ) printk("RSTFIFO ");
+ if( s & SWINT ) printk("SWINT ");
+ printk("); ");
+
+
+#if 0
+ printk("DMACNTRL1 ( ");
+
+ s=GETPORT(DMACNTRL1);
+ if( s & PWRDWN ) printk("PWRDN ");
+ printk("); ");
+
+
+ printk("STK ( %d ); ", s & 0xf);
+
+ printk("DMASTAT (");
+ s=GETPORT(DMASTAT);
+ if( s & ATDONE ) printk("ATDONE ");
+ if( s & WORDRDY ) printk("WORDRDY ");
+ if( s & DFIFOFULL ) printk("DFIFOFULL ");
+ if( s & DFIFOEMP ) printk("DFIFOEMP ");
+ printk(")");
+
+#endif
+
+ printk("\n");
+#endif
+}
+
+/*
+ * display enabled interrupts
+ */
+static void disp_enintr(void)
+{
+ int s;
+
+ printk("enabled interrupts ( ");
+
+ s=GETPORT(SIMODE0);
+ if( s & ENSELDO ) printk("ENSELDO ");
+ if( s & ENSELDI ) printk("ENSELDI ");
+ if( s & ENSELINGO ) printk("ENSELINGO ");
+ if( s & ENSWRAP ) printk("ENSWRAP ");
+ if( s & ENSDONE ) printk("ENSDONE ");
+ if( s & ENSPIORDY ) printk("ENSPIORDY ");
+ if( s & ENDMADONE ) printk("ENDMADONE ");
+
+ s=GETPORT(SIMODE1);
+ if( s & ENSELTIMO ) printk("ENSELTIMO ");
+ if( s & ENATNTARG ) printk("ENATNTARG ");
+ if( s & ENPHASEMIS ) printk("ENPHASEMIS ");
+ if( s & ENBUSFREE ) printk("ENBUSFREE ");
+ if( s & ENSCSIPERR ) printk("ENSCSIPERR ");
+ if( s & ENPHASECHG ) printk("ENPHASECHG ");
+ if( s & ENREQINIT ) printk("ENREQINIT ");
+ printk(")\n");
+}
+
+#if defined(DEBUG_RACE)
+
+static const char *should_leave;
+static int in_driver=0;
+
+/*
+ * Only one routine can be in the driver at once.
+ */
+static void enter_driver(const char *func)
+{
+ cli();
+ printk("aha152x: entering %s() (%x)\n", func, jiffies);
+ if(in_driver)
+ {
+ printk("%s should leave first.\n", should_leave);
+ panic("aha152x: already in driver\n");
+ }
+
+ in_driver++;
+ should_leave=func;
+ sti();
+}
+
+static void leave_driver(const char *func)
+{
+ cli();
+ printk("\naha152x: leaving %s() (%x)\n", func, jiffies);
+ if(!in_driver)
+ {
+ printk("aha152x: %s already left.\n", should_leave);
+ panic("aha152x: %s already left driver.\n");
+ }
+
+ in_driver--;
+ should_leave=func;
+ sti();
+}
+#endif
+
+/*
+ * Show the command data of a command
+ */
+static void show_command(Scsi_Cmnd *ptr)
+{
+ int i;
+
+ printk("0x%08x: target=%d; lun=%d; cmnd=( ",
+ (unsigned long) ptr, ptr->target, ptr->lun);
+
+ for(i=0; i<COMMAND_SIZE(ptr->cmnd[0]); i++)
+ printk("%02x ", ptr->cmnd[i]);
+
+ printk("); residual=%d; buffers=%d; phase |",
+ ptr->SCp.this_residual, ptr->SCp.buffers_residual);
+
+ if( ptr->SCp.phase & not_issued ) printk("not issued|");
+ if( ptr->SCp.phase & in_selection ) printk("in selection|");
+ if( ptr->SCp.phase & disconnected ) printk("disconnected|");
+ if( ptr->SCp.phase & aborted ) printk("aborted|");
+ if( ptr->SCp.phase & sent_ident ) printk("send_ident|");
+ if( ptr->SCp.phase & in_other )
+ {
+ printk("; in other(");
+ switch( (ptr->SCp.phase >> 16) & P_MASK )
+ {
+ case P_DATAO:
+ printk("DATA OUT");
+ break;
+ case P_DATAI:
+ printk("DATA IN");
+ break;
+ case P_CMD:
+ printk("COMMAND");
+ break;
+ case P_STATUS:
+ printk("STATUS");
+ break;
+ case P_MSGO:
+ printk("MESSAGE OUT");
+ break;
+ case P_MSGI:
+ printk("MESSAGE IN");
+ break;
+ default:
+ printk("*illegal*");
+ break;
+ }
+ printk(")");
+ if(ptr->SCp.phase & (1<<16))
+ printk("; phaseend");
+ }
+ printk("; next=0x%08x\n", (unsigned long) ptr->host_scribble);
+}
+
+/*
+ * Dump the queued data
+ */
+static void show_queues(void)
+{
+ Scsi_Cmnd *ptr;
+
+ cli();
+ printk("QUEUE STATUS:\nissue_SC:\n");
+ for(ptr=issue_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble )
+ show_command(ptr);
+
+ printk("current_SC:\n");
+ if(current_SC)
+ show_command(current_SC);
+ else
+ printk("none\n");
+
+ printk("disconnected_SC:\n");
+ for(ptr=disconnected_SC; ptr; ptr = (Scsi_Cmnd *) ptr->host_scribble )
+ show_command(ptr);
+
+ disp_ports();
+ disp_enintr();
+ sti();
+}
diff --git a/drivers/scsi/aha152x.h b/drivers/scsi/aha152x.h
new file mode 100644
index 0000000..e693988
--- /dev/null
+++ b/drivers/scsi/aha152x.h
@@ -0,0 +1,334 @@
+#ifndef _AHA152X_H
+#define _AHA152X_H
+
+/*
+ * $Id: aha152x.h,v 0.2 1993/10/03 00:58:03 root Exp $
+ */
+
+#include "../block/blk.h"
+#include "scsi.h"
+#if defined(__KERNEL__)
+#include <asm/io.h>
+
+int aha152x_detect(int);
+const char *aha152x_info(void);
+int aha152x_command(Scsi_Cmnd *);
+int aha152x_queue(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int aha152x_abort(Scsi_Cmnd *, int);
+int aha152x_reset(void);
+int aha152x_biosparam(int, int, int*);
+
+/* number of queueable commands
+ (unless we support more than 1 cmd_per_lun this should do) */
+#define AHA152X_MAXQUEUE 7
+
+/* Initial value of Scsi_Host entry */
+#define AHA152X { /* name */ "Adaptec 152x SCSI driver", \
+ /* detect */ aha152x_detect, \
+ /* info */ aha152x_info, \
+ /* command */ aha152x_command, \
+ /* queuecommand */ aha152x_queue, \
+ /* abort */ aha152x_abort, \
+ /* reset */ aha152x_reset, \
+ /* slave_attach */ /* NULL */ 0, \
+ /* bios_param */ aha152x_biosparam, \
+ /* can_queue */ 1, \
+ /* this_id */ 7, \
+ /* sg_tablesize */ SG_ALL, \
+ /* cmd_per_lun */ 1, \
+ /* present */ 0, \
+ /* unchecked_isa_dma */ 0 }
+#endif
+
+
+/* port addresses */
+#define SCSISEQ (port_base+0x00) /* SCSI sequence control */
+#define SXFRCTL0 (port_base+0x01) /* SCSI transfer control 0 */
+#define SXFRCTL1 (port_base+0x02) /* SCSI transfer control 1 */
+#define SCSISIG (port_base+0x03) /* SCSI signal in/out */
+#define SCSIRATE (port_base+0x04) /* SCSI rate control */
+#define SELID (port_base+0x05) /* selection/reselection ID */
+#define SCSIID SELID /* SCSI ID */
+#define SCSIDAT (port_base+0x06) /* SCSI latched data */
+#define SCSIBUS (port_base+0x07) /* SCSI data bus */
+#define STCNT0 (port_base+0x08) /* SCSI transfer count 0 */
+#define STCNT1 (port_base+0x09) /* SCSI transfer count 1 */
+#define STCNT2 (port_base+0x0a) /* SCSI transfer count 2 */
+#define SSTAT0 (port_base+0x0b) /* SCSI interrupt status 0 */
+#define SSTAT1 (port_base+0x0c) /* SCSI interrupt status 1 */
+#define SSTAT2 (port_base+0x0d) /* SCSI interrupt status 2 */
+#define SCSITEST (port_base+0x0e) /* SCSI test control */
+#define SSTAT4 (port_base+0x0f) /* SCSI status 4 */
+#define SIMODE0 (port_base+0x10) /* SCSI interrupt mode 0 */
+#define SIMODE1 (port_base+0x11) /* SCSI interrupt mode 1 */
+#define DMACNTRL0 (port_base+0x12) /* DMA control 0 */
+#define DMACNTRL1 (port_base+0x13) /* DMA control 1 */
+#define DMASTAT (port_base+0x14) /* DMA status */
+#define FIFOSTAT (port_base+0x15) /* FIFO status */
+#define DATAPORT (port_base+0x16) /* DATA port */
+#define BRSTCNTRL (port_base+0x18) /* burst control */
+#define PORTA (port_base+0x1a) /* PORT A */
+#define PORTB (port_base+0x1b) /* PORT B */
+#define REV (port_base+0x1c) /* revision */
+#define STACK (port_base+0x1d) /* stack */
+#define TEST (port_base+0x1e) /* test register */
+
+
+/* bits and bitmasks to ports */
+
+/* SCSI sequence control */
+#define TEMODEO 0x80
+#define ENSELO 0x40
+#define ENSELI 0x20
+#define ENRESELI 0x10
+#define ENAUTOATNO 0x08
+#define ENAUTOATNI 0x04
+#define ENAUTOATNP 0x02
+#define SCSIRSTO 0x01
+
+/* SCSI transfer control 0 */
+#define SCSIEN 0x80
+#define DMAEN 0x40
+#define CH1 0x20
+#define CLRSTCNT 0x10
+#define SPIOEN 0x08
+#define CLRCH1 0x02
+
+/* SCSI transfer control 1 */
+#define BITBUCKET 0x80
+#define SWRAPEN 0x40
+#define ENSPCHK 0x20
+#define STIMESEL 0x18 /* mask */
+#define STIMESEL_ 3
+#define ENSTIMER 0x04
+#define BYTEALIGN 0x02
+
+/* SCSI signal IN */
+#define CDI 0x80
+#define IOI 0x40
+#define MSGI 0x20
+#define ATNI 0x10
+#define SELI 0x08
+#define BSYI 0x04
+#define REQI 0x02
+#define ACKI 0x01
+
+/* SCSI Phases */
+#define P_MASK (MSGI|CDI|IOI)
+#define P_DATAO (0)
+#define P_DATAI (IOI)
+#define P_CMD (CDI)
+#define P_STATUS (CDI|IOI)
+#define P_MSGO (MSGI|CDI)
+#define P_MSGI (MSGI|CDI|IOI)
+
+/* SCSI signal OUT */
+#define CDO 0x80
+#define IOO 0x40
+#define MSGO 0x20
+#define ATNO 0x10
+#define SELO 0x08
+#define BSYO 0x04
+#define REQO 0x02
+#define ACKO 0x01
+
+/* SCSI rate control */
+#define SXFR 0x70 /* mask */
+#define SXFR_ 4
+#define SOFS 0x0f /* mask */
+
+/* SCSI ID */
+#define OID 0x70
+#define OID_ 4
+#define TID 0x07
+
+/* SCSI transfer count */
+#define GETSTCNT() ( (GETPORT(STCNT2)<<16) \
+ + (GETPORT(STCNT1)<< 8) \
+ + GETPORT(STCNT0) )
+
+#define SETSTCNT(X) { SETPORT(STCNT2, ((X) & 0xFF0000) >> 16); \
+ SETPORT(STCNT1, ((X) & 0x00FF00) >> 8); \
+ SETPORT(STCNT0, ((X) & 0x0000FF) ); }
+
+/* SCSI interrupt status */
+#define TARGET 0x80
+#define SELDO 0x40
+#define SELDI 0x20
+#define SELINGO 0x10
+#define SWRAP 0x08
+#define SDONE 0x04
+#define SPIORDY 0x02
+#define DMADONE 0x01
+
+#define SETSDONE 0x80
+#define CLRSELDO 0x40
+#define CLRSELDI 0x20
+#define CLRSELINGO 0x10
+#define CLRSWRAP 0x08
+#define CLRSDONE 0x04
+#define CLRSPIORDY 0x02
+#define CLRDMADONE 0x01
+
+/* SCSI status 1 */
+#define SELTO 0x80
+#define ATNTARG 0x40
+#define SCSIRSTI 0x20
+#define PHASEMIS 0x10
+#define BUSFREE 0x08
+#define SCSIPERR 0x04
+#define PHASECHG 0x02
+#define REQINIT 0x01
+
+#define CLRSELTIMO 0x80
+#define CLRATNO 0x40
+#define CLRSCSIRSTI 0x20
+#define CLRBUSFREE 0x08
+#define CLRSCSIPERR 0x04
+#define CLRPHASECHG 0x02
+#define CLRREQINIT 0x01
+
+/* SCSI status 2 */
+#define SOFFSET 0x20
+#define SEMPTY 0x10
+#define SFULL 0x08
+#define SFCNT 0x07 /* mask */
+
+/* SCSI status 3 */
+#define SCSICNT 0xf0 /* mask */
+#define SCSICNT_ 4
+#define OFFCNT 0x0f /* mask */
+
+/* SCSI TEST control */
+#define SCTESTU 0x08
+#define SCTESTD 0x04
+#define STCTEST 0x01
+
+/* SCSI status 4 */
+#define SYNCERR 0x04
+#define FWERR 0x02
+#define FRERR 0x01
+
+#define CLRSYNCERR 0x04
+#define CLRFWERR 0x02
+#define CLRFRERR 0x01
+
+/* SCSI interrupt mode 0 */
+#define ENSELDO 0x40
+#define ENSELDI 0x20
+#define ENSELINGO 0x10
+#define ENSWRAP 0x08
+#define ENSDONE 0x04
+#define ENSPIORDY 0x02
+#define ENDMADONE 0x01
+
+/* SCSI interrupt mode 1 */
+#define ENSELTIMO 0x80
+#define ENATNTARG 0x40
+#define ENSCSIRST 0x20
+#define ENPHASEMIS 0x10
+#define ENBUSFREE 0x08
+#define ENSCSIPERR 0x04
+#define ENPHASECHG 0x02
+#define ENREQINIT 0x01
+
+/* DMA control 0 */
+#define ENDMA 0x80
+#define _8BIT 0x40
+#define DMA 0x20
+#define WRITE_READ 0x08
+#define INTEN 0x04
+#define RSTFIFO 0x02
+#define SWINT 0x01
+
+/* DMA control 1 */
+#define PWRDWN 0x80
+#define STK 0x07 /* mask */
+
+/* DMA status */
+#define ATDONE 0x80
+#define WORDRDY 0x40
+#define INTSTAT 0x20
+#define DFIFOFULL 0x10
+#define DFIFOEMP 0x08
+
+/* BURST control */
+#define BON 0xf0
+#define BOFF 0x0f
+
+/* TEST REGISTER */
+#define BOFFTMR 0x40
+#define BONTMR 0x20
+#define STCNTH 0x10
+#define STCNTM 0x08
+#define STCNTL 0x04
+#define SCSIBLK 0x02
+#define DMABLK 0x01
+
+/* On the AHA-152x board PORTA and PORTB contain
+ some information about the board's configuration. */
+typedef union {
+ struct {
+ unsigned reserved:2; /* reserved */
+ unsigned tardisc:1; /* Target disconnect: 0=disabled, 1=enabled */
+ unsigned syncneg:1; /* Initial sync neg: 0=disabled, 1=enabled */
+ unsigned msgclasses:2; /* Message classes
+ 0=#4
+ 1=#0, #1, #2, #3, #4
+ 2=#0, #3, #4
+ 3=#0, #4
+ */
+ unsigned boot:1; /* boot: 0=disabled, 1=enabled */
+ unsigned dma:1; /* Transfer mode: 0=PIO; 1=DMA */
+ unsigned id:3; /* SCSI-id */
+ unsigned irq:2; /* IRQ-Channel: 0,3=12, 1=10, 2=11 */
+ unsigned dmachan:2; /* DMA-Channel: 0=0, 1=5, 2=6, 3=7 */
+ unsigned parity:1; /* SCSI-parity: 1=enabled 0=disabled */
+ } fields;
+ unsigned short port;
+} aha152x_config ;
+
+#define cf_parity fields.parity
+#define cf_dmachan fields.dmachan
+#define cf_irq fields.irq
+#define cf_id fields.id
+#define cf_dma fields.dma
+#define cf_boot fields.boot
+#define cf_msgclasses fields.msgclasses
+#define cf_syncneg fields.syncneg
+#define cf_tardisc fields.tardisc
+#define cf_port port
+
+/* Some macros to manipulate ports and their bits */
+
+#define SETPORT(PORT, VAL) \
+ outb( (VAL), (PORT) )
+
+#define SETPORTP(PORT, VAL) \
+ outb_p( (VAL), (PORT) )
+
+#define SETPORTW(PORT, VAL) \
+ outw( (VAL), (PORT) )
+
+#define GETPORT(PORT) \
+ inb( PORT )
+
+#define GETPORTW(PORT) \
+ inw( PORT )
+
+#define SETBITS(PORT, BITS) \
+ outb( (inb(PORT) | (BITS)), (PORT) )
+
+#define CLRBITS(PORT, BITS) \
+ outb( (inb(PORT) & ~(BITS)), (PORT) )
+
+#define CLRSETBITS(PORT, CLR, SET) \
+ outb( (inb(PORT) & ~(CLR)) | (SET) , (PORT) )
+
+#define TESTHI(PORT, BITS) \
+ ((inb(PORT) & (BITS)) == BITS)
+
+#define TESTLO(PORT, BITS) \
+ ((inb(PORT) & (BITS)) == 0)
+
+#endif /* _AHA152X_H */
diff --git a/kernel/blk_drv/scsi/aha1542.c b/drivers/scsi/aha1542.c
index 2e06f45..c905002 100644
--- a/kernel/blk_drv/scsi/aha1542.c
+++ b/drivers/scsi/aha1542.c
@@ -22,7 +22,7 @@
#include <asm/system.h>
#include <asm/io.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
@@ -44,34 +44,33 @@ card, which also used 0x330 */
static unsigned int bases[]={0x330, 0x334};
-static unsigned int base;
-static unsigned char dma_chan;
-static unsigned char irq_level;
-
-static int aha_disable = 0;
-
/* The DMA-Controller. We need to fool with this because we want to
be able to use the aha1542 without having to have the bios enabled */
#define DMA_MODE_REG 0xd6
#define DMA_MASK_REG 0xd4
#define CASCADE 0xc0
-static struct mailbox mb[2*AHA1542_MAILBOXES];
-static struct ccb ccb[AHA1542_MAILBOXES];
+struct aha1542_hostdata{
+ /* This will effectively start both of them at the first mailbox */
+ int aha1542_last_mbi_used;
+ int aha1542_last_mbo_used;
+ Scsi_Cmnd * SCint[AHA1542_MAILBOXES];
+ struct mailbox mb[2*AHA1542_MAILBOXES];
+ struct ccb ccb[AHA1542_MAILBOXES];
+};
+
+#define HOSTDATA(host) ((struct aha1542_hostdata *) &host->hostdata)
-static Scsi_Cmnd * SCint[AHA1542_MAILBOXES] = {NULL, };
+static struct Scsi_Host * aha_host[7] = {NULL,}; /* One for each IRQ level (9-15) */
-/* This will effectively start both of them at the first mailbox */
-static int aha1542_last_mbi_used = (2*AHA1542_MAILBOXES - 1);
-static int aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
-static long WAITnexttimeout = 3000000;
-static int aha1542_host = 0;
-static void setup_mailboxes(void);
+#define WAITnexttimeout 3000000
-#define aha1542_intr_reset() outb(IRST, CONTROL)
+static void setup_mailboxes(int base_io, struct Scsi_Host * shpnt);
+
+#define aha1542_intr_reset(base) outb(IRST, CONTROL(base))
#define WAIT(port, mask, allof, noneof) \
{ register WAITbits; \
@@ -90,12 +89,12 @@ static void aha1542_stat(void)
printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */
}
-static int aha1542_out(unchar *cmdp, int len)
+static int aha1542_out(unsigned int base, unchar *cmdp, int len)
{
while (len--)
{
- WAIT(STATUS, CDF, 0, CDF);
- outb(*cmdp++, DATA);
+ WAIT(STATUS(base), CDF, 0, CDF);
+ outb(*cmdp++, DATA(base));
}
return 0;
fail:
@@ -103,19 +102,20 @@ static int aha1542_out(unchar *cmdp, int len)
return 1;
}
-static int aha1542_in(unchar *cmdp, int len)
+static int aha1542_in(unsigned int base, unchar *cmdp, int len)
{
while (len--)
{
- WAIT(STATUS, DF, DF, 0);
- *cmdp++ = inb(DATA);
+ WAIT(STATUS(base), DF, DF, 0);
+ *cmdp++ = inb(DATA(base));
}
return 0;
fail:
printk("aha1542_in failed(%d): ", len+1); aha1542_stat();
return 1;
}
-int makecode(unsigned hosterr, unsigned scsierr)
+
+static int makecode(unsigned hosterr, unsigned scsierr)
{
switch (hosterr) {
case 0x0:
@@ -154,6 +154,7 @@ int makecode(unsigned hosterr, unsigned scsierr)
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. */
+ DEB(printk("Aha1542: %x %x\n", hosterr, scsierr));
hosterr = DID_ERROR; /* Couldn't find any better */
break;
@@ -170,58 +171,60 @@ int makecode(unsigned hosterr, unsigned scsierr)
return scsierr|(hosterr << 16);
}
-int aha1542_test_port(int bse)
+static int aha1542_test_port(int bse, struct Scsi_Host * shpnt)
{
volatile int debug = 0;
- base = bse;
+ /* Quick and dirty test for presence of the card. */
+ if(inb(STATUS(bse)) == 0xff) return 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(HRST|IRST/*|SCRST*/, CONTROL);
+ outb(SRST|IRST/*|SCRST*/, CONTROL(bse));
debug = 1;
/* Expect INIT and IDLE, any of the others are bad */
- WAIT(STATUS, STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
+ WAIT(STATUS(bse), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF);
debug = 2;
/* Shouldn't have generated any interrupts during reset */
- if (inb(INTRFLAGS)&INTRMASK) goto fail;
- setup_mailboxes();
+ if (inb(INTRFLAGS(bse))&INTRMASK) goto fail;
+ setup_mailboxes(bse, shpnt);
debug = 3;
/* Test the basic ECHO command */
- outb(CMD_ECHO, DATA);
+ outb(CMD_ECHO, DATA(bse));
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);
+ WAIT(STATUS(bse), STATMASK, 0, STST|DIAGF|INVDCMD|DF|CDF);
debug = 5;
/* The meaning of life */
- outb(42, DATA);
+ outb(42, DATA(bse));
debug = 6;
/* Expect only DF, that is, data ready */
- WAIT(STATUS, STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
+ WAIT(STATUS(bse), STATMASK, DF, STST|DIAGF|CDF|INVDCMD);
debug = 7;
/* Is the answer correct? */
- if (inb(DATA) != 42) goto fail;
+ if (inb(DATA(bse)) != 42) goto fail;
debug = 8;
/* Reading port should reset DF */
- if (inb(STATUS) & DF) goto fail;
+ if (inb(STATUS(bse)) & DF) goto fail;
debug = 9;
/* When HACC, command is completed, and we're though testing */
- WAIT(INTRFLAGS, HACC, HACC, 0);
+ WAIT(INTRFLAGS(bse), HACC, HACC, 0);
/* now initialize adapter */
debug = 10;
/* Clear interrupts */
- outb(IRST, CONTROL);
+ outb(IRST, CONTROL(bse));
debug = 11;
@@ -230,47 +233,62 @@ int aha1542_test_port(int bse)
return 0; /* 0 = not ok */
}
+static const char aha_ident[] = "Adaptec 1542";
+
/* What's this little function for? */
const char *aha1542_info(void)
{
- static char buffer[] = "Adaptec 1542";
- return buffer;
+ return aha_ident;
}
/* A "high" level interrupt handler */
-void aha1542_intr_handle(int foo)
+static void aha1542_intr_handle(int foo)
{
void (*my_done)(Scsi_Cmnd *) = NULL;
int errstatus, mbi, mbo, mbistatus;
int number_serviced;
+ struct Scsi_Host * shost;
Scsi_Cmnd * SCtmp;
+ int irqno, * irqp;
+ struct mailbox * mb;
+ struct ccb *ccb;
+
+ irqp = (int *) foo;
+ irqp -= 2; /* Magic - this is only required for slow interrupt handlers */
+ irqno = *irqp;
+
+ shost = aha_host[irqno - 9];
+ mb = HOSTDATA(shost)->mb;
+ ccb = HOSTDATA(shost)->ccb;
+
+ if(!shost) panic("Splunge!");
#ifdef DEBUG
{
- int flag = inb(INTRFLAGS);
+ int flag = inb(INTRFLAGS(shost->io_port));
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));
+ printk("status %02x\n", inb(STATUS(shost->io_port)));
};
#endif
number_serviced = 0;
while(1==1){
- aha1542_intr_reset();
+ aha1542_intr_reset(shost->io_port);
cli();
- mbi = aha1542_last_mbi_used + 1;
+ mbi = HOSTDATA(shost)->aha1542_last_mbi_used + 1;
if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
do{
if(mb[mbi].status != 0) break;
mbi++;
if (mbi >= 2*AHA1542_MAILBOXES) mbi = AHA1542_MAILBOXES;
- } while (mbi != aha1542_last_mbi_used);
+ } while (mbi != HOSTDATA(shost)->aha1542_last_mbi_used);
if(mb[mbi].status == 0){
sti();
@@ -283,7 +301,7 @@ void aha1542_intr_handle(int foo)
mbo = (scsi2int(mb[mbi].ccbptr) - ((unsigned int) &ccb[0])) / sizeof(struct ccb);
mbistatus = mb[mbi].status;
mb[mbi].status = 0;
- aha1542_last_mbi_used = mbi;
+ HOSTDATA(shost)->aha1542_last_mbi_used = mbi;
sti();
#ifdef DEBUG
@@ -300,7 +318,7 @@ void aha1542_intr_handle(int foo)
printk("...done %d %d\n",mbo, mbi);
#endif
- SCtmp = SCint[mbo];
+ SCtmp = HOSTDATA(shost)->SCint[mbo];
if (!SCtmp || !SCtmp->scsi_done) {
printk("aha1542_intr_handle: Unexpected interrupt\n");
@@ -351,7 +369,7 @@ void aha1542_intr_handle(int foo)
}
DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus));
SCtmp->result = errstatus;
- SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as
+ HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as
far as queuecommand is concerned */
my_done(SCtmp);
number_serviced++;
@@ -368,9 +386,14 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
void *buff = SCpnt->request_buffer;
int bufflen = SCpnt->request_bufflen;
int mbo;
+ struct mailbox * mb;
+ struct ccb *ccb;
DEB(int i);
+ mb = HOSTDATA(SCpnt->host)->mb;
+ ccb = HOSTDATA(SCpnt->host)->ccb;
+
DEB(if (target > 1) {
SCpnt->result = DID_TIME_OUT << 16;
done(SCpnt); return 0;});
@@ -409,23 +432,23 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
is how the host adapter will scan for them */
cli();
- mbo = aha1542_last_mbo_used + 1;
+ mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1;
if (mbo >= AHA1542_MAILBOXES) mbo = 0;
do{
- if(mb[mbo].status == 0 && SCint[mbo] == NULL)
+ if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL)
break;
mbo++;
if (mbo >= AHA1542_MAILBOXES) mbo = 0;
- } while (mbo != aha1542_last_mbo_used);
+ } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used);
- if(mb[mbo].status || SCint[mbo])
+ if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo])
panic("Unable to find empty mailbox for aha1542.\n");
- SCint[mbo] = SCpnt; /* This will effectively prevent someone else from
+ HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from
screwing with this cdb. */
- aha1542_last_mbo_used = mbo;
+ HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo;
sti();
#ifdef DEBUG
@@ -464,10 +487,10 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
unsigned char * ptr;
printk("Bad segment list supplied to aha1542.c (%d, %d)\n",SCpnt->use_sg,i);
for(i=0;i<SCpnt->use_sg++;i++){
- printk("%d: %x %x %d\n",i,sgpnt[i].address, sgpnt[i].alt_address,
+ printk("%d: %x %x %d\n",i,(unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address,
sgpnt[i].length);
};
- printk("cptr %x: ",cptr);
+ printk("cptr %x: ",(unsigned int) cptr);
ptr = (unsigned char *) &cptr[i];
for(i=0;i<18;i++) printk("%02x ", ptr[i]);
panic("Foooooooood fight!");
@@ -507,7 +530,7 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat());
SCpnt->scsi_done = done;
mb[mbo].status = 1;
- aha1542_out(&ahacmd, 1); /* start scsi command */
+ aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */
DEB(aha1542_stat());
}
else
@@ -518,12 +541,9 @@ int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *))
panic("Buffer at address > 16Mb used for 1542B");
}
-static volatile int internal_done_flag = 0;
-static volatile int internal_done_errcode = 0;
static void internal_done(Scsi_Cmnd * SCpnt)
{
- internal_done_errcode = SCpnt->result;
- ++internal_done_flag;
+ SCpnt->SCp.Status++;
}
int aha1542_command(Scsi_Cmnd * SCpnt)
@@ -532,58 +552,64 @@ int aha1542_command(Scsi_Cmnd * SCpnt)
aha1542_queuecommand(SCpnt, internal_done);
- while (!internal_done_flag);
- internal_done_flag = 0;
- return internal_done_errcode;
+ SCpnt->SCp.Status = 0;
+ while (!SCpnt->SCp.Status);
+ return SCpnt->result;
}
/* Initialize mailboxes */
-static void setup_mailboxes(void)
+static void setup_mailboxes(int bse, struct Scsi_Host * shpnt)
{
int i;
- static unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES};
+ struct mailbox * mb;
+ struct ccb *ccb;
+
+ unchar cmd[5] = {CMD_MBINIT, AHA1542_MAILBOXES};
+
+ mb = HOSTDATA(shpnt)->mb;
+ ccb = HOSTDATA(shpnt)->ccb;
for(i=0; i<AHA1542_MAILBOXES; i++){
mb[i].status = mb[AHA1542_MAILBOXES+i].status = 0;
any2scsi(mb[i].ccbptr, &ccb[i]);
};
- aha1542_intr_reset(); /* reset interrupts, so they don't block */
+ aha1542_intr_reset(bse); /* reset interrupts, so they don't block */
any2scsi((cmd+2), mb);
- aha1542_out(cmd, 5);
- WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+ aha1542_out(bse, cmd, 5);
+ WAIT(INTRFLAGS(bse), INTRMASK, HACC, 0);
while (0) {
fail:
printk("aha1542_detect: failed setting up mailboxes\n");
}
- aha1542_intr_reset();
+ aha1542_intr_reset(bse);
}
-static int aha1542_getconfig(int hostnum)
+static int aha1542_getconfig(int base_io, unsigned char * irq_level, unsigned char * dma_chan)
{
- static unchar inquiry_cmd[] = {CMD_RETCONF };
- static unchar inquiry_result[3];
+ unchar inquiry_cmd[] = {CMD_RETCONF };
+ unchar inquiry_result[3];
int i;
- i = inb(STATUS);
+ i = inb(STATUS(base_io));
if (i & DF) {
- i = inb(DATA);
+ i = inb(DATA(base_io));
};
- aha1542_out(inquiry_cmd, 1);
- aha1542_in(inquiry_result, 3);
- WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+ aha1542_out(base_io, inquiry_cmd, 1);
+ aha1542_in(base_io, inquiry_result, 3);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
while (0) {
fail:
printk("aha1542_detect: query board settings\n");
}
- aha1542_intr_reset();
+ aha1542_intr_reset(base_io);
switch(inquiry_result[0]){
case 0x80:
- dma_chan = 7;
+ *dma_chan = 7;
break;
case 0x40:
- dma_chan = 6;
+ *dma_chan = 6;
break;
case 0x20:
- dma_chan = 5;
+ *dma_chan = 5;
break;
case 0x01:
printk("DMA priority 0 not available for Adaptec driver\n");
@@ -591,7 +617,7 @@ static int aha1542_getconfig(int hostnum)
case 0:
/* This means that the adapter, although Adaptec 1542 compatible, doesn't use a DMA channel.
Currently only aware of the BusLogic BT-445S VL-Bus adapter which needs this. */
- dma_chan = 0xFF;
+ *dma_chan = 0xFF;
break;
default:
printk("Unable to determine Adaptec DMA priority. Disabling board\n");
@@ -599,22 +625,22 @@ static int aha1542_getconfig(int hostnum)
};
switch(inquiry_result[1]){
case 0x40:
- irq_level = 15;
+ *irq_level = 15;
break;
case 0x20:
- irq_level = 14;
+ *irq_level = 14;
break;
case 0x8:
- irq_level = 12;
+ *irq_level = 12;
break;
case 0x4:
- irq_level = 11;
+ *irq_level = 11;
break;
case 0x2:
- irq_level = 10;
+ *irq_level = 10;
break;
case 0x1:
- irq_level = 9;
+ *irq_level = 9;
break;
default:
printk("Unable to determine Adaptec IRQ level. Disabling board\n");
@@ -624,23 +650,23 @@ static int aha1542_getconfig(int hostnum)
}
/* Query the board to find out if it is a 1542 or a 1740, or whatever. */
-static void aha1542_query(int hostnum)
+static int aha1542_query(int base_io)
{
- static unchar inquiry_cmd[] = {CMD_INQUIRY };
- static unchar inquiry_result[4];
+ unchar inquiry_cmd[] = {CMD_INQUIRY };
+ unchar inquiry_result[4];
int i;
- i = inb(STATUS);
+ i = inb(STATUS(base_io));
if (i & DF) {
- i = inb(DATA);
+ i = inb(DATA(base_io));
};
- aha1542_out(inquiry_cmd, 1);
- aha1542_in(inquiry_result, 4);
- WAIT(INTRFLAGS, INTRMASK, HACC, 0);
+ aha1542_out(base_io, inquiry_cmd, 1);
+ aha1542_in(base_io, inquiry_result, 4);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
while (0) {
fail:
printk("aha1542_detect: query card type\n");
}
- aha1542_intr_reset();
+ aha1542_intr_reset(base_io);
/* For an AHA1740 series board, we ignore the board since there is a
hardware bug which can lead to wrong blocks being returned if the board
@@ -650,117 +676,133 @@ static void aha1542_query(int hostnum)
if (inquiry_result[0] == 0x43) {
printk("aha1542.c: Emulation mode not supported for AHA 174N hardware.\n");
- aha_disable = 1;
+ return 1;
};
+ return 0;
}
/* return non-zero on detection */
int aha1542_detect(int hostnum)
{
- int i;
+ unsigned char dma_chan;
+ unsigned char irq_level;
+ unsigned int base_io;
+ struct Scsi_Host * shpnt = NULL;
+ int count = 0;
int indx;
DEB(printk("aha1542_detect: \n"));
- indx = 0;
- while(indx < sizeof(bases)/sizeof(bases[0])){
- if(!check_region(bases[indx], 4)){
- i = aha1542_test_port(bases[indx]);
- if (i) break;
- };
- indx++;
- }
- if (indx == sizeof(bases)/sizeof(bases[0])) return 0;
-
- /* Set the Bus on/off-times as not to ruin floppy performance */
- {
- static unchar oncmd[] = {CMD_BUSON_TIME, 7};
- static unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
-
- 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_query(hostnum);
-
- if (aha_disable) return 0;
-
- if (aha1542_getconfig(hostnum) == -1) return 0;
-
- printk("Configuring Adaptec at IO:%x, IRQ %d",base, irq_level);
- if (dma_chan != 0xFF)
- printk(", DMA priority %d", dma_chan);
- printk("\n");
-
- DEB(aha1542_stat());
- setup_mailboxes();
-
- DEB(aha1542_stat());
-
- DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
-
- if (request_irq(irq_level,aha1542_intr_handle)) {
- printk("Unable to allocate IRQ for adaptec controller.\n");
- return 0;
- }
-
- if (dma_chan != 0xFF) {
- if (request_dma(dma_chan)) {
- printk("Unable to allocate DMA channel for Adaptec.\n");
- free_irq(irq_level);
- return 0;
- }
-
- if (dma_chan >= 5) {
- outb((dma_chan - 4) | CASCADE, DMA_MODE_REG);
- outb(dma_chan - 4, DMA_MASK_REG);
- }
- }
-
+ for(indx = 0; indx < sizeof(bases)/sizeof(bases[0]); indx++)
+ if(!check_region(bases[indx], 4)) {
+ shpnt = scsi_register(hostnum,
+ sizeof(struct aha1542_hostdata));
+
+ if(!aha1542_test_port(bases[indx], shpnt)) goto unregister;
+
+
+ base_io = bases[indx];
+
+ /* Set the Bus on/off-times as not to ruin floppy performance */
+ {
+ unchar oncmd[] = {CMD_BUSON_TIME, 7};
+ unchar offcmd[] = {CMD_BUSOFF_TIME, 5};
+
+ aha1542_intr_reset(base_io);
+ aha1542_out(base_io, oncmd, 2);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ aha1542_intr_reset(base_io);
+ aha1542_out(base_io, offcmd, 2);
+ WAIT(INTRFLAGS(base_io), INTRMASK, HACC, 0);
+ while (0) {
+ fail:
+ printk("aha1542_detect: setting bus on/off-time failed\n");
+ }
+ aha1542_intr_reset(base_io);
+ }
+ if(aha1542_query(base_io)) goto unregister;
+
+ if (aha1542_getconfig(base_io, &irq_level, &dma_chan) == -1) goto unregister;
+
+ printk("Configuring Adaptec at IO:%x, IRQ %d",base_io, irq_level);
+ if (dma_chan != 0xFF)
+ printk(", DMA priority %d", dma_chan);
+ printk("\n");
+
+ DEB(aha1542_stat());
+ setup_mailboxes(base_io, shpnt);
+
+ DEB(aha1542_stat());
+
+ DEB(printk("aha1542_detect: enable interrupt channel %d\n", irq_level));
+
+ if (request_irq(irq_level,aha1542_intr_handle)) {
+ printk("Unable to allocate IRQ for adaptec controller.\n");
+ goto unregister;
+ }
+
+ if (dma_chan != 0xFF) {
+ if (request_dma(dma_chan)) {
+ printk("Unable to allocate DMA channel for Adaptec.\n");
+ free_irq(irq_level);
+ goto unregister;
+ }
+
+ if (dma_chan >= 5) {
+ outb((dma_chan - 4) | CASCADE, DMA_MODE_REG);
+ outb(dma_chan - 4, DMA_MASK_REG);
+ }
+ }
+
+ aha_host[irq_level - 9] = shpnt;
+ shpnt->io_port = base_io;
+ shpnt->dma_channel = dma_chan;
+ shpnt->irq = irq_level;
+ HOSTDATA(shpnt)->aha1542_last_mbi_used = (2*AHA1542_MAILBOXES - 1);
+ HOSTDATA(shpnt)->aha1542_last_mbo_used = (AHA1542_MAILBOXES - 1);
+ memset(HOSTDATA(shpnt)->SCint, 0, sizeof(HOSTDATA(shpnt)->SCint));
#if 0
- 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
- snarf_region(bases[indx], 4); /* Register the IO ports that we use */
- aha1542_host = hostnum;
- return 1;
+ 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
+ snarf_region(bases[indx], 4); /* Register the IO ports that we use */
+ count++;
+ continue;
+ unregister:
+ scsi_unregister(shpnt, sizeof(struct aha1542_hostdata));
+ continue;
+
+ };
+ return count;
}
/* The abort command does not leave the device in a clean state where
@@ -777,7 +819,7 @@ int aha1542_abort(Scsi_Cmnd * SCpnt, int i)
#if 0
cli();
for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++)
- if (SCpnt == SCint[mbo]){
+ if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){
mb[mbo].status = 2; /* Abort command */
aha1542_out(&ahacmd, 1); /* start scsi command */
sti();
diff --git a/kernel/blk_drv/scsi/aha1542.h b/drivers/scsi/aha1542.h
index 10131d6..4992ffe 100644
--- a/kernel/blk_drv/scsi/aha1542.h
+++ b/drivers/scsi/aha1542.h
@@ -35,7 +35,7 @@
/* I/O Port interface 4.2 */
/* READ */
-#define STATUS base
+#define STATUS(base) base
#define STST 0x80 /* Self Test in Progress */
#define DIAGF 0x40 /* Internal Diagonostic Failure */
#define INIT 0x20 /* Mailbox Initialization Required */
@@ -45,7 +45,7 @@
#define INVDCMD 0x01 /* Invalid H A Command */
#define STATMASK 0xfd /* 0x02 is reserved */
-#define INTRFLAGS STATUS+2
+#define INTRFLAGS(base) (STATUS(base)+2)
#define ANYINTR 0x80 /* Any Interrupt */
#define SCRD 0x08 /* SCSI Reset Detected */
#define HACC 0x04 /* HA Command Complete */
@@ -54,14 +54,14 @@
#define INTRMASK 0x8f
/* WRITE */
-#define CONTROL STATUS
+#define CONTROL(base) STATUS(base)
#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 DATA(base) (STATUS(base)+1)
#define CMD_NOP 0x00 /* No Operation */
#define CMD_MBINIT 0x01 /* Mailbox Initialization */
#define CMD_START_SCSI 0x02 /* Start SCSI Command */
diff --git a/kernel/blk_drv/scsi/aha1740.c b/drivers/scsi/aha1740.c
index 1325cdc..5ddc028 100644
--- a/kernel/blk_drv/scsi/aha1740.c
+++ b/drivers/scsi/aha1740.c
@@ -28,7 +28,7 @@
#include <asm/system.h>
#include <asm/io.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
diff --git a/kernel/blk_drv/scsi/aha1740.h b/drivers/scsi/aha1740.h
index ec25861..ec25861 100644
--- a/kernel/blk_drv/scsi/aha1740.h
+++ b/drivers/scsi/aha1740.h
diff --git a/kernel/blk_drv/scsi/constants.c b/drivers/scsi/constants.c
index 031a06c..157c5bd 100644
--- a/kernel/blk_drv/scsi/constants.c
+++ b/drivers/scsi/constants.c
@@ -4,18 +4,15 @@
*/
#include <linux/config.h>
-#ifdef CONFIG_SCSI
-#include "../blk.h"
+#include "../block/blk.h"
#include <linux/kernel.h>
#include "scsi.h"
-static const char reserved[] = "RESERVED";
-static const char unknown[] = "UNKNOWN";
-static const char vendor[] = "VENDOR SPECIFIC";
#define CONST_COMMAND 0x01
#define CONST_STATUS 0x02
#define CONST_SENSE 0x04
#define CONST_XSENSE 0x08
+static const char unknown[] = "UNKNOWN";
#ifdef CONFIG_SCSI_CONSTANTS
#ifdef CONSTANTS
@@ -72,6 +69,8 @@ group_0_commands, group_1_commands, group_2_commands,
(const char **) NOTEXT_GROUP, (const char **) VENDOR_GROUP,
(const char **) VENDOR_GROUP};
+static const char reserved[] = "RESERVED";
+static const char vendor[] = "VENDOR SPECIFIC";
static void print_opcode(int opcode) {
char **table = commands[ group(opcode) ];
@@ -121,18 +120,6 @@ void print_status (int status) {
#endif
}
-#if (CONSTANTS & CONST_MSG)
-static const char * msgs[] = {
-};
-void print_msg (int msg) {
- printk("%s ", msgs[msg]);
-}
-#else
-void print_msg (int msg) {
- printk("0x%02x ", msg);
-}
-#endif
-
#if (CONSTANTS & CONST_XSENSE)
#define D 0x001 /* DIRECT ACCESS DEVICE (disk) */
#define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */
@@ -456,5 +443,87 @@ void print_sense(char * devclass, Scsi_Cmnd * SCpnt)
return;
}
+#if (CONSTANTS & CONST_MSG)
+static const char *one_byte_msgs[] = {
+/* 0x00 */ "Command Complete", NULL, "Save Pointers",
+/* 0x03 */ "Restore Pointers", "Disconnect", "Initiator Error",
+/* 0x06 */ "Abort", "Message Reject", "Nop", "Message Parity Error",
+/* 0x0a */ "Linked Command Complete", "Linked Command Complete w/flag",
+/* 0x0c */ "Bus device reset", "Abort Tag", "Clear Queue",
+/* 0x0f */ "Initiate Recovery", "Release Recovery"
+}
+
+#define NO_ONE_BYTE_MSGS (sizeof(one_byte_msgs) / sizeof (const char *))
-#endif CONFIG_SCSI
+static const char *queue_tag_msgs[] = {
+/* 0x20 */ "Simple Queue Tag", "Head of Queue Tag", "Ordered Queue Tag"
+/* 0x23 */ "Ignore Wide Residue"
+}
+
+#define NO_TWO_BYTE_MSGS (sizeof(two_byte_msgs) / sizeof (const char *))
+
+static const char *extended_msgs[] = {
+/* 0x00 */ "Modify Data Pointer", "Synchronous Data Transfer Request",
+/* 0x02 */ "SCSI-I Extended Identify", "Wide Data Transfer Reqeust"
+};
+
+#define NO_EXTENDED_MSGS (sizeof(two_byte_msgs) / sizeof (const char *))
+#endif /* (CONSTANTS & CONST_MSG) */
+
+int print_msg (const unsigned char *msg) {
+ int len = 0, i;
+ if (msg[0] == EXTENDED_MESSAGE) {
+ len = 3 + msg[1];
+#if (CONSTANTS & CONST_MSG)
+ printk("Extended Message code %s arguments ",
+ (msg[2] < NO_EXTENDED_MESSAGES) ?
+ printk("%s " extended_msgs[msg[2]]),
+ reserved);
+ for (i = 3; i < msg[1]; ++i)
+#else
+ for (i = 0; i < msg[1]; ++i)
+#endif
+ printk("%02x ", msg[i]);
+ /* Identify */
+ } else if (msg[0] & 0x80) {
+#if (CONSTANTS & CONST_MSG)
+ printk("Identify disconnect %sallowed %s %d ",
+ (msg[0] & 0x40) ? "" : "not ",
+ (msg[0] & 0x20) ? "target routine" : "lun",
+ msg[0] & 0x7);
+#else
+ printk("%02x ", msg[0]);
+#endif
+ len = 1;
+ /* Normal One byte */
+ } else if (msg[0] < 0x1f) {
+#if (CONSTANTS & CONST_MSG)
+ if (msg[0] < NO_ONE_BYTE_MSGS)
+ printk(one_byte_msgs[msg[0]]);
+ else
+ printk("reserved (%02x) ", msg[0]);
+#else
+ printk("%02x ", msg[0]);
+#endif
+ len = 1;
+ /* Two byte */
+ } else if (msg[0] <= 0x2f) {
+#if (CONSTANTS & CONST_MSG)
+ if ((msg[0] - 0x20) < NO_TWO_BYTE_MESSAGES)
+ printk("%s %02x ", two_byte_msgs[msg[0] - 0x20],
+ msg[1]);
+ else
+ printk("reserved two byte (%02x %02x) ",
+ msg[0], msg[1]);
+#else
+ printk("%02x %02x", msg[0], msg[1]);
+#endif
+ len = 2;
+ } else
+#if (CONSTANTS & CONST_MSG)
+ printk(reserved);
+#else
+ printk("%02x ", msg[0]);
+#endif
+ return len;
+}
diff --git a/kernel/blk_drv/scsi/constants.h b/drivers/scsi/constants.h
index 7a37602..15f8744 100644
--- a/kernel/blk_drv/scsi/constants.h
+++ b/drivers/scsi/constants.h
@@ -1,6 +1,7 @@
#ifndef _CONSTANTS_H
#define _CONSTANTS_H
extern void print_command(unsigned char *);
+extern int print_msg(unsigned char *);
extern void print_sense(char *, Scsi_Cmnd *);
extern void print_status(int);;
#endif /* def _CONSTANTS_H */
diff --git a/kernel/blk_drv/scsi/fdomain.c b/drivers/scsi/fdomain.c
index d207945..6364c67 100644
--- a/kernel/blk_drv/scsi/fdomain.c
+++ b/drivers/scsi/fdomain.c
@@ -1,10 +1,10 @@
/* fdomain.c -- Future Domain TMC-16x0 driver
* Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu
- * Revised: Fri Aug 13 22:44:05 1993 by faith@cs.unc.edu
+ * Revised: Sun Oct 10 20:15:47 1993 by faith@cs.unc.edu
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993 Rickard E. Faith
*
- * $Id: fdomain.c,v 3.18 1993/08/13 22:44:12 root Exp $
+ * $Id: fdomain.c,v 5.3 1993/10/11 00:16:12 root Exp $
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
@@ -87,10 +87,9 @@
more recent times):
Todd Carrico (todd@wutc.wustl.edu), Dan Poirier (poirier@cs.unc.edu ), Ken
- Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@dutiba.tudelft.nl),
- Sakari Aaltonen (sakaria@vipunen.hit.fi), John Rice
- (rice@xanth.cs.odu.edu), Brad Yearwood (brad@optilink.com), and Ray Toy
- (toy@soho.crd.ge.com).
+ Corey (kenc@sol.acs.unt.edu), C. de Bruin (bruin@bruin@sterbbs.nl), Sakari
+ Aaltonen (sakaria@vipunen.hit.fi), John Rice (rice@xanth.cs.odu.edu), Brad
+ Yearwood (brad@optilink.com), and Ray Toy (toy@soho.crd.ge.com).
Special thanks to Tien-Wan Yang (twyang@cs.uh.edu), who graciously lent me
his 18C50-based card for debugging. He is the sole reason that this
@@ -123,15 +122,20 @@
turning this on should not hurt, and might help. Please let me know if
this is the case, since this code will be removed from future drivers.
- RESELECTION: DO *NOT* USE THIS OPTION! This turns on SCSI device
- disconnect and reselection, which does not work at this time. When I get
- this working, it will support multiple outstanding SCSI commands.
+ RESELECTION: This is no longer an option, since I gave up trying to
+ implement it in version 4.x of this driver. It did not improve
+ performance at all and made the driver unstable (because I never found one
+ of the two race conditions which were introduced by multiple outstanding
+ commands). The instability seems a very high price to pay just so that
+ you don't have to wait for the tape to rewind. When I have time, I will
+ work on this again. In the interim, if anyone want to work on the code, I
+ can give them my latest version.
**************************************************************************/
#include <linux/sched.h>
#include <asm/io.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "fdomain.h"
@@ -140,7 +144,7 @@
#include <linux/string.h>
#include <linux/ioport.h>
-#define VERSION "$Revision: 3.18 $"
+#define VERSION "$Revision: 5.3 $"
/* START OF USER DEFINABLE OPTIONS */
@@ -148,7 +152,6 @@
#define ENABLE_PARITY 1 /* Enable SCSI Parity */
#define FIFO_COUNT 2 /* Number of 512 byte blocks before INTR */
#define DO_DETECT 0 /* Do device detection here (see scsi.c) */
-#define RESELECTION 0 /* Support RESELECTION PHASE (NOT stable) */
/* END OF USER DEFINABLE OPTIONS */
@@ -316,7 +319,7 @@ struct signature {
geometry information in the on-board RAM area for each of the first
three BIOS's, it is still important to enter a fully qualified
signature in the table for any new BIOS's (after the host SCSI ID and
- geometry location are verified. */
+ geometry location are verified.) */
};
#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature ))
@@ -525,12 +528,19 @@ int fdomain_16x0_detect( int hostnum )
though, about reading all these random port addresses--there
are rumors that the Future Domain BIOS does something very
similar.
+
+ Do not, however, check ports which the kernel knows are being used
+ by another driver.
*/
for (i = 0; !flag && i < PORT_COUNT; i++) {
port_base = ports[i];
- if(check_region(port_base, 0x10)) continue; /* skip if I/O port in
- use */
+ if (check_region( port_base, 0x10 )) {
+#if DEBUG_DETECT
+ printf( " (%x inuse),", port_base );
+#endif
+ continue;
+ }
#if DEBUG_DETECT
printk( " %x,", port_base );
#endif
@@ -571,6 +581,8 @@ int fdomain_16x0_detect( int hostnum )
}
this_host = hostnum;
+
+ /* Log IRQ with kernel */
if (!interrupt_level) {
panic( "Future Domain: *NO* interrupt level selected!\n" );
@@ -605,13 +617,15 @@ int fdomain_16x0_detect( int hostnum )
}
}
+ /* Log I/O ports with kernel */
+
+ snarf_region( port_base, 0x10 );
+
if ((bios_major == 3 && bios_minor >= 2) || bios_major < 0) {
adapter_mask = 0x80;
scsi_hosts[this_host].this_id = 7;
}
- snarf_region(port_base, 0x10); /* Register */
-
#if DO_DETECT
/* These routines are here because of the way the SCSI bus behaves after
@@ -730,13 +744,8 @@ static int fdomain_select( int target )
unsigned long timeout;
- if (RESELECTION) {
- outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
- outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port );
- } else {
- outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
- outb( 1 << target, SCSI_Data_NoACK_port );
- }
+ outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
+ outb( adapter_mask | (1 << target), SCSI_Data_NoACK_port );
/* Stop arbitration and enable parity */
outb( PARITY_MASK, TMC_Cntl_port );
@@ -802,7 +811,7 @@ void fdomain_16x0_intr( int unused )
if (current_SC->SCp.phase & aborted) {
#if EVERY_ACCESS
- if (current_SC->SCp.phase & (in_other || disconnect))
+ if (current_SC->SCp.phase & (in_other | disconnect))
printk( "aborted (%s) = %d, ",
current_SC->SCp.phase & in_other
? "in_other" : "disconnect",
@@ -812,7 +821,7 @@ void fdomain_16x0_intr( int unused )
current_SC->result );
#endif
/* Force retry for timeouts after selection complete */
- if (current_SC->SCp.phase & (in_other || disconnect)) {
+ if (current_SC->SCp.phase & (in_other | disconnect)) {
fdomain_16x0_reset();
my_done( DID_RESET << 16 );
} else {
@@ -821,19 +830,6 @@ void fdomain_16x0_intr( int unused )
return;
}
-#if RESELECTION
- if (current_SC->SCp.phase & disconnect) {
- printk( " RECON %x ", inb( SCSI_Data_NoACK_port ) );
- current_SC->SCp.phase = in_other;
- outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
- outb( 0x84, SCSI_Cntl_port );
- while ( (status = inb( SCSI_Status_port )) & 0x20 ) {
- printk( "s = %x, ", status );
- }
- outb( 0x80, SCSI_Cntl_port );
- } else
-#endif
-
if (current_SC->SCp.phase & in_arbitration) {
status = inb( TMC_Status_port ); /* Read adapter status */
if (!(status & 0x02)) {
@@ -847,13 +843,8 @@ void fdomain_16x0_intr( int unused )
outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port );
-#if RESELECTION
- outb( 0x8a, SCSI_Cntl_port ); /* Bus Enable + Attention + Select */
- outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port );
-#else
outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */
- outb( 1 << current_SC->target, SCSI_Data_NoACK_port );
-#endif
+ outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port );
/* Stop arbitration and enable parity */
outb( 0x10 | PARITY_MASK, TMC_Cntl_port );
@@ -881,11 +872,7 @@ void fdomain_16x0_intr( int unused )
}
current_SC->SCp.phase = in_other;
outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port );
-#if RESELECTION
- outb( 0x88, SCSI_Cntl_port );
-#else
outb( 0x80, SCSI_Cntl_port );
-#endif
#if DEBUG_RACE
in_interrupt_flag = 0;
#endif
@@ -951,18 +938,7 @@ void fdomain_16x0_intr( int unused )
#endif
break;
case 0x0a: /* MESSAGE OUT */
-#if RESELECTION
- if (!(current_SC->SCp.phase & sent_ident)) {
-#if EVERY_ACCESS
- printk( " IDENT " );
-#endif
- outb( 0x80, SCSI_Cntl_port );
- outb( IDENTIFY( 1, 0 ), Write_SCSI_Data_port );
- current_SC->SCp.phase |= sent_ident;
- } else
-#else
- outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */
-#endif
+ outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */
break;
case 0x0e: /* MESSAGE IN */
current_SC->SCp.Message = inb( Read_SCSI_Data_port );
@@ -970,12 +946,6 @@ void fdomain_16x0_intr( int unused )
printk( "Message = %x, ", current_SC->SCp.Message );
#endif
if (!current_SC->SCp.Message) ++done;
-#if RESELECTION
- if (current_SC->SCp.Message == DISCONNECT) {
- printk( " DISCON " );
- current_SC->SCp.phase = disconnect;
- }
-#endif
#if DEBUG_MESSAGES || EVERY_ACCESS
if (current_SC->SCp.Message) {
printk( "Future Domain: Message = %x\n",
@@ -1530,7 +1500,12 @@ int fdomain_16x0_biosparam( int size, int dev, int *info_array )
if (!info_array[0]
|| !info_array[1]
|| !info_array[2]
- || info_array[2] > 1024 /* DOS uses only 10 bits */
+ || info_array[2] > 1024 /* DOS uses only 10 bits.
+ Should this be changed
+ to support larger drives?
+ I.e., will the controller
+ "do the right thing"?
+ */
) {
info_array[0]
diff --git a/kernel/blk_drv/scsi/fdomain.h b/drivers/scsi/fdomain.h
index abc8a4d..d913e92 100644
--- a/kernel/blk_drv/scsi/fdomain.h
+++ b/drivers/scsi/fdomain.h
@@ -4,7 +4,7 @@
* Author: Rickard E. Faith, faith@cs.unc.edu
* Copyright 1992, 1993 Rickard E. Faith
*
- * $Id: fdomain.h,v 3.7 1993/06/06 15:42:16 root Exp $
+ * $Id: fdomain.h,v 5.1 1993/10/10 13:33:11 root Exp $
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the
diff --git a/drivers/scsi/g_NCR5380.c b/drivers/scsi/g_NCR5380.c
new file mode 100644
index 0000000..91ebdda
--- /dev/null
+++ b/drivers/scsi/g_NCR5380.c
@@ -0,0 +1,179 @@
+#define AUTOSENSE
+
+/*
+ * Generic Generic NCR5380 driver
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * TODO : flesh out DMA support, find some one actually using this (I have
+ * a memory mapped Trantor board that works fine)
+ */
+
+/*
+ * Options :
+ *
+ * PARITY - enable parity checking. Not supported.
+ *
+ * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
+ *
+ * USLEEP - enable support for devices that don't disconnect. Untested.
+ *
+ * The card is detected and initialized in one of several ways :
+ * 1. With command line overrides - NCR5380=port,irq may be
+ * used on the LILO command line to override the defaults.
+ *
+ * 2. With the GENERIC_NCR5380_OVERRIDE compile time define. This is
+ * specified as an array of address, irq tupples. Ie, for
+ * one board at the default 0xcc000 address, IRQ5, no dma, I could
+ * say -DGENERIC_NCR5380_OVERRIDE={{0xcc000, 5, DMA_NONE}}
+ *
+ * -1 should be specified for no or DMA interrupt, -2 to autoprobe for an
+ * IRQ line if overriden on the command line.
+ */
+
+/*
+ * $Log: generic_NCR5380.c,v $
+ */
+
+#include <linux/config.h>
+#if defined(CONFIG_SCSI_GENERIC_NCR5380)
+/* Standard option */
+#define AUTOPROBE_IRQ
+
+#include <asm/system.h>
+#include <asm/io.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "g_NCR5380.h"
+#include "NCR5380.h"
+#include "constants.h"
+
+static struct override {
+ int port;
+ int irq;
+ int dma;
+} overrides
+#ifdef GENERIC_NCR5380_OVERRIDE
+ [] = GENERIC_NCR5380_OVERRIDE
+#else
+ [1] = {{0,},};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+/*
+ * Function : generic_NCR5380_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer paramters with ints[0]
+ * equal to the number of ints.
+ *
+ */
+
+void generic_NCR5380_setup(char *str, int *ints) {
+ static int commandline_current = 0;
+ if (ints[0] != 2)
+ printk("generic_NCR5380_setup : usage ncr5380=port,irq,dma\n");
+ else
+ if (commandline_current < NO_OVERRIDES) {
+ overrides[commandline_current].port = ints[1];
+ overrides[commandline_current].irq = ints[2];
+ overrides[commandline_current].dma = ints[3];
+ ++commandline_current;
+ }
+}
+
+static struct sigaction sa = { generic_NCR5380_intr, 0,
+ SA_INTERRUPT , NULL };
+
+/*
+ * Function : int generic_NCR5380_detect(int hostno)
+ *
+ * Purpose : initializes generic NCR5380 driver based on the
+ * command line / compile time port and irq definitions.
+ *
+ * Inputs : hostno - id of this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+
+int generic_NCR5380_detect(int hostno) {
+ static int current_override = 0;
+ int count;
+ struct Scsi_Host *instance;
+
+ for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+ if (!(overrides[current_override].port))
+ continue;
+
+ instance = scsi_register (hostno, sizeof(struct NCR5380_hostdata));
+ instance->io_port = overrides[current_override].port;
+
+ NCR5380_init(instance);
+
+ if (overrides[current_override].irq != IRQ_AUTO)
+ instance->irq = overrides[current_override].irq;
+ else
+ instance->irq = NCR5380_probe_irq(instance, 0xffff);
+
+ if (instance->irq != IRQ_NONE)
+ if (irqaction (instance->irq, &sa)) {
+ printk("scsi%d : IRQ%d not free, interrupts disabled\n",
+ hostno, instance->irq);
+ instance->irq = IRQ_NONE;
+ }
+
+ if (instance->irq == IRQ_NONE) {
+ printk("scsi%d : interrupts not enabled. for better interactive performance,\n", hostno);
+ printk("scsi%d : please jumper the board for a free IRQ.\n", hostno);
+ }
+
+ printk("scsi%d : at port %d", instance->host_no, instance->io_port);
+ if (instance->irq == IRQ_NONE)
+ printk (" interrupts disabled");
+ else
+ printk (" irq %d", instance->irq);
+ printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+ CAN_QUEUE, CMD_PER_LUN, GENERIC_NCR5380_PUBLIC_RELEASE);
+ NCR5380_print_options(instance);
+ printk("\n");
+
+ ++current_override;
+ ++count;
+ }
+ return count;
+}
+
+const char * generic_NCR5380_info (void) {
+ static const char string[]="";
+ return string;
+}
+
+#include "NCR5380.c"
+
+#endif /* defined(CONFIG_SCSI_GENERIC_NCR5380) */
diff --git a/drivers/scsi/g_NCR5380.h b/drivers/scsi/g_NCR5380.h
new file mode 100644
index 0000000..cb55068
--- /dev/null
+++ b/drivers/scsi/g_NCR5380.h
@@ -0,0 +1,84 @@
+/*
+ * Generic Generic NCR5380 driver defines
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
+ *
+ * ALPHA RELEASE 1.
+ *
+ * For more information, please consult
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: generic_NCR5380.h,v $
+ */
+
+#ifndef GENERIC_NCR5380_H
+#define GENERIC_NCR5380_H
+
+#define GENERIC_NCR5380_PUBLIC_RELEASE 1
+
+
+#ifndef ASM
+int generic_NCR5380_abort(Scsi_Cmnd *, int);
+int generic_NCR5380_detect(int);
+const char *generic_NCR5380_info(void);
+int generic_NCR5380_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int generic_NCR5380_reset(void);
+
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 16
+#endif
+
+#ifdef HOSTS_C
+
+#define GENERIC_NCR5380 {"Trantor T128/T128F/T228", \
+ generic_NCR5380_detect, generic_NCR5380_info, NULL, \
+ generic_NCR5380_queue_command, generic_NCR5380_abort, \
+ generic_NCR5380_reset, NULL, \
+ NULL, /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
+ /* cmd per lun */ CMD_PER_LUN , 0, 0}
+
+#else
+#define NCR5380_implementation_fields \
+ int port
+
+#define NCR5380_local_declare() \
+ register int port
+
+#define NCR5380_setup(instance) \
+ port = (instance)->io_port
+
+#define NCR5380_read(reg) (inb(port + (reg)))
+#define NCR5380_write(reg, value) (outb((value), (port + (reg))))
+
+#define NCR5380_intr generic_NCR5380_intr
+#define NCR5380_queue_command generic_NCR5380_queue_command
+#define NCR5380_abort generic_NCR5380_abort
+#define NCR5380_reset generic_NCR5380_reset
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* GENERIC_NCR5380_H */
diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c
new file mode 100644
index 0000000..63ea77d
--- /dev/null
+++ b/drivers/scsi/hosts.c
@@ -0,0 +1,304 @@
+/*
+ * 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>
+#include "../block/blk.h"
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include "scsi.h"
+
+#ifndef NULL
+#define NULL 0L
+#endif
+
+#define HOSTS_C
+
+#include "hosts.h"
+
+#ifdef CONFIG_SCSI_AHA152X
+#include "aha152x.h"
+#endif
+
+#ifdef CONFIG_SCSI_AHA1542
+#include "aha1542.h"
+#endif
+
+#ifdef CONFIG_SCSI_AHA1740
+#include "aha1740.h"
+#endif
+
+#ifdef CONFIG_SCSI_FUTURE_DOMAIN
+#include "fdomain.h"
+#endif
+
+#ifdef CONFIG_SCSI_GENERIC_NCR5380
+#include "g_NCR5380.h"
+#endif
+
+#ifdef CONFIG_SCSI_PAS16
+#include "pas16.h"
+#endif
+
+#ifdef CONFIG_SCSI_SEAGATE
+#include "seagate.h"
+#endif
+
+#ifdef CONFIG_SCSI_T128
+#include "t128.h"
+#endif
+
+#ifdef CONFIG_SCSI_ULTRASTOR
+#include "ultrastor.h"
+#endif
+
+#ifdef CONFIG_SCSI_7000FASST
+#include "wd7000.h"
+#endif
+
+#ifdef CONFIG_SCSI_DEBUG
+#include "scsi_debug.h"
+#endif
+
+/*
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.3 1993/09/24 12:21:00 drew Exp drew $";
+*/
+
+/*
+ * 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.
+ */
+
+/* This is a placeholder for controllers that are not configured into
+ the system - we do this to ensure that the controller numbering is
+ always consistent, no matter how the kernel is configured. */
+
+#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
+ NULL, NULL, 0, 0, 0, 0, 0, 0}
+
+/*
+ * 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.
+ */
+
+Scsi_Host_Template scsi_hosts[] =
+ {
+#ifdef CONFIG_SCSI_AHA152X
+ AHA152X,
+#endif
+#ifdef CONFIG_SCSI_AHA1542
+ AHA1542,
+#endif
+#ifdef CONFIG_SCSI_AHA1740
+ AHA1740,
+#endif
+#ifdef CONFIG_SCSI_FUTURE_DOMAIN
+ FDOMAIN_16X0,
+#endif
+#ifdef CONFIG_SCSI_GENERIC_NCR5380
+ GENERIC_NCR5380,
+#endif
+#ifdef CONFIG_SCSI_PAS16
+ MV_PAS16,
+#endif
+#ifdef CONFIG_SCSI_SEAGATE
+ SEAGATE_ST0X,
+#endif
+#ifdef CONFIG_SCSI_T128
+ TRANTOR_T128,
+#endif
+#ifdef CONFIG_SCSI_ULTRASTOR
+ ULTRASTOR_14F,
+#endif
+#ifdef CONFIG_SCSI_7000FASST
+ WD7000,
+#endif
+#ifdef CONFIG_SCSI_DEBUG
+ SCSI_DEBUG,
+#endif
+ };
+
+#define MAX_SCSI_HOSTS (sizeof(scsi_hosts) / sizeof(Scsi_Host_Template))
+
+/*
+ * Our semaphores and timeout counters, where size depends on MAX_SCSI_HOSTS here.
+ */
+
+struct Scsi_Host * scsi_hostlist = NULL;
+
+static int scsi_init_memory_start = 0;
+
+int max_scsi_hosts = 0;
+static int next_host = 0;
+
+void
+scsi_unregister(struct Scsi_Host * sh, int j){
+ struct Scsi_Host * shpnt;
+
+ if(((unsigned int) sh) + sizeof(struct Scsi_Host) + j != scsi_init_memory_start)
+ panic("Unable to unregister scsi host");
+ if(scsi_hostlist == sh)
+ scsi_hostlist = NULL;
+ else {
+ shpnt = scsi_hostlist;
+ while(shpnt->next != sh) shpnt = shpnt->next;
+ shpnt->next = shpnt->next->next;
+
+ };
+ next_host--;
+ scsi_init_memory_start = (unsigned int) sh;
+}
+
+/* We call this when we come across a new host adapter. We only do this
+ once we are 100% sure that we want to use this host adapter - it is a
+ pain to reverse this, so we try and avoid it */
+
+struct Scsi_Host * scsi_register(int i, int j){
+ struct Scsi_Host * retval, *shpnt;
+ retval = (struct Scsi_Host*) scsi_init_memory_start;
+ scsi_init_memory_start += sizeof(struct Scsi_Host) + j;
+ retval->host_busy = 0;
+ retval->host_no = next_host++;
+ retval->host_queue = NULL;
+ retval->host_wait = NULL;
+ retval->last_reset = 0;
+ retval->hostt = &scsi_hosts[i];
+ retval->next = NULL;
+#ifdef DEBUG
+ printk("Register %x %x: %d %d\n", retval, retval->hostt, i, j);
+#endif
+
+ /* The next three are the default values which can be overridden
+ if need be */
+ retval->this_id = scsi_hosts[i].this_id;
+ retval->sg_tablesize = scsi_hosts[i].sg_tablesize;
+ retval->unchecked_isa_dma = scsi_hosts[i].unchecked_isa_dma;
+
+ if(!scsi_hostlist)
+ scsi_hostlist = retval;
+ else
+ {
+ shpnt = scsi_hostlist;
+ while(shpnt->next) shpnt = shpnt->next;
+ shpnt->next = retval;
+ }
+
+ return retval;
+}
+
+unsigned int
+scsi_init(unsigned long memory_start,unsigned long memory_end)
+{
+ static int called = 0;
+ int i, j, count, pcount;
+
+ count = 0;
+
+ if(called) return memory_start;
+
+ scsi_init_memory_start = memory_start;
+ called = 1;
+ for (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.
+ */
+
+ pcount = next_host;
+ if ((scsi_hosts[i].detect) &&
+ (scsi_hosts[i].present =
+ scsi_hosts[i].detect(i)))
+ {
+ /* The only time this should come up is when people use
+ some kind of patched driver of some kind or another. */
+ if(pcount == next_host) {
+ if(scsi_hosts[i].present > 1)
+ panic("Failure to register low-level scsi driver");
+ /* The low-level driver failed to register a driver. We
+ can do this now. */
+ scsi_register(i,0);
+ };
+ for(j = 0; j < scsi_hosts[i].present; j++)
+ printk ("scsi%d : %s\n",
+ count++, scsi_hosts[i].name);
+ }
+ }
+ printk ("scsi : %d hosts.\n", count);
+
+ max_scsi_hosts = count;
+ return scsi_init_memory_start;
+}
+
+#ifndef CONFIG_BLK_DEV_SD
+unsigned long sd_init(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+unsigned long sd_init1(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+void sd_attach(Scsi_Device * SDp){
+};
+int NR_SD=-1;
+int MAX_SD=0;
+#endif
+
+
+#ifndef CONFIG_BLK_DEV_SR
+unsigned long sr_init(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+unsigned long sr_init1(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+void sr_attach(Scsi_Device * SDp){
+};
+int NR_SR=-1;
+int MAX_SR=0;
+#endif
+
+
+#ifndef CONFIG_CHR_DEV_ST
+unsigned long st_init(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+unsigned long st_init1(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+void st_attach(Scsi_Device * SDp){
+};
+int NR_ST=-1;
+int MAX_ST=0;
+#endif
+
+#ifndef CONFIG_CHR_DEV_SG
+unsigned long sg_init(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+unsigned long sg_init1(unsigned long memory_start, unsigned long memory_end){
+ return memory_start;
+};
+void sg_attach(Scsi_Device * SDp){
+};
+int NR_SG=-1;
+int MAX_SG=0;
+#endif
diff --git a/kernel/blk_drv/scsi/hosts.h b/drivers/scsi/hosts.h
index e9485d7..69e67b8 100644
--- a/kernel/blk_drv/scsi/hosts.h
+++ b/drivers/scsi/hosts.h
@@ -8,19 +8,18 @@
* Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to
* add scatter-gather, multiple outstanding request, and other
* enhancements.
+ *
+ * Further modified by Eric Youngdale to support multiple host adapters
+ * of the same type.
*/
#ifndef _HOSTS_H
#define _HOSTS_H
/*
- $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.1 1992/07/24 06:27:38 root Exp root $
+ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.h,v 1.3 1993/09/24 12:21:00 drew Exp drew $
*/
-/*
- The Scsi_Host type has all that is needed to interface with a SCSI
- host in a device independant matter.
-*/
#define SG_NONE 0
#define SG_ALL 0xff
@@ -34,6 +33,12 @@
used in one scatter-gather request.
*/
+/*
+ The Scsi_Host_Template type has all that is needed to interface with a SCSI
+ host in a device independant matter. There is one entry for each different
+ type of host adapter that is supported on the system.
+*/
+
typedef struct
{
/*
@@ -45,9 +50,18 @@ typedef struct
/*
The detect function shall return non zero on detection,
- and initialize all data necessary for this particular
+ indicating the number of host adapters of this particular
+ type were found. It should also
+ 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
+ knows where the first entry is in the scsi_hosts[] array.
+
+ Note that the detect routine MUST not call any of the mid level
+ functions to queue commands because things are not guaranteed
+ to be set up yet. The detect routine can send commands to
+ the host adapter as long as the program control will not be
+ passed to scsi.c in the processesing of the command. Note
+ especially that scsi_malloc/scsi_free must not be called.
*/
int (* detect)(int);
@@ -155,47 +169,64 @@ typedef struct
short cmd_per_lun;
/*
- present contains a flag as to weather we are present -
- so we don't have to call detect multiple times.
+ present contains counter indicating how many boards of this
+ type were found when we did the scan.
*/
- unsigned present:1;
+ unsigned char present;
/*
true if this host adapter uses unchecked DMA onto an ISA bus.
*/
unsigned unchecked_isa_dma:1;
- } Scsi_Host;
+ } Scsi_Host_Template;
/*
The scsi_hosts array is the array containing the data for all
- possible <supported> scsi hosts.
+ possible <supported> scsi hosts. This is similar to the
+ Scsi_Host_Template, except that we have one entry for each
+ actual physical host adapter on the system, stored as a linked
+ list. Note that if there are 2 aha1542 boards, then there will
+ be two Scsi_Host entries, but only 1 Scsi_Host_Template entries.
*/
-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[];
-
-/*
- This is the queue of currently pending commands for a given
- SCSI host.
-*/
-
-extern Scsi_Cmnd *host_queue[];
-
-extern struct wait_queue *host_wait[]; /* For waiting until host available*/
+struct Scsi_Host
+ {
+ struct Scsi_Host * next;
+ volatile unsigned char host_busy;
+ char host_no; /* Used for IOCTL_GET_IDLUN */
+ int last_reset;
+ struct wait_queue *host_wait;
+ Scsi_Cmnd *host_queue;
+ Scsi_Host_Template * hostt;
+
+ /* These parameters should be set by the detect routine */
+ unsigned char *base;
+ short unsigned int io_port;
+ unsigned char irq;
+ unsigned char dma_channel;
+ /*
+ The rest can be copied from the template, or specifically
+ initialized, as required.
+ */
+
+ int this_id;
+ short unsigned int sg_tablesize;
+ unsigned unchecked_isa_dma:1;
+ int hostdata[0]; /* Used for storage of host specific stuff */
+ };
+
+extern struct Scsi_Host * scsi_hostlist;
+
+extern Scsi_Host_Template scsi_hosts[];
/*
scsi_init initializes the scsi hosts.
*/
-void scsi_init(void);
+unsigned int scsi_init(unsigned long memory_start,unsigned long memory_end);
+extern struct Scsi_Host * scsi_register(int i, int j);
+extern void scsi_unregister(struct Scsi_Host * i, int j);
#define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
#endif
diff --git a/drivers/scsi/pas16.c b/drivers/scsi/pas16.c
new file mode 100644
index 0000000..e7de2a1
--- /dev/null
+++ b/drivers/scsi/pas16.c
@@ -0,0 +1,483 @@
+#define AUTOSENSE
+#define PSEUDO_DMA
+
+/*
+ * This driver adapted from Drew Eckhardt's Trantor T128 driver
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
+ *
+ * ( Based on T128 - DISTRIBUTION RELEASE 3. )
+ *
+ * Modified to work with the Pro Audio Spectrum/Studio 16
+ * by John Weidman.
+ *
+ *
+ * For more information, please consult
+ *
+ * Media Vision
+ * (510) 770-8600
+ * (800) 348-7116
+ *
+ * and
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * Options :
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ * for commands that return with a CHECK CONDITION status.
+ *
+ * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
+ * increase compared to polled I/O.
+ *
+ * PARITY - enable parity checking. Not supported.
+ *
+ * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
+ *
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
+ * only really want to use this if you're having a problem with
+ * dropped characters during high speed communications, and even
+ * then, you're going to be better off twiddling with transfersize.
+ *
+ * USLEEP - enable support for devices that don't disconnect. Untested.
+ *
+ * The card is detected and initialized in one of several ways :
+ * 1. Autoprobe (default) - There are many different models of
+ * the Pro Audio Spectrum/Studio 16, and I only have one of
+ * them, so this may require a little tweaking. An interrupt
+ * is triggered to autoprobe for the interrupt line. Note:
+ * with the newer model boards, the interrupt is set via
+ * software after reset using the default_irq for the
+ * current board number.
+ *
+ *
+ * 2. With command line overrides - pas16=port,irq may be
+ * used on the LILO command line to override the defaults.
+ * NOTE: untested.
+ *
+ * 3. With the PAS16_OVERRIDE compile time define. This is
+ * specified as an array of address, irq tupples. Ie, for
+ * one board at the default 0x388 address, IRQ10, I could say
+ * -DPAS16_OVERRIDE={{0x388, 10}}
+ * NOTE: Also untested.
+ *
+ * Note that if the override methods are used, place holders must
+ * be specified for other boards in the system.
+ *
+ */
+
+#include <asm/system.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <asm/io.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "pas16.h"
+#define AUTOPROBE_IRQ
+#include "NCR5380.h"
+#include "constants.h"
+
+
+
+int scsi_irq_translate[] =
+ { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 };
+
+/* The default_irqs array contains values used to set the irq into the
+ * board via software (as must be done on newer model boards without
+ * irq jumpers on the board). The first value in the array will be
+ * assigned to logical board 0, the next to board 1, etc.
+ */
+int default_irqs[] = { PAS16_DEFAULT_BOARD_1_IRQ,
+ PAS16_DEFAULT_BOARD_2_IRQ,
+ PAS16_DEFAULT_BOARD_3_IRQ,
+ PAS16_DEFAULT_BOARD_4_IRQ
+ };
+
+static struct override {
+ unsigned short io_port;
+ int irq;
+} overrides
+#ifdef PAS16_OVERRIDE
+ [] = PAS16_OVERRIDE;
+#else
+ [4] = {{0,IRQ_AUTO}, {0,IRQ_AUTO}, {0,IRQ_AUTO},
+ {0,IRQ_AUTO}};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+static struct base {
+ unsigned short io_port;
+ int noauto;
+} bases[] = { {PAS16_DEFAULT_BASE_1, 0},
+ {PAS16_DEFAULT_BASE_2, 0},
+ {PAS16_DEFAULT_BASE_3, 0},
+ {PAS16_DEFAULT_BASE_4, 0}
+ };
+
+#define NO_BASES (sizeof (bases) / sizeof (struct base))
+
+unsigned short pas16_offset[ 8 ] =
+ {
+ 0x1c00, /* OUTPUT_DATA_REG */
+ 0x1c01, /* INITIATOR_COMMAND_REG */
+ 0x1c02, /* MODE_REG */
+ 0x1c03, /* TARGET_COMMAND_REG */
+ 0x3c00, /* STATUS_REG ro, SELECT_ENABLE_REG wo */
+ 0x3c01, /* BUS_AND_STATUS_REG ro, START_DMA_SEND_REG wo */
+ 0x3c02, /* INPUT_DATA_REGISTER ro, (N/A on PAS16 ?)
+ * START_DMA_TARGET_RECIEVE_REG wo
+ */
+ 0x3c03, /* RESET_PARITY_INTERRUPT_REG ro,
+ * START_DMA_INITIATOR_RECIEVE_REG wo
+ */
+ };
+
+
+
+/*
+ * Function : enable_board( int board_num, unsigned short port )
+ *
+ * Purpose : set address in new model board
+ *
+ * Inputs : board_num - logical board number 0-3, port - base address
+ *
+ */
+
+void enable_board( int board_num, unsigned short port )
+{
+ outb( 0xbc + board_num, MASTER_ADDRESS_PTR );
+ outb( port >> 2, MASTER_ADDRESS_PTR );
+}
+
+
+
+/*
+ * Function : init_board( unsigned short port, int irq )
+ *
+ * Purpose : Set the board up to handle the SCSI interface
+ *
+ * Inputs : port - base address of the board,
+ * irq - irq to assign to the SCSI port
+ *
+ */
+
+void init_board( unsigned short io_port, int irq )
+{
+ unsigned int tmp;
+
+ /* Initialize the SCSI part of the board */
+
+ outb( 0x30, io_port + P_TIMEOUT_COUNTER_REG ); /* Timeout counter */
+ outb( 0x01, io_port + P_TIMEOUT_STATUS_REG_OFFSET ); /* Reset TC */
+ outb( 0x01, io_port + WAIT_STATE ); /* 1 Wait state */
+
+ NCR5380_read( RESET_PARITY_INTERRUPT_REG );
+
+ /* Set the SCSI interrupt pointer without mucking up the sound
+ * interrupt pointer in the same byte.
+ */
+ tmp = inb( io_port + IO_CONFIG_3 );
+ tmp = ( tmp & 0x0f ) | ( scsi_irq_translate[irq] << 4 );
+ outb( tmp, io_port + IO_CONFIG_3 );
+
+ /* Set up the drive parameters and enable 5380 interrupts */
+ outb( 0x6d, io_port + SYS_CONFIG_4 );
+}
+
+
+/*
+ * Function : pas16_hw_detect( unsigned short board_num )
+ *
+ * Purpose : determine if a pas16 board is present
+ *
+ * Inputs : board_num - logical board number ( 0 - 3 )
+ *
+ * Returns : 0 if board not found, 1 if found.
+ */
+
+int pas16_hw_detect( unsigned short board_num )
+{
+ unsigned char board_rev, tmp;
+ unsigned short port = bases[ board_num ].io_port;
+
+ /* See if we can find a PAS16 board at the address associated
+ * with this logical board number.
+ */
+
+ /* First, attempt to take a newer model board out of reset and
+ * give it a base address. This shouldn't affect older boards.
+ */
+ enable_board( board_num, port );
+
+ /* Now see if it looks like a PAS16 board */
+ board_rev = inb( port + PCB_CONFIG );
+
+ if( board_rev == 0xff )
+ return 0;
+
+ tmp = board_rev ^ 0xe0;
+
+ outb( tmp, port + PCB_CONFIG );
+ tmp = inb( port + PCB_CONFIG );
+ outb( board_rev, port + PCB_CONFIG );
+
+ if( board_rev != tmp ) /* Not a PAS-16 */
+ return 0;
+
+ if( ( inb( port + OPERATION_MODE_1 ) & 0x03 ) != 0x03 )
+ return 0; /* return if no SCSI interface found */
+
+ return 1;
+}
+
+
+/*
+ * Function : pas16_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer paramters with ints[0]
+ * equal to the number of ints.
+ *
+ */
+
+void pas16_setup(char *str, int *ints) {
+ static int commandline_current = 0;
+ int i;
+ if (ints[0] != 2)
+ printk("pas16_setup : usage pas16=io_port,irq\n");
+ else
+ if (commandline_current < NO_OVERRIDES) {
+ overrides[commandline_current].io_port = (unsigned short) ints[1];
+ overrides[commandline_current].irq = ints[2];
+ for (i = 0; i < NO_BASES; ++i)
+ if (bases[i].io_port == (unsigned short) ints[1]) {
+ bases[i].noauto = 1;
+ break;
+ }
+ ++commandline_current;
+ }
+}
+
+static struct sigaction pas16_sigaction = { pas16_intr, 0, SA_INTERRUPT , NULL };
+
+/*
+ * Function : int pas16_detect(int hostno)
+ *
+ * Purpose : detects and initializes PAS16 controllers
+ * that were autoprobed, overriden on the LILO command line,
+ * or specified at compile time.
+ *
+ * Inputs : hostno - id of this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+
+int pas16_detect(int hostno) {
+ static int current_override = 0;
+ static unsigned short current_base = 0;
+ struct Scsi_Host *instance;
+ unsigned short io_port;
+ int count;
+
+ for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+ io_port = 0;
+
+ if (overrides[current_override].io_port)
+ {
+ io_port = overrides[current_override].io_port;
+ enable_board( current_override, io_port );
+ init_board( io_port, overrides[current_override].irq );
+ }
+ else
+ for (; !io_port && (current_base < NO_BASES); ++current_base) {
+#if (PDEBUG & PDEBUG_INIT)
+ printk("scsi%d : probing io_port %04x\n", hostno, (unsigned int) bases[current_base].io_port);
+#endif
+ if ( !bases[current_base].noauto &&
+ pas16_hw_detect( current_base ) ){
+ io_port = bases[current_base].io_port;
+ init_board( io_port, default_irqs[ current_base ] );
+#if (PDEBUG & PDEBUG_INIT)
+ printk("scsi%d : detected board.\n", hostno);
+#endif
+ }
+ }
+
+
+#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
+ printk("scsi%d : io_port = %04x\n", hostno, (unsigned int) io_port);
+#endif
+
+ if (!io_port)
+ break;
+
+ instance = scsi_register (hostno, sizeof(struct NCR5380_hostdata));
+ instance->io_port = io_port;
+
+ NCR5380_init(instance);
+
+ if (overrides[current_override].irq != IRQ_AUTO)
+ instance->irq = overrides[current_override].irq;
+ else
+ instance->irq = NCR5380_probe_irq(instance, PAS16_IRQS);
+
+ if (instance->irq != IRQ_NONE)
+ if (irqaction (instance->irq, &pas16_sigaction)) {
+ printk("scsi%d : IRQ%d not free, interrupts disabled\n",
+ hostno, instance->irq);
+ instance->irq = IRQ_NONE;
+ }
+
+ if (instance->irq == IRQ_NONE) {
+ printk("scsi%d : interrupts not enabled. for better interactive performance,\n", hostno);
+ printk("scsi%d : please jumper the board for a free IRQ.\n", hostno);
+ }
+
+#if defined(PDEBUG) && (PDEBUG & PDEBUG_INIT)
+ printk("scsi%d : irq = %d\n", hostno, instance->irq);
+#endif
+
+ printk("scsi%d : at 0x%04x", instance->host_no, (int)
+ instance->io_port);
+ if (instance->irq == IRQ_NONE)
+ printk (" interrupts disabled");
+ else
+ printk (" irq %d", instance->irq);
+ printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+ CAN_QUEUE, CMD_PER_LUN, PAS16_PUBLIC_RELEASE);
+ NCR5380_print_options(instance);
+ printk("\n");
+
+ ++current_override;
+ ++count;
+ ++hostno;
+ }
+ return count;
+}
+
+/*
+ * Function : int pas16_biosparam(int size, int dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for
+ * the specified device / size.
+ *
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ * major / minor, ip[] = {heads, sectors, cylinders}
+ *
+ * Returns : allways 0 (success), initializes ip
+ *
+ */
+
+/*
+ * XXX Most SCSI boards use this mapping, I could be incorrect. Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+ */
+
+int pas16_biosparam(int size, int dev, int * ip)
+{
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = size >> 11;
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_pread (struct Scsi_Host *instance,
+ * unsigned char *dst, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to
+ * dst
+ *
+ * Inputs : dst = destination, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog
+ * timeout.
+ */
+
+static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
+ int len) {
+ register unsigned char *d = dst;
+ register unsigned short reg = (unsigned short) (instance->io_port +
+ P_DATA_REG_OFFSET);
+ register i = len;
+
+ while ( inb(instance->io_port + P_STATUS_REG_OFFSET) & P_ST_RDY );
+
+ for (; i; --i)
+ *d++ = (unsigned char) inb(reg);
+
+ if ( inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
+ outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+ printk("scsi%d : watchdog timer fired in NCR5480_pread()\n",
+ instance->host_no);
+ return -1;
+ } else
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_pwrite (struct Scsi_Host *instance,
+ * unsigned char *src, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
+ * src
+ *
+ * Inputs : src = source, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog
+ * timeout.
+ */
+
+static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
+ int len) {
+ register unsigned char *s = src;
+ register unsigned short reg = (instance->io_port + P_DATA_REG_OFFSET);
+ register i = len;
+
+ while ( ( inb( instance->io_port + P_STATUS_REG_OFFSET ) ) & P_ST_RDY );
+ for (; i; --i)
+ outb( *s++, reg );
+
+ if (inb(instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET) & P_TS_TIM) {
+ outb( P_TS_CT, instance->io_port + P_TIMEOUT_STATUS_REG_OFFSET);
+ printk("scsi%d : watchdog timer fired in NCR5480_pwrite()\n",
+ instance->host_no);
+ return -1;
+ } else
+ return 0;
+}
+
+/*
+ * Function : const char *pas16_info(void)
+ *
+ * Purpose : provide furthur information about this driver.
+ *
+ * Returns : an empty string.
+ */
+
+const char *pas16_info (void) {
+ static const char string[]="";
+ return string;
+}
+
+#include "NCR5380.c"
diff --git a/drivers/scsi/pas16.h b/drivers/scsi/pas16.h
new file mode 100644
index 0000000..d3b9bb0
--- /dev/null
+++ b/drivers/scsi/pas16.h
@@ -0,0 +1,191 @@
+/*
+ * This driver adapted from Drew Eckhardt's Trantor T128 driver
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 666-5836
+ *
+ * ( Based on T128 - DISTRIBUTION RELEASE 3. )
+ *
+ * Modified to work with the Pro Audio Spectrum/Studio 16
+ * by John Weidman.
+ *
+ *
+ * For more information, please consult
+ *
+ * Media Vision
+ * (510) 770-8600
+ * (800) 348-7116
+ *
+ * and
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+
+#ifndef PAS16_H
+#define PAS16_H
+
+#define PAS16_PUBLIC_RELEASE 1
+
+#define PDEBUG_INIT 0x1
+#define PDEBUG_TRANSFER 0x2
+
+#define PAS16_DEFAULT_BASE_1 0x388
+#define PAS16_DEFAULT_BASE_2 0x384
+#define PAS16_DEFAULT_BASE_3 0x38c
+#define PAS16_DEFAULT_BASE_4 0x288
+
+#define PAS16_DEFAULT_BOARD_1_IRQ 10
+#define PAS16_DEFAULT_BOARD_2_IRQ 12
+#define PAS16_DEFAULT_BOARD_3_IRQ 14
+#define PAS16_DEFAULT_BOARD_4_IRQ 15
+
+
+/*
+ * The Pro Audio Spectrum boards are I/O mapped. They use a Zilog 5380
+ * SCSI controller, which is the equivalent of NCR's 5380. "Pseudo-DMA"
+ * architecture is used, where a PAL drives the DMA signals on the 5380
+ * allowing fast, blind transfers with propper handshaking.
+ */
+
+
+/* The Time-out Counter register is used to safe-guard against a stuck
+ * bus (in the case of RDY driven hadnshake) or a stuck byte (if 16-Bit
+ * DMA conversion is used). The counter uses a 28.224MHz clock
+ * divided by 14 as its clock source. In the case of a stuck byte in
+ * the holding register, an interrupt is generated (and mixed with the
+ * one with the drive) using the CD-ROM interrupt pointer.
+ */
+
+#define P_TIMEOUT_COUNTER_REG 0x4000
+#define P_TC_DISABLE 0x80 /* Set to 0 to enable timeout int. */
+ /* Bits D6-D0 contain timeout count */
+
+
+#define P_TIMEOUT_STATUS_REG_OFFSET 0x4001
+#define P_TS_TIM 0x80 /* check timeout status */
+ /* Bits D6-D4 N/U */
+#define P_TS_ARM_DRQ_INT 0x08 /* Arm DRQ Int. When set high,
+ * the next rising edge will
+ * cause a CD-ROM interrupt.
+ * When set low, the interrupt
+ * will be cleared. There is
+ * no status available for
+ * this interrupt.
+ */
+#define P_TS_ENABLE_TO_ERR_INTERRUPT /* Enable timeout error int. */
+#define P_TS_ENABLE_WAIT /* Enable Wait */
+
+#define P_TS_CT 0x01 /* clear timeout. Note: writing
+ * to this register clears the
+ * timeout error int. or status
+ */
+
+
+/*
+ * The data register reads/writes to/from the 5380 in pseudo-DMA mode
+ */
+
+#define P_DATA_REG_OFFSET 0x5c00 /* rw */
+
+#define P_STATUS_REG_OFFSET 0x5c01 /* ro */
+#define P_ST_RDY 0x80 /* 5380 DDRQ Status */
+
+#define P_IRQ_STATUS 0x5c03
+#define P_IS_IRQ 0x80 /* DIRQ status */
+
+#define PCB_CONFIG 0x803
+#define MASTER_ADDRESS_PTR 0x9a01 /* Fixed position - no relo */
+#define SYS_CONFIG_4 0x8003
+#define WAIT_STATE 0xbc00
+#define OPERATION_MODE_1 0xec03
+#define IO_CONFIG_3 0xf002
+
+
+#ifndef ASM
+int pas16_abort(Scsi_Cmnd *, int);
+int pas16_biosparam(int, int, int*);
+int pas16_detect(int);
+const char *pas16_info(void);
+int pas16_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int pas16_reset(void);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 32
+#endif
+
+/*
+ * I hadn't thought of this with the earlier drivers - but to prevent
+ * macro definition conflicts, we shouldn't define all of the internal
+ * macros when this is being used solely for the host stub.
+ */
+
+#ifdef HOSTS_C
+
+#define MV_PAS16 {"Pro Audio Spectrum-16 SCSI", pas16_detect, pas16_info,\
+ NULL, pas16_queue_command, pas16_abort, pas16_reset, NULL, \
+ pas16_biosparam, \
+ /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
+ /* cmd per lun */ CMD_PER_LUN , 0, 0}
+
+#else
+
+#define NCR5380_implementation_fields \
+ volatile unsigned short io_port
+
+#define NCR5380_local_declare() \
+ volatile unsigned short io_port
+
+#define NCR5380_setup(instance) \
+ io_port = (instance)->io_port
+
+#define PAS16_io_port(reg) ( io_port + pas16_offset[(reg)] )
+
+#if !(PDEBUG & PDEBUG_TRANSFER)
+#define NCR5380_read(reg) ( inb(PAS16_io_port(reg)) )
+#define NCR5380_write(reg, value) ( outb((value),PAS16_io_port(reg)) )
+#else
+#define NCR5380_read(reg) \
+ (((unsigned char) printk("scsi%d : read register %d at io_port %04x\n"\
+ , instance->hostno, (reg), PAS16_io_port(reg))), inb( PAS16_io_port(reg)) )
+
+#define NCR5380_write(reg, value) \
+ (printk("scsi%d : write %02x to register %d at io_port %04x\n", \
+ instance->hostno, (value), (reg), PAS16_io_port(reg)), \
+ outb( (value),PAS16_io_port(reg) ) )
+
+#endif
+
+
+#define NCR5380_intr pas16_intr
+#define NCR5380_queue_command pas16_queue_command
+#define NCR5380_abort pas16_abort
+#define NCR5380_reset pas16_reset
+
+/* 15 14 12 10 7 5 3
+ 1101 0100 1010 1000 */
+
+#define PAS16_IRQS 0xd4a8
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* PAS16_H */
diff --git a/kernel/blk_drv/scsi/scsi.c b/drivers/scsi/scsi.c
index 0c9f94e..ada400a 100644
--- a/kernel/blk_drv/scsi/scsi.c
+++ b/drivers/scsi/scsi.c
@@ -20,19 +20,19 @@
#include <linux/timer.h>
#include <linux/string.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "constants.h"
/*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
+static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.c,v 1.5 1993/09/24 12:45:18 drew Exp drew $";
*/
/* Command groups 3 and 4 are reserved and should never be used. */
const unsigned char scsi_command_size[8] = { 6, 10, 10, 12, 12, 12, 10, 10 };
-#define INTERNAL_ERROR (printk ("Internal error in file %s, line %d.\n", __FILE__, __LINE__), panic(""))
+#define INTERNAL_ERROR (panic ("Internal error in file %s, line %d.\n", __FILE__, __LINE__))
static void scsi_done (Scsi_Cmnd *SCpnt);
static int update_timeout (Scsi_Cmnd *, int);
@@ -42,6 +42,22 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt);
static int time_start;
static int time_elapsed;
+#define MAX_SCSI_DEVICE_CODE 10
+const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE] =
+{
+ "Direct-Access ",
+ "Sequential-Access",
+ "Printer ",
+ "Processor ",
+ "WORM ",
+ "CD-ROM ",
+ "Scanner ",
+ "Optical Device ",
+ "Medium Changer ",
+ "Communications "
+};
+
+
/*
global variables :
NR_SCSI_DEVICES is the number of SCSI devices we have detected,
@@ -70,8 +86,6 @@ static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0};
#define IS_RESETTING 0x08
#define ASKED_FOR_SENSE 0x10
-extern int last_reset[];
-
/*
* 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
@@ -110,13 +124,19 @@ extern int last_reset[];
};
static struct blist blacklist[] =
-{{"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */
- {"SEAGATE","ST296","921"}, /* Responds to all lun */
- {"SONY","CD-ROM CDU-541","4.3d"},
+{
{"DENON","DRD-25X","V"}, /* A cdrom that locks up when probed at lun != 0 */
- {"TEXEL","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 for seagate
- * controller, which causes SCSI code to reset bus.*/
{"MAXTOR","XT-4380S","B3C"}, /* Locks-up when LUN>0 polled. */
+ {"MAXTOR","MXT-1240S","I1.2"}, /* Locks up when LUN > 0 polled */
+ {"MAXTOR","XT-4170S","B5A"}, /* Locks-up sometimes when LUN>0 polled. */
+ {"NEC","CD-ROM DRIVE:841","1.0"}, /* Locks-up when LUN>0 polled. */
+ {"SEAGATE", "ST157N", "\004|j"}, /* causes failed REQUEST SENSE on lun 1 for aha152x
+ * controller, which causes SCSI code to reset bus.*/
+ {"SEAGATE", "ST296","921"}, /* Responds to all lun */
+ {"SONY","CD-ROM CDU-541","4.3d"},
+ {"TANDBERG","TDC 3600","U07"}, /* Locks up if polled for lun != 0 */
+ {"TEXEL","CD-ROM","1.06"}, /* causes failed REQUEST SENSE on lun 1 for seagate
+ * controller, which causes SCSI code to reset bus.*/
{NULL, NULL, NULL}};
static int blacklisted(unsigned char * response_data){
@@ -165,9 +185,10 @@ static void scan_scsis_done (Scsi_Cmnd * SCpnt)
static void scan_scsis (void)
{
- int host_nr , dev, lun, type;
+ int dev, lun, type;
unsigned char scsi_cmd [12];
unsigned char scsi_result [256];
+ struct Scsi_Host * shpnt;
Scsi_Cmnd SCmd;
++in_scan;
@@ -175,13 +196,12 @@ static void scan_scsis (void)
SCmd.next = NULL;
SCmd.prev = NULL;
- for (host_nr = 0; host_nr < max_scsi_hosts; ++host_nr)
- if (scsi_hosts[host_nr].present)
+ for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next)
{
- host_queue[host_nr] = &SCmd; /* We need this so that commands can
- time out */
+ shpnt->host_queue = &SCmd; /* We need this so that
+ commands can time out */
for (dev = 0; dev < 8; ++dev)
- if (scsi_hosts[host_nr].this_id != dev)
+ if (shpnt->this_id != dev)
/*
* We need the for so our continue, etc. work fine.
*/
@@ -192,7 +212,7 @@ static void scan_scsis (void)
for (lun = 0; lun < 8; ++lun)
#endif
{
- scsi_devices[NR_SCSI_DEVICES].host_no = host_nr;
+ scsi_devices[NR_SCSI_DEVICES].host = shpnt;
scsi_devices[NR_SCSI_DEVICES].id = dev;
scsi_devices[NR_SCSI_DEVICES].lun = lun;
scsi_devices[NR_SCSI_DEVICES].index = NR_SCSI_DEVICES;
@@ -208,7 +228,7 @@ static void scan_scsis (void)
scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0;
scsi_cmd[4] = 0;
- SCmd.host = host_nr;
+ SCmd.host = shpnt;
SCmd.target = dev;
SCmd.lun = lun;
@@ -331,30 +351,51 @@ static void scan_scsis (void)
switch(type){
case TYPE_TAPE:
printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", MAX_ST,
- host_nr , dev, lun);
+ shpnt->host_no , dev, lun);
if(NR_ST != -1) ++MAX_ST;
break;
case TYPE_ROM:
printk("Detected scsi CD-ROM sr%d at scsi%d, id %d, lun %d\n", MAX_SR,
- host_nr , dev, lun);
+ shpnt->host_no , dev, lun);
if(NR_SR != -1) ++MAX_SR;
break;
case TYPE_DISK:
case TYPE_MOD:
printk("Detected scsi disk sd%d at scsi%d, id %d, lun %d\n", MAX_SD,
- host_nr , dev, lun);
+ shpnt->host_no , dev, lun);
if(NR_SD != -1) ++MAX_SD;
break;
default:
break;
};
+ if(NR_SG != -1) ++MAX_SG;
+
scsi_devices[NR_SCSI_DEVICES].scsi_level =
scsi_result[2] & 0x07;
if (scsi_devices[NR_SCSI_DEVICES].scsi_level >= 2 ||
(scsi_devices[NR_SCSI_DEVICES].scsi_level == 1 &&
(scsi_result[3] & 0x0f) == 1))
scsi_devices[NR_SCSI_DEVICES].scsi_level++;
+/*
+ * Set the tagged_queue flag for SCSI-II devices that purport to support
+ * tagged queuing in the INQUIRY data.
+ */
+
+ scsi_devices[NR_SCSI_DEVICES].tagged_queue = 0;
+
+ if ((scsi_devices[NR_SCSI_DEVICES].scsi_level == SCSI_2) &&
+ (scsi_result[7] & 2)) {
+ scsi_devices[NR_SCSI_DEVICES].tagged_supported = 1;
+ scsi_devices[NR_SCSI_DEVICES].current_tag = 0;
+ }
+
+/*
+ * Accomodate drivers that want to sleep when they should be in a polling
+ * loop.
+ */
+
+ scsi_devices[NR_SCSI_DEVICES].disconnect = 0;
/*
* Some revisions of the Texel CD ROM drives have handshaking
@@ -364,8 +405,8 @@ static void scan_scsis (void)
* a TEXEL drive.
*/
- if(memcmp("TEXEL", &scsi_result[8], 5) != 0 ||
- memcmp("CD-ROM", &scsi_result[16], 6) != 0
+ if(strncmp("TEXEL", (char *) &scsi_result[8], 5) != 0 ||
+ strncmp("CD-ROM", (char *) &scsi_result[16], 6) != 0
/*
* XXX 1.06 has problems, some one should figure out the others too so
* ALL TEXEL drives don't suffer in performance, especially when I finish
@@ -373,7 +414,7 @@ static void scan_scsis (void)
*/
#ifdef notyet
- || (strncmp("1.06", &scsi_result[[, 4) != 0)
+ || (strncmp("1.06", (char *) &scsi_result[[, 4) != 0)
#endif
)
scsi_devices[NR_SCSI_DEVICES].borken = 0;
@@ -414,13 +455,9 @@ static void scan_scsis (void)
}
} /* if result == DID_OK ends */
} /* for lun ends */
- host_queue[host_nr] = NULL; /* No longer needed here */
+ shpnt->host_queue = NULL; /* No longer needed here */
} /* if present */
- for (host_nr = 0; host_nr < max_scsi_hosts; ++host_nr)
- if (scsi_hosts[host_nr].present)
- if(host_queue[host_nr]) panic("host_queue not cleared");
-
printk("scsi : detected ");
if(NR_SD != -1)
printk("%d SCSI disk%s ", MAX_SD, (MAX_SD != 1) ? "s" : "");
@@ -456,19 +493,18 @@ static void scsi_times_out (Scsi_Cmnd * SCpnt)
case NORMAL_TIMEOUT:
if (!in_scan)
printk("SCSI host %d timed out - aborting command\n",
- SCpnt->host);
+ SCpnt->host->host_no);
if (!scsi_abort (SCpnt, DID_TIME_OUT))
return;
case IN_ABORT:
printk("SCSI host %d abort() timed out - reseting\n",
- SCpnt->host);
+ SCpnt->host->host_no);
if (!scsi_reset (SCpnt))
return;
case IN_RESET:
case (IN_ABORT | IN_RESET):
- printk("Unable to reset scsi host %d\n",SCpnt->host);
- panic("");
+ panic("Unable to reset scsi host %d\n",SCpnt->host->host_no);
default:
INTERNAL_ERROR;
}
@@ -484,8 +520,9 @@ of the calling code to ensure that this is the case. */
Scsi_Cmnd * request_queueable (struct request * req, int index)
{
- int host;
Scsi_Cmnd * SCpnt = NULL;
+ int tablesize;
+ struct buffer_head * bh;
if ((index < 0) || (index > NR_SCSI_DEVICES))
panic ("Index number in allocate_device() is out of range.\n");
@@ -493,8 +530,7 @@ Scsi_Cmnd * request_queueable (struct request * req, int index)
if (req && req->dev <= 0)
panic("Invalid device in allocate_device");
- host = scsi_devices[index].host_no;
- SCpnt = host_queue[host];
+ SCpnt = scsi_devices[index].host->host_queue;
while(SCpnt){
if(SCpnt->target == scsi_devices[index].id &&
SCpnt->lun == scsi_devices[index].lun)
@@ -504,12 +540,37 @@ Scsi_Cmnd * request_queueable (struct request * req, int index)
if (!SCpnt) return NULL;
- if (scsi_hosts[host].can_queue
- && host_busy[host] >= scsi_hosts[host].can_queue) return NULL;
+ if (scsi_devices[index].host->hostt->can_queue
+ && scsi_devices[index].host->host_busy >= scsi_devices[index].host->hostt->can_queue) return NULL;
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
- req->dev = -1;
+ tablesize = scsi_devices[index].host->sg_tablesize;
+ bh = req->bh;
+ if(!tablesize) bh = NULL;
+ /* Take a quick look through the table to see how big it is. We already
+ have our copy of req, so we can mess with that if we want to. */
+ while(req->nr_sectors && bh){
+ tablesize--;
+ req->nr_sectors -= bh->b_size >> 9;
+ req->sector += bh->b_size >> 9;
+ if(!tablesize) break;
+ bh = bh->b_reqnext;
+ };
+ if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */
+ SCpnt->request.bhtail = bh;
+ req->bh = bh->b_reqnext; /* Divide request */
+ bh->b_reqnext = NULL;
+ bh = req->bh;
+
+ /* Now reset things so that req looks OK */
+ SCpnt->request.nr_sectors -= req->nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ SCpnt->request.waiting = NULL; /* Wait until whole thing done */
+ } else
+ req->dev = -1;
+
} else {
SCpnt->request.dev = 0xffff; /* Busy, but no request */
SCpnt->request.waiting = NULL; /* And no one is waiting for the device either */
@@ -533,8 +594,11 @@ of the packets for each device */
Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
{
- int host, dev = -1;
+ int dev = -1;
struct request * req = NULL;
+ int tablesize;
+ struct buffer_head * bh;
+ struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
Scsi_Cmnd * SCwait = NULL;
@@ -546,10 +610,10 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
/* See if this request has already been queued by an interrupt routine */
if (req && (dev = req->dev) <= 0) return NULL;
- host = scsi_devices[index].host_no;
+ host = scsi_devices[index].host;
while (1==1){
- SCpnt = host_queue[host];
+ SCpnt = host->host_queue;
while(SCpnt){
if(SCpnt->target == scsi_devices[index].id &&
SCpnt->lun == scsi_devices[index].lun) {
@@ -578,8 +642,34 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
} else {
if (req) {
memcpy(&SCpnt->request, req, sizeof(struct request));
- req->dev = -1;
- *reqp = req->next;
+ tablesize = scsi_devices[index].host->sg_tablesize;
+ bh = req->bh;
+ if(!tablesize) bh = NULL;
+ /* Take a quick look through the table to see how big it is. We already
+ have our copy of req, so we can mess with that if we want to. */
+ while(req->nr_sectors && bh){
+ tablesize--;
+ req->nr_sectors -= bh->b_size >> 9;
+ req->sector += bh->b_size >> 9;
+ if(!tablesize) break;
+ bh = bh->b_reqnext;
+ };
+ if(req->nr_sectors && bh && bh->b_reqnext){ /* Any leftovers? */
+ SCpnt->request.bhtail = bh;
+ req->bh = bh->b_reqnext; /* Divide request */
+ bh->b_reqnext = NULL;
+ bh = req->bh;
+ /* Now reset things so that req looks OK */
+ SCpnt->request.nr_sectors -= req->nr_sectors;
+ req->current_nr_sectors = bh->b_size >> 9;
+ req->buffer = bh->b_data;
+ SCpnt->request.waiting = NULL; /* Wait until whole thing done */
+ }
+ else
+ {
+ req->dev = -1;
+ *reqp = req->next;
+ };
} else {
SCpnt->request.dev = 0xffff; /* Busy */
SCpnt->request.waiting = NULL; /* And no one is waiting for this to complete */
@@ -602,22 +692,19 @@ Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait)
inline void internal_cmnd (Scsi_Cmnd * SCpnt)
{
- int temp, host;
-
+ int temp;
+ struct Scsi_Host * host;
#ifdef DEBUG_DELAY
int clock;
#endif
host = SCpnt->host;
- 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];
+temp = host->last_reset;
while (jiffies < temp);
update_timeout(SCpnt, SCpnt->timeout_per_command);
@@ -628,29 +715,29 @@ update_timeout(SCpnt, SCpnt->timeout_per_command);
*/
#ifdef DEBUG
printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer = %08x, \n"
- "bufflen = %d, done = %08x)\n", SCpnt->host, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
+ "bufflen = %d, done = %08x)\n", SCpnt->host->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done);
#endif
- if (scsi_hosts[host].can_queue)
+ if (host->hostt->can_queue)
{
#ifdef DEBUG
printk("queuecommand : routine at %08x\n",
- scsi_hosts[host].queuecommand);
+ host->hostt->queuecommand);
#endif
- scsi_hosts[host].queuecommand (SCpnt, scsi_done);
+ host->hostt->queuecommand (SCpnt, scsi_done);
}
else
{
#ifdef DEBUG
- printk("command() : routine at %08x\n", scsi_hosts[host].command);
+ printk("command() : routine at %08x\n", host->hostt->command);
#endif
- temp=scsi_hosts[host].command (SCpnt);
+ temp=host->hostt->command (SCpnt);
SCpnt->result = temp;
#ifdef DEBUG_DELAY
clock = jiffies + 400;
while (jiffies < clock);
- printk("done(host = %d, result = %04x) : routine at %08x\n", host, temp, done);
+ printk("done(host = %d, result = %04x) : routine at %08x\n", host->host_no, temp, done);
#endif
scsi_done(SCpnt);
}
@@ -694,7 +781,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
int timeout, int retries
)
{
- int host = SCpnt->host;
+ struct Scsi_Host * host = SCpnt->host;
#ifdef DEBUG
{
@@ -702,17 +789,16 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
int target = SCpnt->target;
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);
+ "command : " , host->host_no, target, buffer, bufflen, done, timeout, retries);
for (i = 0; i < 10; ++i)
printk ("%02x ", ((unsigned char *) cmnd)[i]);
printk("\n");
};
#endif
- if ((host < 0) || (host >= max_scsi_hosts) || !scsi_hosts[host].present)
+ if (!host)
{
- printk ("Invalid or not present host number. %d\n", host);
- panic("");
+ panic ("Invalid or not present host. %d\n", host->host_no);
}
@@ -726,14 +812,14 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
while (1==1){
cli();
- if (scsi_hosts[host].can_queue
- && host_busy[host] >= scsi_hosts[host].can_queue)
+ if (host->hostt->can_queue
+ && host->host_busy >= host->hostt->can_queue)
{
sti();
- SCSI_SLEEP(&host_wait[host],
- (host_busy[host] >= scsi_hosts[host].can_queue));
+ SCSI_SLEEP(&host->host_wait,
+ (host->host_busy >= host->hostt->can_queue));
} else {
- host_busy[host]++;
+ host->host_busy++;
sti();
break;
};
@@ -746,7 +832,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
*/
- memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 10);
+ memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 12);
#if 0
SCpnt->host = host;
SCpnt->target = target;
@@ -760,7 +846,7 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
SCpnt->done = done;
SCpnt->timeout_per_command = timeout;
- memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 10);
+ memcpy ((void *) SCpnt->cmnd , (void *) cmnd, 12);
/* Zero the sense buffer. Some host adapters automatically request
sense on error. 0 is not a valid sense code. */
memset ((void *) SCpnt->sense_buffer, 0, sizeof SCpnt->sense_buffer);
@@ -787,20 +873,22 @@ void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd ,
*/
static void reset (Scsi_Cmnd * SCpnt)
- {
- #ifdef DEBUG
- printk("scsi: reset(%d)\n", SCpnt->host);
- #endif
-
+{
+#ifdef DEBUG
+ printk("scsi: reset(%d)\n", SCpnt->host->host_no);
+#endif
+
SCpnt->flags |= (WAS_RESET | IS_RESETTING);
scsi_reset(SCpnt);
-
- #ifdef DEBUG
- printk("performing request sense\n");
- #endif
-
+
+#if 0
+#ifdef DEBUG
+ printk("performing request sense\n");
+#endif
+
scsi_request_sense (SCpnt);
- }
+#endif
+}
@@ -819,7 +907,7 @@ static int check_sense (Scsi_Cmnd * SCpnt)
SCpnt->flags &= ~ASKED_FOR_SENSE;
#ifdef DEBUG_INIT
- printk("scsi%d : ", SCpnt->host);
+ printk("scsi%d : ", SCpnt->host->host_no);
print_sense("", SCpnt);
printk("\n");
#endif
@@ -881,7 +969,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
int exit=0;
int checked;
int oldto;
- int host = SCpnt->host;
+ struct Scsi_Host * host = SCpnt->host;
int result = SCpnt->result;
oldto = update_timeout(SCpnt, 0);
@@ -891,14 +979,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
#define PENDING 4
#ifdef DEBUG
- printk("In scsi_done(host = %d, result = %06x)\n", host, result);
+ printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result);
#endif
- if (host > max_scsi_hosts || host < 0)
- {
- update_timeout(SCpnt, 0);
- panic("scsi_done() called with invalid host number.\n");
- }
-
switch (host_byte(result))
{
case DID_OK:
@@ -918,7 +1000,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
if (!(SCpnt->flags & WAS_RESET))
{
printk("scsi%d : target %d lun %d request sense failed, performing reset.\n",
- SCpnt->host, SCpnt->target, SCpnt->lun);
+ SCpnt->host->host_no, SCpnt->target, SCpnt->lun);
reset(SCpnt);
return;
}
@@ -1022,7 +1104,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
case RESERVATION_CONFLICT:
printk("scsi%d : RESERVATION CONFLICT performing reset.\n",
- SCpnt->host);
+ SCpnt->host->host_no);
reset(SCpnt);
return;
#if 0
@@ -1038,8 +1120,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
}
break;
default:
- printk("scsi: unsupported message byte %d recieved\n", msg_byte(result));
- panic ("");
+ panic("scsi: unsupported message byte %d recieved\n", msg_byte(result));
}
break;
case DID_TIME_OUT:
@@ -1130,7 +1211,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
&& !(SCpnt->flags & WAS_RESET))
{
printk("scsi%d : reseting for second half of retries.\n",
- SCpnt->host);
+ SCpnt->host->host_no);
reset(SCpnt);
break;
}
@@ -1166,8 +1247,8 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
#ifdef DEBUG
printk("Calling done function - at address %08x\n", SCpnt->done);
#endif
- host_busy[host]--; /* Indicate that we are free */
- wake_up(&host_wait[host]);
+ host->host_busy--; /* Indicate that we are free */
+ wake_up(&host->host_wait);
SCpnt->result = result | ((exit & 0xff) << 24);
SCpnt->use_sg = SCpnt->old_use_sg;
SCpnt->done (SCpnt);
@@ -1199,7 +1280,7 @@ static void scsi_done (Scsi_Cmnd * SCpnt)
int scsi_abort (Scsi_Cmnd * SCpnt, int why)
{
int temp, oldto;
- int host = SCpnt->host;
+ struct Scsi_Host * host = SCpnt->host;
while(1)
{
@@ -1216,7 +1297,7 @@ int scsi_abort (Scsi_Cmnd * SCpnt, int why)
sti();
- if (!host_busy[host] || !scsi_hosts[host].abort(SCpnt, why))
+ if (!host->host_busy || !host->hostt->abort(SCpnt, why))
temp = 0;
else
temp = 1;
@@ -1234,10 +1315,10 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
{
int temp, oldto;
Scsi_Cmnd * SCpnt1;
- int host = SCpnt->host;
+ struct Scsi_Host * host = SCpnt->host;
#ifdef DEBUG
- printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host);
+ printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no);
#endif
while (1) {
cli();
@@ -1251,10 +1332,10 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
SCpnt->internal_timeout |= IN_RESET;
oldto = update_timeout(SCpnt, RESET_TIMEOUT);
- if (host_busy[host])
+ if (host->host_busy)
{
sti();
- SCpnt1 = host_queue[host];
+ SCpnt1 = host->host_queue;
while(SCpnt1) {
if ((SCpnt1->request.dev > 0) &&
!(SCpnt1->flags & IS_RESETTING) &&
@@ -1263,16 +1344,16 @@ int scsi_reset (Scsi_Cmnd * SCpnt)
SCpnt1 = SCpnt1->next;
};
- temp = scsi_hosts[host].reset();
+ temp = host->hostt->reset();
}
else
{
- host_busy[host]++;
+ host->host_busy++;
sti();
- temp = scsi_hosts[host].reset();
- last_reset[host] = jiffies;
- host_busy[host]--;
+ temp = host->hostt->reset();
+ host->last_reset = jiffies;
+ host->host_busy--;
}
cli();
@@ -1291,7 +1372,8 @@ static void scsi_main_timeout(void)
We must not enter update_timeout with a timeout condition still pending.
*/
- int timed_out, host;
+ int timed_out;
+ struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
do {
@@ -1303,8 +1385,8 @@ static void scsi_main_timeout(void)
*/
timed_out = 0;
- for(host = 0; host < max_scsi_hosts; host++) {
- SCpnt = host_queue[host];
+ for(host = scsi_hostlist; host; host = host->next) {
+ SCpnt = host->host_queue;
while (SCpnt){
if (SCpnt->timeout > 0 && SCpnt->timeout <= time_elapsed)
{
@@ -1332,8 +1414,9 @@ static void scsi_main_timeout(void)
static int update_timeout(Scsi_Cmnd * SCset, int timeout)
{
- unsigned int least, used, host;
+ unsigned int least, used;
unsigned int oldto;
+ struct Scsi_Host * host;
Scsi_Cmnd * SCpnt = NULL;
cli();
@@ -1359,8 +1442,8 @@ static int update_timeout(Scsi_Cmnd * SCset, int timeout)
least = 0xffffffff;
- for(host = 0; host < max_scsi_hosts; host++) {
- SCpnt = host_queue[host];
+ for(host = scsi_hostlist; host; host = host->next) {
+ SCpnt = host->host_queue;
while (SCpnt){
if (SCpnt->timeout > 0 && (SCpnt->timeout -= used) < least)
least = SCpnt->timeout;
@@ -1463,7 +1546,7 @@ int scsi_free(void *obj, unsigned int len)
unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end)
{
int i;
- int host;
+ struct Scsi_Host * host;
Scsi_Cmnd * SCpnt;
#ifdef FOO_ON_YOU
return;
@@ -1471,10 +1554,8 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
timer_table[SCSI_TIMER].fn = scsi_main_timeout;
timer_table[SCSI_TIMER].expires = 0;
- scsi_init(); /* initialize all hosts */
-
- for (i = 0; i < max_scsi_hosts; ++i)
- last_reset[i] = 0;
+ /* initialize all hosts */
+ memory_start = scsi_init(memory_start, memory_end);
scsi_devices = (Scsi_Device *) memory_start;
scan_scsis(); /* scan for scsi devices */
@@ -1483,6 +1564,7 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
memory_start = sd_init1(memory_start, memory_end);
memory_start = st_init1(memory_start, memory_end);
memory_start = sr_init1(memory_start, memory_end);
+ memory_start = sg_init1(memory_start, memory_end);
last_cmnd = (Scsi_Cmnd *) memory_start;
@@ -1504,9 +1586,10 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
default:
break;
};
+ sg_attach(&scsi_devices[i]);
if(scsi_devices[i].type != -1){
- for(j=0;j<scsi_hosts[scsi_devices[i].host_no].cmd_per_lun;j++){
- SCpnt->host = scsi_devices[i].host_no;
+ for(j=0;j<scsi_devices[i].host->hostt->cmd_per_lun;j++){
+ SCpnt->host = scsi_devices[i].host;
SCpnt->target = scsi_devices[i].id;
SCpnt->lun = scsi_devices[i].lun;
SCpnt->index = i;
@@ -1516,12 +1599,12 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
SCpnt->underflow = 0;
SCpnt->transfersize = 0;
SCpnt->host_scribble = NULL;
- host = scsi_devices[i].host_no;
- if(host_queue[host])
- host_queue[host]->prev = SCpnt;
- SCpnt->next = host_queue[host];
+ host = scsi_devices[i].host;
+ if(host->host_queue)
+ host->host_queue->prev = SCpnt;
+ SCpnt->next = host->host_queue;
SCpnt->prev = NULL;
- host_queue[host] = SCpnt;
+ host->host_queue = SCpnt;
SCpnt++;
};
};
@@ -1533,19 +1616,19 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
dma_sectors = 16; /* Base value we use */
for (i = 0; i < NR_SCSI_DEVICES; ++i) {
- int host;
- host = scsi_devices[i].host_no;
+ struct Scsi_Host * host;
+ host = scsi_devices[i].host;
if(scsi_devices[i].type != TYPE_TAPE)
- dma_sectors += ((scsi_hosts[host].sg_tablesize *
+ dma_sectors += ((host->sg_tablesize *
sizeof(struct scatterlist) + 511) >> 9) *
- scsi_hosts[host].cmd_per_lun;
+ host->hostt->cmd_per_lun;
- if(scsi_hosts[host].unchecked_isa_dma &&
+ if(host->unchecked_isa_dma &&
memory_end > ISA_DMA_THRESHOLD &&
scsi_devices[i].type != TYPE_TAPE) {
- dma_sectors += (PAGE_SIZE >> 9) * scsi_hosts[host].sg_tablesize *
- scsi_hosts[host].cmd_per_lun;
+ dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize *
+ host->hostt->cmd_per_lun;
need_isa_buffer++;
};
};
@@ -1565,7 +1648,9 @@ unsigned long scsi_dev_init (unsigned long memory_start,unsigned long memory_end
memory_start = sd_init(memory_start, memory_end); /* init scsi disks */
memory_start = st_init(memory_start, memory_end); /* init scsi tapes */
- memory_start = sr_init(memory_start, memory_end);
+ memory_start = sr_init(memory_start, memory_end); /* init scsi CDROMs */
+ memory_start = sg_init(memory_start, memory_end); /* init scsi generic */
+
return memory_start;
}
@@ -1576,7 +1661,7 @@ static void print_inquiry(unsigned char *data)
printk(" Vendor: ");
for (i = 8; i < 16; i++)
{
- if (data[i] >= 20 && i < data[4] + 5)
+ if (data[i] >= 0x20 && i < data[4] + 5)
printk("%c", data[i]);
else
printk(" ");
@@ -1585,7 +1670,7 @@ static void print_inquiry(unsigned char *data)
printk(" Model: ");
for (i = 16; i < 32; i++)
{
- if (data[i] >= 20 && i < data[4] + 5)
+ if (data[i] >= 0x20 && i < data[4] + 5)
printk("%c", data[i]);
else
printk(" ");
@@ -1594,7 +1679,7 @@ static void print_inquiry(unsigned char *data)
printk(" Rev: ");
for (i = 32; i < 36; i++)
{
- if (data[i] >= 20 && i < data[4] + 5)
+ if (data[i] >= 0x20 && i < data[4] + 5)
printk("%c", data[i]);
else
printk(" ");
@@ -1604,17 +1689,8 @@ static void print_inquiry(unsigned char *data)
i = data[0] & 0x1f;
- printk(" Type: %s ", i == 0x00 ? "Direct-Access " :
- i == 0x01 ? "Sequential-Access" :
- i == 0x02 ? "Printer " :
- i == 0x03 ? "Processor " :
- i == 0x04 ? "WORM " :
- i == 0x05 ? "CD-ROM " :
- i == 0x06 ? "Scanner " :
- i == 0x07 ? "Optical Device " :
- i == 0x08 ? "Medium Changer " :
- i == 0x09 ? "Communications " :
- "Unknown " );
+ printk(" Type: %s ",
+ i < MAX_SCSI_DEVICE_CODE ? scsi_device_types[i] : "Unknown " );
printk(" ANSI SCSI revision: %02x", data[2] & 0x07);
if ((data[2] & 0x07) == 1 && (data[3] & 0x0f) == 1)
printk(" CCS\n");
diff --git a/kernel/blk_drv/scsi/scsi.h b/drivers/scsi/scsi.h
index 0b0e094..45a6c5c 100644
--- a/kernel/blk_drv/scsi/scsi.h
+++ b/drivers/scsi/scsi.h
@@ -14,7 +14,7 @@
#define _SCSI_H
/*
- $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.1 1992/07/24 06:27:38 root Exp root $
+ $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/scsi.h,v 1.3 1993/09/24 12:20:33 drew Exp $
For documentation on the OPCODES, MESSAGES, and SENSE values,
please consult the SCSI standard.
@@ -96,6 +96,11 @@ extern const unsigned char scsi_command_size[8];
#define LINKED_CMD_COMPLETE 0x0a
#define LINKED_FLG_CMD_COMPLETE 0x0b
#define BUS_DEVICE_RESET 0x0c
+
+#define SIMPLE_QUEUE_TAG 0x20
+#define HEAD_OF_QUEUE_TAG 0x21
+#define ORDERED_QUEUE_TAG 0x22
+
#define IDENTIFY_BASE 0x80
#define IDENTIFY(can_disconnect, lun) (IDENTIFY_BASE |\
((can_disconnect) ? 0x40 : 0) |\
@@ -225,6 +230,8 @@ extern const unsigned char scsi_command_size[8];
#define TYPE_MOD 0x07 /* Magneto-optical disk - treated as TYPE_DISK */
#define TYPE_NO_LUN 0x7f
+
+#define MAX_COMMAND_SIZE 12
/*
SCSI command sets
@@ -250,9 +257,10 @@ extern const unsigned char scsi_command_size[8];
*/
typedef struct scsi_device {
- unsigned char host_no, id, lun, index;
+ unsigned char id, lun, index;
int access_count; /* Count of open channels/mounts */
struct wait_queue * device_wait; /* Used to wait if device is busy */
+ struct Scsi_Host * host;
char type;
char scsi_level;
unsigned writeable:1;
@@ -263,6 +271,10 @@ typedef struct scsi_device {
unsigned lockable:1; /* Able to prevent media removal */
unsigned borken:1; /* Tell the Seagate driver to be
painfully slow on this device */
+ unsigned tagged_supported:1; /* Supports SCSI-II tagged queing */
+ unsigned tagged_queue:1; /*SCSI-II tagged queing enabled */
+ unsigned disconnect:1; /* can disconnect */
+ unsigned char current_tag; /* current tag */
} Scsi_Device;
/*
Use these to separate status msg and our bytes
@@ -323,12 +335,12 @@ typedef struct scsi_pointer {
} Scsi_Pointer;
typedef struct scsi_cmnd {
- int host;
+ struct Scsi_Host * host;
unsigned char target, lun, index;
struct scsi_cmnd *next, *prev;
/* These elements define the operation we are about to perform */
- unsigned char cmnd[10];
+ unsigned char cmnd[12];
unsigned request_bufflen; /* Actual request size */
void * request_buffer; /* Actual requested buffer */
@@ -393,6 +405,8 @@ typedef struct scsi_cmnd {
to be at an address < 16Mb). */
int result; /* Status code from lower level driver */
+
+ unsigned char tag; /* SCSI-II queued command tag */
} Scsi_Cmnd;
/*
@@ -415,7 +429,7 @@ extern Scsi_Cmnd * request_queueable(struct request *, int);
extern int scsi_reset (Scsi_Cmnd *);
extern int max_scsi_hosts;
-extern int MAX_SD, NR_SD, MAX_ST, NR_ST, MAX_SR, NR_SR;
+extern int MAX_SD, NR_SD, MAX_ST, NR_ST, MAX_SR, NR_SR, NR_SG, MAX_SG;
extern unsigned long sd_init(unsigned long, unsigned long);
extern unsigned long sd_init1(unsigned long, unsigned long);
extern void sd_attach(Scsi_Device *);
@@ -428,6 +442,10 @@ extern unsigned long st_init(unsigned long, unsigned long);
extern unsigned long st_init1(unsigned long, unsigned long);
extern void st_attach(Scsi_Device *);
+extern unsigned long sg_init(unsigned long, unsigned long);
+extern unsigned long sg_init1(unsigned long, unsigned long);
+extern void sg_attach(Scsi_Device *);
+
#if defined(MAJOR_NR) && (MAJOR_NR != 9)
static void end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors)
{
diff --git a/kernel/blk_drv/scsi/scsi_debug.c b/drivers/scsi/scsi_debug.c
index e5bc737..ffda507 100644
--- a/kernel/blk_drv/scsi/scsi_debug.c
+++ b/drivers/scsi/scsi_debug.c
@@ -18,7 +18,7 @@
#include <asm/system.h>
#include <asm/io.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
diff --git a/kernel/blk_drv/scsi/scsi_debug.h b/drivers/scsi/scsi_debug.h
index 263fda3..263fda3 100644
--- a/kernel/blk_drv/scsi/scsi_debug.h
+++ b/drivers/scsi/scsi_debug.h
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.c b/drivers/scsi/scsi_ioctl.c
index f25fb77..64835f6 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.c
+++ b/drivers/scsi/scsi_ioctl.c
@@ -7,7 +7,7 @@
#include <linux/sched.h>
#include <linux/string.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "scsi_ioctl.h"
@@ -25,15 +25,15 @@
* (int *) arg
*/
-static int ioctl_probe(int dev, void *buffer)
+static int ioctl_probe(struct Scsi_Host * host, void *buffer)
{
int temp;
unsigned int len,slen;
const char * string;
- if ((temp = scsi_hosts[dev].present) && buffer) {
+ if ((temp = host->hostt->present) && buffer) {
len = get_fs_long ((unsigned long *) buffer);
- string = scsi_hosts[dev].info();
+ string = host->hostt->info();
slen = strlen(string);
if (len > slen)
len = slen + 1;
@@ -88,11 +88,9 @@ static void scsi_ioctl_done (Scsi_Cmnd * SCpnt)
static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
{
- int host, result;
+ int result;
Scsi_Cmnd * SCpnt;
- host = dev->host_no;
-
SCpnt = allocate_device(NULL, dev->index, 1);
scsi_do_cmd(SCpnt, cmd, NULL, 0,
scsi_ioctl_done, MAX_TIMEOUT,
@@ -124,7 +122,7 @@ static int ioctl_internal_command(Scsi_Device *dev, char * cmd)
};
default: /* Fall through for non-removable media */
printk("SCSI CD error: host %d id %d lun %d return code = %x\n",
- dev->host_no,
+ dev->host->host_no,
dev->id,
dev->lun,
SCpnt->result);
@@ -148,7 +146,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
char * cmd_in;
Scsi_Cmnd * SCpnt;
unsigned char opcode;
- int inlen, outlen, cmdlen, host;
+ int inlen, outlen, cmdlen;
int needed;
int result;
@@ -172,7 +170,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode));
memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen);
- host = dev->host_no;
+
cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5);
#ifndef DEBUG_NO_CMD
@@ -202,7 +200,7 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
{
int i;
printk("scsi_ioctl : device %d. command = ", dev->id);
- for (i = 0; i < 10; ++i)
+ for (i = 0; i < 12; ++i)
printk("%02x ", cmd[i]);
printk("\nbuffer =");
for (i = 0; i < 20; ++i)
@@ -225,21 +223,31 @@ static int ioctl_command(Scsi_Device *dev, void *buffer)
*/
int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
{
- char scsi_cmd[10];
+ char scsi_cmd[12];
if ((cmd != 0 && dev->index > NR_SCSI_DEVICES))
return -ENODEV;
- if ((cmd == 0 && dev->host_no > max_scsi_hosts))
- return -ENODEV;
switch (cmd) {
case SCSI_IOCTL_GET_IDLUN:
verify_area(VERIFY_WRITE, (void *) arg, sizeof(int));
put_fs_long(dev->id + (dev->lun << 8) +
- (dev->host_no << 16), (unsigned long *) arg);
+ (dev->host->host_no << 16), (unsigned long *) arg);
return 0;
+ case SCSI_IOCTL_TAGGED_ENABLE:
+ if(!suser()) return -EACCES;
+ if(!dev->tagged_supported) return -EINVAL;
+ dev->tagged_queue = 1;
+ dev->current_tag = 1;
+ break;
+ case SCSI_IOCTL_TAGGED_DISABLE:
+ if(!suser()) return -EACCES;
+ if(!dev->tagged_supported) return -EINVAL;
+ dev->tagged_queue = 0;
+ dev->current_tag = 0;
+ break;
case SCSI_IOCTL_PROBE_HOST:
- return ioctl_probe(dev->host_no, arg);
+ return ioctl_probe(dev->host, arg);
case SCSI_IOCTL_SEND_COMMAND:
return ioctl_command((Scsi_Device *) dev, arg);
case SCSI_IOCTL_DOORLOCK:
@@ -267,6 +275,7 @@ int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg)
default :
return -EINVAL;
}
+ return -EINVAL;
}
/*
diff --git a/kernel/blk_drv/scsi/scsi_ioctl.h b/drivers/scsi/scsi_ioctl.h
index dac9548..dac9548 100644
--- a/kernel/blk_drv/scsi/scsi_ioctl.h
+++ b/drivers/scsi/scsi_ioctl.h
diff --git a/kernel/blk_drv/scsi/sd.c b/drivers/scsi/sd.c
index aeef78e..712cea6 100644
--- a/kernel/blk_drv/scsi/sd.c
+++ b/drivers/scsi/sd.c
@@ -20,7 +20,7 @@
#define MAJOR_NR 8
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "sd.h"
@@ -143,7 +143,7 @@ static void rw_intr (Scsi_Cmnd *SCpnt)
int this_count = SCpnt->bufflen >> 9;
#ifdef DEBUG
- printk("sd%d : rw_intr(%d, %x)\n", MINOR(SCpnt->request.dev), SCpnt->host, result);
+ printk("sd%d : rw_intr(%d, %d)\n", MINOR(SCpnt->request.dev), SCpnt->host->host_no, result);
#endif
/*
@@ -291,7 +291,7 @@ of the disk.
} /* driver byte != 0 */
if (result) {
printk("SCSI disk error : host %d id %d lun %d return code = %x\n",
- rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->host_no,
+ rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->id,
rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->lun, result);
@@ -360,7 +360,7 @@ static void do_sd_request (void)
req1 = req;
req = req->next;
};
- if (SCpnt) {
+ if (SCpnt && req->dev == -1) {
if (req == CURRENT)
CURRENT = CURRENT->next;
else
@@ -436,8 +436,7 @@ repeat:
cmd[0] = READ_6;
break;
default :
- printk ("Unknown sd command %d\n", SCpnt->request.cmd);
- panic("");
+ panic ("Unknown sd command %d\n", SCpnt->request.cmd);
}
SCpnt->this_count = 0;
@@ -450,7 +449,7 @@ repeat:
buff = SCpnt->request.buffer;
SCpnt->use_sg = 0;
- } else if (scsi_hosts[SCpnt->host].sg_tablesize == 0 ||
+ } else if (SCpnt->host->sg_tablesize == 0 ||
(need_isa_buffer &&
dma_free_sectors < 10)) {
@@ -461,7 +460,7 @@ repeat:
it all, we need to be conservative, because if we run low enough
we have no choice but to panic. */
- if (scsi_hosts[SCpnt->host].sg_tablesize != 0 &&
+ if (SCpnt->host->sg_tablesize != 0 &&
need_isa_buffer &&
dma_free_sectors < 10)
printk("Warning: SCSI DMA buffer space running low. Using non scatter-gather I/O.\n");
@@ -480,7 +479,7 @@ repeat:
this_count = 0;
this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff);
count = 0;
- while(bh && count < scsi_hosts[SCpnt->host].sg_tablesize) {
+ while(bh && count < SCpnt->host->sg_tablesize) {
if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
this_count += (bh->b_size >> 9);
count++;
@@ -507,7 +506,7 @@ repeat:
sgpnt[count].alt_address = NULL;
sgpnt[count].length = bh->b_size;
if (((int) sgpnt[count].address) + sgpnt[count].length >
- ISA_DMA_THRESHOLD & (scsi_hosts[SCpnt->host].unchecked_isa_dma)) {
+ ISA_DMA_THRESHOLD & (SCpnt->host->unchecked_isa_dma)) {
sgpnt[count].alt_address = sgpnt[count].address;
/* We try and avoid exhausting the DMA pool, since it is easier
to control usage here. In other places we might have a more
@@ -547,7 +546,7 @@ repeat:
if(SCpnt->use_sg == 0){
if (((int) buff) + (this_count << 9) > ISA_DMA_THRESHOLD &&
- (scsi_hosts[SCpnt->host].unchecked_isa_dma)) {
+ (SCpnt->host->unchecked_isa_dma)) {
buff = (char *) scsi_malloc(this_count << 9);
if(buff == NULL) panic("Ran out of DMA buffers.");
if (SCpnt->request.cmd == WRITE)
@@ -783,10 +782,8 @@ static int sd_init_onedisk(int i)
if (the_result)
{
printk ("sd%d : READ CAPACITY failed.\n"
- "sd%d : status = %x, message = %02x, host = %02x, driver = %02x \n",
+ "sd%d : status = %x, message = %02x, host = %d, driver = %02x \n",
i,i,
- rscsi_disks[i].device->host_no, rscsi_disks[i].device->id,
- rscsi_disks[i].device->lun,
status_byte(the_result),
msg_byte(the_result),
host_byte(the_result),
@@ -886,10 +883,11 @@ unsigned long sd_init(unsigned long memory_start, unsigned long memory_end)
blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
/* If our host adapter is capable of scatter-gather, then we increase
- the read-ahead to 8 blocks (16 sectors). If not, we use
+ the read-ahead to 16 blocks (32 sectors). If not, we use
a two block (4 sector) read ahead. */
- if(scsi_hosts[rscsi_disks[0].device->host_no].sg_tablesize)
- read_ahead[MAJOR_NR] = 16; /* 16 sector read-ahead */
+ if(rscsi_disks[0].device->host->sg_tablesize)
+ read_ahead[MAJOR_NR] = 32;
+ /* 64 sector read-ahead */
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
diff --git a/kernel/blk_drv/scsi/sd.h b/drivers/scsi/sd.h
index efa63e3..efa63e3 100644
--- a/kernel/blk_drv/scsi/sd.h
+++ b/drivers/scsi/sd.h
diff --git a/kernel/blk_drv/scsi/sd_ioctl.c b/drivers/scsi/sd_ioctl.c
index eefd1ff..f51ec66 100644
--- a/kernel/blk_drv/scsi/sd_ioctl.c
+++ b/drivers/scsi/sd_ioctl.c
@@ -6,7 +6,7 @@
#include <asm/segment.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "scsi_ioctl.h"
#include "hosts.h"
@@ -17,7 +17,8 @@ extern int revalidate_scsidisk(int, int);
int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg)
{
int dev = inode->i_rdev;
- int host, error;
+ int error;
+ struct Scsi_Host * host;
int diskinfo[4];
struct hd_geometry *loc = (struct hd_geometry *) arg;
@@ -27,12 +28,12 @@ int sd_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
error = verify_area(VERIFY_WRITE, loc, sizeof(*loc));
if (error)
return error;
- host = rscsi_disks[MINOR(dev) >> 4].device->host_no;
+ host = rscsi_disks[MINOR(dev) >> 4].device->host;
diskinfo[0] = 0;
diskinfo[1] = 0;
diskinfo[2] = 0;
- if(scsi_hosts[host].bios_param != NULL)
- scsi_hosts[host].bios_param(rscsi_disks[MINOR(dev) >> 4].capacity,
+ if(host->hostt->bios_param != NULL)
+ host->hostt->bios_param(rscsi_disks[MINOR(dev) >> 4].capacity,
dev,
&diskinfo[0]);
put_fs_byte(diskinfo[0],
diff --git a/kernel/blk_drv/scsi/seagate.c b/drivers/scsi/seagate.c
index 2ef2321..d5fb319 100644
--- a/kernel/blk_drv/scsi/seagate.c
+++ b/drivers/scsi/seagate.c
@@ -18,6 +18,17 @@
* Configuration :
* To use without BIOS -DOVERRIDE=base_address -DCONTROLLER=FD or SEAGATE
* -DIRQ will overide the default of 5.
+ * Note: You can now set these options from the kernel's "command line".
+ * The syntax is:
+ *
+ * st0x=ADDRESS,IRQ (for a Seagate controller)
+ * or:
+ * tmc8xx=ADDRESS,IRQ (for a TMC-8xx or TMC-950 controller)
+ * eg:
+ * tmc8xx=0xC8000,15
+ *
+ * will configure the driver for a TMC-8xx style controller using IRQ 15
+ * with a base address of 0xC8000.
*
* -DFAST or -DFAST32 will use blind transfers where possible
*
@@ -37,12 +48,13 @@
#include <linux/config.h>
-#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_88x)
+#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_8xx)
#include <asm/io.h>
#include <asm/system.h>
#include <linux/signal.h>
#include <linux/sched.h>
-#include "../blk.h"
+#include <linux/string.h>
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "seagate.h"
@@ -107,18 +119,26 @@ 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.
- */
-static unsigned char controller_type; /* set to SEAGATE for ST0x boards or FD for TMC-88x boards */
+static unsigned char controller_type = 0; /* set to SEAGATE for ST0x boards or FD for TMC-8xx boards */
+static unsigned char irq = IRQ;
#define retcode(result) (((result) << 16) | (message << 8) | status)
#define STATUS (*(volatile unsigned char *) st0x_cr_sr)
#define CONTROL STATUS
#define DATA (*(volatile unsigned char *) st0x_dr)
+void st0x_setup (char *str, int *ints) {
+ controller_type = SEAGATE;
+ base_address = (void *) ints[1];
+ irq = ints[2];
+}
+
+void tmc8xx_setup (char *str, int *ints) {
+ controller_type = FD;
+ base_address = (void *) ints[1];
+ irq = ints[2];
+}
+
#ifndef OVERRIDE
static const char * seagate_bases[] = {
@@ -135,44 +155,34 @@ typedef struct {
static const Signature signatures[] = {
#ifdef CONFIG_SCSI_SEAGATE
+{"ST01 v1.7 (C) Copyright 1987 Seagate", 15, 37, SEAGATE},
{"SCSI BIOS 2.00 (C) Copyright 1987 Seagate", 15, 40, SEAGATE},
/*
- The following two lines are NOT mistakes. One detects
- ROM revision 3.0.0, the other 3.2. Since seagate
- has only one type of SCSI adapter, and this is not
- going to change, the "SEAGATE" and "SCSI" together
- are probably "good enough"
-*/
+ * The following two lines are NOT mistakes. One detects ROM revision
+ * 3.0.0, the other 3.2. Since seagate has only one type of SCSI adapter,
+ * and this is not going to change, the "SEAGATE" and "SCSI" together
+ * are probably "good enough"
+ */
{"SEAGATE SCSI BIOS ",16, 17, SEAGATE},
{"SEAGATE SCSI BIOS ",17, 17, SEAGATE},
/*
- This is for the Future Domain 88x series. I've been told that
- the Seagate controllers are just repackages of these, and seeing
- early seagate BIOS bearing the Future Domain copyright,
- I believe it.
-*/
+ * However, future domain makes several incompatable SCSI boards, so specific
+ * signatures must be used.
+ */
-{"FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88",5,48, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89", 5, 46, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89", 5, 46, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90",5, 47, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90",5, 47, FD},
{"FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90", 5, 46, FD},
{"FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92", 5, 44, FD},
+{"FUTURE DOMAIN TMC-950", 5, 21, FD},
#endif /* CONFIG_SCSI_SEAGATE */
}
;
-/*
- 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 /* n OVERRIDE */
@@ -286,8 +296,11 @@ static struct sigaction seagate_sigaction = {
printk ("ERROR : seagate_st0x_detect() called twice.\n");
return 0;
}
-
- base_address = NULL;
+
+ /* If the user specified the controller type from the command line,
+ controller_type will be non-zero, so don't try and detect one */
+
+ if (!controller_type) {
#ifdef OVERRIDE
base_address = (void *) OVERRIDE;
@@ -321,6 +334,7 @@ static struct sigaction seagate_sigaction = {
controller_type = signatures[j].type;
}
#endif /* OVERIDE */
+ } /* (! controller_type) */
scsi_hosts[hostnum].this_id = (controller_type == SEAGATE) ? 7 : 6;
@@ -336,16 +350,16 @@ static struct sigaction seagate_sigaction = {
* loose our first interrupt.
*/
hostno = hostnum;
- if (irqaction(IRQ, &seagate_sigaction)) {
+ if (irqaction((int) irq, &seagate_sigaction)) {
printk("scsi%d : unable to allocate IRQ%d\n",
- hostno, IRQ);
+ hostno, (int) irq);
return 0;
}
#ifdef SLOW_HANDSHAKE
borken_init();
#endif
- return -1;
+ return 1;
}
else
{
@@ -377,7 +391,7 @@ const char *seagate_st0x_info(void) {
" LINKED"
#endif
"\n", hostno, (controller_type == SEAGATE) ? "seagate" :
- "FD TMC-950", IRQ, base_address);
+ "FD TMC-8xx", irq, base_address);
return buffer;
}
@@ -566,10 +580,10 @@ int seagate_st0x_command (Scsi_Cmnd * SCpnt) {
static int internal_command(unsigned char target, unsigned char lun, const void *cmnd,
void *buff, int bufflen, int reselect) {
- int len;
- unsigned char *data;
- struct scatterlist *buffer;
- int nobuffs;
+ int len = 0;
+ unsigned char *data = NULL;
+ struct scatterlist *buffer = NULL;
+ int nobuffs = 0;
int clock;
int temp;
#ifdef SLOW_HANDSHAKE
@@ -1661,8 +1675,8 @@ int seagate_st0x_biosparam(int size, int dev, int* ip) {
printk("scsi%d : heads = %d cylinders = %d sectors = %d total = %d formatted = %d\n",
hostno, heads, cylinders, sectors, total_sectors, formatted_sectors);
- if (!heads || !sectors)
- cylinders = 1025;
+ if (!heads || !sectors || !cylinders)
+ result = -1;
else
cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors));
diff --git a/kernel/blk_drv/scsi/seagate.h b/drivers/scsi/seagate.h
index 0be87ab..0be87ab 100644
--- a/kernel/blk_drv/scsi/seagate.h
+++ b/drivers/scsi/seagate.h
diff --git a/drivers/scsi/sg.c b/drivers/scsi/sg.c
new file mode 100644
index 0000000..7509699
--- /dev/null
+++ b/drivers/scsi/sg.c
@@ -0,0 +1,337 @@
+/*
+ History:
+ Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user
+ process control of SCSI devices.
+ Development Sponsored by Killy Corp. NY NY
+
+ Borrows code from st driver.
+*/
+
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/string.h>
+#include <linux/errno.h>
+#include <linux/mtio.h>
+#include <linux/ioctl.h>
+#include <linux/fcntl.h>
+#include <asm/io.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+
+#include "../block/blk.h"
+#include "scsi.h"
+#include "scsi_ioctl.h"
+#include "sg.h"
+
+#define MAJOR_NR 21
+
+int NR_SG=0;
+int MAX_SG=0;
+
+#ifdef SG_BIG_BUFF
+static char *big_buff;
+static struct wait_queue *big_wait; /* wait for buffer available */
+static int big_inuse=0;
+#endif
+
+struct scsi_generic
+ {
+ Scsi_Device *device;
+ int users; /* how many people have it open? */
+ struct wait_queue *generic_wait; /* wait for device to be available */
+ struct wait_queue *read_wait; /* wait for response */
+ struct wait_queue *write_wait; /* wait for free buffer */
+ int timeout; /* current default value for device */
+ int buff_len; /* length of current buffer */
+ char *buff; /* the buffer */
+ struct sg_header header; /* header of pending command */
+ char exclude; /* opened for exclusive access */
+ char pending; /* don't accept writes now */
+ char complete; /* command complete allow a read */
+ };
+
+static struct scsi_generic *scsi_generics=NULL;
+
+static int sg_ioctl(struct inode * inode,struct file * file,
+ unsigned int cmd_in, unsigned long arg)
+ {
+ int dev = MINOR(inode->i_rdev);
+ if ((dev<0) || (dev>=NR_SG))
+ return -ENODEV;
+ switch(cmd_in)
+ {
+ case SG_SET_TIMEOUT:
+ scsi_generics[dev].timeout=get_fs_long((int *) arg);
+ return 0;
+ case SG_GET_TIMEOUT:
+ return scsi_generics[dev].timeout;
+ default:
+ return scsi_ioctl(scsi_generics[dev].device, cmd_in, (void *) arg);
+ }
+ }
+
+static int sg_open(struct inode * inode, struct file * filp)
+ {
+ int dev=MINOR(inode->i_rdev);
+ int flags=filp->f_flags;
+ if (dev>=NR_SG)
+ return -ENODEV;
+ if (O_RDWR!=(flags & O_ACCMODE))
+ return -EACCES;
+ if (flags & O_EXCL)
+ {
+ while(scsi_generics[dev].users)
+ {
+ if (flags & O_NONBLOCK)
+ return -EBUSY;
+ interruptible_sleep_on(&scsi_generics[dev].generic_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ scsi_generics[dev].exclude=1;
+ }
+ else
+ while(scsi_generics[dev].exclude)
+ {
+ if (flags & O_NONBLOCK)
+ return -EBUSY;
+ interruptible_sleep_on(&scsi_generics[dev].generic_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ if (!scsi_generics[dev].users && scsi_generics[dev].pending && scsi_generics[dev].complete)
+ {
+ scsi_free(scsi_generics[dev].buff,scsi_generics[dev].buff_len);
+ scsi_generics[dev].pending=0;
+ }
+ if (!scsi_generics[dev].users)
+ scsi_generics[dev].timeout=SG_DEFAULT_TIMEOUT;
+ scsi_generics[dev].users++;
+ return 0;
+ }
+
+static void sg_close(struct inode * inode, struct file * filp)
+ {
+ int dev=MINOR(inode->i_rdev);
+ scsi_generics[dev].users--;
+ scsi_generics[dev].exclude=0;
+ wake_up(&scsi_generics[dev].generic_wait);
+ }
+
+static char *sg_malloc(int size)
+ {
+ if (size<=4096)
+ return (char *) scsi_malloc(size);
+#ifdef SG_BIG_BUFF
+ if (size<SG_BIG_BUFF)
+ {
+ while(big_inuse)
+ {
+ interruptible_sleep_on(&big_wait);
+ if (current->signal & ~current->blocked)
+ return NULL;
+ }
+ big_inuse=1;
+ return big_buff;
+ }
+#endif
+ return NULL;
+ }
+
+static void sg_free(char *buff,int size)
+ {
+#ifdef SG_BIG_BUFF
+ if (buff==big_buff)
+ {
+ big_inuse=0;
+ wake_up(&big_wait);
+ return;
+ }
+#endif
+ scsi_free(buff,size);
+ }
+
+static int sg_read(struct inode *inode,struct file *filp,char *buf,int count)
+ {
+ int dev=MINOR(inode->i_rdev);
+ int i;
+ struct scsi_generic *device=&scsi_generics[dev];
+ if ((i=verify_area(VERIFY_WRITE,buf,count)))
+ return i;
+ while(!device->pending || !device->complete)
+ {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+ interruptible_sleep_on(&device->read_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ device->header.pack_len=device->header.reply_len;
+ device->header.result=0;
+ if (count>=sizeof(struct sg_header))
+ {
+ memcpy_tofs(buf,&device->header,sizeof(struct sg_header));
+ buf+=sizeof(struct sg_header);
+ if (count>device->header.pack_len)
+ count=device->header.pack_len;
+ memcpy_tofs(buf,device->buff,count-sizeof(struct sg_header));
+ }
+ else
+ count=0;
+ sg_free(device->buff,device->buff_len);
+ device->pending=0;
+ wake_up(&device->write_wait);
+ return count;
+ }
+
+static void sg_command_done(Scsi_Cmnd * SCpnt)
+ {
+ int dev=SCpnt->request.dev;
+ struct scsi_generic *device=&scsi_generics[dev];
+ if (!device->pending)
+ {
+ printk("unexpected done for sg %d\n",dev);
+ SCpnt->request.dev=-1;
+ return;
+ }
+ if (SCpnt->sense_buffer[0])
+ {
+ device->header.result=EIO;
+ }
+ else
+ device->header.result=SCpnt->result;
+ device->complete=1;
+ SCpnt->request.dev=-1;
+ wake_up(&scsi_generics[dev].read_wait);
+ }
+
+static int sg_write(struct inode *inode,struct file *filp,char *buf,int count)
+ {
+ int dev=MINOR(inode->i_rdev);
+ Scsi_Cmnd *SCpnt;
+ int bsize,size,amt,i;
+ unsigned char cmnd[MAX_COMMAND_SIZE];
+ struct scsi_generic *device=&scsi_generics[dev];
+ if ((i=verify_area(VERIFY_READ,buf,count)))
+ return i;
+ if (count<sizeof(struct sg_header))
+ return -EIO;
+ /* make sure we can fit */
+ while(device->pending)
+ {
+ if (filp->f_flags & O_NONBLOCK)
+ return -EWOULDBLOCK;
+#ifdef DEBUG
+ printk("sg_write: sleeping on pending request\n");
+#endif
+ interruptible_sleep_on(&device->write_wait);
+ if (current->signal & ~current->blocked)
+ return -ERESTARTSYS;
+ }
+ device->pending=1;
+ device->complete=0;
+ memcpy_fromfs(&device->header,buf,sizeof(struct sg_header));
+ /* fix input size */
+ device->header.pack_len=count;
+ buf+=sizeof(struct sg_header);
+ bsize=(device->header.pack_len>device->header.reply_len) ? device->header.pack_len : device->header.reply_len;
+ bsize-=sizeof(struct sg_header);
+ amt=bsize;
+ if (!bsize)
+ bsize++;
+ bsize=(bsize+511) & ~511;
+ if ((bsize<0) || !(device->buff=sg_malloc(device->buff_len=bsize)))
+ {
+ device->pending=0;
+ wake_up(&device->write_wait);
+ return -ENOMEM;
+ }
+#ifdef DEBUG
+ printk("allocating device\n");
+#endif
+ if (!(SCpnt=allocate_device(NULL,device->device->index, !(filp->f_flags & O_NONBLOCK))))
+ {
+ device->pending=0;
+ wake_up(&device->write_wait);
+ sg_free(device->buff,device->buff_len);
+ return -EWOULDBLOCK;
+ }
+#ifdef DEBUG
+ printk("device allocated\n");
+#endif
+ /* now issue command */
+ SCpnt->request.dev=dev;
+ SCpnt->sense_buffer[0]=0;
+ size=COMMAND_SIZE(get_fs_byte(buf));
+ memcpy_fromfs(cmnd,buf,size);
+ buf+=size;
+ memcpy_fromfs(device->buff,buf,device->header.pack_len-size-sizeof(struct sg_header));
+ cmnd[1]=(cmnd[1] & 0x1f) | (device->device->lun<<5);
+#ifdef DEBUG
+ printk("do cmd\n");
+#endif
+ scsi_do_cmd (SCpnt,(void *) cmnd,
+ (void *) device->buff,amt,sg_command_done,device->timeout,SG_DEFAULT_RETRIES);
+#ifdef DEBUG
+ printk("done cmd\n");
+#endif
+ return count;
+ }
+
+static struct file_operations sg_fops = {
+ NULL, /* lseek */
+ sg_read, /* read */
+ sg_write, /* write */
+ NULL, /* readdir */
+ NULL, /* select */
+ sg_ioctl, /* ioctl */
+ NULL, /* mmap */
+ sg_open, /* open */
+ sg_close, /* release */
+ NULL /* fsync */
+};
+
+
+/* Driver initialization */
+unsigned long sg_init(unsigned long mem_start, unsigned long mem_end)
+ {
+ if (register_chrdev(MAJOR_NR,"sg",&sg_fops))
+ {
+ printk("Unable to get major %d for Generic SCSI device\n",MAJOR_NR);
+ return mem_start;
+ }
+ if (NR_SG == 0) return mem_start;
+
+#ifdef DEBUG
+ printk("sg: Init generic device.\n");
+#endif
+
+#ifdef SG_BIG_BUFF
+ big_buff= (char *) mem_start;
+ mem_start+=SG_BIG_BUFF;
+#endif
+ return mem_start;
+ }
+
+unsigned long sg_init1(unsigned long mem_start, unsigned long mem_end)
+ {
+ scsi_generics = (struct scsi_generic *) mem_start;
+ mem_start += MAX_SG * sizeof(struct scsi_generic);
+ return mem_start;
+ };
+
+void sg_attach(Scsi_Device * SDp)
+ {
+ if(NR_SG >= MAX_SG)
+ panic ("scsi_devices corrupt (sg)");
+ scsi_generics[NR_SG].device=SDp;
+ scsi_generics[NR_SG].users=0;
+ scsi_generics[NR_SG].generic_wait=NULL;
+ scsi_generics[NR_SG].read_wait=NULL;
+ scsi_generics[NR_SG].write_wait=NULL;
+ scsi_generics[NR_SG].exclude=0;
+ scsi_generics[NR_SG].pending=0;
+ scsi_generics[NR_SG].timeout=SG_DEFAULT_TIMEOUT;
+ NR_SG++;
+ };
diff --git a/drivers/scsi/sg.h b/drivers/scsi/sg.h
new file mode 100644
index 0000000..a28c8db
--- /dev/null
+++ b/drivers/scsi/sg.h
@@ -0,0 +1,33 @@
+/*
+ History:
+ Started: Aug 9 by Lawrence Foard (entropy@world.std.com), to allow user
+ process control of SCSI devices.
+ Development Sponsored by Killy Corp. NY NY
+*/
+
+/*
+ An SG device is accessed by writting "packets" to it, the replies
+ are then read using the read call. The same header is used for
+ reply, just ignore reply_len field.
+*/
+
+struct sg_header
+ {
+ int pack_len; /* length of incoming packet <4096 (including header) */
+ int reply_len; /* maximum length <4096 of expected reply */
+ int pack_id; /* id number of packet */
+ int result; /* 0==ok, otherwise refer to errno codes */
+ /* command follows then data for command */
+ };
+
+/* ioctl's */
+#define SG_SET_TIMEOUT 0x2201 /* set timeout *(int *)arg==timeout */
+#define SG_GET_TIMEOUT 0x2202 /* get timeout return timeout */
+
+#define SG_DEFAULT_TIMEOUT 6000 /* 1 minute timeout */
+#define SG_DEFAULT_RETRIES 1
+
+#define SG_MAX_QUEUE 4 /* maximum outstanding request, arbitrary, may be
+ changed if sufficient DMA buffer room available */
+
+#define SG_BIG_BUFF 32768
diff --git a/kernel/blk_drv/scsi/sr.c b/drivers/scsi/sr.c
index 32da76e..b86e30d 100644
--- a/kernel/blk_drv/scsi/sr.c
+++ b/drivers/scsi/sr.c
@@ -22,7 +22,7 @@
#define MAJOR_NR 11
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
#include "sr.h"
@@ -243,7 +243,7 @@ static void rw_intr (Scsi_Cmnd * SCpnt)
/* We only get this far if we have an error we have not recognized */
if(result) {
printk("SCSI CD error : host %d id %d lun %d return code = %03x\n",
- scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->host_no,
+ scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->host->host_no,
scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->id,
scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->lun,
result);
@@ -304,7 +304,6 @@ static void do_sr_request (void)
else SCpnt = NULL;
sti();
-
/* This is a performance enhancement. We dig down into the request list and
try and find a queueable request (i.e. device not busy, and host able to
accept another command. If we find one, then we queue it. This can
@@ -324,7 +323,7 @@ static void do_sr_request (void)
req1 = req;
req = req->next;
};
- if (SCpnt) {
+ if (SCpnt && req->dev == -1) {
if (req == CURRENT)
CURRENT = CURRENT->next;
else
@@ -399,8 +398,7 @@ void requeue_sr_request (Scsi_Cmnd * SCpnt)
cmd[0] = READ_6;
break;
default :
- printk ("Unknown sr command %d\n", SCpnt->request.cmd);
- panic("");
+ panic ("Unknown sr command %d\n", SCpnt->request.cmd);
}
cmd[1] = (SCpnt->lun << 5) & 0xe0;
@@ -423,7 +421,7 @@ are any multiple of 512 bytes long. */
SCpnt->use_sg = 0;
- if (scsi_hosts[SCpnt->host].sg_tablesize > 0 &&
+ if (SCpnt->host->sg_tablesize > 0 &&
(!need_isa_buffer ||
dma_free_sectors >= 10)) {
struct buffer_head * bh;
@@ -437,7 +435,7 @@ are any multiple of 512 bytes long. */
a padding record at the start */
this_count = SCpnt->request.sector % 4;
if(this_count) count++;
- while(bh && count < scsi_hosts[SCpnt->host].sg_tablesize) {
+ while(bh && count < SCpnt->host->sg_tablesize) {
if ((this_count + (bh->b_size >> 9)) > this_count_max) break;
this_count += (bh->b_size >> 9);
count++;
@@ -446,7 +444,7 @@ are any multiple of 512 bytes long. */
/* Fix up in case of an odd record at the end */
end_rec = 0;
if(this_count % 4) {
- if (count < scsi_hosts[SCpnt->host].sg_tablesize) {
+ if (count < SCpnt->host->sg_tablesize) {
count++;
end_rec = (4 - (this_count % 4)) << 9;
this_count += 4 - (this_count % 4);
@@ -491,7 +489,7 @@ are any multiple of 512 bytes long. */
break;
};
if (((int) sgpnt[count].address) + sgpnt[count].length >
- ISA_DMA_THRESHOLD & (scsi_hosts[SCpnt->host].unchecked_isa_dma)) {
+ ISA_DMA_THRESHOLD & (SCpnt->host->unchecked_isa_dma)) {
sgpnt[count].alt_address = sgpnt[count].address;
/* We try and avoid exhausting the DMA pool, since it is easier
to control usage here. In other places we might have a more
@@ -555,7 +553,7 @@ are any multiple of 512 bytes long. */
this_count -= this_count % 4;
buffer = (unsigned char *) SCpnt->request.buffer;
if (((int) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD &
- (scsi_hosts[SCpnt->host].unchecked_isa_dma))
+ (SCpnt->host->unchecked_isa_dma))
buffer = (unsigned char *) scsi_malloc(this_count << 9);
}
};
@@ -602,7 +600,14 @@ are any multiple of 512 bytes long. */
}
#ifdef DEBUG
+{
+ int i;
printk("ReadCD: %d %d %d %d\n",block, realcount, buffer, this_count);
+ printk("Use sg: %d\n", SCpnt->use_sg);
+ printk("Dumping command: ");
+ for(i=0; i<12; i++) printk("%2.2x ", cmd[i]);
+ printk("\n");
+};
#endif
SCpnt->this_count = this_count;
@@ -731,10 +736,10 @@ unsigned long sr_init(unsigned long memory_start, unsigned long memory_end)
blk_size[MAJOR_NR] = sr_sizes;
/* If our host adapter is capable of scatter-gather, then we increase
- the read-ahead to 8 blocks (16 sectors). If not, we use
+ the read-ahead to 16 blocks (32 sectors). If not, we use
a two block (4 sector) read ahead. */
- if(scsi_hosts[scsi_CDs[0].device->host_no].sg_tablesize)
- read_ahead[MAJOR_NR] = 16; /* 16 sector read-ahead */
+ if(scsi_CDs[0].device->host->sg_tablesize)
+ read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */
else
read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */
diff --git a/kernel/blk_drv/scsi/sr.h b/drivers/scsi/sr.h
index c023567..c023567 100644
--- a/kernel/blk_drv/scsi/sr.h
+++ b/drivers/scsi/sr.h
diff --git a/kernel/blk_drv/scsi/sr_ioctl.c b/drivers/scsi/sr_ioctl.c
index 2f198b4..4423188 100644
--- a/kernel/blk_drv/scsi/sr_ioctl.c
+++ b/drivers/scsi/sr_ioctl.c
@@ -4,8 +4,9 @@
#include <asm/segment.h>
#include <linux/errno.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
+#include "hosts.h"
#include "sr.h"
#include "scsi_ioctl.h"
@@ -71,7 +72,7 @@ static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned
break;
default:
printk("SCSI CD error: host %d id %d lun %d return code = %03x\n",
- scsi_CDs[target].device->host_no,
+ scsi_CDs[target].device->host->host_no,
scsi_CDs[target].device->id,
scsi_CDs[target].device->lun,
result);
@@ -171,7 +172,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
case CDROMREADTOCHDR:
{
struct cdrom_tochdr tochdr;
- char buffer[12];
+ char * buffer;
sr_cmd[0] = SCMD_READ_TOC;
sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
@@ -181,11 +182,16 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
sr_cmd[8] = 12; /* LSB of length */
sr_cmd[9] = 0;
- result = do_ioctl(target, sr_cmd, buffer, sizeof (buffer));
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ result = do_ioctl(target, sr_cmd, buffer, 12);
tochdr.cdth_trk0 = buffer[2];
tochdr.cdth_trk1 = buffer[3];
+ scsi_free(buffer, 512);
+
verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tochdr));
memcpy_tofs ((void *) arg, &tochdr, sizeof (struct cdrom_tochdr));
@@ -195,7 +201,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
case CDROMREADTOCENTRY:
{
struct cdrom_tocentry tocentry;
- char buffer[12];
+ char * buffer;
verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry));
memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry));
@@ -208,7 +214,10 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
sr_cmd[8] = 12; /* LSB of length */
sr_cmd[9] = 0;
- result = do_ioctl (target, sr_cmd, buffer, sizeof (buffer));
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ result = do_ioctl (target, sr_cmd, buffer, 12);
if (tocentry.cdte_format == CDROM_MSF) {
tocentry.cdte_addr.msf.minute = buffer[9];
@@ -219,6 +228,8 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
else
tocentry.cdte_addr.lba = (int) buffer[0];
+ scsi_free(buffer, 512);
+
verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_tocentry));
memcpy_tofs ((void *) arg, &tocentry, sizeof (struct cdrom_tocentry));
@@ -259,7 +270,7 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
case CDROMVOLCTRL:
{
- char buffer[28], mask[28];
+ char * buffer, * mask;
struct cdrom_volctrl volctrl;
verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl));
@@ -274,8 +285,12 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
sr_cmd[4] = 28;
sr_cmd[5] = 0;
- if ((result = do_ioctl (target, sr_cmd, buffer, sizeof (buffer)))) {
+ buffer = (unsigned char *) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ if ((result = do_ioctl (target, sr_cmd, buffer, 28))) {
printk ("Hosed while obtaining audio mode page\n");
+ scsi_free(buffer, 512);
return result;
}
@@ -286,8 +301,16 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
sr_cmd[4] = 28;
sr_cmd[5] = 0;
- if ((result = do_ioctl (target, sr_cmd, mask, sizeof (mask)))) {
+ mask = (unsigned char *) scsi_malloc(512);
+ if(!mask) {
+ scsi_free(buffer, 512);
+ return -ENOMEM;
+ };
+
+ if ((result = do_ioctl (target, sr_cmd, mask, 28))) {
printk ("Hosed while obtaining mask for audio mode page\n");
+ scsi_free(buffer, 512);
+ scsi_free(mask, 512);
return result;
}
@@ -304,14 +327,16 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
sr_cmd[4] = 28;
sr_cmd[5] = 0;
- result = do_ioctl (target, sr_cmd, buffer, sizeof (buffer));
+ result = do_ioctl (target, sr_cmd, buffer, 28);
+ scsi_free(buffer, 512);
+ scsi_free(mask, 512);
return result;
}
case CDROMSUBCHNL:
{
struct cdrom_subchnl subchnl;
- char buffer[16];
+ char * buffer;
sr_cmd[0] = SCMD_READ_SUBCHANNEL;
sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */
@@ -323,7 +348,10 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
sr_cmd[8] = 16;
sr_cmd[9] = 0;
- result = do_ioctl(target, sr_cmd, buffer, sizeof (buffer));
+ buffer = (unsigned char*) scsi_malloc(512);
+ if(!buffer) return -ENOMEM;
+
+ result = do_ioctl(target, sr_cmd, buffer, 16);
subchnl.cdsc_audiostatus = buffer[1];
subchnl.cdsc_format = CDROM_MSF;
@@ -338,6 +366,8 @@ int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigne
subchnl.cdsc_absaddr.msf.second = buffer[10];
subchnl.cdsc_absaddr.msf.frame = buffer[11];
+ scsi_free(buffer, 512);
+
verify_area (VERIFY_WRITE, (void *) arg, sizeof (struct cdrom_subchnl));
memcpy_tofs ((void *) arg, &subchnl, sizeof (struct cdrom_subchnl));
return result;
diff --git a/kernel/blk_drv/scsi/st.c b/drivers/scsi/st.c
index 0249be5..06e8148 100644
--- a/kernel/blk_drv/scsi/st.c
+++ b/drivers/scsi/st.c
@@ -48,7 +48,7 @@
#include <asm/system.h>
#define MAJOR_NR 9
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "scsi_ioctl.h"
#include "st.h"
diff --git a/kernel/blk_drv/scsi/st.h b/drivers/scsi/st.h
index 0c50024..0c50024 100644
--- a/kernel/blk_drv/scsi/st.h
+++ b/drivers/scsi/st.h
diff --git a/drivers/scsi/t128.c b/drivers/scsi/t128.c
new file mode 100644
index 0000000..5531405
--- /dev/null
+++ b/drivers/scsi/t128.c
@@ -0,0 +1,391 @@
+#define AUTOSENSE
+#define PSEUDO_DMA
+
+/*
+ * Trantor T128/T128F/T228 driver
+ * Note : architecturally, the T100 and T130 are different and won't
+ * work
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 3.
+ *
+ * For more information, please consult
+ *
+ * Trantor Systems, Ltd.
+ * T128/T128F/T228 SCSI Host Adapter
+ * Hardware Specifications
+ *
+ * Trantor Systems, Ltd.
+ * 5415 Randall Place
+ * Fremont, CA 94538
+ * 1+ (415) 770-1400, FAX 1+ (415) 770-9910
+ *
+ * and
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * Options :
+ * AUTOSENSE - if defined, REQUEST SENSE will be performed automatically
+ * for commands that return with a CHECK CONDITION status.
+ *
+ * PSEUDO_DMA - enables PSEUDO-DMA hardware, should give a 3-4X performance
+ * increase compared to polled I/O.
+ *
+ * PARITY - enable parity checking. Not supported.
+ *
+ * SCSI2 - enable support for SCSI-II tagged queueing. Untested.
+ *
+ *
+ * UNSAFE - leave interrupts enabled during pseudo-DMA transfers. You
+ * only really want to use this if you're having a problem with
+ * dropped characters during high speed communications, and even
+ * then, you're going to be better off twiddling with transfersize.
+ *
+ * USLEEP - enable support for devices that don't disconnect. Untested.
+ *
+ * The card is detected and initialized in one of several ways :
+ * 1. Autoprobe (default) - since the board is memory mapped,
+ * a BIOS signature is scanned for to locate the registers.
+ * An interrupt is triggered to autoprobe for the interrupt
+ * line.
+ *
+ * 2. With command line overrides - t128=address,irq may be
+ * used on the LILO command line to override the defaults.
+ *
+ * 3. With the T128_OVERRIDE compile time define. This is
+ * specified as an array of address, irq tupples. Ie, for
+ * one board at the default 0xcc000 address, IRQ5, I could say
+ * -DT128_OVERRIDE={{0xcc000, 5}}
+ *
+ * Note that if the override methods are used, place holders must
+ * be specified for other boards in the system.
+ *
+ * T128/T128F jumper/dipswitch settings (note : on my sample, the switches
+ * were epoxy'd shut, meaning I couldn't change the 0xcc000 base address) :
+ *
+ * T128 Sw7 Sw8 Sw6 = 0ws Sw5 = boot
+ * T128F Sw6 Sw7 Sw5 = 0ws Sw4 = boot Sw8 = floppy disable
+ * cc000 off off
+ * c8000 off on
+ * dc000 on off
+ * d8000 on on
+ *
+ *
+ * Interrupts
+ * There is a 12 pin jumper block, jp1, numbered as follows :
+ * T128 (JP1) T128F (J5)
+ * 2 4 6 8 10 12 11 9 7 5 3 1
+ * 1 3 5 7 9 11 12 10 8 6 4 2
+ *
+ * 3 2-4
+ * 5 1-3
+ * 7 3-5
+ * T128F only
+ * 10 8-10
+ * 12 7-9
+ * 14 10-12
+ * 15 9-11
+ */
+
+/*
+ * $Log: t128.c,v $
+ */
+
+#include <asm/system.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "t128.h"
+#define AUTOPROBE_IRQ
+#include "NCR5380.h"
+#include "constants.h"
+
+
+
+
+static struct override {
+ unsigned char *address;
+ int irq;
+} overrides
+#ifdef T128_OVERRIDE
+ [] = T128_OVERRIDE;
+#else
+ [4] = {{NULL,IRQ_AUTO}, {NULL,IRQ_AUTO}, {NULL,IRQ_AUTO},
+ {NULL,IRQ_AUTO}};
+#endif
+
+#define NO_OVERRIDES (sizeof(overrides) / sizeof(struct override))
+
+static struct base {
+ unsigned char *address;
+ int noauto;
+} bases[] = {{(unsigned char *) 0xcc000, 0}, {(unsigned char *) 0xc8000, 0},
+ {(unsigned char *) 0xdc000, 0}, {(unsigned char *) 0xd8000, 0}};
+
+#define NO_BASES (sizeof (bases) / sizeof (struct base))
+
+static const struct signature {
+ const char *string;
+ int offset;
+} signatures[] = {
+{"TSROM: SCSI BIOS, Version 1.12", 0x36},
+};
+
+#define NO_SIGNATURES (sizeof (signatures) / sizeof (struct signature))
+
+/*
+ * Function : t128_setup(char *str, int *ints)
+ *
+ * Purpose : LILO command line initialization of the overrides array,
+ *
+ * Inputs : str - unused, ints - array of integer paramters with ints[0]
+ * equal to the number of ints.
+ *
+ */
+
+void t128_setup(char *str, int *ints) {
+ static int commandline_current = 0;
+ int i;
+ if (ints[0] != 2)
+ printk("t128_setup : usage t128=address,irq\n");
+ else
+ if (commandline_current < NO_OVERRIDES) {
+ overrides[commandline_current].address = (unsigned char *) ints[1];
+ overrides[commandline_current].irq = ints[2];
+ for (i = 0; i < NO_BASES; ++i)
+ if (bases[i].address == (unsigned char *) ints[1]) {
+ bases[i].noauto = 1;
+ break;
+ }
+ ++commandline_current;
+ }
+}
+
+static struct sigaction t128_sigaction = { t128_intr, 0, SA_INTERRUPT , NULL };
+
+/*
+ * Function : int t128_detect(int hostno)
+ *
+ * Purpose : detects and initializes T128,T128F, or T228 controllers
+ * that were autoprobed, overriden on the LILO command line,
+ * or specified at compile time.
+ *
+ * Inputs : hostno - id of this SCSI adapter.
+ *
+ * Returns : 1 if a host adapter was found, 0 if not.
+ *
+ */
+
+int t128_detect(int hostno) {
+ static int current_override = 0, current_base = 0;
+ struct Scsi_Host *instance;
+ unsigned char *base;
+ int sig, count;
+
+ for (count = 0; current_override < NO_OVERRIDES; ++current_override) {
+ base = NULL;
+
+ if (overrides[current_override].address)
+ base = overrides[current_override].address;
+ else
+ for (; !base && (current_base < NO_BASES); ++current_base) {
+#if (TDEBUG & TDEBUG_INIT)
+ printk("scsi%d : probing address %08x\n", hostno, (unsigned int) bases[current_base].address);
+#endif
+ for (sig = 0; sig < NO_SIGNATURES; ++sig)
+ if (!bases[current_base].noauto && !memcmp
+ (bases[current_base].address + signatures[sig].offset,
+ signatures[sig].string, strlen(signatures[sig].string))) {
+ base = bases[current_base].address;
+#if (TDEBUG & TDEBUG_INIT)
+ printk("scsi%d : detected board.\n", hostno);
+#endif
+ break;
+ }
+ }
+
+#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
+ printk("scsi%d : base = %08x\n", hostno, (unsigned int) base);
+#endif
+
+ if (!base)
+ break;
+
+ instance = scsi_register (hostno, sizeof(struct NCR5380_hostdata));
+ instance->base = base;
+
+ NCR5380_init(instance);
+
+ if (overrides[current_override].irq != IRQ_AUTO)
+ instance->irq = overrides[current_override].irq;
+ else
+ instance->irq = NCR5380_probe_irq(instance, T128_IRQS);
+
+ if (instance->irq != IRQ_NONE)
+ if (irqaction (instance->irq, &t128_sigaction)) {
+ printk("scsi%d : IRQ%d not free, interrupts disabled\n",
+ hostno, instance->irq);
+ instance->irq = IRQ_NONE;
+ }
+
+ if (instance->irq == IRQ_NONE) {
+ printk("scsi%d : interrupts not enabled. for better interactive performance,\n", hostno);
+ printk("scsi%d : please jumper the board for a free IRQ.\n", hostno);
+ }
+
+#if defined(TDEBUG) && (TDEBUG & TDEBUG_INIT)
+ printk("scsi%d : irq = %d\n", hostno, instance->irq);
+#endif
+
+ printk("scsi%d : at 0x%08x", instance->host_no, (int)
+ instance->base);
+ if (instance->irq == IRQ_NONE)
+ printk (" interrupts disabled");
+ else
+ printk (" irq %d", instance->irq);
+ printk(" options CAN_QUEUE=%d CMD_PER_LUN=%d release=%d",
+ CAN_QUEUE, CMD_PER_LUN, T128_PUBLIC_RELEASE);
+ NCR5380_print_options(instance);
+ printk("\n");
+
+ ++current_override;
+ ++count;
+ ++hostno;
+ }
+ return count;
+}
+
+/*
+ * Function : int t128_biosparam(int size, int dev, int *ip)
+ *
+ * Purpose : Generates a BIOS / DOS compatable H-C-S mapping for
+ * the specified device / size.
+ *
+ * Inputs : size = size of device in sectors (512 bytes), dev = block device
+ * major / minor, ip[] = {heads, sectors, cylinders}
+ *
+ * Returns : allways 0 (success), initializes ip
+ *
+ */
+
+/*
+ * XXX Most SCSI boards use this mapping, I could be incorrect. Some one
+ * using hard disks on a trantor should verify that this mapping corresponds
+ * to that used by the BIOS / ASPI driver by running the linux fdisk program
+ * and matching the H_C_S coordinates to what DOS uses.
+ */
+
+int t128_biosparam(int size, int dev, int * ip)
+{
+ ip[0] = 64;
+ ip[1] = 32;
+ ip[2] = size >> 11;
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_pread (struct Scsi_Host *instance,
+ * unsigned char *dst, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma read function, transfers len bytes to
+ * dst
+ *
+ * Inputs : dst = destination, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog
+ * timeout.
+ */
+
+static inline int NCR5380_pread (struct Scsi_Host *instance, unsigned char *dst,
+ int len) {
+ register unsigned char *reg = (unsigned char *) (instance->base +
+ T_DATA_REG_OFFSET), *d = dst;
+ register i = len;
+
+ while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
+
+ for (; i; --i)
+ *d++ = *reg;
+
+ if (*(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
+ unsigned char tmp;
+ volatile unsigned char *foo;
+ foo = instance->base + T_CONTROL_REG_OFFSET;
+ tmp = *foo;
+ *foo = tmp | T_CR_CT;
+ *foo = tmp;
+ printk("scsi%d : watchdog timer fired in NCR5480_pread()\n",
+ instance->host_no);
+ return -1;
+ } else
+ return 0;
+}
+
+/*
+ * Function : int NCR5380_pwrite (struct Scsi_Host *instance,
+ * unsigned char *src, int len)
+ *
+ * Purpose : Fast 5380 pseudo-dma write function, transfers len bytes from
+ * src
+ *
+ * Inputs : src = source, len = length in bytes
+ *
+ * Returns : 0 on success, non zero on a failure such as a watchdog
+ * timeout.
+ */
+
+static inline int NCR5380_pwrite (struct Scsi_Host *instance, unsigned char *src,
+ int len) {
+ register unsigned char *reg = (unsigned char *) (instance->base +
+ T_DATA_REG_OFFSET), *s = src;
+ register i = len;
+
+ while (!(instance->base[T_STATUS_REG_OFFSET]) & T_ST_RDY);
+ for (; i; --i)
+ *reg = *s++;
+
+ if (*(instance->base + T_STATUS_REG_OFFSET) & T_ST_TIM) {
+ unsigned char tmp;
+ volatile unsigned char *foo;
+ foo = instance->base + T_CONTROL_REG_OFFSET;
+ tmp = *foo;
+ *foo = tmp | T_CR_CT;
+ *foo = tmp;
+ printk("scsi%d : watchdog timer fired in NCR5480_pwrite()\n",
+ instance->host_no);
+ return -1;
+ } else
+ return 0;
+}
+
+/*
+ * Function : const char *t128_info(void)
+ *
+ * Purpose : provide furthur information about this driver.
+ *
+ * Returns : an empty string.
+ */
+
+const char *t128_info (void) {
+ static const char string[]="";
+ return string;
+}
+
+#include "NCR5380.c"
diff --git a/drivers/scsi/t128.h b/drivers/scsi/t128.h
new file mode 100644
index 0000000..39e1ba2
--- /dev/null
+++ b/drivers/scsi/t128.h
@@ -0,0 +1,167 @@
+/*
+ * Trantor T128/T128F/T228 defines
+ * Note : architecturally, the T100 and T128 are different and won't work
+ *
+ * Copyright 1993, Drew Eckhardt
+ * Visionary Computing
+ * (Unix and Linux consulting and custom programming)
+ * drew@colorado.edu
+ * +1 (303) 440-4894
+ *
+ * DISTRIBUTION RELEASE 3.
+ *
+ * For more information, please consult
+ *
+ * Trantor Systems, Ltd.
+ * T128/T128F/T228 SCSI Host Adapter
+ * Hardware Specifications
+ *
+ * Trantor Systems, Ltd.
+ * 5415 Randall Place
+ * Fremont, CA 94538
+ * 1+ (415) 770-1400, FAX 1+ (415) 770-9910
+ *
+ * and
+ *
+ * NCR 5380 Family
+ * SCSI Protocol Controller
+ * Databook
+ *
+ * NCR Microelectronics
+ * 1635 Aeroplaza Drive
+ * Colorado Springs, CO 80916
+ * 1+ (719) 578-3400
+ * 1+ (800) 334-5454
+ */
+
+/*
+ * $Log: t128.h,v $
+ */
+
+#ifndef T128_H
+#define T128_H
+
+#define T128_PUBLIC_RELEASE 3
+
+#define TDEBUG_INIT 0x1
+#define TDEBUG_TRANSFER 0x2
+
+/*
+ * The trantor boards are memory mapped. They use an NCR5380 or
+ * equivalent (my sample board had part second sourced from ZILOG).
+ * NCR's recommended "Pseudo-DMA" architecture is used, where
+ * a PAL drives the DMA signals on the 5380 allowing fast, blind
+ * transfers with propper handshaking.
+ */
+
+/*
+ * Note : a boot switch is provided for the purpose of informing the
+ * firmware to boot or not boot from attached SCSI devices. So, I imagine
+ * there are fewer people who've yanked the ROM like they do on the Seagate
+ * to make bootup faster, and I'll probably use this for autodetection.
+ */
+#define T_ROM_OFFSET 0
+
+/*
+ * Note : my sample board *WAS NOT* populated with the SRAM, so this
+ * can't be used for autodetection without a ROM present.
+ */
+#define T_RAM_OFFSET 0x1800
+
+/*
+ * All of the registers are allocated 32 bytes of address space, except
+ * for the data register (read/write to/from the 5380 in pseudo-DMA mode)
+ */
+#define T_CONTROL_REG_OFFSET 0x1c00 /* rw */
+#define T_CR_INT 0x10 /* Enable interrupts */
+#define T_CR_CT 0x02 /* Reset watchdog timer */
+
+#define T_STATUS_REG_OFFSET 0x1c20 /* ro */
+#define T_ST_BOOT 0x80 /* Boot switch */
+#define T_ST_S3 0x40 /* User setable switches, */
+#define T_ST_S2 0x20 /* read 0 when switch is on, 1 off */
+#define T_ST_S1 0x10
+#define T_ST_PS2 0x08 /* Set for Microchannel 228 */
+#define T_ST_RDY 0x04 /* 5380 DRQ */
+#define T_ST_TIM 0x02 /* indicates 40us watchdog timer fired */
+#define T_ST_ZERO 0x01 /* Allways zero */
+
+#define T_5380_OFFSET 0x1d00 /* 8 registers here, see NCR5380.h */
+
+#define T_DATA_REG_OFFSET 0x1e00 /* rw 512 bytes long */
+
+#ifndef ASM
+int t128_abort(Scsi_Cmnd *, int);
+int t128_biosparam(int, int, int*);
+int t128_detect(int);
+const char *t128_info(void);
+int t128_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
+int t128_reset(void);
+
+#ifndef NULL
+#define NULL 0
+#endif
+
+#ifndef CMD_PER_LUN
+#define CMD_PER_LUN 2
+#endif
+
+#ifndef CAN_QUEUE
+#define CAN_QUEUE 32
+#endif
+
+/*
+ * I hadn't thought of this with the earlier drivers - but to prevent
+ * macro definition conflicts, we shouldn't define all of the internal
+ * macros when this is being used solely for the host stub.
+ */
+
+#ifdef HOSTS_C
+
+#define TRANTOR_T128 {"Trantor T128/T128F/T228", t128_detect, t128_info,\
+ NULL, t128_queue_command, t128_abort, t128_reset, NULL, \
+ t128_biosparam, \
+ /* can queue */ CAN_QUEUE, /* id */ 7, SG_ALL, \
+ /* cmd per lun */ CMD_PER_LUN , 0, 0}
+
+#else
+
+#define NCR5380_implementation_fields \
+ volatile unsigned char *base
+
+#define NCR5380_local_declare() \
+ volatile unsigned char *base
+
+#define NCR5380_setup(instance) \
+ base = (volatile unsigned char *) (instance)->base
+
+#define T128_address(reg) (base + T_5380_OFFSET + ((reg) * 0x20))
+
+#if !(TDEBUG & TDEBUG_TRANSFER)
+#define NCR5380_read(reg) (*(T128_address(reg)))
+#define NCR5380_write(reg, value) (*(T128_address(reg)) = (value))
+#else
+#define NCR5380_read(reg) \
+ (((unsigned char) printk("scsi%d : read register %d at address %08x\n"\
+ , instance->hostno, (reg), T128_address(reg))), *(T128_address(reg)))
+
+#define NCR5380_write(reg, value) { \
+ printk("scsi%d : write %02x to register %d at address %08x\n", \
+ instance->hostno, (value), (reg), T128_address(reg)); \
+ *(T128_address(reg)) = (value); \
+}
+#endif
+
+#define NCR5380_intr t128_intr
+#define NCR5380_queue_command t128_queue_command
+#define NCR5380_abort t128_abort
+#define NCR5380_reset t128_reset
+
+/* 15 14 12 10 7 5 3
+ 1101 0100 1010 1000 */
+
+#define T128_IRQS 0xc4a8
+
+#endif /* else def HOSTS_C */
+#endif /* ndef ASM */
+#endif /* T128_H */
diff --git a/drivers/scsi/ultrastor.c b/drivers/scsi/ultrastor.c
new file mode 100644
index 0000000..9b03cf5
--- /dev/null
+++ b/drivers/scsi/ultrastor.c
@@ -0,0 +1,1120 @@
+/*
+ * ultrastor.c Copyright (C) 1992 David B. Gentzel
+ * Low-level SCSI driver for UltraStor 14F, 24F, and 34F
+ * by David B. Gentzel, Whitfield Software Services, Carnegie, PA
+ * (gentzel@nova.enet.dec.com)
+ * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
+ * 24F and multiple command support by John F. Carr (jfc@athena.mit.edu)
+ * John's work modified by Caleb Epstein (cae@jpmorgan.com) and
+ * Eric Youngdale (eric@tantalus.nrl.navy.mil).
+ * Thanks to UltraStor for providing the necessary documentation
+ */
+
+/*
+ * TODO:
+ * 1. Find out why scatter/gather is limited to 16 requests per command.
+ * 2. Look at command linking (mscp.command_link and
+ * mscp.command_link_id). (Does not work with many disks,
+ * and no performance increase. ERY).
+ * 3. Allow multiple adapters.
+ */
+
+/*
+ * NOTES:
+ * The UltraStor 14F, 24F, and 34F are a family of intelligent, high
+ * performance SCSI-2 host adapters. They all support command queueing
+ * and scatter/gather I/O. Some of them can also emulate the standard
+ * WD1003 interface for use with OS's which don't support SCSI. Here
+ * is the scoop on the various models:
+ * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
+ * 14N - ISA HA with floppy support. I think that this is a non-DMA
+ * HA. Nothing further known.
+ * 24F - EISA Bus Master HA with floppy support and WD1003 emulation.
+ * 34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation).
+ *
+ * The 14F, 24F, and 34F are supported by this driver.
+ *
+ * Places flagged with a triple question-mark are things which are either
+ * unfinished, questionable, or wrong.
+ */
+
+/* Changes from version 1.9 to 1.11
+ *
+ * Patches to bring this driver up to speed with the default kernel
+ * driver which supports only the 14F and 34F adapters. This version
+ * should compile cleanly into 0.99.13, 0.99.12 and probably 0.99.11.
+ *
+ * Fixes from Eric Youngdale to fix a few possible race conditions and
+ * several problems with bit testing operations (insufficient
+ * parentheses).
+ *
+ * Removed the ultrastor_abort() and ultrastor_reset() functions
+ * (enclosed them in #if 0 / #endif). These functions, at least on
+ * the 24F, cause the SCSI bus to do odd things and generally lead to
+ * kernel panics and machine hangs. This is like the Adaptec code.
+ *
+ * Use check/snarf_region for 14f, 34f to avoid I/O space address conflicts.
+ */
+
+/* Changes from version 1.8 to version 1.9
+ *
+ * 0.99.11 patches (cae@jpmorgan.com) */
+
+/* Changes from version 1.7 to version 1.8
+ *
+ * Better error reporting.
+ */
+
+/* Changes from version 1.6 to version 1.7
+ *
+ * Removed CSIR command code.
+ *
+ * Better race condition avoidance (xchgb function added).
+ *
+ * Set ICM and OGM status to zero at probe (24F)
+ *
+ * reset sends soft reset to UltraStor adapter
+ *
+ * reset adapter if adapter interrupts with an invalid MSCP address
+ *
+ * handle aborted command interrupt (24F)
+ *
+ */
+
+/* Changes from version 1.5 to version 1.6:
+ *
+ * Read MSCP address from ICM _before_ clearing the interrupt flag.
+ * This fixes a race condition.
+ */
+
+/* Changes from version 1.4 to version 1.5:
+ *
+ * Abort now calls done when multiple commands are enabled.
+ *
+ * Clear busy when aborted command finishes, not when abort is called.
+ *
+ * More debugging messages for aborts.
+ */
+
+/* Changes from version 1.3 to version 1.4:
+ *
+ * Enable automatic request of sense data on error (requires newer version
+ * of scsi.c to be useful).
+ *
+ * Fix PORT_OVERRIDE for 14F.
+ *
+ * Fix abort and reset to work properly (config.aborted wasn't cleared
+ * after it was tested, so after a command abort no further commands would
+ * work).
+ *
+ * Boot time test to enable SCSI bus reset (defaults to not allowing reset).
+ *
+ * Fix test for OGM busy -- the busy bit is in different places on the 24F.
+ *
+ * Release ICM slot by clearing first byte on 24F.
+ */
+
+#include <linux/stddef.h>
+#include <linux/string.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+
+#include <asm/io.h>
+#include <asm/bitops.h>
+#include <asm/system.h>
+#include <asm/dma.h>
+
+#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */
+#include "../block/blk.h"
+#include "scsi.h"
+#include "hosts.h"
+#include "ultrastor.h"
+
+#define FALSE 0
+#define TRUE 1
+
+#ifndef ULTRASTOR_DEBUG
+#define ULTRASTOR_DEBUG (UD_ABORT|UD_CSIR|UD_RESET)
+#endif
+
+#define VERSION "1.11 alpha"
+
+#define ARRAY_SIZE(arr) (sizeof (arr) / sizeof (arr)[0])
+
+#define PACKED __attribute__((packed))
+#define ALIGNED(x) __attribute__((aligned(x)))
+
+
+/* The 14F uses an array of 4-byte ints for its scatter/gather list.
+ The data can be unaligned, but need not be. It's easier to give
+ the list normal alignment since it doesn't need to fit into a
+ packed structure. */
+
+typedef struct {
+ unsigned int address;
+ unsigned int num_bytes;
+} ultrastor_sg_list;
+
+
+/* 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 */
+ unsigned int transfer_data PACKED; /* transfer data pointer */
+ unsigned int transfer_data_length PACKED; /* length in bytes */
+ unsigned int command_link PACKED; /* 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 */
+ unsigned int sense_data PACKED;
+ /* The following fields are for software only. They are included in
+ the MSCP structure because they are associated with SCSI requests. */
+ void (*done)(Scsi_Cmnd *);
+ Scsi_Cmnd *SCint;
+ ultrastor_sg_list sglist[ULTRASTOR_14F_MAX_SG];
+};
+
+
+/* Port addresses (relative to the base address) */
+#define U14F_PRODUCT_ID(port) ((port) + 0x4)
+#define CONFIG(port) ((port) + 0x6)
+
+/* Port addresses relative to the doorbell 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)
+
+
+/* Used to store configuration info read from config i/o registers. Most of
+ this is not used yet, but might as well save it.
+
+ This structure also holds port addresses that are not at the same offset
+ on the 14F and 24F.
+
+ This structure holds all data that must be duplicated to support multiple
+ adapters. */
+
+static struct ultrastor_config
+{
+ unsigned short port_address; /* base address of card */
+ unsigned short doorbell_address; /* base address of doorbell CSRs */
+ unsigned short ogm_address; /* base address of OGM */
+ unsigned short icm_address; /* base address of ICM */
+ const void *bios_segment;
+ unsigned char interrupt: 4;
+ unsigned char dma_channel: 3;
+ unsigned char bios_drive_number: 1;
+ unsigned char heads;
+ unsigned char sectors;
+ unsigned char ha_scsi_id: 3;
+ unsigned char subversion: 4;
+ unsigned char revision;
+ /* The slot number is used to distinguish the 24F (slot != 0) from
+ the 14F and 34F (slot == 0). */
+ unsigned char slot;
+
+#ifdef PRINT_U24F_VERSION
+ volatile int csir_done;
+#endif
+
+ /* Our index in the host adapter array maintained by higher-level driver */
+ int host_number;
+
+ /* A pool of MSCP structures for this adapter, and a bitmask of
+ busy structures. (If ULTRASTOR_14F_MAX_CMDS == 1, a 1 byte
+ busy flag is used instead.) */
+
+#if ULTRASTOR_MAX_CMDS == 1
+ unsigned char mscp_busy;
+#else
+ unsigned short mscp_free;
+#endif
+ volatile unsigned char aborted[ULTRASTOR_MAX_CMDS];
+ struct mscp mscp[ULTRASTOR_MAX_CMDS];
+} config = {0};
+
+/* Set this to 1 to reset the SCSI bus on error. */
+int ultrastor_bus_reset = 0;
+
+
+/* Allowed BIOS base addresses (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_14f[4] = { 15, 14, 11, 10 };
+
+/* Allowed DMA channels for 14f (0 indicates reserved) */
+static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
+
+/* Head/sector mappings allowed by 14f */
+static const struct {
+ unsigned char heads;
+ unsigned char sectors;
+} mapping_table[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 64, 32 } };
+
+#ifndef PORT_OVERRIDE
+/* ??? A probe of address 0x310 screws up NE2000 cards */
+static const unsigned short ultrastor_ports_14f[] = {
+ 0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140,
+};
+#endif
+
+static void ultrastor_interrupt(int cpl);
+static inline void build_sg_list(struct mscp *, Scsi_Cmnd *SCpnt);
+
+
+static inline int find_and_clear_bit_16(unsigned short *field)
+{
+ int rv;
+ cli();
+ if (*field == 0) panic("No free mscp");
+ asm("xorl %0,%0\n0:\tbsfw %1,%w0\n\tbtr %0,%1\n\tjnc 0b"
+ : "=&r" (rv), "=m" (*field) : "1" (*field));
+ sti();
+ return rv;
+}
+
+/* This asm is fragile: it doesn't work without the casts and it may
+ not work without optimization. Maybe I should add a swap builtin
+ to gcc. --jfc */
+static inline unsigned char xchgb(unsigned char reg,
+ volatile unsigned char *mem)
+{
+ asm("xchgb %0,%1" :
+ "=r" (reg), "=m" (*(unsigned char *)mem) :
+ "0" (reg), "1" (*(unsigned char *)mem));
+ return reg;
+}
+
+static inline void outl(unsigned int value, unsigned short port)
+{
+__asm__ __volatile__ ("outl %%al,%%dx"
+ : :"a" (value),"d" ((unsigned short) port));
+}
+
+static inline unsigned int inl(unsigned short port)
+{
+ unsigned int _v;
+__asm__ __volatile__ ("inl %%dx,%%eax"
+ :"=a" (_v):"d" ((unsigned short) port),"0" (0));
+ return _v;
+}
+
+#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
+
+static void log_ultrastor_abort(register struct ultrastor_config *config,
+ int command)
+{
+ static char fmt[80] = "abort %d (%x); MSCP free pool: %x;";
+ register int i;
+ int flags;
+ save_flags(flags);
+ cli();
+
+ for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
+ {
+ fmt[20 + i*2] = ' ';
+ if (! (config->mscp_free & (1 << i)))
+ fmt[21 + i*2] = '0' + config->mscp[i].target_id;
+ else
+ fmt[21 + i*2] = '-';
+ }
+ fmt[20 + ULTRASTOR_MAX_CMDS * 2] = '\n';
+ fmt[21 + ULTRASTOR_MAX_CMDS * 2] = 0;
+ printk(fmt, command, &config->mscp[command], config->mscp_free);
+ restore_flags(flags);
+}
+#endif
+
+static int ultrastor_14f_detect(int hostnum)
+{
+ size_t i;
+ unsigned char in_byte, version_byte = 0;
+ struct config_1 {
+ unsigned char bios_segment: 3;
+ unsigned char removable_disks_as_fixed: 1;
+ unsigned char interrupt: 2;
+ unsigned char dma_channel: 2;
+ } config_1;
+ struct config_2 {
+ unsigned char ha_scsi_id: 3;
+ unsigned char mapping_mode: 2;
+ unsigned char bios_drive_number: 1;
+ unsigned char tfr_port: 2;
+ } config_2;
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: called\n");
+#endif
+
+ /* If a 24F has already been configured, don't look for a 14F. */
+ if (config.bios_segment)
+ return FALSE;
+
+#ifdef PORT_OVERRIDE
+ if(check_region(PORT_OVERRIDE, 0xc)) {
+ printk("Ultrastor I/O space already in use\n");
+ return FALSE;
+ };
+ config.port_address = PORT_OVERRIDE;
+#else
+ for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
+ if(check_region(ultrastor_ports_14f[i], 0x0c)) continue;
+ config.port_address = ultrastor_ports_14f[i];
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: testing port address %03X\n", config.port_address);
+#endif
+
+ in_byte = inb(U14F_PRODUCT_ID(config.port_address));
+ if (in_byte != US14F_PRODUCT_ID_0) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+# ifdef PORT_OVERRIDE
+ printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
+# else
+ printk("US14F: detect: no adapter at port %03X\n", config.port_address);
+# endif
+#endif
+#ifdef PORT_OVERRIDE
+ return FALSE;
+#else
+ continue;
+#endif
+ }
+ in_byte = inb(U14F_PRODUCT_ID(config.port_address) + 1);
+ /* Only upper nibble is significant for Product ID 1 */
+ if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+# ifdef PORT_OVERRIDE
+ printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
+# else
+ printk("US14F: detect: no adapter at port %03X\n", config.port_address);
+# endif
+#endif
+#ifdef PORT_OVERRIDE
+ return FALSE;
+#else
+ continue;
+#endif
+ }
+ version_byte = in_byte;
+#ifndef PORT_OVERRIDE
+ break;
+ }
+ if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
+# if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: no port address found!\n");
+# endif
+ return FALSE;
+ }
+#endif
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: adapter found at port address %03X\n",
+ config.port_address);
+#endif
+
+ /* Set local doorbell mask to disallow bus reset unless
+ ultrastor_bus_reset is true. */
+ outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(config.port_address));
+
+ /* All above tests passed, must be the right thing. Get some useful
+ info. */
+
+ snarf_region(config.port_address, 0x0c); /* Register the I/O space that we use */
+
+ *(char *)&config_1 = inb(CONFIG(config.port_address + 0));
+ *(char *)&config_2 = inb(CONFIG(config.port_address + 1));
+ config.bios_segment = bios_segment_table[config_1.bios_segment];
+ config.doorbell_address = config.port_address;
+ config.ogm_address = config.port_address + 0x8;
+ config.icm_address = config.port_address + 0xC;
+ config.interrupt = interrupt_table_14f[config_1.interrupt];
+ config.ha_scsi_id = config_2.ha_scsi_id;
+ config.heads = mapping_table[config_2.mapping_mode].heads;
+ config.sectors = mapping_table[config_2.mapping_mode].sectors;
+ config.bios_drive_number = config_2.bios_drive_number;
+ config.subversion = (version_byte & 0x0F);
+ if (config.subversion == U34F)
+ config.dma_channel = 0;
+ else
+ config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
+
+ if (!config.bios_segment) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: not detected.\n");
+#endif
+ return FALSE;
+ }
+
+ /* Final consistancy check, verify previous info. */
+ if (config.subversion != U34F)
+ if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: consistancy check failed\n");
+#endif
+ return FALSE;
+ }
+
+ /* If we were TRULY paranoid, we could issue a host adapter inquiry
+ command here and verify the data returned. But frankly, I'm
+ exhausted! */
+
+ /* Finally! Now I'm satisfied... */
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US14F: detect: detect succeeded\n"
+ " Port address: %03X\n"
+ " BIOS segment: %05X\n"
+ " Interrupt: %u\n"
+ " DMA channel: %u\n"
+ " H/A SCSI ID: %u\n"
+ " Subversion: %u\n",
+ config.port_address, config.bios_segment, config.interrupt,
+ config.dma_channel, config.ha_scsi_id, config.subversion);
+#endif
+ config.host_number = hostnum;
+ scsi_hosts[hostnum].this_id = config.ha_scsi_id;
+ scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);
+
+#if ULTRASTOR_MAX_CMDS > 1
+ config.mscp_free = ~0;
+#endif
+
+ if (request_irq(config.interrupt, ultrastor_interrupt)) {
+ printk("Unable to allocate IRQ%u for UltraStor controller.\n",
+ config.interrupt);
+ return FALSE;
+ }
+ if (config.dma_channel && request_dma(config.dma_channel)) {
+ printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
+ config.dma_channel);
+ free_irq(config.interrupt);
+ return FALSE;
+ }
+ scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
+ printk("UltraStor driver version" VERSION ". Using %d SG lists.\n",
+ ULTRASTOR_14F_MAX_SG);
+
+ return TRUE;
+}
+
+static int ultrastor_24f_detect(int hostnum)
+{
+ register int i;
+
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US24F: detect");
+#endif
+
+ /* probe each EISA slot at slot address C80 */
+ for (i = 1; i < 15; i++)
+ {
+ unsigned char config_1, config_2;
+ unsigned short addr = (i << 12) | ULTRASTOR_24F_PORT;
+
+ if (inb(addr) != US24F_PRODUCT_ID_0 &&
+ inb(addr+1) != US24F_PRODUCT_ID_1 &&
+ inb(addr+2) != US24F_PRODUCT_ID_2)
+ continue;
+
+ config.revision = inb(addr+3);
+ config.slot = i;
+ if (! (inb(addr+4) & 1))
+ {
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("U24F: found disabled card in slot %u\n", i);
+#endif
+ continue;
+ }
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("U24F: found card in slot %u\n", i);
+#endif
+ config_1 = inb(addr + 5);
+ config.bios_segment = bios_segment_table[config_1 & 7];
+ switch(config_1 >> 4)
+ {
+ case 1:
+ config.interrupt = 15;
+ break;
+ case 2:
+ config.interrupt = 14;
+ break;
+ case 4:
+ config.interrupt = 11;
+ break;
+ case 8:
+ config.interrupt = 10;
+ break;
+ default:
+ printk("U24F: invalid IRQ\n");
+ return FALSE;
+ }
+ if (request_irq(config.interrupt, ultrastor_interrupt))
+ {
+ printk("Unable to allocate IRQ%u for UltraStor controller.\n",
+ config.interrupt);
+ return FALSE;
+ }
+ /* BIOS addr set */
+ /* base port set */
+ config.port_address = addr;
+ config.doorbell_address = addr + 12;
+ config.ogm_address = addr + 0x17;
+ config.icm_address = addr + 0x1C;
+ config_2 = inb(addr + 7);
+ config.ha_scsi_id = config_2 & 7;
+ config.heads = mapping_table[(config_2 >> 3) & 3].heads;
+ config.sectors = mapping_table[(config_2 >> 3) & 3].sectors;
+#if (ULTRASTOR_DEBUG & UD_DETECT)
+ printk("US24F: detect: detect succeeded\n"
+ " Port address: %03X\n"
+ " BIOS segment: %05X\n"
+ " Interrupt: %u\n"
+ " H/A SCSI ID: %u\n",
+ config.port_address, config.bios_segment,
+ config.interrupt, config.ha_scsi_id);
+#endif
+ config.host_number = hostnum;
+ scsi_hosts[hostnum].this_id = config.ha_scsi_id;
+ scsi_hosts[hostnum].unchecked_isa_dma = 0;
+ scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
+
+#if ULTRASTOR_MAX_CMDS > 1
+ config.mscp_free = ~0;
+#endif
+ /* Mark ICM and OGM free */
+ outb(0, addr + 0x16);
+ outb(0, addr + 0x1B);
+
+ /* Set local doorbell mask to disallow bus reset unless
+ ultrastor_bus_reset is true. */
+ outb(ultrastor_bus_reset ? 0xc2 : 0x82, LCL_DOORBELL_MASK(addr+12));
+ outb(0x02, SYS_DOORBELL_MASK(addr+12));
+ printk("UltraStor driver version " VERSION ". Using %d SG lists.\n",
+ ULTRASTOR_14F_MAX_SG);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+int ultrastor_detect(int hostnum)
+{
+ return ultrastor_14f_detect(hostnum) || ultrastor_24f_detect(hostnum);
+}
+
+const char *ultrastor_info(void)
+{
+ static char buf[64];
+
+ if (config.slot)
+ sprintf(buf, "UltraStor 24F SCSI @ Slot %u IRQ%u\n",
+ config.slot, config.interrupt);
+ else if (config.subversion)
+ sprintf(buf, "UltraStor 34F SCSI @ Port %03X BIOS %05X IRQ%u\n",
+ config.port_address, (int)config.bios_segment,
+ config.interrupt);
+ else
+ sprintf(buf, "UltraStor 14F SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
+ config.port_address, (int)config.bios_segment,
+ config.interrupt, config.dma_channel);
+ return buf;
+}
+
+static inline void build_sg_list(register struct mscp *mscp, Scsi_Cmnd *SCpnt)
+{
+ struct scatterlist *sl;
+ long transfer_length = 0;
+ int i, max;
+
+ sl = (struct scatterlist *) SCpnt->request_buffer;
+ max = SCpnt->use_sg;
+ for (i = 0; i < max; i++) {
+ mscp->sglist[i].address = (unsigned int)sl[i].address;
+ mscp->sglist[i].num_bytes = sl[i].length;
+ transfer_length += sl[i].length;
+ }
+ mscp->number_of_sg_list = max;
+ mscp->transfer_data = (unsigned int)mscp->sglist;
+ /* ??? May not be necessary. Docs are unclear as to whether transfer
+ length field is ignored or whether it should be set to the total
+ number of bytes of the transfer. */
+ mscp->transfer_data_length = transfer_length;
+}
+
+int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
+{
+ register struct mscp *my_mscp;
+#if ULTRASTOR_MAX_CMDS > 1
+ int mscp_index;
+#endif
+ unsigned int status;
+ int flags;
+
+ /* Next test is for debugging; "can't happen" */
+ if ((config.mscp_free & ((1U << ULTRASTOR_MAX_CMDS) - 1)) == 0)
+ panic("ultrastor_queuecommand: no free MSCP\n");
+ mscp_index = find_and_clear_bit_16(&config.mscp_free);
+
+ /* Has the command been aborted? */
+ if (xchgb(0xff, &config.aborted[mscp_index]) != 0)
+ {
+ status = DID_ABORT << 16;
+ goto aborted;
+ }
+
+ my_mscp = &config.mscp[mscp_index];
+
+#if 1
+ /* This way is faster. */
+ *(unsigned char *)my_mscp = OP_SCSI | (DTD_SCSI << 3);
+#else
+ my_mscp->opcode = OP_SCSI;
+ my_mscp->xdir = DTD_SCSI;
+ my_mscp->dcn = FALSE;
+#endif
+ /* Tape drives don't work properly if the cache is used. The SCSI
+ READ command for a tape doesn't have a block offset, and the adapter
+ incorrectly assumes that all reads from the tape read the same
+ blocks. Results will depend on read buffer size and other disk
+ activity.
+
+ ??? Which other device types should never use the cache? */
+ my_mscp->ca = scsi_devices[SCpnt->index].type != TYPE_TAPE;
+ my_mscp->target_id = SCpnt->target;
+ my_mscp->ch_no = 0;
+ my_mscp->lun = SCpnt->lun;
+ if (SCpnt->use_sg) {
+ /* Set scatter/gather flag in SCSI command packet */
+ my_mscp->sg = TRUE;
+ build_sg_list(my_mscp, SCpnt);
+ } else {
+ /* Unset scatter/gather flag in SCSI command packet */
+ my_mscp->sg = FALSE;
+ my_mscp->transfer_data = (unsigned int)SCpnt->request_buffer;
+ my_mscp->transfer_data_length = SCpnt->request_bufflen;
+ }
+ my_mscp->command_link = 0; /*???*/
+ my_mscp->scsi_command_link_id = 0; /*???*/
+ my_mscp->length_of_sense_byte = sizeof SCpnt->sense_buffer;
+ my_mscp->length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
+ memcpy(my_mscp->scsi_cdbs, SCpnt->cmnd, my_mscp->length_of_scsi_cdbs);
+ my_mscp->adapter_status = 0;
+ my_mscp->target_status = 0;
+ my_mscp->sense_data = (unsigned int)&SCpnt->sense_buffer;
+ my_mscp->done = done;
+ my_mscp->SCint = SCpnt;
+ SCpnt->host_scribble = (unsigned char *)my_mscp;
+
+ /* Find free OGM slot. On 24F, look for OGM status byte == 0.
+ On 14F and 34F, wait for local interrupt pending flag to clear. */
+
+ retry:
+ if (config.slot)
+ while (inb(config.ogm_address - 1) != 0 &&
+ config.aborted[mscp_index] == 0xff);
+
+ /* else??? */
+
+ while ((inb(LCL_DOORBELL_INTR(config.doorbell_address)) &
+ (config.slot ? 2 : 1))
+ && config.aborted[mscp_index] == 0xff);
+
+ /* To avoid race conditions, make the code to write to the adapter
+ atomic. This simplifies the abort code. */
+
+ save_flags(flags);
+ cli();
+
+ if (inb(LCL_DOORBELL_INTR(config.doorbell_address)) &
+ (config.slot ? 2 : 1))
+ {
+ restore_flags(flags);
+ goto retry;
+ }
+
+ status = xchgb(0, &config.aborted[mscp_index]);
+ if (status != 0xff) {
+ restore_flags(flags);
+
+#if ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT)
+ printk("USx4F: queuecommand: aborted\n");
+#if ULTRASTOR_MAX_CMDS > 1
+ log_ultrastor_abort(&config, mscp_index);
+#endif
+#endif
+ status <<= 16;
+
+ aborted:
+ set_bit(mscp_index, &config.mscp_free);
+ /* If the driver queues commands, call the done proc here. Otherwise
+ return an error. */
+#if ULTRASTOR_MAX_CMDS > 1
+ SCpnt->result = status;
+ done(SCpnt);
+ return 0;
+#else
+ return status;
+#endif
+ }
+
+ /* Store pointer in OGM address bytes */
+ outl((unsigned int)my_mscp, config.ogm_address);
+
+ /* Issue OGM interrupt */
+ if (config.slot) {
+ /* Write OGM command register on 24F */
+ outb(1, config.ogm_address - 1);
+ outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
+ } else {
+ outb(0x1, LCL_DOORBELL_INTR(config.doorbell_address));
+ }
+
+ restore_flags(flags);
+
+#if (ULTRASTOR_DEBUG & UD_COMMAND)
+ printk("USx4F: queuecommand: returning\n");
+#endif
+
+ return 0;
+}
+
+/* This code must deal with 2 cases:
+
+ 1. The command has not been written to the OGM. In this case, set
+ the abort flag and return.
+
+ 2. The command has been written to the OGM and is stuck somewhere in
+ the adapter.
+
+ 2a. On a 24F, ask the adapter to abort the command. It will interrupt
+ when it does.
+
+ 2b. Call the command's done procedure.
+
+ */
+
+int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
+{
+#if ULTRASTOR_DEBUG & UD_ABORT
+ char out[108];
+ unsigned char icm_status = 0, ogm_status = 0;
+ unsigned int icm_addr = 0, ogm_addr = 0;
+#endif
+ unsigned int mscp_index;
+ unsigned char old_aborted;
+ void (*done)(Scsi_Cmnd *);
+
+ if(config.slot) return 0; /* Do not attempt an abort for the 24f */
+
+ mscp_index = ((struct mscp *)SCpnt->host_scribble) - config.mscp;
+ if (mscp_index >= ULTRASTOR_MAX_CMDS)
+ panic("Ux4F aborting invalid MSCP");
+
+#if ULTRASTOR_DEBUG & UD_ABORT
+ if (config.slot)
+ {
+ int port0 = (config.slot << 12) | 0xc80;
+ int i;
+ int flags;
+ save_flags(flags);
+ cli();
+ strcpy(out, "OGM %d:%x ICM %d:%x ports: ");
+ for (i = 0; i < 16; i++)
+ {
+ unsigned char p = inb(port0 + i);
+ out[28 + i * 3] = "0123456789abcdef"[p >> 4];
+ out[29 + i * 3] = "0123456789abcdef"[p & 15];
+ out[30 + i * 3] = ' ';
+ }
+ out[28 + i * 3] = '\n';
+ out[29 + i * 3] = 0;
+ ogm_status = inb(port0 + 22);
+ ogm_addr = inl(port0 + 23);
+ icm_status = inb(port0 + 27);
+ icm_addr = inl(port0 + 28);
+ restore_flags(flags);
+ }
+
+ /* First check to see if an interrupt is pending. I suspect the SiS
+ chipset loses interrupts. (I also suspect is mangles data, but
+ one bug at a time... */
+ if (config.slot ? inb(config.icm_address - 1) == 2 :
+ (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
+ {
+ int flags;
+ save_flags(flags);
+ printk("Ux4F: abort while completed command pending\n");
+ restore_flags(flags);
+ cli();
+ ultrastor_interrupt(0);
+ restore_flags(flags);
+ return 0;
+ }
+#endif
+
+ old_aborted = xchgb(code ? code : DID_ABORT, &config.aborted[mscp_index]);
+
+ /* aborted == 0xff is the signal that queuecommand has not yet sent
+ the command. It will notice the new abort flag and fail. */
+ if (old_aborted == 0xff)
+ return 0;
+
+ /* On 24F, send an abort MSCP request. The adapter will interrupt
+ and the interrupt handler will call done. */
+ if (config.slot && inb(config.ogm_address - 1) == 0)
+ {
+ int flags;
+
+ save_flags(flags);
+ cli();
+ outl((int)&config.mscp[mscp_index], config.ogm_address);
+ inb(0xc80); /* delay */
+ outb(0x80, config.ogm_address - 1);
+ outb(0x2, LCL_DOORBELL_INTR(config.doorbell_address));
+#if ULTRASTOR_DEBUG & UD_ABORT
+ log_ultrastor_abort(&config, mscp_index);
+ printk(out, ogm_status, ogm_addr, icm_status, icm_addr);
+#endif
+ restore_flags(flags);
+ return 0;
+ }
+
+#if ULTRASTOR_DEBUG & UD_ABORT
+ log_ultrastor_abort(&config, mscp_index);
+#endif
+
+ /* Can't request a graceful abort. Either this is not a 24F or
+ the OGM is busy. Don't free the command -- the adapter might
+ still be using it. Setting SCint = 0 causes the interrupt
+ handler to ignore the command. */
+
+#if ULTRASTOR_DEBUG & UD_ABORT
+ if (config.mscp[mscp_index].SCint != SCpnt)
+ printk("abort: command mismatch, %x != %x\n",
+ config.mscp[mscp_index].SCint, SCpnt);
+#endif
+ if (config.mscp[mscp_index].SCint == 0)
+ return 1;
+
+ if (config.mscp[mscp_index].SCint != SCpnt) panic("Bad abort");
+ config.mscp[mscp_index].SCint = 0;
+ done = config.mscp[mscp_index].done;
+ config.mscp[mscp_index].done = 0;
+ SCpnt->result = DID_ABORT << 16;
+ /* I worry about reentrancy in scsi.c */
+ done(SCpnt);
+
+ /* Need to set a timeout here in case command never completes. */
+ return 0;
+
+}
+
+int ultrastor_reset(void)
+{
+ int flags;
+ register int i;
+#if (ULTRASTOR_DEBUG & UD_RESET)
+ printk("US14F: reset: called\n");
+#endif
+
+ if(config.slot) return 0; /* Do not attempt a reset for the 24f */
+ save_flags(flags);
+ cli();
+
+ /* Reset the adapter and SCSI bus. The SCSI bus reset can be
+ inhibited by clearing ultrastor_bus_reset before probe. */
+ outb(0xc0, LCL_DOORBELL_INTR(config.doorbell_address));
+ if (config.slot)
+ {
+ outb(0, config.ogm_address - 1);
+ outb(0, config.icm_address - 1);
+ }
+
+#if ULTRASTOR_MAX_CMDS == 1
+ if (config.mscp_busy && config.mscp->done && config.mscp->SCint)
+ {
+ config.mscp->SCint->result = DID_RESET << 16;
+ config.mscp->done(config.mscp->SCint);
+ }
+ config.mscp->SCint = 0;
+#else
+ for (i = 0; i < ULTRASTOR_MAX_CMDS; i++)
+ {
+ if (! (config.mscp_free & (1 << i)) &&
+ config.mscp[i].done && config.mscp[i].SCint)
+ {
+ config.mscp[i].SCint->result = DID_RESET << 16;
+ config.mscp[i].done(config.mscp[i].SCint);
+ config.mscp[i].done = 0;
+ }
+ config.mscp[i].SCint = 0;
+ }
+#endif
+
+ memset((unsigned char *)config.aborted, 0, sizeof config.aborted);
+#if ULTRASTOR_MAX_CMDS == 1
+ config.mscp_busy = 0;
+#else
+ config.mscp_free = ~0;
+#endif
+
+ restore_flags(flags);
+ return 0;
+
+}
+
+int ultrastor_biosparam(int size, int dev, int * dkinfo)
+{
+ unsigned int s = config.heads * config.sectors;
+
+ dkinfo[0] = config.heads;
+ dkinfo[1] = config.sectors;
+ dkinfo[2] = size / s; /* Ignore partial cylinders */
+ if (dkinfo[2] > 1024)
+ dkinfo[2] = 1024;
+ return 0;
+}
+
+static void ultrastor_interrupt(int cpl)
+{
+ unsigned int status;
+#if ULTRASTOR_MAX_CMDS > 1
+ unsigned int mscp_index;
+#endif
+ register struct mscp *mscp;
+ void (*done)(Scsi_Cmnd *);
+ Scsi_Cmnd *SCtmp;
+
+#if ULTRASTOR_MAX_CMDS == 1
+ mscp = &config.mscp[0];
+#else
+ mscp = (struct mscp *)inl(config.icm_address);
+ mscp_index = mscp - config.mscp;
+ if (mscp_index >= ULTRASTOR_MAX_CMDS) {
+ printk("Ux4F interrupt: bad MSCP address %x\n", (unsigned int) mscp);
+ /* A command has been lost. Reset and report an error
+ for all commands. */
+ ultrastor_reset();
+ return;
+ }
+#endif
+
+ /* Clean ICM slot (set ICMINT bit to 0) */
+ if (config.slot) {
+ unsigned char icm_status = inb(config.icm_address - 1);
+#if ULTRASTOR_DEBUG & (UD_INTERRUPT|UD_ERROR|UD_ABORT)
+ if (icm_status != 1 && icm_status != 2)
+ printk("US24F: ICM status %x for MSCP %d (%x)\n", icm_status,
+ mscp_index, (unsigned int) mscp);
+#endif
+ /* The manual says clear interrupt then write 0 to ICM status.
+ This seems backwards, but I'll do it anyway. --jfc */
+ outb(2, SYS_DOORBELL_INTR(config.doorbell_address));
+ outb(0, config.icm_address - 1);
+ if (icm_status == 4) {
+ printk("UltraStor abort command failed\n");
+ return;
+ }
+ if (icm_status == 3) {
+ void (*done)(Scsi_Cmnd *) = mscp->done;
+ if (done) {
+ mscp->done = 0;
+ mscp->SCint->result = DID_ABORT << 16;
+ done(mscp->SCint);
+ }
+ return;
+ }
+ } else {
+ outb(1, SYS_DOORBELL_INTR(config.doorbell_address));
+ }
+
+ SCtmp = mscp->SCint;
+ mscp->SCint = NULL;
+
+ if (SCtmp == 0)
+ {
+#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
+ printk("MSCP %d (%x): no command\n", mscp_index, (unsigned int) mscp);
+#endif
+#if ULTRASTOR_MAX_CMDS == 1
+ config.mscp_busy = FALSE;
+#else
+ set_bit(mscp_index, &config.mscp_free);
+#endif
+ config.aborted[mscp_index] = 0;
+ return;
+ }
+
+ /* Save done locally and zero before calling. This is needed as
+ once we call done, we may get another command queued before this
+ interrupt service routine can return. */
+ done = mscp->done;
+ mscp->done = 0;
+
+ /* Let the higher levels know that we're done */
+ switch (mscp->adapter_status)
+ {
+ case 0:
+ status = DID_OK << 16;
+ break;
+ case 0x01: /* invalid command */
+ case 0x02: /* invalid parameters */
+ case 0x03: /* invalid data list */
+ default:
+ status = DID_ERROR << 16;
+ break;
+ case 0x84: /* SCSI bus abort */
+ status = DID_ABORT << 16;
+ break;
+ case 0x91:
+ status = DID_TIME_OUT << 16;
+ break;
+ }
+
+ SCtmp->result = status | mscp->target_status;
+
+ SCtmp->host_scribble = 0;
+
+ /* Free up mscp block for next command */
+#if ULTRASTOR_MAX_CMDS == 1
+ config.mscp_busy = FALSE;
+#else
+ set_bit(mscp_index, &config.mscp_free);
+#endif
+
+#if ULTRASTOR_DEBUG & (UD_ABORT|UD_INTERRUPT)
+ if (config.aborted[mscp_index])
+ printk("Ux4 interrupt: MSCP %d (%x) aborted = %d\n",
+ mscp_index, (unsigned int) mscp, config.aborted[mscp_index]);
+#endif
+ config.aborted[mscp_index] = 0;
+
+ if (done)
+ done(SCtmp);
+ else
+ printk("US14F: interrupt: unexpected interrupt\n");
+
+ if (config.slot ? inb(config.icm_address - 1) : (inb(SYS_DOORBELL_INTR(config.doorbell_address)) & 1))
+ printk("Ux4F: multiple commands completed\n");
+
+#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
+ printk("USx4F: interrupt: returning\n");
+#endif
+}
diff --git a/kernel/blk_drv/scsi/ultrastor.h b/drivers/scsi/ultrastor.h
index f79ed5d..dbbaa7c 100644
--- a/kernel/blk_drv/scsi/ultrastor.h
+++ b/drivers/scsi/ultrastor.h
@@ -4,20 +4,15 @@
* by David B. Gentzel, Whitfield Software Services, Carnegie, PA
* (gentzel@nova.enet.dec.com)
* scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
+ * 24F support by John F. Carr (jfc@athena.mit.edu)
+ * John's work modified by Caleb Epstein (cae@jpmorgan.com) and
+ * Eric Youngdale (eric@tantalus.nrl.navy.mil).
* Thanks to UltraStor for providing the necessary documentation
*/
#ifndef _ULTRASTOR_H
#define _ULTRASTOR_H
-/* ??? These don't really belong here */
-#ifndef TRUE
-# define TRUE 1
-#endif
-#ifndef FALSE
-# define FALSE 0
-#endif
-
int ultrastor_detect(int);
const char *ultrastor_info(void);
int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *));
@@ -25,40 +20,41 @@ int ultrastor_abort(Scsi_Cmnd *, int);
int ultrastor_reset(void);
int ultrastor_biosparam(int, int, int *);
-#define ULTRASTOR_14F_MAX_CMDS 1 /*???*/
-#define ULTRASTOR_14F_MAX_SG 16 /* Should be 32, but 32 doesn't work */
-#define ULTRASTOR_14F_MAX_CMDS_PER_LUN 1 /*???*/
+#define ULTRASTOR_14F_MAX_SG 16
+#define ULTRASTOR_MAX_CMDS_PER_LUN 5
+#define ULTRASTOR_MAX_CMDS 16
+
+#define ULTRASTOR_24F_PORT 0xC80
+
#define ULTRASTOR_14F \
- { "UltraStor 14F", ultrastor_detect, ultrastor_info, 0, \
+ { "UltraStor 14F/24F/34F", ultrastor_detect, ultrastor_info, 0, \
ultrastor_queuecommand, ultrastor_abort, ultrastor_reset, \
- 0, ultrastor_biosparam, ULTRASTOR_14F_MAX_CMDS, 0, \
- ULTRASTOR_14F_MAX_SG, ULTRASTOR_14F_MAX_CMDS_PER_LUN, 0, 1 }
+ 0, ultrastor_biosparam, ULTRASTOR_MAX_CMDS, 0, \
+ ULTRASTOR_14F_MAX_SG, ULTRASTOR_MAX_CMDS_PER_LUN, 0, 1 }
+
#ifdef ULTRASTOR_PRIVATE
-#define UD_ABORT 0x0001
-#define UD_COMMAND 0x0002
-#define UD_DETECT 0x0004
-#define UD_INTERRUPT 0x0008
-#define UD_RESET 0x0010
+#define UD_ABORT 0x0001
+#define UD_COMMAND 0x0002
+#define UD_DETECT 0x0004
+#define UD_INTERRUPT 0x0008
+#define UD_RESET 0x0010
+#define UD_MULTI_CMD 0x0020
+#define UD_CSIR 0x0040
+#define UD_ERROR 0x0080
/* #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 */
+#define US24F_PRODUCT_ID_0 0x56
+#define US24F_PRODUCT_ID_1 0x63
+#define US24F_PRODUCT_ID_2 0x02
+
/* Subversion values */
#define U14F 0
#define U34F 1
diff --git a/kernel/blk_drv/scsi/wd7000.c b/drivers/scsi/wd7000.c
index b1cf124..bc21559 100644
--- a/kernel/blk_drv/scsi/wd7000.c
+++ b/drivers/scsi/wd7000.c
@@ -22,7 +22,7 @@
#include <asm/io.h>
#include <linux/ioport.h>
-#include "../blk.h"
+#include "../block/blk.h"
#include "scsi.h"
#include "hosts.h"
@@ -609,7 +609,7 @@ int wd7000_biosparam(int size, int dev, int* ip)
{
ip[0] = 64;
ip[1] = 32;
- ip[2] = (size + 2047) >> 11;
+ ip[2] = size >> 11;
/* if (ip[2] >= 1024) ip[2] = 1024; */
return 0;
}
diff --git a/kernel/blk_drv/scsi/wd7000.h b/drivers/scsi/wd7000.h
index bc27c61..bc27c61 100644
--- a/kernel/blk_drv/scsi/wd7000.h
+++ b/drivers/scsi/wd7000.h
diff --git a/kernel/chr_drv/sound/Makefile b/drivers/sound/Makefile
index 85e5ccd..85e5ccd 100644
--- a/kernel/chr_drv/sound/Makefile
+++ b/drivers/sound/Makefile
diff --git a/kernel/chr_drv/sound/sound_stub.c b/drivers/sound/sound_stub.c
index e7f6255..e7f6255 100644
--- a/kernel/chr_drv/sound/sound_stub.c
+++ b/drivers/sound/sound_stub.c
diff --git a/fs/binfmt_elf.c b/fs/binfmt_elf.c
index 701cf50..bb02f09 100644
--- a/fs/binfmt_elf.c
+++ b/fs/binfmt_elf.c
@@ -1,3 +1,6 @@
+/*
+ * linux/fs/binfmt_elf.c
+ */
#include <linux/fs.h>
#include <linux/sched.h>
#include <linux/mm.h>
@@ -6,22 +9,45 @@
#include <linux/errno.h>
#include <linux/signal.h>
#include <linux/binfmts.h>
-#include <asm/segment.h>
#include <linux/string.h>
#include <linux/fcntl.h>
#include <linux/ptrace.h>
+#include <linux/malloc.h>
+
+#include <asm/segment.h>
asmlinkage int sys_exit(int exit_code);
asmlinkage int sys_close(unsigned fd);
asmlinkage int sys_open(const char *, int, int);
+asmlinkage int sys_brk(unsigned long);
+
+#include <linux/elf.h>
+
+/* We need to explicitly zero any fractional pages
+ after the data section (i.e. bss). This would
+ contain the junk from the file that should not
+ be in memory */
+
+static void padzero(int elf_bss){
+ unsigned int fpnt, nbyte;
+
+ if(elf_bss & 0xfff) {
+
+ nbyte = (PAGE_SIZE - (elf_bss & 0xfff)) & 0xfff;
+ if(nbyte){
+ verify_area(VERIFY_WRITE, (void *) elf_bss, nbyte);
+
+ fpnt = elf_bss;
+ while(fpnt & 0xfff) put_fs_byte(0, fpnt++);
+ };
+ };
+}
/*
* These are the functions used to load ELF style executables and shared
* libraries. There is no binary dependent code anywhere else.
*/
-#include <linux/elf.h>
-
int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
{
struct elfhdr elf_ex;
@@ -106,7 +132,9 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
retval = read_exec(bprm->inode,elf_ppnt->p_offset,elf_interpreter,
elf_ppnt->p_filesz);
+#if 0
printk("Using ELF interpreter %s\n", elf_interpreter);
+#endif
if(retval >= 0)
retval = namei(elf_interpreter, &interpreter_inode);
if(retval >= 0)
@@ -198,15 +226,21 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_fs(old_fs);
if (N_MAGIC(ex) == OMAGIC) {
- retval = read_exec(interpreter_inode, 32, (char *) 0,
- ex.a_text+ex.a_data);
+ do_mmap(NULL, 0, ex.a_text+ex.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ retval = read_exec(interpreter_inode, 32, (char *) 0,
+ ex.a_text+ex.a_data);
iput(interpreter_inode);
} else if (N_MAGIC(ex) == ZMAGIC || N_MAGIC(ex) == QMAGIC) {
- retval = read_exec(interpreter_inode,
- N_TXTOFF(ex) ,
- (char *) N_TXTADDR(ex),
- ex.a_text+ex.a_data);
- iput(interpreter_inode);
+ do_mmap(NULL, 0, ex.a_text+ex.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ retval = read_exec(interpreter_inode,
+ N_TXTOFF(ex) ,
+ (char *) N_TXTADDR(ex),
+ ex.a_text+ex.a_data);
+ iput(interpreter_inode);
} else
retval = -1;
@@ -214,8 +248,11 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
set_fs(get_ds());
if(retval >= 0)
- zeromap_page_range((ex.a_text + ex.a_data + 0xfff) &
- 0xfffff000, ex.a_bss, PAGE_COPY);
+ do_mmap(NULL, (ex.a_text + ex.a_data + 0xfff) &
+ 0xfffff000, ex.a_bss,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+
kfree(elf_interpreter);
if(retval < 0) {
@@ -275,34 +312,61 @@ int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs)
current->start_brk = current->brk = elf_brk;
current->end_code = end_code;
current->start_code = start_code;
+ current->end_data = end_data;
current->start_stack = bprm->p;
current->suid = current->euid = bprm->e_uid;
current->sgid = current->egid = bprm->e_gid;
- zeromap_page_range((elf_bss + 0xfff) & 0xfffff000, elf_brk - elf_bss,
- PAGE_COPY);
+
+ /* Calling sys_brk effectively mmaps the pages that we need for the bss and break
+ sections */
+ current->brk = (elf_bss + 0xfff) & 0xfffff000;
+ sys_brk((elf_brk + 0xfff) & 0xfffff000);
+
+ padzero(elf_bss);
+
regs->eip = elf_entry; /* eip, magic happens :-) */
regs->esp = bprm->p; /* stack pointer */
+ {
+ struct vm_area_struct *mpnt;
+
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+
+ mpnt->vm_task = current;
+ mpnt->vm_start = bprm->p & PAGE_MASK;
+ mpnt->vm_end = TASK_SIZE;
+ mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+ mpnt->vm_share = NULL;
+ mpnt->vm_inode = NULL;
+ mpnt->vm_offset = 0;
+ mpnt->vm_ops = NULL;
+ insert_vm_struct(current, mpnt);
+ current->stk_vma = mpnt;
+ }
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
-
return 0;
}
+/* This is really simpleminded and specialized - we are loading an a.out library that is given
+ an ELF header */
+
int load_elf_library(int fd){
struct file * file;
struct elfhdr elf_ex;
struct elf_phdr *elf_phdata = NULL;
struct inode * inode;
unsigned int len;
+ int elf_bss;
int old_fs, retval;
unsigned int bss;
int error;
- int i,j;
+ int i,j, k;
len = 0;
file = current->filp[fd];
inode = file->f_inode;
+ elf_bss = 0;
set_fs(KERNEL_DS);
if (file->f_op->read(inode, file, (char *) &elf_ex, sizeof(elf_ex)) != sizeof(elf_ex)) {
@@ -355,16 +419,24 @@ int load_elf_library(int fd){
PROT_READ | PROT_WRITE | PROT_EXEC,
MAP_FIXED | MAP_PRIVATE,
elf_phdata->p_offset & 0xfffff000);
+
+ k = elf_phdata->p_vaddr + elf_phdata->p_filesz;
+ if(k > elf_bss) elf_bss = k;
sys_close(fd);
if (error != elf_phdata->p_vaddr & 0xfffff000) {
kfree(elf_phdata);
return error;
}
+
+ padzero(elf_bss);
+
len = (elf_phdata->p_filesz + elf_phdata->p_vaddr+ 0xfff) & 0xfffff000;
bss = elf_phdata->p_memsz + elf_phdata->p_vaddr;
if (bss > len)
- zeromap_page_range(len, bss-len, PAGE_COPY);
+ do_mmap(NULL, len, bss-len,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
kfree(elf_phdata);
return 0;
}
diff --git a/fs/block_dev.c b/fs/block_dev.c
index 76bc169..686c069 100644
--- a/fs/block_dev.c
+++ b/fs/block_dev.c
@@ -73,7 +73,7 @@ int block_write(struct inode * inode, struct file * filp, char * buf, int count)
return written;
}
-#define NBUF 16
+#define NBUF 32
int block_read(struct inode * inode, struct file * filp, char * buf, int count)
{
diff --git a/fs/buffer.c b/fs/buffer.c
index 8773875..17d5f64 100644
--- a/fs/buffer.c
+++ b/fs/buffer.c
@@ -45,6 +45,8 @@ extern int check_cdu31a_media_change(int, int);
extern int check_mcd_media_change(int, int);
#endif
+static int grow_buffers(int pri, int size);
+
static struct buffer_head * hash_table[NR_HASH];
static struct buffer_head * free_list = NULL;
static struct buffer_head * unused_list = NULL;
@@ -456,8 +458,8 @@ repeat:
}
grow_size -= size;
if (nr_free_pages > min_free_pages && grow_size <= 0) {
- grow_buffers(size);
- grow_size = PAGE_SIZE;
+ if (grow_buffers(GFP_BUFFER, size))
+ grow_size = PAGE_SIZE;
}
buffers = nr_buffers;
bh = NULL;
@@ -482,13 +484,14 @@ repeat:
}
if (!bh && nr_free_pages > 5) {
- grow_buffers(size);
- goto repeat;
+ if (grow_buffers(GFP_BUFFER, size))
+ goto repeat;
}
/* and repeat until we find something good */
if (!bh) {
- sleep_on(&buffer_wait);
+ if (!grow_buffers(GFP_ATOMIC, size))
+ sleep_on(&buffer_wait);
goto repeat;
}
wait_on_buffer(bh);
@@ -861,21 +864,21 @@ unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, in
* Try to increase the number of buffers available: the size argument
* is used to determine what kind of buffers we want.
*/
-void grow_buffers(int size)
+static int grow_buffers(int pri, int size)
{
unsigned long page;
struct buffer_head *bh, *tmp;
if ((size & 511) || (size > PAGE_SIZE)) {
printk("VFS: grow_buffers: size = %d\n",size);
- return;
+ return 0;
}
- if(!(page = __get_free_page(GFP_BUFFER)))
- return;
+ if(!(page = __get_free_page(pri)))
+ return 0;
bh = create_buffers(page, size);
if (!bh) {
free_page(page);
- return;
+ return 0;
}
tmp = bh;
while (1) {
@@ -897,7 +900,7 @@ void grow_buffers(int size)
}
tmp->b_this_page = bh;
buffermem += PAGE_SIZE;
- return;
+ return 1;
}
/*
@@ -989,7 +992,7 @@ void buffer_init(void)
for (i = 0 ; i < NR_HASH ; i++)
hash_table[i] = NULL;
free_list = 0;
- grow_buffers(BLOCK_SIZE);
+ grow_buffers(GFP_KERNEL, BLOCK_SIZE);
if (!free_list)
panic("VFS: Unable to initialize buffer free list!");
return;
diff --git a/fs/exec.c b/fs/exec.c
index 1f41a03..a4c3e31 100644
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -37,6 +37,8 @@
#include <linux/ptrace.h>
#include <linux/user.h>
#include <linux/segment.h>
+#include <linux/malloc.h>
+
#include <asm/system.h>
#include <linux/binfmts.h>
@@ -47,6 +49,7 @@
asmlinkage int sys_exit(int exit_code);
asmlinkage int sys_close(unsigned fd);
asmlinkage int sys_open(const char *, int, int);
+asmlinkage int sys_brk(unsigned long);
extern void shm_exit (void);
@@ -117,6 +120,7 @@ int core_dump(long signr, struct pt_regs * regs)
unsigned short fs;
int has_dumped = 0;
char corefile[6+sizeof(current->comm)];
+ int i;
register int dump_start, dump_size;
struct user dump;
@@ -160,6 +164,7 @@ int core_dump(long signr, struct pt_regs * regs)
dump.u_dsize = ((unsigned long) (current->brk + (PAGE_SIZE-1))) >> 12;
dump.u_dsize -= dump.u_tsize;
dump.u_ssize = 0;
+ for(i=0; i<8; i++) dump.u_debugreg[i] = current->debugreg[i];
if (dump.start_stack < TASK_SIZE)
dump.u_ssize = ((unsigned long) (TASK_SIZE - dump.start_stack)) >> 12;
/* If the size of the dump file exceeds the rlimit, then see what would happen
@@ -171,7 +176,7 @@ int core_dump(long signr, struct pt_regs * regs)
if ((dump.u_ssize+1) * PAGE_SIZE >
current->rlim[RLIMIT_CORE].rlim_cur)
dump.u_ssize = 0;
- dump.u_comm = 0;
+ strncpy(dump.u_comm, current->comm, sizeof(current->comm));
dump.u_ar0 = (struct pt_regs *)(((int)(&dump.regs)) -((int)(&dump)));
dump.signal = signr;
dump.regs = *regs;
@@ -192,8 +197,6 @@ int core_dump(long signr, struct pt_regs * regs)
set_fs(KERNEL_DS);
/* struct user */
DUMP_WRITE(&dump,sizeof(dump));
-/* name of the executable */
- DUMP_WRITE(current->comm,16);
/* Now dump all of the user data. Include malloced stuff as well */
DUMP_SEEK(PAGE_SIZE);
/* now we start writing out the user space info */
@@ -419,6 +422,8 @@ int read_exec(struct inode *inode, unsigned long offset,
goto close_readexec;
} else
file.f_pos = offset;
+ if (get_fs() == USER_DS)
+ verify_area(VERIFY_WRITE, addr, count);
result = file.f_op->read(inode, &file, addr, count);
close_readexec:
if (file.f_op->release)
@@ -460,6 +465,7 @@ void flush_old_exec(struct linux_binprm * bprm)
mpnt = current->mmap;
current->mmap = NULL;
+ current->stk_vma = NULL;
while (mpnt) {
mpnt1 = mpnt->vm_next;
if (mpnt->vm_ops && mpnt->vm_ops->close)
@@ -481,6 +487,8 @@ void flush_old_exec(struct linux_binprm * bprm)
}
}
+ for (i=0 ; i<8 ; i++) current->debugreg[i] = 0;
+
if (bprm->e_uid != current->euid || bprm->e_gid != current->egid ||
!permission(bprm->inode,MAY_READ))
current->dumpable = 0;
@@ -744,18 +752,20 @@ int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
/* OK, This is the point of no return */
flush_old_exec(bprm);
- current->start_brk = current->brk = ex.a_bss +
- (current->end_data = ex.a_data +
- (current->end_code = N_TXTADDR(ex) + ex.a_text));
+ current->end_code = N_TXTADDR(ex) + ex.a_text;
+ current->end_data = ex.a_data + current->end_code;
+ current->start_brk = current->brk = current->end_data;
current->start_code += N_TXTADDR(ex);
-
current->rss = 0;
current->suid = current->euid = bprm->e_uid;
current->mmap = NULL;
current->executable = NULL; /* for OMAGIC files */
current->sgid = current->egid = bprm->e_gid;
if (N_MAGIC(ex) == OMAGIC) {
+ do_mmap(NULL, 0, ex.a_text+ex.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data);
} else {
if (ex.a_text & 0xfff || ex.a_data & 0xfff)
@@ -768,7 +778,10 @@ int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
file = current->filp[fd];
if (!file->f_op || !file->f_op->mmap) {
sys_close(fd);
- read_exec(bprm->inode, N_TXTOFF(ex),
+ do_mmap(NULL, 0, ex.a_text+ex.a_data,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
+ read_exec(bprm->inode, N_TXTOFF(ex),
(char *) N_TXTADDR(ex), ex.a_text+ex.a_data);
goto beyond_if;
}
@@ -794,13 +807,30 @@ int load_aout_binary(struct linux_binprm * bprm, struct pt_regs * regs)
bprm->inode->i_count++;
}
beyond_if:
- zeromap_page_range((N_TXTADDR(ex) + ex.a_text + ex.a_data + 0xfff) & 0xfffff000,ex.a_bss, PAGE_COPY);
+ sys_brk(current->brk+ex.a_bss);
+
p += change_ldt(ex.a_text,bprm->page);
p -= MAX_ARG_PAGES*PAGE_SIZE;
p = (unsigned long) create_tables((char *)p,bprm->argc,bprm->envc);
current->start_stack = p;
regs->eip = ex.a_entry; /* eip, magic happens :-) */
regs->esp = p; /* stack pointer */
+ {
+ struct vm_area_struct *mpnt;
+
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+
+ mpnt->vm_task = current;
+ mpnt->vm_start = p & PAGE_MASK;
+ mpnt->vm_end = TASK_SIZE;
+ mpnt->vm_page_prot = PAGE_PRIVATE|PAGE_DIRTY;
+ mpnt->vm_share = NULL;
+ mpnt->vm_inode = NULL;
+ mpnt->vm_offset = 0;
+ mpnt->vm_ops = NULL;
+ insert_vm_struct(current, mpnt);
+ current->stk_vma = mpnt;
+ }
if (current->flags & PF_PTRACED)
send_sig(SIGTRAP, current, 0);
return 0;
@@ -851,9 +881,11 @@ int load_aout_library(int fd)
N_TXTOFF(ex));
if (error != start_addr)
return error;
- len = (ex.a_text + ex.a_data + 0xfff) & 0xfffff000;
+ len = PAGE_ALIGN(ex.a_text + ex.a_data);
bss = ex.a_text + ex.a_data + ex.a_bss;
if (bss > len)
- zeromap_page_range(start_addr + len, bss-len, PAGE_COPY);
+ do_mmap(NULL, start_addr + len, bss-len,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_PRIVATE|MAP_FIXED, 0);
return 0;
}
diff --git a/fs/ext/file.c b/fs/ext/file.c
index 75b6bd1..125461d 100644
--- a/fs/ext/file.c
+++ b/fs/ext/file.c
@@ -23,7 +23,7 @@
#include <linux/stat.h>
#include <linux/locks.h>
-#define NBUF 16
+#define NBUF 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
diff --git a/fs/ext2/dir.c b/fs/ext2/dir.c
index 4634b7e..ff43e3a 100644
--- a/fs/ext2/dir.c
+++ b/fs/ext2/dir.c
@@ -132,6 +132,10 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
#endif
i = de->name_len;
brelse (bh);
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return i;
}
de = (struct ext2_dir_entry *) ((char *) de +
@@ -139,5 +143,9 @@ static int ext2_readdir (struct inode * inode, struct file * filp,
}
brelse (bh);
}
+ if (!IS_RDONLY(inode)) {
+ inode->i_atime = CURRENT_TIME;
+ inode->i_dirt = 1;
+ }
return 0;
}
diff --git a/fs/ext2/file.c b/fs/ext2/file.c
index e48448c..463dc00 100644
--- a/fs/ext2/file.c
+++ b/fs/ext2/file.c
@@ -23,7 +23,7 @@
#include <linux/stat.h>
#include <linux/locks.h>
-#define NBUF 16
+#define NBUF 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
@@ -261,8 +261,7 @@ static int ext2_file_write (struct inode * inode, struct file * filp,
bh->b_dirt = 1;
brelse (bh);
}
- inode->i_mtime = CURRENT_TIME;
- inode->i_ctime = CURRENT_TIME;
+ inode->i_ctime = inode->i_mtime = CURRENT_TIME;
filp->f_pos = pos;
inode->i_dirt = 1;
return written;
diff --git a/fs/ext2/ialloc.c b/fs/ext2/ialloc.c
index de0046f..4444048 100644
--- a/fs/ext2/ialloc.c
+++ b/fs/ext2/ialloc.c
@@ -178,6 +178,7 @@ static void set_inode_dtime (struct inode * inode,
(((inode->i_ino - 1) %
EXT2_INODES_PER_GROUP(inode->i_sb)) %
EXT2_INODES_PER_BLOCK(inode->i_sb));
+ raw_inode->i_links_count = 0;
raw_inode->i_dtime = CURRENT_TIME;
bh->b_dirt = 1;
brelse (bh);
@@ -258,8 +259,8 @@ void ext2_free_inode (struct inode * inode)
es->s_free_inodes_count++;
sb->u.ext2_sb.s_sbh->b_dirt = 1;
sb->s_dirt = 1;
- unlock_super (sb);
clear_inode (inode);
+ unlock_super (sb);
}
/*
diff --git a/fs/ext2/namei.c b/fs/ext2/namei.c
index cd0d05e..c387807 100644
--- a/fs/ext2/namei.c
+++ b/fs/ext2/namei.c
@@ -935,6 +935,7 @@ start_up:
goto end_rename;
if (new_inode) {
new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
new_inode->i_dirt = 1;
}
old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
diff --git a/fs/fifo.c b/fs/fifo.c
index c899f8a..2589457 100644
--- a/fs/fifo.c
+++ b/fs/fifo.c
@@ -22,7 +22,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
* POSIX.1 says that O_NONBLOCK means return with the FIFO
* opened, even when there is no process writing the FIFO.
*/
- filp->f_op = &connecting_pipe_fops;
+ filp->f_op = &connecting_fifo_fops;
if (!PIPE_READERS(*inode)++)
wake_up(&PIPE_WRITE_WAIT(*inode));
if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) {
@@ -40,7 +40,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
while (PIPE_WR_OPENERS(*inode))
interruptible_sleep_on(&PIPE_READ_WAIT(*inode));
if (PIPE_WRITERS(*inode))
- filp->f_op = &read_pipe_fops;
+ filp->f_op = &read_fifo_fops;
if (retval && !--PIPE_READERS(*inode))
wake_up(&PIPE_WRITE_WAIT(*inode));
break;
@@ -55,7 +55,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
retval = -ENXIO;
break;
}
- filp->f_op = &write_pipe_fops;
+ filp->f_op = &write_fifo_fops;
if (!PIPE_WRITERS(*inode)++)
wake_up(&PIPE_READ_WAIT(*inode));
if (!PIPE_READERS(*inode)) {
@@ -83,7 +83,7 @@ static int fifo_open(struct inode * inode,struct file * filp)
* This implementation will NEVER block on a O_RDWR open, since
* the process can at least talk to itself.
*/
- filp->f_op = &rdwr_pipe_fops;
+ filp->f_op = &rdwr_fifo_fops;
if (!PIPE_READERS(*inode)++)
wake_up(&PIPE_WRITE_WAIT(*inode));
while (PIPE_WR_OPENERS(*inode))
diff --git a/fs/isofs/dir.c b/fs/isofs/dir.c
index 66b24e9..829beec 100644
--- a/fs/isofs/dir.c
+++ b/fs/isofs/dir.c
@@ -18,6 +18,7 @@
#include <linux/stat.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/malloc.h>
static int isofs_readdir(struct inode *, struct file *, struct dirent *, int);
@@ -63,6 +64,8 @@ struct lookup_cache cache = {0,};
static int isofs_readdir(struct inode * inode, struct file * filp,
struct dirent * dirent, int count)
{
+ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
+ unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
unsigned int block,offset,i, j;
char c = 0;
int inode_number;
@@ -76,49 +79,56 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
if (!inode || !S_ISDIR(inode->i_mode))
return -EBADF;
- offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode) - 1);
- block = isofs_bmap(inode,(filp->f_pos)>>ISOFS_BUFFER_BITS(inode));
- if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
+ offset = filp->f_pos & (bufsize - 1);
+ block = isofs_bmap(inode,filp->f_pos>>bufbits);
+ if (!block || !(bh = bread(inode->i_dev,block,bufsize)))
return 0;
while (filp->f_pos < inode->i_size) {
#ifdef DEBUG
- printk("Block, offset: %x %x %x\n",block, offset, filp->f_pos);
+ printk("Block, offset: %x %x %x\n",
+ block, offset, filp->f_pos);
#endif
- de = (struct iso_directory_record *) (offset + bh->b_data);
- inode_number = (block << ISOFS_BUFFER_BITS(inode))+(offset & (ISOFS_BUFFER_SIZE(inode) - 1));
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ inode_number = (block << bufbits) + (offset & (bufsize - 1));
- /* If the length byte is zero, we should move on to the next CDROM sector.
- If we are at the end of the directory, we kick out of the while loop. */
+ /* If the length byte is zero, we should move on to the next
+ CDROM sector. If we are at the end of the directory, we
+ kick out of the while loop. */
- if (*((char*) de) == 0) {
+ if (*((unsigned char *) de) == 0) {
brelse(bh);
offset = 0;
- filp->f_pos =(filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))+ISOFS_BLOCK_SIZE;
- block = isofs_bmap(inode,(filp->f_pos)>>ISOFS_BUFFER_BITS(inode));
- if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
+ filp->f_pos = ((filp->f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ + ISOFS_BLOCK_SIZE);
+ block = isofs_bmap(inode,(filp->f_pos)>>bufbits);
+ if (!block
+ || !(bh = bread(inode->i_dev,block,bufsize)))
return 0;
continue;
}
- /* Make sure that the entire directory record is in the current bh block.
- If not, we malloc a buffer, and put the two halves together, so that
- we can cleanly read the block */
-
+ /* Make sure that the entire directory record is in the
+ current bh block.
+ If not, we malloc a buffer, and put the two halves together,
+ so that we can cleanly read the block */
+
old_offset = offset;
- offset += *((unsigned char*) de);
- filp->f_pos += *((unsigned char*) de);
+ offset += *((unsigned char *) de);
+ filp->f_pos += *((unsigned char *) de);
- if (offset >= ISOFS_BUFFER_SIZE(inode)) {
+ if (offset >= bufsize) {
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
- de = (struct iso_directory_record *) (old_offset + cpnt);
+ memcpy(cpnt, bh->b_data, bufsize);
+ de = (struct iso_directory_record *)
+ ((char *)cpnt + old_offset);
brelse(bh);
- offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode) - 1);
- block = isofs_bmap(inode,(filp->f_pos)>> ISOFS_BUFFER_BITS(inode));
- if (!block || !(bh = bread(inode->i_dev,block,ISOFS_BUFFER_SIZE(inode))))
+ offset = filp->f_pos & (bufsize - 1);
+ block = isofs_bmap(inode,(filp->f_pos)>> bufbits);
+ if (!block
+ || !(bh = bread(inode->i_dev,block,bufsize)))
return 0;
- memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
+ memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
}
/* Handle the case of the '.' directory */
@@ -138,7 +148,8 @@ static int isofs_readdir(struct inode * inode, struct file * filp,
put_fs_byte('.',dirent->d_name+1);
i = 2;
dpnt = "..";
- if((inode->i_sb->u.isofs_sb.s_firstdatazone << ISOFS_BUFFER_BITS(inode)) != inode->i_ino)
+ if((inode->i_sb->u.isofs_sb.s_firstdatazone
+ << bufbits) != inode->i_ino)
inode_number = inode->u.isofs_i.i_backlink;
else
inode_number = inode->i_ino;
diff --git a/fs/isofs/file.c b/fs/isofs/file.c
index 5fdb3e7..35d501a 100644
--- a/fs/isofs/file.c
+++ b/fs/isofs/file.c
@@ -21,7 +21,7 @@
#include <linux/dirent.h>
-#define NBUF 16
+#define NBUF 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c
index 7c9777e..e5457e2 100644
--- a/fs/isofs/inode.c
+++ b/fs/isofs/inode.c
@@ -13,6 +13,7 @@
#include <linux/mm.h>
#include <linux/string.h>
#include <linux/locks.h>
+#include <linux/malloc.h>
#include <asm/system.h>
#include <asm/segment.h>
@@ -316,32 +317,33 @@ int isofs_bmap(struct inode * inode,int block)
void isofs_read_inode(struct inode * inode)
{
+ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
struct buffer_head * bh;
+ struct iso_directory_record * raw_inode;
unsigned char *pnt = NULL;
void *cpnt = NULL;
- struct iso_directory_record * raw_inode;
int high_sierra;
int block;
int i;
block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
- if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode))))
+ if (!(bh=bread(inode->i_dev,block, bufsize)))
panic("unable to read i-node block");
- pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
-
+ pnt = ((unsigned char *) bh->b_data
+ + (inode->i_ino & (bufsize - 1)));
raw_inode = ((struct iso_directory_record *) pnt);
high_sierra = inode->i_sb->u.isofs_sb.s_high_sierra;
-
- if ((inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1)) + *pnt > ISOFS_BUFFER_SIZE(inode)){
+ if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
+ memcpy(cpnt, bh->b_data, bufsize);
brelse(bh);
- if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE(inode))))
+ if (!(bh = bread(inode->i_dev,++block, bufsize)))
panic("unable to read i-node block");
- memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
- pnt = ((unsigned char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
+ memcpy((char *)cpnt + bufsize, bh->b_data, bufsize);
+ pnt = ((unsigned char *) cpnt
+ + (inode->i_ino & (bufsize - 1)));
raw_inode = ((struct iso_directory_record *) pnt);
};
@@ -494,7 +496,10 @@ void isofs_read_inode(struct inode * inode)
to change the inode numbers and eliminate this function.
*/
-int isofs_lookup_grandparent(struct inode * parent, int extent) {
+int isofs_lookup_grandparent(struct inode * parent, int extent)
+{
+ unsigned long bufsize = ISOFS_BUFFER_SIZE(parent);
+ unsigned char bufbits = ISOFS_BUFFER_BITS(parent);
unsigned int block,offset;
int parent_dir, inode_number;
int old_offset;
@@ -504,105 +509,110 @@ int isofs_lookup_grandparent(struct inode * parent, int extent) {
struct iso_directory_record * de;
offset = 0;
- block = extent << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(parent));
- if (!(bh = bread(parent->i_dev, block, ISOFS_BUFFER_SIZE(parent)))) return 0;
+ block = extent << (ISOFS_BLOCK_BITS - bufbits);
+ if (!(bh = bread(parent->i_dev, block, bufsize))) return -1;
while (1 == 1) {
- de = (struct iso_directory_record *) (offset + bh->b_data);
-
- if (*((char*) de) == 0)
- {
- brelse(bh);
- return -1;
- }
-
- offset += *((unsigned char*) de);
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ if (*((unsigned char *) de) == 0)
+ {
+ brelse(bh);
+ return -1;
+ }
- if (offset >= ISOFS_BUFFER_SIZE(parent))
- {
- printk(".. Directory not in first block of directory.\n");
- brelse(bh);
- return -1;
- }
+ offset += *((unsigned char *) de);
+
+ if (offset >= bufsize)
+ {
+ printk(".. Directory not in first block"
+ " of directory.\n");
+ brelse(bh);
+ return -1;
+ }
if (de->name_len[0] == 1 && de->name[0] == 1)
- {
- parent_dir = find_rock_ridge_relocation(de, parent);
- brelse(bh);
- break;
- };
+ {
+ parent_dir = find_rock_ridge_relocation(de, parent);
+ brelse(bh);
+ break;
+ }
}
#ifdef DEBUG
printk("Parent dir:%x\n",parent_dir);
#endif
/* Now we know the extent where the parent dir starts on. We have no
- idea how long it is, so we just start reading until we either find it
- or we find some kind of unreasonable circumstance. */
+ idea how long it is, so we just start reading until we either find
+ it or we find some kind of unreasonable circumstance. */
result = -1;
-
+
offset = 0;
- block = parent_dir << (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(parent));
- if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
- return 0;
+ block = parent_dir << (ISOFS_BLOCK_BITS - bufbits);
+ if (!block || !(bh = bread(parent->i_dev,block, bufsize)))
+ return -1;
- while (1==1) {
- de = (struct iso_directory_record *) (offset + bh->b_data);
- inode_number = (block << ISOFS_BUFFER_BITS(parent))+(offset & (ISOFS_BUFFER_SIZE(parent) - 1));
-
- /* If the length byte is zero, we should move on to the next CDROM sector.
- If we are at the end of the directory, we kick out of the while loop. */
+ for(;;)
+ {
+ de = (struct iso_directory_record *) (bh->b_data + offset);
+ inode_number = (block << bufbits)+(offset & (bufsize - 1));
- if (*((char*) de) == 0)
- {
- brelse(bh);
- offset = 0;
- block++;
- if(block & 1) return -1;
- if (!block || !(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
- return -1;
- continue;
- }
+ /* If the length byte is zero, we should move on to the next
+ CDROM sector. If we are at the end of the directory, we
+ kick out of the while loop. */
- /* Make sure that the entire directory record is in the current bh block.
- If not, we malloc a buffer, and put the two halves together, so that
- we can cleanly read the block */
+ if (*((unsigned char *) de) == 0)
+ {
+ brelse(bh);
+ offset = 0;
+ block++;
+ if(block & 1) return -1;
+ if (!block
+ || !(bh = bread(parent->i_dev,block, bufsize)))
+ return -1;
+ continue;
+ }
+ /* Make sure that the entire directory record is in the current
+ bh block. If not, we malloc a buffer, and put the two
+ halves together, so that we can cleanly read the block. */
+
old_offset = offset;
- offset += *((unsigned char*) de);
-
- if (offset >= ISOFS_BUFFER_SIZE(parent))
- {
- cpnt = kmalloc(1<<ISOFS_BLOCK_BITS,GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(parent));
- de = (struct iso_directory_record *) (old_offset + cpnt);
- brelse(bh);
- offset -= ISOFS_BUFFER_SIZE(parent);
- block++;
- if((block & 1) == 0) return -1;
- if (!(bh = bread(parent->i_dev,block, ISOFS_BUFFER_SIZE(parent))))
- return -1;
- memcpy(cpnt+ISOFS_BUFFER_SIZE(parent), bh->b_data, ISOFS_BUFFER_SIZE(parent));
- }
+ offset += *((unsigned char *) de);
+
+ if (offset >= bufsize)
+ {
+ cpnt = kmalloc(1<<ISOFS_BLOCK_BITS,GFP_KERNEL);
+ memcpy(cpnt, bh->b_data, bufsize);
+ de = (struct iso_directory_record *)
+ ((char *)cpnt + old_offset);
+ brelse(bh);
+ offset -= bufsize;
+ block++;
+ if((block & 1) == 0) return -1;
+ if (!(bh = bread(parent->i_dev,block,bufsize)))
+ return -1;
+ memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
+ }
if (find_rock_ridge_relocation(de, parent) == extent){
result = inode_number;
goto out;
- };
+ }
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
cpnt = NULL;
- };
+ }
}
- /* We go here for any condition we cannot handle. We also drop through
- to here at the end of the directory. */
-
+
+ /* We go here for any condition we cannot handle.
+ We also drop through to here at the end of the directory. */
+
out:
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
cpnt = NULL;
- };
+ }
brelse(bh);
#ifdef DEBUG
printk("Resultant Inode %d\n",result);
diff --git a/fs/isofs/namei.c b/fs/isofs/namei.c
index ca00791..24fd8c9 100644
--- a/fs/isofs/namei.c
+++ b/fs/isofs/namei.c
@@ -13,6 +13,7 @@
#include <linux/stat.h>
#include <linux/fcntl.h>
#include <asm/segment.h>
+#include <linux/malloc.h>
#include <linux/errno.h>
@@ -64,7 +65,9 @@ static int isofs_match(int len,const char * name, char * compare, int dlen)
static struct buffer_head * isofs_find_entry(struct inode * dir,
const char * name, int namelen, int * ino, int * ino_back)
{
- unsigned int block,i, f_pos, offset, inode_number;
+ unsigned long bufsize = ISOFS_BUFFER_SIZE(dir);
+ unsigned char bufbits = ISOFS_BUFFER_BITS(dir);
+ unsigned int block, i, f_pos, offset, inode_number;
struct buffer_head * bh;
void * cpnt = NULL;
unsigned int old_offset;
@@ -80,47 +83,48 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
if (!(block = dir->u.isofs_i.i_first_extent)) return NULL;
f_pos = 0;
-
- offset = f_pos & (ISOFS_BUFFER_SIZE(dir) - 1);
- block = isofs_bmap(dir,f_pos >> ISOFS_BUFFER_BITS(dir));
- if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE(dir)))) return NULL;
+ offset = f_pos & (bufsize - 1);
+ block = isofs_bmap(dir,f_pos >> bufbits);
+
+ if (!block || !(bh = bread(dir->i_dev,block,bufsize))) return NULL;
while (f_pos < dir->i_size) {
- de = (struct iso_directory_record *) (offset + bh->b_data);
+ de = (struct iso_directory_record *) (bh->b_data + offset);
backlink = dir->i_ino;
- inode_number = (block << ISOFS_BUFFER_BITS(dir))+(offset & (ISOFS_BUFFER_SIZE(dir) - 1));
-
+ inode_number = (block << bufbits) + (offset & (bufsize - 1));
+
/* If byte is zero, this is the end of file, or time to move to
the next sector. Usually 2048 byte boundaries. */
- if (*((unsigned char*) de) == 0) {
+ if (*((unsigned char *) de) == 0) {
brelse(bh);
offset = 0;
- f_pos =(f_pos & ~(ISOFS_BLOCK_SIZE - 1))+ISOFS_BLOCK_SIZE;
- block = isofs_bmap(dir,(f_pos)>>ISOFS_BUFFER_BITS(dir));
- if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE(dir))))
+ f_pos = ((f_pos & ~(ISOFS_BLOCK_SIZE - 1))
+ + ISOFS_BLOCK_SIZE);
+ block = isofs_bmap(dir,f_pos>>bufbits);
+ if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
return 0;
continue; /* Will kick out if past end of directory */
- };
-
+ }
+
old_offset = offset;
- offset += *((unsigned char*) de);
- f_pos += *((unsigned char*) de);
-
-
- /* Handle case where the directory entry spans two blocks. Usually
- 1024 byte boundaries */
- if (offset >= ISOFS_BUFFER_SIZE(dir)) {
+ offset += *((unsigned char *) de);
+ f_pos += *((unsigned char *) de);
+
+ /* Handle case where the directory entry spans two blocks.
+ Usually 1024 byte boundaries */
+ if (offset >= bufsize) {
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(dir));
- de = (struct iso_directory_record *) (old_offset + cpnt);
+ memcpy(cpnt, bh->b_data, bufsize);
+ de = (struct iso_directory_record *)
+ ((char *)cpnt + old_offset);
brelse(bh);
- offset = f_pos & (ISOFS_BUFFER_SIZE(dir) - 1);
- block = isofs_bmap(dir,f_pos>>ISOFS_BUFFER_BITS(dir));
- if (!block || !(bh = bread(dir->i_dev,block,ISOFS_BUFFER_SIZE(dir))))
+ offset = f_pos & (bufsize - 1);
+ block = isofs_bmap(dir,f_pos>>bufbits);
+ if (!block || !(bh = bread(dir->i_dev,block,bufsize)))
return 0;
- memcpy(cpnt+ISOFS_BUFFER_SIZE(dir), bh->b_data, ISOFS_BUFFER_SIZE(dir));
+ memcpy((char *)cpnt+bufsize,bh->b_data,bufsize);
}
/* Handle the '.' case */
@@ -134,9 +138,12 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
if (de->name[0]==1 && de->name_len[0]==1) {
#if 0
- printk("Doing .. (%d %d)",dir->i_sb->s_firstdatazone << ISOFS_BUFFER_BITS(dir), dir->i_ino);
+ printk("Doing .. (%d %d)",
+ dir->i_sb->s_firstdatazone << bufbits,
+ dir->i_ino);
#endif
- if((dir->i_sb->u.isofs_sb.s_firstdatazone << ISOFS_BUFFER_BITS(dir)) != dir->i_ino)
+ if((dir->i_sb->u.isofs_sb.s_firstdatazone
+ << bufbits) != dir->i_ino)
inode_number = dir->u.isofs_i.i_backlink;
else
inode_number = dir->i_ino;
@@ -152,21 +159,22 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
} else {
if(dir->i_sb->u.isofs_sb.s_mapping == 'n') {
for (i = 0; i < dlen; i++) {
- c = dpnt[i];
- if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
- if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
- dlen -= 2;
- break;
- };
- if (c == ';') c = '.';
- de->name[i] = c;
- };
- /* This allows us to match with and without a trailing period */
- if(dpnt[dlen-1] == '.' && namelen == dlen-1)
- dlen--;
- };
- };
- match = isofs_match(namelen,name,dpnt, dlen);
+ c = dpnt[i];
+ if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */
+ if (c == ';' && i == dlen-2 && dpnt[i+1] == '1') {
+ dlen -= 2;
+ break;
+ }
+ if (c == ';') c = '.';
+ de->name[i] = c;
+ }
+ /* This allows us to match with and without a trailing
+ period. */
+ if(dpnt[dlen-1] == '.' && namelen == dlen-1)
+ dlen--;
+ }
+ }
+ match = isofs_match(namelen,name,dpnt,dlen);
if (cpnt) {
kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
cpnt = NULL;
@@ -174,22 +182,25 @@ static struct buffer_head * isofs_find_entry(struct inode * dir,
if(rrflag) kfree(dpnt);
if (match) {
- if(inode_number == -1) { /* Should only happen for the '..' entry */
+ if(inode_number == -1) {
+ /* Should only happen for the '..' entry */
inode_number =
isofs_lookup_grandparent(dir,
- find_rock_ridge_relocation(de,dir));
- if(inode_number == -1){ /* Should never happen */
+ find_rock_ridge_relocation(de,dir));
+ if(inode_number == -1){
+ /* Should never happen */
printk("Backlink not properly set.\n");
goto out;
- };
- };
+ }
+ }
*ino = inode_number;
*ino_back = backlink;
return bh;
- }
+ }
}
out:
- if (cpnt) kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
+ if (cpnt)
+ kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS);
brelse(bh);
return NULL;
}
@@ -243,10 +254,15 @@ int isofs_lookup(struct inode * dir,const char * name, int len,
return -EACCES;
}
- /* We need this backlink for the .. entry */
+ /* We need this backlink for the ".." entry unless the name that we
+ are looking up traversed a mount point (in which case the inode
+ may not even be on an iso9660 filesystem, and writing to
+ u.isofs_i would only cause memory corruption).
+ */
- if (ino_back && !(*result)->i_pipe)
+ if (ino_back && !(*result)->i_pipe && (*result)->i_sb == dir->i_sb) {
(*result)->u.isofs_i.i_backlink = ino_back;
+ }
iput(dir);
return 0;
diff --git a/fs/isofs/rock.c b/fs/isofs/rock.c
index 29932c4..c2aeb26 100644
--- a/fs/isofs/rock.c
+++ b/fs/isofs/rock.c
@@ -11,6 +11,7 @@
#include <linux/iso_fs.h>
#include <linux/string.h>
#include <linux/mm.h>
+#include <linux/malloc.h>
#include "rock.h"
@@ -249,6 +250,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
int cnt, sig;
struct inode * reloc;
struct rock_ridge * rr;
+ int rootflag;
while (len > 1){ /* There may be one byte for padding somewhere */
rr = (struct rock_ridge *) chr;
@@ -300,6 +302,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
slen = rr->len - 5;
slp = &rr->u.SL.link;
while (slen > 1){
+ rootflag = 0;
switch(slp->flags &~1){
case 0:
inode->i_size += slp->len;
@@ -311,6 +314,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
inode->i_size += 2;
break;
case 8:
+ rootflag = 1;
inode->i_size += 1;
break;
default:
@@ -320,7 +324,7 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
if(slen < 2) break;
- inode->i_size += 1;
+ if(!rootflag) inode->i_size += 1;
};
};
break;
@@ -363,6 +367,8 @@ int parse_rock_ridge_inode(struct iso_directory_record * de,
char * get_rock_ridge_symlink(struct inode * inode)
{
+ unsigned long bufsize = ISOFS_BUFFER_SIZE(inode);
+ unsigned char bufbits = ISOFS_BUFFER_BITS(inode);
struct buffer_head * bh;
unsigned char * pnt;
void * cpnt = NULL;
@@ -371,6 +377,7 @@ char * get_rock_ridge_symlink(struct inode * inode)
CONTINUE_DECLS;
int block;
int sig;
+ int rootflag;
int len;
unsigned char * chr;
struct rock_ridge * rr;
@@ -380,22 +387,22 @@ char * get_rock_ridge_symlink(struct inode * inode)
rpnt = 0;
- block = inode->i_ino >> ISOFS_BUFFER_BITS(inode);
- if (!(bh=bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode))))
+ block = inode->i_ino >> bufbits;
+ if (!(bh=bread(inode->i_dev,block, bufsize)))
panic("unable to read i-node block");
- pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
+ pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1));
raw_inode = ((struct iso_directory_record *) pnt);
- if ((inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1)) + *pnt > ISOFS_BUFFER_SIZE(inode)){
+ if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){
cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL);
- memcpy(cpnt, bh->b_data, ISOFS_BUFFER_SIZE(inode));
+ memcpy(cpnt, bh->b_data, bufsize);
brelse(bh);
- if (!(bh = bread(inode->i_dev,++block, ISOFS_BUFFER_SIZE(inode))))
+ if (!(bh = bread(inode->i_dev,++block, bufsize)))
panic("unable to read i-node block");
- memcpy(cpnt+ISOFS_BUFFER_SIZE(inode), bh->b_data, ISOFS_BUFFER_SIZE(inode));
- pnt = ((unsigned char *) cpnt) + (inode->i_ino & (ISOFS_BUFFER_SIZE(inode) - 1));
+ memcpy((char *)cpnt+bufsize, bh->b_data, bufsize);
+ pnt = ((unsigned char *) cpnt) + (inode->i_ino & (bufsize - 1));
raw_inode = ((struct iso_directory_record *) pnt);
};
@@ -430,6 +437,7 @@ char * get_rock_ridge_symlink(struct inode * inode)
rpnt = (char *) kmalloc (inode->i_size +1, GFP_KERNEL);
*rpnt = 0;
};
+ rootflag = 0;
switch(slp->flags &~1){
case 0:
strncat(rpnt,slp->text, slp->len);
@@ -441,7 +449,8 @@ char * get_rock_ridge_symlink(struct inode * inode)
strcat(rpnt,"..");
break;
case 8:
- strcpy(rpnt,"/");
+ rootflag = 1;
+ strcat(rpnt,"/");
break;
default:
printk("Symlink component flag not implemented (%d)\n",slen);
@@ -450,7 +459,7 @@ char * get_rock_ridge_symlink(struct inode * inode)
slp = (struct SL_component *) (((char *) slp) + slp->len + 2);
if(slen < 2) break;
- strcat(rpnt,"/");
+ if(!rootflag) strcat(rpnt,"/");
};
break;
default:
diff --git a/fs/isofs/symlink.c b/fs/isofs/symlink.c
index 03adf92..7b25a8f 100644
--- a/fs/isofs/symlink.c
+++ b/fs/isofs/symlink.c
@@ -16,6 +16,7 @@
#include <linux/fs.h>
#include <linux/iso_fs.h>
#include <linux/stat.h>
+#include <linux/malloc.h>
static int isofs_readlink(struct inode *, char *, int);
static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **);
diff --git a/fs/isofs/util.c b/fs/isofs/util.c
index 9778393..141891d 100644
--- a/fs/isofs/util.c
+++ b/fs/isofs/util.c
@@ -85,6 +85,10 @@ isonum_733 (char * p)
return (isonum_731 (p));
}
+/* We have to convert from a MM/DD/YY format to the unix ctime format. We have to
+ take into account leap years and all of that good stuff. Unfortunately, the kernel
+ does not have the information on hand to take into account daylight savings time,
+ so there will be cases (roughly half the time) where the dates are off by one hour. */
int iso_date(char * p, int flag)
{
int year, month, day, hour ,minute, second, tz;
@@ -105,7 +109,7 @@ int iso_date(char * p, int flag)
int monlen[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
days = year * 365;
if (year > 2)
- days += (year+2) / 4;
+ days += (year+1) / 4;
for (i = 1; i < month; i++)
days += monlen[i-1];
if (((year+2) % 4) == 0 && month > 2)
diff --git a/fs/minix/file.c b/fs/minix/file.c
index ebcba50..903318a 100644
--- a/fs/minix/file.c
+++ b/fs/minix/file.c
@@ -17,7 +17,7 @@
#include <linux/stat.h>
#include <linux/locks.h>
-#define NBUF 16
+#define NBUF 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
diff --git a/fs/minix/namei.c b/fs/minix/namei.c
index 05a573b..f7fd367 100644
--- a/fs/minix/namei.c
+++ b/fs/minix/namei.c
@@ -760,8 +760,13 @@ start_up:
/* ok, that's it */
old_de->inode = 0;
new_de->inode = old_inode->i_ino;
+ old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
+ old_dir->i_dirt = 1;
+ new_dir->i_ctime = new_dir->i_mtime = CURRENT_TIME;
+ new_dir->i_dirt = 1;
if (new_inode) {
new_inode->i_nlink--;
+ new_inode->i_ctime = CURRENT_TIME;
new_inode->i_dirt = 1;
}
old_bh->b_dirt = 1;
diff --git a/fs/namei.c b/fs/namei.c
index 66a53b1..70ae8a7 100644
--- a/fs/namei.c
+++ b/fs/namei.c
@@ -75,10 +75,7 @@ int permission(struct inode * inode,int mask)
{
int mode = inode->i_mode;
-/* special case: not even root can read/write a deleted file */
- if (inode->i_dev && !inode->i_nlink)
- return 0;
- else if (inode->i_op && inode->i_op->permission)
+ if (inode->i_op && inode->i_op->permission)
return inode->i_op->permission(inode, mask);
else if (current->euid == inode->i_uid)
mode >>= 6;
@@ -426,8 +423,17 @@ asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev)
int error;
char * tmp;
- if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !suser()))
+ if (S_ISDIR(mode) || (!S_ISFIFO(mode) && !suser()))
return -EPERM;
+ switch (mode & S_IFMT) {
+ case 0:
+ mode |= S_IFREG;
+ break;
+ case S_IFREG: case S_IFCHR: case S_IFBLK: case S_IFIFO:
+ break;
+ default:
+ return -EINVAL;
+ }
error = getname(filename,&tmp);
if (!error) {
error = do_mknod(tmp,mode,dev);
diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c
index f4e567d..d8aa881 100644
--- a/fs/nfs/dir.c
+++ b/fs/nfs/dir.c
@@ -13,6 +13,7 @@
#include <linux/fcntl.h>
#include <linux/string.h>
#include <linux/kernel.h>
+#include <linux/malloc.h>
#include <linux/mm.h>
#include <asm/segment.h> /* for fs functions */
diff --git a/fs/nfs/file.c b/fs/nfs/file.c
index a77d0e4..b6a269f 100644
--- a/fs/nfs/file.c
+++ b/fs/nfs/file.c
@@ -16,9 +16,11 @@
#include <linux/stat.h>
#include <linux/mm.h>
#include <linux/nfs_fs.h>
+#include <linux/malloc.h>
static int nfs_file_read(struct inode *, struct file *, char *, int);
static int nfs_file_write(struct inode *, struct file *, char *, int);
+static int nfs_fsync(struct inode *, struct file *);
extern int nfs_mmap(struct inode * inode, struct file * file,
unsigned long addr, size_t len, int prot, unsigned long off);
@@ -32,7 +34,7 @@ static struct file_operations nfs_file_operations = {
nfs_mmap, /* mmap */
NULL, /* no special open is needed */
NULL, /* release */
- NULL /* fsync */
+ nfs_fsync, /* fsync */
};
struct inode_operations nfs_file_inode_operations = {
@@ -52,6 +54,11 @@ struct inode_operations nfs_file_inode_operations = {
NULL /* truncate */
};
+static int nfs_fsync(struct inode *inode, struct file *file)
+{
+ return 0;
+}
+
static int nfs_file_read(struct inode *inode, struct file *file, char *buf,
int count)
{
diff --git a/fs/nfs/mmap.c b/fs/nfs/mmap.c
index 22f660c..2ae370c 100644
--- a/fs/nfs/mmap.c
+++ b/fs/nfs/mmap.c
@@ -17,9 +17,11 @@
#include <linux/errno.h>
#include <linux/mman.h>
#include <linux/string.h>
+#include <linux/malloc.h>
+#include <linux/nfs_fs.h>
+
#include <asm/segment.h>
#include <asm/system.h>
-#include <linux/nfs_fs.h>
extern int share_page(struct vm_area_struct * area, struct task_struct * tsk,
struct inode * inode, unsigned long address, unsigned long error_code,
@@ -41,6 +43,7 @@ struct vm_operations_struct nfs_file_mmap = {
nfs_file_mmap_nopage, /* nopage */
NULL, /* wppage */
file_mmap_share, /* share */
+ NULL, /* unmap */
};
@@ -75,8 +78,8 @@ int nfs_mmap(struct inode * inode, struct file * file,
inode->i_count++;
mpnt->vm_offset = off;
mpnt->vm_ops = &nfs_file_mmap;
- mpnt->vm_next = current->mmap;
- current->mmap = mpnt;
+ insert_vm_struct(current, mpnt);
+ merge_segments(current->mmap, NULL, NULL);
return 0;
}
diff --git a/fs/nfs/proc.c b/fs/nfs/proc.c
index a9f699c..4bb519d 100644
--- a/fs/nfs/proc.c
+++ b/fs/nfs/proc.c
@@ -689,6 +689,7 @@ static struct {
{ NFSERR_NODEV, ENODEV },
{ NFSERR_NOTDIR, ENOTDIR },
{ NFSERR_ISDIR, EISDIR },
+ { NFSERR_INVAL, EINVAL },
{ NFSERR_FBIG, EFBIG },
{ NFSERR_NOSPC, ENOSPC },
{ NFSERR_ROFS, EROFS },
diff --git a/fs/nfs/sock.c b/fs/nfs/sock.c
index ec64064..323aa88 100644
--- a/fs/nfs/sock.c
+++ b/fs/nfs/sock.c
@@ -1,7 +1,7 @@
/*
* linux/fs/nfs/sock.c
*
- * Copyright (C) 1992 Rick Sladkey
+ * Copyright (C) 1992, 1993 Rick Sladkey
*
* low-level nfs remote procedure call interface
*/
@@ -19,6 +19,8 @@
extern struct socket *socki_lookup(struct inode *inode);
+#define _S(nr) (1<<((nr)-1))
+
/*
* We violate some modularity principles here by poking around
* in some socket internals. Besides having to call socket
@@ -48,6 +50,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
char *server_name;
int n;
int addrlen;
+ unsigned long old_mask;
xid = start[0];
len = ((char *) end) - ((char *) start);
@@ -55,15 +58,26 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
inode = file->f_inode;
select = file->f_op->select;
sock = socki_lookup(inode);
+ if (!sock) {
+ printk("nfs_rpc_call: socki_lookup failed\n");
+ return -EBADF;
+ }
init_timeout = server->timeo;
max_timeout = NFS_MAX_RPC_TIMEOUT*HZ/10;
retrans = server->retrans;
major_timeout_seen = 0;
server_name = server->hostname;
- if (!sock) {
- printk("nfs_rpc_call: socki_lookup failed\n");
- return -EBADF;
- }
+ old_mask = current->blocked;
+ current->blocked |= ~(_S(SIGKILL)
+#if 0
+ | _S(SIGSTOP)
+#endif
+ | ((server->flags & NFS_MOUNT_INTR)
+ ? ((current->sigaction[SIGINT - 1].sa_handler == SIG_DFL
+ ? _S(SIGINT) : 0)
+ | (current->sigaction[SIGQUIT - 1].sa_handler == SIG_DFL
+ ? _S(SIGQUIT) : 0))
+ : 0));
fs = get_fs();
set_fs(get_ds());
for (n = 0, timeout = init_timeout; ; n++, timeout <<= 1) {
@@ -85,11 +99,6 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
remove_wait_queue(entry.wait_address, &entry.wait);
current->state = TASK_RUNNING;
if (current->signal & ~current->blocked) {
-#if 0
- /* doesn't work yet */
- if (!(server->flags & NFS_MOUNT_INTR))
- goto re_select;
-#endif
current->timeout = 0;
result = -ERESTARTSYS;
break;
@@ -124,10 +133,10 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
NULL, &addrlen);
if (result < 0) {
if (result == -EAGAIN) {
- goto re_select;
#if 0
printk("nfs_rpc_call: bad select ready\n");
#endif
+ goto re_select;
}
if (result != -ERESTARTSYS) {
printk("nfs_rpc_call: recv error = %d\n",
@@ -144,6 +153,7 @@ static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end)
printk("nfs_rpc_call: XID mismatch\n");
#endif
}
+ current->blocked = old_mask;
set_fs(fs);
return result;
}
diff --git a/fs/nfs/symlink.c b/fs/nfs/symlink.c
index 29b7b8e..b4984ad 100644
--- a/fs/nfs/symlink.c
+++ b/fs/nfs/symlink.c
@@ -13,6 +13,7 @@
#include <linux/nfs_fs.h>
#include <linux/stat.h>
#include <linux/mm.h>
+#include <linux/malloc.h>
static int nfs_readlink(struct inode *, char *, int);
static int nfs_follow_link(struct inode *, struct inode *, int, int,
diff --git a/fs/pipe.c b/fs/pipe.c
index 351684d..f8289ea 100644
--- a/fs/pipe.c
+++ b/fs/pipe.c
@@ -146,6 +146,32 @@ static int pipe_select(struct inode * inode, struct file * filp, int sel_type, s
}
/*
+ * Arggh. Why does SunOS have to have different select() behaviour
+ * for pipes and fifos? Hate-Hate-Hate. See difference in SEL_IN..
+ */
+static int fifo_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait)
+{
+ switch (sel_type) {
+ case SEL_IN:
+ if (!PIPE_EMPTY(*inode))
+ return 1;
+ select_wait(&PIPE_READ_WAIT(*inode), wait);
+ return 0;
+ case SEL_OUT:
+ if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode))
+ return 1;
+ select_wait(&PIPE_WRITE_WAIT(*inode), wait);
+ return 0;
+ case SEL_EX:
+ if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode))
+ return 1;
+ select_wait(&inode->i_wait,wait);
+ return 0;
+ }
+ return 0;
+}
+
+/*
* The 'connect_xxx()' functions are needed for named pipes when
* the open() code hasn't guaranteed a connection (O_NONBLOCK),
* and we need to act differently until we do get a writer..
@@ -162,7 +188,7 @@ static int connect_read(struct inode * inode, struct file * filp, char * buf, in
return -ERESTARTSYS;
interruptible_sleep_on(& PIPE_READ_WAIT(*inode));
}
- filp->f_op = &read_pipe_fops;
+ filp->f_op = &read_fifo_fops;
return pipe_read(inode,filp,buf,count);
}
@@ -171,7 +197,7 @@ static int connect_select(struct inode * inode, struct file * filp, int sel_type
switch (sel_type) {
case SEL_IN:
if (!PIPE_EMPTY(*inode)) {
- filp->f_op = &read_pipe_fops;
+ filp->f_op = &read_fifo_fops;
return 1;
}
select_wait(&PIPE_READ_WAIT(*inode), wait);
@@ -218,7 +244,7 @@ static void pipe_rdwr_release(struct inode * inode, struct file * filp)
* The file_operations structs are not static because they
* are also used in linux/fs/fifo.c to do operations on fifo's.
*/
-struct file_operations connecting_pipe_fops = {
+struct file_operations connecting_fifo_fops = {
pipe_lseek,
connect_read,
bad_pipe_rw,
@@ -231,6 +257,45 @@ struct file_operations connecting_pipe_fops = {
NULL
};
+struct file_operations read_fifo_fops = {
+ pipe_lseek,
+ pipe_read,
+ bad_pipe_rw,
+ pipe_readdir,
+ fifo_select,
+ pipe_ioctl,
+ NULL, /* no mmap on pipes.. surprise */
+ NULL, /* no special open code */
+ pipe_read_release,
+ NULL
+};
+
+struct file_operations write_fifo_fops = {
+ pipe_lseek,
+ bad_pipe_rw,
+ pipe_write,
+ pipe_readdir,
+ fifo_select,
+ pipe_ioctl,
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ pipe_write_release,
+ NULL
+};
+
+struct file_operations rdwr_fifo_fops = {
+ pipe_lseek,
+ pipe_read,
+ pipe_write,
+ pipe_readdir,
+ fifo_select,
+ pipe_ioctl,
+ NULL, /* mmap */
+ NULL, /* no special open code */
+ pipe_rdwr_release,
+ NULL
+};
+
struct file_operations read_pipe_fops = {
pipe_lseek,
pipe_read,
diff --git a/fs/proc/array.c b/fs/proc/array.c
index ba8f8c1..017bcf7 100644
--- a/fs/proc/array.c
+++ b/fs/proc/array.c
@@ -12,6 +12,10 @@
#include <linux/sched.h>
#include <linux/kernel.h>
#include <linux/tty.h>
+#include <linux/user.h>
+#include <linux/a.out.h>
+#include <linux/string.h>
+#include <linux/mman.h>
#include <asm/segment.h>
#include <asm/io.h>
@@ -23,6 +27,51 @@
int get_malloc(char * buffer);
#endif
+static int read_core(struct inode * inode, struct file * file,char * buf, int count)
+{
+ unsigned long p = file->f_pos;
+ int read;
+ int count1;
+ char * pnt;
+ struct user dump;
+
+ memset(&dump, 0, sizeof(struct user));
+ dump.magic = CMAGIC;
+ dump.u_dsize = high_memory >> 12;
+
+ if (count < 0)
+ return -EINVAL;
+ if (p >= high_memory)
+ return 0;
+ if (count > high_memory - p)
+ count = high_memory - p;
+ read = 0;
+
+ if (p < sizeof(struct user) && count > 0) {
+ count1 = count;
+ if (p + count1 > sizeof(struct user))
+ count1 = sizeof(struct user)-p;
+ pnt = (char *) &dump + p;
+ memcpy_tofs(buf,(void *) pnt, count1);
+ buf += count1;
+ p += count1;
+ count -= count1;
+ read += count1;
+ }
+
+ while (p < 2*PAGE_SIZE && count > 0) {
+ put_fs_byte(0,buf);
+ buf++;
+ p++;
+ count--;
+ read++;
+ }
+ memcpy_tofs(buf,(void *) (p - PAGE_SIZE),count);
+ read += count;
+ file->f_pos += read;
+ return read;
+}
+
static int get_loadavg(char * buffer)
{
int a, b, c;
@@ -41,7 +90,7 @@ static int get_uptime(char * buffer)
unsigned long uptime;
unsigned long idle;
- uptime = jiffies + jiffies_offset;
+ uptime = jiffies;
idle = task[0]->utime + task[0]->stime;
return sprintf(buffer,"%d.%02d %d.%02d\n",
uptime / HZ,
@@ -300,6 +349,70 @@ static int get_statm(int pid, char * buffer)
size, resident, share, trs, lrs, drs, dt);
}
+static int get_maps(int pid, char *buf)
+{
+ int sz = 0;
+ struct task_struct **p = get_task(pid);
+ struct vm_area_struct *map;
+
+ if (!p || !*p)
+ return 0;
+
+ for(map = (*p)->mmap; map != NULL; map = map->vm_next) {
+ char str[7], *cp = str;
+ int prot = map->vm_page_prot;
+ int perms, flags;
+ int end = sz + 80; /* Length of line */
+ dev_t dev;
+ unsigned long ino;
+
+ /*
+ * This tries to get an "rwxsp" string out of silly
+ * intel page permissions. The vm_area_struct should
+ * probably have the original mmap args preserved.
+ */
+
+ flags = perms = 0;
+
+ if ((prot & PAGE_READONLY) == PAGE_READONLY)
+ perms |= PROT_READ | PROT_EXEC;
+ if (prot & (PAGE_COW|PAGE_RW)) {
+ perms |= PROT_WRITE | PROT_READ;
+ flags = prot & PAGE_COW ? MAP_PRIVATE : MAP_SHARED;
+ }
+
+ *cp++ = perms & PROT_READ ? 'r' : '-';
+ *cp++ = perms & PROT_WRITE ? 'w' : '-';
+ *cp++ = perms & PROT_EXEC ? 'x' : '-';
+ *cp++ = flags & MAP_SHARED ? 's' : '-';
+ *cp++ = flags & MAP_PRIVATE ? 'p' : '-';
+ *cp++ = 0;
+
+ if (end >= PAGE_SIZE) {
+ sprintf(buf+sz, "...\n");
+ break;
+ }
+
+ if (map->vm_inode != NULL) {
+ dev = map->vm_inode->i_dev;
+ ino = map->vm_inode->i_ino;
+ } else {
+ dev = 0;
+ ino = 0;
+ }
+
+ sz += sprintf(buf+sz, "%08x-%08x %s %08x %02x:%02x %d\n",
+ map->vm_start, map->vm_end, str, map->vm_offset,
+ MAJOR(dev),MINOR(dev), ino);
+ if (sz > end) {
+ printk("get_maps: end(%d) < sz(%d)\n", end, sz);
+ break;
+ }
+ }
+
+ return sz;
+}
+
static int array_read(struct inode * inode, struct file * file,char * buf, int count)
{
char * page;
@@ -344,6 +457,12 @@ static int array_read(struct inode * inode, struct file * file,char * buf, int c
length = get_malloc(page);
break;
#endif
+ case 14:
+ free_page((unsigned long) page);
+ return read_core(inode, file, buf, count);
+ case 15:
+ length = get_maps(pid, page);
+ break;
default:
free_page((unsigned long) page);
return -EBADF;
diff --git a/fs/proc/base.c b/fs/proc/base.c
index b6df88d..5209d22 100644
--- a/fs/proc/base.c
+++ b/fs/proc/base.c
@@ -62,7 +62,8 @@ static struct proc_dir_entry base_dir[] = {
{ 9,7,"environ" },
{ 10,7,"cmdline" },
{ 11,4,"stat" },
- { 12,5,"statm" }
+ { 12,5,"statm" },
+ { 15,4,"maps" }
};
#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0])))
diff --git a/fs/proc/inode.c b/fs/proc/inode.c
index 97cbe2a..4f102df 100644
--- a/fs/proc/inode.c
+++ b/fs/proc/inode.c
@@ -118,6 +118,11 @@ void proc_read_inode(struct inode * inode)
inode->i_nlink = 2;
inode->i_op = &proc_net_inode_operations;
break;
+ case 14:
+ inode->i_mode = S_IFREG | S_IRUSR;
+ inode->i_op = &proc_array_inode_operations;
+ inode->i_size = high_memory + PAGE_SIZE;
+ break;
default:
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_array_inode_operations;
@@ -155,6 +160,7 @@ void proc_read_inode(struct inode * inode)
case 10:
case 11:
case 12:
+ case 15:
inode->i_mode = S_IFREG | S_IRUGO;
inode->i_op = &proc_array_inode_operations;
return;
diff --git a/fs/proc/root.c b/fs/proc/root.c
index 691f5f9..0890d25 100644
--- a/fs/proc/root.c
+++ b/fs/proc/root.c
@@ -64,6 +64,7 @@ static struct proc_dir_entry root_dir[] = {
#ifdef CONFIG_DEBUG_MALLOC
{13,6,"malloc" },
#endif
+ {14,5,"kcore" },
};
#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0])))
diff --git a/fs/super.c b/fs/super.c
index cf30024..772bdd1 100644
--- a/fs/super.c
+++ b/fs/super.c
@@ -485,7 +485,7 @@ void mount_root(void)
memset(super_blocks, 0, sizeof(super_blocks));
fcntl_init_locks();
if (MAJOR(ROOT_DEV) == 2) {
- printk("VFS: Insert root floppy and press ENTER");
+ printk("VFS: Insert root floppy and press ENTER\n");
wait_for_keypress();
}
for (fs_type = file_systems; fs_type->read_super; fs_type++) {
diff --git a/fs/xiafs/file.c b/fs/xiafs/file.c
index ad09f12..44e9e24 100644
--- a/fs/xiafs/file.c
+++ b/fs/xiafs/file.c
@@ -23,7 +23,7 @@
#include "xiafs_mac.h"
-#define NBUF 16
+#define NBUF 32
#define MIN(a,b) (((a)<(b))?(a):(b))
#define MAX(a,b) (((a)>(b))?(a):(b))
diff --git a/include/asm/irq.h b/include/asm/irq.h
index 89dbe62..191a668 100644
--- a/include/asm/irq.h
+++ b/include/asm/irq.h
@@ -33,7 +33,9 @@ extern void enable_irq(unsigned int);
"mov %dx,%ds\n\t" \
"mov %dx,%es\n\t" \
"movl $" STR(USER_DS) ",%edx\n\t" \
- "mov %dx,%fs\n\t"
+ "mov %dx,%fs\n\t" \
+ "movl $0,%edx\n\t" \
+ "movl %edx,%db7\n"
/*
* SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers,
diff --git a/include/linux/debugreg.h b/include/linux/debugreg.h
new file mode 100644
index 0000000..ba93e10
--- /dev/null
+++ b/include/linux/debugreg.h
@@ -0,0 +1,61 @@
+#ifndef _LINUX_DEBUGREG_H
+#define _LINUX_DEBUGREG_H
+
+
+/* Indicate the register numbers for a number of the specific
+ debug registers. Registers 0-3 contain the addresses we wish to trap on */
+#define DR_FIRSTADDR 0 /* u_debugreg[DR_FIRSTADDR] */
+#define DR_LASTADDR 3 /* u_debugreg[DR_LASTADDR] */
+
+#define DR_STATUS 6 /* u_debugreg[DR_STATUS] */
+#define DR_CONTROL 7 /* u_debugreg[DR_CONTROL] */
+
+/* Define a few things for the status register. We can use this to determine
+ which debugging register was responsible for the trap. The other bits
+ are either reserved or not of interest to us. */
+
+#define DR_TRAP0 (0x1) /* Trap due to db0 */
+#define DR_TRAP1 (0x2) /* Trap due to db1 */
+#define DR_TRAP2 (0x4) /* Trap due to db2 */
+#define DR_TRAP3 (0x8) /* Trap due to db3 */
+
+/* Now define a bunch of things for manipulating the control register.
+ The top two bytes of the control register consist of 4 fields of 4
+ bytes - each field corresponds to one of the four debug registers,
+ and indicates what types of access we trap on, and how large the data
+ field is that we are looking at */
+
+#define DR_CONTROL_SHIFT 16 /* Skip this many bits in ctl register */
+#define DR_CONTROL_SIZE 4 /* 4 control bits per register */
+
+#define DR_RW_EXECUTE (0x0) /* Settings for the access types to trap on */
+#define DR_RW_WRITE (0x1)
+#define DR_RW_READ (0x3)
+
+#define DR_LEN_1 (0x0) /* Settings for data length to trap on */
+#define DR_LEN_2 (0x4)
+#define DR_LEN_4 (0xC)
+
+/* The low byte to the control register determine which registers are
+ enabled. There are 4 fields of two bits. One bit is "local", meaning
+ that the processor will reset the bit after a task switch and the other
+ is global meaning that we have to explicitly reset the bit. With linux,
+ you can use either one, since we explicitly zero the register when we enter
+ kernel mode. */
+
+#define DR_LOCAL_ENABLE_SHIFT 0 /* Extra shift to the local enable bit */
+#define DR_GLOBAL_ENABLE_SHIFT 1 /* Extra shift to the global enable bit */
+#define DR_ENABLE_SIZE 2 /* 2 enable bits per register */
+
+#define DR_LOCAL_ENABLE_MASK (0x55) /* Set local bits for all 4 regs */
+#define DR_GLOBAL_ENABLE_MASK (0xAA) /* Set global bits for all 4 regs */
+
+/* The second byte to the control register has a few special things.
+ We can slow the instruction pipeline for instructions coming via the
+ gdt or the ldt if we want to. I am not sure why this is an advantage */
+
+#define DR_CONTROL_RESERVED (0xFC00) /* Reserved by Intel */
+#define DR_LOCAL_SLOWDOWN (0x100) /* Local slow the pipeline */
+#define DR_GLOBAL_SLOWDOWN (0x200) /* Global slow the pipeline */
+
+#endif
diff --git a/include/linux/fs.h b/include/linux/fs.h
index b9f03a7..69d4784 100644
--- a/include/linux/fs.h
+++ b/include/linux/fs.h
@@ -54,6 +54,12 @@
* 13 -
* 14 - sound card (?)
* 15 -
+ * 16 -
+ * 17 -
+ * 18 -
+ * 19 -
+ * 20 -
+ * 21 - /dev/sg
*/
#define UNNAMED_MAJOR 0
@@ -131,6 +137,11 @@ extern unsigned long file_table_init(unsigned long start, unsigned long end);
#define SCSI_IOCTL_GET_IDLUN 0x5382
+/* Used to turn on and off tagged queueing for scsi devices */
+
+#define SCSI_IOCTL_TAGGED_ENABLE 0x5383
+#define SCSI_IOCTL_TAGGED_DISABLE 0x5384
+
#define BMAP_IOCTL 1 /* obsolete - kept for compatibility */
#define FIBMAP 1 /* bmap access */
@@ -339,7 +350,10 @@ extern struct inode_operations chrdev_inode_operations;
extern void init_fifo(struct inode * inode);
-extern struct file_operations connecting_pipe_fops;
+extern struct file_operations connecting_fifo_fops;
+extern struct file_operations read_fifo_fops;
+extern struct file_operations write_fifo_fops;
+extern struct file_operations rdwr_fifo_fops;
extern struct file_operations read_pipe_fops;
extern struct file_operations write_pipe_fops;
extern struct file_operations rdwr_pipe_fops;
@@ -354,7 +368,6 @@ extern struct file *first_file;
extern int nr_files;
extern struct super_block super_blocks[NR_SUPER];
-extern void grow_buffers(int size);
extern int shrink_buffers(unsigned int priority);
extern int nr_buffers;
diff --git a/include/linux/if.h b/include/linux/if.h
index 909bd02..5cbe651 100644
--- a/include/linux/if.h
+++ b/include/linux/if.h
@@ -101,8 +101,14 @@ struct ifaddr {
* remainder may be interface specific.
*/
struct ifreq {
+#define IFHWADDRLEN 6
#define IFNAMSIZ 16
- char ifr_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ union
+ {
+ char ifrn_name[IFNAMSIZ]; /* if name, e.g. "en0" */
+ char ifrn_hwaddr[IFHWADDRLEN];
+ } ifr_ifrn;
+
union {
struct sockaddr ifru_addr;
struct sockaddr ifru_dstaddr;
@@ -114,6 +120,9 @@ struct ifreq {
caddr_t ifru_data;
} ifr_ifru;
};
+
+#define ifr_name ifr_ifrn.ifrn_name /* interface name */
+#define ifr_hwaddr ifr_ifrn.ifrn_hwaddr /* interface hardware */
#define ifr_addr ifr_ifru.ifru_addr /* address */
#define ifr_dstaddr ifr_ifru.ifru_dstaddr /* other end of p-p lnk */
#define ifr_broadaddr ifr_ifru.ifru_broadaddr /* broadcast address */
diff --git a/include/linux/if_ether.h b/include/linux/if_ether.h
index 2efcfee..e8a3513 100644
--- a/include/linux/if_ether.h
+++ b/include/linux/if_ether.h
@@ -32,6 +32,7 @@
#define ETH_P_IP 0x0800 /* Internet Protocol packet */
#define ETH_P_ARP 0x0806 /* Address Resolution packet */
#define ETH_P_RARP 0x0835 /* Reverse Addr Res packet */
+#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */
/* Define the Ethernet Broadcast Address (48 bits set to "1"). */
#define ETH_A_BCAST "\377\377\377\377\377\377"
diff --git a/include/linux/kd.h b/include/linux/kd.h
index 2f8c740..5db5a5f 100644
--- a/include/linux/kd.h
+++ b/include/linux/kd.h
@@ -160,6 +160,7 @@ typedef char scrnmap_t;
#define K_RAW 0x00
#define K_XLATE 0x01
+#define K_MEDIUMRAW 0x02
#define KDGKBMODE 0x4B44 /* gets current keyboard mode */
#define KDSKBMODE 0x4B45 /* sets current keyboard mode */
diff --git a/include/linux/kernel.h b/include/linux/kernel.h
index 8d9eeb6..9bbb2f6 100644
--- a/include/linux/kernel.h
+++ b/include/linux/kernel.h
@@ -7,7 +7,6 @@
#ifdef __KERNEL__
-#include <linux/config.h>
#include <linux/linkage.h>
#define INT_MAX ((int)(~0U>>1))
@@ -20,6 +19,15 @@
int verify_area(int type, void * addr, unsigned long count);
+#define KERN_EMERG "<0>" /* system is unusable */
+#define KERN_ALERT "<1>" /* action must be taken immediately */
+#define KERN_CRIT "<2>" /* critical conditions */
+#define KERN_ERR "<3>" /* error conditions */
+#define KERN_WARNING "<4>" /* warning conditions */
+#define KERN_NOTICE "<5>" /* normal but significant condition */
+#define KERN_INFO "<6>" /* informational */
+#define KERN_DEBUG "<7>" /* debug-level messages */
+
extern void math_error(void);
volatile void panic(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
@@ -30,31 +38,6 @@ int sprintf(char * buf, const char * fmt, ...);
asmlinkage int printk(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
-#ifdef CONFIG_DEBUG_MALLOC
-#define kmalloc(a,b) deb_kmalloc(__FILE__,__LINE__, a,b)
-#define kfree_s(a,b) deb_kfree_s(__FILE__,__LINE__,a,b)
-
-void *deb_kmalloc(const char *deb_file, unsigned short deb_line,unsigned int size, int priority);
-void deb_kfree_s (const char *deb_file, unsigned short deb_line,void * obj, int size);
-void deb_kcheck_s(const char *deb_file, unsigned short deb_line,void * obj, int size);
-
-#define kfree(a) deb_kfree_s(__FILE__,__LINE__, a,0)
-#define kcheck(a) deb_kcheck_s(__FILE__,__LINE__, a,0)
-#define kcheck_s(a,b) deb_kcheck_s(__FILE__,__LINE__, a,b)
-
-#else /* !debug */
-
-void * kmalloc(unsigned int size, int priority);
-void kfree_s(void * obj, int size);
-
-#define kcheck_s(a,b) 0
-
-#define kfree(x) kfree_s((x), 0)
-#define kcheck(x) kcheck_s((x), 0)
-
-#endif
-
-
/*
* This is defined as a macro, but at some point this might become a
* real subroutine that sets a flag if it returns true (to do
diff --git a/include/linux/keyboard.h b/include/linux/keyboard.h
index 5151bd3..6fdaaae 100644
--- a/include/linux/keyboard.h
+++ b/include/linux/keyboard.h
@@ -5,19 +5,6 @@
#define set_leds() mark_bh(KEYBOARD_BH)
/*
- * "dead" keys - prefix key values that are valid only for the next
- * character code (sticky shift, E0/E1 special scancodes, diacriticals)
- */
-extern unsigned long kbd_dead_keys;
-extern unsigned long kbd_prev_dead_keys;
-
-/*
- * these are the hardcoded dead key flags
- */
-#define KGD_E0 0
-#define KGD_E1 1
-
-/*
* kbd->xxx contains the VC-local things (flag settings etc..)
* The low 3 local flags are hardcoded to be the led setting..
*/
@@ -42,31 +29,16 @@ extern struct kbd_struct kbd_table[];
#define VC_CRLF 8 /* 0 - enter sends CR, 1 - enter sends CRLF */
#define VC_META 9 /* 0 - meta, 1 - meta=prefix with ESC */
#define VC_PAUSE 10 /* pause key pressed */
+#define VC_MEDIUMRAW 11 /* medium raw (keycode) mode */
+#define VC_SHIFTLOCK 12 /* shift lock mode */
+#define VC_ALTGRLOCK 13 /* altgr lock mode */
+#define VC_CTRLLOCK 14 /* control lock mode */
+#define VC_ALTLOCK 15 /* alt lock mode */
#define LED_MASK 7
extern unsigned long kbd_init(unsigned long);
-extern inline int kbd_dead(int flag)
-{
- return kbd_prev_dead_keys & (1 << flag);
-}
-
-extern inline void set_kbd_dead(int flag)
-{
- kbd_dead_keys |= 1 << flag;
-}
-
-extern inline void clr_kbd_dead(int flag)
-{
- kbd_dead_keys &= ~(1 << flag);
-}
-
-extern inline void chg_kbd_dead(int flag)
-{
- kbd_dead_keys ^= 1 << flag;
-}
-
extern inline int vc_kbd_flag(struct kbd_struct * kbd, int flag)
{
return ((kbd->flags >> flag) & 1);
@@ -93,7 +65,7 @@ extern const int NR_TYPES;
extern const int max_vals[];
extern unsigned short key_map[NR_KEYMAPS][NR_KEYS];
-#define NR_FUNC 32
+#define NR_FUNC 35
#define FUNC_BUFSIZE 512
extern char func_buf[FUNC_BUFSIZE];
extern char *func_table[NR_FUNC];
@@ -108,6 +80,7 @@ extern char *func_table[NR_FUNC];
#define KT_SHIFT 7
#define KT_META 8
#define KT_ASCII 9
+#define KT_LOCK 10
#define K(t,v) (((t)<<8)|(v))
#define KTYP(x) ((x) >> 8)
@@ -139,6 +112,9 @@ extern char *func_table[NR_FUNC];
#define K_SELECT K(KT_FN,23)
#define K_PGUP K(KT_FN,24)
#define K_PGDN K(KT_FN,25)
+#define K_MACRO K(KT_FN,26)
+#define K_HELP K(KT_FN,27)
+#define K_DO K(KT_FN,28)
#define K_HOLE K(KT_SPEC,0)
#define K_ENTER K(KT_SPEC,1)
@@ -154,6 +130,7 @@ extern char *func_table[NR_FUNC];
#define K_SCROLLBACK K(KT_SPEC,11)
#define K_BOOT K(KT_SPEC,12)
#define K_CAPSON K(KT_SPEC,13)
+#define K_DEADNEXT K(KT_SPEC,14)
#define K_P0 K(KT_PAD,0)
#define K_P1 K(KT_PAD,1)
@@ -172,6 +149,7 @@ extern char *func_table[NR_FUNC];
#define K_PENTER K(KT_PAD,14) /* key-pad enter */
#define K_PCOMMA K(KT_PAD,15) /* key-pad comma: kludge... */
#define K_PDOT K(KT_PAD,16) /* key-pad dot (period): kludge... */
+#define K_PPLUSMINUS K(KT_PAD,17) /* key-pad plus/minus */
#define K_DGRAVE K(KT_DEAD,0)
#define K_DACUTE K(KT_DEAD,1)
@@ -194,7 +172,7 @@ extern char *func_table[NR_FUNC];
#define K_ALT K(KT_SHIFT,KG_ALT)
#define K_ALTGR K(KT_SHIFT,KG_ALTGR)
-#define NR_SHIFT 16
+#define NR_SHIFT 4
#define K_CAPSSHIFT K(KT_SHIFT,NR_SHIFT)
@@ -209,4 +187,9 @@ extern char *func_table[NR_FUNC];
#define K_ASC8 K(KT_ASCII,8)
#define K_ASC9 K(KT_ASCII,9)
+#define K_SHIFTLOCK K(KT_LOCK,0)
+#define K_CTRLLOCK K(KT_LOCK,2)
+#define K_ALTLOCK K(KT_LOCK,3)
+#define K_ALTGRLOCK K(KT_LOCK,1)
+
#endif
diff --git a/include/linux/malloc.h b/include/linux/malloc.h
new file mode 100644
index 0000000..b803b8b
--- /dev/null
+++ b/include/linux/malloc.h
@@ -0,0 +1,30 @@
+#ifndef _LINUX_MALLOC_H
+#define _LINUX_MALLOC_H
+
+#include <linux/config.h>
+
+#ifdef CONFIG_DEBUG_MALLOC
+#define kmalloc(a,b) deb_kmalloc(__FILE__,__LINE__,a,b)
+#define kfree_s(a,b) deb_kfree_s(__FILE__,__LINE__,a,b)
+
+void *deb_kmalloc(const char *deb_file, unsigned short deb_line,unsigned int size, int priority);
+void deb_kfree_s (const char *deb_file, unsigned short deb_line,void * obj, int size);
+void deb_kcheck_s(const char *deb_file, unsigned short deb_line,void * obj, int size);
+
+#define kfree(a) deb_kfree_s(__FILE__,__LINE__, a,0)
+#define kcheck(a) deb_kcheck_s(__FILE__,__LINE__, a,0)
+#define kcheck_s(a,b) deb_kcheck_s(__FILE__,__LINE__, a,b)
+
+#else /* !debug */
+
+void * kmalloc(unsigned int size, int priority);
+void kfree_s(void * obj, int size);
+
+#define kcheck_s(a,b) 0
+
+#define kfree(x) kfree_s((x), 0)
+#define kcheck(x) kcheck_s((x), 0)
+
+#endif
+
+#endif /* _LINUX_MALLOC_H */
diff --git a/include/linux/mc146818rtc.h b/include/linux/mc146818rtc.h
new file mode 100644
index 0000000..741aa2d
--- /dev/null
+++ b/include/linux/mc146818rtc.h
@@ -0,0 +1,104 @@
+/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM
+ * Copyright Torsten Duwe <duwe@informatik.uni-erlangen.de> 1993
+ * derived from Data Sheet, Copyright Motorola 1984 (!).
+ * It was written to be part of the Linux operating system.
+ */
+/* permission is hereby granted to copy, modify and redistribute this code
+ * in terms of the GNU Library General Public License, Version 2 or later,
+ * at your option.
+ */
+
+#ifndef _MC146818RTC_H
+#define _MC146818RTC_H
+#include <asm/io.h>
+
+#define CMOS_READ(addr) ({ \
+outb_p(addr|0x80,0x70); \
+inb_p(0x71); \
+})
+#define CMOS_WRITE(val, addr) ({ \
+outb_p(addr|0x80,0x70); \
+outb_p(val,0x71); \
+})
+
+/**********************************************************************
+ * register summary
+ **********************************************************************/
+#define RTC_SECONDS 0
+#define RTC_SECONDS_ALARM 1
+#define RTC_MINUTES 2
+#define RTC_MINUTES_ALARM 3
+#define RTC_HOURS 4
+#define RTC_HOURS_ALARM 5
+/* RTC_*_alarm is always true if 2 MSBs are set */
+# define RTC_ALARM_DONT_CARE 0xC0
+
+#define RTC_DAY_OF_WEEK 6
+#define RTC_DAY_OF_MONTH 7
+#define RTC_MONTH 8
+#define RTC_YEAR 9
+
+/* control registers - Moto names
+ */
+#define RTC_REG_A 10
+#define RTC_REG_B 11
+#define RTC_REG_C 12
+#define RTC_REG_D 13
+
+/**********************************************************************
+ * register details
+ **********************************************************************/
+#define RTC_FREQ_SELECT RTC_REG_A
+
+/* update-in-progress - set to "1" 244 microsecs before RTC goes off the bus,
+ * reset after update (may take 1.984ms @ 32768Hz RefClock) is complete,
+ * totalling to a max high interval of 2.228 ms.
+ */
+# define RTC_UIP 0x80
+# define RTC_DIV_CTL 0x70
+ /* divider control: refclock values 4.194 / 1.049 MHz / 32.768 kHz */
+# define RTC_REF_CLCK_4MHZ 0x00
+# define RTC_REF_CLCK_1MHZ 0x10
+# define RTC_REF_CLCK_32KHZ 0x20
+ /* 2 values for divider stage reset, others for "testing purposes only" */
+# define RTC_DIV_RESET1 0x60
+# define RTC_DIV_RESET2 0x70
+ /* Periodic intr. / Square wave rate select. 0=none, 1=32.8kHz,... 15=2Hz */
+# define RTC_RATE_SELECT 0x0F
+
+/**********************************************************************/
+#define RTC_CONTROL RTC_REG_B
+# define RTC_SET 0x80 /* disable updates for clock setting */
+# define RTC_PIE 0x40 /* periodic interrupt enable */
+# define RTC_AIE 0x20 /* alarm interrupt enable */
+# define RTC_UIE 0x10 /* update-finished interrupt enable */
+# define RTC_SQWE 0x08 /* enable square-wave output */
+# define RTC_DM_BINARY 0x04 /* all time/date values are BCD if clear */
+# define RTC_24H 0x02 /* 24 hour mode - else hours bit 7 means pm */
+# define RTC_DST_EN 0x01 /* auto switch DST - works f. USA only */
+
+/**********************************************************************/
+#define RTC_INTR_FLAGS RTC_REG_C
+/* caution - cleared by read */
+# define RTC_IRQF 0x80 /* any of the following 3 is active */
+# define RTC_PF 0x40
+# define RTC_AF 0x20
+# define RTC_UF 0x10
+
+/**********************************************************************/
+#define RTC_VALID RTC_REG_D
+# define RTC_VRT 0x80 /* valid RAM and time */
+/**********************************************************************/
+
+/* example: !(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY)
+ * determines if the following two #defines are needed
+ */
+#ifndef BCD_TO_BIN
+#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
+#endif
+
+#ifndef BIN_TO_BCD
+#define BIN_TO_BCD(val) ((val)=(((val)/10)<<4) + (val)%10)
+#endif
+
+#endif /* _MC146818RTC_H */
diff --git a/include/linux/mm.h b/include/linux/mm.h
index ff66453..875e106 100644
--- a/include/linux/mm.h
+++ b/include/linux/mm.h
@@ -45,6 +45,7 @@ struct vm_operations_struct {
struct vm_area_struct * area, unsigned long address);
void (*wppage)(struct vm_area_struct * area, unsigned long address);
int (*share)(struct vm_area_struct * from, struct vm_area_struct * to, unsigned long address);
+ int (*unmap)(struct vm_area_struct *area, unsigned long, size_t);
};
extern unsigned long __bad_page(void);
@@ -84,8 +85,6 @@ extern inline unsigned long get_free_page(int priority)
return page;
}
-/* mmap.c */
-
/* memory.c */
extern void free_page(unsigned long addr);
@@ -111,6 +110,11 @@ extern void show_mem(void);
extern void oom(struct task_struct * task);
extern void si_meminfo(struct sysinfo * val);
+/* vmalloc.c */
+
+extern void * vmalloc(unsigned long size);
+extern void vfree(void * addr);
+
/* swap.c */
extern void swap_free(unsigned long page_nr);
@@ -122,6 +126,13 @@ extern void rw_swap_page(int rw, unsigned long nr, char * buf);
/* mmap.c */
extern int do_mmap(struct file * file, unsigned long addr, unsigned long len,
unsigned long prot, unsigned long flags, unsigned long off);
+typedef int (*map_mergep_fnp)(const struct vm_area_struct *,
+ const struct vm_area_struct *, void *);
+extern void merge_segments(struct vm_area_struct *, map_mergep_fnp, void *);
+extern void insert_vm_struct(struct task_struct *, struct vm_area_struct *);
+extern int ignoff_mergep(const struct vm_area_struct *,
+ const struct vm_area_struct *, void *);
+extern int do_munmap(unsigned long, size_t);
#define read_swap_page(nr,buf) \
rw_swap_page(READ,(nr),(buf))
diff --git a/include/linux/nfs.h b/include/linux/nfs.h
index cc290ef..97f14f2 100644
--- a/include/linux/nfs.h
+++ b/include/linux/nfs.h
@@ -72,6 +72,7 @@ enum nfs_stat {
NFSERR_NODEV = 19,
NFSERR_NOTDIR = 20,
NFSERR_ISDIR = 21,
+ NFSERR_INVAL = 22, /* that Sun forgot */
NFSERR_FBIG = 27,
NFSERR_NOSPC = 28,
NFSERR_ROFS = 30,
diff --git a/include/linux/resource.h b/include/linux/resource.h
index 86c15c7..9d9bc16 100644
--- a/include/linux/resource.h
+++ b/include/linux/resource.h
@@ -54,7 +54,7 @@ struct rusage {
#define RLIM_NLIMITS 6
-#define RLIM_INFINITY LONG_MAX
+#define RLIM_INFINITY 0x7FFFFFFF
struct rlimit {
int rlim_cur;
diff --git a/include/linux/sched.h b/include/linux/sched.h
index 0ec8bed..3a943dd 100644
--- a/include/linux/sched.h
+++ b/include/linux/sched.h
@@ -83,7 +83,7 @@ extern unsigned long avenrun[]; /* Load averages */
extern void sched_init(void);
extern void show_state(void);
extern void trap_init(void);
-extern void panic(const char * fmt, ...)
+extern volatile void panic(const char * fmt, ...)
__attribute__ ((format (printf, 1, 2)));
asmlinkage void schedule(void);
@@ -147,6 +147,7 @@ struct tss_struct {
unsigned short trace, bitmap;
unsigned long io_bitmap[IO_BITMAP_SIZE+1];
unsigned long tr;
+ unsigned long cr2;
union i387_union i387;
};
@@ -159,6 +160,7 @@ struct task_struct {
unsigned long blocked; /* bitmap of masked signals */
unsigned long flags; /* per process flags, defined below */
int errno;
+ int debugreg[8]; /* Hardware debugging registers */
/* various fields */
struct task_struct *next_task, *prev_task;
struct sigaction sigaction[32];
@@ -220,6 +222,7 @@ struct task_struct {
short swap_table; /* current page table */
short swap_page; /* current page */
#endif NEW_SWAP
+ struct vm_area_struct *stk_vma;
};
/*
@@ -243,6 +246,7 @@ struct task_struct {
*/
#define INIT_TASK \
/* state etc */ { 0,15,15,0,0,0,0, \
+/* debugregs */ { 0, }, \
/* schedlink */ &init_task,&init_task, \
/* signals */ {{ 0, },}, \
/* stack */ 0,0, \
@@ -275,7 +279,7 @@ struct task_struct {
_LDT(0),0, \
0, 0x8000, \
/* ioperm */ {~0, }, \
- _TSS(0), \
+ _TSS(0), 0, \
/* 387 state */ { { 0, }, } \
} \
}
@@ -285,8 +289,7 @@ extern struct task_struct *task[NR_TASKS];
extern struct task_struct *last_task_used_math;
extern struct task_struct *current;
extern unsigned long volatile jiffies;
-extern unsigned long startup_time;
-extern int jiffies_offset;
+extern struct timeval xtime;
extern int need_resched;
extern int hard_math;
@@ -294,7 +297,7 @@ extern int x86;
extern int ignore_irq13;
extern int wp_works_ok;
-#define CURRENT_TIME (startup_time+(jiffies+jiffies_offset)/HZ)
+#define CURRENT_TIME (xtime.tv_sec)
extern void sleep_on(struct wait_queue ** p);
extern void interruptible_sleep_on(struct wait_queue ** p);
@@ -398,7 +401,7 @@ extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wa
unsigned long pc;
__asm__ __volatile__("call 1f\n"
"1:\tpopl %0":"=r" (pc));
- printk("add_wait_queue (%08x): wait->next = %08x\n",pc,wait->next);
+ printk("add_wait_queue (%08x): wait->next = %08x\n",pc,(unsigned long) wait->next);
}
#endif
save_flags(flags);
@@ -445,7 +448,7 @@ extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue *
#ifdef DEBUG
if (!ok) {
printk("removed wait_queue not on list.\n");
- printk("list = %08x, queue = %08x\n",p,wait);
+ printk("list = %08x, queue = %08x\n",(unsigned long) p, (unsigned long) wait);
__asm__("call 1f\n1:\tpopl %0":"=r" (ok));
printk("eip = %08x\n",ok);
}
@@ -527,4 +530,13 @@ static inline unsigned long get_limit(unsigned long segment)
*/
extern struct desc_struct default_ldt;
+/* This special macro can be used to load a debugging register */
+
+#define loaddebug(register) \
+ __asm__("movl %0,%%edx\n\t" \
+ "movl %%edx,%%db" #register "\n\t" \
+ : /* no output */ \
+ :"m" (current->debugreg[register]) \
+ :"dx");
+
#endif
diff --git a/include/linux/sockios.h b/include/linux/sockios.h
index fe5591e..76b8d90 100644
--- a/include/linux/sockios.h
+++ b/include/linux/sockios.h
@@ -59,6 +59,8 @@ struct ip_config {
#define SIOCSIFMEM 0x8920 /* set memory address (BSD) */
#define SIOCGIFMTU 0x8921 /* get MTU size */
#define SIOCSIFMTU 0x8922 /* set MTU size */
+#define SIOCGIFHWADDR 0x8923 /* get hardware address */
+#define SIOCSIFHWADDR 0x8924 /* set hardware address (NI) */
/* Routing table calls. */
#define SIOCADDRT 0x8940 /* add routing table entry */
diff --git a/include/linux/sys.h b/include/linux/sys.h
index 5104bab..55b99f5 100644
--- a/include/linux/sys.h
+++ b/include/linux/sys.h
@@ -1,5 +1,5 @@
/*
- * Why isn't this a .c file? Enquiring minds....
+ * system call entry points
*/
#define sys_clone sys_fork
@@ -132,6 +132,7 @@ extern int sys_setdomainname();
extern int sys_olduname();
extern int sys_old_syscall();
extern int sys_modify_ldt();
+extern int sys_adjtimex();
/*
* These are system calls that will be removed at some time
@@ -148,33 +149,7 @@ extern int sys_modify_ldt();
typedef int (*fn_ptr)();
-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_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
-sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
-sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
-sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
-sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
-sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
-sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
-sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
-sys_olduname, 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_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, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
-sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
-sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
-sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt};
-
#ifdef __cplusplus
}
#endif
-/* So we don't have to do any more manual updating.... */
-int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
diff --git a/include/linux/timex.h b/include/linux/timex.h
new file mode 100644
index 0000000..091576c
--- /dev/null
+++ b/include/linux/timex.h
@@ -0,0 +1,187 @@
+/*****************************************************************************
+ * *
+ * Copyright (c) David L. Mills 1993 *
+ * *
+ * Permission to use, copy, modify, and distribute this software and its *
+ * documentation for any purpose and without fee is hereby granted, provided *
+ * that the above copyright notice appears in all copies and that both the *
+ * copyright notice and this permission notice appear in supporting *
+ * documentation, and that the name University of Delaware not be used in *
+ * advertising or publicity pertaining to distribution of the software *
+ * without specific, written prior permission. The University of Delaware *
+ * makes no representations about the suitability this software for any *
+ * purpose. It is provided "as is" without express or implied warranty. *
+ * *
+ *****************************************************************************/
+
+/*
+ * Modification history timex.h
+ *
+ * 17 Sep 93 David L. Mills
+ * Created file $NTP/include/sys/timex.h
+ * 07 Oct 93 Torsten Duwe
+ * Derived linux/timex.h
+ */
+#ifndef _LINUX_TIMEX_H
+#define _LINUX_TIMEX_H
+
+#include <sys/syscall.h>
+#include <linux/unistd.h>
+
+/*
+ * The following defines establish the engineering parameters of the PLL
+ * model. The HZ variable establishes the timer interrupt frequency, 100 Hz
+ * for the SunOS kernel, 256 Hz for the Ultrix kernel and 1024 Hz for the
+ * OSF/1 kernel. The SHIFT_HZ define expresses the same value as the
+ * nearest power of two in order to avoid hardware multiply operations.
+ */
+#define SHIFT_HZ 7 /* log2(HZ) */
+
+/*
+ * The SHIFT_KG and SHIFT_KF defines establish the damping of the PLL
+ * and are chosen by analysis for a slightly underdamped convergence
+ * characteristic. The MAXTC define establishes the maximum time constant
+ * of the PLL. With the parameters given and the default time constant of
+ * zero, the PLL will converge in about 15 minutes.
+ */
+#define SHIFT_KG 8 /* shift for phase increment */
+#define SHIFT_KF 20 /* shift for frequency increment */
+#define MAXTC 6 /* maximum time constant (shift) */
+
+/*
+ * The SHIFT_SCALE define establishes the decimal point of the time_phase
+ * variable which serves as a an extension to the low-order bits of the
+ * system clock variable. The SHIFT_UPDATE define establishes the decimal
+ * point of the time_offset variable which represents the current offset
+ * with respect to standard time. The FINEUSEC define represents 1 usec in
+ * scaled units.
+ */
+#define SHIFT_SCALE 24 /* shift for phase scale factor */
+#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale factor */
+#define FINEUSEC (1 << SHIFT_SCALE) /* 1 us in scaled units */
+
+#define MAXPHASE 128000 /* max phase error (us) */
+#define MAXFREQ 100 /* max frequency error (ppm) */
+#define MINSEC 16 /* min interval between updates (s) */
+#define MAXSEC 1200 /* max interval between updates (s) */
+
+#define CLOCK_TICK_RATE 1193180 /* Underlying HZ */
+#define CLOCK_TICK_FACTOR 20 /* Factor of both 1000000 and CLOCK_TICK_RATE */
+#define LATCH ((CLOCK_TICK_RATE + HZ/2) / HZ) /* For divider */
+
+#define FINETUNE (((((LATCH * HZ - CLOCK_TICK_RATE) << SHIFT_HZ) * \
+ (1000000/CLOCK_TICK_FACTOR) / (CLOCK_TICK_RATE/CLOCK_TICK_FACTOR)) \
+ << (SHIFT_SCALE-SHIFT_HZ)) / HZ)
+
+/*
+ * syscall interface - used (mainly by NTP daemon)
+ * to discipline kernel clock oscillator
+ */
+struct timex {
+ int mode; /* mode selector */
+ long offset; /* time offset (usec) */
+ long frequency; /* frequency offset (scaled ppm) */
+ long maxerror; /* maximum error (usec) */
+ long esterror; /* estimated error (usec) */
+ int status; /* clock command/status */
+ long time_constant; /* pll time constant */
+ long precision; /* clock precision (usec) (read only) */
+ long tolerance; /* clock frequency tolerance (ppm)
+ * (read only)
+ */
+ struct timeval time; /* (read only) */
+};
+
+/*
+ * Mode codes (timex.mode)
+ */
+#define ADJ_OFFSET 0x0001 /* time offset */
+#define ADJ_FREQUENCY 0x0002 /* frequency offset */
+#define ADJ_MAXERROR 0x0004 /* maximum time error */
+#define ADJ_ESTERROR 0x0008 /* estimated time error */
+#define ADJ_STATUS 0x0010 /* clock status */
+#define ADJ_TIMECONST 0x0020 /* pll time constant */
+
+/*
+ * Clock command/status codes (timex.status)
+ */
+#define TIME_OK 0 /* clock synchronized */
+#define TIME_INS 1 /* insert leap second */
+#define TIME_DEL 2 /* delete leap second */
+#define TIME_OOP 3 /* leap second in progress */
+#define TIME_BAD 4 /* clock not synchronized */
+
+#ifndef __KERNEL__
+/* This is used only by one or two programs so it isn't worth putting it into
+ * a library; the functions are small enough to be substituted inline.
+ */
+inline static
+_syscall1(int, adjtimex, struct timex *, ntx);
+
+inline static int
+adjtime(struct timeval * itv, struct timeval * otv)
+{
+ struct timex tntx;
+ int result;
+
+ tntx.mode = 0;
+ if (itv)
+ {
+ tntx.offset = itv->tv_usec;
+ tntx.mode = ADJ_OFFSET;
+ }
+ result = adjtimex(&tntx);
+ if (result > 0) result = 0;
+
+ if (otv)
+ {
+ otv->tv_usec = tntx.offset;
+ otv->tv_sec = 0;
+ }
+ return result;
+}
+
+struct ntptimeval {
+ struct timeval time; /* current time */
+ long maxerror; /* maximum error (usec) */
+ long esterror; /* estimated error (usec) */
+};
+
+inline static int
+ntp_gettime(struct ntptimeval * ntv)
+{
+ struct timex tntx;
+ int result;
+ result = adjtimex(&tntx);
+ ntv->time = tntx.time;
+ ntv->maxerror = tntx.maxerror;
+ ntv->esterror = tntx.esterror;
+ return result;
+}
+
+#else
+/*
+ * kernel variables
+ */
+extern long tick; /* timer interrupt period */
+extern int tickadj; /* amount of adjustment per tick */
+extern volatile struct timeval xtime; /* The current time */
+
+/*
+ * phase-lock loop variables
+ */
+extern int time_status; /* clock synchronization status */
+extern long time_offset; /* time adjustment (us) */
+extern long time_constant; /* pll time constant */
+extern long time_tolerance; /* frequency tolerance (ppm) */
+extern long time_precision; /* clock precision (us) */
+extern long time_maxerror; /* maximum error */
+extern long time_esterror; /* estimated error */
+extern long time_phase; /* phase offset (scaled us) */
+extern long time_freq; /* frequency offset (scaled ppm) */
+extern long time_adj; /* tick adjust (scaled 1 / HZ) */
+extern long time_reftime; /* time at last adjustment (s) */
+
+extern long time_adjust; /* The amount of adjtime left */
+#endif /* KERNEL */
+#endif /* LINUX_TIMEX_H */
diff --git a/include/linux/tty.h b/include/linux/tty.h
index 5f43cb3..a54bbe4 100644
--- a/include/linux/tty.h
+++ b/include/linux/tty.h
@@ -214,7 +214,7 @@ struct tty_struct {
struct termios *termios;
int pgrp;
int session;
- unsigned char stopped:1, status_changed:1, packet:1, lnext:1;
+ unsigned char stopped:1, packet:1, lnext:1;
unsigned char char_error:2;
unsigned char ctrl_status;
short line;
@@ -241,6 +241,7 @@ struct tty_struct {
struct tty_queue read_q;
struct tty_queue write_q;
struct tty_queue secondary;
+ struct wait_queue * except_q;
};
struct tty_ldisc {
diff --git a/include/linux/unistd.h b/include/linux/unistd.h
index dbb0295..e500b5c 100644
--- a/include/linux/unistd.h
+++ b/include/linux/unistd.h
@@ -130,6 +130,8 @@
#define __NR_setdomainname 121
#define __NR_uname 122
#define __NR_modify_ldt 123
+#define __NR_adjtimex 124
+#define __NR_mprotect 125
extern int errno;
diff --git a/include/linux/user.h b/include/linux/user.h
index 106e710..3fbee19 100644
--- a/include/linux/user.h
+++ b/include/linux/user.h
@@ -61,11 +61,13 @@ struct user{
the top of the stack is always found in the
esp register. */
long int signal; /* Signal that caused the core dump. */
- char * u_comm; /* User command that was responsible */
+ int reserved; /* No longer used */
struct pt_regs * u_ar0; /* Used by gdb to help find the values for */
/* the registers. */
struct user_i387_struct* u_fpstate; /* Math Co-processor pointer. */
unsigned long magic; /* To uniquely identify a core file */
+ char u_comm[32]; /* User command that was responsible */
+ int u_debugreg[8];
};
#define NBPG 4096
#define UPAGES 1
diff --git a/include/linux/xd.h b/include/linux/xd.h
index f90822a..567584b 100644
--- a/include/linux/xd.h
+++ b/include/linux/xd.h
@@ -68,7 +68,6 @@
#define XD_RETRIES 4 /* maximum 4 retries */
#undef DEBUG /* define for debugging output */
-#undef XD_OVERRIDE /* define to override auto-detection */
#ifdef DEBUG
#define DEBUG_STARTUP /* debug driver initialisation */
@@ -76,7 +75,7 @@
#define DEBUG_READWRITE /* debug each read/write command */
#define DEBUG_OTHER /* debug misc. interrupt/DMA stuff */
#define DEBUG_COMMAND /* debug each controller command */
-#endif DEBUG
+#endif /* DEBUG */
/* this structure defines the XT drives and their types */
typedef struct {
@@ -105,7 +104,8 @@ typedef struct {
char *name;
} XD_SIGNATURE;
-u_long xd_init(u_long mem_start,u_long mem_end);
+u_long xd_init (u_long mem_start,u_long mem_end);
+void xd_setup (char *command,int *integers);
static u_char xd_detect (u_char *controller,u_char **address);
static u_char xd_initdrives (void (*init_drive)(u_char drive));
static void xd_geninit (void);
@@ -125,17 +125,13 @@ static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long t
static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout);
/* card specific setup and geometry gathering code */
-#ifndef XD_OVERRIDE
-static void xd_dtc5150x_init_controller (u_char *address);
-static void xd_dtc5150x_init_drive (u_char drive);
-static void xd_wd1004a27x_init_controller (u_char *address);
-static void xd_wd1004a27x_init_drive (u_char drive);
-static void xd_seagate11_init_controller (u_char *address);
-static void xd_seagate11_init_drive (u_char drive);
+static void xd_dtc_init_controller (u_char *address);
+static void xd_dtc_init_drive (u_char drive);
+static void xd_wd_init_controller (u_char *address);
+static void xd_wd_init_drive (u_char drive);
+static void xd_seagate_init_controller (u_char *address);
+static void xd_seagate_init_drive (u_char drive);
static void xd_setparam (u_char command,u_char drive,u_char heads,u_short cylinders,u_short rwrite,u_short wprecomp,u_char ecc);
-#endif XD_OVERRIDE
-
-static void xd_override_init_controller (u_char *address);
static void xd_override_init_drive (u_char drive);
-#endif _LINUX_XD_H
+#endif /* _LINUX_XD_H */
diff --git a/init/main.c b/init/main.c
index 09ff447..349020e 100644
--- a/init/main.c
+++ b/init/main.c
@@ -9,7 +9,6 @@
#include <asm/system.h>
#include <asm/io.h>
-#include <linux/mktime.h>
#include <linux/types.h>
#include <linux/fcntl.h>
#include <linux/config.h>
@@ -75,12 +74,17 @@ extern long chr_dev_init(long,long);
extern void floppy_init(void);
extern void sock_init(void);
extern long rd_init(long mem_start, int length);
-extern long kernel_mktime(struct mktime * time);
extern unsigned long simple_strtoul(const char *,char **,unsigned int);
extern void hd_setup(char *str, int *ints);
extern void bmouse_setup(char *str, int *ints);
extern void eth_setup(char *str, int *ints);
+extern void xd_setup(char *str, int *ints);
+extern void st0x_setup(char *str, int *ints);
+extern void tmc8xx_setup(char *str, int *ints);
+extern void t128_setup(char *str, int *ints);
+extern void generic_NCR5380_setup(char *str, int *intr);
+extern void aha152x_setup(char *str, int *ints);
#ifdef CONFIG_SYSVIPC
extern void ipc_init(void);
@@ -108,59 +112,24 @@ extern unsigned long scsi_dev_init(unsigned long, unsigned long);
#define MAX_INIT_ENVS 8
#define COMMAND_LINE ((char *) (PARAM+2048))
-/*
- * Yeah, yeah, it's ugly, but I cannot find how to do this correctly
- * and this seems to work. I anybody has more info on the real-time
- * clock I'd be interested. Most of this was trial and error, and some
- * bios-listing reading. Urghh.
- */
-
-#define CMOS_READ(addr) ({ \
-outb_p(addr,0x70); \
-inb_p(0x71); \
-})
-
-#define BCD_TO_BIN(val) ((val)=((val)&15) + ((val)>>4)*10)
-
-static void time_init(void)
-{
- struct mktime time;
- int i;
-
- for (i = 0 ; i < 1000000 ; i++)
- if (!(CMOS_READ(10) & 0x80))
- break;
- do {
- time.sec = CMOS_READ(0);
- time.min = CMOS_READ(2);
- time.hour = CMOS_READ(4);
- time.day = CMOS_READ(7);
- time.mon = CMOS_READ(8);
- time.year = CMOS_READ(9);
- } while (time.sec != CMOS_READ(0));
- BCD_TO_BIN(time.sec);
- BCD_TO_BIN(time.min);
- BCD_TO_BIN(time.hour);
- BCD_TO_BIN(time.day);
- BCD_TO_BIN(time.mon);
- BCD_TO_BIN(time.year);
- time.mon--;
- startup_time = kernel_mktime(&time);
-}
+extern void time_init(void);
static unsigned long memory_start = 0; /* After mem_init, stores the */
/* amount of free user memory */
static unsigned long memory_end = 0;
static unsigned long low_memory_start = 0;
+static char term[21];
+int rows, cols;
+
static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, };
-static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=console", NULL, };
+static char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", term, NULL, };
static char * argv_rc[] = { "/bin/sh", NULL };
-static char * envp_rc[] = { "HOME=/", "TERM=console", NULL };
+static char * envp_rc[] = { "HOME=/", term, NULL };
static char * argv[] = { "-/bin/sh",NULL };
-static char * envp[] = { "HOME=/usr/root", "TERM=console", NULL };
+static char * envp[] = { "HOME=/usr/root", term, NULL };
struct drive_info_struct { char dummy[32]; } drive_info;
struct screen_info screen_info;
@@ -201,6 +170,22 @@ struct {
#ifdef CONFIG_BUSMOUSE
{ "bmouse=", bmouse_setup },
#endif
+#ifdef CONFIG_SCSI_SEAGATE
+ { "st0x=", st0x_setup },
+ { "tmc8xx=", tmc8xx_setup },
+#endif
+#ifdef CONFIG_SCSI_T128
+ { "t128=", t128_setup },
+#endif
+#ifdef CONFIG_SCSI_GENERIC_NCR5380
+ { "ncr5380=", generic_NCR5380_setup },
+#endif
+#ifdef CONFIG_SCSI_AHA152X
+ { "aha152x=", aha152x_setup},
+#endif
+#ifdef CONFIG_BLK_DEV_XD
+ { "xd=", xd_setup },
+#endif
{ 0, 0 }
};
@@ -262,8 +247,8 @@ static void calibrate_delay(void)
static void parse_options(char *line)
{
char *next;
- char *devnames[] = { "hda", "hdb", "sda", "sdb", "sdc", "sdd", "sde", "fd", NULL };
- int devnums[] = { 0x300, 0x340, 0x800, 0x810, 0x820, 0x830, 0x840, 0x200, 0};
+ char *devnames[] = { "hda", "hdb", "sda", "sdb", "sdc", "sdd", "sde", "fd", "xda", "xdb", NULL };
+ int devnums[] = { 0x300, 0x340, 0x800, 0x810, 0x820, 0x830, 0x840, 0x200, 0xC00, 0xC40, 0};
int args, envs;
if (!*line)
@@ -374,6 +359,8 @@ asmlinkage void start_kernel(void)
#endif
memory_start = chr_dev_init(memory_start,memory_end);
memory_start = blk_dev_init(memory_start,memory_end);
+ sti();
+ calibrate_delay();
#ifdef CONFIG_SCSI
memory_start = scsi_dev_init(memory_start,memory_end);
#endif
@@ -388,7 +375,7 @@ asmlinkage void start_kernel(void)
ipc_init();
#endif
sti();
- calibrate_delay();
+
/*
* check if exception 16 works correctly.. This is truly evil
* code: it disables the high 8 interrupts to make sure that
@@ -422,6 +409,10 @@ asmlinkage void start_kernel(void)
for (;;) ;
}
#endif
+
+ system_utsname.machine[1] = '0' + x86;
+ printk(linux_banner);
+
move_to_user_mode();
if (!fork()) /* we count on this going ok */
init();
@@ -454,13 +445,11 @@ void init(void)
int pid,i;
setup((void *) &drive_info);
+ sprintf(term, "TERM=con%dx%d", ORIG_VIDEO_COLS, ORIG_VIDEO_LINES);
(void) open("/dev/tty1",O_RDWR,0);
(void) dup(0);
(void) dup(0);
- system_utsname.machine[1] = '0' + x86;
- printf(linux_banner);
-
execve("/etc/init",argv_init,envp_init);
execve("/bin/init",argv_init,envp_init);
execve("/sbin/init",argv_init,envp_init);
diff --git a/ipc/Makefile b/ipc/Makefile
index 5180a80..b2f237b 100644
--- a/ipc/Makefile
+++ b/ipc/Makefile
@@ -7,8 +7,6 @@
#
# Note 2! The CFLAGS definition is now in the main makefile...
-
-SUBDIRS =
.c.o:
$(CC) $(CFLAGS) -c $<
.s.o:
@@ -17,24 +15,21 @@ SUBDIRS =
$(CC) $(CFLAGS) -S $<
OBJS = util.o
+SRCS = util.c
ifdef CONFIG_SYSVIPC
OBJS := $(OBJS) msg.o sem.o shm.o
+SRCS := $(SRCS) msg.c sem.c shm.c
endif
ipc.o: $(OBJS)
$(LD) -r -o ipc.o $(OBJS)
-subdirs: dummy
- for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
-
clean:
rm -f core *.o *.a *.s
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) clean) || exit; done
dep:
- $(CPP) -M *.c > .depend
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
+ $(CPP) -M $(SRCS) > .depend
dummy:
diff --git a/ipc/msg.c b/ipc/msg.c
index b8f5f12..b4acda6 100644
--- a/ipc/msg.c
+++ b/ipc/msg.c
@@ -4,10 +4,12 @@
*/
#include <linux/errno.h>
-#include <asm/segment.h>
#include <linux/sched.h>
#include <linux/msg.h>
#include <linux/stat.h>
+#include <linux/malloc.h>
+
+#include <asm/segment.h>
extern int ipcperms (struct ipc_perm *ipcp, short msgflg);
diff --git a/ipc/sem.c b/ipc/sem.c
index a258716..de26b04 100644
--- a/ipc/sem.c
+++ b/ipc/sem.c
@@ -10,6 +10,7 @@
#include <linux/sem.h>
#include <linux/ipc.h>
#include <linux/stat.h>
+#include <linux/malloc.h>
extern int ipcperms (struct ipc_perm *ipcp, short semflg);
static int newary (key_t, int, int);
diff --git a/ipc/shm.c b/ipc/shm.c
index 69b14ec..48723d5 100644
--- a/ipc/shm.c
+++ b/ipc/shm.c
@@ -11,6 +11,7 @@
#include <linux/ipc.h>
#include <linux/shm.h>
#include <linux/stat.h>
+#include <linux/malloc.h>
extern int ipcperms (struct ipc_perm *ipcp, short semflg);
extern unsigned int get_swap_page(void);
@@ -596,7 +597,7 @@ void shm_no_page (unsigned long *ptent)
}
if (!(shp->shm_pages[idx] & PAGE_PRESENT)) {
- if(!(page = __get_free_page(GFP_KERNEL))) {
+ if(!(page = get_free_page(GFP_KERNEL))) {
oom(current);
*ptent = BAD_PAGE | PAGE_ACCESSED | 7;
return;
diff --git a/kernel/Makefile b/kernel/Makefile
index 7c9637a..9473e32 100644
--- a/kernel/Makefile
+++ b/kernel/Makefile
@@ -16,22 +16,17 @@
.c.o:
$(CC) $(CFLAGS) -c $<
-SUBDIRS = chr_drv blk_drv FPU-emu
-
OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o \
panic.o printk.o vsprintf.o sys.o exit.o \
signal.o mktime.o ptrace.o ioport.o itimer.o \
- info.o ldt.o
+ info.o ldt.o time.o
-all: kernel.o kernelsubdirs
+all: kernel.o
kernel.o: $(OBJS)
$(LD) -r -o kernel.o $(OBJS)
sync
-kernelsubdirs: dummy
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
-
sys_call.s: sys_call.S
sys_call.o: sys_call.s
@@ -41,11 +36,9 @@ sched.o: sched.c
clean:
rm -f core *.o *.a *.s
- for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
dep:
$(CPP) -M *.c > .depend
- for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep) || exit; done
dummy:
diff --git a/kernel/blk_drv/Makefile b/kernel/blk_drv/Makefile
deleted file mode 100644
index 3cf68b3..0000000
--- a/kernel/blk_drv/Makefile
+++ /dev/null
@@ -1,52 +0,0 @@
-#
-# Makefile for the 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).
-#
-# Note 2! The CFLAGS definition is now inherited from the
-# parent makefile.
-#
-
-.c.s:
- $(CC) $(CFLAGS) $(RAMDISK) -S $<
-.s.o:
- $(AS) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) $(RAMDISK) -c $<
-
-SUBDIRS = scsi
-
-OBJS = xd.o hd.o ll_rw_blk.o floppy.o ramdisk.o genhd.o cdu31a.o mcd.o
-
-all: blk_drv.a scsisubdirs
-
-blk_drv.a: $(OBJS)
- rm -f blk_drv.a
- $(AR) rcs blk_drv.a $(OBJS)
- sync
-
-scsisubdirs: dummy
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE)) || exit; done
-
-clean:
- rm -f core *.o *.a *.s
- for i in $(SUBDIRS); do (cd $$i && $(MAKE) clean); done
-
-dep:
- $(CPP) -M *.c > .depend
- for i in $(SUBDIRS); do (cd $$i && $(MAKE) dep); done
-
-xd.o:
- $(CC) $(CFLAGS) -fno-omit-frame-pointer $(RAMDISK) -c $<
-
-dummy:
-
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
-
diff --git a/kernel/blk_drv/scsi/hosts.c b/kernel/blk_drv/scsi/hosts.c
deleted file mode 100644
index e1a7680..0000000
--- a/kernel/blk_drv/scsi/hosts.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * 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>
-#include "../blk.h"
-#include <linux/kernel.h>
-#include "scsi.h"
-
-#ifndef NULL
-#define NULL 0L
-#endif
-
-#include "hosts.h"
-
-#ifdef CONFIG_SCSI_AHA1542
-#include "aha1542.h"
-#endif
-
-#ifdef CONFIG_SCSI_AHA1740
-#include "aha1740.h"
-#endif
-
-#ifdef CONFIG_SCSI_FUTURE_DOMAIN
-#include "fdomain.h"
-#endif
-
-#ifdef CONFIG_SCSI_SEAGATE
-#include "seagate.h"
-#endif
-
-#ifdef CONFIG_SCSI_ULTRASTOR
-#include "ultrastor.h"
-#endif
-
-#ifdef CONFIG_SCSI_7000FASST
-#include "wd7000.h"
-#endif
-
-#ifdef CONFIG_SCSI_DEBUG
-#include "scsi_debug.h"
-#endif
-
-/*
-static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/hosts.c,v 1.1 1992/07/24 06:27:38 root Exp root $";
-*/
-
-/*
- * The scsi host entries should be in the order you wish the
- * cards to be detected. A driver may appear more than once IFF
- * it can deal with being detected (and therefore initialized)
- * with more than one simulatenous host number, can handle being
- * rentrant, etc.
- *
- * They may appear in any order, as each SCSI host is told which host number it is
- * during detection.
- */
-
-/* This is a placeholder for controllers that are not configured into
- the system - we do this to ensure that the controller numbering is
- always consistent, no matter how the kernel is configured. */
-
-#define NO_CONTROLLER {NULL, NULL, NULL, NULL, NULL, NULL, NULL, \
- NULL, NULL, 0, 0, 0, 0, 0, 0}
-
-/*
- * 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.
- */
-
-Scsi_Host scsi_hosts[] =
- {
-#ifdef CONFIG_SCSI_AHA1542
- AHA1542,
-#endif
-#ifdef CONFIG_SCSI_AHA1740
- AHA1740,
-#endif
-#ifdef CONFIG_SCSI_FUTURE_DOMAIN
- FDOMAIN_16X0,
-#endif
-#ifdef CONFIG_SCSI_SEAGATE
- SEAGATE_ST0X,
-#endif
-#ifdef CONFIG_SCSI_ULTRASTOR
- ULTRASTOR_14F,
-#endif
-#ifdef CONFIG_SCSI_7000FASST
- WD7000,
-#endif
-#ifdef CONFIG_SCSI_DEBUG
- SCSI_DEBUG,
-#endif
- };
-
-#define MAX_SCSI_HOSTS (sizeof(scsi_hosts) / sizeof(Scsi_Host))
-
-/*
- * 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];
-int last_reset[MAX_SCSI_HOSTS];
-Scsi_Cmnd *host_queue[MAX_SCSI_HOSTS];
-struct wait_queue *host_wait[MAX_SCSI_HOSTS] = {NULL,}; /* For waiting until host available*/
-int max_scsi_hosts = MAX_SCSI_HOSTS; /* This is used by scsi.c */
-
-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_queue[i] = NULL;
-
- if ((scsi_hosts[i].detect) && (scsi_hosts[i].present = scsi_hosts[i].detect(i)))
- {
- printk ("scsi%d : %s.\n",
- count, scsi_hosts[i].name);
- printk ("%s", scsi_hosts[i].info());
- ++count;
- }
- }
- printk ("scsi : %d hosts.\n", count);
- }
-
- }
-
-#ifndef CONFIG_BLK_DEV_SD
-unsigned long sd_init(unsigned long memory_start, unsigned long memory_end){
- return memory_start;
-};
-unsigned long sd_init1(unsigned long memory_start, unsigned long memory_end){
- return memory_start;
-};
-void sd_attach(Scsi_Device * SDp){
-};
-int NR_SD=-1;
-int MAX_SD=0;
-#endif
-
-
-#ifndef CONFIG_BLK_DEV_SR
-unsigned long sr_init(unsigned long memory_start, unsigned long memory_end){
- return memory_start;
-};
-unsigned long sr_init1(unsigned long memory_start, unsigned long memory_end){
- return memory_start;
-};
-void sr_attach(Scsi_Device * SDp){
-};
-int NR_SR=-1;
-int MAX_SR=0;
-#endif
-
-
-#ifndef CONFIG_BLK_DEV_ST
-unsigned long st_init(unsigned long memory_start, unsigned long memory_end){
- return memory_start;
-};
-unsigned long st_init1(unsigned long memory_start, unsigned long memory_end){
- return memory_start;
-};
-void st_attach(Scsi_Device * SDp){
-};
-int NR_ST=-1;
-int MAX_ST=0;
-#endif
-
diff --git a/kernel/blk_drv/scsi/ultrastor.c b/kernel/blk_drv/scsi/ultrastor.c
deleted file mode 100644
index a33605d..0000000
--- a/kernel/blk_drv/scsi/ultrastor.c
+++ /dev/null
@@ -1,561 +0,0 @@
-/*
- * ultrastor.c Copyright (C) 1992 David B. Gentzel
- * Low-level SCSI driver for UltraStor 14F
- * by David B. Gentzel, Whitfield Software Services, Carnegie, PA
- * (gentzel@nova.enet.dec.com)
- * scatter/gather added by Scott Taylor (n217cg@tamuts.tamu.edu)
- * Thanks to UltraStor for providing the necessary documentation
- */
-
-/*
- * TODO:
- * 1. Cleanup error handling & reporting.
- * 2. Find out why scatter/gather is limited to 16 requests per command.
- * 3. Add multiple outstanding requests.
- * 4. See if we can make good use of having more than one command per lun.
- * 5. Test/improve/fix abort & reset functions.
- * 6. Look at command linking (mscp.command_link and
- * mscp.command_link_id).
- */
-
-/*
- * NOTES:
- * The UltraStor 14F is one of a family of intelligent, high performance
- * SCSI-2 host adapters. They all support command queueing and
- * scatter/gather I/O. Some of them can also emulate the standard
- * WD1003 interface for use with OS's which don't support SCSI.
- * Here is the scoop on the various models:
- * 14F - ISA first-party DMA HA with floppy support and WD1003 emulation.
- * 14N - ISA HA with floppy support. I think that this is a non-DMA
- * HA. Nothing further known.
- * 24F - EISA Bus Master HA with floppy support and WD1003 emulation.
- * 34F - VL-Bus Bus Master HA with floppy support (no WD1003 emulation).
- *
- * The 14F is supported by this driver. An effort has been made to support
- * the 34F. It should work, but is untested. The 24F does not work at
- * present.
- *
- * Places flagged with a triple question-mark are things which are either
- * unfinished, questionable, or wrong.
- */
-
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/sched.h>
-#include <linux/kernel.h>
-#include <linux/ioport.h>
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/dma.h>
-
-#define ULTRASTOR_PRIVATE /* Get the private stuff from ultrastor.h */
-#include "../blk.h"
-#include "scsi.h"
-#include "hosts.h"
-#include "ultrastor.h"
-
-#define ULTRASTOR_DEBUG 0
-
-#define VERSION "1.1 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 fetch the configuration info from the config i/o registers. We
- then store (in a friendlier format) in config. */
-struct config_1 {
- unsigned char bios_segment: 3;
- unsigned char removable_disks_as_fixed: 1;
- unsigned char interrupt: 2;
- unsigned char dma_channel: 2;
-};
-struct config_2 {
- unsigned char ha_scsi_id: 3;
- unsigned char mapping_mode: 2;
- unsigned char bios_drive_number: 1;
- unsigned char tfr_port: 2;
-};
-
-/* Used to store configuration info read from config i/o registers. Most of
- this is not used yet, but might as well save it. */
-struct config {
- const void *bios_segment;
- unsigned short port_address;
- unsigned char interrupt: 4;
- unsigned char dma_channel: 3;
- unsigned char bios_drive_number: 1;
- unsigned char heads;
- unsigned char sectors;
- unsigned char ha_scsi_id: 3;
- unsigned char subversion: 4;
-};
-
-/* 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;
-};
-
-/* The 14F uses an array of unaligned 4-byte ints for its scatter/gather list. */
-typedef struct {
- unsigned long address;
- unsigned long num_bytes;
-} ultrastor_sg_list;
-
-/* This is our semaphore for mscp block availability */
-int mscp_free = TRUE;
-
-/* Allowed BIOS base addresses for 14f (NULL indicates reserved) */
-static const void *const bios_segment_table_14f[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_14f[4] = { 15, 14, 11, 10 };
-
-/* Allowed DMA channels for 14f (0 indicates reserved) */
-static const unsigned char dma_channel_table_14f[4] = { 5, 6, 7, 0 };
-
-/* Head/sector mappings allowed by 14f */
-static const struct {
- unsigned char heads;
- unsigned char sectors;
-} mapping_table_14f[4] = { { 16, 63 }, { 64, 32 }, { 64, 63 }, { 0, 0 } };
-
-/* Subversions of the 14F */
-static const char *const subversion_names[] = { "14F", "34F" };
-
-/* Config info */
-static struct config config;
-
-/* Our index in the host adapter array maintained by higher-level driver */
-static int host_number;
-
-/* PORT_ADDRESS is first port address used for i/o of messages. */
-#ifdef PORT_OVERRIDE
-# define PORT_ADDRESS PORT_OVERRIDE
-#else
-# define PORT_ADDRESS (config.port_address)
-#endif
-
-static volatile int aborted = 0;
-
-#ifndef PORT_OVERRIDE
-/* ??? A probe of address 0x310 screws up NE2000 cards */
-static const unsigned short ultrastor_ports_14f[] = {
- 0x330, 0x340, /*0x310,*/ 0x230, 0x240, 0x210, 0x130, 0x140,
-};
-#endif
-
-static void ultrastor_interrupt(int cpl);
-static inline void build_sg_list(Scsi_Cmnd *SCpnt);
-
-static void (*ultrastor_done)(Scsi_Cmnd *) = 0;
-static Scsi_Cmnd *SCint = NULL;
-
-int ultrastor_detect(int hostnum)
-{
- size_t i;
- unsigned char in_byte, version_byte = 0;
- struct config_1 config_1;
- struct config_2 config_2;
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: called\n");
-#endif
-
-#ifndef PORT_OVERRIDE
- PORT_ADDRESS = 0;
- for (i = 0; i < ARRAY_SIZE(ultrastor_ports_14f); i++) {
- PORT_ADDRESS = ultrastor_ports_14f[i];
- if(check_region(PORT_ADDRESS, 4)) continue;
-#else
- if(check_region(PORT_ADDRESS, 4)) {
- printk("Ultrastor I/O space already in use\n");
- return FALSE;
- };
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: testing port address %03X\n", PORT_ADDRESS);
-#endif
-
- in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 0));
- if (in_byte != US14F_PRODUCT_ID_0) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
-# ifdef PORT_OVERRIDE
- printk("US14F: detect: wrong product ID 0 - %02X\n", in_byte);
-# else
- printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
-# endif
-#endif
-#ifdef PORT_OVERRIDE
- return FALSE;
-#else
- continue;
-#endif
- }
- in_byte = inb(PRODUCT_ID(PORT_ADDRESS + 1));
- /* Only upper nibble is significant for Product ID 1 */
- if ((in_byte & 0xF0) != US14F_PRODUCT_ID_1) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
-# ifdef PORT_OVERRIDE
- printk("US14F: detect: wrong product ID 1 - %02X\n", in_byte);
-# else
- printk("US14F: detect: no adapter at port %03X\n", PORT_ADDRESS);
-# endif
-#endif
-#ifdef PORT_OVERRIDE
- return FALSE;
-#else
- continue;
-#endif
- }
- version_byte = in_byte;
-#ifndef PORT_OVERRIDE
- break;
- }
- if (i == ARRAY_SIZE(ultrastor_ports_14f)) {
-# if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: no port address found!\n");
-# endif
- return FALSE;
- }
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: adapter found at port address %03X\n",
- PORT_ADDRESS);
-#endif
-
- snarf_region(PORT_ADDRESS, 4); /* Register the I/O space that we use */
- /* All above tests passed, must be the right thing. Get some useful
- info. */
- *(char *)&config_1 = inb(CONFIG(PORT_ADDRESS + 0));
- *(char *)&config_2 = inb(CONFIG(PORT_ADDRESS + 1));
- config.bios_segment = bios_segment_table_14f[config_1.bios_segment];
- config.interrupt = interrupt_table_14f[config_1.interrupt];
- config.ha_scsi_id = config_2.ha_scsi_id;
- config.heads = mapping_table_14f[config_2.mapping_mode].heads;
- config.sectors = mapping_table_14f[config_2.mapping_mode].sectors;
- config.bios_drive_number = config_2.bios_drive_number;
- config.subversion = (version_byte & 0x0F);
- if (config.subversion == U34F)
- config.dma_channel = 0;
- else
- config.dma_channel = dma_channel_table_14f[config_1.dma_channel];
-
- if (!config.bios_segment) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: not detected.\n");
-#endif
- return FALSE;
- }
-
- /* Final consistancy check, verify previous info. */
- if (config.subversion != U34F)
- if (!config.dma_channel || !(config_2.tfr_port & 0x2)) {
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: consistancy check failed\n");
-#endif
- return FALSE;
- }
-
- /* If we were TRULY paranoid, we could issue a host adapter inquiry
- command here and verify the data returned. But frankly, I'm
- exhausted! */
-
- /* Finally! Now I'm satisfied... */
-#if (ULTRASTOR_DEBUG & UD_DETECT)
- printk("US14F: detect: detect succeeded\n"
- " Port address: %03X\n"
- " BIOS segment: %05X\n"
- " Interrupt: %u\n"
- " DMA channel: %u\n"
- " H/A SCSI ID: %u\n"
- " Subversion: %u\n",
- PORT_ADDRESS, config.bios_segment, config.interrupt,
- config.dma_channel, config.ha_scsi_id, config.subversion);
-#endif
- host_number = hostnum;
- scsi_hosts[hostnum].this_id = config.ha_scsi_id;
- scsi_hosts[hostnum].unchecked_isa_dma = (config.subversion != U34F);
-
- if (request_irq(config.interrupt, ultrastor_interrupt)) {
- printk("Unable to allocate IRQ%u for UltraStor controller.\n",
- config.interrupt);
- return FALSE;
- }
- if (config.dma_channel && request_dma(config.dma_channel)) {
- printk("Unable to allocate DMA channel %u for UltraStor controller.\n",
- config.dma_channel);
- free_irq(config.interrupt);
- return FALSE;
- }
- scsi_hosts[hostnum].sg_tablesize = ULTRASTOR_14F_MAX_SG;
- printk("UltraStor: scatter/gather enabled. Using %d SG lists.\n", ULTRASTOR_14F_MAX_SG);
-
- return TRUE;
-}
-
-const char *ultrastor_info(void)
-{
- static char buf[64];
-
- (void)sprintf(buf, "UltraStor %s SCSI @ Port %03X BIOS %05X IRQ%u DMA%u\n",
- ((config.subversion < ARRAY_SIZE(subversion_names))
- ? subversion_names[config.subversion] : "14F?"),
- PORT_ADDRESS, (int)config.bios_segment, config.interrupt,
- config.dma_channel);
- return buf;
-}
-
-static struct mscp mscp = {
- OP_SCSI, DTD_SCSI, 0, 1, 0 /* This stuff doesn't change */
-};
-
-static inline void build_sg_list(Scsi_Cmnd *SCpnt)
-{
- ultrastor_sg_list *sglist;
- struct scatterlist *sl;
- long transfer_length = 0;
- int i;
-
- sl = (struct scatterlist *) SCpnt->request_buffer;
- SCpnt->host_scribble = (unsigned char *) scsi_malloc(512);
- if (SCpnt->host_scribble == NULL)
- /* Not sure what to do here; just panic for now */
- panic("US14F: Can't allocate DMA buffer for scatter-gather list!\n");
- /* Save ourselves some casts; can eliminate when we don't have to look at it anymore! */
- sglist = (ultrastor_sg_list *) SCpnt->host_scribble;
- for (i = 0; i < SCpnt->use_sg; i++) {
- sglist[i].address = (unsigned long) sl[i].address;
- sglist[i].num_bytes = sl[i].length;
- transfer_length += sl[i].length;
- }
- mscp.number_of_sg_list = (char) SCpnt->use_sg;
- mscp.transfer_data = *(Longword *)&sglist;
- /* ??? May not be necessary. Docs are unclear as to whether transfer length field is */
- /* ignored or whether it should be set to the total number of bytes of the transfer. */
- mscp.transfer_data_length = *(Longword *)&transfer_length;
-}
-
-int ultrastor_queuecommand(Scsi_Cmnd *SCpnt, void (*done)(Scsi_Cmnd *))
-{
- unsigned char in_byte;
-
-#if (ULTRASTOR_DEBUG & UD_COMMAND)
- printk("US14F: queuecommand: called\n");
-#endif
-
- /* We want to be sure that a command queued while another command */
- /* is running doesn't overwrite the mscp block until the running */
- /* command is finished. mscp_free is set in the interrupt handler. */
- /* I'm not sure if the upper level driver will send another command */
- /* with a command pending; this is just insurance. */
- while (1) {
- cli();
- if (mscp_free) {
- mscp_free = FALSE;
- sti();
- break;
- }
- sti();
- }
- mscp.opcode = OP_SCSI;
- mscp.xdir = DTD_SCSI;
- mscp.dcn = FALSE;
- /* Tape drives don't work properly if the cache is used. The SCSI
- READ command for a tape doesn't have a block offset, and the adapter
- incorrectly assumes that all reads from the tape read the same
- blocks. Results will depend on read buffer size and other disk
- activity.
-
- ??? Which other device types should never use the cache? */
- mscp.ca = scsi_devices[SCpnt->index].type != TYPE_TAPE;
- mscp.target_id = SCpnt->target;
- mscp.ch_no = 0;
- mscp.lun = SCpnt->lun;
- if (SCpnt->use_sg) {
- /* Set scatter/gather flag in SCSI command packet */
- mscp.sg = TRUE;
- build_sg_list(SCpnt);
- }
- else {
- /* Unset scatter/gather flag in SCSI command packet */
- mscp.sg = FALSE;
- mscp.transfer_data = *(Longword *)&SCpnt->request_buffer;
- mscp.transfer_data_length = *(Longword *)&SCpnt->request_bufflen;
- SCpnt->host_scribble = NULL;
- }
- memset(&mscp.command_link, 0, sizeof(mscp.command_link)); /*???*/
- mscp.scsi_command_link_id = 0; /*???*/
- mscp.length_of_sense_byte = 0; /*???*/
- mscp.length_of_scsi_cdbs = COMMAND_SIZE(*(unsigned char *)SCpnt->cmnd);
- memcpy(mscp.scsi_cdbs, SCpnt->cmnd, mscp.length_of_scsi_cdbs);
- mscp.adapter_status = 0;
- mscp.target_status = 0;
- memset(&mscp.sense_data, 0, sizeof(mscp.sense_data)); /*???*/
-
- /* Find free OGM slot (OGMINT bit is 0) */
- do
- in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
- while (!aborted && (in_byte & 1));
- if (aborted) {
-#if (ULTRASTOR_DEBUG & (UD_COMMAND | UD_ABORT))
- printk("US14F: queuecommand: aborted\n");
-#endif
- /* ??? is this right? */
- return (aborted << 16);
- }
-
- /* Store pointer in OGM address bytes */
- outb_p(BYTE(&mscp, 0), OGM_DATA_PTR(PORT_ADDRESS + 0));
- outb_p(BYTE(&mscp, 1), OGM_DATA_PTR(PORT_ADDRESS + 1));
- outb_p(BYTE(&mscp, 2), OGM_DATA_PTR(PORT_ADDRESS + 2));
- outb_p(BYTE(&mscp, 3), OGM_DATA_PTR(PORT_ADDRESS + 3));
-
- /* Issue OGM interrupt */
- outb_p(0x1, LCL_DOORBELL_INTR(PORT_ADDRESS));
-
- ultrastor_done = done;
- SCint = SCpnt;
-
-#if (ULTRASTOR_DEBUG & UD_COMMAND)
- printk("US14F: queuecommand: returning\n");
-#endif
-
- return 0;
-}
-
-int ultrastor_abort(Scsi_Cmnd *SCpnt, int code)
-{
-#if (ULTRASTOR_DEBUG & UD_ABORT)
- printk("US14F: abort: called\n");
-#endif
-
- aborted = (code ? code : DID_ABORT);
-
- /* Free DMA buffer used for scatter/gather list */
- if (SCpnt->host_scribble)
- scsi_free(SCpnt->host_scribble, 512);
-
- /* Free up mscp block for next command */
- mscp_free = TRUE;
-
-#if (ULTRASTOR_DEBUG & UD_ABORT)
- printk("US14F: abort: returning\n");
-#endif
-
- return 0;
-}
-
-int ultrastor_reset(void)
-{
-#if 0
- unsigned char in_byte;
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_RESET)
- printk("US14F: reset: called\n");
-#endif
-
- /* ??? SCSI bus reset causes problems on some systems. */
-#if 0
- /* Issue SCSI BUS reset */
- outb_p(0x20, LCL_DOORBELL_INTR(PORT_ADDRESS));
-
- /* Wait for completion... */
- do
- in_byte = inb_p(LCL_DOORBELL_INTR(PORT_ADDRESS));
- while (in_byte & 0x20);
-
- aborted = DID_RESET;
-#endif
-
-#if (ULTRASTOR_DEBUG & UD_RESET)
- printk("US14F: reset: returning\n");
-#endif
- return 0;
-}
-
-int ultrastor_biosparam(int size, int dev, int *ip)
-{
- unsigned int s = config.heads * config.sectors;
-
- ip[0] = config.heads;
- ip[1] = config.sectors;
- ip[2] = (size + (s - 1)) / s;
-/* if (ip[2] > 1024)
- ip[2] = 1024; */
- return 0;
-}
-
-static void ultrastor_interrupt(int cpl)
-{
-#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
- printk("US14F: interrupt: called: status = %08X\n",
- (mscp.adapter_status << 16) | mscp.target_status);
-#endif
-
- if (ultrastor_done == 0)
- panic("US14F: interrupt: unexpected interrupt");
- else {
- void (*done)(Scsi_Cmnd *);
- Scsi_Cmnd *SCtmp;
-
- /* Save ultrastor_done locally and zero before calling. This is needed
- as once we call done, we may get another command queued before this
- interrupt service routine can return. */
- done = ultrastor_done;
- ultrastor_done = 0;
- SCtmp = SCint;
-
- /* Clean ICM slot (set ICMINT bit to 0) */
- outb_p(0x1, SYS_DOORBELL_INTR(PORT_ADDRESS));
-
- /* Let the higher levels know that we're done */
- /* ??? status is wrong here... */
- SCtmp->result = (mscp.adapter_status << 16) | mscp.target_status;
-
- /* Free temp space used for scatter-gather list */
- if (SCtmp->host_scribble)
- scsi_free(SCtmp->host_scribble, 512);
-
- /* Free up mscp block for next command */
- mscp_free = TRUE;
-
- done(SCtmp);
- }
-
-#if (ULTRASTOR_DEBUG & UD_INTERRUPT)
- printk("US14F: interrupt: returning\n");
-#endif
-}
diff --git a/kernel/exit.c b/kernel/exit.c
index d324cb6..7ba3116 100644
--- a/kernel/exit.c
+++ b/kernel/exit.c
@@ -14,6 +14,7 @@
#include <linux/resource.h>
#include <linux/mm.h>
#include <linux/tty.h>
+#include <linux/malloc.h>
#include <asm/segment.h>
extern void shm_exit (void);
diff --git a/kernel/fork.c b/kernel/fork.c
index 39b832d..ba153dc 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -19,6 +19,7 @@
#include <linux/unistd.h>
#include <linux/segment.h>
#include <linux/ptrace.h>
+#include <linux/malloc.h>
#include <asm/segment.h>
#include <asm/system.h>
@@ -35,36 +36,33 @@ long last_pid=0;
static int find_empty_process(void)
{
- int i, task_nr, tasks_free;
+ int free_task;
+ int i, tasks_free;
int this_user_tasks;
repeat:
if ((++last_pid) & 0xffff8000)
last_pid=1;
this_user_tasks = 0;
- for(i=0 ; i < NR_TASKS ; i++) {
- if (!task[i])
+ tasks_free = 0;
+ free_task = -EAGAIN;
+ i = NR_TASKS;
+ while (--i > 0) {
+ if (!task[i]) {
+ free_task = i;
+ tasks_free++;
continue;
+ }
if (task[i]->uid == current->uid)
this_user_tasks++;
if (task[i]->pid == last_pid || task[i]->pgrp == last_pid)
goto repeat;
}
- if (this_user_tasks > MAX_TASKS_PER_USER && current->uid)
- return -EAGAIN;
-
-/* Only the super-user can fill the last MIN_TASKS_LEFT_FOR_ROOT slots */
-
- tasks_free = 0; task_nr = 0;
- for (i=NR_TASKS-1; i > 0; i--) {
- if (!task[i]) {
- tasks_free++;
- task_nr = i;
- }
- }
- if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT && current->uid)
- return -EAGAIN;
- return task_nr;
+ if (tasks_free <= MIN_TASKS_LEFT_FOR_ROOT ||
+ this_user_tasks > MAX_TASKS_PER_USER)
+ if (current->uid)
+ return -EAGAIN;
+ return free_task;
}
static struct file * copy_fd(struct file * old_file)
@@ -94,6 +92,7 @@ int dup_mmap(struct task_struct * tsk)
struct vm_area_struct * mpnt, **p, *tmp;
tsk->mmap = NULL;
+ tsk->stk_vma = NULL;
p = &tsk->mmap;
for (mpnt = current->mmap ; mpnt ; mpnt = mpnt->vm_next) {
tmp = (struct vm_area_struct *) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
@@ -106,6 +105,8 @@ int dup_mmap(struct task_struct * tsk)
tmp->vm_inode->i_count++;
*p = tmp;
p = &tmp->vm_next;
+ if (current->stk_vma == mpnt)
+ tsk->stk_vma = tmp;
}
return 0;
}
diff --git a/kernel/info.c b/kernel/info.c
index 27cb324..c7b2b9a 100644
--- a/kernel/info.c
+++ b/kernel/info.c
@@ -25,7 +25,7 @@ asmlinkage int sys_sysinfo(struct sysinfo *info)
return error;
memset((char *)&val, 0, sizeof(struct sysinfo));
- val.uptime = (jiffies + jiffies_offset) / HZ;
+ val.uptime = jiffies / HZ;
val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT);
val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT);
diff --git a/kernel/panic.c b/kernel/panic.c
index 24edec2..ee91d22 100644
--- a/kernel/panic.c
+++ b/kernel/panic.c
@@ -19,17 +19,15 @@ extern int vsprintf(char * buf, const char * fmt, va_list args);
volatile void panic(const char * fmt, ...)
{
- extern int log_to_console;
static char buf[1024];
va_list args;
va_start(args, fmt);
vsprintf(buf, fmt, args);
va_end(args);
- log_to_console = 1;
- printk("Kernel panic: %s\n",buf);
+ printk(KERN_EMERG "Kernel panic: %s\n",buf);
if (current == task[0])
- printk("In swapper task - not syncing\n");
+ printk(KERN_EMERG "In swapper task - not syncing\n");
else
sys_sync();
for(;;);
diff --git a/kernel/printk.c b/kernel/printk.c
index 7c37ee8..491cd7d 100644
--- a/kernel/printk.c
+++ b/kernel/printk.c
@@ -27,12 +27,14 @@ static char buf[1024];
extern int vsprintf(char * buf, const char * fmt, va_list args);
extern void console_print(const char *);
+#define DEFAULT_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */
+
static void (*console_print_proc)(const char *) = 0;
static char log_buf[LOG_BUF_LEN];
static unsigned long log_start = 0;
static unsigned long logged_chars = 0;
+static int console_loglevel = DEFAULT_LOGLEVEL;
unsigned long log_size = 0;
-int log_to_console = 1;
struct wait_queue * log_wait = NULL;
/*
@@ -46,6 +48,7 @@ struct wait_queue * log_wait = NULL;
* 5 -- Clear ring buffer.
* 6 -- Disable printk's to console
* 7 -- Enable printk's to console
+ * 8 -- Set level of messages printed to console
*/
asmlinkage int sys_syslog(int type, char * buf, int len)
{
@@ -114,35 +117,69 @@ asmlinkage int sys_syslog(int type, char * buf, int len)
logged_chars = 0;
return 0;
case 6: /* Disable logging to console */
- log_to_console = 0;
+ console_loglevel = 1; /* only panic messages shown */
return 0;
case 7: /* Enable logging to console */
- log_to_console = 1;
+ console_loglevel = DEFAULT_LOGLEVEL;
+ return 0;
+ case 8:
+ if (len < 0 || len > 8)
+ return -EINVAL;
+ console_loglevel = len;
return 0;
}
return -EINVAL;
}
-
+
asmlinkage int printk(const char *fmt, ...)
{
va_list args;
- int i,j;
+ int i;
+ char *msg, *p, *buf_end;
+ static char msg_level = -1;
va_start(args, fmt);
- i=vsprintf(buf,fmt,args);
+ i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */
+ buf_end = buf + 3 + i;
va_end(args);
- for (j = 0; j < i ; j++) {
- log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = buf[j];
- if (log_size < LOG_BUF_LEN)
- log_size++;
- else
- log_start++;
- logged_chars++;
+ for (p = buf + 3; p < buf_end; p++) {
+ msg = p;
+ if (msg_level < 0) {
+ if (
+ p[0] != '<' ||
+ p[1] < '0' ||
+ p[1] > '7' ||
+ p[2] != '>'
+ ) {
+ p -= 3;
+ p[0] = '<';
+ p[1] = DEFAULT_LOGLEVEL - 1 + '0';
+ p[2] = '>';
+ } else
+ msg += 3;
+ msg_level = p[1] - '0';
+ }
+ for (; p < buf_end; p++) {
+ log_buf[(log_start+log_size) & (LOG_BUF_LEN-1)] = *p;
+ if (log_size < LOG_BUF_LEN)
+ log_size++;
+ else
+ log_start++;
+ logged_chars++;
+ if (*p == '\n')
+ break;
+ }
+ if (msg_level < console_loglevel && console_print_proc) {
+ char tmp = p[1];
+ p[1] = '\0';
+ (*console_print_proc)(msg);
+ p[1] = tmp;
+ }
+ if (*p == '\n')
+ msg_level = -1;
}
wake_up_interruptible(&log_wait);
- if (log_to_console && console_print_proc)
- (*console_print_proc)(buf);
return i;
}
@@ -150,25 +187,33 @@ asmlinkage int printk(const char *fmt, ...)
* The console driver calls this routine during kernel initialization
* to register the console printing procedure with printk() and to
* print any messages that were printed by the kernel before the
- * console priver was initialized.
+ * console driver was initialized.
*/
void register_console(void (*proc)(const char *))
{
int i,j;
int p = log_start;
char buf[16];
+ char msg_level = -1;
+ char *q;
console_print_proc = proc;
for (i=0,j=0; i < log_size; i++) {
buf[j++] = log_buf[p];
p++; p &= LOG_BUF_LEN-1;
- if (j < sizeof(buf)-1)
+ if (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1)
continue;
buf[j] = 0;
- (*proc)(buf);
+ q = buf;
+ if (msg_level < 0) {
+ msg_level = buf[1] - '0';
+ q = buf + 3;
+ }
+ if (msg_level < console_loglevel)
+ (*proc)(q);
+ if (buf[j-1] == '\n')
+ msg_level = -1;
j = 0;
}
- buf[j] = 0;
- (*proc)(buf);
}
diff --git a/kernel/ptrace.c b/kernel/ptrace.c
index ccc93a4..4e5d87b 100644
--- a/kernel/ptrace.c
+++ b/kernel/ptrace.c
@@ -8,9 +8,11 @@
#include <linux/mm.h>
#include <linux/errno.h>
#include <linux/ptrace.h>
+#include <linux/user.h>
#include <asm/segment.h>
#include <asm/system.h>
+#include <linux/debugreg.h>
/*
* does not yet catch signals sent when the child dies.
@@ -219,6 +221,10 @@ static int write_long(struct task_struct * tsk, unsigned long addr,
asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
{
struct task_struct *child;
+ struct user * dummy;
+ int i;
+
+ dummy = NULL;
if (request == PTRACE_TRACEME) {
/* are we already being traced? */
@@ -278,17 +284,29 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
unsigned long tmp;
int res;
- addr = addr >> 2; /* temporary hack. */
- if (addr < 0 || addr >= 17)
+ if ((addr & 3) || addr < 0 ||
+ addr > sizeof(struct user) - 3)
return -EIO;
+
res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long));
if (res)
return res;
- tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
- if (addr == DS || addr == ES ||
- addr == FS || addr == GS ||
- addr == CS || addr == SS)
- tmp &= 0xffff;
+ tmp = 0; /* Default return condition */
+ if(addr < 17*sizeof(long)) {
+ addr = addr >> 2; /* temporary hack. */
+
+ tmp = get_stack_long(child, sizeof(long)*addr - MAGICNUMBER);
+ if (addr == DS || addr == ES ||
+ addr == FS || addr == GS ||
+ addr == CS || addr == SS)
+ tmp &= 0xffff;
+ };
+ if(addr >= (long) &dummy->u_debugreg[0] &&
+ addr <= (long) &dummy->u_debugreg[7]){
+ addr -= (long) &dummy->u_debugreg[0];
+ addr = addr >> 2;
+ tmp = child->debugreg[addr];
+ };
put_fs_long(tmp,(unsigned long *) data);
return 0;
}
@@ -299,9 +317,12 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
return write_long(child,addr,data);
case PTRACE_POKEUSR: /* write the word at location addr in the USER area */
- addr = addr >> 2; /* temproary hack. */
- if (addr < 0 || addr >= 17)
+ if ((addr & 3) || addr < 0 ||
+ addr > sizeof(struct user) - 3)
return -EIO;
+
+ addr = addr >> 2; /* temproary hack. */
+
if (addr == ORIG_EAX)
return -EIO;
if (addr == DS || addr == ES ||
@@ -315,9 +336,41 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
data &= FLAG_MASK;
data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK;
}
- if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
+ /* Do not allow the user to set the debug register for kernel
+ address space */
+ if(addr < 17){
+ if (put_stack_long(child, sizeof(long)*addr-MAGICNUMBER, data))
return -EIO;
return 0;
+ };
+
+ /* We need to be very careful here. We implicitly
+ want to modify a portion of the task_struct, and we
+ have to be selective about what portions we allow someone
+ to modify. */
+
+ addr = addr << 2; /* Convert back again */
+ if(addr >= (long) &dummy->u_debugreg[0] &&
+ addr <= (long) &dummy->u_debugreg[7]){
+
+ if(addr == (long) &dummy->u_debugreg[4]) return -EIO;
+ if(addr == (long) &dummy->u_debugreg[5]) return -EIO;
+ if(addr < (long) &dummy->u_debugreg[4] &&
+ ((unsigned long) data) >= 0xbffffffd) return -EIO;
+
+ if(addr == (long) &dummy->u_debugreg[7]) {
+ data &= ~DR_CONTROL_RESERVED;
+ for(i=0; i<4; i++)
+ if ((0x5f54 >> ((data >> (16 + 4*i)) & 0xf)) & 1)
+ return -EIO;
+ };
+
+ addr -= (long) &dummy->u_debugreg;
+ addr = addr >> 2;
+ child->debugreg[addr] = data;
+ return 0;
+ };
+ return -EIO;
case PTRACE_SYSCALL: /* continue and stop at next (return from) syscall */
case PTRACE_CONT: { /* restart after signal. */
diff --git a/kernel/sched.c b/kernel/sched.c
index 0cd5a3b..1b95bcb 100644
--- a/kernel/sched.c
+++ b/kernel/sched.c
@@ -30,6 +30,32 @@
#define TIMER_IRQ 0
+#include <linux/timex.h>
+
+/*
+ * kernel variables
+ */
+long tick = 1000000 / HZ; /* timer interrupt period */
+volatile struct timeval xtime; /* The current time */
+int tickadj = 500/HZ; /* microsecs */
+
+/*
+ * phase-lock loop variables
+ */
+int time_status = TIME_BAD; /* clock synchronization status */
+long time_offset = 0; /* time adjustment (us) */
+long time_constant = 0; /* pll time constant */
+long time_tolerance = MAXFREQ; /* frequency tolerance (ppm) */
+long time_precision = 1; /* clock precision (us) */
+long time_maxerror = 0x70000000;/* maximum error */
+long time_esterror = 0x70000000;/* estimated error */
+long time_phase = 0; /* phase offset (scaled us) */
+long time_freq = 0; /* frequency offset (scaled ppm) */
+long time_adj = 0; /* tick adjust (scaled 1 / HZ) */
+long time_reftime = 0; /* time at last adjustment (s) */
+
+long time_adjust = 0;
+
int need_resched = 0;
/*
@@ -38,7 +64,7 @@ int need_resched = 0;
int hard_math = 0; /* set by boot/head.S */
int x86 = 0; /* set by boot/head.S to 3 or 4 */
int ignore_irq13 = 0; /* set if exception 16 works */
-int wp_works_ok = 0; /* not used currently */
+int wp_works_ok = 0; /* set if paging hardware honours WP */
extern int _setitimer(int, struct itimerval *, struct itimerval *);
unsigned long * prof_buffer = NULL;
@@ -46,8 +72,6 @@ unsigned long prof_len = 0;
#define _S(nr) (1<<((nr)-1))
-#define LATCH ((1193180 + HZ/2)/HZ)
-
extern void mem_use(void);
extern int timer_interrupt(void);
@@ -57,12 +81,6 @@ static unsigned long init_kernel_stack[1024];
struct task_struct init_task = INIT_TASK;
unsigned long volatile jiffies=0;
-unsigned long startup_time=0;
-int jiffies_offset = 0; /* # clock ticks to add to get "true
- time". Should always be less than
- 1 second's worth. For time fanatics
- who like to syncronize their machines
- to WWV :-) */
struct task_struct *current = &init_task;
struct task_struct *last_task_used_math = NULL;
@@ -75,6 +93,47 @@ struct {
long * a;
short b;
} stack_start = { & user_stack [PAGE_SIZE>>2] , KERNEL_DS };
+
+/*
+ * int 0x80 entry points.. Moved away from the header file, as
+ * iBCS2 may also want to use the '<linux/sys.h>' headers..
+ */
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+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_unlink, sys_execve, sys_chdir, sys_time, sys_mknod, sys_chmod,
+sys_chown, sys_break, sys_stat, sys_lseek, sys_getpid, sys_mount,
+sys_umount, sys_setuid, sys_getuid, sys_stime, sys_ptrace, sys_alarm,
+sys_fstat, sys_pause, sys_utime, sys_stty, sys_gtty, sys_access,
+sys_nice, sys_ftime, sys_sync, sys_kill, sys_rename, sys_mkdir,
+sys_rmdir, sys_dup, sys_pipe, sys_times, sys_prof, sys_brk, sys_setgid,
+sys_getgid, sys_signal, sys_geteuid, sys_getegid, sys_acct, sys_phys,
+sys_lock, sys_ioctl, sys_fcntl, sys_mpx, sys_setpgid, sys_ulimit,
+sys_olduname, 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_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, sys_setitimer, sys_getitimer, sys_newstat, sys_newlstat,
+sys_newfstat, sys_uname, sys_iopl, sys_vhangup, sys_idle, sys_vm86,
+sys_wait4, sys_swapoff, sys_sysinfo, sys_ipc, sys_fsync, sys_sigreturn,
+sys_clone, sys_setdomainname, sys_newuname, sys_modify_ldt,
+sys_adjtimex};
+
+/* So we don't have to do any more manual updating.... */
+int NR_syscalls = sizeof(sys_call_table)/sizeof(fn_ptr);
+
+#ifdef __cplusplus
+}
+#endif
+
/*
* 'math_state_restore()' saves the current math information in the
* old math state array, and gets the new ones from the current task
@@ -103,6 +162,18 @@ asmlinkage void math_state_restore(void)
timer_active &= ~(1<<COPRO_TIMER);
}
+#ifndef CONFIG_MATH_EMULATION
+
+asmlinkage void math_emulate(long arg)
+{
+ printk("math-emulation not enabled and no coprocessor found.\n");
+ printk("killing %s.\n",current->comm);
+ send_sig(SIGFPE,current,1);
+ schedule();
+}
+
+#endif /* CONFIG_MATH_EMULATION */
+
/*
* 'schedule()' is the scheduler function. It's a very simple and nice
* scheduler: it's not perfect, but certainly works for most things.
@@ -167,6 +238,14 @@ confuse_gcc2:
p->counter = (p->counter >> 1) + p->priority;
}
switch_to(next);
+ /* Now maybe reload the debug registers */
+ if(current->debugreg[7]){
+ loaddebug(0);
+ loaddebug(1);
+ loaddebug(2);
+ loaddebug(3);
+ loaddebug(6);
+ };
}
asmlinkage int sys_pause(void)
@@ -355,6 +434,73 @@ static inline void calc_load(void)
}
/*
+ * this routine handles the overflow of the microsecond field
+ *
+ * The tricky bits of code to handle the accurate clock support
+ * were provided by Dave Mills (Mills@UDEL.EDU) of NTP fame.
+ * They were originally developed for SUN and DEC kernels.
+ * All the kudos should go to Dave for this stuff.
+ *
+ * These were ported to Linux by Philip Gladstone.
+ */
+static void second_overflow(void)
+{
+ long ltemp;
+ /* last time the cmos clock got updated */
+ static long last_rtc_update=0;
+ extern int set_rtc_mmss(unsigned long);
+
+ /* Bump the maxerror field */
+ time_maxerror = (0x70000000-time_maxerror < time_tolerance) ?
+ 0x70000000 : (time_maxerror + time_tolerance);
+
+ /* Run the PLL */
+ if (time_offset < 0) {
+ ltemp = (-(time_offset+1) >> (SHIFT_KG + time_constant)) + 1;
+ time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+ time_offset += (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
+ time_adj = - time_adj;
+ } else if (time_offset > 0) {
+ ltemp = ((time_offset-1) >> (SHIFT_KG + time_constant)) + 1;
+ time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE);
+ time_offset -= (time_adj * HZ) >> (SHIFT_SCALE - SHIFT_UPDATE);
+ } else {
+ time_adj = 0;
+ }
+
+ time_adj += (time_freq >> (SHIFT_KF + SHIFT_HZ - SHIFT_SCALE))
+ + FINETUNE;
+
+ /* Handle the leap second stuff */
+ switch (time_status) {
+ case TIME_INS:
+ /* ugly divide should be replaced */
+ if (xtime.tv_sec % 86400 == 0) {
+ xtime.tv_sec--; /* !! */
+ time_status = TIME_OOP;
+ printk("Clock: inserting leap second 23:59:60 GMT\n");
+ }
+ break;
+
+ case TIME_DEL:
+ /* ugly divide should be replaced */
+ if (xtime.tv_sec % 86400 == 86399) {
+ xtime.tv_sec++;
+ time_status = TIME_OK;
+ printk("Clock: deleting leap second 23:59:59 GMT\n");
+ }
+ break;
+
+ case TIME_OOP:
+ time_status = TIME_OK;
+ break;
+ }
+ if (xtime.tv_sec > last_rtc_update + 660)
+ if (set_rtc_mmss(xtime.tv_sec) == 0)
+ last_rtc_update = xtime.tv_sec;
+}
+
+/*
* The int argument is really a (struct pt_regs *), in case the
* interrupt wants to know from where it was called. The timer
* irq uses this to decide if it should update the user or system
@@ -366,6 +512,57 @@ static void do_timer(struct pt_regs * regs)
struct timer_struct *tp = timer_table+0;
struct task_struct * task_p;
+ long ltemp;
+
+ /* Advance the phase, once it gets to one microsecond, then
+ * advance the tick more.
+ */
+ time_phase += time_adj;
+ if (time_phase < -FINEUSEC) {
+ ltemp = -time_phase >> SHIFT_SCALE;
+ time_phase += ltemp << SHIFT_SCALE;
+ xtime.tv_usec += tick - ltemp;
+ }
+ else if (time_phase > FINEUSEC) {
+ ltemp = time_phase >> SHIFT_SCALE;
+ time_phase -= ltemp << SHIFT_SCALE;
+ xtime.tv_usec += tick + ltemp;
+ } else
+ xtime.tv_usec += tick;
+
+ if (time_adjust)
+ {
+ /* We are doing an adjtime thing.
+ */
+
+ /* Limit the amount of the step for *next* tick to be
+ * in the range -tickadj .. +tickadj
+ */
+ if (time_adjust > tickadj)
+ ltemp = tickadj;
+ else if (time_adjust < -tickadj)
+ ltemp = -tickadj;
+ else
+ ltemp = time_adjust;
+
+ /* Reduce the amount of time left by this step */
+ time_adjust -= ltemp;
+
+ /* Modify the value of the tick for next time.
+ * Note that a positive delta means we want the clock
+ * to run fast. This means that the tick should be bigger
+ */
+ tick = 1000000/HZ + ltemp;
+ }
+ else
+ tick = 1000000/HZ;
+
+ if (xtime.tv_usec >= 1000000) {
+ xtime.tv_usec -= 1000000;
+ xtime.tv_sec++;
+ second_overflow();
+ }
+
jiffies++;
calc_load();
if ((VM_MASK & regs->eflags) || (3 & regs->cs)) {
diff --git a/kernel/sys.c b/kernel/sys.c
index 310989e..45e33c8 100644
--- a/kernel/sys.c
+++ b/kernel/sys.c
@@ -4,11 +4,11 @@
* Copyright (C) 1991, 1992 Linus Torvalds
*/
+#include <linux/config.h>
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/tty.h>
#include <linux/kernel.h>
-#include <linux/config.h>
#include <linux/times.h>
#include <linux/utsname.h>
#include <linux/param.h>
@@ -17,6 +17,7 @@
#include <linux/string.h>
#include <linux/ptrace.h>
#include <linux/stat.h>
+#include <linux/mman.h>
#include <asm/segment.h>
#include <asm/io.h>
@@ -26,12 +27,6 @@
*/
static int C_A_D = 1;
-/*
- * The timezone where the local system is located. Used as a default by some
- * programs who obtain this value by using gettimeofday.
- */
-struct timezone sys_tz = { 0, 0};
-
extern int session_of_pgrp(int pgrp);
extern void adjust_clock(void);
@@ -328,20 +323,6 @@ asmlinkage int sys_old_syscall(void)
return -ENOSYS;
}
-asmlinkage int sys_time(long * tloc)
-{
- int i, error;
-
- i = CURRENT_TIME;
- if (tloc) {
- error = verify_area(VERIFY_WRITE, tloc, 4);
- if (error)
- return error;
- put_fs_long(i,(unsigned long *)tloc);
- }
- return i;
-}
-
/*
* Unprivileged users may change the real user id to the effective uid
* or vice versa. (BSD-style)
@@ -403,15 +384,6 @@ asmlinkage int sys_setuid(uid_t uid)
return(0);
}
-asmlinkage int sys_stime(long * tptr)
-{
- if (!suser())
- return -EPERM;
- startup_time = get_fs_long((unsigned long *)tptr) - jiffies/HZ;
- jiffies_offset = 0;
- return 0;
-}
-
asmlinkage int sys_times(struct tms * tbuf)
{
if (tbuf) {
@@ -436,12 +408,15 @@ asmlinkage int sys_brk(unsigned long brk)
return current->brk;
newbrk = PAGE_ALIGN(brk);
oldbrk = PAGE_ALIGN(current->brk);
+ if (oldbrk == newbrk)
+ return current->brk = brk;
+
/*
* Always allow shrinking brk
*/
if (brk <= current->brk) {
current->brk = brk;
- unmap_page_range(newbrk, oldbrk-newbrk);
+ do_munmap(newbrk, oldbrk-newbrk);
return brk;
}
/*
@@ -474,7 +449,9 @@ asmlinkage int sys_brk(unsigned long brk)
* Ok, we have probably got enough memory - let it rip.
*/
current->brk = brk;
- zeromap_page_range(oldbrk, newbrk-oldbrk, PAGE_COPY);
+ do_mmap(NULL, oldbrk, newbrk-oldbrk,
+ PROT_READ|PROT_WRITE|PROT_EXEC,
+ MAP_FIXED|MAP_PRIVATE, 0);
return brk;
}
@@ -768,126 +745,6 @@ asmlinkage int sys_getrusage(int who, struct rusage *ru)
return getrusage(current, who, ru);
}
-#define LATCH ((1193180 + HZ/2)/HZ)
-
-/*
- * This version of gettimeofday has near microsecond resolution.
- * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
- */
-static inline void do_gettimeofday(struct timeval *tv)
-{
- unsigned long nowtime;
- long count;
-
-#ifdef __i386__
- cli();
- /* timer count may underflow right here */
- outb_p(0x00, 0x43); /* latch the count ASAP */
- nowtime = jiffies; /* must be saved inside cli/sti */
- count = inb_p(0x40); /* read the latched count */
- count |= inb_p(0x40) << 8;
- /* we know probability of underflow is always MUCH less than 1% */
- if (count < (LATCH - LATCH/100))
- sti();
- else {
- /* check for pending timer interrupt */
- outb_p(0x0a, 0x20);
- if (inb(0x20) & 1)
- nowtime++;
- sti();
- }
- nowtime += jiffies_offset;
- tv->tv_sec = startup_time + CT_TO_SECS(nowtime);
- /* the correction term is always in the range [0, 1) clocktick */
- tv->tv_usec = CT_TO_USECS(nowtime)
- + ((LATCH - 1) - count)*(1000000/HZ)/LATCH;
-#else /* not __i386__ */
- nowtime = jiffies + jiffes_offset;
- tv->tv_sec = startup_time + CT_TO_SECS(nowtime);
- tv->tv_usec = CT_TO_USECS(nowtime);
-#endif /* not __i386__ */
-}
-
-asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
-{
- int error;
-
- if (tv) {
- struct timeval ktv;
- error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
- if (error)
- return error;
- do_gettimeofday(&ktv);
- put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
- put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
- }
- if (tz) {
- error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
- if (error)
- return error;
- put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
- put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
- }
- return 0;
-}
-
-/*
- * The first time we set the timezone, we will warp the clock so that
- * it is ticking GMT time instead of local time. Presumably,
- * if someone is setting the timezone then we are running in an
- * environment where the programs understand about timezones.
- * This should be done at boot time in the /etc/rc script, as
- * soon as possible, so that the clock can be set right. Otherwise,
- * various programs will get confused when the clock gets warped.
- */
-asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
-{
- static int firsttime = 1;
-
- if (!suser())
- return -EPERM;
- if (tz) {
- sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
- sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
- if (firsttime) {
- firsttime = 0;
- if (!tv)
- adjust_clock();
- }
- }
- if (tv) {
- int sec, usec;
-
- sec = get_fs_long((unsigned long *)tv);
- usec = get_fs_long(((unsigned long *)tv)+1);
-
- startup_time = sec - jiffies/HZ;
- jiffies_offset = usec * HZ / 1000000 - jiffies%HZ;
- }
- return 0;
-}
-
-/*
- * Adjust the time obtained from the CMOS to be GMT time instead of
- * local time.
- *
- * This is ugly, but preferable to the alternatives. Otherwise we
- * would either need to write a program to do it in /etc/rc (and risk
- * confusion if the program gets run more than once; it would also be
- * hard to make the program warp the clock precisely n hours) or
- * compile in the timezone information into the kernel. Bad, bad....
- *
- * XXX Currently does not adjust for daylight savings time. May not
- * need to do anything, depending on how smart (dumb?) the BIOS
- * is. Blast it all.... the best thing to do not depend on the CMOS
- * clock at all, but get the time via NTP or timed if you're on a
- * network.... - TYT, 1/1/92
- */
-void adjust_clock(void)
-{
- startup_time += sys_tz.tz_minuteswest*60;
-}
-
asmlinkage int sys_umask(int mask)
{
int old = current->umask;
diff --git a/kernel/sys_call.S b/kernel/sys_call.S
index 1fefe05..b4d8373 100644
--- a/kernel/sys_call.S
+++ b/kernel/sys_call.S
@@ -75,6 +75,8 @@ signal = 12
blocked = 16
flags = 20
errno = 24
+dbgreg6 = 52
+dbgreg7 = 56
ENOSYS = 38
@@ -104,10 +106,15 @@ ENOSYS = 38
mov %dx,%ds; \
mov %dx,%es; \
movl $(USER_DS),%edx; \
- mov %dx,%fs
+ mov %dx,%fs;
#define RESTORE_ALL \
- popl %ebx; \
+ cmpw $(KERNEL_CS),CS(%esp); \
+ je 1f; \
+ movl _current,%eax; \
+ movl dbgreg7(%eax),%ebx; \
+ movl %ebx,%db7; \
+1: popl %ebx; \
popl %ecx; \
popl %edx; \
popl %esi; \
@@ -161,6 +168,8 @@ _system_call:
movl _current,%ebx
andl $~CF_MASK,EFLAGS(%esp) # clear carry - assume no errors
movl $0,errno(%ebx)
+ movl %db6,%edx
+ movl %edx,dbgreg6(%ebx) # save current hardware debugging status
testb $0x20,flags(%ebx) # PF_TRACESYS
jne 1f
call _sys_call_table(,%eax,4)
@@ -253,6 +262,8 @@ error_code:
pushl %edx
pushl %ecx
pushl %ebx
+ movl $0,%eax
+ movl %eax,%db7 # disable hardware debugging...
cld
movl $-1, %eax
xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. )
@@ -267,6 +278,11 @@ error_code:
mov %dx,%es
movl $(USER_DS),%edx
mov %dx,%fs
+ pushl %eax
+ movl _current,%eax
+ movl %db6,%edx
+ movl %edx,dbgreg6(%eax) # save current hardware debugging status
+ popl %eax
call *%ebx
addl $8,%esp
jmp ret_from_sys_call
diff --git a/kernel/time.c b/kernel/time.c
new file mode 100644
index 0000000..f7b20fe
--- /dev/null
+++ b/kernel/time.c
@@ -0,0 +1,428 @@
+/*
+ * linux/kernel/time.c
+ *
+ * Copyright (C) 1991, 1992 Linus Torvalds
+ *
+ * This file contains the interface functions for the various
+ * time related system calls: time, stime, gettimeofday, settimeofday,
+ * adjtime
+ */
+/*
+ * Modification history kernel/time.c
+ *
+ * 02 Sep 93 Philip Gladstone
+ * Created file with time related functions from sched.c and adjtimex()
+ * 08 Oct 93 Torsten Duwe
+ * adjtime interface update and CMOS clock write code
+ */
+
+#include <linux/config.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include <linux/kernel.h>
+#include <linux/param.h>
+#include <linux/string.h>
+
+#include <asm/segment.h>
+#include <asm/io.h>
+
+#include <linux/mc146818rtc.h>
+#define RTC_ALWAYS_BCD 1
+
+#include <linux/timex.h>
+extern struct timeval xtime;
+
+#include <linux/mktime.h>
+extern long kernel_mktime(struct mktime * time);
+
+void time_init(void)
+{
+ struct mktime time;
+ int i;
+
+ /* checking for Update-In-Progress could be done more elegantly
+ * (using the "update finished"-interrupt for example), but that
+ * would require excessive testing. promise I'll do that when I find
+ * the time. - Torsten
+ */
+ /* read RTC exactly on falling edge of update flag */
+ for (i = 0 ; i < 1000000 ; i++) /* may take up to 1 second... */
+ if (CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP)
+ break;
+ for (i = 0 ; i < 1000000 ; i++) /* must try at least 2.228 ms*/
+ if (!(CMOS_READ(RTC_FREQ_SELECT) & RTC_UIP))
+ break;
+ do { /* Isn't this overkill ? UIP above should guarantee consistency */
+ time.sec = CMOS_READ(RTC_SECONDS);
+ time.min = CMOS_READ(RTC_MINUTES);
+ time.hour = CMOS_READ(RTC_HOURS);
+ time.day = CMOS_READ(RTC_DAY_OF_MONTH);
+ time.mon = CMOS_READ(RTC_MONTH);
+ time.year = CMOS_READ(RTC_YEAR);
+ } while (time.sec != CMOS_READ(RTC_SECONDS));
+ if (!(CMOS_READ(RTC_CONTROL) & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BCD_TO_BIN(time.sec);
+ BCD_TO_BIN(time.min);
+ BCD_TO_BIN(time.hour);
+ BCD_TO_BIN(time.day);
+ BCD_TO_BIN(time.mon);
+ BCD_TO_BIN(time.year);
+ }
+ time.mon--;
+ xtime.tv_sec = kernel_mktime(&time);
+ }
+/*
+ * The timezone where the local system is located. Used as a default by some
+ * programs who obtain this value by using gettimeofday.
+ */
+struct timezone sys_tz = { 0, 0};
+
+asmlinkage int sys_time(long * tloc)
+{
+ int i, error;
+
+ i = CURRENT_TIME;
+ if (tloc) {
+ error = verify_area(VERIFY_WRITE, tloc, 4);
+ if (error)
+ return error;
+ put_fs_long(i,(unsigned long *)tloc);
+ }
+ return i;
+}
+
+asmlinkage int sys_stime(long * tptr)
+{
+ if (!suser())
+ return -EPERM;
+ cli();
+ xtime.tv_sec = get_fs_long((unsigned long *) tptr);
+ xtime.tv_usec = 0;
+ time_status = TIME_BAD;
+ time_maxerror = 0x70000000;
+ time_esterror = 0x70000000;
+ sti();
+ return 0;
+}
+
+/* This function must be called with interrupts disabled
+ * It was inspired by Steve McCanne's microtime-i386 for BSD. -- jrs
+ *
+ * However, the pc-audio speaker driver changes the divisor so that
+ * it gets interrupted rather more often - it loads 64 into the
+ * counter rather than 11932! This has an adverse impact on
+ * do_gettimeoffset() -- it stops working! What is also not
+ * good is that the interval that our timer function gets called
+ * is no longer 10.0002 msecs, but 9.9767 msec. To get around this
+ * would require using a different timing source. Maybe someone
+ * could use the RTC - I know that this can interrupt at frequencies
+ * ranging from 8192Hz to 2Hz. If I had the energy, I'd somehow fix
+ * it so that at startup, the timer code in sched.c would select
+ * using either the RTC or the 8253 timer. The decision would be
+ * based on whether there was any other device around that needed
+ * to trample on the 8253. I'd set up the RTC to interrupt at 1024Hz,
+ * and then do some jiggery to have a version of do_timer that
+ * advanced the clock by 1/1024 sec. Every time that reached over 1/100
+ * of a second, then do all the old code. If the time was kept correct
+ * then do_gettimeoffset could just return 0 - there is no low order
+ * divider that can be accessed.
+ *
+ * Ideally, you would be able to use the RTC for the speaker driver,
+ * but it appears that the speaker driver really needs interrupt more
+ * often than every 120us or so.
+ *
+ * Anyway, this needs more thought.... pjsg (28 Aug 93)
+ *
+ * If you are really that interested, you should be reading
+ * comp.protocols.time.ntp!
+ */
+
+#define TICK_SIZE tick
+
+static inline unsigned long do_gettimeoffset(void)
+{
+ int count;
+ unsigned long offset = 0;
+
+ /* timer count may underflow right here */
+ outb_p(0x00, 0x43); /* latch the count ASAP */
+ count = inb_p(0x40); /* read the latched count */
+ count |= inb(0x40) << 8;
+ /* we know probability of underflow is always MUCH less than 1% */
+ if (count > (LATCH - LATCH/100)) {
+ /* check for pending timer interrupt */
+ outb_p(0x0a, 0x20);
+ if (inb(0x20) & 1)
+ offset = TICK_SIZE;
+ }
+ count = ((LATCH-1) - count) * TICK_SIZE;
+ count = (count + LATCH/2) / LATCH;
+ return offset + count;
+}
+
+/*
+ * This version of gettimeofday has near microsecond resolution.
+ */
+static inline void do_gettimeofday(struct timeval *tv)
+{
+#ifdef __i386__
+ cli();
+ *tv = xtime;
+ tv->tv_usec += do_gettimeoffset();
+ if (tv->tv_usec >= 1000000) {
+ tv->tv_usec -= 1000000;
+ tv->tv_sec++;
+ }
+ sti();
+#else /* not __i386__ */
+ cli();
+ *tv = xtime;
+ sti();
+#endif /* not __i386__ */
+}
+
+asmlinkage int sys_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+ int error;
+
+ if (tv) {
+ struct timeval ktv;
+ error = verify_area(VERIFY_WRITE, tv, sizeof *tv);
+ if (error)
+ return error;
+ do_gettimeofday(&ktv);
+ put_fs_long(ktv.tv_sec, (unsigned long *) &tv->tv_sec);
+ put_fs_long(ktv.tv_usec, (unsigned long *) &tv->tv_usec);
+ }
+ if (tz) {
+ error = verify_area(VERIFY_WRITE, tz, sizeof *tz);
+ if (error)
+ return error;
+ put_fs_long(sys_tz.tz_minuteswest, (unsigned long *) tz);
+ put_fs_long(sys_tz.tz_dsttime, ((unsigned long *) tz)+1);
+ }
+ return 0;
+}
+
+/*
+ * Adjust the time obtained from the CMOS to be GMT time instead of
+ * local time.
+ *
+ * This is ugly, but preferable to the alternatives. Otherwise we
+ * would either need to write a program to do it in /etc/rc (and risk
+ * confusion if the program gets run more than once; it would also be
+ * hard to make the program warp the clock precisely n hours) or
+ * compile in the timezone information into the kernel. Bad, bad....
+ *
+ * XXX Currently does not adjust for daylight savings time. May not
+ * need to do anything, depending on how smart (dumb?) the BIOS
+ * is. Blast it all.... the best thing to do not depend on the CMOS
+ * clock at all, but get the time via NTP or timed if you're on a
+ * network.... - TYT, 1/1/92
+ */
+inline static void warp_clock(void)
+{
+ cli();
+ xtime.tv_sec += sys_tz.tz_minuteswest * 60;
+ sti();
+}
+
+/*
+ * The first time we set the timezone, we will warp the clock so that
+ * it is ticking GMT time instead of local time. Presumably,
+ * if someone is setting the timezone then we are running in an
+ * environment where the programs understand about timezones.
+ * This should be done at boot time in the /etc/rc script, as
+ * soon as possible, so that the clock can be set right. Otherwise,
+ * various programs will get confused when the clock gets warped.
+ */
+asmlinkage int sys_settimeofday(struct timeval *tv, struct timezone *tz)
+{
+ static int firsttime = 1;
+
+ if (!suser())
+ return -EPERM;
+ if (tz) {
+ sys_tz.tz_minuteswest = get_fs_long((unsigned long *) tz);
+ sys_tz.tz_dsttime = get_fs_long(((unsigned long *) tz)+1);
+ if (firsttime) {
+ firsttime = 0;
+ if (!tv)
+ warp_clock();
+ }
+ }
+ if (tv) {
+ int sec, usec;
+
+ sec = get_fs_long((unsigned long *)tv);
+ usec = get_fs_long(((unsigned long *)tv)+1);
+
+ cli();
+ /* This is revolting. We need to set the xtime.tv_usec
+ * correctly. However, the value in this location is
+ * is value at the last tick.
+ * Discover what correction gettimeofday
+ * would have done, and then undo it!
+ */
+ usec -= do_gettimeoffset();
+
+ if (usec < 0)
+ {
+ usec += 1000000;
+ sec--;
+ }
+ xtime.tv_sec = sec;
+ xtime.tv_usec = usec;
+ time_status = TIME_BAD;
+ time_maxerror = 0x70000000;
+ time_esterror = 0x70000000;
+ sti();
+ }
+ return 0;
+}
+
+/* adjtimex mainly allows reading (and writing, if superuser) of
+ * kernel time-keeping variables. used by xntpd.
+ */
+asmlinkage int sys_adjtimex(struct timex *txc_p)
+{
+ long ltemp, mtemp, save_adjust;
+ int error;
+
+ /* Local copy of parameter */
+ struct timex txc;
+
+ error = verify_area(VERIFY_WRITE, txc_p, sizeof(struct timex));
+ if (error)
+ return error;
+
+ /* Copy the user data space into the kernel copy
+ * structure. But bear in mind that the structures
+ * may change
+ */
+ memcpy_fromfs(&txc, txc_p, sizeof(struct timex));
+
+ /* In order to modify anything, you gotta be super-user! */
+ if (txc.mode && !suser())
+ return -EPERM;
+
+ /* Now we validate the data before disabling interrupts
+ */
+
+ if (txc.mode & ADJ_OFFSET)
+ /* Microsec field limited to -131000 .. 131000 usecs */
+ if (txc.offset <= -(1 << (31 - SHIFT_UPDATE))
+ || txc.offset >= (1 << (31 - SHIFT_UPDATE)))
+ return -EINVAL;
+
+ /* time_status must be in a fairly small range */
+ if (txc.mode & ADJ_STATUS)
+ if (txc.status < TIME_OK || txc.status > TIME_BAD)
+ return -EINVAL;
+
+ cli();
+
+ /* Save for later - semantics of adjtime is to return old value */
+ save_adjust = time_adjust;
+
+ /* If there are input parameters, then process them */
+ if (txc.mode)
+ {
+ if (time_status == TIME_BAD)
+ time_status = TIME_OK;
+
+ if (txc.mode & ADJ_STATUS)
+ time_status = txc.status;
+
+ if (txc.mode & ADJ_FREQUENCY)
+ time_freq = txc.frequency;
+
+ if (txc.mode & ADJ_MAXERROR)
+ time_maxerror = txc.maxerror;
+
+ if (txc.mode & ADJ_ESTERROR)
+ time_esterror = txc.esterror;
+
+ if (txc.mode & ADJ_TIMECONST)
+ time_constant = txc.time_constant;
+
+ if (txc.mode & ADJ_OFFSET)
+ {
+ time_offset = txc.offset << SHIFT_UPDATE;
+ mtemp = xtime.tv_sec - time_reftime;
+ time_reftime = xtime.tv_sec;
+ if (mtemp > (MAXSEC+2) || mtemp < 0)
+ mtemp = 0;
+
+ if (txc.offset < 0)
+ time_freq -= (-txc.offset * mtemp) >>
+ (time_constant + time_constant);
+ else
+ time_freq += (txc.offset * mtemp) >>
+ (time_constant + time_constant);
+
+ ltemp = time_tolerance << SHIFT_KF;
+
+ if (time_freq > ltemp)
+ time_freq = ltemp;
+ else if (time_freq < -ltemp)
+ time_freq = -ltemp;
+ }
+ }
+ txc.offset = save_adjust;
+ txc.frequency = time_freq;
+ txc.maxerror = time_maxerror;
+ txc.esterror = time_esterror;
+ txc.status = time_status;
+ txc.time_constant = time_constant;
+ txc.precision = time_precision;
+ txc.tolerance = time_tolerance;
+ txc.time = xtime;
+
+ sti();
+
+ memcpy_tofs(txc_p, &txc, sizeof(struct timex));
+ return time_status;
+}
+
+int set_rtc_mmss(unsigned long nowtime)
+{
+ int retval = 0;
+ short real_seconds = nowtime % 60, real_minutes = (nowtime / 60) % 60;
+ unsigned char save_control, save_freq_select, cmos_minutes;
+
+ save_control = CMOS_READ(RTC_CONTROL); /* tell the clock it's being set */
+ CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
+
+ save_freq_select = CMOS_READ(RTC_FREQ_SELECT); /* stop and reset prescaler */
+ CMOS_WRITE((save_freq_select|RTC_DIV_RESET2), RTC_FREQ_SELECT);
+
+ cmos_minutes = CMOS_READ(RTC_MINUTES);
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ BCD_TO_BIN(cmos_minutes);
+
+ /* since we're only adjusting minutes and seconds,
+ * don't interfere with hour overflow. This avoids
+ * messing with unknown time zones but requires your
+ * RTC not to be off by more than 30 minutes
+ */
+ if (((cmos_minutes < real_minutes) ?
+ (real_minutes - cmos_minutes) :
+ (cmos_minutes - real_minutes)) < 30)
+ {
+ if (!(save_control & RTC_DM_BINARY) || RTC_ALWAYS_BCD)
+ {
+ BIN_TO_BCD(real_seconds);
+ BIN_TO_BCD(real_minutes);
+ }
+ CMOS_WRITE(real_seconds,RTC_SECONDS);
+ CMOS_WRITE(real_minutes,RTC_MINUTES);
+ }
+ else
+ retval = -1;
+
+ CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
+ CMOS_WRITE(save_control, RTC_CONTROL);
+ return retval;
+}
diff --git a/kernel/traps.c b/kernel/traps.c
index e276cd4..111b443 100644
--- a/kernel/traps.c
+++ b/kernel/traps.c
@@ -118,6 +118,7 @@ asmlinkage void do_int3(struct pt_regs * regs, long error_code)
asmlinkage void do_nmi(struct pt_regs * regs, long error_code)
{
printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
+ printk("You probably have a hardware problem with your RAM chips\n");
}
asmlinkage void do_debug(struct pt_regs * regs, long error_code)
@@ -125,6 +126,15 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code)
if (current->flags & PF_PTRACED)
current->blocked &= ~(1 << (SIGTRAP-1));
send_sig(SIGTRAP, current, 1);
+ if((regs->cs & 3) == 0) {
+ /* If this is a kernel mode trap, then reset db7 and allow us to continue */
+ __asm__("movl $0,%%edx\n\t" \
+ "movl %%edx,%%db7\n\t" \
+ : /* no output */ \
+ : /* no input */ :"dx");
+
+ return;
+ };
die_if_kernel("debug",regs,error_code);
}
diff --git a/lib/malloc.c b/lib/malloc.c
index 4d14749..4cf5268 100644
--- a/lib/malloc.c
+++ b/lib/malloc.c
@@ -64,6 +64,7 @@
#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/string.h>
+#include <linux/malloc.h>
#include <asm/system.h>
diff --git a/mm/Makefile b/mm/Makefile
index ed3c2e3..510861c 100644
--- a/mm/Makefile
+++ b/mm/Makefile
@@ -14,7 +14,7 @@
.c.s:
$(CC) $(CFLAGS) -S $<
-OBJS = memory.o swap.o mmap.o
+OBJS = memory.o swap.o mmap.o vmalloc.o
mm.o: $(OBJS)
$(LD) -r -o mm.o $(OBJS)
diff --git a/mm/memory.c b/mm/memory.c
index 5fe17a4..1ea52f1 100644
--- a/mm/memory.c
+++ b/mm/memory.c
@@ -29,6 +29,7 @@
*/
#include <asm/system.h>
+#include <linux/config.h>
#include <linux/signal.h>
#include <linux/sched.h>
@@ -42,6 +43,8 @@
unsigned long high_memory = 0;
+extern unsigned long pg0[1024]; /* page table for 0-4MB for everybody */
+
extern void sound_mem_init(void);
extern void die_if_kernel(char *,struct pt_regs *,long);
@@ -629,6 +632,7 @@ void do_wp_page(unsigned long error_code, unsigned long address,
return;
if (!(page & PAGE_COW)) {
if (user_esp && tsk == current) {
+ current->tss.cr2 = address;
send_sig(SIGSEGV, tsk, 1);
return;
}
@@ -654,7 +658,7 @@ int verify_area(int type, void * addr, unsigned long size)
return -EFAULT;
if (size > TASK_SIZE - start)
return -EFAULT;
- if (type == VERIFY_READ || !size)
+ if (wp_works_ok || type == VERIFY_READ || !size)
return 0;
if (!size)
return 0;
@@ -846,10 +850,10 @@ void do_no_page(unsigned long error_code, unsigned long address,
return;
}
address &= 0xfffff000;
- for (mpnt = tsk->mmap ; mpnt ; mpnt = mpnt->vm_next) {
+ for (mpnt = tsk->mmap; mpnt != NULL; mpnt = mpnt->vm_next) {
if (address < mpnt->vm_start)
continue;
- if (address >= ((mpnt->vm_end + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
+ if (address >= mpnt->vm_end)
continue;
if (!mpnt->vm_ops || !mpnt->vm_ops->nopage)
break;
@@ -863,8 +867,9 @@ void do_no_page(unsigned long error_code, unsigned long address,
if (address >= tsk->end_data && address < tsk->brk)
return;
if (address+8192 >= (user_esp & 0xfffff000) &&
- address <= current->start_stack)
+ address <= tsk->start_stack)
return;
+ current->tss.cr2 = address;
send_sig(SIGSEGV,tsk,1);
return;
}
@@ -899,16 +904,36 @@ asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code)
if (!user_esp)
return;
stack_limit = current->rlim[RLIMIT_STACK].rlim_cur;
- if (stack_limit >= RLIM_INFINITY)
- return;
- if (stack_limit >= current->start_stack)
- return;
- stack_limit = current->start_stack - stack_limit;
- if (user_esp < stack_limit)
+ if (stack_limit >= RLIM_INFINITY ||
+ stack_limit >= current->start_stack ||
+ user_esp >= (current->start_stack - stack_limit)) {
+#if 0
+ if (current->stk_vma != NULL) {
+ if (current->stk_vma->vm_start > user_esp)
+ current->stk_vma->vm_start = user_esp & PAGE_MASK;
+ } else
+ printk("do_no_page: no stack segment\n");
+#endif
+ } else {
+ current->tss.cr2 = address;
send_sig(SIGSEGV, current, 1);
+ }
return;
}
- printk("Unable to handle kernel paging request at address %08x\n",address);
+ if (error_code & PAGE_RW) {
+ if (!wp_works_ok) {
+ wp_works_ok = 1;
+ pg0[0] = PAGE_SHARED;
+ printk("This processor honours the WP bit even when in supervisor mode. Good.\n");
+ return;
+ }
+ printk("Unable to handle kernel paging WP error");
+ } else if (address < PAGE_SIZE) {
+ printk("Unable to handle kernel NULL pointer dereference");
+ pg0[0] = PAGE_SHARED;
+ } else
+ printk("Unable to handle kernel paging request");
+ printk(" at address %08x\n",address);
die_if_kernel("Oops", regs, error_code);
do_exit(SIGKILL);
}
@@ -1024,7 +1049,7 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem)
pg_dir++;
pg_table = (unsigned long *) (tmp & PAGE_MASK);
for (tmp = 0 ; tmp < PTRS_PER_PAGE ; tmp++,pg_table++) {
- if (address && address < end_mem)
+ if (address < end_mem)
*pg_table = address | PAGE_SHARED;
else
*pg_table = 0;
@@ -1066,7 +1091,9 @@ void mem_init(unsigned long start_low_mem,
mem_map[MAP_NR(start_mem)] = 0;
start_mem += PAGE_SIZE;
}
+#ifdef CONFIG_SOUND
sound_mem_init();
+#endif
free_page_list = 0;
nr_free_pages = 0;
for (tmp = 0 ; tmp < end_mem ; tmp += PAGE_SIZE) {
@@ -1090,6 +1117,10 @@ void mem_init(unsigned long start_low_mem,
codepages << (PAGE_SHIFT-10),
reservedpages << (PAGE_SHIFT-10),
datapages << (PAGE_SHIFT-10));
+ pg0[0] = PAGE_READONLY;
+ *((char *) 0) = 0; /* test if the WP bit is honoured in supervisor mode */
+ pg0[0] = 0;
+ invalidate();
return;
}
@@ -1124,12 +1155,10 @@ void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned lon
{
struct inode * inode = area->vm_inode;
unsigned int block;
- unsigned int clear;
unsigned long page;
- unsigned long tmp;
int nr[8];
int i, j;
- int prot = area->vm_page_prot; /* prot for buffer cache.. */
+ int prot = area->vm_page_prot;
address &= PAGE_MASK;
block = address - area->vm_start + area->vm_offset;
@@ -1149,30 +1178,15 @@ void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned lon
}
for (i=0, j=0; i< PAGE_SIZE ; j++, block++, i += inode->i_sb->s_blocksize)
nr[j] = bmap(inode,block);
-
- /*
- * If we don't mmap a whole page, we have to clear the end of the page,
- * which also means that we can't share the page with the buffer cache.
- * This is easy to handle by giving the 'bread_page()' a protection mask
- * that contains PAGE_RW, as the cache code won't try to share then..
- */
- clear = 0;
- if (address + PAGE_SIZE > area->vm_end) {
- clear = address + PAGE_SIZE - area->vm_end;
- prot |= PAGE_RW;
- }
+ if (error_code & PAGE_RW)
+ prot |= PAGE_RW | PAGE_DIRTY;
page = bread_page(page, inode->i_dev, nr, inode->i_sb->s_blocksize, prot);
- if (!(error_code & PAGE_RW)) {
+ if (!(prot & PAGE_RW)) {
if (share_page(area, area->vm_task, inode, address, error_code, page))
return;
}
-
- tmp = page + PAGE_SIZE;
- while (clear--) {
- *(char *)--tmp = 0;
- }
- if (put_page(area->vm_task,page,address,area->vm_page_prot))
+ if (put_page(area->vm_task,page,address,prot))
return;
free_page(page);
oom(current);
@@ -1216,4 +1230,5 @@ struct vm_operations_struct file_mmap = {
file_mmap_nopage, /* nopage */
NULL, /* wppage */
file_mmap_share, /* share */
+ NULL, /* unmap */
};
diff --git a/mm/mmap.c b/mm/mmap.c
index e84fe47..11ed1a9 100644
--- a/mm/mmap.c
+++ b/mm/mmap.c
@@ -11,10 +11,14 @@
#include <linux/errno.h>
#include <linux/mman.h>
#include <linux/string.h>
+#include <linux/malloc.h>
#include <asm/segment.h>
#include <asm/system.h>
+static int anon_map(struct inode *, struct file *,
+ unsigned long, size_t, int,
+ unsigned long);
/*
* 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
@@ -40,6 +44,9 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
{
int mask, error;
+ if ((len = PAGE_ALIGN(len)) == 0)
+ return addr;
+
if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len)
return -EINVAL;
@@ -49,20 +56,20 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
* 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 -EACCES;
- /* fall through */
- case MAP_PRIVATE:
- if (!(file->f_mode & 1))
- return -EACCES;
- break;
-
- default:
- return -EINVAL;
- }
+ if (file != NULL)
+ switch (flags & MAP_TYPE) {
+ case MAP_SHARED:
+ if ((prot & PROT_WRITE) && !(file->f_mode & 2))
+ return -EACCES;
+ /* fall through */
+ case MAP_PRIVATE:
+ if (!(file->f_mode & 1))
+ return -EACCES;
+ break;
+ default:
+ return -EINVAL;
+ }
/*
* obtain the address to map to. we verify (or select) it and ensure
* that it represents a valid section of the address space.
@@ -72,7 +79,7 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
if (addr & ~PAGE_MASK)
return -EINVAL;
if (len > TASK_SIZE || addr > TASK_SIZE - len)
- return -ENOMEM;
+ return -EINVAL;
} else {
struct vm_area_struct * vmm;
@@ -97,9 +104,9 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
/*
* determine the object being mapped and call the appropriate
* specific mapper. the address has already been validated, but
- * not unmapped
+ * not unmapped, but the maps are removed from the list.
*/
- if (!file->f_op || !file->f_op->mmap)
+ if (file && (!file->f_op || !file->f_op->mmap))
return -ENODEV;
mask = 0;
if (prot & (PROT_READ | PROT_EXEC))
@@ -112,7 +119,13 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
if (!mask)
return -EINVAL;
- error = file->f_op->mmap(file->f_inode, file, addr, len, mask, off);
+ do_munmap(addr, len); /* Clear old maps */
+
+ if (file)
+ error = file->f_op->mmap(file->f_inode, file, addr, len, mask, off);
+ else
+ error = anon_map(NULL, NULL, addr, len, mask, off);
+
if (!error)
return addr;
@@ -123,9 +136,13 @@ int do_mmap(struct file * file, unsigned long addr, unsigned long len,
asmlinkage int sys_mmap(unsigned long *buffer)
{
+ int error;
unsigned long fd;
struct file * file;
+ error = verify_area(VERIFY_READ, buffer, 6*4);
+ if (error)
+ return error;
fd = get_fs_long(buffer+4);
if (fd >= NR_OPEN || !(file = current->filp[fd]))
return -EBADF;
@@ -133,60 +150,156 @@ asmlinkage int sys_mmap(unsigned long *buffer)
get_fs_long(buffer+2), get_fs_long(buffer+3), get_fs_long(buffer+5));
}
+/*
+ * Normal function to fix up a mapping
+ * This function is the default for when an area has no specific
+ * function. This may be used as part of a more specific routine.
+ * This function works out what part of an area is affected and
+ * adjusts the mapping information. Since the actual page
+ * manipulation is done in do_mmap(), none need be done here,
+ * though it would probably be more appropriate.
+ *
+ * By the time this function is called, the area struct has been
+ * removed from the process mapping list, so it needs to be
+ * reinserted if necessary.
+ *
+ * The 4 main cases are:
+ * Unmapping the whole area
+ * Unmapping from the start of the segment to a point in it
+ * Unmapping from an intermediate point to the end
+ * Unmapping between to intermediate points, making a hole.
+ *
+ * Case 4 involves the creation of 2 new areas, for each side of
+ * the hole.
+ */
+void unmap_fixup(struct vm_area_struct *area,
+ unsigned long addr, size_t len)
+{
+ struct vm_area_struct *mpnt;
+ unsigned long end = addr + len;
+
+ if (addr < area->vm_start || addr >= area->vm_end ||
+ end <= area->vm_start || end > area->vm_end ||
+ end < addr)
+ {
+ printk("unmap_fixup: area=%x-%x, unmap %x-%x!!\n",
+ area->vm_start, area->vm_end, addr, end);
+ return;
+ }
+
+ /* Unmapping the whole area */
+ if (addr == area->vm_start && end == area->vm_end)
+ {
+ if (area->vm_ops && area->vm_ops->close)
+ area->vm_ops->close(area);
+ return;
+ }
+
+ /* Work out to one of the ends */
+ if (addr >= area->vm_start && end == area->vm_end)
+ area->vm_end = addr;
+ if (addr == area->vm_start && end <= area->vm_end)
+ area->vm_start = end;
+
+ /* Unmapping a hole */
+ if (addr > area->vm_start && end < area->vm_end)
+ {
+ /* Add end mapping -- leave beginning for below */
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+
+ *mpnt = *area;
+ mpnt->vm_start = end;
+ if (mpnt->vm_inode)
+ mpnt->vm_inode->i_count++;
+ insert_vm_struct(current, mpnt);
+ area->vm_end = addr; /* Truncate area */
+ }
+
+ /* construct whatever mapping is needed */
+ mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL);
+ *mpnt = *area;
+ insert_vm_struct(current, mpnt);
+}
+
+
+asmlinkage int sys_mprotect(unsigned long addr, size_t len, unsigned long prot)
+{
+ return -EINVAL; /* Not implemented yet */
+}
+
asmlinkage int sys_munmap(unsigned long addr, size_t len)
{
- struct vm_area_struct *mpnt, **p, *free;
+ return do_munmap(addr, len);
+}
+
+/*
+ * Munmap is split into 2 main parts -- this part which finds
+ * what needs doing, and the areas themselves, which do the
+ * work. This now handles partial unmappings.
+ * Jeremy Fitzhardine <jeremy@sw.oz.au>
+ */
+int do_munmap(unsigned long addr, size_t len)
+{
+ struct vm_area_struct *mpnt, **npp, *free;
- if ((addr & ~PAGE_MASK) || addr > LONG_MAX || addr == 0 || addr + len > TASK_SIZE)
+ if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr)
return -EINVAL;
- /* This needs a bit of work - we need to figure out how to
- deal with areas that overlap with something that we are using */
+ if ((len = PAGE_ALIGN(len)) == 0)
+ return 0;
- p = &current->mmap;
- free = NULL;
/*
* Check if this memory area is ok - put it on the temporary
- * list if so..
+ * list if so.. The checks here are pretty simple --
+ * every area affected in some way (by any overlap) is put
+ * on the list. If nothing is put on, nothing is affected.
*/
- while ((mpnt = *p) != NULL) {
- if (addr > mpnt->vm_start && addr < mpnt->vm_end)
- goto bad_munmap;
- if (addr+len > mpnt->vm_start && addr + len < mpnt->vm_end)
- goto bad_munmap;
- if (addr <= mpnt->vm_start && addr + len >= mpnt->vm_end) {
- *p = mpnt->vm_next;
- mpnt->vm_next = free;
- free = mpnt;
+ npp = &current->mmap;
+ free = NULL;
+ for (mpnt = *npp; mpnt != NULL; mpnt = *npp) {
+ unsigned long end = addr+len;
+
+ if ((addr < mpnt->vm_start && end <= mpnt->vm_start) ||
+ (addr >= mpnt->vm_end && end > mpnt->vm_end))
+ {
+ npp = &mpnt->vm_next;
continue;
}
- p = &mpnt->vm_next;
+
+ *npp = mpnt->vm_next;
+ mpnt->vm_next = free;
+ free = mpnt;
}
+
+ if (free == NULL)
+ return 0;
+
/*
* Ok - we have the memory areas we should free on the 'free' list,
* so release them, and unmap the page range..
+ * If the one of the segments is only being partially unmapped,
+ * it will put new vm_area_struct(s) into the address space.
*/
while (free) {
+ unsigned long st, end;
+
mpnt = free;
free = free->vm_next;
- if (mpnt->vm_ops && mpnt->vm_ops->close)
- mpnt->vm_ops->close(mpnt);
+
+ st = addr < mpnt->vm_start ? mpnt->vm_start : addr;
+ end = addr+len;
+ end = end > mpnt->vm_end ? mpnt->vm_end : end;
+
+ if (mpnt->vm_ops && mpnt->vm_ops->unmap)
+ mpnt->vm_ops->unmap(mpnt, st, end-st);
+ else
+ unmap_fixup(mpnt, st, end-st);
+
kfree(mpnt);
}
unmap_page_range(addr, len);
return 0;
-bad_munmap:
-/*
- * the arguments we got were bad: put the temporary list back into the mmap list
- */
- while (free) {
- mpnt = free;
- free = free->vm_next;
- mpnt->vm_next = current->mmap;
- current->mmap = mpnt;
- }
- return -EINVAL;
}
/* This is used for a general mmap of a disk file */
@@ -227,8 +340,137 @@ int generic_mmap(struct inode * inode, struct file * file,
inode->i_count++;
mpnt->vm_offset = off;
mpnt->vm_ops = &file_mmap;
- mpnt->vm_next = current->mmap;
- current->mmap = mpnt;
+ insert_vm_struct(current, mpnt);
+ merge_segments(current->mmap, NULL, NULL);
+
+ return 0;
+}
+
+/*
+ * Insert vm structure into process list
+ * This makes sure the list is sorted by start address, and
+ * some some simple overlap checking.
+ * JSGF
+ */
+void insert_vm_struct(struct task_struct *t, struct vm_area_struct *vmp)
+{
+ struct vm_area_struct **nxtpp, *mpnt;
+
+ nxtpp = &t->mmap;
+
+ for(mpnt = t->mmap; mpnt != NULL; mpnt = mpnt->vm_next)
+ {
+ if (mpnt->vm_start > vmp->vm_start)
+ break;
+ nxtpp = &mpnt->vm_next;
+
+ if ((vmp->vm_start >= mpnt->vm_start &&
+ vmp->vm_start < mpnt->vm_end) ||
+ (vmp->vm_end >= mpnt->vm_start &&
+ vmp->vm_end < mpnt->vm_end))
+ printk("insert_vm_struct: ins area %x-%x in area %x-%x\n",
+ vmp->vm_start, vmp->vm_end,
+ mpnt->vm_start, vmp->vm_end);
+ }
+
+ vmp->vm_next = mpnt;
+
+ *nxtpp = vmp;
+}
+
+/*
+ * Merge a list of memory segments if possible.
+ * Redundant vm_area_structs are freed.
+ * This assumes that the list is ordered by address.
+ */
+void merge_segments(struct vm_area_struct *mpnt,
+ map_mergep_fnp mergep, void *mpd)
+{
+ struct vm_area_struct *prev, *next;
+
+ if (mpnt == NULL)
+ return;
+
+ for(prev = mpnt, mpnt = mpnt->vm_next;
+ mpnt != NULL;
+ prev = mpnt, mpnt = next)
+ {
+ int mp;
+
+ next = mpnt->vm_next;
+
+ if (mergep == NULL)
+ {
+ unsigned long psz = prev->vm_end - prev->vm_start;
+ mp = prev->vm_offset + psz == mpnt->vm_offset;
+ }
+ else
+ mp = (*mergep)(prev, mpnt, mpd);
+
+ /*
+ * Check they are compatible.
+ * and the like...
+ * What does the share pointer mean?
+ */
+ if (prev->vm_ops != mpnt->vm_ops ||
+ prev->vm_page_prot != mpnt->vm_page_prot ||
+ prev->vm_inode != mpnt->vm_inode ||
+ prev->vm_end != mpnt->vm_start ||
+ !mp ||
+ prev->vm_share != mpnt->vm_share || /* ?? */
+ prev->vm_next != mpnt) /* !!! */
+ continue;
+
+ /*
+ * merge prev with mpnt and set up pointers so the new
+ * big segment can possibly merge with the next one.
+ * The old unused mpnt is freed.
+ */
+ prev->vm_end = mpnt->vm_end;
+ prev->vm_next = mpnt->vm_next;
+ kfree_s(mpnt, sizeof(*mpnt));
+ mpnt = prev;
+ }
+}
+
+/*
+ * Map memory not associated with any file into a process
+ * address space. Adjecent memory is merged.
+ */
+static int anon_map(struct inode *ino, struct file * file,
+ unsigned long addr, size_t len, int mask,
+ unsigned long off)
+{
+ struct vm_area_struct * mpnt;
+
+ if (zeromap_page_range(addr, len, mask))
+ return -ENOMEM;
+
+ mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL);
+ if (!mpnt)
+ return -ENOMEM;
+
+ mpnt->vm_task = current;
+ mpnt->vm_start = addr;
+ mpnt->vm_end = addr + len;
+ mpnt->vm_page_prot = mask;
+ mpnt->vm_share = NULL;
+ mpnt->vm_inode = NULL;
+ mpnt->vm_offset = 0;
+ mpnt->vm_ops = NULL;
+ insert_vm_struct(current, mpnt);
+ merge_segments(current->mmap, ignoff_mergep, NULL);
+
return 0;
}
+/* Merge, ignoring offsets */
+int ignoff_mergep(const struct vm_area_struct *m1,
+ const struct vm_area_struct *m2,
+ void *data)
+{
+ if (m1->vm_inode != m2->vm_inode) /* Just to be sure */
+ return 0;
+
+ return (struct inode *)data == m1->vm_inode;
+}
diff --git a/mm/swap.c b/mm/swap.c
index 8869959..c885362 100644
--- a/mm/swap.c
+++ b/mm/swap.c
@@ -41,6 +41,7 @@ static struct swap_info_struct {
int pages;
int lowest_bit;
int highest_bit;
+ unsigned long max;
} swap_info[MAX_SWAPFILES];
extern unsigned long free_page_list;
@@ -53,8 +54,6 @@ extern int shm_swap (int);
#define NR_LAST_FREE_PAGES 32
static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,};
-#define SWAP_BITS PAGE_SIZE
-
void rw_swap_page(int rw, unsigned long entry, char * buf)
{
unsigned long type, offset;
@@ -67,7 +66,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
}
p = &swap_info[type];
offset = SWP_OFFSET(entry);
- if (offset >= SWAP_BITS) {
+ if (offset >= p->max) {
printk("rw_swap_page: weirdness\n");
return;
}
@@ -94,7 +93,7 @@ void rw_swap_page(int rw, unsigned long entry, char * buf)
ll_rw_swap_file(rw,p->swap_file->i_dev, zones, i,buf);
} else
printk("re_swap_page: no swap file or device\n");
- if (!clear_bit(offset,p->swap_lockmap))
+ if (offset && !clear_bit(offset,p->swap_lockmap))
printk("rw_swap_page: lock already cleared\n");
wake_up(&lock_queue);
}
@@ -138,7 +137,7 @@ unsigned long swap_duplicate(unsigned long entry)
return 0;
}
p = type + swap_info;
- if (offset >= SWAP_BITS) {
+ if (offset >= p->max) {
printk("swap_free: weirness\n");
return 0;
}
@@ -166,7 +165,7 @@ void swap_free(unsigned long entry)
}
p = & swap_info[type];
offset = SWP_OFFSET(entry);
- if (offset >= SWAP_BITS) {
+ if (offset >= p->max) {
printk("swap_free: weirness\n");
return;
}
@@ -700,7 +699,7 @@ asmlinkage int sys_swapoff(const char * specialfile)
iput(p->swap_file);
p->swap_file = NULL;
p->swap_device = 0;
- free_page((long) p->swap_map);
+ vfree(p->swap_map);
p->swap_map = NULL;
free_page((long) p->swap_lockmap);
p->swap_lockmap = NULL;
@@ -718,8 +717,8 @@ asmlinkage int sys_swapon(const char * specialfile)
struct swap_info_struct * p;
struct inode * swap_inode;
unsigned int type;
- unsigned char * tmp;
int i,j;
+ int error;
if (!suser())
return -EPERM;
@@ -738,102 +737,89 @@ asmlinkage int sys_swapon(const char * specialfile)
p->swap_lockmap = NULL;
p->lowest_bit = 0;
p->highest_bit = 0;
- i = namei(specialfile,&swap_inode);
- if (i) {
- p->flags = 0;
- return i;
- }
- if (swap_inode->i_count != 1) {
- iput(swap_inode);
- p->flags = 0;
- return -EBUSY;
- }
+ p->max = 1;
+ error = namei(specialfile,&swap_inode);
+ if (error)
+ goto bad_swap;
+ error = -EBUSY;
+ if (swap_inode->i_count != 1)
+ goto bad_swap;
+ error = -EINVAL;
if (S_ISBLK(swap_inode->i_mode)) {
p->swap_device = swap_inode->i_rdev;
iput(swap_inode);
- if (!p->swap_device) {
- p->flags = 0;
- return -ENODEV;
- }
+ error = -ENODEV;
+ if (!p->swap_device)
+ goto bad_swap;
+ error = -EBUSY;
for (i = 0 ; i < nr_swapfiles ; i++) {
if (i == type)
continue;
- if (p->swap_device == swap_info[i].swap_device) {
- p->swap_device = 0;
- p->flags = 0;
- return -EBUSY;
- }
+ if (p->swap_device == swap_info[i].swap_device)
+ goto bad_swap;
}
} else if (S_ISREG(swap_inode->i_mode))
p->swap_file = swap_inode;
- else {
- iput(swap_inode);
- p->flags = 0;
- return -EINVAL;
- }
- tmp = (unsigned char *) get_free_page(GFP_USER);
+ else
+ goto bad_swap;
p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER);
- if (!tmp || !p->swap_lockmap) {
+ if (!p->swap_lockmap) {
printk("Unable to start swapping: out of memory :-)\n");
- free_page((long) tmp);
- free_page((long) p->swap_lockmap);
- iput(p->swap_file);
- p->swap_device = 0;
- p->swap_file = NULL;
- p->swap_map = NULL;
- p->swap_lockmap = NULL;
- p->flags = 0;
- return -ENOMEM;
- }
- read_swap_page(SWP_ENTRY(type,0), (char *) tmp);
- if (memcmp("SWAP-SPACE",tmp+4086,10)) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+ read_swap_page(SWP_ENTRY(type,0), (char *) p->swap_lockmap);
+ if (memcmp("SWAP-SPACE",p->swap_lockmap+4086,10)) {
printk("Unable to find swap-space signature\n");
- free_page((long) tmp);
- free_page((long) p->swap_lockmap);
- iput(p->swap_file);
- p->swap_device = 0;
- p->swap_file = NULL;
- p->swap_map = NULL;
- p->swap_lockmap = NULL;
- p->flags = 0;
- return -EINVAL;
+ error = -EINVAL;
+ goto bad_swap;
}
- memset(tmp+PAGE_SIZE-10,0,10);
+ memset(p->swap_lockmap+PAGE_SIZE-10,0,10);
j = 0;
p->lowest_bit = 0;
p->highest_bit = 0;
- for (i = 1 ; i < SWAP_BITS ; i++)
- if (test_bit(i,tmp)) {
+ for (i = 1 ; i < 8*PAGE_SIZE ; i++) {
+ if (test_bit(i,p->swap_lockmap)) {
if (!p->lowest_bit)
p->lowest_bit = i;
p->highest_bit = i;
+ p->max = i+1;
j++;
}
+ }
if (!j) {
printk("Empty swap-file\n");
- free_page((long) tmp);
- free_page((long) p->swap_lockmap);
- iput(p->swap_file);
- p->swap_device = 0;
- p->swap_file = NULL;
- p->swap_map = NULL;
- p->swap_lockmap = NULL;
- p->flags = 0;
- return -EINVAL;
+ error = -EINVAL;
+ goto bad_swap;
}
- i = SWAP_BITS;
- while (i--)
- if (test_bit(i,tmp))
- tmp[i] = 0;
+ p->swap_map = vmalloc(p->max);
+ if (!p->swap_map) {
+ error = -ENOMEM;
+ goto bad_swap;
+ }
+ for (i = 1 ; i < p->max ; i++) {
+ if (test_bit(i,p->swap_lockmap))
+ p->swap_map[i] = 0;
else
- tmp[i] = 0x80;
- tmp[0] = 0x80;
- p->swap_map = tmp;
+ p->swap_map[i] = 0x80;
+ }
+ p->swap_map[0] = 0x80;
+ memset(p->swap_lockmap,0,PAGE_SIZE);
p->flags = SWP_WRITEOK;
p->pages = j;
nr_swap_pages += j;
printk("Adding Swap: %dk swap-space\n",j<<2);
return 0;
+bad_swap:
+ free_page((long) p->swap_lockmap);
+ vfree(p->swap_map);
+ iput(p->swap_file);
+ p->swap_device = 0;
+ p->swap_file = NULL;
+ p->swap_map = NULL;
+ p->swap_lockmap = NULL;
+ p->flags = 0;
+ return error;
}
void si_swapinfo(struct sysinfo *val)
@@ -844,7 +830,7 @@ void si_swapinfo(struct sysinfo *val)
for (i = 0; i < nr_swapfiles; i++) {
if (!(swap_info[i].flags & SWP_USED))
continue;
- for (j = 0; j < SWAP_BITS; ++j)
+ for (j = 0; j < swap_info[i].max; ++j)
switch (swap_info[i].swap_map[j]) {
case 128:
continue;
diff --git a/mm/vmalloc.c b/mm/vmalloc.c
new file mode 100644
index 0000000..c33ad8d
--- /dev/null
+++ b/mm/vmalloc.c
@@ -0,0 +1,164 @@
+/*
+ * linux/mm/vmalloc.c
+ *
+ * Copyright (C) 1993 Linus Torvalds
+ */
+
+#include <asm/system.h>
+#include <linux/config.h>
+
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/head.h>
+#include <linux/kernel.h>
+#include <linux/errno.h>
+#include <linux/types.h>
+#include <linux/malloc.h>
+
+struct vm_struct {
+ unsigned long flags;
+ void * addr;
+ unsigned long size;
+ struct vm_struct * next;
+};
+
+static struct vm_struct * vmlist = NULL;
+
+#define VMALLOC_OFFSET (8*1024*1024)
+
+static inline void set_pgdir(unsigned long dindex, unsigned long value)
+{
+ struct task_struct * p;
+
+ p = &init_task;
+ do {
+ ((unsigned long *) p->tss.cr3)[dindex] = value;
+ p = p->next_task;
+ } while (p != &init_task);
+}
+
+static int free_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
+{
+ unsigned long page, *pte;
+
+ if (!(PAGE_PRESENT & (page = swapper_pg_dir[dindex])))
+ return 0;
+ page &= PAGE_MASK;
+ pte = index + (unsigned long *) page;
+ for ( ; nr > 0 ; nr--, pte++) {
+ unsigned long pg = *pte;
+ *pte = 0;
+ if (!(pg & PAGE_PRESENT))
+ continue;
+ free_page(pg);
+ }
+ pte = (unsigned long *) page;
+ for (nr = 0 ; nr < 1024 ; nr++, pte++)
+ if (*pte)
+ return 0;
+ set_pgdir(dindex,0);
+ mem_map[MAP_NR(page)] &= ~MAP_PAGE_RESERVED;
+ free_page(page);
+ return 0;
+}
+
+static int alloc_area_pages(unsigned long dindex, unsigned long index, unsigned long nr)
+{
+ unsigned long page, *pte;
+
+ page = swapper_pg_dir[dindex];
+ if (!page) {
+ page = get_free_page(GFP_KERNEL);
+ if (!page)
+ return -ENOMEM;
+ if (swapper_pg_dir[dindex]) {
+ free_page(page);
+ page = swapper_pg_dir[dindex];
+ } else {
+ mem_map[MAP_NR(page)] |= MAP_PAGE_RESERVED;
+ set_pgdir(dindex, page | PAGE_SHARED);
+ }
+ }
+ page &= PAGE_MASK;
+ pte = index + (unsigned long *) page;
+ *pte = PAGE_SHARED; /* remove a race with vfree() */
+ for ( ; nr > 0 ; nr--, pte++) {
+ unsigned long pg = get_free_page(GFP_KERNEL);
+
+ if (!pg)
+ return -ENOMEM;
+ *pte = pg | PAGE_SHARED;
+ }
+ return 0;
+}
+
+static int do_area(void * addr, unsigned long size,
+ int (*area_fn)(unsigned long,unsigned long,unsigned long))
+{
+ unsigned long nr, dindex, index;
+
+ nr = size >> PAGE_SHIFT;
+ dindex = (TASK_SIZE + (unsigned long) addr) >> 22;
+ index = (((unsigned long) addr) >> PAGE_SHIFT) & (PTRS_PER_PAGE-1);
+ while (nr > 0) {
+ unsigned long i = PTRS_PER_PAGE - index;
+
+ if (i > nr)
+ i = nr;
+ if (area_fn(dindex, index, i))
+ return -1;
+ nr -= i;
+ index = 0;
+ }
+ return 0;
+}
+
+void vfree(void * addr)
+{
+ struct vm_struct **p, *tmp;
+
+ if (!addr)
+ return;
+ if ((PAGE_SIZE-1) & (unsigned long) addr) {
+ printk("Trying to vfree() bad address (%p)\n", addr);
+ return;
+ }
+ for (p = &vmlist ; (tmp = *p) ; p = &tmp->next) {
+ if (tmp->addr == addr) {
+ *p = tmp->next;
+ do_area(tmp->addr, tmp->size, free_area_pages);
+ kfree(tmp);
+ return;
+ }
+ }
+ printk("Trying to vfree() nonexistent vm area (%p)\n", addr);
+}
+
+void * vmalloc(unsigned long size)
+{
+ void * addr;
+ struct vm_struct **p, *tmp, *area;
+
+ size = PAGE_ALIGN(size);
+ if (!size || size > high_memory)
+ return NULL;
+ area = (struct vm_struct *) kmalloc(sizeof(*area), GFP_KERNEL);
+ if (!area)
+ return NULL;
+ addr = (void *) ((high_memory + VMALLOC_OFFSET) & ~(VMALLOC_OFFSET-1));
+ area->size = size + PAGE_SIZE;
+ area->next = NULL;
+ for (p = &vmlist; (tmp = *p) ; p = &tmp->next) {
+ if (size + (unsigned long) addr <= (unsigned long) tmp->addr)
+ break;
+ addr = (void *) (tmp->size + (unsigned long) tmp->addr);
+ }
+ area->addr = addr;
+ area->next = *p;
+ *p = area;
+ if (do_area(addr, size, alloc_area_pages)) {
+ vfree(addr);
+ return NULL;
+ }
+ return addr;
+}
diff --git a/net/Makefile b/net/Makefile
index 84c95da..6cfd584 100644
--- a/net/Makefile
+++ b/net/Makefile
@@ -10,7 +10,7 @@
# only these two lines should need to be changed to remove inet sockets.
# (and the inet/tcpip.o in net.o)
-DRIVERS = drv
+DRIVERS =
SUBDIRS := unix inet
.c.o:
@@ -25,16 +25,15 @@ OBJS = Space.o ddi.o socket.o
all: net.o
net.o: $(OBJS) subdirs
- $(LD) -r -o net.o $(OBJS) $(DRIVERS)/$(DRIVERS).a network.a
+ $(LD) -r -o net.o $(OBJS) network.a
subdirs: dummy
@rm -f network.a
- @for i in $(DRIVERS); do (cd $$i && echo $$i && $(MAKE) $$i.a) || exit; done
@for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) && ar rcs ../network.a $$i.o) || exit; done
@ranlib network.a
clean:
- rm -f core *.o *.a *.s .depend
+ rm -f core *.o *.a *.s
@for i in $(DRIVERS) $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) clean) || exit; done
dep:
diff --git a/net/Space.c b/net/Space.c
index e3505a9..59a3112 100644
--- a/net/Space.c
+++ b/net/Space.c
@@ -50,7 +50,7 @@ struct ddi_proto protocols[] = {
*
* WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!!
*/
-#include "drv/we8003/we8003.h" /* Western Digital WD-80[01]3 */
+/*#include "drv/we8003/we8003.h" Western Digital WD-80[01]3 */
/*#include "drv/dp8390/dp8390.h" Donald Becker's DP8390 kit */
/*#inclde "drv/slip/slip.h" Laurence Culhane's SLIP kit */
diff --git a/net/drv/Makefile b/net/drv/Makefile
deleted file mode 100644
index 0ef1d71..0000000
--- a/net/drv/Makefile
+++ /dev/null
@@ -1,47 +0,0 @@
-#
-# Makefile for the linux 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).
-#
-# Note 2! The CFLAGS definitions are now in the main makefile...
-
-OBJS =
-SUBDIRS = #we8003 slip dp8390
-
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-.s.o:
- $(AS) -o $*.o $<
-
-all: drv.a
-
-drv.a: $(OBJS) dummy
- @rm -f drv.a
- @$(AR) rcs drv.a
- @for i in $(SUBDIRS); do [ ! -d $$i ] || \
- (cd $$i && echo $$i && $(MAKE) && \
- $(AR) rcs ../drv.a $$i.o) || \
- exit; \
- done
-
-
-clean:
- rm -f core *.o *.a tmp_make .depend
- for i in *.c; do rm -f `basename $$i .c`.s;done
- for i in $(SUBDIRS); do ([ -d $$i ] && cd $$i && $(MAKE) clean); done
-
-dep:
- > .depend
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
-
-dummy:
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/net/drv/README b/net/drv/README
deleted file mode 100644
index ee91361..0000000
--- a/net/drv/README
+++ /dev/null
@@ -1,9 +0,0 @@
-
- The files and directories in this directory are under
- heavy construction, and are intended only for device
- driver writers to see how they should redo their code
- to make it fit into DDI.
-
- THESE DRIVERS ARE NOT YET OPERATIONAL !!!
-
- Fred, 05/07/93
diff --git a/net/drv/slip/Makefile b/net/drv/slip/Makefile
deleted file mode 100644
index d169e27..0000000
--- a/net/drv/slip/Makefile
+++ /dev/null
@@ -1,39 +0,0 @@
-#
-# Makefile for the SLIP device driver..
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-SUBDIRS =
-
-
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-
-
-slip.o: slip.c
-
-clean:
- rm -f core *.o *.a tmp_make keyboard.s
- for i in *.c;do rm -f `basename $$i .c`.s;done
-
-dep:
- $(CPP) -M *.c > .depend
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
-
-dummy:
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/net/drv/slip/slip.c b/net/drv/slip/slip.c
deleted file mode 100644
index f433af2..0000000
--- a/net/drv/slip/slip.c
+++ /dev/null
@@ -1,661 +0,0 @@
-/*
- * slip.c This module implements the SLIP protocol for kernel-based
- * devices like TTY. It interfaces between a raw TTY, and the
- * kernel's NET protocol layers (via DDI).
- *
- * Version: @(#)slip.c 0.5.0 (02/11/93)
- *
- * Authors: Laurence Culhane, <loz@holmes.demon.co.uk>
- * Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- */
-#include <asm/segment.h>
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/mm.h>
-#include <linux/socket.h>
-#include <linux/termios.h>
-#include <linux/tty.h>
-#include <linux/errno.h>
-#include <linux/stat.h>
-#include <linux/tty.h>
-#include <linux/slip.h>
-#include <netinet/in.h>
-
-
-#define SLIP_VERSION "0.5.0"
-#define SL_DUMP
-
-
-#define SL_DEBUG
-#ifdef SL_DEBUG
-# define PRINTK(x) printk x
-#else
-# define PRINTK(x) /**/
-#endif
-
-
-/* Define some IP layer stuff. Not all systems have it. */
-#ifdef SL_DUMP
-# define IP_VERSION 4 /* version# of our IP software */
-# define IPF_F_OFFSET 0x1fff /* Offset field */
-# define IPF_DF 0x4000 /* Don't fragment flag */
-# define IPF_MF 0x2000 /* More Fragments flag */
-
- typedef struct ipheader {
- u_char v_ihl; /* Version + IP header length */
- u_char tos; /* Type of service */
- u_short length; /* Total length */
- u_short id; /* Identification */
- u_short fl_offs; /* Flags + fragment offset */
- u_char ttl; /* Time to live */
- u_char protocol; /* Protocol */
- u_short checksum; /* Header checksum */
- u_long source; /* Source address */
- u_long dest; /* Destination address */
- } IP;
-# define IP_OF_COPIED 0x80 /* Copied-on-fragmentation flag */
-# define IP_OF_CLASS 0x60 /* Option class */
-# define IP_OF_NUMBER 0x1f /* Option number */
-# define IPO_EOL 0 /* End of options list */
-# define IPO_NOOP 1 /* No Operation */
-# define IPO_SECURITY 2 /* Security parameters */
-# define IPO_LSROUTE 3 /* Loose Source Routing */
-# define IPO_TIMESTAMP 4 /* Internet Timestamp */
-# define IPO_RROUTE 7 /* Record Route */
-# define IPO_STREAMID 8 /* Stream ID */
-# define IPO_SSROUTE 9 /* Strict Source Routing */
-# define IP_TS_ONLY 0 /* Time stamps only */
-# define IP_TS_ADDRESS 1 /* Addresses + Time stamps */
-# define IP_TS_PRESPEC 3 /* Prespecified addresses only */
-#endif
-
-
-/* This table holds the control blocks for all SLIP channels. */
-static struct slip sl_ctrl[SL_NRUNIT];
-
-
-#ifdef SL_DUMP
-/* Dump the contents of an IP datagram. */
-static void
-ip_dump(unsigned char *ptr, int len)
-{
- int hdr_ver, hdr_len, dta_len, dta_off;
- IP *ip;
- extern char *in_ntoa(long num);
-
- ip = (IP *) ptr;
- hdr_ver = (ip->v_ihl & 0xF0) >> 4;
- hdr_len = (ip->v_ihl & 0x0F) * sizeof(long);
- dta_len = ntohs(ip->length);
- dta_off = (ntohs(ip->fl_offs) & IPF_F_OFFSET) << 3 ;
-
- printk("\r*****\n");
- printk("SLIP: %s->", in_ntoa(ip->source));
- printk("%s\n", in_ntoa(ip->dest));
- printk(" len %u ihl %u ttl %u prot %u",
- dta_len, ip->v_ihl & 0xFF, ip->ttl & 0xFF, ip->protocol & 0xFF);
-
- if (ip->tos != 0) printk(" tos %u", ip->tos);
- if (dta_off != 0 || (ntohs(ip->fl_offs) & IPF_MF))
- printk(" id %u offs %u", ntohs(ip->id), dta_off);
-
- if (ntohs(ip->fl_offs) & IPF_DF) printk(" DF");
- if (ntohs(ip->fl_offs) & IPF_MF) printk(" MF");
- printk("\n*****\n");
-}
-#endif
-
-
-/*
- * Read data from a TTY queue. This function will eventually
- * be moved into the TTY layer itself, making it available for
- * other layers, too.
- */
-int tty_read_data(struct tty_struct *tty, unsigned char *buf, int max)
-{
- register int count;
- register unsigned char c;
-
- /* Keep fetching characters from TTY until done or full. */
- count = 0;
- PRINTK (("SLIP: tty_read:"));
- while (max-- > 0) {
- if (EMPTY(&tty->read_q)) break;
- c = (get_tty_queue(&tty->read_q) & 0377);
- *buf++ = c;
- PRINTK ((" %02x", (int) (c & 255)));
- count++;
- }
- PRINTK (("\r\nSLIP: tty_read: read %d bytes\r\n", count));
- return(count);
-}
-
-
-/*
- * Write data to a TTY queue. This function will eventually
- * be moved into the TTY layer itself, making it available for
- * other layers, too.
- */
-void tty_write_data(struct tty_struct *tty, char *buf, int count)
-{
- /* PRINTK (("SLIP: tty_write: writing %d bytes\r\n", count)); */
- while(count--) {
- put_tty_queue(*buf++, &tty->write_q);
- }
-}
-
-
-/*
- * Flush a TTY write queue by calling the TTY layer. This
- * function will eventually be moved into the TTY layer itself,
- * making it available for other layers, too.
- */
-void tty_flush(struct tty_struct *tty)
-{
- /* PRINTK (("SLIP: tty_flush: flusing the toilet...\r\n")); */
- /*
- * This should also tell TTY which function to call-back
- * when the work is done, allowing us to clean up and
- * possibly start another output...
- */
- tty_write_flush(tty);
-}
-
-
-/* Find a SLIP channel from its `tty' link. */
-static struct slip *
-sl_find(struct tty_struct *tty)
-{
- int i;
- struct slip *sl;
-
- if (tty == NULL) return(NULL);
- for (i = 0; i < SL_NRUNIT; i++) {
- sl = &sl_ctrl[i];
- if (sl->tty == tty) return(sl);
- }
- return(NULL);
-}
-
-
-/* Find a free SLIP channel, and link in this `tty' line. */
-static inline struct slip *
-sl_alloc(void)
-{
- int i;
- struct slip *sl;
- unsigned long flags;
-
- for (i = 0; i < SL_NRUNIT; i++) {
- sl = &sl_ctrl[i];
- if (sl->inuse == 0) {
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- sl->inuse++;
- sl->tty = NULL;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
- return(sl);
- }
- }
- return(NULL);
-}
-
-
-/* Free a SLIP channel. */
-static inline void
-sl_free(struct slip *sl)
-{
- unsigned long flags;
-
- if (sl->inuse == 1) {
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- sl->inuse--;
- sl->tty = NULL;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
- }
-}
-
-
-/* Stuff one byte into a SLIP queue. */
-static inline void
-put_sl_queue(struct sl_queue * queue, char c)
-{
- int head;
- unsigned long flags;
-
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- head = (queue->head + 1) & (SL_BUF_SIZE-1);
- if (head != queue->tail) {
- queue->buf[queue->head] = c;
- queue->head = head;
- }
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
-}
-
-
-/* Release 'i' bytes from a SLIP queue. */
-static inline void
-eat_sl_queue(struct sl_queue * queue, int i)
-{
- unsigned long flags;
-
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- if (queue->tail != queue->head)
- queue->tail = (queue->tail + i) & (SL_BUF_SIZE-1);
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
-}
-
-
-/* Set the "sending" flag. This must be atomic, hence the ASM. */
-static inline void
-sl_lock(struct slip *sl)
-{
- unsigned long flags;
-
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- sl->sending = 1;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
-}
-
-
-/* Clear the "sending" flag. This must be atomic, hence the ASM. */
-static inline void
-sl_unlock(struct slip *sl)
-{
- unsigned long flags;
-
- __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags));
- sl->sending = 0;
- __asm__ __volatile__("pushl %0 ; popfl"::"r" (flags));
-}
-
-
-/* Send one completely decapsulated IP datagram to the IP layer. */
-static void
-sl_recv(struct slip *sl, int len)
-{
-#if 0
- struct device *dev;
-#endif
- register unsigned char *p;
- int done;
-
- PRINTK (("SLIP: sending one dgram to IP (len=%d)\r\n", len));
-#ifdef SL_DUMP
- printk("<< iface \"sl%d\" recv:\r\n", sl->line);
- ip_dump((unsigned char *) &sl->rcv_queue.buf[sl->rcv_queue.tail], len);
-#endif
-
- /* Bump the datagram to the upper layers... */
-#if 0
- dev = sl->dev;
- p = (unsigned char *) &sl->rcv_queue.buf[sl->rcv_queue.tail];
- do {
- done = dev_rint(p, len, 0, dev);
- if (done == 1) break;
- } while(1);
-#endif
- eat_sl_queue(&sl->rcv_queue, len);
- sl->rcvd++;
-}
-
-
-/* Encapsulate one IP datagram and stuff into a TTY queue. */
-static void
-sl_send(struct slip *sl, unsigned char *p, int len)
-{
- register unsigned char *bp;
- register int count;
-
- /* PRINTK (("SLIP: sl_send(0x%X, %d) called\n", p, len)); */
- bp = (unsigned char *)sl->xbuff;
-#ifdef SL_DUMP
- printk(">> iface \"sl%d\" sent:\r\n", sl->line);
- ip_dump(p, len);
-#endif
- count = 0;
-
- /*
- * Send an initial END character to flush out any
- * data that may have accumulated in the receiver
- * due to line noise.
- */
- *bp++ = END;
- count++;
-
- /*
- * For each byte in the packet, send the appropriate
- * character sequence, according to the SLIP protocol.
- * FIXME: change this to copy blocks of characters between
- * special characters to improve speed.
- */
- while(len--) {
- switch(*p) {
- case END:
- *bp++ = ESC;
- *bp++ = ESC_END;
- count += 2;
- break;
- case ESC:
- *bp++ = ESC;
- *bp++ = ESC_ESC;
- count += 2;
- break;
- default:
- *bp++ = *p;
- count++;
- }
- p++;
- }
- *bp++ = END;
- count++;
- sl->sent++;
- tty_write_data(sl->tty, sl->xbuff, count); /* stuff into TTY */
-}
-
-
-/* Encapsulate an IP datagram and kick it into a TTY queue. */
-static int
-sl_start_xmit(void /*struct sk_buff*/ *skb, void /*struct device*/ *dev)
-{
- struct slip *sl;
- struct tty_struct *tty;
-
-#if 0
- /* Find the correct SLIP channel to use. */
- sl = &sl_ctrl[dev->base_addr];
- tty = sl->tty;
- /* PRINTK (("SLIP: sl_start_xmit(\"%s\") skb=0x%X busy=%d\n",
- dev->name, skb, sl->sending)); */
-
- /*
- * If we are busy already- too bad. We ought to be able
- * to queue things at this point, to allow for a little
- * frame buffer. Oh well...
- */
- if (sl->sending) {
- PRINTK (("SLIP: sl_start_xmit: BUSY\r\n"));
- return(1);
- }
-
- /* We were not, so we are now... :-) */
- sti();
- sl_lock(sl);
-
- if (skb != NULL) {
- /* PRINTK (("SLIP: sl_start_xmit: encaps(0x%X, %d)\r\n",
- (unsigned) skb, skb->len)); */
- sl_send(sl, (unsigned char *) (skb + 1), skb->len);
- }
-
- /* PRINTK (("SLIP: sl_start_xmit: kicking TTY!\n")); */
- tty_flush(tty); /* kick TTY in the butt */
- sl_unlock(sl);
-#endif
- return(0);
-}
-
-
-/*
- * Return the frame type ID. Shouldn't we pick this up from the
- * frame on which we have to operate, like in 'eth' ? - FvK
- */
-static unsigned short
-sl_type_trans (void /*struct sk_buff*/ *skb, void /*struct device*/ *dev)
-{
-#ifdef notdef
- struct slip *sl;
-
- sl = sl_ctrl[dev->base_addr];
- return(sl->type);
-#else
- return(NET16(ETHERTYPE_IP));
-#endif
-}
-
-
-/* Open the low-level part of the SLIP channel. Easy! */
-static int
-sl_open(void /*struct device*/ *dev)
-{
- struct slip *sl;
-
-#if 0
- sl = &sl_ctrl[dev->base_addr];
- if (sl->tty == NULL) {
- PRINTK (("SLIP: channel sl%d not connected!\n", sl->line));
- return(-ENXIO);
- }
-
- sl->escape = 0; /* SLIP state machine */
- sl->received = 0; /* SLIP receiver count */
- PRINTK (("SLIP: channel sl%d opened.\n", sl->line));
-#endif
- return(0);
-}
-
-
-/* Close the low-level part of the SLIP channel. Easy! */
-static int
-sl_close(void /*struct device*/ *dev)
-{
- struct slip *sl;
-
-#if 0
- sl = &sl_ctrl[dev->base_addr];
- if (sl->tty == NULL) {
- PRINTK (("SLIP: channel sl%d not connected!\n", sl->line));
- return(-EBUSY);
- }
- sl_free(sl);
-
- /*
- * The next two lines should be handled by a "dev_down()"
- * function, which takes care of shutting down an inter-
- * face. It would also be called by the "ip" module when
- * an interface is brought down manually.
- */
- del_devroute(dev);
- dev->up = 0;
- PRINTK (("SLIP: channel sl%d closed.\n", sl->line));
-#endif
- return(0);
-}
-
-
-/*
- * Handle the 'receiver data ready' interrupt.
- * This function is called by the 'tty_io' module in the kernel when
- * a block of SLIP data has been received, which can now be decapsulated
- * and sent on to some IP layer for further processing.
- */
-static void
-slip_recv(struct tty_struct *tty)
-{
- unsigned char buff[SL_MTU * 2];
- register unsigned char *p;
- register int count;
- struct slip *sl;
- unsigned char c;
-
-#if 0
-PRINTK (("SLIP: slip_recv(%d) called\n", tty->line));
- if ((sl = sl_find(tty)) == NULL) return; /* not connected */
-
- if (SL_FULL(&sl->rcv_queue)) {
- PRINTK (("SLIP: recv queue full\r\n"));
- return;
- }
-
- while((count = tty_read_data(tty, buff, (SL_MTU * 2))) > 0) {
- p = buff;
- while(count-- > 0) {
- c = *p++;
- switch(c) {
- case ESC:
- sl->escape = 1;
- break;
- case ESC_ESC:
- if (sl->escape) c = ESC;
- put_sl_queue(&sl->rcv_queue, c);
- sl->escape = 0;
- sl->received++;
- break;
- case ESC_END:
- if (sl->escape) c = END;
- put_sl_queue(&sl->rcv_queue, c);
- sl->escape = 0;
- sl->received++;
- break;
- case END:
- sl->escape = 0;
- if (sl->received < 3) {
- if (sl->received)
- eat_sl_queue(&sl->rcv_queue,
- sl->received);
- sl->received = 0;
- } else {
- PRINTK (("SLIP: full frame received!\r\n"));
- sl_recv(sl, sl->received);
- sl->received = 0;
- }
- break;
- default:
- put_sl_queue(&sl->rcv_queue, c);
- sl->escape = 0;
- sl->received++;
- }
- }
- }
-#endif
-}
-
-
-/* Return the channel number of a SLIP connection. */
-static int
-slip_chan(struct tty_struct *tty)
-{
- struct slip *sl;
-
- if ((sl = sl_find(tty)) == NULL) return(-ENXIO); /* not connected */
- return(sl->line);
-}
-
-
-/*
- * Open the high-level part of the SLIP channel.
- * This function is called by the TTY module when the
- * SLIP line discipline is called for. Because we are
- * sure the tty line exists, we only have to link it to
- * a free SLIP channel...
- */
-static int
-slip_open(struct tty_struct *tty)
-{
- struct slip *sl;
-
- /* First make sure we're not already connected. */
- if ((sl = sl_find(tty)) != NULL) {
- PRINTK (("SLIP: TTY %d already connected to sl%d !\n",
- tty->line, sl->line));
- return(-EEXIST);
- }
-
- /* OK. Find a free SLIP channel to use. */
- if ((sl = sl_alloc()) == NULL) {
- PRINTK (("SLIP: TTY %d not connected: all channels in use!\n",
- tty->line));
- return(-ENFILE);
- }
- sl->tty = tty;
-
- /* Link the TTY line to this channel. */
- (void) sl_open(sl->dev);
- PRINTK (("SLIP: TTY %d connected to sl%d.\n", tty->line, sl->line));
-
- /* Done. We have linked the TTY line to a channel. */
- return(sl->line);
-}
-
-
-/*
- * Close down a SLIP channel.
- * This means flushing out any pending queues, and then restoring the
- * TTY line discipline to what it was before it got hooked to SLIP
- * (which usually is TTY again).
- */
-static void
-slip_close(struct tty_struct *tty)
-{
- struct slip *sl;
-
- /* First make sure we're connected. */
- if ((sl = sl_find(tty)) == NULL) {
- PRINTK (("SLIP: TTY %d not connected !\n", tty->line));
- return;
- }
-
- (void) sl_close(sl->dev);
- PRINTK (("SLIP: TTY %d disconnected from sl%d.\n", tty->line, sl->line));
-}
-
-
-/* Initialize the SLIP driver. Called by DDI. */
-int
-slip_init(struct ddi *dev)
-{
- int i;
- struct slip *sl;
-
-#if 1
- PRINTK(("SLIP/DDI: version %s (%d channels, buffer=0x%X:%d)\n",
- ddi->ioaddr, ddi->memaddr, ddi->memsize));
-#else
- sl = &sl_ctrl[dev->base_addr];
-
- if (already++ == 0) {
- printk("SLIP: version %s (%d channels): ",
- SLIP_VERSION, SL_NRUNIT);
- if ((i = tty_set_ldisc(N_SLIP, slip_open, slip_close,
- slip_chan, slip_recv)) == 0) printk("OK\n");
- else printk("ERROR: %d\n", i);
- }
-
- /* Set up the "SLIP Control Block". */
- sl->inuse = 0; /* not allocated now */
- sl->line = dev->base_addr; /* SLIP channel number */
- sl->tty = NULL; /* pointer to TTY line */
- sl->dev = dev; /* pointer to DEVICE */
- sl->sending = 0; /* locked on output */
- sl->rcv_queue.head = 0; /* ptr to RECV queue */
- sl->rcv_queue.tail = 0; /* ptr to RECV queue */
- sl->escape = 0; /* SLIP state machine */
- sl->received = 0; /* SLIP receiver count */
- sl->sent = 0; /* #frames sent out */
- sl->rcvd = 0; /* #frames received */
- sl->errors = 0; /* not used at present */
-
- /* Finish setting up the DEVICE info. */
- dev->mtu = SL_MTU;
- dev->rmem_end = (unsigned long)&sl->rcv_queue.buf[SL_BUF_SIZE-1];
- dev->rmem_start = (unsigned long)&sl->rcv_queue.buf[0];
- dev->mem_end = (unsigned long)&sl->xbuff[(SL_MTU * 2) -1];
- dev->mem_start = (unsigned long)&sl->xbuff[0];
- dev->hard_start_xmit = sl_start_xmit;
- dev->open = sl_open;
- dev->stop = sl_close;
- dev->hard_header = sl_hard_header;
- dev->add_arp = sl_add_arp;
- dev->type_trans = sl_type_trans;
- dev->hard_header_len = 0;
- dev->addr_len = 0;
- dev->type = 0; /* FIXME: ??? */
- dev->queue_xmit = dev_queue_xmit;
- dev->rebuild_header = sl_rebuild_header;
- for (i = 0; i < DEV_NUMBUFFS; i++) dev->buffs[i] = NULL;
-
-#endif
- return(0);
-}
diff --git a/net/drv/slip/slip.h b/net/drv/slip/slip.h
deleted file mode 100644
index 6c2e871..0000000
--- a/net/drv/slip/slip.h
+++ /dev/null
@@ -1,64 +0,0 @@
-/*
- * slip.h Define the SLIP device driver interface and constants.
- *
- * NOTE: THIS FILE WILL BE MOVED TO THE LINUX INCLUDE DIRECTORY
- * AS SOON AS POSSIBLE!
- *
- * Version: @(#)slip.h 1.2.0 (02/11/93)
- *
- * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- */
-#ifndef _LINUX_SLIP_H
-#define _LINUX_SLIP_H
-
-/* SLIP configuration. */
-#define SL_NRUNIT 4 /* number of SLIP channels */
-#define SL_MTU 296 /* 296; I am used to 600- FvK */
-#define SL_BUF_SIZE 8192 /* same as TTY for now */
-#ifdef not_any_more
-#define SL_RCV_SIZE 2048
-#endif
-
-/* SLIP protocol characters. */
-#define END 0300 /* indicates end of frame */
-#define ESC 0333 /* indicates byte stuffing */
-#define ESC_END 0334 /* ESC ESC_END means END 'data' */
-#define ESC_ESC 0335 /* ESC ESC_ESC means ESC 'data' */
-
-struct sl_queue {
- unsigned long data;
- unsigned long head;
- unsigned long tail;
- struct wait_queue *proc_list;
- unsigned char buf[SL_BUF_SIZE];
-};
-
-struct slip {
- int inuse; /* are we allocated? */
- int line; /* SLIP channel number */
- struct tty_struct *tty; /* ptr to TTY structure */
-#if 0
- struct device *dev; /* easy for intr handling */
-#endif
- unsigned int sending; /* "channel busy" indicator */
- struct sl_queue rcv_queue;
- char snd_buf[(SL_MTU*2)+4];
- unsigned char xbuff[(SL_MTU * 2)];
- int escape; /* SLIP state machine */
- int received; /* SLIP receive counter */
- unsigned long sent; /* #frames sent */
- unsigned long rcvd; /* #frames rcvd */
- unsigned long errors; /* error count */
-};
-
-#define SL_INC(a) ((a) = ((a)+1) & (SL_BUF_SIZE-1))
-#define SL_DEC(a) ((a) = ((a)-1) & (SL_BUF_SIZE-1))
-#define SL_EMPTY(a) ((a)->head == (a)->tail)
-#define SL_LEFT(a) (((a)->tail-(a)->head-1)&(SL_BUF_SIZE-1))
-#define SL_LAST(a) ((a)->buf[(SL_BUF_SIZE-1)&((a)->head-1)])
-#define SL_FULL(a) (!SL_LEFT(a))
-#define SL_CHARS(a) (((a)->head-(a)->tail)&(SL_BUF_SIZE-1))
-
-extern int slip_init(struct ddi *dev);
-
-#endif /* _LINUX_SLIP.H */
diff --git a/net/drv/we8003/Makefile b/net/drv/we8003/Makefile
deleted file mode 100644
index 3a5bafb..0000000
--- a/net/drv/we8003/Makefile
+++ /dev/null
@@ -1,42 +0,0 @@
-#
-# Makefile for the WE8003 device driver..
-#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
-
-SUBDIRS =
-
-
-.c.s:
- $(CC) $(CFLAGS) -S $<
-.s.o:
- $(AS) -c -o $*.o $<
-.c.o:
- $(CC) $(CFLAGS) -c $<
-
-OBJS = main.o
-
-
-we8003.o: $(OBJS)
- ld -r -o we8003.o $(OBJS)
-
-clean:
- rm -f core *.o *.a tmp_make .depend
- for i in *.c;do rm -f `basename $$i .c`.s;done
-
-dep:
- $(CPP) -M *.c > .depend
- @for i in $(SUBDIRS); do (cd $$i && echo $$i && $(MAKE) dep) || exit; done
-
-dummy:
-#
-# include a dependency file if one exists
-#
-ifeq (.depend,$(wildcard .depend))
-include .depend
-endif
diff --git a/net/drv/we8003/dp8390.h b/net/drv/we8003/dp8390.h
deleted file mode 100644
index 5372a38..0000000
--- a/net/drv/we8003/dp8390.h
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * Definitions for the DP8390 Network Interface Controller.
- *
- * Version: $Id: dp8390.h,v 0.8.4.1 1992/11/10 00:17:18 waltje Exp $
- *
- * Authors: Original taken from the 386BSD operating system.
- * Ross Biro, <bir7@leland.Stanford.Edu>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-
-/* format of status
- bit
- 0 packet ok
- 1 crc error
- 2 frame alignment error
- 3 fifo overrun
-*/
-#define STRECVD 0xf1
-struct wd_ring {
- unsigned char status; /* status */
- unsigned char next; /* pointer to next packet */
- unsigned short count; /* packet length in bytes + 4 */
-};
-
-/* interrupt status defenitions
- bits
- 0 Recv.
- 1 Transmit
- 2 RcvErr
- 3 Transmit Err
- 4 Overwrite warning
- 5 Counter overflow
- 6 Remote DMA complete
- 7 Reset Status
-*/
-#define IRCV 0x1
-#define ITRS 0x2
-#define IRCE 0x4
-#define ITRE 0x8
-#define IOVER 0x10
-#define ICOUNTERS 0x20
-#define IDMA 0x40
-#define IRESET 0x80
-#define IOVER 0x10
-#define ICOUNTERS 0x20
-#define IDMA 0x40
-#define IRESET 0x80
-
-/* transmit status format
- bits
- 0 Packet transmitted ok.
- 1 Non Deferred transmition
- 2 Transmit collied
- 3 Transmit aborted
- 4 Carrier Sense Lost
- 5 Fifo Underrun
- 6 CD Heartbeat
- 7 Out of Window Collision
-*/
-#define TROK 0x1
-#define TRAB 0x4
-
-/* Page 0 */
-#define CR (WD_BASE+WD_NIC+0) /* RW - Command */
-#define CLDA0 (WD_BASE+WD_NIC+1) /* R - CurrentLocalDMA Addr 0 */
-#define PSTART (WD_BASE+WD_NIC+1) /* W - Page Start Register */
-#define CLDA1 (WD_BASE+WD_NIC+2) /* R - Current Local DMA Addr 1 */
-#define PSTOP (WD_BASE+WD_NIC+2) /* W - Page Stop Register */
-#define BNRY (WD_BASE+WD_NIC+3) /* RW - Boundry Pointer */
-#define TSR (WD_BASE+WD_NIC+4) /* R - Transmit Status Register */
-#define TPSR (WD_BASE+WD_NIC+4) /* W - Transmit Page Start */
-#define NCR (WD_BASE+WD_NIC+5) /* R - Number of Collisions */
-#define TBCR0 (WD_BASE+WD_NIC+5) /* W - Transmit Byte Count 0 */
-#define FIFO (WD_BASE+WD_NIC+6) /* R - FIFO */
-#define TBCR1 (WD_BASE+WD_NIC+6) /* W - Transmit Byte Count 1 */
-#define ISR (WD_BASE+WD_NIC+7) /* RW - Interrupt Status Reg */
-#define CRDA0 (WD_BASE+WD_NIC+8) /* R - Current Remote DMA Add 0 */
-#define RSAR0 (WD_BASE+WD_NIC+8) /* W - Remote Start Address 0 */
-#define CRDA1 (WD_BASE+WD_NIC+9) /* R - CurrentRemote DMA Addr 1 */
- /* R - Reserved */
-#define RBCR0 (WD_BASE+WD_NIC+0x0a) /* W - Remote Byte Count 0 */
- /* R - Reserved */
-#define RBCR1 (WD_BASE+WD_NIC+0x0b) /* W - Remote Byte Count 1 */
-#define RSR (WD_BASE+WD_NIC+0x0c) /* R - Receive Status Register */
-#define RCR (WD_BASE+WD_NIC+0x0c) /* W - Receive Configuration */
-#define CNTR0 (WD_BASE+WD_NIC+0x0d) /* R - Frame Alignment Errors 0 */
-#define TCR (WD_BASE+WD_NIC+0x0d) /* W - Transmit Configuration */
-#define CNTR1 (WD_BASE+WD_NIC+0x0e) /* R - Frame Alignment Errors 1 */
-#define DCR (WD_BASE+WD_NIC+0x0e) /* W - Data Configuration */
-#define CNTR2 (WD_BASE+WD_NIC+0x0f) /* R - Missed Packet Errors */
-#define IMR (WD_BASE+WD_NIC+0x0f) /* W - Interrupt Mask Register */
-
-/* Page 1 */
- /* RW - Command */
-#define PAR0 (WD_BASE+WD_NIC+0x01) /* RW - Physical Address 0 */
-#define PAR1 (WD_BASE+WD_NIC+0x02) /* RW - Physical Address 1 */
-#define PAR2 (WD_BASE+WD_NIC+0x03) /* RW - Physical Address 2 */
-#define PAR3 (WD_BASE+WD_NIC+0x04) /* RW - Physical Address 3 */
-#define PAR4 (WD_BASE+WD_NIC+0x04) /* RW - Physical Address 4 */
-#define PAR5 (WD_BASE+WD_NIC+0x05) /* RW - Physical Address 5 */
-#define PAR6 (WD_BASE+WD_NIC+0x06) /* RW - Physical Address 6 */
-#define CURR (WD_BASE+WD_NIC+0x07) /* RW - Current Page */
-#define MAR0 (WD_BASE+WD_NIC+0x08) /* RW - Multicast Address 0 */
-#define MAR1 (WD_BASE+WD_NIC+0x09) /* RW - Multicast Address 1 */
-#define MAR2 (WD_BASE+WD_NIC+0x0a) /* RW - Multicast Address 2 */
-#define MAR3 (WD_BASE+WD_NIC+0x0b) /* RW - Multicast Address 3 */
-#define MAR4 (WD_BASE+WD_NIC+0x0c) /* RW - Multicast Address 4 */
-#define MAR5 (WD_BASE+WD_NIC+0x0d) /* RW - Multicast Address 5 */
-#define MAR6 (WD_BASE+WD_NIC+0x0e) /* RW - Multicast Address 6 */
-#define MAR7 (WD_BASE+WD_NIC+0x0f) /* RW - Multicast Address 7 */
-
-/* Page 2 */
-/* Page 2 Registers are RW opposite Page 0 */
-/* and should be used for diagnostic purposes only */
-
-/* Command Register bits */
-#define STOP 1 /* In progress jobs finished, reset */
-#define STA 2 /* Activate the NIC */
-#define TXP 4 /* Initiate TX packet */
-#define RD0 8 /* Remote DMA commands */
-#define RD1 0x10
-#define RD2 0x20
-#define PS0 0x40 /* Page Select */
-#define PS1 0x80 /* 00 = 0, 01 = 1, 10 = 2, 11=reserved */
-
-#define PAGE0 ~(PS0|PS1) /* Remember to AND this */
-#define PAGE1 PS0 /* these can be OR'd */
-#define PAGE2 PS1
-#define NO_DMA RD2
-
-/* Interrupt Status Register bits */
-#define PRX 1 /* Packet received with no errors */
-#define PTX 2 /* Packet transmitted with no errors */
-#define RXE 4 /* Packet received with errors */
-#define TXE 8 /* Transmit aborted with errors */
-#define OVW 0x10 /* Overwrite warning */
-#define CNT 0x20 /* Counter overflow warning */
-#define RDC 0x40 /* Remote DMA complete */
-#define RST 0x80 /* Reset status - does not cause intr */
-
-/* Interrupt Mask Register - 1 = enabled */
-#define PRXE 1 /* Packet received */
-#define PTXE 2 /* Packet transmitted */
-#define RXEE 4 /* Receive error */
-#define TXEE 8 /* Transmit error */
-#define OVWE 0x10 /* Overwrite error */
-#define CNTE 0x20 /* Counter overflow */
-#define RDCE 0x40 /* Remote DMA complete */
-
-/* Data Configuration Register */
-#define WTS 1 /* Word Transfer 0 = byte, 1 = word */
-#define BOS 2 /* Byte Order 0 = 8086, 1 = 68000 */
-#define LAS 4 /* Long Address 0=16bit, 1=32 bit DMA */
-#define LS 8 /* Loopback = 0, 1 = Normal */
-#define AR 0x10 /* Autoinitialize = 1 DMA, 0 = software */
-#define FT0 0x20 /* FIFO Threshold (word mode /2 ) */
-#define FT1 0x40 /* 00 = 2, 01 = 4, 10 = 8, 11=12 bytes */
-
-/* Transmit Configuration Register */
-#define CRCI 1 /* CRC inhibit = 1, append = 0 */
-#define LB0 2 /* Loopback control 00=normal loopback */
-#define LB1 4 /* 01=internal, 10=ext1, 11=ext2 */
-#define ATD 8 /* Auto Transmit Enable=1 tx inh enb */
-#define OFST 0x10 /* Collision offset 1 = modify to low
- priority mode */
-
-/* Transmitter Status Register */
-#define PTXOK 1 /* Packet transmitted without error */
- /* reserved */
-#define COL 4 /* Xmit, check NCR for count */
-#define ABT 8 /* Xmit aborted - 16 tries */
-#define CRS 0x10 /* Carrier Sense lost */
-#define FU 0x20 /* FIFO underrun */
-#define CDH 0x40 /* CD Heartbeat failed */
-#define OWC 0x80 /* Out of window collision */
-
-/* Receive configuration Register */
-#define SEP 1 /* Save error packets = 1 */
-#define ARUNT 2 /* Accept RUNT packets < 64 bytes */
-#define AB 4 /* Accept Broadcast packets */
-#define AM 8 /* Accept Multicast packets */
-#define PRO 0x10 /* Promiscuous mode */
-#define MON 0x20 /* Monitor mode */
-
-/* Receive Status Register */
-#define PRX 1 /* Packet received without error */
-#define CRC 2 /* CRC error */
-#define FAE 4 /* Frame Alignment error */
-#define FO 8 /* FIFO overrun error */
-#define MPA 0x10 /* Missed packet */
-#define PHY 0x20 /* Physical=0, Multicast/Broadcast = 1 */
-#define DIS 0x40 /* Receiver disabled (monitor mode) */
-#define DFR 0x80 /* Deferring - jabber on line */
diff --git a/net/drv/we8003/handler.c b/net/drv/we8003/handler.c
deleted file mode 100644
index 2d1670f..0000000
--- a/net/drv/we8003/handler.c
+++ /dev/null
@@ -1,681 +0,0 @@
-/*
- * INET An implementation of the TCP/IP protocol suite for the LINUX
- * operating system. INET is implemented using the BSD Socket
- * interface as the means of communication with the user level.
- *
- * WE - A simple WD8003, WD8013 and SMC Elite-16 driver.
- *
- * Version: $Id: handler.c,v 1.0.0 1993/02/15 00:00:00 waltje Exp $
- *
- * Authors: Original taken from the 386BSD operating system.
- * Ross Biro, <bir7@leland.Stanford.Edu>
- * Bob Harris, <rth@sparta.com>
- * Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version
- * 2 of the License, or (at your option) any later version.
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <errno.h>
-#include <linux/fcntl.h>
-#include <netinet/in.h>
-#include <linux/interrupt.h>
-#include "dp8390.h"
-#include "we8003.h"
-
-
-static unsigned char interrupt_mask;
-
-static struct enet_statistics stats; /* Statistics collection */
-static unsigned char max_pages; /* Board memory/256 */
-static unsigned char wd_debug = 0; /* turns on/off debug messages */
-static unsigned char dconfig = WD_DCONFIG; /* default data configuration */
-static int tx_aborted = 0; /* Empties tx bit bucket */
-
-static void wd_trs (struct device *);
-
-static int
-max(int a, int b)
-{
- if (a>b) return (a);
- return (b);
-}
-
-static void
-wd_start(struct device *dev)
-{
- unsigned char cmd;
- interrupt_mask=RECV_MASK|TRANS_MASK;
- cli();
- cmd = inb_p(WD_COMM);
- cmd &= ~(CSTOP|CPAGE);
- cmd |= CSTART;
- outb_p(cmd, WD_COMM);
- outb_p(interrupt_mask,WD_IMR);
- sti();
- dev->start = 1;
-}
-
-int
-wd8003_open(struct device *dev)
-{
- unsigned char cmd;
- int i;
- /* we probably don't want to be interrupted here. */
- cli();
- /* This section of code is mostly copied from the bsd driver which is
- mostly copied from somewhere else. */
- /* The somewhere else is probably the cmwymr(sp?) dos packet driver */
-
- cmd=inb_p(WD_COMM);
- cmd|=CSTOP;
- cmd &= ~(CSTART|CPAGE);
- outb_p(cmd, WD_COMM);
- outb_p(0, WD_IMR);
- sti();
- outb_p( dconfig,WD_DCR);
- /*Zero the remote byte count. */
- outb_p(0, WD_RBY0);
- outb_p(0, WD_RBY1);
- outb_p(WD_MCONFIG,WD_RCC);
- outb_p(WD_TCONFIG,WD_TRC);
- outb_p(0,WD_TRPG); /* Set the transmit page start = 0 */
- outb_p( max_pages,WD_PSTOP); /* (read) page stop = top of board memory */
- outb_p(WD_TXBS,WD_PSTRT); /* (read) page start = cur = bnd = top of tx memory */
- outb_p(WD_TXBS,WD_BNDR);
- /* clear interrupt status. */
- outb_p(0xff,WD_ISR);
- /* we don't want no stinking interrupts. */
- outb_p(0 ,WD_IMR);
- cmd|=1<<CPAGE_SHIFT;
- outb_p(cmd,WD_COMM);
- /* set the ether address. */
- for (i=0; i < ETHER_ADDR_LEN; i++)
- {
- outb_p(dev->dev_addr[i],WD_PAR0+i);
- }
- /* National recommends setting the boundry < current page register */
- outb_p(WD_TXBS+1,WD_CUR); /* Set the current page = page start + 1 */
- /* set the multicast address. */
- for (i=0; i < ETHER_ADDR_LEN; i++)
- {
- outb_p(dev->broadcast[i],WD_MAR0+i);
- }
-
- cmd&=~(CPAGE|CRDMA);
- cmd|= 4<<CRDMA_SHIFT;
- outb_p(cmd, WD_COMM);
- outb_p(WD_RCONFIG,WD_RCC);
- wd_start(dev);
- return (0);
-}
-
-/* This routine just calls the ether rcv_int. */
-static int
-wdget(volatile struct wd_ring *ring, struct device *dev)
-{
- unsigned char *fptr;
- long len;
- fptr = (unsigned char *)(ring +1);
- /* some people have bugs in their hardware which let
- ring->count be 0. It shouldn't happen, but we
- should check for it. */
- len = ring->count-4;
- if (len < 56)
- printk ("we.c: Hardware problem, runt packet. ring->count = %d\n",
- ring->count);
- return (dev_rint(fptr, len, 0, dev));
-}
-
-int
-wd8003_start_xmit(struct sk_buff *skb, struct device *dev)
-{
- unsigned char cmd;
- int len;
-
- cli();
- if (dev->tbusy)
- {
- /* put in a time out. */
- if (jiffies - dev->trans_start < 30)
- {
- return (1);
- }
-
- printk ("wd8003 transmit timed out. \n");
- }
- dev->tbusy = 1;
-
- if (skb == NULL)
- {
- sti();
- wd_trs(dev);
- return (0);
- }
-
- /* this should check to see if it's been killed. */
- if (skb->dev != dev)
- {
- sti();
- return (0);
- }
-
-
- if (!skb->arp)
- {
- if ( dev->rebuild_header (skb+1, dev))
- {
- cli();
- if (skb->dev == dev)
- {
- arp_queue (skb);
- }
- cli (); /* arp_queue turns them back on. */
- dev->tbusy = 0;
- sti();
- return (0);
- }
- }
-
- memcpy ((unsigned char *)dev->mem_start, skb+1, skb->len);
-
- len = skb->len;
-
- /* now we need to set up the card info. */
- dev->trans_start = jiffies;
- len=max(len, ETHER_MIN_LEN); /* actually we should zero out
- the extra memory. */
-/* printk ("start_xmit len - %d\n", len);*/
-
- cmd=inb_p(WD_COMM);
- cmd &= ~CPAGE;
- outb_p(cmd, WD_COMM);
-
- interrupt_mask |= TRANS_MASK;
- if (!(dev->interrupt))
- outb (interrupt_mask, WD_IMR);
-
- outb_p(len&0xff,WD_TB0);
- outb_p(len>>8,WD_TB1);
- cmd |= CTRANS;
- outb_p(cmd,WD_COMM);
- sti();
-
- if (skb->free)
- {
- kfree_skb (skb, FREE_WRITE);
- }
-
- return (0);
-}
-
-/* tell the card about the new boundary. */
-
-static void
-wd_put_bnd(unsigned char bnd, struct device *dev )
-{
-
- unsigned char cmd;
-
- /* Ensure page 0 selected */
- cmd = inb_p( CR );
- if (cmd & 0x40) {
- outb_p(cmd & (~CPAGE1), WD_COMM); /* select page 0 */
- outb_p(bnd, WD_BNDR);
- outb_p(cmd | CPAGE1, WD_COMM); /* reselect page 1 */
- } else {
- outb_p(bnd, WD_BNDR);
- }
-}
-
-static unsigned char
-wd_get_bnd( struct device *dev )
-{
-
- unsigned char cmd, bnd;
-
- /* Ensure page 0 selected */
- cmd = inb_p(WD_COMM);
- if (cmd & 0x40) {
- outb_p(cmd & (~CPAGE1), WD_COMM); /* select page 0 */
- bnd = inb_p(WD_BNDR);
- outb_p(cmd | CPAGE1, WD_COMM); /* reselect page 1 */
- return (bnd);
- } else {
- return (inb_p(WD_BNDR));
- }
-}
-
-static unsigned char
-wd_get_cur( struct device *dev )
-{
-
- unsigned char cmd, cur;
-
- /* Ensure page 1 selected */
- cmd = inb_p(WD_COMM);
- if (cmd & 0x40) {
- return (inb_p(WD_CUR));
- } else {
- outb_p(cmd | CPAGE1, WD_COMM); /* select page 1 */
- cur = inb_p(WD_CUR);
- outb_p(cmd & (~CPAGE1), WD_COMM); /* reselect page 0 */
- return (cur);
- }
-}
-
-/* This routine handles the packet recieved interrupt. */
-/* Debug routines slow things down, but reveal bugs... */
-/* Modified Boundry Page Register to follow Current Page */
-
-static void
-wd_rcv( struct device *dev )
-{
-
- unsigned char pkt; /* Next packet page start */
- unsigned char bnd; /* Last packet page end */
- unsigned char cur; /* Future packet page start */
- unsigned char cmd; /* Command register save */
- volatile struct wd_ring *ring;
- int done=0;
-
- /* Calculate next packet location */
- cur = wd_get_cur( dev );
- bnd = wd_get_bnd( dev );
- if( (pkt = bnd + 1) == max_pages )
- pkt = WD_TXBS;
-
- while( done != 1)
- {
- if (pkt != cur)
- {
-
- /* Position pointer to packet in card ring buffer */
- ring = (volatile struct wd_ring *) (dev->mem_start + (pkt << 8));
-
- /* Ensure a valid packet */
- if( ring->status & 1 )
- {
- /* Too small and too big packets are
- filtered by the board */
- if( wd_debug )
- printk("\nwd8013 - wdget: bnd = %d, pkt = %d, "
- "cur = %d, status = %d, len = %d, next = %d",
- bnd, pkt, cur, ring->status, ring->count,
- ring->next);
-
- stats.rx_packets++; /* count all receives */
- done = wdget( ring, dev ); /* get the packet */
-
- /* Calculate next packet location */
- pkt = ring->next;
-
- /* Compute new boundry - tell the chip */
- if( (bnd = pkt - 1) < WD_TXBS )
- bnd = max_pages - 1;
- wd_put_bnd(bnd, dev);
-
- /* update our copy of cur. */
- cur = wd_get_cur(dev);
- }
- else
- { /* Bad packet in ring buffer -
- should not happen due to hardware filtering */
- printk("wd8013 - bad packet: len = %d, status = x%x, "
- "bnd = %d, pkt = %d, cur = %d\n"
- "trashing receive buffer!",
- ring->count, ring->status, bnd, pkt,
- cur);
- /* Reset bnd = cur-1 */
- if( ( bnd = wd_get_cur( dev ) - 1 ) < WD_TXBS )
- bnd = max_pages - 1;
- wd_put_bnd( bnd, dev );
- break; /* return */
- }
-
- }
- else
- {
- done = dev_rint(NULL, 0,0, dev);
- }
- }
-
- /* reset to page 0 */
- cmd = inb_p(WD_COMM);
- if (cmd & 0x40)
- {
- outb_p(cmd & ~(CPAGE1), WD_COMM); /* select page 0 */
- }
-}
-
-
-/* Handle the "receiver overrun" interrupt. */
-static void
-wd_rx_over( struct device *dev )
-{
- unsigned char cmd, dummy;
- register int io;
-
- /*
- * Nothing actually has been overwritten;
- * the chip has stopped at the boundry but
- * we must get it going again - according
- * to National Semiconductor.
- */
- printk("wd_rx_over\n");
- cmd = inb_p( CR ); /* get current command register */
- cmd = (cmd&~(STA|PS0|PS1))|STOP; /* toggle start and stop bits, select page 0 */
- outb_p( cmd, CR );
- dummy = inb_p( RBCR0 ); /* required to detect reset status */
- dummy = inb_p( RBCR1 );
- wd_rcv( dev ); /* clear out received packets */
-
- if( inb_p( ISR ) & PRX )
- outb_p( PRX, ISR ); /* acknowledge RX interrupt */
- while( ( inb_p( ISR ) & RST ) == 0 ); /* wait for reset to be completed */
- outb_p( RST, ISR ); /* acknowledge RST interrupt */
- outb_p( (cmd&~STOP)|STA, CR ); /* Start NIC */
- outb_p( WD_TCONFIG, TCR ); /* resume normal mode */
-}
-
-/*
- * This get's the transmit interrupts. It assumes command page 0 is set, and
- * returns with command page 0 set.
- */
-
-static void
-wd_trs( struct device *dev )
-{
- unsigned char errors;
-
- if( wd_debug )
- printk("\nwd_trs() - TX complete, status = x%x", inb_p(TSR));
-
- if( ( errors = inb_p( TSR ) & PTXOK ) || tx_aborted ){
- if( (errors&~0x02) == 0 ){
- stats.tx_packets++;
- tx_aborted = 0;
- }
- dev->tbusy = 0;
- mark_bh (INET_BH);
-
-#if 0
- /* attempt to start a new transmission. */
- len = dev_tint( (unsigned char *)dev->mem_start, dev );
- if( len != 0 ){
- len=max(len, ETHER_MIN_LEN);
- cmd=inb_p(WD_COMM);
- outb_p(len&0xff,WD_TB0);
- outb_p(len>>8,WD_TB1);
- cmd |= CTRANS;
- outb_p(cmd,WD_COMM);
- interrupt_mask |= TRANS_MASK;
- }
- else
- {
- dev->tbusy = 0
- interrupt_mask &= ~TRANS_MASK;
- return;
- }
-#endif
- }
- else{ /* TX error occurred! - H/W will reschedule */
- if( errors & CRS ){
- stats.tx_carrier_errors++;
- printk("\nwd8013 - network cable short!");
- }
- if (errors & COL )
- stats.collisions += inb_p( NCR );
- if (errors & CDH )
- stats.tx_heartbeat_errors++;
- if (errors & OWC )
- stats.tx_window_errors++;
- }
-}
-
-void
-wd8003_interrupt(int reg_ptr)
-{
- unsigned char cmd;
- unsigned char errors;
- unsigned char isr;
- struct device *dev;
- struct pt_regs *ptr;
- int irq;
- int count = 0;
-
- ptr = (struct pt_regs *)reg_ptr;
- irq = -(ptr->orig_eax+2);
- for (dev = dev_base; dev != NULL; dev = dev->next)
- {
- if (dev->irq == irq) break;
- }
- if (dev == NULL)
- {
- printk ("we.c: irq %d for unknown device\n", irq);
- return;
- }
- sti(); /* this could take a long time, we should have interrupts on. */
-
- cmd = inb_p( CR );/* Select page 0 */
- if( cmd & (PS0|PS1 ) ){
- cmd &= ~(PS0|PS1);
- outb_p(cmd, CR );
- }
-
- if (wd_debug)
- printk("\nwd8013 - interrupt isr = x%x", inb_p( ISR ) );
-
- dev->interrupt = 1;
-
- do{ /* find out who called */
- sti();
- /* Check for overrunning receive buffer first */
- if ( ( isr = inb_p( ISR ) ) & OVW ) { /* Receiver overwrite warning */
- stats.rx_over_errors++;
- if( wd_debug )
- printk("\nwd8013 overrun bnd = %d, cur = %d", wd_get_bnd( dev ), wd_get_cur( dev ) );
- wd_rx_over( dev ); /* performs wd_rcv() as well */
- outb_p( OVW, ISR ); /* acknowledge interrupt */
- }
- else if ( isr & PRX ) { /* got a packet. */
- wd_rcv( dev );
- outb_p( PRX, ISR ); /* acknowledge interrupt */
- }
- /* This completes rx processing... whats next */
-
- if ( inb_p( ISR ) & PTX ) { /* finished sending a packet. */
- wd_trs( dev );
- outb_p( PTX, ISR ); /* acknowledge interrupt */
- }
-
- if (inb_p( ISR ) & RXE ) { /* recieve error */
- stats.rx_errors++; /* general errors */
- errors = inb_p( RSR ); /* detailed errors */
- if (errors & CRC )
- stats.rx_crc_errors++;
- if (errors & FAE )
- stats.rx_frame_errors++;
- if (errors & FO )
- stats.rx_fifo_errors++;
- if (errors & MPA )
- stats.rx_missed_errors++;
- outb_p( RXE, ISR ); /* acknowledge interrupt */
- }
-
- if (inb_p( ISR ) & TXE ) { /* transmit aborted! */
- stats.tx_errors++; /* general errors */
- errors = inb_p( TSR ); /* get detailed errors */
- if (errors & ABT ){
- stats.tx_aborted_errors++;
- printk("\nwd8013 - network cable open!");
- }
- if (errors & FU )
- {
- stats.tx_fifo_errors++;
- printk("\nwd8013 - TX FIFO underrun!");
- }
-
- /* Cannot do anymore - empty the bit bucket */
- tx_aborted = 1;
- wd_trs( dev );
- tx_aborted = 0;
-
- outb_p( TXE, ISR ); /* acknowledge interrupt */
- }
-
- if( inb_p( ISR ) & CNTE ){ /* Tally counters overflowing */
- errors = inb_p( CNTR0 );
- errors = inb_p( CNTR1 );
- errors = inb_p( CNTR2 );
- outb_p( CNTE, ISR ); /* acknowledge interrupt */
- }
- if( inb_p( ISR ) & RST ) /* Reset has been performed */
- outb_p( RST, ISR ); /* acknowledge interrupt */
-
- if( wd_debug ){
- if( ( isr = inb_p( ISR ) ) != 0 )
- printk("\nwd8013 - ISR not cleared = x%x", isr );
- }
- if( ++count > max_pages + 1 ){
- printk("\nwd8013_interrupt - infinite loop detected, isr = x%x, count = %d", isr, count );
- }
- cli();
- } while( inb_p( ISR ) != 0 );
-
- dev->interrupt = 0;
-}
-
-
-static struct sigaction wd8003_sigaction =
-{
- wd8003_interrupt,
- 0,
- 0,
- NULL
-};
-
-
-/* Probe for a WD80x3 board. */
-static int
-we8003_probe(struct ddconf *conf)
-{
- unsigned char csum;
- register int io;
- int i;
-
- io = conf->ioaddr;
- csum = 0;
- for (i = 0; i < 8; i++) {
- csum += inb_p(io + WD_ROM + i);
- }
- if (csum != WD_CHECK) {
- PRINTK (("%s: Warning: board not found at IO=0x%X.\n", io));
- return(-ENODEV);
- }
- return(0);
-}
-
-
-/* Check for a 16-bit ISA controller. Set a flag if found. */
-static void
-we8003_8bit(struct ddi *dev)
-{
-#if !FORCE_8BIT
- unsigned char csum;
- register int io;
- int i;
-
- io = dev->config.ioaddr;
- for (i = 0; i < 8; i++) {
- if (inb_p(io + EN_SAPROM +i) != inb_p(io + EN_CMD + i)) {
- /* Fiddle with 16-bit bit. */
- csum = inb_p(io + EN_REG1);
-
- /* Attempt to clear 16-bit bit. */
- outb(csum ^ BUS16, io + EN_REG1);
- if ((csum & BUS16) == (inb_p(io + EN_REG1) & BUS16)) {
- outb_p(LAN16ENABLE|MEMMASK, io + EN_REG5);
- outb(csum, io + EN_REG1);
- dev->flags |= DDI_FBUS16;
- break;
- }
- outb(csum, io + EN_REG1);
- }
- }
-#endif
-}
-
-
-/* Setup and clear the on-board memory. */
-static void
-we8003_cmem(struct ddi *dev)
-{
- register int io;
-
- io = dev->config.ioaddr;
- outb_p(WD_IMEM, io + WD_CTL); /* mapin the interface memory */
-
- /* FIXME: clear the interface memory here. */
-}
-
-
-/* Fetch and record the interface's hardware address. */
-static void
-we8003_geth(struct ddi *dev)
-{
- register int io;
- register int i;
-
- io = dev->config.ioaddr;
- for (i = 0; i < ETHER_ADDR_LEN; i++) {
- dev->dev_addr[i] = inb_p(io + WD_ROM + i);
- dev->broadcast[i] = 0xff;
- }
-}
-
-
-/* Initialize the WD8003 hardware. */
-int
-we8003_conf(struct ddi *dev)
-{
- /*
- * Check for any boards present. We must change this one
- * time to include complete AutoProbe, but for now, we just
- * see if we need to initialize a board at all. - FvK
- */
- if (dev->config.ioaddr == 0) return(0); /* fake it's OK */
- if (we8003_probe(&dev->config) < 0) return(1);
-
- /* Check for 16-bit board- it doesn't have register 0/8 aliasing. */
- we8003_8bit(dev);
-
- /* Set up and clear the shared memory. */
- we8003_cmem(dev);
-
- /* Fetch and record the hardware address. */
- we8003_geth(dev);
-
- /* Clear the statistics */
- memset((char *) &stats, 0, sizeof(struct enet_statistics);
-
- dev->tbusy = 0;
- dev->interrupt = 0;
- if (irqaction (dev->irq, &we8003_sigaction)) {
- printk("%s: unable to get IRQ%d\n", dev->name, dev->irq);
- return(1);
- }
- return(0);
-}
diff --git a/net/drv/we8003/main.c b/net/drv/we8003/main.c
deleted file mode 100644
index 8a2f671..0000000
--- a/net/drv/we8003/main.c
+++ /dev/null
@@ -1,179 +0,0 @@
-/*
- * we8003.c A generic WD8003 driver for LINUX.
- *
- * Version: @(#)we8003.c 1.0.0 04/22/93
- *
- * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- */
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <linux/ddi.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <errno.h>
-#include <linux/fcntl.h>
-#include <netinet/in.h>
-#include "we8003.h"
-
-
-#define VERSION "1.0.0" /* current version ID */
-
-
-struct ddi_device *we_ptrs[NR_WE8003]; /* pointers to DDI blocks */
-
-
-static int
-we_getconf(struct ddi_device *dev, struct ddconf *cp)
-{
- cp->ioaddr = dev->config.ioaddr; /* I/O base address */
- cp->ioaux = 0; /* not used */
- cp->irq = dev->config.irq; /* IRQ channel */
- cp->dma = 0; /* not used */
- cp->memaddr = dev->config.memaddr; /* RAM base address */
- cp->memsize = dev->config.memsize; /* RAM size */
- return(0);
-}
-
-
-static int
-we_setconf(struct ddi_device *dev, struct ddconf *cp)
-{
- dev->config.ioaddr = cp->ioaddr; /* I/O base address */
- dev->config.irq = cp->irq; /* IRQ channel */
- dev->config.memaddr = cp->memaddr; /* RAM base address */
- dev->config.memsize = cp->memsize; /* RAM size */
- PRINTK (("%s: IO=0x%X IRQ=%d MEM=0x%X(%d)\n",
- dev->name, dev->config.ioaddr, dev->config.irq,
- dev->config.memaddr, dev->config.memsize));
-
- /* FIXME: request the IRQ line and initialize HW here! */
-
- return(0);
-}
-
-
-static int
-we_open(struct inode * inode, struct file * file)
-{
- int minor;
- struct ddi_device *dev;
-
- minor = MINOR(inode->i_rdev);
- if (minor < 0 || minor >= NR_WE8003) return(-ENODEV);
- dev = we_ptrs[minor];
- if (dev == NULL || (dev->flags & DDI_FREADY) == 0) return(-ENODEV);
-
- return(0);
-}
-
-
-static void
-we_close(struct inode * inode, struct file * file)
-{
- int minor;
- struct ddi_device *dev;
-
- minor = MINOR(inode->i_rdev);
- if (minor < 0 || minor >= NR_WE8003) return;
- dev = we_ptrs[minor];
- if (dev == NULL || (dev->flags & DDI_FREADY) == 0) return;
-}
-
-
-static int
-we_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- int minor, ret;
- struct ddi_device *dev;
- struct ddconf conf;
-
- minor = MINOR(inode->i_rdev);
- if (minor < 0 || minor >= NR_WE8003) return(-ENODEV);
- dev = we_ptrs[minor];
- if (dev == NULL || (dev->flags & DDI_FREADY) == 0) return(-ENODEV);
-
- ret = -EINVAL;
- switch(cmd) {
- case DDIOCGNAME:
- memcpy_tofs((void *)arg, dev->name, DDI_MAXNAME);
- ret = 0;
- break;
- case DDIOCGCONF:
- ret = we_getconf(dev, &conf);
- memcpy_tofs((void *)arg, &conf, sizeof(conf));
- break;
- case DDIOCSCONF:
- memcpy_fromfs(&conf, (void *)arg, sizeof(conf));
- ret = we_setconf(dev, &conf);
- break;
- default:
- break;
- }
- return(ret);
-}
-
-
-static struct file_operations we_fops = {
- NULL, /* LSEEK */
- NULL, /* READ */
- NULL, /* WRITE */
- NULL, /* READDIR */
- NULL, /* SELECT */
- we_ioctl, /* IOCTL */
- NULL, /* MMAP */
- we_open, /* OPEN */
- we_close /* CLOSE */
-};
-
-
-/* This is the main entry point of this driver. */
-int
-we8003_init(struct ddi_device *dev)
-{
- static int unit_nr = 0;
- int i;
-
- /* Initialize the driver if this is the first call. */
- if (unit_nr == 0) {
- for(i = 0; i < NR_WE8003; i++) we_ptrs[i] = NULL;
- }
-
- /* Initialize the local control block pointer. */
- we_ptrs[unit_nr] = dev;
- dev->unit = unit_nr++;
- sprintf(dev->name, WE_NAME, dev->unit);
- dev->flags |= DDI_FREADY;
-
- /* Say hello to our viewers. */
- PRINTK (("%s: version %s: ", dev->title, VERSION));
- (void) we_setconf(dev, &dev->config);
-
- /* First of all, setup a VFS major device handler if needed. */
- if (dev->major != 0) {
- if (dev->flags & DDI_FBLKDEV) {
- if (register_blkdev(dev->major, "WE8003", &we_fops) < 0) {
- printk("%s: cannot register block device %d!\n",
- dev->name, dev->major);
- return(-EINVAL);
- }
- }
- if (dev->flags & DDI_FCHRDEV) {
- if (register_chrdev(dev->major, "WE8003", &we_fops) < 0) {
- printk("%s: cannot register character device %d!\n",
- dev->name, dev->major);
- return(-EINVAL);
- }
- }
- }
-
- /* All done... */
- return(0);
-}
diff --git a/net/drv/we8003/we8003.h b/net/drv/we8003/we8003.h
deleted file mode 100644
index e853622..0000000
--- a/net/drv/we8003/we8003.h
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * we8003.h Define the interface of the WE8003 Ethernet driver.
- *
- * Version: @(#)we8003.h 1.0.0 (02/11/93)
- *
- * Author: Fred N. van Kempen, <waltje@uwalt.nl.mugnet.org>
- */
-#ifndef _LINUX_WE8003_H
-#define _LINUX_WE8003_H
-
-
-#define CONF_WE8003 0 /* add this driver to kernel */
-#define FORCE_8BIT 0 /* for forcing the WD8003 mode */
-
-
-#define WE_DEBUG
-#ifdef WE_DEBUG
-# define PRINTK(x) printk x
-#else
-# define PRINTK(x) /**/
-#endif
-
-
-#define NR_WE8003 4 /* max number of units */
-#define WE_NAME "WE8003.%d" /* our DDI ID string */
-
-
-extern struct ddi_device *we_ptrs[NR_WE8003]; /* pointers to DDI blocks */
-
-
-extern int we8003_init(struct ddi_device *dev);
-
-#endif /* _LINUX_WE8003_H */
diff --git a/net/inet/8390.c b/net/inet/8390.c
deleted file mode 100644
index 3c15fe9..0000000
--- a/net/inet/8390.c
+++ /dev/null
@@ -1,707 +0,0 @@
-/* 8390.c: A general NS8390 ethernet driver core for linux. */
-/*
- Written 1992,1993 by Donald Becker.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used and
- distributed according to the terms of the GNU Public License,
- incorporated herein by reference.
-
- This is the chip-specific code for many 8390-based ethernet adaptors.
-
- The Author may be reached as becker@super.org or
- C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-*/
-
-static char *version =
- "8390.c:v0.99-13 9/3/93 for 0.99.13 Donald Becker (becker@super.org)\n";
-#include <linux/config.h>
-
-/*
- Braindamage remaining:
-
- Ethernet devices should use a chr_drv device interface, with ioctl()s to
- configure the card, bring the interface up or down, allow access to
- statistics, and maybe read() and write() access to raw packets.
- This won't be done until after Linux 1.00.
-
-Sources:
- The National Semiconductor LAN Databook, and the 3Com 3c503 databook.
- The NE* programming info came from the Crynwr packet driver, and figuring
- out that the those boards are similar to the NatSemi evaluation board
- described in AN-729. Thanks NS, no thanks to Novell/Eagle.
- */
-
-#include <linux/config.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/fs.h>
-#include <linux/tty.h>
-#include <linux/types.h>
-#include <linux/ptrace.h>
-#include <linux/string.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <asm/io.h>
-#include <errno.h>
-#include <linux/fcntl.h>
-#include <linux/in.h>
-#include <linux/interrupt.h>
-
-#include "dev.h"
-#include "eth.h"
-#include "ip.h"
-#include "protocol.h"
-#include "tcp.h"
-#include "skbuff.h"
-#include "sock.h"
-#include "arp.h"
-
-#include "8390.h"
-
-#define ei_reset_8390 (ei_local->reset_8390)
-#define ei_block_output (ei_local->block_output)
-#define ei_block_input (ei_local->block_input)
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifdef EI_DEBUG
-int ei_debug = EI_DEBUG;
-#else
-int ei_debug = 1;
-#endif
-
-/* Max number of packets received at one Intr. */
-/*static int high_water_mark = 0;*/
-
-/* Index to functions. */
-/* Put in the device structure. */
-int ei_open(struct device *dev);
-/* Dispatch from interrupts. */
-void ei_interrupt(int reg_ptr);
-static void ei_tx_intr(struct device *dev);
-static void ei_receive(struct device *dev);
-static void ei_rx_overrun(struct device *dev);
-
-/* Routines generic to NS8390-based boards. */
-void NS8390_init(struct device *dev, int startp);
-static void NS8390_trigger_send(struct device *dev, unsigned int length,
- int start_page);
-
-struct sigaction ei_sigaction = { ei_interrupt, 0, 0, NULL, };
-
-/* Open/initialize the board. This routine goes all-out, setting everything
- up anew at each open, even though many of these registers should only
- need to be set once at boot.
- */
-int
-ei_open(struct device *dev)
-{
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
-
- if ( ! ei_local) {
- printk("%s: Opening a non-existent physical device\n", dev->name);
- return 1; /* ENXIO would be more accurate. */
- }
-
- irq2dev_map[dev->irq] = dev;
- NS8390_init(dev, 1);
- ei_local->tx1 = ei_local->tx2 = 0;
- /* The old local flags... */
- ei_local->txing = 0;
- /* ... are now global. */
- dev->tbusy = 0;
- dev->interrupt = 0;
- dev->start = 1;
- ei_local->irqlock = 0;
- return 0;
-}
-
-static int
-ei_start_xmit(struct sk_buff *skb, struct device *dev)
-{
- int e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int length, send_length;
- int tmp_tbusy; /* we must lock dev_tint in dev.c with dev->t_busy =1 */
- /* because on a slow pc a quasi endless loop can appear */
-
- if (dev->tbusy) { /* Do timeouts, just like the 8003 driver. */
- int txsr = inb(e8390_base+EN0_TSR), isr;
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5 || (tickssofar < 15 && ! (txsr & ENTSR_PTX))) {
- return 1;
- }
- isr = inb(e8390_base+EN0_ISR);
- printk("%s: transmit timed out, TX status %#2x, ISR %#2x.\n",
- dev->name, txsr, isr);
- /* It's possible to check for an IRQ conflict here.
- I may have to do that someday. */
- if (isr)
- printk("%s: Possible IRQ conflict on IRQ%d?", dev->name, dev->irq);
- else
- printk("%s: Possible network cable problem?\n", dev->name);
- /* It futile, but try to restart it anyway. */
- ei_reset_8390(dev);
- NS8390_init(dev, 1);
- printk("\n");
- }
-
- /* This is new: it means some higher layer thinks we've missed an
- tx-done interrupt. Caution: dev_tint() handles the cli()/sti()
- itself. */
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
- /* Fill in the ethernet header. */
- if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
- skb->dev = dev;
- arp_queue (skb);
- return 0;
- }
-
- if (skb->len <= 0)
- return 0;
- length = skb->len;
- send_length = ETH_ZLEN < length ? length : ETH_ZLEN;
- /* Turn off interrupts so that we can put the packet out safely. */
- cli();
- if (dev->interrupt || ei_local->irqlock) {
- /* We should never get here during an interrupt after 0.99.4. */
- sti();
- if (ei_debug > 2)
- printk("%s: Attempt to reenter critical zone%s.\n",
- dev->name, ei_local->irqlock ? " during interrupt" : "");
- return 1;
- }
- outb(0x00, e8390_base + EN0_IMR);
- tmp_tbusy=dev->tbusy;
- dev->tbusy = 1; /* lock dev_tint() in dev.c */
- ei_local->irqlock = 1;
- sti();
- if (ei_local->pingpong) {
- int output_page;
- if (ei_local->tx1 == 0) {
- output_page = ei_local->tx_start_page;
- ei_local->tx1 = send_length;
- if (ei_debug && ei_local->tx2 > 0)
- printk("%s: idle transmitter tx2=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx2, ei_local->lasttx,
- ei_local->txing);
- } else if (ei_local->tx2 == 0) {
- output_page = ei_local->tx_start_page + 6;
- ei_local->tx2 = send_length;
- if (ei_debug && ei_local->tx1 > 0)
- printk("%s: idle transmitter, tx1=%d, lasttx=%d, txing=%d.\n",
- dev->name, ei_local->tx1, ei_local->lasttx,
- ei_local->txing);
- } else {
- /* We can get to here if we get an rx interrupt and queued
- a tx packet just before masking 8390 irqs above. */
- if (ei_debug > 2)
- printk("%s: No packet buffer space for ping-pong use.\n",
- dev->name);
- cli();
- ei_local->irqlock = 0;
- dev->tbusy = tmp_tbusy;
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- sti();
- return 1;
- }
- dev->trans_start = jiffies;
- ei_block_output(dev, length, (unsigned char *)(skb+1), output_page);
- if (! ei_local->txing) {
- NS8390_trigger_send(dev, send_length, output_page);
- if (output_page == ei_local->tx_start_page)
- ei_local->tx1 = -1, ei_local->lasttx = -1;
- else
- ei_local->tx2 = -1, ei_local->lasttx = -2;
- ei_local->txing = 1;
- } else
- ei_local->txqueue++;
- if (ei_local->tx1 && ei_local->tx2)
- tmp_tbusy = 1;
- } else {
- dev->trans_start = jiffies;
- ei_block_output(dev, length, (unsigned char *)(skb+1),
- ei_local->tx_start_page);
- NS8390_trigger_send(dev, send_length, ei_local->tx_start_page);
- tmp_tbusy = 1;
- } /* PINGPONG */
-
- if (skb->free)
- kfree_skb (skb, FREE_WRITE);
-
- /* Turn 8390 interrupts back on. */
- cli();
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- ei_local->irqlock = 0;
- dev->tbusy=tmp_tbusy;
- sti();
- return 0;
-}
-
-/* The typical workload of the driver:
- Handle the ether interface interrupts. */
-void
-ei_interrupt(int reg_ptr)
-{
- int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
- struct device *dev = (struct device *)(irq2dev_map[irq]);
- int e8390_base;
- int interrupts, boguscount = 0;
- struct ei_device *ei_local;
-
- if (dev == NULL) {
- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- e8390_base = dev->base_addr;
- ei_local = (struct ei_device *) dev->priv;
- if (dev->interrupt || ei_local->irqlock) {
- /* The "irqlock" check is only for testing. */
- sti();
- printk(ei_local->irqlock
- ? "%s: Interrupted while interrupts are masked! isr=%#2x imr=%#2x.\n"
- : "%s: Reentering the interrupt handler! isr=%#2x imr=%#2x.\n",
- dev->name, inb_p(e8390_base + EN0_ISR),
- inb_p(e8390_base + EN0_IMR));
- return;
- }
-
- dev->interrupt = 1;
- sti(); /* Allow other interrupts. */
-
- /* Change to page 0 and read the intr status reg. */
- outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
- if (ei_debug > 3)
- printk("%s: interrupt(isr=%#2.2x).\n", dev->name,
- inb_p(e8390_base + EN0_ISR));
-
- /* !!Assumption!! -- we stay in page 0. Don't break this. */
- while ((interrupts = inb_p(e8390_base + EN0_ISR)) != 0
- && ++boguscount < 20) {
- if (interrupts & ENISR_RDC) {
- /* Ack meaningless DMA complete. */
- outb_p(ENISR_RDC, e8390_base + EN0_ISR);
- }
- if (interrupts & ENISR_OVER) {
- ei_rx_overrun(dev);
- } else if (interrupts & (ENISR_RX+ENISR_RX_ERR)) {
- /* Got a good (?) packet. */
- ei_receive(dev);
- }
- /* Push the next to-transmit packet through. */
- if (interrupts & ENISR_TX) {
- ei_tx_intr(dev);
- } else if (interrupts & ENISR_COUNTERS) {
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- ei_local->stat.rx_frame_errors += inb_p(e8390_base + EN0_COUNTER0);
- ei_local->stat.rx_crc_errors += inb_p(e8390_base + EN0_COUNTER1);
- ei_local->stat.rx_missed_errors+= inb_p(e8390_base + EN0_COUNTER2);
- outb_p(ENISR_COUNTERS, e8390_base + EN0_ISR); /* Ack intr. */
- }
-
- /* Ignore the transmit errs and reset intr for now. */
- if (interrupts & ENISR_TX_ERR) {
- outb_p(ENISR_TX_ERR, e8390_base + EN0_ISR); /* Ack intr. */
- }
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
- }
-
- if (interrupts && ei_debug) {
- printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base + E8390_CMD);
- outb_p(0xff, e8390_base + EN0_ISR); /* Ack. all intrs. */
- }
- dev->interrupt = 0;
- return;
-}
-
-/* We have finished a transmit: check for errors and then trigger the next
- packet to be sent. */
-static void
-ei_tx_intr(struct device *dev)
-{
- int e8390_base = dev->base_addr;
- int status = inb(e8390_base + EN0_TSR);
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
-
- outb_p(ENISR_TX, e8390_base + EN0_ISR); /* Ack intr. */
-
- if (ei_local->pingpong) {
- ei_local->txqueue--;
- if (ei_local->tx1 < 0) {
- if (ei_local->lasttx != 1 && ei_local->lasttx != -1)
- printk("%s: bogus last_tx_buffer %d, tx1=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx1);
- ei_local->tx1 = 0;
- dev->tbusy = 0;
- if (ei_local->tx2 > 0) {
- NS8390_trigger_send(dev, ei_local->tx2, ei_local->tx_start_page + 6);
- dev->trans_start = jiffies;
- ei_local->txing = 1;
- ei_local->tx2 = -1,
- ei_local->lasttx = 2;
- } else
- ei_local->lasttx = 20, ei_local->txing = 0;
- } else if (ei_local->tx2 < 0) {
- if (ei_local->lasttx != 2 && ei_local->lasttx != -2)
- printk("%s: bogus last_tx_buffer %d, tx2=%d.\n",
- ei_local->name, ei_local->lasttx, ei_local->tx2);
- ei_local->tx2 = 0;
- dev->tbusy = 0;
- if (ei_local->tx1 > 0) {
- NS8390_trigger_send(dev, ei_local->tx1, ei_local->tx_start_page);
- dev->trans_start = jiffies;
- ei_local->txing = 1;
- ei_local->tx1 = -1;
- ei_local->lasttx = 1;
- } else
- ei_local->lasttx = 10, ei_local->txing = 0;
- } else
- printk("%s: unexpected TX-done interrupt, lasttx=%d.\n",
- dev->name, ei_local->lasttx);
- } else {
- ei_local->txing = 0;
- dev->tbusy = 0;
- }
-
- /* Do the statistics _after_ we start the next TX. */
- if (status & ENTSR_PTX)
- ei_local->stat.tx_packets++;
- else
- ei_local->stat.tx_errors++;
- if (status & ENTSR_COL)
- ei_local->stat.collisions++;
- if (status & ENTSR_ABT)
- ei_local->stat.tx_aborted_errors++;
- if (status & ENTSR_CRS)
- ei_local->stat.tx_carrier_errors++;
- if (status & ENTSR_FU)
- ei_local->stat.tx_fifo_errors++;
- if (status & ENTSR_CDH)
- ei_local->stat.tx_heartbeat_errors++;
- if (status & ENTSR_OWC)
- ei_local->stat.tx_window_errors++;
-
- mark_bh (INET_BH);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-
-static void
-ei_receive(struct device *dev)
-{
- int e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int rxing_page, this_frame, next_frame, current_offset;
- int boguscount = 0;
- struct e8390_pkt_hdr rx_frame;
- int num_rx_pages = ei_local->stop_page-ei_local->rx_start_page;
-
- while (++boguscount < 10) {
- int size;
-
- /* Get the rx page (incoming packet pointer). */
- outb_p(E8390_NODMA+E8390_PAGE1, e8390_base + E8390_CMD);
- rxing_page = inb_p(e8390_base + EN1_CURPAG);
- outb_p(E8390_NODMA+E8390_PAGE0, e8390_base + E8390_CMD);
-
- /* Remove one frame from the ring. Boundary is alway a page behind. */
- this_frame = inb_p(e8390_base + EN0_BOUNDARY) + 1;
- if (this_frame >= ei_local->stop_page)
- this_frame = ei_local->rx_start_page;
-
- /* Someday we'll omit the previous step, iff we never get this message.*/
- if (ei_debug > 0 && this_frame != ei_local->current_page)
- printk("%s: mismatched read page pointers %2x vs %2x.\n",
- dev->name, this_frame, ei_local->current_page);
-
- if (this_frame == rxing_page) /* Read all the frames? */
- break; /* Done for now */
-
- current_offset = this_frame << 8;
- ei_block_input(dev, sizeof(rx_frame), (char *)&rx_frame,
- current_offset);
-
- size = rx_frame.count - sizeof(rx_frame);
-
- next_frame = this_frame + 1 + ((size+4)>>8);
-
- /* Check for bogosity warned by 3c503 book: the status byte is never
- written. This happened a lot during testing! This code should be
- cleaned up someday, and the printk()s should be PRINTK()s. */
- if ( rx_frame.next != next_frame
- && rx_frame.next != next_frame + 1
- && rx_frame.next != next_frame - num_rx_pages
- && rx_frame.next != next_frame + 1 - num_rx_pages) {
-#ifndef EI_DEBUG
- ei_local->current_page = rxing_page;
- outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
- continue;
-#else
- static int last_rx_bogosity = -1;
- printk("%s: bogus packet header, status=%#2x nxpg=%#2x sz=%#x (at %#4x)\n",
- dev->name, rx_frame.status, rx_frame.next, rx_frame.count,
- current_offset);
-
- if (ei_local->stat.rx_packets != last_rx_bogosity) {
- /* Maybe we can avoid resetting the chip... empty the packet ring. */
- ei_local->current_page = rxing_page;
- printk("%s: setting next frame to %#2x (nxt=%#2x, rx_frm.nx=%#2x rx_frm.stat=%#2x).\n",
- dev->name, ei_local->current_page, next_frame,
- rx_frame.next, rx_frame.status);
- last_rx_bogosity = ei_local->stat.rx_packets;
- outb(ei_local->current_page-1, e8390_base+EN0_BOUNDARY);
- continue;
- } else {
- /* Oh no Mr Bill! Last ditch error recovery. */
- printk("%s: recovery failed, resetting at packet #%d..",
- dev->name, ei_local->stat.rx_packets);
- sti();
- ei_reset_8390(dev);
- NS8390_init(dev, 1);
- printk("restarting.\n");
- return;
- }
-#endif /* EI8390_NOCHECK */
- }
-
- if ((size < 32 || size > 1535) && ei_debug)
- printk("%s: bogus packet size, status=%#2x nxpg=%#2x size=%#x\n",
- dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
- if ((rx_frame.status & 0x0F) == ENRSR_RXOK) {
- int sksize = sizeof(struct sk_buff) + size;
- struct sk_buff *skb;
- skb = (struct sk_buff *) kmalloc(sksize, GFP_ATOMIC);
- if (skb != NULL) {
- skb->lock = 0;
- skb->mem_len = sksize;
- skb->mem_addr = skb;
- /* 'skb+1' points to the start of sk_buff data area. */
- ei_block_input(dev, size, (char *)(skb+1),
- current_offset + sizeof(rx_frame));
- if (dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev)) {
- printk("%s: receive buffers full.\n", dev->name);
- kfree_s(skb, sksize);
- break;
- }
- } else if (ei_debug) {
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, sksize);
- break;
- }
- ei_local->stat.rx_packets++;
- } else {
- int errs = rx_frame.status;
- if (ei_debug)
- printk("%s: bogus packet, status=%#2x nxpg=%#2x size=%d\n",
- dev->name, rx_frame.status, rx_frame.next, rx_frame.count);
- if (errs & ENRSR_FO)
- ei_local->stat.rx_fifo_errors++;
- }
- next_frame = rx_frame.next;
-
- /* This should never happen, it's here for debugging. */
- if (next_frame >= ei_local->stop_page) {
- printk("%s: next frame inconsistency, %#2x..", dev->name, next_frame);
- next_frame = ei_local->rx_start_page;
- }
- ei_local->current_page += 1 + ((size+4)>>8);
- ei_local->current_page = next_frame;
- outb(next_frame-1, e8390_base+EN0_BOUNDARY);
- }
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(INET_BH) for us and will work on them
- when we get to the bottom-half routine. */
-
- /* Bug alert! Reset ENISR_OVER to avoid spurious overruns! */
- outb_p(ENISR_RX+ENISR_RX_ERR+ENISR_OVER, e8390_base+EN0_ISR);
- return;
-}
-
-/* We have a receiver overrun: we have to kick the 8390 to get it started
- again.*/
-static void
-ei_rx_overrun(struct device *dev)
-{
- int e8390_base = dev->base_addr;
- int reset_start_time = jiffies;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
-
- /* We should already be stopped and in page0. Remove after testing. */
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base+E8390_CMD);
-
- if (ei_debug)
- printk("%s: Receiver overrun.\n", dev->name);
- ei_local->stat.rx_over_errors++;
-
- /* The we.c driver does dummy = inb_p( RBCR[01] ); at this point.
- It might mean something -- magic to speed up a reset? A 8390 bug?*/
-
- /* Wait for reset in case the NIC is doing a tx or rx. This could take up to
- 1.5msec, but we have no way of timing something in that range. The 'jiffies'
- are just a sanity check. */
- while ((inb_p(e8390_base+EN0_ISR) & ENISR_RESET) == 0)
- if (jiffies - reset_start_time > 1) {
- printk("%s: reset did not complete at ei_rx_overrun.\n",
- dev->name);
- NS8390_init(dev, 1);
- return;
- };
-
- /* Remove packets right away. */
- ei_receive(dev);
-
- outb_p(0xff, e8390_base+EN0_ISR);
- /* Generic 8390 insns to start up again, same as in open_8390(). */
- outb_p(E8390_NODMA + E8390_PAGE0 + E8390_START, e8390_base + E8390_CMD);
- outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
-}
-
-static struct enet_statistics *
-get_stats(struct device *dev)
-{
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- return &ei_local->stat;
-}
-
-/* Initialize the rest of the 8390 device structure. */
-int
-ethdev_init(struct device *dev)
-{
- int i;
-
- if (ei_debug > 1)
- printk(version);
-
- for (i = 0; i < DEV_NUMBUFFS; i++)
- dev->buffs[i] = NULL;
-
- /* The open call may be overridden by the card-specific code. */
- if (dev->open == NULL)
- dev->open = &ei_open;
-
- dev->get_stats = get_stats;
- dev->hard_header = eth_header;
- dev->add_arp = eth_add_arp;
- dev->queue_xmit = dev_queue_xmit;
- dev->rebuild_header = eth_rebuild_header;
- dev->type_trans = eth_type_trans;
-
- if (dev->priv == NULL) {
- struct ei_device *ei_local;
-
- dev->priv = kmalloc(sizeof(struct ei_device), GFP_KERNEL);
- memset(dev->priv, 0, sizeof(struct ei_device));
- ei_local = (struct ei_device *)dev->priv;
-#ifndef NO_PINGPONG
- ei_local->pingpong = 1;
-#endif
- }
-
- dev->hard_start_xmit = &ei_start_xmit;
-
- dev->type = ARPHRD_ETHER;
- dev->hard_header_len = ETH_HLEN;
- dev->mtu = 1500; /* eth_mtu */
- dev->addr_len = ETH_ALEN;
- for (i = 0; i < dev->addr_len; i++) {
- dev->broadcast[i]=0xff;
- }
-
- /* New-style flags. */
- dev->flags = IFF_BROADCAST;
- dev->family = AF_INET;
- dev->pa_addr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = sizeof(unsigned long);
-
- return 0;
-}
-
-
-/* This page of functions should be 8390 generic */
-/* Follow National Semi's recommendations for initializing the "NIC". */
-void NS8390_init(struct device *dev, int startp)
-{
- int e8390_base = dev->base_addr;
- struct ei_device *ei_local = (struct ei_device *) dev->priv;
- int i;
- int endcfg = ei_local->word16 ? (0x48 | ENDCFG_WTS) : 0x48;
-
- /* Follow National Semi's recommendations for initing the DP83902. */
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base); /* 0x21 */
- outb_p(endcfg, e8390_base + EN0_DCFG); /* 0x48 or 0x49 */
- /* Clear the remote byte count registers. */
- outb_p(0x00, e8390_base + EN0_RCNTLO);
- outb_p(0x00, e8390_base + EN0_RCNTHI);
- /* Set to monitor and loopback mode -- this is vital!. */
- outb_p(E8390_RXOFF, e8390_base + EN0_RXCR); /* 0x20 */
- outb_p(E8390_TXOFF, e8390_base + EN0_TXCR); /* 0x02 */
- /* Set the transmit page and receive ring. */
- outb_p(ei_local->tx_start_page, e8390_base + EN0_TPSR);
- ei_local->tx1 = ei_local->tx2 = 0;
- outb_p(ei_local->rx_start_page, e8390_base + EN0_STARTPG);
- outb_p(ei_local->stop_page-1, e8390_base + EN0_BOUNDARY); /* 3c503 says 0x3f,NS0x26*/
- ei_local->current_page = ei_local->rx_start_page; /* assert boundary+1 */
- outb_p(ei_local->stop_page, e8390_base + EN0_STOPPG);
- /* Clear the pending interrupts and mask. */
- outb_p(0xFF, e8390_base + EN0_ISR);
- outb_p(0x00, e8390_base + EN0_IMR);
-
- /* Copy the station address into the DS8390 registers,
- and set the multicast hash bitmap to receive all multicasts. */
- cli();
- outb_p(E8390_NODMA + E8390_PAGE1 + E8390_STOP, e8390_base); /* 0x61 */
- for(i = 0; i < 6; i++) {
- outb_p(dev->dev_addr[i], e8390_base + EN1_PHYS + i);
- }
- for(i = 0; i < 8; i++)
- outb_p(0xff, e8390_base + EN1_MULT + i);
-
- outb_p(ei_local->rx_start_page, e8390_base + EN1_CURPAG);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_STOP, e8390_base);
- sti();
- if (startp) {
- outb_p(0xff, e8390_base + EN0_ISR);
- outb_p(ENISR_ALL, e8390_base + EN0_IMR);
- outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, e8390_base);
- outb_p(E8390_TXCONFIG, e8390_base + EN0_TXCR); /* xmit on. */
- /* 3c503 TechMan says rxconfig only after the NIC is started. */
- outb_p(E8390_RXCONFIG, e8390_base + EN0_RXCR); /* rx on, */
- }
- return;
-}
-
-/* Trigger a transmit start, assuming the length is valid. */
-static void NS8390_trigger_send(struct device *dev, unsigned int length,
- int start_page)
-{
- int e8390_base = dev->base_addr;
-
- ei_status.txing = 1;
- outb_p(E8390_NODMA+E8390_PAGE0, e8390_base);
-
- if (inb_p(e8390_base) & E8390_TRANS) {
- printk("%s: trigger_send() called with the transmitter busy.\n",
- dev->name);
- return;
- }
- outb_p(length & 0xff, e8390_base + EN0_TCNTLO);
- outb_p(length >> 8, e8390_base + EN0_TCNTHI);
- outb_p(start_page, e8390_base + EN0_TPSR);
- outb_p(E8390_NODMA+E8390_TRANS+E8390_START, e8390_base);
- return;
-}
-
-
-/*
- * Local variables:
- * compile-command: "gcc -D__KERNEL__ -Wall -O6 -x c++ -c 8390.c"
- * version-control: t
- * kept-new-versions: 5
- * End:
- */
diff --git a/net/inet/INTRO.8390 b/net/inet/INTRO.8390
deleted file mode 100644
index 714f69a..0000000
--- a/net/inet/INTRO.8390
+++ /dev/null
@@ -1,62 +0,0 @@
-
-Subject: Enhanced Ethercard driver available for alpha test.
-
-My "8390" Linux ethercard drivers are now available from usra.edu and
-super.org in ~ftp/pub/linux/ethercards/*. They'll be at tsx-11 and
-sunsite RSN.
-
-These drivers support all common 8390-based ethernet boards. Currently
-"common" is defined as:
-
- 3Com Products:
-* 3Com 3c503 Board loaned by Chance Reschke, USRA.edu (thanks!)
- 3Com 3c503/16 and excellent documentation provided by 3Com.
-
- Clones-n-things
- NE1000 Novell and Eagle are useless for documentation,
-* NE2000 but copied the designs directly from NatSemi;->.
-
- WD/SMC products
- WD8003
-* WD8013 Board loaned by Russ Nelson, Crynwr Software. Thanks!
-
-* I've seen it work myself!
-
-There is support for the following boards, but since I've only been
-able to borrow a thinnet of an HP ethercard I haven't been able to test it:
-
- HP LAN adaptors
-** HP27245
-** HP27247
-** HP27250
-
-Thanks are due to the dozens of alpha testers, and special thanks to Chance Reschke <@usra.edu> and Russ Nelson <@crynwr.com> for loaning me ethercards.
-
-The following addresses are autoprobed, in this order:
-wd.c: 0x300, 0x280, 0x380, 0x240
-3c503: 0x300, 0x310, 0x330, 0x350, 0x250, 0x280, 0x2a0, 0x2e0
-ne.c: 0x300, 0x280, 0x320, 0x340, 0x360
-hp.c: 0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240
-
-80x3 clones that are reported to work:
- LANNET LEC-45
-
-"NE2000" clones that are reported to work:
- Alta Combo(NE2000 clone)
- Aritsoft LANtastic AE-2 (NE2000 clone w/ extra memory)
- Asante Etherpak 2001/2003
- D-Link Ethernet II
- LTC E-NET/16 P/N: 8300-200-002 (lipka@lip.hanse.de)
- Network Solutions HE-203
- SVEC 4 Dimension Ethernet
- 4-Dimension FD0490 EtherBoard16
- Cabletron products:
- I've had a really bad time with Cabletron -- they strung
- me along for months before telling me all information was
- proprietary. The following boards work, but there probably
- won't be drivers for other versions. Complain to pkelly@ctron.com.
- E1010 No ID PROM and sketchy info from Ctron means you'll
- E1010-x have to compile-in information about your board.
- E2010
- E2010-x
-
diff --git a/net/inet/LICENSE.8390 b/net/inet/LICENSE.8390
deleted file mode 100644
index 500940a..0000000
--- a/net/inet/LICENSE.8390
+++ /dev/null
@@ -1,15 +0,0 @@
-Code in this directory written at the IDA Supercomputing Research Center
-carries the following copyright and license.
-
- Copyright 1993 United States Government as represented by the
- Director, National Security Agency. This software may be used
- and distributed according to the terms of the GNU Public License,
- incorporated herein by reference.
-
- In addition to the disclaimers in the GPL, SRC expressly disclaims any
- and all warranties, expressed or implied, concerning the enclosed software.
- This software was developed at SRC for use in internal research, and the
- intent in sharing this software is to promote the productive interchange
- of ideas throughout the research community. All software is furnished
- on an "as-is" basis. No further updates to this software should be
- expected. Although updates may occur, no commitment exists.
diff --git a/net/inet/Makefile b/net/inet/Makefile
index eeebd52..b4245cf 100644
--- a/net/inet/Makefile
+++ b/net/inet/Makefile
@@ -8,19 +8,16 @@
# Note 2! The CFLAGS definition is now in the main makefile...
.c.o:
- $(CC) $(CFLAGS) \
- -c -o $*.o $<
+ $(CC) $(CFLAGS) -c -o $*.o $<
.s.o:
$(AS) -o $*.o $<
.c.s:
- $(CC) $(CFLAGS) \
- -S -o $*.s $<
+ $(CC) $(CFLAGS) -S -o $*.s $<
-OBJS = Space.o sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \
- eth.o packet.o arp.o dev.o 8390.o wd.o ne.o el2.o hp.o plip.o \
- slip.o slhc.o d_link.o auto_irq.o ip.o raw.o icmp.o tcp.o udp.o\
- lance.o 3c509.o #ip-frag.o
+OBJS = sock.o utils.o route.o proc.o timer.o protocol.o loopback.o \
+ eth.o packet.o arp.o dev.o ip.o raw.o icmp.o tcp.o udp.o \
+ datagram.o skbuff.o
ifdef CONFIG_INET
@@ -34,44 +31,6 @@ inet.o:
endif
-CARDS :=
-include CONFIG
-
-
-Space.o: Space.c CONFIG /usr/include/linux/autoconf.h
- $(CC) $(CPPFLAGS) $(CFLAGS) $(OPTS) $(CARDS) $(DL_OPTS) \
- -c $< -o $@
-
-8390.o: 8390.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(CARDS) -c $< -o $@
-
-wd.o: wd.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $< -o $@
-
-el2.o: el2.c CONFIG el2reg.h
- $(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $< -o $@
-
-ne.o: ne.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $< -o $@
-
-hp.o: hp.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $< -o $@
-
-plip.o: plip.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $< -o $@
-
-slip.o: slip.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(SLIP_OPTS) -c $< -o $@
-
-d_link.o: d_link.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c $< -o $@
-
-lance.o: lance.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(AT_OPTS) -c $< -o $@
-
-3c509.o: 3c509.c CONFIG
- $(CC) $(CPPFLAGS) $(CFLAGS) $(EL3_OPTS) -c $< -o $@
-
subdirs: dummy
for i in $(SUBDIRS); do (cd $$i; $(MAKE)); done
diff --git a/net/inet/README b/net/inet/README
new file mode 100644
index 0000000..c98d222
--- /dev/null
+++ b/net/inet/README
@@ -0,0 +1,28 @@
+
+NET2Debugged 1.22 README
+------------------------
+
+Major Changes
+
+o PLIP driver sort of works
+o UDP and RAW have been partially rewritten for speed
+o Internals heavily cleaned up, and memory monitoring of network
+ memory is now done. (On shift-scroll-lock)
+o ARP should now not generate garbage
+o Using MSG_PEEK can't cause race conditions and crashes
+o Support for bootp clients.
+o Supports RFC931 TAP authd
+o NFS problems with certain types of network configuration are
+ fixed.
+o Doesn't forward packets for other subnet (can cause packet storms)
+o TCP won't ack rst frames causing packet storms (especially with
+ Lan workplace for DOS).
+o Numerous fixes for solidity
+o Verify_area used properly.
+
+
+Bug fixes and improvements for this section of the code should be mailed to
+iiitac@pyr.swan.ac.uk.
+
+
+Alan
diff --git a/net/inet/README.DLINK b/net/inet/README.DLINK
deleted file mode 100644
index cd69879..0000000
--- a/net/inet/README.DLINK
+++ /dev/null
@@ -1,258 +0,0 @@
-From: bj0rn@blox.se (Bjorn Ekwall)
-To: waltje@nic.NL.Mugnet.ORG
-Subject: Re: NET-2 and the D-Link Ethernet driver
-X-Mailer: Mail User's Shell (7.2.4 2/2/92)
-Message-ID: <m0nvKUE-0001OLC@blox.se>
-Date: Tue, 18 May 1993 07:45:13 +0000
-
-
-Hello Fred!
-
-> My collegue put a copy of your article regarding the Dlink 0.20
-> driver on my desk. I wasn't aware such a driver already existed...
->
-> Anyway. I'd like to get a copy of your driver to add it to the
-> current "new" kernel code (called NET-2). Many people are waiting
-> for it, and now is the time to add it... right?
-
-That's true, I'm waiting too :-)
-
-Enclosed is the most current release that has been shipped so far (== v 0.20+).
-Note that there are some things that still needs some attention:
-
- - There is a not yet fully tested part of the code for handling
- alternations of transmitter pages. Enable with "-DD_LINK_FIFO".
-
- - I am only 99% sure that I have not missed any valid
- interrupt-code from the adapter.
-
- - There is always(?) a spurious IRQ 7 interrupt at boot. This might
- come from the port being initialized by lp_init(), but I haven't
- been able to stomp it out. Kludge found in d_link_interrupt().
-
-Anyway, there seems to be some people out there using the driver,
-and I haven't received any bugreports yet on this version
-(hope that Murphy doesn't read email :-))
-
-
-Good luck with the code,
-
-Bjorn Ekwall == bj0rn@blox.se
-
-
-= = = = = = Release shar-file follows = = = = = = = = = = = = = = = = = = =
-Now, here it is!
-
-A driver for the D-Link Ethernet pocket adapter in the parallel port,
-to use with Linux on a laptop PC.
-
-It has been tested with mount, rsh, ftp, telnet and remote X-clients.
-TCP/IP throughput can be expected to be around 70-80 kbytes/second.
-
-It now "runs" on:
- - linux 0.99pl5, (with supplied patch for linux/net/tcp/dev.c)
- - linux 0.99pl6, and later
-(using a 386-25 Taiwan-made with 5Mb DRAM + 120Mb disk (60Mb == linux)).
-
-Since this still is an alpha-release, some bugs might still be lurking...
-
-All comments/requests/fixes to Bjorn Ekwall == bj0rn@blox.se
-
-*** If you read nothing else, at least check around line 20 in the source! ***
-
-(You may want to unshar this in /linux/net/tcp)
-
-This is version 0.20
----- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ---- 8< ----
-= = = = = = Release shar-file ends = = = = = = = = = = = = = = = = = = =
-
-
-
- CONTENTS:
-
- 1. Introduction.
- 2. License.
- 3. Files in this release.
- 4. Installation.
- 5. Known problems and some solutions.
- 6. Acknowledgments.
-
-
- 1. INTRODUCTION.
-
- This is an Ethernet driver for the D-Link Ethernet pocket
- adapter for the parallel port, used with Linux on a laptop.
-
- This is an ALPHA release, i.e. it might not work flawlessly! (:-)
- It now runs on SLS (beg. of February) linux 0.99pl5, patched
- in linux/net/tcp/dev.c, and 0.99pl6 (and later), in a 386-25
- Taiwan-made with 5Mb DRAM + 120Mb disk (60Mb == linux).
-
- I have used this driver for ftp, telnet and X-clients on
- remote machines. Transmissions with ftp seems to work as
- good as can be expected (i.e. about 80k bytes/sec) from a
- parallel port...:-)
-
- All comments/fixes to Bjorn Ekwall (bj0rn@blox.se).
-
-
- 2. LICENSE.
-
- This program is free software; you can redistribute it
- and/or modify it under the terms of the GNU General Public
- License as published by the Free Software Foundation; either
- version 2, or (at your option) any later version.
-
- This program is distributed in the hope that it will be
- useful, but WITHOUT ANY WARRANTY; without even the implied
- warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
- PURPOSE. See the GNU General Public License for more
- details.
-
- You should have received a copy of the GNU General Public
- License along with this program; if not, write to the Free
- Software Foundation, Inc., 675 Mass Ave, Cambridge, MA
- 02139, USA.
-
-
- 3. FILES IN THIS RELEASE.
-
- README.d_link This file.
- d_link.c The Source (,may it be with You :-).
- Makefile.new Replaced "we.o" with "d_link.o"
- Space.c.new An entry for "d_link" instead of "wdxxx"
-
-
- 4. INSTALLATION.
-
- o Replace (or edit) /linux/net/tcp/Makefile with
- Makefile.new (save the original!). Actually, you only
- have to make sure that "d_link.o" is included in the list
- at "OBJS =".
-
- o Replace /linux/net/tcp/Space.c with Space.c.new (save the
- original!). If your kernel source is later than 0.99p5,
- check your original for any greater differences
- (shouldn't really be any).
-
- o Copy d_link.c to /linux/net/tcp if you unshared somewhere
- else.
-
- o If you have linux 0.99p5, then add two lines close to the
- end of /linux/net/tcp/dev.c (thanks Ross Biro, for the
- information!):
- ...
- }
- }
- skb->next = NULL;
- skb->prev = NULL;
- sti();
- /* this will send it through the process again. */
- dev->queue_xmit (skb, dev, -i-1);
- + if (dev->tbusy)
- + return;
- }
- }
-
- ...
-
- o Read the NET_FAQ and the relevant files in /etc/inet
- (hint: "hosts")
-
- o Make sure that TCP/IP is included in your config, and
- then do:
- # cd /linux
- # make clean
- # make depend
- # make Image (or whatever magic you usually do)
-
- o I use lilo to boot multiple kernels, so that I at least
- can have one working kernel :-). If you do too, append
- these lines to /etc/lilo/config:
- ...
- image = /usr/src/linux/Image
- label = newlinux
- root = /dev/hda2 (or whatever YOU have...)
- ...
-
- # /etc/lilo/install
-
- o Do "sync" and reboot the new kernel with a D-Link pocket
- adapter connected.
-
- Now, watch for any fireworks (try to ignore (or live with)
- the smoke... :-) or:
-
- do
- read NET-FAQ and all info in /etc/inet
- if fix in code needed...
- vi /linux/net/tcp/d_link.c
- cd /linux
- make Image
- /etc/lilo/install
- sync
- reboot
- endif
- try it...
- until satisfied
-
-
- 5. KNOWN "PROBLEMS" AND SOME SOLUTIONS.
-
- o Some machines have trouble handling the parallel port and
- the adapter at high speed. If you experience problems
- like "Strange interrupt...", try to uncomment the
- "#define REALLY_SLOW_IO" near line 20 in d_link.c
-
- o A frequent number of "eth0: transmit timed out..." might
- indicate a heavy load on your network or some strange
- internal driver bug. You can decrease the number of
- messages by changing about 25 lines into the function
- "d_link_start_xmit()", where it looks like:
- if (tickssofar < 5)
- Change the "5" to something greater, like 10, 20 or
- whatever... Every "tick" equals 10 milliseconds.
-
- o There has been some "hangs" when communicating with other
- systems. As of now I'm not clear of where the trouble
- might come from. It seems that reception of large
- amounts of information can trigger this. Try to be
- patient and see if the machines can clear up the mess
- without any help (can happen!). If not, try to switch to
- another virtual console and call the other system with
- telnet and see what happens. If your machine seems
- completely locked, there might be a race of transmit and
- receive interrupts emanating from inet_bh() in dev.c .
- The reason why this driver can trigger this is not quite
- clear yet.
-
- o There will always(?) be a spurious IRQ 7 interrupt at
- boot. This might come from the port being initialized by
- lp_init(), but I haven't been able to stomp it out.
- Kludge can be found in d_link_interrupt().
-
- o The code inside d_link_interrupt() is somewhat of a
- guesswork since I'm not quite clear about how the adapter
- REALLY tells us about its internal status. Since my only
- source of information is the asm-source (:-), I'm not
- sure of how to improve on it. Some more turns around the
- edit_a_hack-compile-boot-tryout loop...
-
- o There is some rudimentary support for debugging, see
- the source. Use "-DD_LINK_DEBUG=3" when compiling.
-
-
- 6. ACKNOWLEDGMENTS.
-
- This driver wouldn't have been done without the base
- (and support) from Ross Biro (bir7@leland.stanford.edu).
- The driver also relies upon GPL-ed source from D-Link Inc.
- and from Russel Nelson at Crynwr Software (nelson@crynwr.com).
- Additional input also from Donald Becker (becker@super.org).
- Alpha release primary victim^H^H^H^H^H^Htester:
- Erik Proper (erikp@cs.kun.nl).
-
-
- Happy hacking!
-
- Bjorn Ekwall == bj0rn@blox.se
diff --git a/net/inet/README.DRIVERS b/net/inet/README.DRIVERS
deleted file mode 100644
index 1a769a1..0000000
--- a/net/inet/README.DRIVERS
+++ /dev/null
@@ -1,424 +0,0 @@
-This file contains some info on writing device driver for the
-NET-2 networking suite of the Linux operating system.
-
-Basically, have a look at the "loopback.c" and "slip.c" drivers
-to get a feel of what is going on, and then use the code below
-as a skeleton of the new driver you are writing.
-
-=============================================================================
-/* network.c: A sample network driver core for linux. */
-/*
- Written 1993 by Donald Becker.
- Copyright 1993 United States Government as represented by the Director,
- National Security Agency. This software may only be used and distributed
- according to the terms of the GNU Public License as modified by SRC,
- incorported herein by reference.
-
- The author may be reached as becker@super.org or
- C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715
-*/
-
-static char *version =
- "network.c:v0.02 Donald Becker (becker@super.org)\n";
-
-/* Always include 'config.h' first in case the user wants to turn on
- or override something. */
-#include <linux/config.h>
-
-/*
- Sources:
- List your sources of programming information to document that
- the driver is your own creation, and give due credit to others
- that contributed to the work. Remember that GNU project code
- cannot use proprietary or trade secret information. Interface
- definitions are generally considered non-copyrightable to the
- extent that the same names and structures must be used to be
- compatible. */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/types.h>
-#include <linux/fcntl.h>
-#include <linux/interrupt.h>
-#include <linux/ptrace.h>
-#include <asm/system.h>
-#include <asm/io.h>
-#include <linux/in.h>
-
-#include "inet.h"
-#include "dev.h"
-#include "eth.h"
-#include "ip.h"
-#include "route.h"
-#include "protocol.h"
-#include "tcp.h"
-#include "skbuff.h"
-#include "sock.h"
-#include "arp.h"
-
-/* use 0 for production, 1 for verification, >2 for debug */
-#ifndef NET_DEBUG
-#define NET_DEBUG 2
-#endif
-static unsigned int net_debug = NET_DEBUG;
-
-/* The map from IRQ number (as passed to the interrupt handler) to
- 'struct device'. */
-extern struct device *irq2dev_map[16];
-
-/* Common network statistics -- these will be in *.h someday. */
-struct netstats {
- int tx_packets;
- int rx_packets;
- int tx_errors;
- int rx_errors;
- int missed_packets;
- int soft_tx_errors;
- int soft_rx_errors;
- int soft_trx_err_bits;
-};
-static struct netstats *localstats;
-
-/* Index to functions, as function prototypes. */
-/* Put in the device structure. */
-static int net_open(struct device *dev);
-static void net_send_packet(struct sk_buff *skb, struct device *dev);
-/* Dispatch from interrupts. */
-static void net_interrupt(int reg_ptr);
-static void net_tx_intr(struct device *dev);
-static void net_rx_intr(struct device *dev);
-/* Routines used internally. */
-static void chipset_init(struct device *dev, int startp);
-static void trigger_send(struct device *dev, unsigned int length,
- int start_page);
-extern int netcard_probe(int ioaddr, struct device *dev);
-
-
-/* Open/initialize the board. This is called (in the current kernel)
- sometime after booting when the 'config <dev->name>' program is
- run.
-
- This routine should set everything up anew at each open, even
- registers that "should" only need to be set once at boot, so that
- there is non-reboot way to recover if something goes wrong.
- */
-static int
-net_open(struct device *dev)
-{
- if ( ! net_status.exists) {
- printk("%s: Opening a non-existent physical device\n",
- dev ? dev->name : "(null)");
- return ENXIO; /* Anything non-zero will do. */
- }
-
- chipset_init(dev, 1);
-
- /* If the IRQ line can be software selected find a free line to use. */
- if (dev->irq < 2) {
- int irq_list[] = { 11, 10, 5, 3, 4, 7, 9, 0};
- int *irq = irq_list;
- for (; *irq; irq++) {
- if (request_irq(dev->irq = *irq, &net_interrupt) == 0)
- break;
- }
- if (*irq == 0) {
- printk (" unable to get an IRQ.\n");
- return EAGAIN;
- }
- card_set_irq(dev, *irq);
- }
-
- irq2dev_map[irq] = dev;
- dev->tbusy = 0; /* Transmit busy... */
- dev->interrupt = 0;
- dev->start = 1;
- return 0;
-}
-
-/* The inverse routine to net_open(). */
-static int
-net_close(struct device *dev)
-{
- dev->start = 0;
- card_flush_tx(dev);
- card_disable_reciever(dev);
- irq2dev_map[dev->irq] = NULL;
- /* If not IRQ jumpered, free up the interrupt line. */
- card_set_irq(0);
- free_irq(dev->irq);
- return 0;
-}
-
-static int
-net_start_xmit(struct sk_buff *skb, struct device *dev)
-{
-
- if (dev->tbusy) { /* Do timeouts, to avoid hangs. */
- int tickssofar = jiffies - dev->trans_start;
- if (tickssofar < 5)
- return 1;
- printk("%s: transmit timed out, %s?\n", dev->name,
- tx_done(dev) ? "IRQ conflict" : "network cable problem");
- /* Try to restart the adaptor. */
- chipset_init(dev, 1);
- }
-
- /* If some higher layer thinks we've missed an tx-done interrupt
- we are passed NULL. Caution: dev_tint() handles the cli()/sti()
- itself. */
- if (skb == NULL) {
- dev_tint(dev);
- return 0;
- }
-
- /* For ethernet, fill in the header. */
- if (!skb->arp && dev->rebuild_header(skb+1, dev)) {
- skb->dev = dev;
- arp_queue (skb);
- return 0;
- }
-
- dev->trans_start = jiffies;
- cli();
- net_send_packet(skb, dev);
- sti();
- if (skb->free)
- kfree_skb (skb, FREE_WRITE);
- return 0;
-}
-
-/* The typical workload of the driver:
- Handle the network interface interrupts. */
-static void
-net_interrupt(int reg_ptr)
-{
- int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2);
- struct device *dev = irq2dev_map[irq];
- int interrupts, boguscount = 0;
-
- if (dev == NULL) {
- printk ("net_interrupt(): irq %d for unknown device.\n", irq);
- return;
- }
- dev->interrupt = 1;
- sti(); /* Allow other interrupts. */
-
- if (net_debug >= 4)
- printk("%s: interrupt.\n", dev->name);
-
- localstats = (struct netstats*) dev->private;
-
- do {
- interrupts = chip_read_status(dev);
- if (interrupts & OVERRUN_INTR) {
- localstats->missed_packets++;
- net_rx_overrun(dev);
- } else if (interrupts & RX_INTR) {
- /* Got a good (?) packet. */
- net_receive(dev);
- localstats->rx_packets++;
- }
- if (interrupts & TX_INTR) {
- /* Push the next to-transmit packet through. */
- net_tx_intr(dev);
- } else if (interrupts & COUNTERS_INTR) {
- /* Increment the appropriate 'localstats' field. */
- }
- } while (++boguscount < 20) ;
-
- if (interrupts && net_debug) {
- printk("%s: unknown interrupt %#2x\n", dev->name, interrupts);
- }
- return;
-}
-
-/* We have finished a transmit: check for errors and then mark that
- the bottom half has some work to do. */
-static void
-net_tx_intr(struct device *dev)
-{
- int status = card_get_status(dev);
- if (status & TX_OK)
- tx_packets++;
- else {
- tx_errors++;
- card_reset(dev);
- }
- dev->tbusy = 0;
- mark_bh (INET_BH);
-}
-
-/* We have a good packet(s), get it/them out of the buffers. */
-static void
-net_receive(struct device *dev)
-{
- int boguscount = 0;
-
- do {
- int size = chip_get_rx_size(dev);
- int sksize;
- struct sk_buff *skb;
-
- if (size == 0) /* Read all the frames? */
- break; /* Done for now */
-
- if ((size < 32 || size > dev->mtu) && net_debug)
- printk("%s: Bogus packet size %d.\n", dev->name, size);
-
- sksize = sizeof(struct sk_buff) + size;
- skb = kmalloc(sksize, GFP_ATOMIC);
- if (skb != NULL) {
- skb->lock = 0;
- skb->mem_len = sksize;
- skb->mem_addr = skb;
- /* 'skb+1' points to the start of sk_buff data area. */
- card_get_packet(dev, size, (void *)(skb+1));
- if(dev_rint((void *)skb, size, IN_SKBUFF, dev)) {
- printk("%s: receive buffers full.\n", dev->name);
- break;
- }
- } else if (net_debug) {
- printk("%s: Couldn't allocate a sk_buff of size %d.\n",
- dev->name, sksize);
- break;
- }
- rx_packets++;
- } while (++boguscount < 10);
-
- /* If any worth-while packets have been received, dev_rint()
- has done a mark_bh(INET_BH) for us and will work on them
- when we get to the bottom-half routine. */
- return;
-}
-
-/* We have a receiver overrun: do whatever this chipset needs
- to recover. */
-static void
-net_rx_overrun(struct device *dev)
-{
- int reset_start_time = jiffies;
- if (net_debug)
- printk("%s: Receiver overrun.\n", dev->name);
- return;
-}
-
-int
-netdev_init(struct device *dev)
-{
- int i, found = 0;
- int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0};
-
- /* Alpha testers must have the version number to report bugs. */
- if (net_debug > 1)
- printk(version);
-
- /* Probe for an adaptor at a likely set of locations. */
- if (dev->base_addr > 0x100) {
- if (card_probe_addr(dev, ioaddr) == 0) {
- printk("%s: probe failed at %#3x.\n", dev->name, ioaddr);
- return ENODEV;
- }
- } else {
- for (port = &ports[0]; *port; port++)
- if (card_probe_addr(dev, *port))
- break;
- if (*port == 0) {
- dev->open = NULL;
- printk("No network device found.\n");
- return ENODEV;
- }
- }
-
- /* Initialize the device structure. */
- dev->private = kmalloc(sizeof(struct netstats), GFP_KERNEL);
- memset(dev->private, 0, sizeof(struct netstats));
- for (i = 0; i < DEV_NUMBUFFS; i++)
- dev->buffs[i] = NULL;
-
- dev->type = ETHER_TYPE;
- for (i = 0; i < dev->addr_len; i++) {
- dev->broadcast[i]=0xff;
- }
- card_get_station_address(dev->dev_addr);
-
- /* Finish setting up the DEVICE info. */
- dev->queue_xmit = dev_queue_xmit;
- dev->open = net_open;
- dev->stop = net_close;
- dev->hard_start_xmit= net_start_xmit;
-
- /* These are ethernet specific. */
- dev->type = ARPHRD_ETHER;
- dev->mtu = 1500; /* eth_mtu */
- dev->hard_header = eth_header;
- dev->add_arp = eth_add_arp;
- dev->rebuild_header = eth_rebuild_header;
- dev->type_trans = eth_type_trans;
- dev->hard_header_len= ETH_HLEN;
- dev->addr_len = ETH_ALEN;
-
- /* New-style flags. */
- dev->flags = 0;
- dev->family = AF_INET;
- dev->pa_addr = 0;
- dev->pa_brdaddr = 0;
- dev->pa_mask = 0;
- dev->pa_alen = sizeof(unsigned long);
-
-#ifdef jumpered_interrupts
- /* If this board has jumpered interrupts, snarf the interrupt vector
- now. There is no point in waiting since no other device can use
- the interrupt, and this marks the 'irqaction' as busy. */
-
- if (dev->irq == -1)
- ; /* Do nothing: a user-level program will set it. */
- else if (dev->irq < 2) { /* "Auto-IRQ" */
- autoirq_setup(0);
- /* Trigger an interrupt here. */
- dev->irq = autoirq_report(0);
- if (net_debug >= 2)
- printk(" autoirq is %d", dev->irq);
- } else if (dev->irq == 2)
- /* Fixup for users that don't know that IRQ 2 is really IRQ 9,
- or don't know which one to set. */
- dev->irq = 9;
-
- { int irqval = request_irq(dev->irq, &net_interrupt);
- if (irqval) {
- printk ("%s: unable to get IRQ %d (irqval=%d).\n", dev->name,
- dev->irq, irqval);
- return 0;
- }
- }
-#endif /* jumpered interrupt */
- printk("%s: %s found at %#3x, IRQ %d.\n", dev->name,
- "network card", dev->base_addr, dev->irq);
-
- return 0;
-}
-
-/* Check IOADDR for a network adaptor of this type, and return
- a non-zero value iff one exists. */
-static int
-card_probe_addr(struct device *dev, int ioaddr)
-{
- if (inb_p(ioaddr) == 0xFF) { /* Trivial check. */
- return 0;
- }
-
- /* Check for the card here. You should minimize outb()s, and
- restore the previous value if possible. */
- if (/*probe result */1 == 0)
- return 0;
-
- return dev->base_addr = ioaddr;
-}
-
-/*
- * Local variables:
- * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c network.c"
- * version-control: t
- * kept-new-versions: 5
- * End:
- */
-===============================================================================
diff --git a/net/inet/README.TODO b/net/inet/README.TODO
deleted file mode 100644
index ce2d19e..0000000
--- a/net/inet/README.TODO
+++ /dev/null
@@ -1,32 +0,0 @@
-THINGS TO DO:
-
-+ All device drivers must adhere to the DDI scheme of being able
- to get configured dynamically (i.e. at run time). This requires
- lots of work in the drivers, and in the way the "dev" structures
- are handled. Before Linux 1.0 if possible.
-
-+ Replace the ugly 'sk_buff' structure with the 'mbuf' structure,
- and redo all code accordingly.
-
-+ Move all device drivers to the 'drv' layer.
-
-+ Impose a much stricter layering between the protocol modules.
-
-+ Implement IP fragmentation.
-
-+ Add support for the PPP and AX.25 protocols, possibly via the
- external 'pkt' driver. This is NOT the current 'packet.c' module,
- but a scheme in which we can implement external (user-space) drivers
- for networking protocols, like SLIP, PPP and AX.25.
-
-+ Add support for the Novell IPX/SPX protocols.
-
-REMAINING KNOWN BUGS AND PROBLEMS:
-
-+ Local-port weirdness when using the 'r' utilities?
- All connections seem to be using the same local (privileged) TCP
- port (1023), and this cannot be the way God wanted it to be...
-
-+ Sudden lockups when overloading a socket?
- This seems to occur with X11 sessions (as per Linus Torvalds, 05/28/93)
- and has its origin in the new timer.c code...
diff --git a/net/inet/arp.c b/net/inet/arp.c
index e78bc0e..a3e5ff8 100644
--- a/net/inet/arp.c
+++ b/net/inet/arp.c
@@ -20,6 +20,26 @@
* Stephen A. Wood, <saw@hallc1.cebaf.gov>
* Arnt Gulbrandsen, <agulbra@pvv.unit.no>
*
+ * Fixes:
+ * 'Mr Linux' : arp problems.
+ * Alan Cox : arp_ioctl now checks memory areas with verify_area.
+ * Alan Cox : Non IP arp message now only appears with debugging on.
+ * Alan Cox : arp queue is volatile (may be altered by arp messages while doing sends)
+ * Generic queue code is urgently needed!
+ * Alan Cox : Deleting your own ip addr now gives EINVAL not a printk message.
+ * Alan Cox : Fix to arp linked list error
+ * Alan Cox : Ignore broadcast arp (Linus' idea 8-))
+ * Alan Cox : arp_send memory leak removed
+ * Alan Cox : generic skbuff code fixes.
+ * Alan Cox : 'Bad Packet' only reported on debugging
+ * To Fix:
+ * : arp response allocates an skbuff to send. However there is a perfectly
+ * good spare skbuff the right size about to be freed (the query). Use the
+ * query for the reply. This avoids an out of memory case _and_ speeds arp
+ * up.
+ * : FREE_READ v FREE_WRITE errors. Not critical as loopback arps don't occur
+ *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -88,7 +108,8 @@ static struct {
struct arp_table *arp_tables[ARP_TABLE_SIZE] = {
NULL,
};
-struct sk_buff *arp_q = NULL;
+
+struct sk_buff * volatile arp_q = NULL;
/* Dump the ADDRESS bytes of an unknown hardware type. */
@@ -166,38 +187,15 @@ static void
arp_send_q(void)
{
struct sk_buff *skb;
- struct sk_buff *next;
-
+ struct sk_buff *volatile work_q;
cli();
- next = arp_q;
+ work_q = arp_q;
+ skb_new_list_head(&work_q);
arp_q = NULL;
sti();
- while ((skb = next) != NULL) {
- if (skb->magic != ARP_QUEUE_MAGIC) {
- printk("ARP: *** Bug: skb with bad magic %X: squashing queue\n",
- skb->magic);
- return;
- }
-
- /* Extra consistency check. */
- if (skb->next == NULL
-#ifdef CONFIG_MAX_16M
- || ((unsigned long)(skb->next) > 16*1024*1024)
-#endif
- ) {
- printk("ARP: *** Bug: bad skb->next, squashing queue\n");
- return;
- }
-
- /* First remove skb from the queue. */
- next = skb->next;
- if (next != skb) {
- skb->prev->next = next;
- next->prev = skb->prev;
- } else {
- next = NULL;
- }
-
+ while((skb=skb_dequeue(&work_q))!=NULL)
+ {
+ IS_SKB(skb);
skb->magic = 0;
skb->next = NULL;
skb->prev = NULL;
@@ -224,27 +222,13 @@ arp_send_q(void)
/* Can we now complete this packet? */
sti();
- if (!skb->dev->rebuild_header(skb+1, skb->dev)) {
- /* Yes, so send it out. */
- skb->next = NULL;
- skb->prev = NULL;
+ if (skb->arp || !skb->dev->rebuild_header(skb+1, skb->dev)) {
skb->arp = 1;
skb->dev->queue_xmit(skb, skb->dev, 0);
} else {
/* Alas. Re-queue it... */
- cli();
skb->magic = ARP_QUEUE_MAGIC;
- if (arp_q == NULL) {
- skb->next = skb;
- skb->prev = skb;
- arp_q = skb;
- } else {
- skb->next = arp_q;
- skb->prev = arp_q->prev;
- arp_q->prev->next = skb;
- arp_q->prev = skb;
- }
- sti();
+ skb_queue_head(&arp_q,skb);
}
}
}
@@ -261,7 +245,7 @@ arp_response(struct arphdr *arp1, struct device *dev)
int hlen;
/* Get some mem and initialize it for the return trip. */
- skb = (struct sk_buff *) kmalloc(sizeof(struct sk_buff) +
+ skb = alloc_skb(sizeof(struct sk_buff) +
sizeof(struct arphdr) +
(2 * arp1->ar_hln) + (2 * arp1->ar_pln) +
dev->hard_header_len, GFP_ATOMIC);
@@ -275,7 +259,6 @@ arp_response(struct arphdr *arp1, struct device *dev)
src = *((unsigned long *) (ptr1 + arp1->ar_hln));
dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln));
- skb->lock = 0;
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) +
(2 * arp1->ar_pln) + dev->hard_header_len;
@@ -284,6 +267,7 @@ arp_response(struct arphdr *arp1, struct device *dev)
ETH_P_ARP, src, dst, skb->len);
if (hlen < 0) {
printk("ARP: cannot create HW frame header for REPLY !\n");
+ kfree_skb(skb, FREE_WRITE);
return(1);
}
@@ -440,17 +424,19 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
arp = skb->h.arp;
arp_print(arp);
- /* If this test doesn't pass, something fishy is going on. */
- if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd)) {
- printk("ARP: Bad packet received on device \"%s\" !\n", dev->name);
+ /* If this test doesn't pass, its not IP. Might be DECNET or friends */
+ if (arp->ar_hln != dev->addr_len || dev->type != NET16(arp->ar_hrd))
+ {
+ DPRINTF((DBG_ARP,"ARP: Bad packet received on device \"%s\" !\n", dev->name));
kfree_skb(skb, FREE_READ);
return(0);
}
/* For now we will only deal with IP addresses. */
- if (arp->ar_pro != NET16(ETH_P_IP) || arp->ar_pln != 4) {
+ if (arp->ar_pro != NET16(ETH_P_IP) || arp->ar_pln != 4)
+ {
if (arp->ar_op != NET16(ARPOP_REQUEST))
- printk("ARP: Non-IP request on device \"%s\" !\n", dev->name);
+ DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name));
kfree_skb(skb, FREE_READ);
return(0);
}
@@ -492,12 +478,23 @@ arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/*
* OK, we used that part of the info. Now check if the
- * request was an ARP REQUEST for one of our own addresses...
+ * request was an ARP REQUEST for one of our own addresses..
*/
if (arp->ar_op != NET16(ARPOP_REQUEST)) {
kfree_skb(skb, FREE_READ);
return(0);
}
+
+ /*
+ * A broadcast arp, ignore it
+ */
+
+ if((dst&0xFF)==0xFF)
+ {
+ kfree_skb(skb, FREE_READ);
+ return 0;
+ }
+
memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln);
if (chk_addr(dst) != IS_MYADDR) {
DPRINTF((DBG_ARP, "ARP: request was not for me!\n"));
@@ -528,7 +525,7 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
DPRINTF((DBG_ARP, "dev=%s, ", dev->name));
DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr)));
- skb = (struct sk_buff *) kmalloc(sizeof(struct sk_buff) +
+ skb = alloc_skb(sizeof(struct sk_buff) +
sizeof(struct arphdr) + (2 * dev->addr_len) +
dev->hard_header_len +
(2 * 4 /* arp->plen */), GFP_ATOMIC);
@@ -538,7 +535,6 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
}
/* Fill in the request. */
- skb->lock = 0;
skb->sk = NULL;
skb->mem_addr = skb;
skb->len = sizeof(struct arphdr) +
@@ -547,10 +543,11 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
skb->arp = 1;
skb->dev = dev;
skb->next = NULL;
+ skb->free = 1;
tmp = dev->hard_header((unsigned char *)(skb+1), dev,
ETH_P_ARP, 0, saddr, skb->len);
if (tmp < 0) {
- kfree_s(skb->mem_addr, skb->mem_len);
+ kfree_skb(skb,FREE_WRITE);
return;
}
arp = (struct arphdr *) ((unsigned char *) (skb+1) + tmp);
@@ -565,7 +562,8 @@ arp_send(unsigned long paddr, struct device *dev, unsigned long saddr)
ptr += arp->ar_hln;
memcpy(ptr, &saddr, arp->ar_pln);
ptr += arp->ar_pln;
- memcpy(ptr, dev->broadcast, arp->ar_hln);
+ /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/
+ memset(ptr,0,arp->ar_hln);
ptr += arp->ar_hln;
memcpy(ptr, &paddr, arp->ar_pln);
@@ -681,6 +679,7 @@ arp_queue(struct sk_buff *skb)
printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic);
return;
}
+#ifdef OLDWAY
if (arp_q == NULL) {
arp_q = skb;
skb->next = skb;
@@ -691,6 +690,9 @@ arp_queue(struct sk_buff *skb)
skb->next->prev = skb;
skb->prev->next = skb;
}
+#else
+ skb_queue_tail(&arp_q,skb);
+#endif
skb->magic = ARP_QUEUE_MAGIC;
sti();
}
@@ -835,6 +837,12 @@ arp_req_del(struct arpreq *req)
if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT);
si = (struct sockaddr_in *) &r.arp_pa;
+
+ /* The system cope with this but splats up a nasty kernel message
+ We trap it beforehand and tell the user off */
+ if(chk_addr(si->sin_addr.s_addr)==IS_MYADDR)
+ return -EINVAL;
+
arp_destroy(si->sin_addr.s_addr);
return(0);
@@ -845,16 +853,26 @@ arp_req_del(struct arpreq *req)
int
arp_ioctl(unsigned int cmd, void *arg)
{
+ int err;
switch(cmd) {
case DDIOCSDBG:
return(dbg_ioctl(arg, DBG_ARP));
case SIOCDARP:
if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
return(arp_req_del((struct arpreq *)arg));
case SIOCGARP:
+ err=verify_area(VERIFY_WRITE,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
return(arp_req_get((struct arpreq *)arg));
case SIOCSARP:
if (!suser()) return(-EPERM);
+ err=verify_area(VERIFY_READ,arg,sizeof(struct arpreq));
+ if(err)
+ return err;
return(arp_req_set((struct arpreq *)arg));
default:
return(-EINVAL);
diff --git a/net/inet/datagram.c b/net/inet/datagram.c
new file mode 100644
index 0000000..cf610ea
--- /dev/null
+++ b/net/inet/datagram.c
@@ -0,0 +1,141 @@
+/*
+ * SUCS NET2 Debugged.
+ *
+ * Generic datagram handling routines. These are generic for all protocols. Possibly a generic IP version on top
+ * of these would make sense. Not tonight however 8-).
+ * This is used because UDP, RAW, PACKET and the to be released IPX layer all have identical select code and mostly
+ * identical recvfrom() code. So we share it here. The select was shared before but buried in udp.c so I moved it.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>. (datagram_select() from old udp.c code)
+ *
+ * Fixes:
+ * Alan Cox : NULL return from skb_peek_copy() understood
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include <linux/errno.h>
+#include <linux/sched.h>
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+
+
+/*
+ * Get a datagram skbuff, understands the peeking, nonblocking wakeups and possible
+ * races. This replaces identical code in packet,raw and udp, as well as the yet to
+ * be released IPX support. It also finally fixes the long standing peek and read
+ * race for datagram sockets. If you alter this routine remember it must be
+ * re-entrant.
+ */
+
+struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags, int noblock, int *err)
+{
+ struct sk_buff *skb;
+
+ /* Socket is inuse - so the timer doesn't attack it */
+ sk->inuse = 1;
+ while(sk->rqueue == NULL) /* No data */
+ {
+ /* If we are shutdown then no more data is going to appear. We are done */
+ if (sk->shutdown & RCV_SHUTDOWN)
+ {
+ release_sock(sk);
+ *err=0;
+ return NULL;
+ }
+
+ /* User doesn't want to wait */
+ if (noblock)
+ {
+ release_sock(sk);
+ *err=-EAGAIN;
+ return NULL;
+ }
+ release_sock(sk);
+
+ /* Interrupts off so that no packet arrives before we begin sleeping.
+ Otherwise we might miss our wake up */
+ cli();
+ if (sk->rqueue == NULL)
+ {
+ interruptible_sleep_on(sk->sleep);
+ /* Signals may need a restart of the syscall */
+ if (current->signal & ~current->blocked)
+ {
+ sti();
+ *err=-ERESTARTSYS;
+ return(NULL);
+ }
+ if(sk->err != 0) /* Error while waiting for packet
+ eg an icmp sent earlier by the
+ peer has finaly turned up now */
+ {
+ *err = -sk->err;
+ sti();
+ sk->err=0;
+ return NULL;
+ }
+ }
+ sk->inuse = 1;
+ sti();
+ }
+ /* Again only user level code calls this function, so nothing interrupt level
+ will suddenely eat the rqueue */
+ if (!(flags & MSG_PEEK))
+ skb=skb_dequeue(&sk->rqueue);
+ else
+ {
+ skb=skb_peek_copy(&sk->rqueue); /* We make a copy with interrupts off. Its the only
+ way to be safe as this code is re-entrant */
+ if(skb==NULL) /* shouldn't happen but .. */
+ *err=-ENOMEM;
+ }
+ return skb;
+}
+
+
+/*
+ * Datagram select: Again totally generic. Moved from udp.c
+ */
+
+int datagram_select(struct sock *sk, int sel_type, select_table *wait)
+{
+ select_wait(sk->sleep, wait);
+ switch(sel_type)
+ {
+ case SEL_IN:
+ if (sk->rqueue != NULL || sk->err != 0)
+ { /* This appears to be consistent
+ with other stacks */
+ return(1);
+ }
+ return(0);
+
+ case SEL_OUT:
+ if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE)
+ {
+ return(1);
+ }
+ return(0);
+
+ case SEL_EX:
+ if (sk->err)
+ return(1); /* Socket has gone into error state (eg icmp error) */
+ return(0);
+ }
+ return(0);
+}
diff --git a/net/inet/dev.c b/net/inet/dev.c
index 78726ad..65f4ecd 100644
--- a/net/inet/dev.c
+++ b/net/inet/dev.c
@@ -10,6 +10,16 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox: check_addr returns a value for a wrong subnet
+ * ie not us but don't forward this!
+ * Alan Cox: block timer if the inet_bh handler is running
+ * Alan Cox: generic queue code added. A lot neater now
+ * C.E.Hawkins: SIOCGIFCONF only reports 'upped' interfaces
+ * C.E.Hawkins: IFF_PROMISC support
+ * Alan Cox: Supports Donald Beckers new hardware
+ * multicast layer, but not yet multicast lists.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -81,12 +91,16 @@ get_mask(unsigned long addr)
{
unsigned long dst;
- if (addr == 0) return(0); /* special case */
+ if (addr == 0L)
+ return(0L); /* special case */
dst = ntohl(addr);
- if (IN_CLASSA(dst)) return(htonl(IN_CLASSA_NET));
- if (IN_CLASSB(dst)) return(htonl(IN_CLASSB_NET));
- if (IN_CLASSC(dst)) return(htonl(IN_CLASSC_NET));
+ if (IN_CLASSA(dst))
+ return(htonl(IN_CLASSA_NET));
+ if (IN_CLASSB(dst))
+ return(htonl(IN_CLASSB_NET));
+ if (IN_CLASSC(dst))
+ return(htonl(IN_CLASSC_NET));
/* Something else, probably a subnet. */
return(0);
@@ -101,7 +115,8 @@ ip_addr_match(unsigned long me, unsigned long him)
DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me)));
DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him)));
- if (me == him) return(1);
+ if (me == him)
+ return(1);
for (i = 0; i < 4; i++, me >>= 8, him >>= 8) {
if ((me & 0xFF) != (him & 0xFF)) {
/*
@@ -133,7 +148,7 @@ chk_addr(unsigned long addr)
}
/* Accept all of the `loopback' class A net. */
- if ((dst & IN_CLASSA_NET) == 0x7F000000) {
+ if ((dst & IN_CLASSA_NET) == 0x7F000000L) {
DPRINTF((DBG_DEV, "LOOPBACK\n"));
/*
@@ -145,7 +160,13 @@ chk_addr(unsigned long addr)
/* OK, now check the interface addresses. */
for (dev = dev_base; dev != NULL; dev = dev->next) {
- if (dev->pa_addr == 0) continue;
+ if (dev->pa_addr == 0)
+ {
+ if(dev->flags&IFF_PROMISC) /* This allows all addresses through */
+ return(IS_MYADDR);
+ else
+ continue;
+ }
/* Is it the exact IP address? */
if (addr == dev->pa_addr) {
@@ -168,6 +189,12 @@ chk_addr(unsigned long addr)
}
DPRINTF((DBG_DEV, "NONE\n"));
+
+ if(addr & 0xFF)
+ {
+ /* Wrong subnetted IS_BROADCAST */
+ return(IS_INVBCAST);
+ }
return(0); /* no match at all */
}
@@ -226,7 +253,8 @@ dev_remove_pack(struct packet_type *pt)
for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next) {
if (pt1->next == pt ) {
cli();
- if (!pt->copy && lpt) lpt->copy = 0;
+ if (!pt->copy && lpt)
+ lpt->copy = 0;
pt1->next = pt->next;
sti();
return;
@@ -246,7 +274,8 @@ dev_get(char *name)
struct device *dev;
for (dev = dev_base; dev != NULL; dev = dev->next) {
- if (strcmp(dev->name, name) == 0) return(dev);
+ if (strcmp(dev->name, name) == 0)
+ return(dev);
}
return(NULL);
}
@@ -265,7 +294,7 @@ dev_check(unsigned long addr)
for (dev = dev_base; dev; dev = dev->next)
if ((dev->flags & IFF_UP) && !(dev->flags & IFF_POINTOPOINT) &&
(dev->flags & IFF_LOOPBACK ? (addr == dev->pa_addr) :
- (dev->pa_addr & addr) == (dev->pa_addr & dev->pa_mask)))
+ (dev->pa_mask & addr) == (dev->pa_addr & dev->pa_mask)))
break;
/* no need to check broadcast addresses */
return dev;
@@ -278,8 +307,10 @@ dev_open(struct device *dev)
{
int ret = 0;
- if (dev->open) ret = dev->open(dev);
- if (ret == 0) dev->flags |= (IFF_UP | IFF_RUNNING);
+ if (dev->open)
+ ret = dev->open(dev);
+ if (ret == 0)
+ dev->flags |= (IFF_UP | IFF_RUNNING);
return(ret);
}
@@ -290,13 +321,24 @@ int
dev_close(struct device *dev)
{
if (dev->flags != 0) {
+ int ct=0;
dev->flags = 0;
- if (dev->stop) dev->stop(dev);
+ if (dev->stop)
+ dev->stop(dev);
rt_flush(dev);
dev->pa_addr = 0;
dev->pa_dstaddr = 0;
dev->pa_brdaddr = 0;
dev->pa_mask = 0;
+ /* Purge any queued packets when we down the link */
+ while(ct<DEV_NUMBUFFS)
+ {
+ struct sk_buff *skb;
+ while((skb=skb_dequeue(&dev->buffs[ct]))!=NULL)
+ if(skb->free)
+ kfree_skb(skb,FREE_WRITE);
+ ct++;
+ }
}
return(0);
@@ -307,7 +349,6 @@ dev_close(struct device *dev)
void
dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
{
- struct sk_buff *skb2;
int where = 0; /* used to say if the packet should go */
/* at the front or the back of the */
/* queue. */
@@ -319,7 +360,9 @@ dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
printk("dev.c: dev_queue_xmit: dev = NULL\n");
return;
}
-
+
+ IS_SKB(skb);
+
skb->dev = dev;
if (skb->next != NULL) {
/* Make sure we haven't missed an interrupt. */
@@ -347,25 +390,11 @@ dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri)
/* Interrupts should already be cleared by hard_start_xmit. */
cli();
- if (dev->buffs[pri] == NULL) {
- dev->buffs[pri] = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- if (where) {
- skb->next = (struct sk_buff *) dev->buffs[pri];
- skb->prev = (struct sk_buff *) dev->buffs[pri]->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- dev->buffs[pri] = skb;
- } else {
- skb2 = (struct sk_buff *) dev->buffs[pri];
- skb->next = skb2;
- skb->prev = skb2->prev;
- skb->next->prev = skb;
- skb->prev->next = skb;
- }
- }
+ skb->magic = DEV_QUEUE_MAGIC;
+ if(where)
+ skb_queue_head(&dev->buffs[pri],skb);
+ else
+ skb_queue_tail(&dev->buffs[pri],skb);
skb->magic = DEV_QUEUE_MAGIC;
sti();
}
@@ -378,22 +407,12 @@ void
netif_rx(struct sk_buff *skb)
{
/* Set any necessary flags. */
- skb->lock = 0;
skb->sk = NULL;
-
+ skb->free = 1;
+
/* and add it to the "backlog" queue. */
- cli();
- if (backlog == NULL) {
- skb->prev = skb;
- skb->next = skb;
- backlog = skb;
- } else {
- skb->prev = (struct sk_buff *) backlog->prev;
- skb->next = (struct sk_buff *) backlog;
- skb->next->prev = skb;
- skb->prev->next = skb;
- }
- sti();
+ IS_SKB(skb);
+ skb_queue_tail(&backlog,skb);
/* If any packet arrived, mark it for processing. */
if (backlog != NULL) mark_bh(INET_BH);
@@ -432,14 +451,13 @@ dev_rint(unsigned char *buff, long len, int flags, struct device *dev)
dropping = 0;
}
- skb = (struct sk_buff *) kmalloc(sizeof(*skb) + len, GFP_ATOMIC);
+ skb = alloc_skb(sizeof(*skb) + len, GFP_ATOMIC);
if (skb == NULL) {
printk("dev_rint: packet dropped on %s (no memory) !\n",
dev->name);
dropping = 1;
return(1);
}
- skb->lock = 0;
skb->mem_len = sizeof(*skb) + len;
skb->mem_addr = (struct sk_buff *) skb;
@@ -461,6 +479,7 @@ dev_rint(unsigned char *buff, long len, int flags, struct device *dev)
}
skb->len = len;
skb->dev = dev;
+ skb->free = 1;
netif_rx(skb);
/* OK, all done. */
@@ -481,10 +500,17 @@ dev_transmit(void)
}
}
+static volatile char in_bh = 0;
+
+int in_inet_bh() /* Used by timer.c */
+{
+ return(in_bh==0?0:1);
+}
/*
* This function gets called periodically, to see if we can
* process any data that came in from some interface.
+ *
*/
void
inet_bh(void *tmp)
@@ -493,7 +519,7 @@ inet_bh(void *tmp)
struct packet_type *ptype;
unsigned short type;
unsigned char flag = 0;
- static volatile char in_bh = 0;
+
/* Atomically check and mark our BUSY state. */
if (set_bit(1, (void*)&in_bh))
@@ -503,18 +529,8 @@ inet_bh(void *tmp)
dev_transmit();
/* Any data left to process? */
- cli();
- while (backlog != NULL) {
- skb = (struct sk_buff *) backlog;
- if (skb->next == skb) {
- backlog = NULL;
- } else {
- backlog = skb->next;
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
- }
- sti();
-
+ while((skb=skb_dequeue(&backlog))!=NULL)
+ {
/*
* Bump the pointer to the next structure.
* This assumes that the basic 'skb' pointer points to
@@ -532,6 +548,7 @@ inet_bh(void *tmp)
* header (the h_proto field in struct ethhdr), but drivers like
* SLIP and PLIP have no alternative but to force the type to be
* IP or something like that. Sigh- FvK
+ * FIXME: Ethernet drivers need potty training in 802.3 packets -AC
*/
type = skb->dev->type_trans(skb, skb->dev);
@@ -546,16 +563,17 @@ inet_bh(void *tmp)
struct sk_buff *skb2;
if (ptype->copy) { /* copy if we need to */
- skb2 = (struct sk_buff *) kmalloc(skb->mem_len, GFP_ATOMIC);
- if (skb2 == NULL) continue;
+ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
+ if (skb2 == NULL)
+ continue;
memcpy(skb2, (const void *) skb, skb->mem_len);
skb2->mem_addr = skb2;
- skb2->lock = 0;
skb2->h.raw = (unsigned char *)(
(unsigned long) skb2 +
(unsigned long) skb->h.raw -
(unsigned long) skb
);
+ skb2->free = 1;
} else {
skb2 = skb;
}
@@ -595,55 +613,23 @@ inet_bh(void *tmp)
* This routine is called when an device driver (i.e. an
* interface) is * ready to transmit a packet.
*/
-void
-dev_tint(struct device *dev)
+
+void dev_tint(struct device *dev)
{
- int i;
- struct sk_buff *skb;
-
- for (i = 0; i < DEV_NUMBUFFS; i++) {
- cli();
- while (dev->buffs[i] != NULL) {
- skb = (struct sk_buff *) dev->buffs[i];
- if (skb->magic != DEV_QUEUE_MAGIC) {
- printk("INET: dev: skb with bad magic-%X:", skb->magic);
- printk("squashing queue\n");
- dev->buffs[i] = NULL;
- continue;
- }
-
- skb->magic = 0;
-
- if (skb->next == skb) {
- dev->buffs[i] = NULL;
- } else {
- /* Extra consistency check. */
- if (skb->next == NULL
-#ifdef CONFIG_MAX_16M
- || (unsigned long)(skb->next) > 16*1024*1024
-#endif
- ) {
- printk("INET: dev: *** bug bad skb->next,");
- printk(", squashing queue\n");
- dev->buffs[i] = NULL;
- } else {
- dev->buffs[i]= skb->next;
- skb->prev->next = skb->next;
- skb->next->prev = skb->prev;
- }
+ int i;
+ struct sk_buff *skb;
+
+ for(i = 0;i < DEV_NUMBUFFS; i++) {
+ while((skb=skb_dequeue(&dev->buffs[i]))!=NULL)
+ {
+ skb->magic = 0;
+ skb->next = NULL;
+ skb->prev = NULL;
+ dev->queue_xmit(skb,dev,-i - 1);
+ if (dev->tbusy)
+ return;
}
-
- skb->next = NULL;
- skb->prev = NULL;
- sti();
-
- /* This will send it through the process again. */
- dev->queue_xmit(skb, dev, -i - 1);
- if (dev->tbusy) return;
- cli();
}
- }
- sti();
}
@@ -665,6 +651,8 @@ dev_ifconf(char *arg)
/* Loop over the interfaces, and write an info block for each. */
for (dev = dev_base; dev != NULL; dev = dev->next) {
+ if(!(dev->flags & IFF_UP))
+ continue;
memset(&ifr, 0, sizeof(struct ifreq));
strcpy(ifr.ifr_name, dev->name);
(*(struct sockaddr_in *) &ifr.ifr_addr).sin_family = dev->family;
@@ -753,6 +741,11 @@ dev_ifsioc(void *arg, unsigned int getset)
IFF_UP | IFF_BROADCAST | IFF_DEBUG | IFF_LOOPBACK |
IFF_POINTOPOINT | IFF_NOTRAILERS | IFF_RUNNING |
IFF_NOARP | IFF_PROMISC | IFF_ALLMULTI);
+
+ if ( (old_flags & IFF_PROMISC) && ((dev->flags & IFF_PROMISC) == 0))
+ dev->set_multicast_list(dev,0,NULL);
+ if ( (dev->flags & IFF_PROMISC) && ((old_flags & IFF_PROMISC) == 0))
+ dev->set_multicast_list(dev,-1,NULL);
if ((old_flags & IFF_UP) && ((dev->flags & IFF_UP) == 0)) {
ret = dev_close(dev);
} else
@@ -849,6 +842,11 @@ dev_ifsioc(void *arg, unsigned int getset)
printk("NET: ioctl(SIOCSIFMEM, 0x%08X)\n", (int)arg);
ret = -EINVAL;
break;
+ case SIOCGIFHWADDR:
+ memcpy(ifr.ifr_hwaddr,dev->dev_addr, MAX_ADDR_LEN);
+ memcpy_tofs(arg,&ifr,sizeof(struct ifreq));
+ ret=0;
+ break;
default:
ret = -EINVAL;
}
@@ -934,6 +932,7 @@ dev_ioctl(unsigned int cmd, void *arg)
case SIOCSIFMTU:
case SIOCGIFMEM:
case SIOCSIFMEM:
+ case SIOCGIFHWADDR:
if (!suser()) return(-EPERM);
ret = dev_ifsioc(arg, cmd);
break;
diff --git a/net/inet/dev.h b/net/inet/dev.h
index 5a69b25..b3756b7 100644
--- a/net/inet/dev.h
+++ b/net/inet/dev.h
@@ -32,7 +32,7 @@
#define IS_MYADDR 1 /* address is (one of) our own */
#define IS_LOOPBACK 2 /* address is for LOOPBACK */
#define IS_BROADCAST 3 /* address is a valid broadcast */
-
+#define IS_INVBCAST 4 /* Wrong netmask bcast not for us */
/*
* The DEVICE structure.
@@ -132,6 +132,9 @@ struct device {
int (*rebuild_header)(void *eth, struct device *dev);
unsigned short (*type_trans) (struct sk_buff *skb,
struct device *dev);
+#define HAVE_MULTICAST
+ void (*set_multicast_list)(struct device *dev,
+ int num_addrs, void *addrs);
};
@@ -175,6 +178,7 @@ extern void netif_rx(struct sk_buff *skb);
extern int dev_rint(unsigned char *buff, long len, int flags,
struct device * dev);
extern void dev_transmit(void);
+extern int in_inet_bh(void);
extern void inet_bh(void *tmp);
extern void dev_tint(struct device *dev);
extern int dev_get_info(char *buffer);
diff --git a/net/inet/eth.c b/net/inet/eth.c
index 8ad98d5..01e2f51 100644
--- a/net/inet/eth.c
+++ b/net/inet/eth.c
@@ -10,6 +10,13 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
+ *
+ * Fixes:
+ * Mr Linux : Arp problems
+ * Alan Cox : Generic queue tidyup (very tiny here)
+ * Alan Cox : eth_header ntohs should be htons
+ * Alan Cox : eth_rebuild_header missing an htons and
+ * minor other things.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -97,12 +104,12 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
/* Fill in the basic Ethernet MAC header. */
eth = (struct ethhdr *) buff;
- eth->h_proto = ntohs(type);
- memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
+ eth->h_proto = htons(type);
/* We don't ARP for the LOOPBACK device... */
if (dev->flags & IFF_LOOPBACK) {
DPRINTF((DBG_DEV, "ETH: No header for loopback\n"));
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
memset(eth->h_dest, 0, dev->addr_len);
return(dev->hard_header_len);
}
@@ -110,14 +117,27 @@ eth_header(unsigned char *buff, struct device *dev, unsigned short type,
/* Check if we can use the MAC BROADCAST address. */
if (chk_addr(daddr) == IS_BROADCAST) {
DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n"));
+ memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
memcpy(eth->h_dest, dev->broadcast, dev->addr_len);
return(dev->hard_header_len);
}
-
+ cli();
+ memcpy(eth->h_source, &saddr, 4);
/* No. Ask ARP to resolve the Ethernet address. */
- if (arp_find(eth->h_dest, daddr, dev, saddr)) {
+ if (arp_find(eth->h_dest, daddr, dev, saddr))
+ {
+ sti();
+ if(type!=ETH_P_IP)
+ printk("Erk: protocol %X got into an arp request state!\n",type);
return(-dev->hard_header_len);
- } else return(dev->hard_header_len);
+ }
+ else
+ {
+ memcpy(eth->h_source,dev->dev_addr,dev->addr_len); /* This was missing causing chaos if the
+ header built correctly! */
+ sti();
+ return(dev->hard_header_len);
+ }
}
@@ -134,16 +154,8 @@ eth_rebuild_header(void *buff, struct device *dev)
dst = *(unsigned long *) eth->h_dest;
DPRINTF((DBG_DEV, "ETH: RebuildHeader: SRC=%s ", in_ntoa(src)));
DPRINTF((DBG_DEV, "DST=%s\n", in_ntoa(dst)));
-/* Kludge to check IP address before sending an ARP request
- to fix invalid IP addresses on ARP calls. jacob@mayhem 9/5/93 */
- if (src != dev->pa_addr) {
- /*
- printk("Got bad arp_find request in eth_rebuild_header: %s\n", in_ntoa(src));
- printk("Replacing with correct source IP address: %s\n", in_ntoa(dev->pa_addr));
- */
- src = dev->pa_addr;
- }
- if (arp_find(eth->h_dest, dst, dev, src)) return(1);
+ if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */
+ if (arp_find(eth->h_dest, dst, dev, src)) return(1);
memcpy(eth->h_source, dev->dev_addr, dev->addr_len);
return(0);
}
@@ -167,5 +179,8 @@ eth_type_trans(struct sk_buff *skb, struct device *dev)
struct ethhdr *eth;
eth = (struct ethhdr *) (skb + 1);
+
+ if(ntohs(eth->h_proto)<1536)
+ return(htons(ETH_P_802_3));
return(eth->h_proto);
}
diff --git a/net/inet/icmp.c b/net/inet/icmp.c
index bd7bed5..5b8728b 100644
--- a/net/inet/icmp.c
+++ b/net/inet/icmp.c
@@ -11,6 +11,10 @@
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Mark Evans, <evansmp@uhura.aston.ac.uk>
*
+ * Fixes:
+ * Alan Cox : Generic queue usage.
+ *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -42,19 +46,19 @@
/* An array of errno for error messages from dest unreach. */
struct icmp_err icmp_err_convert[] = {
- { ENETUNREACH, 1 },
- { EHOSTUNREACH, 1 },
- { ENOPROTOOPT, 1 },
- { ECONNREFUSED, 1 },
- { EOPNOTSUPP, 0 },
- { EOPNOTSUPP, 0 },
- { ENETUNREACH, 1 },
- { EHOSTDOWN, 1 },
- { ENONET, 1 },
- { ENETUNREACH, 1 },
- { EHOSTUNREACH, 1 },
- { EOPNOTSUPP, 0 },
- { EOPNOTSUPP, 0 }
+ { ENETUNREACH, 1 }, /* ICMP_NET_UNREACH */
+ { EHOSTUNREACH, 1 }, /* ICMP_HOST_UNREACH */
+ { ENOPROTOOPT, 1 }, /* ICMP_PROT_UNREACH */
+ { ECONNREFUSED, 1 }, /* ICMP_PORT_UNREACH */
+ { EOPNOTSUPP, 0 }, /* ICMP_FRAG_NEEDED */
+ { EOPNOTSUPP, 0 }, /* ICMP_SR_FAILED */
+ { ENETUNREACH, 1 }, /* ICMP_NET_UNKNOWN */
+ { EHOSTDOWN, 1 }, /* ICMP_HOST_UNKNOWN */
+ { ENONET, 1 }, /* ICMP_HOST_ISOLATED */
+ { ENETUNREACH, 1 }, /* ICMP_NET_ANO */
+ { EHOSTUNREACH, 1 }, /* ICMP_HOST_ANO */
+ { EOPNOTSUPP, 0 }, /* ICMP_NET_UNR_TOS */
+ { EOPNOTSUPP, 0 } /* ICMP_HOST_UNR_TOS */
};
@@ -88,10 +92,10 @@ icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev)
sizeof(struct iphdr) + sizeof(struct icmphdr) +
sizeof(struct iphdr) + 8; /* amount of header to return */
- skb = (struct sk_buff *) kmalloc(len, GFP_ATOMIC);
- if (skb == NULL) return;
+ skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC);
+ if (skb == NULL)
+ return;
- skb->lock = 0;
skb->sk = NULL;
skb->mem_addr = skb;
skb->mem_len = len;
@@ -237,23 +241,23 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
int size, offset;
size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = (struct sk_buff *) kmalloc(size, GFP_ATOMIC);
+ skb2 = alloc_skb(size, GFP_ATOMIC);
if (skb2 == NULL) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
}
skb2->sk = NULL;
- skb2->lock = 0;
skb2->mem_addr = skb2;
skb2->mem_len = size;
+ skb2->free = 1;
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ECHO Response\n");
- kfree_s(skb2->mem_addr, skb2->mem_len);
+ kfree_skb(skb2,FREE_WRITE);
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
@@ -268,10 +272,7 @@ icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
icmphr->type = ICMP_ECHOREPLY;
icmphr->code = 0;
icmphr->checksum = 0;
-
- if (icmph->checksum) { /* Calculate Checksum */
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
- }
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
/* Ship it out - free it when done */
ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
@@ -304,23 +305,23 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
int size, offset;
size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len;
- skb2 = (struct sk_buff *) kmalloc(size, GFP_ATOMIC);
+ skb2 = alloc_skb(size, GFP_ATOMIC);
if (skb2 == NULL) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
}
skb2->sk = NULL;
- skb2->lock = 0;
skb2->mem_addr = skb2;
skb2->mem_len = size;
+ skb2->free = 1;
/* Build Layer 2-3 headers for message back to source */
offset = ip_build_header(skb2, daddr, saddr, &dev,
IPPROTO_ICMP, opt, len);
if (offset < 0) {
printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n");
- kfree_s(skb2->mem_addr, skb2->mem_len);
+ kfree_skb(skb2,FREE_WRITE);
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return;
@@ -338,9 +339,7 @@ icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev,
icmphr->un.echo.sequence = icmph->un.echo.sequence;
memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask));
- if (icmph->checksum) { /* Calculate Checksum */
- icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
- }
+ icmphr->checksum = ip_compute_csum((unsigned char *)icmphr, len);
/* Ship it out - free it when done */
ip_queue_xmit((struct sock *)NULL, dev, skb2, 1);
@@ -372,14 +371,12 @@ icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt,
icmph = (struct icmphdr *) buff;
/* Validate the packet first */
- if (icmph->checksum) { /* Checksums Enabled? */
- if (ip_compute_csum((unsigned char *) icmph, len)) {
- /* Failed checksum! */
- printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
- skb1->sk = NULL;
- kfree_skb(skb1, FREE_READ);
- return(0);
- }
+ if (ip_compute_csum((unsigned char *) icmph, len)) {
+ /* Failed checksum! */
+ printk("ICMP: failed checksum from %s!\n", in_ntoa(saddr));
+ skb1->sk = NULL;
+ kfree_skb(skb1, FREE_READ);
+ return(0);
}
print_icmp(icmph);
diff --git a/net/inet/inet.h b/net/inet/inet.h
index 1b41209..d617de3 100644
--- a/net/inet/inet.h
+++ b/net/inet/inet.h
@@ -58,7 +58,7 @@
#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00))
-#undef INET_DEBUG
+#define INET_DEBUG
#ifdef INET_DEBUG
# define DPRINTF(x) dprintf x
#else
diff --git a/net/inet/ip.c b/net/inet/ip.c
index 90eb68f..4dff2e2 100644
--- a/net/inet/ip.c
+++ b/net/inet/ip.c
@@ -11,6 +11,25 @@
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Donald Becker, <becker@super.org>
*
+ * Fixes:
+ * Alan Cox : Commented a couple of minor bits of surplus code
+ * Alan Cox : Undefining IP_FORWARD doesn't include the code
+ * (just stops a compiler warning).
+ * Alan Cox : Frames with >=MAX_ROUTE record routes, strict routes or loose routes
+ * are junked rather than corrupting things.
+ * Alan Cox : Frames to bad broadcast subnets are dumped
+ * We used to process them non broadcast and
+ * boy could that cause havoc.
+ * Alan Cox : ip_forward sets the free flag on the
+ * new frame it queues. Still crap because
+ * it copies the frame but at least it
+ * doesn't eat memory too.
+ * Alan Cox : Generic queue code and memory fixes.
+ *
+ * To Fix:
+ * IP option processing is mostly not needed. ip_forward needs to know about routing rules
+ * and time stamp but that's about all.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -38,7 +57,7 @@
#include "arp.h"
#include "icmp.h"
-#define CONFIG_IP_FORWARD
+#undef CONFIG_IP_FORWARD
extern int last_retran;
extern void sort_send(struct sock *sk);
@@ -182,19 +201,24 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
static int count = 0;
int tmp;
- if (saddr == 0) saddr = my_addr();
+ if (saddr == 0)
+ saddr = my_addr();
+
DPRINTF((DBG_IP, "ip_build_header (skb=%X, saddr=%X, daddr=%X, *dev=%X,\n"
" type=%d, opt=%X, len = %d)\n",
skb, saddr, daddr, *dev, type, opt, len));
+
buff = (unsigned char *)(skb + 1);
/* See if we need to look up the device. */
if (*dev == NULL) {
rt = rt_route(daddr, &optmem);
- if (rt == NULL) return(-ENETUNREACH);
+ if (rt == NULL)
+ return(-ENETUNREACH);
*dev = rt->rt_dev;
- if (daddr != 0x0100007F) saddr = rt->rt_dev->pa_addr;
+ if (daddr != 0x0100007FL)
+ saddr = rt->rt_dev->pa_addr;
raddr = rt->rt_gateway;
DPRINTF((DBG_IP, "ip_build_header: saddr set to %s\n", in_ntoa(saddr)));
@@ -204,7 +228,8 @@ ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr,
rt = rt_route(daddr, &optmem);
raddr = (rt == NULL) ? 0 : rt->rt_gateway;
}
- if (raddr == 0) raddr = daddr;
+ if (raddr == 0)
+ raddr = daddr;
/* Now build the MAC header. */
tmp = ip_send(skb, raddr, len, *dev, saddr);
@@ -298,6 +323,8 @@ do_options(struct iphdr *iph, struct options *opt)
buff++;
buff++;
for (i = 0; i < opt->loose_route.route_size; i++) {
+ if(i>=MAX_ROUTE)
+ return(1);
opt->loose_route.route[i] = *(unsigned long *)buff;
buff += 4;
}
@@ -313,6 +340,8 @@ do_options(struct iphdr *iph, struct options *opt)
buff++;
buff++;
for (i = 0; i < opt->strict_route.route_size; i++) {
+ if(i>=MAX_ROUTE)
+ return(1);
opt->strict_route.route[i] = *(unsigned long *)buff;
buff += 4;
}
@@ -328,6 +357,8 @@ do_options(struct iphdr *iph, struct options *opt)
buff++;
buff++;
for (i = 0; i < opt->record_route.route_size; i++) {
+ if(i>=MAX_ROUTE)
+ return 1;
opt->record_route.route[i] = *(unsigned long *)buff;
buff += 4;
}
@@ -455,9 +486,7 @@ ip_compute_csum(unsigned char * buff, int len)
int
ip_csum(struct iphdr *iph)
{
- if (iph->check == 0 || ip_fast_csum((unsigned char *)iph, iph->ihl) == 0)
- return(0);
- return(1);
+ return (ip_fast_csum((unsigned char *)iph, iph->ihl) != 0);
}
/* Generate a checksym for an outgoing IP datagram. */
@@ -468,6 +497,7 @@ ip_send_check(struct iphdr *iph)
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
}
+#ifdef CONFIG_IP_FORWARD
/* Forward an IP datagram to its next destination. */
static void
@@ -543,15 +573,15 @@ ip_forward(struct sk_buff *skb, struct device *dev)
in_ntoa(raddr), dev2->name, skb->len));
if (dev2->flags & IFF_UP) {
- skb2 = (struct sk_buff *) kmalloc(sizeof(struct sk_buff) +
+ skb2 = (struct sk_buff *) alloc_skb(sizeof(struct sk_buff) +
dev2->hard_header_len + skb->len, GFP_ATOMIC);
if (skb2 == NULL) {
printk("\nIP: No memory available for IP forward\n");
return;
}
ptr = (unsigned char *)(skb2 + 1);
- skb2->lock = 0;
skb2->sk = NULL;
+ skb2->free = 1;
skb2->len = skb->len + dev2->hard_header_len;
skb2->mem_addr = skb2;
skb2->mem_len = sizeof(struct sk_buff) + skb2->len;
@@ -570,6 +600,8 @@ ip_forward(struct sk_buff *skb, struct device *dev)
}
+#endif
+
/* This function receives all incoming IP datagrams. */
int
ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
@@ -586,8 +618,7 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
DPRINTF((DBG_IP, "<<\n"));
/* Is the datagram acceptable? */
- if (iph->version != 4
- || (iph->check != 0 && ip_fast_csum((unsigned char *)iph, iph->ihl) !=0)) {
+ if (iph->version != 4 || ip_fast_csum((unsigned char *)iph, iph->ihl) !=0) {
DPRINTF((DBG_IP, "\nIP: *** datagram error ***\n"));
DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr)));
DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr)));
@@ -609,13 +640,25 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
#ifdef CONFIG_IP_FORWARD
ip_forward(skb, dev);
#endif
+ printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n",
+ iph->saddr,iph->daddr);
skb->sk = NULL;
kfree_skb(skb, FREE_WRITE);
return(0);
}
+ if(brd==IS_INVBCAST)
+ {
+/* printk("Invalid broadcast address from %x [target %x] (Probably they have a wrong netmask)\n",
+ iph->saddr,iph->daddr);*/
+ skb->sk=NULL;
+ kfree_skb(skb,FREE_WRITE);
+ return(0);
+ }
+
/*
- * Reassemble IP fragments. */
+ * Reassemble IP fragments.
+ */
if ((iph->frag_off & 0x0020) || (ntohs(iph->frag_off) & 0x1fff)) {
#ifdef CONFIG_IP_DEFRAG
@@ -646,19 +689,20 @@ ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
/*
* See if we need to make a copy of it. This will
- * only be set if more than one protpocol wants it.
+ * only be set if more than one protocol wants it.
* and then not for the last one.
*/
if (ipprot->copy) {
- skb2 = (struct sk_buff *) kmalloc (skb->mem_len, GFP_ATOMIC);
- if (skb2 == NULL) continue;
+ skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC);
+ if (skb2 == NULL)
+ continue;
memcpy(skb2, skb, skb->mem_len);
skb2->mem_addr = skb2;
- skb2->lock = 0;
skb2->h.raw = (unsigned char *)(
(unsigned long)skb2 +
(unsigned long) skb->h.raw -
(unsigned long)skb);
+ skb2->free=1;
} else {
skb2 = skb;
}
@@ -711,10 +755,11 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
printk("IP: ip_queue_xmit dev = NULL\n");
return;
}
+ IS_SKB(skb);
skb->free = free;
skb->dev = dev;
skb->when = jiffies;
-
+
DPRINTF((DBG_IP, ">>\n"));
ptr = (unsigned char *)(skb + 1);
ptr += dev->hard_header_len;
@@ -754,7 +799,8 @@ ip_queue_xmit(struct sock *sk, struct device *dev,
if (dev->flags & IFF_UP) {
if (sk != NULL) {
dev->queue_xmit(skb, dev, sk->priority);
- } else {
+ }
+ else {
dev->queue_xmit(skb, dev, SOPRI_NORMAL);
}
} else {
@@ -777,29 +823,36 @@ ip_retransmit(struct sock *sk, int all)
/* I know this can't happen but as it does.. */
if(dev==NULL)
{
- printk("ip_forward: NULL device bug!\n");
+ printk("ip_retransmit: NULL device bug!\n");
goto oops;
}
+ IS_SKB(skb);
+
/*
* The rebuild_header function sees if the ARP is done.
* If not it sends a new ARP request, and if so it builds
* the header.
*/
+ cli(); /* We might get interrupted by an arp reply here and fill
+ the frame in twice. Because of the technique used this
+ would be a little sad */
if (!skb->arp) {
if (dev->rebuild_header((struct enet_header *)(skb+1),dev)) {
+ sti(); /* Failed to rebuild - next */
if (!all) break;
skb = (struct sk_buff *)skb->link3;
continue;
}
}
skb->arp = 1;
+ sti();
skb->when = jiffies;
/* If the interface is (still) up and running, kick it. */
if (dev->flags & IFF_UP) {
if (sk) dev->queue_xmit(skb, dev, sk->priority);
- else dev->queue_xmit(skb, dev, SOPRI_NORMAL );
+ /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */
}
oops: sk->retransmits++;
@@ -812,7 +865,7 @@ oops: sk->retransmits++;
}
/*
- * Double the RTT time every time we retransmit.
+ * Increase the RTT time every time we retransmit.
* This will cause exponential back off on how hard we try to
* get through again. Once we get through, the rtt will settle
* back down reasonably quickly.
@@ -829,8 +882,22 @@ int backoff(int n)
* 1, 2, 4, 8, 16, 25, 36, 49, 64, 81, 100 ...
*/
+ if(n<0)
+ {
+ printk("Backoff < 0!\n");
+ return 16; /* Make up a value */
+ }
+
if(n <= 4)
return 1 << n; /* Binary exponential back off */
else
- return n * n; /* Quadratic back off */
+ {
+ if(n<255)
+ return n * n; /* Quadratic back off */
+ else
+ {
+ printk("Overloaded backoff!\n");
+ return 255*255;
+ }
+ }
}
diff --git a/net/inet/packet.c b/net/inet/packet.c
index 3aeb5fb..a9fcdf2 100644
--- a/net/inet/packet.c
+++ b/net/inet/packet.c
@@ -10,6 +10,15 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : verify_area() now used correctly
+ * Alan Cox : new skbuff lists, look ma no backlogs!
+ * Alan Cox : tidied skbuff lists.
+ * Alan Cox : Now uses generic datagram routines I
+ * added. Also fixed the peek/read crash
+ * from all old Linux datagram code.
+ *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -53,42 +62,16 @@ packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt)
skb->dev = dev;
skb->len += dev->hard_header_len;
- /* Now see if we are in use. */
- cli();
- if (sk->inuse) {
- sti();
- /*
- * Drop any packets if we can't currently deal with
- * them. Assume that the other end will retransmit
- * if it was important.
- */
- skb->sk = NULL;
- kfree_skb(skb, FREE_READ);
- return(0);
- }
- sk->inuse = 1;
- sti();
skb->sk = sk;
/* Charge it too the socket. */
- if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX) {
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return(0);
}
sk->rmem_alloc += skb->mem_len;
-
- /* Now just put it onto the queue. */
- if (sk->rqueue == NULL) {
- sk->rqueue = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- skb->next = sk->rqueue;
- skb->prev = sk->rqueue->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- }
+ skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
release_sock(sk);
return(0);
@@ -104,6 +87,7 @@ packet_sendto(struct sock *sk, unsigned char *from, int len,
struct sk_buff *skb;
struct device *dev;
struct sockaddr saddr;
+ int err;
/* Check the flags. */
if (flags) return(-EINVAL);
@@ -112,30 +96,39 @@ packet_sendto(struct sock *sk, unsigned char *from, int len,
/* Get and verify the address. */
if (usin) {
if (addr_len < sizeof(saddr)) return(-EINVAL);
- /* verify_area(VERIFY_WRITE, usin, sizeof(saddr));*/
+ err=verify_area(VERIFY_READ, usin, sizeof(saddr));
+ if(err)
+ return err;
memcpy_fromfs(&saddr, usin, sizeof(saddr));
} else
return(-EINVAL);
+
+ err=verify_area(VERIFY_READ,from,len);
+ if(err)
+ return(err);
+/* Find the device first to size check it */
+
+ saddr.sa_data[13] = 0;
+ dev = dev_get(saddr.sa_data);
+ if (dev == NULL) {
+ return(-ENXIO);
+ }
+ if(len>dev->mtu)
+ return -EMSGSIZE;
+/* Now allocate the buffer, knowing 4K pagelimits wont break this line */
skb = (struct sk_buff *) sk->prot->wmalloc(sk, len+sizeof(*skb), 0, GFP_KERNEL);
/* This shouldn't happen, but it could. */
if (skb == NULL) {
DPRINTF((DBG_PKT, "packet_sendto: write buffer full?\n"));
- return(-EAGAIN);
+ return(-ENOMEM);
}
- skb->lock = 0;
+ /* Fill it in */
skb->mem_addr = skb;
skb->mem_len = len + sizeof(*skb);
skb->sk = sk;
skb->free = 1;
- saddr.sa_data[13] = 0;
- dev = dev_get(saddr.sa_data);
- if (dev == NULL) {
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(-ENXIO);
- }
- /* verify_area(VERIFY_WRITE, from, len);*/
memcpy_fromfs (skb+1, from, len);
skb->len = len;
skb->next = NULL;
@@ -197,6 +190,7 @@ packet_recvfrom(struct sock *sk, unsigned char *to, int len,
int copied=0;
struct sk_buff *skb;
struct sockaddr *saddr;
+ int err;
saddr = (struct sockaddr *)sin;
if (len == 0) return(0);
@@ -204,39 +198,20 @@ packet_recvfrom(struct sock *sk, unsigned char *to, int len,
if (sk->shutdown & RCV_SHUTDOWN) return(0);
if (addr_len) {
- verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(err)
+ return err;
put_fs_long(sizeof(*saddr), addr_len);
}
- sk->inuse = 1;
- while (sk->rqueue == NULL) {
- if (noblock) {
- release_sock(sk);
- return(-EAGAIN);
- }
- release_sock(sk);
- cli();
- if (sk->rqueue == NULL) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- }
- skb = sk->rqueue;
-
- if (!(flags & MSG_PEEK)) {
- if (skb->next == skb) {
- sk->rqueue = NULL;
- } else {
- sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
- skb->prev->next = skb->next;
- skb->next->prev = skb->prev;
- }
- }
+
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
copied = min(len, skb->len);
- verify_area(VERIFY_WRITE, to, copied);
+
memcpy_tofs(to, skb+1, copied);
/* Copy the address. */
@@ -249,9 +224,7 @@ packet_recvfrom(struct sock *sk, unsigned char *to, int len,
memcpy_tofs(saddr, &addr, sizeof(*saddr));
}
- if (!(flags & MSG_PEEK)) {
- kfree_skb(skb, FREE_READ);
- }
+ kfree_skb(skb, FREE_READ); /* Its either been used up, or its a peek_copy anyway */
release_sock(sk);
return(copied);
@@ -286,7 +259,7 @@ struct proto packet_prot = {
NULL,
NULL,
NULL,
- udp_select,
+ datagram_select,
NULL,
packet_init,
NULL,
diff --git a/net/inet/proc.c b/net/inet/proc.c
index 9137548..db4f840 100644
--- a/net/inet/proc.c
+++ b/net/inet/proc.c
@@ -13,6 +13,15 @@
* Gerald J. Heim, <heim@peanuts.informatik.uni-tuebingen.de>
* Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
*
+ * Fixes:
+ * Alan Cox : UDP sockets show the rxqueue/txqueue
+ * using hint flag for the netinfo.
+ * Pauline Middelink : Pidentd support
+ *
+ * To Do:
+ * Put the creating userid in the proc/net/... files. This will
+ * allow us to write an RFC931 daemon for Linux
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -44,7 +53,7 @@
* happens, get__netinfo returns only part of the available infos.
*/
static int
-get__netinfo(struct proto *pro, char *buffer)
+get__netinfo(struct proto *pro, char *buffer, int format)
{
struct sock **s_array;
struct sock *sp;
@@ -55,7 +64,7 @@ get__netinfo(struct proto *pro, char *buffer)
unsigned short destp, srcp;
s_array = pro->sock_array;
- pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when\n");
+ pos+=sprintf(pos, "sl local_address rem_address st tx_queue rx_queue tr tm->when uid\n");
for(i = 0; i < SOCK_ARRAY_SIZE; i++) {
sp = s_array[i];
while(sp != NULL) {
@@ -71,10 +80,12 @@ get__netinfo(struct proto *pro, char *buffer)
timer_active = del_timer(&sp->timer);
if (!timer_active)
sp->timer.expires = 0;
- pos+=sprintf(pos, "%2d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08X %02X\n",
+ pos+=sprintf(pos, "%2d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08X %08X %d\n",
i, src, srcp, dest, destp, sp->state,
- sp->send_seq-sp->rcv_ack_seq, sp->acked_seq-sp->copied_seq,
- timer_active, sp->timer.expires, sp->retransmits);
+ format==0?sp->send_seq-sp->rcv_ack_seq:sp->rmem_alloc,
+ format==0?sp->acked_seq-sp->copied_seq:sp->wmem_alloc,
+ timer_active, sp->timer.expires, sp->retransmits,
+ SOCK_INODE(sp->socket)->i_uid);
if (timer_active)
add_timer(&sp->timer);
@@ -99,17 +110,17 @@ get__netinfo(struct proto *pro, char *buffer)
int tcp_get_info(char *buffer)
{
- return get__netinfo(&tcp_prot, buffer);
+ return get__netinfo(&tcp_prot, buffer,0);
}
int udp_get_info(char *buffer)
{
- return get__netinfo(&udp_prot, buffer);
+ return get__netinfo(&udp_prot, buffer,1);
}
int raw_get_info(char *buffer)
{
- return get__netinfo(&raw_prot, buffer);
+ return get__netinfo(&raw_prot, buffer,1);
}
diff --git a/net/inet/protocol.c b/net/inet/protocol.c
index 360962c..5690267 100644
--- a/net/inet/protocol.c
+++ b/net/inet/protocol.c
@@ -10,6 +10,12 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : Ahah! udp icmp errors don't work because
+ * udp_err is never called!
+ * Alan Cox : Added new fields for init and ready for
+ * proper fragmentation (_NO_ 4K limits!)
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -36,31 +42,37 @@
static struct inet_protocol tcp_protocol = {
tcp_rcv, /* TCP handler */
+ NULL, /* No fragment handler (and won't be for a long time) */
tcp_err, /* TCP error control */
NULL, /* next */
IPPROTO_TCP, /* protocol ID */
0, /* copy */
- NULL /* data */
+ NULL, /* data */
+ "TCP" /* name */
};
static struct inet_protocol udp_protocol = {
udp_rcv, /* UDP handler */
- NULL, /* UDP error control */
+ NULL, /* Will be UDP fraglist handler */
+ udp_err, /* UDP error control */
&tcp_protocol, /* next */
IPPROTO_UDP, /* protocol ID */
0, /* copy */
- NULL /* data */
+ NULL, /* data */
+ "UDP" /* name */
};
static struct inet_protocol icmp_protocol = {
icmp_rcv, /* ICMP handler */
+ NULL, /* ICMP never fragments anyway */
NULL, /* ICMP error control */
&udp_protocol, /* next */
IPPROTO_ICMP, /* protocol ID */
0, /* copy */
- NULL /* data */
+ NULL, /* data */
+ "ICMP" /* name */
};
diff --git a/net/inet/protocol.h b/net/inet/protocol.h
index b5330b8..3e0b6fb 100644
--- a/net/inet/protocol.h
+++ b/net/inet/protocol.h
@@ -13,7 +13,12 @@
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
+ *
+ * Changes:
+ * Alan Cox : Added a name field and a frag handler
+ * field for later.
*/
+
#ifndef _PROTOCOL_H
#define _PROTOCOL_H
@@ -27,6 +32,10 @@ struct inet_protocol {
struct options *opt, unsigned long daddr,
unsigned short len, unsigned long saddr,
int redo, struct inet_protocol *protocol);
+ int (*frag_handler)(struct sk_buff *skb, struct device *dev,
+ struct options *opt, unsigned long daddr,
+ unsigned short len, unsigned long saddr,
+ int redo, struct inet_protocol *protocol);
void (*err_handler)(int err, unsigned char *buff,
unsigned long daddr,
unsigned long saddr,
@@ -35,6 +44,7 @@ struct inet_protocol {
unsigned char protocol;
unsigned char copy:1;
void *data;
+ char *name;
};
diff --git a/net/inet/raw.c b/net/inet/raw.c
index 0822c48..c05ccf2 100644
--- a/net/inet/raw.c
+++ b/net/inet/raw.c
@@ -10,6 +10,14 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : verify_area() fixed up
+ * Alan Cox : ICMP error handling
+ * Alan Cox : EMSGSIZE if you send too big a packet
+ * Alan Cox : Now uses generic datagrams and shared skbuff
+ * library. No more peek crashes, no more backlogs
+ * Alan Cox : Checks sk->broadcast.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -66,13 +74,8 @@ raw_err (int err, unsigned char *header, unsigned long daddr,
}
sk->err = icmp_err_convert[err & 0xff].errno;
-
- /* None of them are fatal for raw sockets. */
-#if 0
- if (icmp_err_convert[err & 0xff].fatal) {
- sk->prot->close(sk, 0);
- }
-#endif
+ wake_up(sk->sleep);
+
return;
}
@@ -110,47 +113,14 @@ raw_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->saddr = daddr;
skb->daddr = saddr;
- if (!redo) {
- /* Now see if we are in use. */
- cli();
- if (sk->inuse) {
- DPRINTF((DBG_RAW, "raw_rcv adding to backlog.\n"));
- if (sk->back_log == NULL) {
- sk->back_log = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- skb->next = sk->back_log;
- skb->prev = sk->back_log->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- }
- sti();
- return(0);
- }
- sk->inuse = 1;
- sti();
- }
-
/* Charge it too the socket. */
- if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX) {
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
skb->sk = NULL;
kfree_skb(skb, FREE_READ);
return(0);
}
sk->rmem_alloc += skb->mem_len;
-
- /* Now just put it onto the queue. */
- if (sk->rqueue == NULL) {
- sk->rqueue = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- skb->next = sk->rqueue;
- skb->prev = sk->rqueue->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- }
+ skb_queue_tail(&sk->rqueue,skb);
wake_up(sk->sleep);
release_sock(sk);
return(0);
@@ -167,6 +137,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
struct device *dev=NULL;
struct sockaddr_in sin;
int tmp;
+ int err;
DPRINTF((DBG_RAW, "raw_sendto(sk=%X, from=%X, len=%d, noblock=%d, flags=%X,\n"
" usin=%X, addr_len = %d)\n", sk, from, len, noblock,
@@ -176,10 +147,15 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
if (flags) return(-EINVAL);
if (len < 0) return(-EINVAL);
+ err=verify_area(VERIFY_READ,from,len);
+ if(err)
+ return err;
/* Get and verify the address. */
if (usin) {
if (addr_len < sizeof(sin)) return(-EINVAL);
- /* verify_area (VERIFY_WRITE, usin, sizeof (sin));*/
+ err=verify_area (VERIFY_READ, usin, sizeof (sin));
+ if(err)
+ return err;
memcpy_fromfs(&sin, usin, sizeof(sin));
if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
} else {
@@ -189,20 +165,30 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
sin.sin_addr.s_addr = sk->daddr;
}
if (sin.sin_port == 0) sin.sin_port = sk->protocol;
+
+ if (sk->broadcast == 0 && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -ENETUNREACH;
sk->inuse = 1;
skb = NULL;
while (skb == NULL) {
+ if(sk->err!=0)
+ {
+ err= -sk->err;
+ sk->err=0;
+ release_sock(sk);
+ return(err);
+ }
+
skb = (struct sk_buff *) sk->prot->wmalloc(sk,
len+sizeof(*skb) + sk->prot->max_header,
0, GFP_KERNEL);
- /* This shouldn't happen, but it could. */
- /* FIXME: need to change this to sleep. */
if (skb == NULL) {
int tmp;
DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n"));
- if (noblock) return(-EAGAIN);
+ if (noblock)
+ return(-EAGAIN);
tmp = sk->wmem_alloc;
release_sock(sk);
cli();
@@ -217,7 +203,6 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
sti();
}
}
- skb->lock = 0;
skb->mem_addr = skb;
skb->mem_len = len + sizeof(*skb) +sk->prot->max_header;
skb->sk = sk;
@@ -230,7 +215,7 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
sk->protocol, sk->opt, skb->mem_len);
if (tmp < 0) {
DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n"));
- sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
+ kfree_skb(skb,FREE_WRITE);
release_sock(sk);
return(tmp);
}
@@ -252,6 +237,14 @@ raw_sendto(struct sock *sk, unsigned char *from, int len,
}
skb->len = tmp + len;
+
+ if(dev!=NULL && skb->len > dev->mtu)
+ {
+ kfree_skb(skb, FREE_WRITE);
+ release_sock(sk);
+ return(-EMSGSIZE);
+ }
+
sk->prot->queue_xmit(sk, dev, skb, 1);
release_sock(sk);
return(len);
@@ -295,6 +288,8 @@ raw_init(struct sock *sk)
p->protocol = sk->protocol;
p->data = (void *)sk;
p->err_handler = raw_err;
+ p->name="USER";
+ p->frag_handler = NULL; /* For now */
inet_add_protocol(p);
/* We need to remember this somewhere. */
@@ -317,6 +312,7 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
{
int copied=0;
struct sk_buff *skb;
+ int err;
DPRINTF((DBG_RAW, "raw_recvfrom (sk=%X, to=%X, len=%d, noblock=%d, flags=%X,\n"
" sin=%X, addr_len=%X)\n",
@@ -327,41 +323,20 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
if (sk->shutdown & RCV_SHUTDOWN) return(0);
if (addr_len) {
- verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
+ if(err)
+ return err;
put_fs_long(sizeof(*sin), addr_len);
}
- sk->inuse = 1;
- while (sk->rqueue == NULL) {
- if (noblock) {
- release_sock(sk);
- if (copied) return(copied);
- return(-EAGAIN);
- }
- release_sock(sk);
- cli();
- if (sk->rqueue == NULL) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- sti();
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- }
- skb = sk->rqueue;
-
- if (!(flags & MSG_PEEK)) {
- if (skb->next == skb) {
- sk->rqueue = NULL;
- } else {
- sk->rqueue = (struct sk_buff *)sk->rqueue ->next;
- skb->prev->next = skb->next;
- skb->next->prev = skb->prev;
- }
- }
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+
+ skb=skb_recv_datagram(sk,flags,noblock,&err);
+ if(skb==NULL)
+ return err;
+
copied = min(len, skb->len);
- verify_area(VERIFY_WRITE, to, copied);
memcpy_tofs(to, skb->h.raw, copied);
/* Copy the address. */
@@ -374,9 +349,7 @@ raw_recvfrom(struct sock *sk, unsigned char *to, int len,
memcpy_tofs(sin, &addr, sizeof(*sin));
}
- if (!(flags & MSG_PEEK)) {
- kfree_skb(skb, FREE_READ);
- }
+ kfree_skb(skb, FREE_READ);
release_sock(sk);
return (copied);
}
@@ -410,7 +383,7 @@ struct proto raw_prot = {
NULL,
NULL,
raw_rcv,
- udp_select,
+ datagram_select,
NULL,
raw_init,
NULL,
diff --git a/net/inet/route.c b/net/inet/route.c
index 007878c..856a9d4 100644
--- a/net/inet/route.c
+++ b/net/inet/route.c
@@ -10,6 +10,10 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : Verify area fixes.
+ * Alan Cox : cli() protects routing changes
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -61,9 +65,13 @@ static void
rt_del(unsigned long dst)
{
struct rtable *r, *x, *p;
-
+ unsigned long flags;
+
DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst)));
if ((r = rt_base) == NULL) return;
+
+ save_flags(flags);
+ cli();
p = NULL;
while(r != NULL) {
if (r->rt_dst == dst) {
@@ -77,6 +85,7 @@ rt_del(unsigned long dst)
r = r->rt_next;
}
}
+ restore_flags(flags);
}
@@ -85,9 +94,14 @@ void
rt_flush(struct device *dev)
{
struct rtable *r, *x, *p;
-
+ unsigned long flags;
+
DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name));
if ((r = rt_base) == NULL) return;
+
+ cli();
+ save_flags(flags);
+
p = NULL;
while(r != NULL) {
if (r->rt_dev == dev) {
@@ -101,6 +115,7 @@ rt_flush(struct device *dev)
r = r->rt_next;
}
}
+ restore_flags(flags);
}
@@ -110,6 +125,7 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
struct rtable *r, *r1;
struct rtable *rt;
int mask;
+ unsigned long cpuflags;
/* Allocate an entry. */
rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC);
@@ -150,13 +166,17 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
* found the first address which has the same generality
* as the one in rt. Then we can put rt in after it.
*/
- for (mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) {
+ for (mask = 0xff000000L; mask != 0xffffffffL; mask = (mask >> 8) | mask) {
if (mask & dst) {
mask = mask << 8;
break;
}
}
DPRINTF((DBG_RT, "RT: mask = %X\n", mask));
+
+ save_flags(cpuflags);
+ cli();
+
r1 = rt_base;
/* See if we are getting a duplicate. */
@@ -170,6 +190,7 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
r1->rt_next = rt;
}
kfree_s(r, sizeof(struct rtable));
+ restore_flags(cpuflags);
return;
}
@@ -179,10 +200,12 @@ rt_add(short flags, unsigned long dst, unsigned long gw, struct device *dev)
if (r == rt_base) {
rt->rt_next = rt_base;
rt_base = rt;
+ restore_flags(cpuflags);
return;
}
rt->rt_next = r;
r1->rt_next = rt;
+ restore_flags(cpuflags);
return;
}
r1 = r;
@@ -327,6 +350,7 @@ rt_ioctl(unsigned int cmd, void *arg)
struct rtentry rt;
char namebuf[32];
int ret;
+ int err;
switch(cmd) {
case DDIOCSDBG:
@@ -335,10 +359,14 @@ rt_ioctl(unsigned int cmd, void *arg)
case SIOCADDRT:
case SIOCDELRT:
if (!suser()) return(-EPERM);
- verify_area(VERIFY_WRITE, arg, sizeof(struct rtentry));
+ err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry));
+ if(err)
+ return err;
memcpy_fromfs(&rt, arg, sizeof(struct rtentry));
if (rt.rt_dev) {
- verify_area(VERIFY_WRITE, rt.rt_dev, sizeof namebuf);
+ err=verify_area(VERIFY_READ, rt.rt_dev, sizeof namebuf);
+ if(err)
+ return err;
memcpy_fromfs(&namebuf, rt.rt_dev, sizeof namebuf);
dev = dev_get(namebuf);
rt.rt_dev = dev;
diff --git a/net/inet/skbuff.c b/net/inet/skbuff.c
new file mode 100644
index 0000000..144fd55
--- /dev/null
+++ b/net/inet/skbuff.c
@@ -0,0 +1,435 @@
+/*
+ * INET An implementation of the TCP/IP protocol suite for the LINUX
+ * operating system. INET is implemented using the BSD Socket
+ * interface as the means of communication with the user level.
+ *
+ * A saner implementation of the skbuff stuff scattered everywhere
+ * in the old NET2D code.
+ *
+ * Authors: Alan Cox <iiitac@pyr.swan.ac.uk>
+ *
+ * Fixes:
+ * Alan Cox : Tracks memory and number of buffers for kernel memory report
+ * and memory leak hunting.
+ */
+
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <asm/segment.h>
+#include <asm/system.h>
+#include <linux/mm.h>
+#include <linux/interrupt.h>
+#include <linux/in.h>
+#include "inet.h"
+#include "dev.h"
+#include "ip.h"
+#include "protocol.h"
+#include "arp.h"
+#include "route.h"
+#include "tcp.h"
+#include "udp.h"
+#include "skbuff.h"
+#include "sock.h"
+
+
+/* Socket buffer operations. Ideally much of this list swap stuff ought to be using
+ exch instructions on the 386, and CAS/CAS2 on a 68K. This is the boring generic
+ slow C version. No doubt when Linus sees this comment he'll do horrible things
+ to this code 8-)
+*/
+
+/*
+ * Resource tracking variables
+ */
+
+volatile unsigned long net_memory=0;
+volatile unsigned long net_skbcount=0;
+
+/*
+ * Debugging paranoia. Can go later when this crud stack works
+ */
+
+
+
+void skb_check(struct sk_buff *skb, int line, char *file)
+{
+ if(skb->magic_debug_cookie==SK_FREED_SKB)
+ {
+ printk("File: %s Line %d, found a freed skb lurking in the undergrowth!\n",
+ file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%ld, list=%p, free=%d\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
+ }
+ if(skb->magic_debug_cookie!=SK_GOOD_SKB)
+ {
+ printk("File: %s Line %d, passed a non skb!\n", file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%ld, list=%p, free=%d\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list,skb->free);
+ }
+ if(skb->mem_len!=skb->truesize)
+ {
+ printk("File: %s Line %d, Dubious size setting!\n",file,line);
+ printk("skb=%p, real size=%ld, claimed size=%ld, magic=%ld, list=%p\n",
+ skb,skb->truesize,skb->mem_len,skb->magic,skb->list);
+ }
+ /* Guess it might be acceptable then */
+}
+
+/*
+ * Insert an sk_buff at the start of a list.
+ */
+
+void skb_queue_head(struct sk_buff *volatile* list,struct sk_buff *new)
+{
+ unsigned long flags;
+
+ IS_SKB(new);
+ if(new->list)
+ printk("Suspicious queue head: sk_buff on list!\n");
+ save_flags(flags);
+ cli();
+ new->list=list;
+
+ new->next=*list;
+
+ if(*list)
+ new->prev=(*list)->prev;
+ else
+ new->prev=new;
+ new->prev->next=new;
+ new->next->prev=new;
+ IS_SKB(new->prev);
+ IS_SKB(new->next);
+ *list=new;
+ restore_flags(flags);
+}
+
+/*
+ * Insert an sk_buff at the end of a list.
+ */
+
+void skb_queue_tail(struct sk_buff *volatile* list, struct sk_buff *new)
+{
+ unsigned long flags;
+
+ if(new->list)
+ printk("Suspicious queue tail: sk_buff on list!\n");
+
+ IS_SKB(new);
+ save_flags(flags);
+ cli();
+
+ new->list=list;
+ if(*list)
+ {
+ (*list)->prev->next=new;
+ (*list)->prev=new;
+ new->next=*list;
+ new->prev=(*list)->prev;
+ }
+ else
+ {
+ new->next=new;
+ new->prev=new;
+ *list=new;
+ }
+ IS_SKB(new->prev);
+ IS_SKB(new->next);
+ restore_flags(flags);
+
+}
+
+/*
+ * Remove an sk_buff from a list. This routine is also interrupt safe
+ * so you can grab read and free buffers as another process adds them.
+ */
+
+struct sk_buff *skb_dequeue(struct sk_buff *volatile* list)
+{
+ long flags;
+ struct sk_buff *result;
+
+ save_flags(flags);
+ cli();
+
+ if(*list==NULL)
+ {
+ restore_flags(flags);
+ return(NULL);
+ }
+
+ result=*list;
+ if(result->next==result)
+ *list=NULL;
+ else
+ {
+ result->next->prev=result->prev;
+ result->prev->next=result->next;
+ *list=result->next;
+ }
+
+ IS_SKB(result);
+ restore_flags(flags);
+
+ if(result->list!=list)
+ printk("Dequeued packet has invalid list pointer\n");
+
+ result->list=0;
+ result->next=0;
+ result->prev=0;
+ return(result);
+}
+
+/*
+ * Insert a packet before another one in a list.
+ */
+
+void skb_insert(struct sk_buff *old, struct sk_buff *new)
+{
+ unsigned long flags;
+
+ IS_SKB(old);
+ IS_SKB(new);
+
+ if(!old->list)
+ printk("insert before unlisted item!\n");
+ if(new->list)
+ printk("inserted item is already on a list.\n");
+
+ save_flags(flags);
+ cli();
+ new->list=old->list;
+ new->next=old;
+ new->prev=old->prev;
+ new->next->prev=new;
+ new->prev->next=new;
+
+ restore_flags(flags);
+}
+
+/*
+ * Place a packet after a given packet in a list.
+ */
+
+void skb_append(struct sk_buff *old, struct sk_buff *new)
+{
+ unsigned long flags;
+
+ IS_SKB(old);
+ IS_SKB(new);
+
+ if(!old->list)
+ printk("append before unlisted item!\n");
+ if(new->list)
+ printk("append item is already on a list.\n");
+
+ save_flags(flags);
+ cli();
+ new->list=old->list;
+ new->prev=old;
+ new->next=old->next;
+ new->next->prev=new;
+ new->prev->next=new;
+
+ restore_flags(flags);
+}
+
+/*
+ * Remove an sk_buff from its list. Works even without knowing the list it
+ * is sitting on, which can be handy at times. It also means that THE LIST
+ * MUST EXIST when you unlink. Thus a list must have its contents unlinked
+ * _FIRST_.
+ */
+
+void skb_unlink(struct sk_buff *skb)
+{
+ unsigned long flags;
+ save_flags(flags);
+ cli();
+
+ IS_SKB(skb);
+
+ if(skb->list)
+ {
+ skb->next->prev=skb->prev;
+ skb->prev->next=skb->next;
+ if(*skb->list==skb)
+ {
+ if(skb->next==skb)
+ *skb->list=NULL;
+ else
+ *skb->list=skb->next;
+ }
+ skb->next=0;
+ skb->prev=0;
+ skb->list=0;
+ }
+ restore_flags(flags);
+}
+
+/*
+ * An skbuff list has had its head reassigned. Move all the list
+ * pointers. Must be called with ints off during the whole head
+ * shifting
+ */
+
+void skb_new_list_head(struct sk_buff *volatile* list)
+{
+ struct sk_buff *skb=skb_peek(list);
+ if(skb!=NULL)
+ {
+ do
+ {
+ IS_SKB(skb);
+ skb->list=list;
+ skb=skb->next;
+ }
+ while(skb!=*list);
+ }
+}
+
+/*
+ * Peek an sk_buff. Unlike most other operations you _MUST_
+ * be careful with this one. A peek leaves the buffer on the
+ * list and someone else may run off with it. For an interrupt
+ * type system cli() peek the buffer copy the data and sti();
+ */
+
+struct sk_buff *skb_peek(struct sk_buff *volatile* list)
+{
+ return *list;
+}
+
+/*
+ * Get a clone of an sk_buff. This is the safe way to peek at
+ * a socket queue without accidents. Its a bit long but most
+ * of it acutally ends up as tiny bits of inline assembler
+ * anyway. Only the memcpy of upto 4K with ints off is not
+ * as nice as I'd like.
+ */
+
+struct sk_buff *skb_peek_copy(struct sk_buff *volatile* list)
+{
+ struct sk_buff *orig,*new;
+ unsigned long flags;
+ unsigned int len;
+ /* Now for some games to avoid races */
+
+ do
+ {
+ save_flags(flags);
+ cli();
+ orig=skb_peek(list);
+ if(orig==NULL)
+ {
+ restore_flags(flags);
+ return NULL;
+ }
+ IS_SKB(orig);
+ len=orig->truesize;
+ restore_flags(flags);
+
+ new=alloc_skb(len,GFP_KERNEL); /* May sleep */
+
+ if(new==NULL) /* Oh dear... not to worry */
+ return NULL;
+
+ save_flags(flags);
+ cli();
+ if(skb_peek(list)!=orig) /* List changed go around another time */
+ {
+ restore_flags(list);
+ new->sk=NULL;
+ new->free=1;
+ new->mem_addr=new;
+ new->mem_len=len;
+ kfree_skb(new, FREE_WRITE);
+ continue;
+ }
+
+ IS_SKB(orig);
+ IS_SKB(new);
+ memcpy(new,orig,len);
+ new->list=NULL;
+ new->magic=0;
+ new->next=NULL;
+ new->prev=NULL;
+ new->mem_addr=new;
+ new->h.raw+=((char *)new-(char *)orig);
+ new->link3=NULL;
+ new->sk=NULL;
+ new->free=1;
+ }
+ while(0);
+
+ restore_flags(flags);
+ return(new);
+}
+
+/*
+ * Free an sk_buff. This still knows about things it should
+ * not need to like protocols and sockets.
+ */
+
+void kfree_skb(struct sk_buff *skb, int rw)
+{
+ if (skb == NULL) {
+ printk("kfree_skb: skb = NULL\n");
+ return;
+ }
+ IS_SKB(skb);
+ if(skb->free == 2)
+ printk("Warning: kfree_skb passed an skb that nobody set the free flag on!\n");
+ if(skb->list)
+ printk("Warning: kfree_skb passed an skb still on a list.\n");
+ skb->magic = 0;
+ if (skb->sk) {
+ if (rw) {
+ skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
+ } else {
+ skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
+ }
+ } else {
+ kfree_skbmem(skb->mem_addr, skb->mem_len);
+ }
+}
+
+/*
+ * Allocate a new skbuff. We do this ourselves so we can fill in a few 'private'
+ * fields and also do memory statistics to find all the [BEEP] leaks.
+ */
+
+ struct sk_buff *alloc_skb(unsigned int size,int priority)
+ {
+ struct sk_buff *skb=(struct sk_buff *)kmalloc(size,priority);
+ if(skb==NULL)
+ return NULL;
+ skb->free= 2; /* Invalid so we pick up forgetful users */
+ skb->list= 0; /* Not on a list */
+ skb->truesize=size;
+ skb->mem_len=size;
+ skb->mem_addr=skb;
+ net_memory+=size;
+ net_skbcount++;
+ skb->magic_debug_cookie=SK_GOOD_SKB;
+ return skb;
+ }
+
+/*
+ * Free an skbuff by memory
+ */
+
+void kfree_skbmem(void *mem,unsigned size)
+{
+ struct sk_buff *x=mem;
+ IS_SKB(x);
+ if(x->magic_debug_cookie==SK_GOOD_SKB)
+ {
+ x->magic_debug_cookie=SK_FREED_SKB;
+ kfree_s(mem,size);
+ net_skbcount--;
+ net_memory-=size;
+ }
+}
+
diff --git a/net/inet/skbuff.h b/net/inet/skbuff.h
index 8591a3d..66cb498 100644
--- a/net/inet/skbuff.h
+++ b/net/inet/skbuff.h
@@ -11,6 +11,10 @@
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Corey Minyard <wf-rch!minyard@relay.EU.net>
*
+ * Fixes:
+ * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff)
+ * Alan Cox : Declaration for new primitives
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -18,6 +22,8 @@
*/
#ifndef _SKBUFF_H
#define _SKBUFF_H
+#include <linux/malloc.h>
+#define HAVE_ALLOC_SKB /* For the drivers to know */
#define FREE_READ 1
@@ -25,9 +31,11 @@
struct sk_buff {
+ unsigned long magic_debug_cookie;
struct sk_buff *volatile next;
struct sk_buff *volatile prev;
struct sk_buff *volatile link3;
+ struct sk_buff *volatile* list;
struct sock *sk;
volatile unsigned long when; /* used to compute rtt's */
struct device *dev;
@@ -43,6 +51,7 @@ struct sk_buff {
} h;
unsigned long mem_len;
unsigned long len;
+ unsigned long truesize;
unsigned long saddr;
unsigned long daddr;
int magic;
@@ -50,18 +59,33 @@ struct sk_buff {
used,
free,
arp,
- urg_used,
- lock;
- unsigned char tries;
+ urg_used;
+ unsigned char tries,lock; /* Lock is now unused */
};
#define SK_WMEM_MAX 8192
#define SK_RMEM_MAX 32767
+#define SK_FREED_SKB 0x0DE2C0DE
+#define SK_GOOD_SKB 0xDEC0DED1
extern void print_skb(struct sk_buff *);
extern void kfree_skb(struct sk_buff *skb, int rw);
-extern void lock_skb(struct sk_buff *skb);
-extern void unlock_skb(struct sk_buff *skb, int rw);
+extern void skb_queue_head(struct sk_buff * volatile *list,struct sk_buff *buf);
+extern void skb_queue_tail(struct sk_buff * volatile *list,struct sk_buff *buf);
+extern struct sk_buff * skb_dequeue(struct sk_buff * volatile *list);
+extern void skb_insert(struct sk_buff *old,struct sk_buff *new);
+extern void skb_append(struct sk_buff *old,struct sk_buff *new);
+extern void skb_unlink(struct sk_buff *buf);
+extern void skb_new_list_head(struct sk_buff *volatile* list);
+extern struct sk_buff * skb_peek(struct sk_buff * volatile *list);
+extern struct sk_buff * skb_peek_copy(struct sk_buff * volatile *list);
+extern struct sk_buff * alloc_skb(unsigned int size, int priority);
+extern void kfree_skbmem(void *mem, unsigned size);
+
+extern void skb_check(struct sk_buff *skb,int, char *);
+#define IS_SKB(skb) skb_check((skb),__LINE__,__FILE__)
+extern struct sk_buff * skb_recv_datagram(struct sock *sk,unsigned flags,int noblock, int *err);
+extern int datagram_select(struct sock *sk, int sel_type, select_table *wait);
#endif /* _SKBUFF_H */
diff --git a/net/inet/sock.c b/net/inet/sock.c
index 7f97fd7..106e763 100644
--- a/net/inet/sock.c
+++ b/net/inet/sock.c
@@ -11,6 +11,43 @@
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
* Florian La Roche, <flla@stud.uni-sb.de>
*
+ * Fixes:
+ * Alan Cox : Numerous verify_area() problems
+ * Alan Cox : Connecting on a connecting socket
+ * now returns an error for tcp.
+ * Alan Cox : sock->protocol is set correctly.
+ * and is not sometimes left as 0.
+ * Alan Cox : connect handles icmp errors on a
+ * connect properly. Unfortunately there
+ * is a restart syscall nasty there. I
+ * can't match BSD without hacking the C
+ * library. Ideas urgently sought!
+ * Alan Cox : Disallow bind() to addresses that are
+ * not ours - especially broadcast ones!!
+ * Alan Cox : Socket 1024 _IS_ ok for users. (fencepost)
+ * Alan Cox : sock_wfree/sock_rfree don't destroy sockets,
+ * instead they leave that for the DESTROY timer.
+ * Alan Cox : Clean up error flag in accept
+ * Alan Cox : TCP ack handling is buggy, the DESTROY timer
+ * was buggy. Put a remove_sock() in the handler
+ * for memory when we hit 0. Also altered the timer
+ * code. The ACK stuff can wait and needs major
+ * TCP layer surgery.
+ * Alan Cox : Fixed TCP ack bug, removed remove sock
+ * and fixed timer/inet_bh race.
+ * Alan Cox : Added zapped flag for TCP
+ * Alan Cox : Move kfree_skb into skbuff.c and tidied up surplus code
+ * Alan Cox : for new sk_buff allocations wmalloc/rmalloc now call alloc_skb
+ * Alan Cox : kfree_s calls now are kfree_skbmem so we can track skb resources
+ * Alan Cox : Supports socket option broadcast now as does udp. Packet and raw need fixing.
+ * Alan Cox : Added RCVBUF,SNDBUF size setting. It suddenely occured to me how easy it was so...
+ * Rick Sladkey : Relaxed UDP rules for matching packets.
+ * C.E.Hawkins : IFF_PROMISC/SIOCGHWADDR support
+ * Pauline Middelink : Pidentd support
+ *
+ * To Fix:
+ *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -99,51 +136,6 @@ print_skb(struct sk_buff *skb)
}
-void
-lock_skb(struct sk_buff *skb)
-{
- if (skb->lock) {
- printk("*** bug more than one lock on sk_buff. \n");
- }
- skb->lock = 1;
-}
-
-
-void
-kfree_skb(struct sk_buff *skb, int rw)
-{
- if (skb == NULL) {
- printk("kfree_skb: skb = NULL\n");
- return;
- }
-
- if (skb->lock) {
- skb->free = 1;
- return;
- }
- skb->magic = 0;
- if (skb->sk) {
- if (rw) {
- skb->sk->prot->rfree(skb->sk, skb->mem_addr, skb->mem_len);
- } else {
- skb->sk->prot->wfree(skb->sk, skb->mem_addr, skb->mem_len);
- }
- } else {
- kfree_s(skb->mem_addr, skb->mem_len);
- }
-}
-
-
-void
-unlock_skb(struct sk_buff *skb, int rw)
-{
- if (skb->lock != 1) {
- printk("INET: *** bug unlocking non-locked sk_buff. \n");
- }
- skb->lock = 0;
- if (skb->free) kfree_skb(skb, rw);
-}
-
static int
sk_inuse(struct proto *prot, int num)
@@ -305,180 +297,140 @@ remove_sock(struct sock *sk1)
void
destroy_sock(struct sock *sk)
{
- struct sk_buff *skb;
+ struct sk_buff *skb;
- DPRINTF((DBG_INET, "destroying socket %X\n", sk));
- sk->inuse = 1; /* just to be safe. */
+ DPRINTF((DBG_INET, "destroying socket %X\n", sk));
+ sk->inuse = 1; /* just to be safe. */
- /* Incase it's sleeping somewhere. */
- if (!sk->dead) wake_up(sk->sleep);
+ /* Incase it's sleeping somewhere. */
+ if (!sk->dead)
+ wake_up(sk->sleep);
- remove_sock(sk);
+ remove_sock(sk);
+
+ /* Now we can no longer get new packets. */
+ delete_timer(sk);
- /* Now we can no longer get new packets. */
- delete_timer(sk);
- if (sk->send_tmp != NULL) kfree_skb(sk->send_tmp, FREE_WRITE);
+ if (sk->send_tmp != NULL)
+ {
+ IS_SKB(sk->send_tmp);
+ kfree_skb(sk->send_tmp, FREE_WRITE);
+ }
/* Cleanup up the write buffer. */
- for(skb = sk->wfront; skb != NULL; ) {
- struct sk_buff *skb2;
+ for(skb = sk->wfront; skb != NULL; )
+ {
+ struct sk_buff *skb2;
- skb2=(struct sk_buff *)skb->next;
- if (skb->magic != TCP_WRITE_QUEUE_MAGIC) {
- printk("sock.c:destroy_sock write queue with bad magic(%X)\n",
+ skb2=(struct sk_buff *)skb->next;
+ if (skb->magic != TCP_WRITE_QUEUE_MAGIC) {
+ printk("sock.c:destroy_sock write queue with bad magic(%X)\n",
skb->magic);
- break;
- }
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- }
-
- sk->wfront = NULL;
- sk->wback = NULL;
-
- if (sk->rqueue != NULL) {
- skb = sk->rqueue;
- do {
- struct sk_buff *skb2;
+ break;
+ }
+ IS_SKB(skb);
+ kfree_skb(skb, FREE_WRITE);
+ skb = skb2;
+ }
- skb2 = (struct sk_buff *)skb->next;
+ sk->wfront = NULL;
+ sk->wback = NULL;
+ if (sk->rqueue != NULL)
+ {
+ while((skb=skb_dequeue(&sk->rqueue))!=NULL)
+ {
/*
* This will take care of closing sockets that were
* listening and didn't accept everything.
*/
- if (skb->sk != NULL && skb->sk != sk) {
- skb->sk->dead = 1;
- skb->sk->prot->close(skb->sk, 0);
- }
- kfree_skb(skb, FREE_READ);
- skb = skb2;
- } while(skb != sk->rqueue);
- }
- sk->rqueue = NULL;
-
- /* Now we need to clean up the send head. */
- for(skb = sk->send_head; skb != NULL; ) {
- struct sk_buff *skb2;
-
- /*
- * We need to remove skb from the transmit queue,
- * or maybe the arp queue.
- */
- cli();
- /* see if it's in a transmit queue. */
- /* this can be simplified quite a bit. Look */
- /* at tcp.c:tcp_ack to see how. */
- if (skb->next != NULL) {
- int i;
-
- if (skb->next != skb) {
- skb->next->prev = skb->prev;
- skb->prev->next = skb->next;
-
- if (skb == arp_q) {
- if (skb->magic != ARP_QUEUE_MAGIC) {
- sti();
- printk("sock.c: destroy_sock skb on arp queue with"
- "bas magic(%X)\n", skb->magic);
- cli();
- arp_q = NULL;
- continue;
- }
- arp_q = skb->next;
- } else {
- for(i = 0; i < DEV_NUMBUFFS; i++) {
- if (skb->dev &&
- skb->dev->buffs[i] == skb) {
- if (skb->magic != DEV_QUEUE_MAGIC) {
- sti();
- printk("sock.c: destroy sock skb on dev queue"
- "with bad magic(%X)\n", skb->magic);
- cli();
- break;
- }
- skb->dev->buffs[i]= skb->next;
- break;
- }
- }
- }
- } else {
- if (skb == arp_q) {
- if (skb->magic != ARP_QUEUE_MAGIC) {
- sti();
- printk("sock.c: destroy_sock skb on arp queue with"
- "bas magic(%X)\n", skb->magic);
- cli();
- }
- arp_q = NULL;
- } else {
- for(i = 0; i < DEV_NUMBUFFS; i++) {
- if (skb->dev &&
- skb->dev->buffs[i] == skb) {
- if (skb->magic != DEV_QUEUE_MAGIC) {
- sti();
- printk("sock.c: destroy sock skb on dev queue"
- "with bad magic(%X)\n", skb->magic);
- cli();
- break;
- }
- skb->dev->buffs[i]= NULL;
- break;
- }
- }
+ if (skb->sk != NULL && skb->sk != sk)
+ {
+ IS_SKB(skb);
+ skb->sk->dead = 1;
+ skb->sk->prot->close(skb->sk, 0);
}
+ IS_SKB(skb);
+ kfree_skb(skb, FREE_READ);
}
- }
- skb->dev = NULL;
- sti();
- skb2 = (struct sk_buff *)skb->link3;
- kfree_skb(skb, FREE_WRITE);
- skb = skb2;
- }
- sk->send_head = NULL;
+ }
+ sk->rqueue = NULL;
- /* And now the backlog. */
- if (sk->back_log != NULL) {
- /* this should never happen. */
- printk("cleaning back_log. \n");
- cli();
- skb = (struct sk_buff *)sk->back_log;
- do {
+ /* Now we need to clean up the send head. */
+ for(skb = sk->send_head; skb != NULL; )
+ {
struct sk_buff *skb2;
- skb2 = (struct sk_buff *)skb->next;
- kfree_skb(skb, FREE_READ);
+ /*
+ * We need to remove skb from the transmit queue,
+ * or maybe the arp queue.
+ */
+ cli();
+ /* see if it's in a transmit queue. */
+ /* this can be simplified quite a bit. Look */
+ /* at tcp.c:tcp_ack to see how. */
+ if (skb->next != NULL)
+ {
+ IS_SKB(skb);
+ skb_unlink(skb);
+ }
+ skb->dev = NULL;
+ sti();
+ skb2 = (struct sk_buff *)skb->link3;
+ kfree_skb(skb, FREE_WRITE);
skb = skb2;
- } while(skb != sk->back_log);
- sti();
- }
- sk->back_log = NULL;
+ }
+ sk->send_head = NULL;
+
+ /* And now the backlog. */
+ if (sk->back_log != NULL)
+ {
+ /* this should never happen. */
+ printk("cleaning back_log. \n");
+ cli();
+ skb = (struct sk_buff *)sk->back_log;
+ do
+ {
+ struct sk_buff *skb2;
+
+ skb2 = (struct sk_buff *)skb->next;
+ kfree_skb(skb, FREE_READ);
+ skb = skb2;
+ }
+ while(skb != sk->back_log);
+ sti();
+ }
+ sk->back_log = NULL;
/* Now if it has a half accepted/ closed socket. */
- if (sk->pair) {
- sk->pair->dead = 1;
- sk->pair->prot->close(sk->pair, 0);
- sk->pair = NULL;
- }
+ if (sk->pair)
+ {
+ sk->pair->dead = 1;
+ sk->pair->prot->close(sk->pair, 0);
+ sk->pair = NULL;
+ }
/*
* Now if everything is gone we can free the socket
* structure, otherwise we need to keep it around until
* everything is gone.
*/
- if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0) {
- kfree_s((void *)sk,sizeof(*sk));
- } else {
- /* this should never happen. */
- /* actually it can if an ack has just been sent. */
- DPRINTF((DBG_INET, "possible memory leak in socket = %X\n", sk));
- sk->destroy = 1;
- sk->ack_backlog = 0;
- sk->inuse = 0;
- reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
- }
- DPRINTF((DBG_INET, "leaving destroy_sock\n"));
+ if (sk->rmem_alloc == 0 && sk->wmem_alloc == 0)
+ {
+ kfree_s((void *)sk,sizeof(*sk));
+ }
+ else
+ {
+ /* this should never happen. */
+ /* actually it can if an ack has just been sent. */
+ DPRINTF((DBG_INET, "possible memory leak in socket = %X\n", sk));
+ sk->destroy = 1;
+ sk->ack_backlog = 0;
+ sk->inuse = 0;
+ reset_timer(sk, TIME_DESTROY, SOCK_DESTROY_TIME);
+ }
+ DPRINTF((DBG_INET, "leaving destroy_sock\n"));
}
@@ -518,7 +470,8 @@ inet_setsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk;
int val;
-
+ int err;
+
/* This should really pass things on to the other levels. */
if (level != SOL_SOCKET) return(-EOPNOTSUPP);
@@ -529,18 +482,36 @@ inet_setsockopt(struct socket *sock, int level, int optname,
}
if (optval == NULL) return(-EINVAL);
- /* verify_area(VERIFY_WRITE, optval, sizeof(int));*/
+ err=verify_area(VERIFY_READ, optval, sizeof(int));
+ if(err)
+ return err;
+
val = get_fs_long((unsigned long *)optval);
switch(optname) {
case SO_TYPE:
case SO_ERROR:
return(-ENOPROTOOPT);
- case SO_DEBUG: /* not implemented. */
- case SO_DONTROUTE:
+ case SO_DEBUG:
+ sk->debug=val?1:0;
+ case SO_DONTROUTE: /* Still to be implemented */
+ return(0);
case SO_BROADCAST:
+ sk->broadcast=val?1:0;
+ return 0;
case SO_SNDBUF:
+ if(val>32767)
+ val=32767;
+ if(val<256)
+ val=256;
+ sk->sndbuf=val;
+ return 0;
case SO_RCVBUF:
+ if(val>32767)
+ val=32767;
+ if(val<256)
+ val=256;
+ sk->rcvbuf=val;
return(0);
case SO_REUSEADDR:
@@ -583,6 +554,7 @@ inet_getsockopt(struct socket *sock, int level, int optname,
{
struct sock *sk;
int val;
+ int err;
/* This should really pass things on to the other levels. */
if (level != SOL_SOCKET) return(-EOPNOTSUPP);
@@ -595,11 +567,23 @@ inet_getsockopt(struct socket *sock, int level, int optname,
switch(optname) {
case SO_DEBUG: /* not implemented. */
- case SO_DONTROUTE:
+ val = sk->debug; /* No per socket debugging _YET_ */
+ break;
+
+ case SO_DONTROUTE: /* One last option to implement */
+ val = 0;
+ break;
+
case SO_BROADCAST:
+ val= sk->broadcast;
+ break;
+
case SO_SNDBUF:
+ val=sk->sndbuf;
+ break;
+
case SO_RCVBUF:
- val = 0;
+ val =sk->rcvbuf;
break;
case SO_REUSEADDR:
@@ -635,10 +619,14 @@ inet_getsockopt(struct socket *sock, int level, int optname,
default:
return(-ENOPROTOOPT);
}
- verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ err=verify_area(VERIFY_WRITE, optlen, sizeof(int));
+ if(err)
+ return err;
put_fs_long(sizeof(int),(unsigned long *) optlen);
- verify_area(VERIFY_WRITE, optval, sizeof(int));
+ err=verify_area(VERIFY_WRITE, optval, sizeof(int));
+ if(err)
+ return err;
put_fs_long(val,(unsigned long *)optval);
return(0);
@@ -682,7 +670,8 @@ inet_create(struct socket *sock, int protocol)
int err;
sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL);
- if (sk == NULL) return(-ENOMEM);
+ if (sk == NULL)
+ return(-ENOMEM);
sk->num = 0;
switch(sock->type) {
@@ -692,6 +681,7 @@ inet_create(struct socket *sock, int protocol)
kfree_s((void *)sk, sizeof(*sk));
return(-EPROTONOSUPPORT);
}
+ protocol = IPPROTO_TCP;
sk->no_check = TCP_NO_CHECK;
prot = &tcp_prot;
break;
@@ -701,6 +691,7 @@ inet_create(struct socket *sock, int protocol)
kfree_s((void *)sk, sizeof(*sk));
return(-EPROTONOSUPPORT);
}
+ protocol = IPPROTO_UDP;
sk->no_check = UDP_NO_CHECK;
prot=&udp_prot;
break;
@@ -744,9 +735,12 @@ inet_create(struct socket *sock, int protocol)
kfree_s((void *)sk, sizeof(*sk));
return(-ESOCKTNOSUPPORT);
}
+ sk->socket = sock;
sk->protocol = protocol;
sk->wmem_alloc = 0;
sk->rmem_alloc = 0;
+ sk->sndbuf = SK_WMEM_MAX;
+ sk->rcvbuf = SK_RMEM_MAX;
sk->pair = NULL;
sk->opt = NULL;
sk->send_seq = 0;
@@ -770,6 +764,7 @@ inet_create(struct socket *sock, int protocol)
sk->shutdown = 0;
sk->urg = 0;
sk->keepopen = 0;
+ sk->zapped = 0;
sk->done = 0;
sk->ack_backlog = 0;
sk->window = 0;
@@ -802,6 +797,7 @@ inet_create(struct socket *sock, int protocol)
sk->send_tail = NULL;
sk->send_head = NULL;
sk->timeout = 0;
+ sk->broadcast = 0;
sk->timer.data = (unsigned long)sk;
sk->timer.function = &net_timer;
sk->back_log = NULL;
@@ -905,6 +901,7 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
struct sockaddr_in addr;
struct sock *sk, *sk2;
unsigned short snum;
+ int err;
sk = (struct sock *) sock->data;
if (sk == NULL) {
@@ -916,19 +913,11 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
if (sk->state != TCP_CLOSE) return(-EIO);
if (sk->num != 0) return(-EINVAL);
- /* verify_area(VERIFY_WRITE, uaddr, addr_len);*/
+ err=verify_area(VERIFY_READ, uaddr, addr_len);
+ if(err)
+ return err;
memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len));
-#if 0 /* FIXME: */
- if (addr.sin_family && addr.sin_family != AF_INET) {
- /*
- * This is really a bug in BSD which we need
- * to emulate because ftp expects it.
- */
- return(-EINVAL);
- }
-#endif
-
snum = ntohs(addr.sin_port);
DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum));
sk = (struct sock *) sock->data;
@@ -939,11 +928,13 @@ inet_bind(struct socket *sock, struct sockaddr *uaddr,
* be a bug here, we will leave it if the port is not privileged.
*/
if (snum == 0) {
-/* if (sk->num > PROT_SOCK) return(0); */
snum = get_new_socknum(sk->prot, 0);
}
- if (snum <= PROT_SOCK && !suser()) return(-EACCES);
+ if (snum < PROT_SOCK && !suser()) return(-EACCES);
+ if (addr.sin_addr.s_addr!=0 && chk_addr(addr.sin_addr.s_addr)!=IS_MYADDR)
+ return(-EADDRNOTAVAIL); /* Source address MUST be ours! */
+
if (chk_addr(addr.sin_addr.s_addr) || addr.sin_addr.s_addr == 0)
sk->saddr = addr.sin_addr.s_addr;
@@ -999,16 +990,21 @@ inet_connect(struct socket *sock, struct sockaddr * uaddr,
return(0);
}
+ if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP)
+ return -EALREADY; /* Connecting is currently in progress */
+
if (sock->state != SS_CONNECTING) {
/* We may need to bind the socket. */
if (sk->num == 0) {
sk->num = get_new_socknum(sk->prot, 0);
- if (sk->num == 0) return(-EAGAIN);
+ if (sk->num == 0)
+ return(-EAGAIN);
put_sock(sk->num, sk);
sk->dummy_th.source = htons(sk->num);
}
- if (sk->prot->connect == NULL) return(-EOPNOTSUPP);
+ if (sk->prot->connect == NULL)
+ return(-EOPNOTSUPP);
err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len);
if (err < 0) return(err);
@@ -1016,15 +1012,26 @@ inet_connect(struct socket *sock, struct sockaddr * uaddr,
sock->state = SS_CONNECTING;
}
- if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK)) return(-EINPROGRESS);
+ if (sk->state != TCP_ESTABLISHED &&(flags & O_NONBLOCK))
+ return(-EINPROGRESS);
cli(); /* avoid the race condition */
- while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV) {
+ while(sk->state == TCP_SYN_SENT || sk->state == TCP_SYN_RECV)
+ {
interruptible_sleep_on(sk->sleep);
if (current->signal & ~current->blocked) {
sti();
return(-ERESTARTSYS);
}
+ /* This fixes a nasty in the tcp/ip code. There is a hideous hassle with
+ icmp error packets wanting to close a tcp or udp socket. */
+ if(sk->err && sk->protocol == IPPROTO_TCP)
+ {
+ sk->inuse=1; /* keep the socket safe for us to use */
+ sti();
+ sock->state = SS_UNCONNECTED;
+ return -sk->err; /* set by tcp_err() */
+ }
}
sti();
sock->state = SS_CONNECTED;
@@ -1048,6 +1055,7 @@ static int
inet_accept(struct socket *sock, struct socket *newsock, int flags)
{
struct sock *sk1, *sk2;
+ int err;
sk1 = (struct sock *) sock->data;
if (sk1 == NULL) {
@@ -1074,7 +1082,9 @@ inet_accept(struct socket *sock, struct socket *newsock, int flags)
if (sk2 == NULL) {
if (sk1->err <= 0)
printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n");
- return(-sk1->err);
+ err=sk1->err;
+ sk1->err=0;
+ return(-err);
}
}
newsock->data = (void *)sk2;
@@ -1096,9 +1106,9 @@ inet_accept(struct socket *sock, struct socket *newsock, int flags)
sti();
if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) {
- int err;
err = -sk2->err;
+ sk2->err=0;
destroy_sock(sk2);
newsock->data = NULL;
return(err);
@@ -1115,9 +1125,19 @@ inet_getname(struct socket *sock, struct sockaddr *uaddr,
struct sockaddr_in sin;
struct sock *sk;
int len;
-
- len = get_fs_long(uaddr_len);
-
+ int err;
+
+
+ err = verify_area(VERIFY_WRITE,uaddr_len,sizeof(long));
+ if(err)
+ return err;
+
+ len=get_fs_long(uaddr_len);
+
+ err = verify_area(VERIFY_WRITE, uaddr, len);
+ if(err)
+ return err;
+
/* Check this error. */
if (len < sizeof(sin)) return(-EINVAL);
@@ -1137,9 +1157,9 @@ inet_getname(struct socket *sock, struct sockaddr *uaddr,
else sin.sin_addr.s_addr = sk->saddr;
}
len = sizeof(sin);
- verify_area(VERIFY_WRITE, uaddr, len);
+/* verify_area(VERIFY_WRITE, uaddr, len); NOW DONE ABOVE */
memcpy_tofs(uaddr, &sin, sizeof(sin));
- verify_area(VERIFY_WRITE, uaddr_len, sizeof(len));
+/* verify_area(VERIFY_WRITE, uaddr_len, sizeof(len)); NOW DONE ABOVE */
put_fs_long(len, uaddr_len);
return(0);
}
@@ -1354,6 +1374,7 @@ static int
inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
{
struct sock *sk;
+ int err;
DPRINTF((DBG_INET, "INET: in inet_ioctl\n"));
sk = NULL;
@@ -1365,13 +1386,18 @@ inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
switch(cmd) {
case FIOSETOWN:
case SIOCSPGRP:
+ err=verify_area(VERIFY_READ,(int *)arg,sizeof(long));
+ if(err)
+ return err;
if (sk)
sk->proc = get_fs_long((int *) arg);
return(0);
case FIOGETOWN:
case SIOCGPGRP:
if (sk) {
- verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
+ err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long));
+ if(err)
+ return err;
put_fs_long(sk->proc,(int *)arg);
}
return(0);
@@ -1412,6 +1438,7 @@ inet_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
case SIOCGIFMTU:
case SIOCSIFMTU:
case SIOCSIFLINK:
+ case SIOCGIFHWADDR:
return(dev_ioctl(cmd,(void *) arg));
default:
@@ -1428,17 +1455,17 @@ sock_wmalloc(struct sock *sk, unsigned long size, int force,
int priority)
{
if (sk) {
- if (sk->wmem_alloc + size < SK_WMEM_MAX || force) {
+ if (sk->wmem_alloc + size < sk->sndbuf || force) {
cli();
sk->wmem_alloc+= size;
sti();
- return(kmalloc(size, priority));
+ return(alloc_skb(size, priority));
}
DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n",
sk, size, force, priority));
return(NULL);
}
- return(kmalloc(size, priority));
+ return(alloc_skb(size, priority));
}
@@ -1446,8 +1473,8 @@ void *
sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
{
if (sk) {
- if (sk->rmem_alloc + size < SK_RMEM_MAX || force) {
- void *c = kmalloc(size, priority);
+ if (sk->rmem_alloc + size < sk->rcvbuf || force) {
+ void *c = alloc_skb(size, priority);
cli();
if (c) sk->rmem_alloc += size;
sti();
@@ -1457,7 +1484,7 @@ sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority)
sk,size,force, priority));
return(NULL);
}
- return(kmalloc(size, priority));
+ return(alloc_skb(size, priority));
}
@@ -1467,8 +1494,8 @@ sock_rspace(struct sock *sk)
int amt;
if (sk != NULL) {
- if (sk->rmem_alloc >= SK_RMEM_MAX-2*MIN_WINDOW) return(0);
- amt = min((SK_RMEM_MAX-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
+ if (sk->rmem_alloc >= sk->rcvbuf-2*MIN_WINDOW) return(0);
+ amt = min((sk->rcvbuf-sk->rmem_alloc)/2-MIN_WINDOW, MAX_WINDOW);
if (amt < 0) return(0);
return(amt);
}
@@ -1481,8 +1508,8 @@ sock_wspace(struct sock *sk)
{
if (sk != NULL) {
if (sk->shutdown & SEND_SHUTDOWN) return(0);
- if (sk->wmem_alloc >= SK_WMEM_MAX) return(0);
- return(SK_WMEM_MAX-sk->wmem_alloc );
+ if (sk->wmem_alloc >= sk->sndbuf) return(0);
+ return(sk->sndbuf-sk->wmem_alloc );
}
return(0);
}
@@ -1493,7 +1520,8 @@ sock_wfree(struct sock *sk, void *mem, unsigned long size)
{
DPRINTF((DBG_INET, "sock_wfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
- kfree_s(mem, size);
+ IS_SKB(mem);
+ kfree_skbmem(mem, size);
if (sk) {
sk->wmem_alloc -= size;
@@ -1501,9 +1529,7 @@ sock_wfree(struct sock *sk, void *mem, unsigned long size)
if (!sk->dead) wake_up(sk->sleep);
if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) {
DPRINTF((DBG_INET,
- "recovered lost memory, destroying sock = %X\n", sk));
- delete_timer(sk);
- kfree_s((void *)sk, sizeof(*sk));
+ "recovered lost memory, sock = %X\n", sk));
}
return;
}
@@ -1514,13 +1540,13 @@ void
sock_rfree(struct sock *sk, void *mem, unsigned long size)
{
DPRINTF((DBG_INET, "sock_rfree(sk=%X, mem=%X, size=%d)\n", sk, mem, size));
-
- kfree_s(mem, size);
+ IS_SKB(mem);
+ kfree_skbmem(mem, size);
if (sk) {
sk->rmem_alloc -= size;
if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) {
- delete_timer(sk);
- kfree_s((void *)sk, sizeof(*sk));
+ DPRINTF((DBG_INET,
+ "recovered lot memory, sock = %X\n", sk));
}
}
}
@@ -1550,18 +1576,21 @@ struct sock *get_sock(struct proto *prot, unsigned short num,
* socket number when we choose an arbitrary one.
*/
for(s = prot->sock_array[hnum & (SOCK_ARRAY_SIZE - 1)];
- s != NULL; s = s->next) {
- if (s->num == hnum) {
- /* We need to see if this is the socket that we want. */
- if (ip_addr_match(s->daddr, raddr) == 0) continue;
- if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0) continue;
-#if 1 /* C.E. Hawkins ceh@eng.cam.ac.uk */
- if (s->prot != &udp_prot || prot != &udp_prot)
-#endif
- if (ip_addr_match(s->saddr, laddr) == 0) continue;
- if (s->dead && (s->state == TCP_CLOSE)) continue;
- return(s);
- }
+ s != NULL; s = s->next)
+ {
+ if (s->num != hnum)
+ continue;
+ if(s->dead && (s->state == TCP_CLOSE))
+ continue;
+ if(prot == &udp_prot)
+ return s;
+ if(ip_addr_match(s->daddr,raddr)==0)
+ continue;
+ if (s->dummy_th.dest != rnum && s->dummy_th.dest != 0)
+ continue;
+ if(ip_addr_match(s->saddr,laddr) == 0)
+ continue;
+ return(s);
}
return(NULL);
}
@@ -1697,6 +1726,7 @@ void inet_proto_init(struct ddi_proto *pro)
struct inet_protocol *p;
int i;
+ printk("Swansea University Computer Society Net2Debugged [1.22]\n");
/* Set up our UNIX VFS major device. */
if (register_chrdev(AF_INET_MAJOR, "af_inet", &inet_fops) < 0) {
printk("%s: cannot register major device %d!\n",
@@ -1715,11 +1745,13 @@ void inet_proto_init(struct ddi_proto *pro)
udp_prot.sock_array[i] = NULL;
raw_prot.sock_array[i] = NULL;
}
+ printk("IP Protocols: ");
for(p = inet_protocol_base; p != NULL;) {
struct inet_protocol *tmp;
tmp = (struct inet_protocol *) p->next;
inet_add_protocol(p);
+ printk("%s%s ",p->name,tmp?",":"\n");
p = tmp;
}
diff --git a/net/inet/sock.h b/net/inet/sock.h
index 1d0ebb3..bb3eeec 100644
--- a/net/inet/sock.h
+++ b/net/inet/sock.h
@@ -12,6 +12,16 @@
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Florian La Roche <flla@stud.uni-sb.de>
*
+ * Fixes:
+ * Alan Cox : Volatiles in skbuff pointers. See
+ * skbuff comments. May be overdone,
+ * better to prove they can be removed
+ * than the reverse.
+ * Alan Cox : Added a zapped field for tcp to note
+ * a socket is reset and must stay shut up
+ * Alan Cox : New fields for options
+ * Pauline Middelink : identd support
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -63,7 +73,9 @@ struct sock {
destroy,
ack_timed,
no_check,
- exp_growth;
+ exp_growth,
+ zapped, /* In ipx means not linked */
+ broadcast;
int proc;
struct sock *next;
struct sock *pair;
@@ -98,11 +110,18 @@ struct sock {
volatile unsigned char ack_backlog;
unsigned char max_ack_backlog;
unsigned char priority;
+ unsigned char debug;
+ unsigned short rcvbuf;
+ unsigned short sndbuf;
+ unsigned short type; /* IPX type field */
struct tcphdr dummy_th;
/* This part is used for the timeout functions (timer.c). */
int timeout; /* What are we waiting for? */
struct timer_list timer;
+
+ /* identd */
+ struct socket *socket;
};
struct proto {
@@ -168,8 +187,8 @@ struct proto {
#define TIME_DONE 5 /* used to absorb those last few packets */
#define SOCK_DESTROY_TIME 1000 /* about 10 seconds */
+#define PROT_SOCK 1024 /* Sockets 0-1023 can't be bound too unless you are superuser */
-#define PROT_SOCK 1024
#define SHUTDOWN_MASK 3
#define RCV_SHUTDOWN 1
#define SEND_SHUTDOWN 2
diff --git a/net/inet/tcp.c b/net/inet/tcp.c
index 479d6a4..04701ad 100644
--- a/net/inet/tcp.c
+++ b/net/inet/tcp.c
@@ -13,6 +13,44 @@
* Corey Minyard <wf-rch!minyard@relay.EU.net>
* Florian La Roche, <flla@stud.uni-sb.de>
*
+ * Fixes:
+ * Alan Cox : Numerous verify_area() calls
+ * Alan Cox : Set the ACK bit on a reset
+ * Alan Cox : Stopped it crashing if it closed while sk->inuse=1
+ * and was trying to connect (tcp_err()).
+ * Alan Cox : All icmp error handling was broken
+ * pointers passed where wrong and the
+ * socket was looked up backwards. Nobody
+ * tested any icmp error code obviously.
+ * Alan Cox : tcp_err() now handled properly. It wakes people
+ * on errors. select behaves and the icmp error race
+ * has gone by moving it into sock.c
+ * Alan Cox : tcp_reset() fixed to work for everything not just
+ * packets for unknown sockets.
+ * Alan Cox : tcp option processing.
+ * Alan Cox : Reset tweaked (still not 100%) [Had syn rule wrong]
+ * Herp Rosmanith : More reset fixes
+ * Alan Cox : No longer acks invalid rst frames. Acking
+ * any kind of RST is right out.
+ * Alan Cox : Sets an ignore me flag on an rst receive
+ * otherwise odd bits of prattle escape still
+ * Alan Cox : Fixed another acking RST frame bug. Should stop
+ * LAN workplace lockups.
+ * Alan Cox : Some tidyups using the new skb list facilities
+ *
+ *
+ * To Fix:
+ * Possibly a problem with accept(). BSD accept never fails after
+ * it causes a select. Linux can - given the official select semantics I
+ * feel that _really_ its the BSD network programs that are bust (notably
+ * inetd, which hangs occasionally because of this).
+ * Proper processing of piggybacked data on connect.
+ * Add VJ Fastrecovery algorithm ?
+ * Protocol closedown badly messed up.
+ * Incompatiblity with spider ports (tcp hangs on that
+ * socket occasionally).
+ * MSG_PEEK and read on same socket at once can cause crashes.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -79,18 +117,7 @@ print_th(struct tcphdr *th)
static struct sk_buff *
get_firstr(struct sock *sk)
{
- struct sk_buff *skb;
-
- skb = sk->rqueue;
- if (skb == NULL) return(NULL);
- sk->rqueue =(struct sk_buff *)skb->next;
- if (sk->rqueue == skb) {
- sk->rqueue = NULL;
- } else {
- sk->rqueue->prev = skb->prev;
- sk->rqueue->prev->next = sk->rqueue;
- }
- return(skb);
+ return skb_dequeue(&sk->rqueue);
}
@@ -140,7 +167,7 @@ tcp_retransmit(struct sock *sk, int all)
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
* be closed and the error returned to the user. If err > 0
- * it's just the icmp type << 8 | icmp code.
+ * it's just the icmp type << 8 | icmp code. After adjustment
* header points to the first 8 bytes of the tcp header. We need
* to find the appropriate port.
*/
@@ -150,15 +177,25 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
{
struct tcphdr *th;
struct sock *sk;
+ struct iphdr *iph=(struct iphdr *)header;
+
+ header+=4*iph->ihl;
DPRINTF((DBG_TCP, "TCP: tcp_err(%d, hdr=%X, daddr=%X saddr=%X, protocol=%X)\n",
err, header, daddr, saddr, protocol));
th =(struct tcphdr *)header;
- sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
+ sk = get_sock(&tcp_prot, th->source/*dest*/, daddr, th->dest/*source*/, saddr);
print_th(th);
if (sk == NULL) return;
+
+ if(err<0)
+ {
+ sk->err = -err;
+ wake_up(sk->sleep);
+ return;
+ }
if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) {
/*
@@ -180,7 +217,7 @@ tcp_err(int err, unsigned char *header, unsigned long daddr,
if (icmp_err_convert[err & 0xff].fatal) {
if (sk->state == TCP_SYN_SENT) {
sk->state = TCP_CLOSE;
- sk->prot->close(sk, 0);
+ wake_up(sk->sleep); /* Wake people up to see the error (see connect in sock.c) */
}
}
return;
@@ -198,7 +235,8 @@ tcp_readable(struct sock *sk)
DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk));
- if (sk == NULL || sk->rqueue == NULL) return(0);
+ if (sk == NULL || sk->rqueue == NULL)
+ return(0);
counted = sk->copied_seq+1;
amount = 0;
@@ -247,6 +285,11 @@ tcp_select(struct sock *sk, int sel_type, select_table *wait)
return(1);
}
}
+ if (sk->err != 0) /* Receiver error */
+ {
+ release_sock(sk);
+ return(1);
+ }
if (sk->shutdown & RCV_SHUTDOWN) {
release_sock(sk);
return(1);
@@ -306,6 +349,7 @@ tcp_select(struct sock *sk, int sel_type, select_table *wait)
int
tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
{
+ int err;
DPRINTF((DBG_TCP, "tcp_ioctl(sk=%X, cmd = %d, arg=%X)\n", sk, cmd, arg));
switch(cmd) {
case DDIOCSDBG:
@@ -327,8 +371,10 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
release_sock(sk);
DPRINTF((DBG_TCP, "returning %d\n", amount));
- verify_area(VERIFY_WRITE,(void *)arg,
+ err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
+ if(err)
+ return err;
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
@@ -348,8 +394,10 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
skb->h.th->urg) answ = 1;
}
release_sock(sk);
- verify_area(VERIFY_WRITE,(void *) arg,
+ err=verify_area(VERIFY_WRITE,(void *) arg,
sizeof(unsigned long));
+ if(err)
+ return err;
put_fs_long(answ,(int *) arg);
return(0);
}
@@ -359,8 +407,10 @@ tcp_ioctl(struct sock *sk, int cmd, unsigned long arg)
if (sk->state == TCP_LISTEN) return(-EINVAL);
amount = sk->prot->wspace(sk)/2;
- verify_area(VERIFY_WRITE,(void *)arg,
+ err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
+ if(err)
+ return err;
put_fs_long(amount,(unsigned long *)arg);
return(0);
}
@@ -438,7 +488,6 @@ tcp_send_check(struct tcphdr *th, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
th->check = 0;
- if (sk && sk->no_check) return;
th->check = tcp_check(th, len, saddr, daddr);
return;
}
@@ -491,6 +540,8 @@ tcp_send_ack(unsigned long sequence, unsigned long ack,
struct device *dev = NULL;
int tmp;
+ if(sk->zapped)
+ return; /* We have been reset, we may not send again */
/*
* We need to grab some memory, and put together an ack,
* and then put it into the queue to be sent.
@@ -508,7 +559,6 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
buff->mem_addr = buff;
buff->mem_len = MAX_ACK_SIZE;
- buff->lock = 0;
buff->len = sizeof(struct tcphdr);
buff->sk = sk;
t1 =(struct tcphdr *)(buff + 1);
@@ -517,6 +567,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n");
tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev,
IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
if (tmp < 0) {
+ buff->free=1;
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
return;
@@ -546,7 +597,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_ack: build_header failed\n");
sk->bytes_rcv = 0;
sk->ack_timed = 0;
if (sk->send_head == NULL && sk->wfront == NULL) {
- delete_timer(sk);
+/* delete_timer(sk);*/
}
}
t1->ack_seq = ntohl(ack);
@@ -600,9 +651,11 @@ tcp_write(struct sock *sk, unsigned char *from,
DPRINTF((DBG_TCP, "tcp_write(sk=%X, from=%X, len=%d, nonblock=%d, flags=%X)\n",
sk, from, len, nonblock, flags));
+ sk->inuse=1;
prot = sk->prot;
while(len > 0) {
if (sk->err) {
+ release_sock(sk);
if (copied) return(copied);
tmp = -sk->err;
sk->err = 0;
@@ -610,7 +663,6 @@ tcp_write(struct sock *sk, unsigned char *from,
}
/* First thing we do is make sure that we are established. */
- sk->inuse = 1; /* no one else will use this socket.*/
if (sk->shutdown & SEND_SHUTDOWN) {
release_sock(sk);
sk->err = EPIPE;
@@ -621,6 +673,7 @@ tcp_write(struct sock *sk, unsigned char *from,
while(sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) {
if (sk->err) {
+ release_sock(sk);
if (copied) return(copied);
tmp = -sk->err;
sk->err = 0;
@@ -750,9 +803,8 @@ tcp_write(struct sock *sk, unsigned char *from,
/* FIXME: here is another race condition. */
tmp = sk->wmem_alloc;
release_sock(sk);
-
- /* Again we will try to avoid it. */
cli();
+ /* Again we will try to avoid it. */
if (tmp <= sk->wmem_alloc &&
(sk->state == TCP_ESTABLISHED||sk->state == TCP_CLOSE_WAIT)
&& sk->err == 0) {
@@ -772,7 +824,6 @@ tcp_write(struct sock *sk, unsigned char *from,
skb->mem_addr = skb;
skb->len = 0;
skb->sk = sk;
- skb->lock = 0;
skb->free = 0;
buff =(unsigned char *)(skb+1);
@@ -894,7 +945,6 @@ tcp_read_wakeup(struct sock *sk)
buff->mem_addr = buff;
buff->mem_len = MAX_ACK_SIZE;
- buff->lock = 0;
buff->len = sizeof(struct tcphdr);
buff->sk = sk;
@@ -902,6 +952,7 @@ tcp_read_wakeup(struct sock *sk)
tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev,
IPPROTO_TCP, sk->opt, MAX_ACK_SIZE);
if (tmp < 0) {
+ buff->free=1;
sk->prot->wfree(sk, buff->mem_addr, buff->mem_len);
return;
}
@@ -942,7 +993,7 @@ cleanup_rbuf(struct sock *sk)
DPRINTF((DBG_TCP, "cleaning rbuf for sk=%X\n", sk));
left = sk->prot->rspace(sk);
-
+
/*
* We have to loop through all the buffer headers,
* and try to free up all the space we can.
@@ -1069,9 +1120,12 @@ tcp_read_urg(struct sock * sk, int nonblock,
skb->h.th->urg_ptr = ntohs(skb->len);
}
amt = min(ntohs(skb->h.th->urg_ptr),len);
- verify_area(VERIFY_WRITE, to, amt);
- memcpy_tofs(to,(unsigned char *)(skb->h.th) +
+ if(amt)
+ {
+ verify_area(VERIFY_WRITE, to, amt);
+ memcpy_tofs(to,(unsigned char *)(skb->h.th) +
skb->h.th->doff*4, amt);
+ }
if (!(flags & MSG_PEEK)) {
skb->urg_used = 1;
@@ -1099,12 +1153,17 @@ tcp_read(struct sock *sk, unsigned char *to,
struct sk_buff *skb;
unsigned long offset;
unsigned long used;
+ int err;
if (len == 0) return(0);
if (len < 0) {
return(-EINVAL);
}
+ err=verify_area(VERIFY_WRITE,to,len);
+ if(err)
+ return err;
+
/* This error should be checked. */
if (sk->state == TCP_LISTEN) return(-ENOTCONN);
@@ -1219,7 +1278,7 @@ tcp_read(struct sock *sk, unsigned char *to,
* to go into the user buffer.
*/
offset = sk->copied_seq+1 - skb->h.th->seq;
-
+
if (skb->h.th->syn) offset--;
if (offset < skb->len) {
/*
@@ -1243,7 +1302,7 @@ tcp_read(struct sock *sk, unsigned char *to,
}
}
used = min(skb->len - offset, len);
- verify_area(VERIFY_WRITE, to, used);
+/* verify_area(VERIFY_WRITE, to, used); */
memcpy_tofs(to,((unsigned char *)skb->h.th) +
skb->h.th->doff*4 + offset, used);
copied += used;
@@ -1318,7 +1377,6 @@ tcp_shutdown(struct sock *sk, int how)
DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff));
buff->mem_addr = buff;
buff->mem_len = MAX_RESET_SIZE;
- buff->lock = 0;
buff->sk = sk;
buff->len = sizeof(*t1);
t1 =(struct tcphdr *)(buff + 1);
@@ -1376,17 +1434,31 @@ tcp_recvfrom(struct sock *sk, unsigned char *to,
{
struct sockaddr_in sin;
int len;
- int result = tcp_read(sk, to, to_len, nonblock, flags);
+ int err;
+ int result;
+
+ /* Have to check these first unlike the old code. If
+ we check them after we lose data on an error
+ which is wrong */
+ err = verify_area(VERIFY_WRITE,addr_len,sizeof(long));
+ if(err)
+ return err;
+ len = get_fs_long(addr_len);
+ if(len > sizeof(sin))
+ len = sizeof(sin);
+ err=verify_area(VERIFY_WRITE, addr, len);
+ if(err)
+ return err;
+
+ result=tcp_read(sk, to, to_len, nonblock, flags);
if (result < 0) return(result);
- len = get_fs_long(addr_len);
- if (len > sizeof(sin)) len = sizeof(sin);
+
sin.sin_family = AF_INET;
sin.sin_port = sk->dummy_th.dest;
sin.sin_addr.s_addr = sk->daddr;
- verify_area(VERIFY_WRITE, addr, len);
+
memcpy_tofs(addr, &sin, len);
- verify_area(VERIFY_WRITE, addr_len, sizeof(len));
put_fs_long(len, addr_len);
return(result);
}
@@ -1406,12 +1478,12 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
* and then put it into the queue to be sent.
*/
buff = (struct sk_buff *) prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC);
- if (buff == NULL) return;
+ if (buff == NULL)
+ return;
DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff));
buff->mem_addr = buff;
buff->mem_len = MAX_RESET_SIZE;
- buff->lock = 0;
buff->len = sizeof(*t1);
buff->sk = NULL;
buff->dev = dev;
@@ -1422,6 +1494,7 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt,
sizeof(struct tcphdr));
if (tmp < 0) {
+ buff->free = 1;
prot->wfree(NULL, buff->mem_addr, buff->mem_len);
return;
}
@@ -1429,15 +1502,28 @@ tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th,
buff->len += tmp;
memcpy(t1, th, sizeof(*t1));
- /* Wwap the send and the receive. */
+ /* Swap the send and the receive. */
t1->dest = th->source;
t1->source = th->dest;
- t1->seq = th->ack_seq; /* add one so it will be in the right range */
- t1->ack_seq = htonl(ntohl(th->seq)+1);
- t1->rst = 1;
- t1->ack_seq = htonl(ntohl(th->seq)+1); /* send correct ack -FB */
- t1->window = 0; /* should be set to 0 -FB */
- t1->ack = 1;
+ t1->rst = 1;
+ t1->window = 0;
+
+ if(th->ack)
+ {
+ t1->ack=0;
+ t1->seq=th->ack_seq;
+ t1->ack_seq=0;
+ }
+ else
+ {
+ t1->ack=1;
+ if(!th->syn)
+ t1->ack_seq=htonl(th->seq);
+ else
+ t1->ack_seq=htonl(th->seq+1);
+ t1->seq=0;
+ }
+
t1->syn = 0;
t1->urg = 0;
t1->fin = 0;
@@ -1584,7 +1670,6 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
return;
}
- buff->lock = 0;
buff->mem_addr = buff;
buff->mem_len = MAX_SYN_SIZE;
buff->len = sizeof(struct tcphdr)+4;
@@ -1599,7 +1684,8 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
/* Something went wrong. */
if (tmp < 0) {
sk->err = tmp;
- sk->prot->wfree(newsk, buff->mem_addr, buff->mem_len);
+ buff->free=1;
+ kfree_skb(buff,FREE_WRITE);
newsk->dead = 1;
release_sock(newsk);
skb->sk = sk;
@@ -1645,6 +1731,8 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
sk->rmem_alloc -= skb->mem_len;
newsk->rmem_alloc += skb->mem_len;
+ skb_queue_tail(&sk->rqueue,skb);
+#ifdef OLDWAY
if (sk->rqueue == NULL) {
skb->next = skb;
skb->prev = skb;
@@ -1655,6 +1743,7 @@ tcp_conn_request(struct sock *sk, struct sk_buff *skb,
sk->rqueue->prev = skb;
skb->prev->next = skb;
}
+#endif
sk->ack_backlog++;
release_sock(newsk);
}
@@ -1693,7 +1782,7 @@ tcp_close(struct sock *sk, int timeout)
if (skb->len > 0 &&
after(skb->h.th->seq + skb->len + 1, sk->copied_seq))
need_reset = 1;
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb, FREE_WRITE);
skb = skb2;
} while(skb != sk->rqueue);
}
@@ -1740,10 +1829,10 @@ tcp_close(struct sock *sk, int timeout)
reset_timer(sk, TIME_CLOSE, 100);
return;
}
- buff->lock = 0;
buff->mem_addr = buff;
buff->mem_len = MAX_FIN_SIZE;
buff->sk = sk;
+ buff->free = 1;
buff->len = sizeof(*t1);
t1 =(struct tcphdr *)(buff + 1);
@@ -1752,7 +1841,7 @@ tcp_close(struct sock *sk, int timeout)
IPPROTO_TCP, sk->opt,
sizeof(struct tcphdr));
if (tmp < 0) {
- prot->wfree(sk,buff->mem_addr, buff->mem_len);
+ kfree_skb(buff,FREE_WRITE);
DPRINTF((DBG_TCP, "Unable to build header for fin.\n"));
release_sock(sk);
return;
@@ -1811,16 +1900,23 @@ tcp_write_xmit(struct sock *sk)
struct sk_buff *skb;
DPRINTF((DBG_TCP, "tcp_write_xmit(sk=%X)\n", sk));
+
+ /* The bytes will have to remain here. In time closedown will
+ empty the write queue and all will be happy */
+ if(sk->zapped)
+ return;
+
while(sk->wfront != NULL &&
before(sk->wfront->h.seq, sk->window_seq) &&
sk->packets_out < sk->cong_window) {
skb = sk->wfront;
+ IS_SKB(skb);
sk->wfront =(struct sk_buff *)skb->next;
if (sk->wfront == NULL) sk->wback = NULL;
skb->next = NULL;
if (skb->magic != TCP_WRITE_QUEUE_MAGIC) {
- DPRINTF((DBG_TCP, "tcp.c skb with bad magic(%X) on write queue. Squashing "
- "queue\n", skb->magic));
+ printk("tcp.c skb with bad magic(%X) on write queue. Squashing "
+ "queue\n", skb->magic);
sk->wfront = NULL;
sk->wback = NULL;
return;
@@ -1879,6 +1975,9 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
unsigned long ack;
int flag = 0;
+ if(sk->zapped)
+ return(1); /* Dead, cant ack any more so why bother */
+
ack = ntohl(th->ack_seq);
DPRINTF((DBG_TCP, "tcp_ack ack=%d, window=%d, "
"sk->rcv_ack_seq=%d, sk->window_seq = %d\n",
@@ -2038,12 +2137,16 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
cli();
oskb = sk->send_head;
+ IS_SKB(oskb);
sk->send_head =(struct sk_buff *)oskb->link3;
if (sk->send_head == NULL) {
sk->send_tail = NULL;
}
- /* We may need to remove this from the dev send list. */
+ /* We may need to remove this from the dev send list. */
+#ifndef OLDWAY
+ skb_unlink(oskb); /* Much easier! */
+#else
if (oskb->next != NULL) {
int i;
@@ -2065,6 +2168,7 @@ tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len)
else arp_q =(struct sk_buff *)oskb->next;
}
}
+#endif
sti();
oskb->magic = 0;
kfree_skb(oskb, FREE_WRITE); /* write. */
@@ -2166,7 +2270,7 @@ tcp_data(struct sk_buff *skb, struct sock *sk,
sk->bytes_rcv += skb->len;
if (skb->len == 0 && !th->fin && !th->urg && !th->psh) {
- /* Don't want to keep passing ack's back and fourth. */
+ /* Don't want to keep passing ack's back and forth. */
if (!th->ack) tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr);
kfree_skb(skb, FREE_READ);
return(0);
@@ -2484,11 +2588,15 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
unsigned char *ptr;
int tmp;
struct tcphdr *t1;
+ int err;
if (sk->state != TCP_CLOSE) return(-EISCONN);
if (addr_len < 8) return(-EINVAL);
- /* verify_area(VERIFY_WRITE, usin, addr_len);*/
+ err=verify_area(VERIFY_READ, usin, addr_len);
+ if(err)
+ return err;
+
memcpy_fromfs(&sin,usin, min(sizeof(sin), addr_len));
if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
@@ -2500,6 +2608,7 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n"));
return(-ENETUNREACH);
}
+
sk->inuse = 1;
sk->daddr = sin.sin_addr.s_addr;
sk->send_seq = jiffies * SEQ_TICK - seq_offset;
@@ -2513,7 +2622,6 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
return(-ENOMEM);
}
sk->inuse = 1;
- buff->lock = 0;
buff->mem_addr = buff;
buff->mem_len = MAX_SYN_SIZE;
buff->len = 24;
@@ -2558,12 +2666,12 @@ tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
/* This must go first otherwise a really quick response will get reset. */
sk->state = TCP_SYN_SENT;
-
- sk->prot->queue_xmit(sk, dev, buff, 0);
-
sk->rtt = TCP_CONNECT_TIME;
- reset_timer(sk, TIME_WRITE /* -1 FIXME ??? */, TCP_CONNECT_TIME);
+ reset_timer(sk, TIME_WRITE, TCP_CONNECT_TIME); /* Timer for repeating the SYN until an answer */
sk->retransmits = TCP_RETR2 - TCP_SYN_RETRIES;
+
+ sk->prot->queue_xmit(sk, dev, buff, 0);
+
release_sock(sk);
return(0);
}
@@ -2597,7 +2705,8 @@ tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
* other end know what we expect.
*/
if (after(th->seq, sk->acked_seq + sk->window)) {
- tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
+ if(!th->rst)
+ tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr);
return(0);
}
@@ -2614,18 +2723,56 @@ tcp_sequence(struct sock *sk, struct tcphdr *th, short len,
}
-/* This deals with the tcp option. It isn't very general yet. */
+
+/*
+ * Look for tcp options. Parses everything but only knows about MSS
+ */
+
static void
tcp_options(struct sock *sk, struct tcphdr *th)
{
unsigned char *ptr;
-
+ int length=(th->doff*4)-sizeof(struct tcphdr);
+ int mtuset=0;
+
ptr = (unsigned char *)(th + 1);
- if (ptr[0] != 2 || ptr[1] != 4) {
+
+ while(length>0)
+ {
+ int opcode=*ptr++;
+ int opsize=*ptr++;
+ switch(opcode)
+ {
+ case TCPOPT_EOL:
+ return;
+ case TCPOPT_NOP:
+ length-=2;
+ continue;
+
+ default:
+ if(opsize<=2) /* Avoid silly options looping forever */
+ return;
+ switch(opcode)
+ {
+ case TCPOPT_MSS:
+ if(opsize==4)
+ {
+ sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr));
+ mtuset=1;
+ }
+ break;
+ /* Add other options here as people feel the urge to implement stuff like large windows */
+ }
+ ptr+=opsize-2;
+ length-=opsize;
+ }
+ }
+
+ if (!mtuset)
+ {
sk->mtu = min(sk->mtu, 576 - HEADER_SIZE);
return;
}
- sk->mtu = min(sk->mtu, ptr[2]*256 + ptr[3] - HEADER_SIZE);
}
@@ -2661,17 +2808,22 @@ tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
sk = get_sock(&tcp_prot, th->dest, saddr, th->source, daddr);
DPRINTF((DBG_TCP, "<<\n"));
DPRINTF((DBG_TCP, "len = %d, redo = %d, skb=%X\n", len, redo, skb));
+
+ /* If this socket has got a reset its to all intents and purposes
+ really dead */
+ if (sk!=NULL && sk->zapped)
+ sk=NULL;
if (sk) {
DPRINTF((DBG_TCP, "sk = %X:\n", sk));
}
if (!redo) {
- if (th->check && tcp_check(th, len, saddr, daddr )) {
+ if (tcp_check(th, len, saddr, daddr )) {
skb->sk = NULL;
DPRINTF((DBG_TCP, "packet dropped with bad checksum.\n"));
-if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: back checksum\n");
- kfree_skb(skb, 0);
+if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: bad checksum\n");
+ kfree_skb(skb,FREE_READ);
/*
* We don't release the socket because it was
* never marked in use.
@@ -2681,9 +2833,14 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: back checksum\n");
/* See if we know about the socket. */
if (sk == NULL) {
- if (!th->rst) tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
+ if (!th->rst)
+ {
+ th->seq = ntohl(th->seq);
+ /* So reset is always called with th->seq in host order */
+ tcp_reset(daddr, saddr, th, &tcp_prot, opt,dev);
+ }
skb->sk = NULL;
- kfree_skb(skb, 0);
+ kfree_skb(skb, FREE_READ);
return(0);
}
@@ -2729,10 +2886,10 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: back checksum\n");
}
/* Charge the memory to the socket. */
- if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX) {
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
skb->sk = NULL;
DPRINTF((DBG_TCP, "dropping packet due to lack of buffer space.\n"));
- kfree_skb(skb, 0);
+ kfree_skb(skb, FREE_READ);
release_sock(sk);
return(0);
}
@@ -2748,8 +2905,9 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: back checksum\n");
*/
case TCP_LAST_ACK:
if (th->rst) {
+ sk->zapped=1;
sk->err = ECONNRESET;
- sk->state = TCP_CLOSE;
+ sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
if (!sk->dead) {
wake_up(sk->sleep);
@@ -2766,7 +2924,8 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: back checksum\n");
case TCP_TIME_WAIT:
if (!tcp_sequence(sk, th, len, opt, saddr)) {
if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
- tcp_send_ack(sk->send_seq, sk->acked_seq,
+ if(!th->rst)
+ tcp_send_ack(sk->send_seq, sk->acked_seq,
sk, th, saddr);
kfree_skb(skb, FREE_READ);
release_sock(sk);
@@ -2774,6 +2933,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
}
if (th->rst) {
+ sk->zapped=1;
/* This means the thing should really be closed. */
sk->err = ECONNRESET;
@@ -2852,7 +3012,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
if (!th->rst) {
if (!th->ack)
- th->ack_seq = 0;
+ th->ack_seq = 0;
tcp_reset(daddr, saddr, th, sk->prot, opt,dev);
}
kfree_skb(skb, FREE_READ);
@@ -2908,6 +3068,7 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
sk->err = ECONNREFUSED;
sk->state = TCP_CLOSE;
sk->shutdown = SHUTDOWN_MASK;
+ sk->zapped = 1;
if (!sk->dead) {
wake_up(sk->sleep);
}
@@ -2998,10 +3159,10 @@ if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n");
return(0);
}
}
+ if (th->fin) tcp_fin(sk, th, saddr, dev);
if (tcp_data(skb, sk, saddr, len))
- kfree_skb(skb, FREE_READ);
+ kfree_skb(skb, FREE_READ);
- if (th->fin) tcp_fin(sk, th, saddr, dev);
release_sock(sk);
return(0);
}
@@ -3043,12 +3204,14 @@ tcp_write_wakeup(struct sock *sk)
struct device *dev=NULL;
int tmp;
+ if (sk->zapped)
+ return; /* Afer a valid reset we can send no more */
+
if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) return;
buff = (struct sk_buff *) sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC);
if (buff == NULL) return;
- buff->lock = 0;
buff->mem_addr = buff;
buff->mem_len = MAX_ACK_SIZE;
buff->len = sizeof(struct tcphdr);
diff --git a/net/inet/tcp.h b/net/inet/tcp.h
index b567e3c..cb051e4 100644
--- a/net/inet/tcp.h
+++ b/net/inet/tcp.h
@@ -41,7 +41,7 @@
* 90 minutes to time out.
*/
-#define TCP_TIMEOUT_LEN 720000 /* should be about 2 hrs */
+#define TCP_TIMEOUT_LEN 5000 /* should be about 5 mins */
#define TCP_TIMEWAIT_LEN 1000 /* how long to wait to sucessfully
* close the socket, about 60 seconds */
#define TCP_ACK_TIME 3000 /* time to delay before sending an ACK */
@@ -62,6 +62,14 @@
#define TCP_WRITE_QUEUE_MAGIC 0xa5f23477
/*
+ * TCP option
+ */
+
+#define TCPOPT_NOP 1
+#define TCPOPT_EOL 0
+#define TCPOPT_MSS 2
+
+/*
* The next routines deal with comparing 32 bit unsigned ints
* and worry about wraparound. The general strategy is to do a
* normal compare so long as neither of the numbers is within
diff --git a/net/inet/timer.c b/net/inet/timer.c
index 00c524b..f6540a1 100644
--- a/net/inet/timer.c
+++ b/net/inet/timer.c
@@ -13,6 +13,18 @@
* Fred Baumgarten, <dc6iq@insu1.etec.uni-karlsruhe.de>
* Florian La Roche, <flla@stud.uni-sb.de>
*
+ * Fixes:
+ * Alan Cox : To avoid destroying a wait queue as we use it
+ * we defer destruction until the destroy timer goes
+ * off.
+ * Alan Cox : Destroy socket doesnt write a status value to the
+ * socket buffer _AFTER_ freeing it! Also sock ensures
+ * the socket will get removed BEFORE this is called
+ * otherwise if the timer TIME_DESTROY occurs inside
+ * of inet_bh() with this socket being handled it goes
+ * BOOM! Have to stop timer going off if inet_bh is
+ * active or the destroy causes crashes.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -81,7 +93,7 @@ net_timer (unsigned long data)
int why = sk->timeout;
/* timeout is overwritten by 'delete_timer' and 'reset_timer' */
- if (sk->inuse) {
+ if (sk->inuse || in_inet_bh()) {
sk->timer.expires = 10;
add_timer(&sk->timer);
return;
@@ -113,9 +125,16 @@ net_timer (unsigned long data)
/* We've waited for a while for all the memory associated with
* the socket to be freed. We need to print an error message.
*/
- DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk));
- destroy_sock (sk);
- sk->inuse = 0;
+ if(sk->wmem_alloc!=0 || sk->rmem_alloc!=0)
+ {
+ DPRINTF ((DBG_TMR, "possible memory leak. sk = %X\n", sk));
+ sk->wmem_alloc++; /* So it DOESNT go away */
+ destroy_sock (sk);
+ sk->wmem_alloc--; /* Might now have hit 0 - fall through and do it again if so */
+ sk->inuse = 0; /* This will be ok, the destroy won't totally work */
+ }
+ if(sk->wmem_alloc==0 && sk->rmem_alloc==0)
+ destroy_sock(sk); /* Socket gone, DONT update sk->inuse! */
break;
case TIME_CLOSE:
/* We've waited long enough, close the socket. */
diff --git a/net/inet/udp.c b/net/inet/udp.c
index 17c19da..3575bea 100644
--- a/net/inet/udp.c
+++ b/net/inet/udp.c
@@ -10,11 +10,36 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : verify_area() calls
+ * Alan Cox : stopped close while in use off icmp
+ * messages. Not a fix but a botch that
+ * for udp at least is 'valid'.
+ * Alan Cox : Fixed icmp handling properly
+ * Alan Cox : Correct error for oversized datagrams
+ * Alan Cox : Tidied select() semantics.
+ * Alan Cox : udp_err() fixed properly, also now
+ * select and read wake correctly on errors
+ * Alan Cox : udp_send verify_area moved to avoid mem leak
+ * Alan Cox : UDP can count its memory
+ * Alan Cox : send to an uknown connection causes
+ * an ECONNREFUSED off the icmp, but
+ * does NOT close.
+ * Alan Cox : Switched to new sk_buff handlers. No more backlog!
+ * Alan Cox : Using generic datagram code. Even smaller and the PEEK
+ * bug no longer crashes it.
+ * Fred Van Kempen : Net2e support for sk->broadcast.
+ *
+ * To Do:
+ * Verify all the error codes from UDP operations match the
+ * BSD behaviour, since thats effectively the formal spec.
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
* 2 of the License, or (at your option) any later version.
*/
+
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/types.h>
@@ -55,37 +80,14 @@ print_udp(struct udphdr *uh)
}
-int
-udp_select(struct sock *sk, int sel_type, select_table *wait)
-{
- select_wait(sk->sleep, wait);
- switch(sel_type) {
- case SEL_IN:
- if (sk->rqueue != NULL) {
- return(1);
- }
- return(0);
-
- case SEL_OUT:
- if (sk->prot->wspace(sk) >= MIN_WRITE_SPACE) {
- return(1);
- }
- return(0);
-
- case SEL_EX:
- if (sk->err) return(1); /* can this ever happen? */
- return(0);
- }
- return(0);
-}
-
-
/*
* This routine is called by the ICMP module when it gets some
* sort of error condition. If err < 0 then the socket should
* be closed and the error returned to the user. If err > 0
* it's just the icmp type << 8 | icmp code.
- * header points to the first 8 bytes of the tcp header. We need
+ * Header points to the ip header of the error packet. We move
+ * on past this. Then (as it used to claim before adjustment)
+ * header points to the first 8 bytes of the udp header. We need
* to find the appropriate port.
*/
void
@@ -94,17 +96,30 @@ udp_err(int err, unsigned char *header, unsigned long daddr,
{
struct udphdr *th;
struct sock *sk;
+ struct iphdr *ip=(struct iphdr *)header;
+
+ header += 4*ip->ihl;
+
+ th = (struct udphdr *)header;
- DPRINTF((DBG_UDP,
- "UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n",
- err, header, daddr, saddr, protocol));
+ DPRINTF((DBG_UDP,"UDP: err(err=%d, header=%X, daddr=%X, saddr=%X, protocl=%X)\n\
+sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest));
- th = (struct udphdr *)header;
- sk = get_sock(&udp_prot, th->dest, saddr, th->source, daddr);
+ sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr);
- if (sk == NULL) return;
- if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) {
- if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2;
+ if (sk == NULL)
+ return; /* No socket for error */
+
+ if (err < 0) /* As per the calling spec */
+ {
+ sk->err = -err;
+ wake_up(sk->sleep); /* User process wakes to see error */
+ return;
+ }
+
+ if (err & 0xff00 ==(ICMP_SOURCE_QUENCH << 8)) { /* Slow down! */
+ if (sk->cong_window > 1)
+ sk->cong_window = sk->cong_window/2;
return;
}
@@ -112,8 +127,9 @@ udp_err(int err, unsigned char *header, unsigned long daddr,
/* It's only fatal if we have connected to them. */
if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) {
- sk->prot->close(sk, 0);
+ sk->err=ECONNREFUSED;
}
+ wake_up(sk->sleep);
}
@@ -187,8 +203,10 @@ udp_send_check(struct udphdr *uh, unsigned long saddr,
unsigned long daddr, int len, struct sock *sk)
{
uh->check = 0;
- if (sk && sk->no_check) return;
+ if (sk && sk->no_check)
+ return;
uh->check = udp_check(uh, len, saddr, daddr);
+ if (uh->check == 0) uh->check = 0xffff;
}
@@ -208,15 +226,18 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
in_ntoa(sin->sin_addr.s_addr), ntohs(sin->sin_port),
from, len));
+ err=verify_area(VERIFY_READ, from, len);
+ if(err)
+ return(err);
+
/* Allocate a copy of the packet. */
size = sizeof(struct sk_buff) + sk->prot->max_header + len;
skb = (struct sk_buff *) sk->prot->wmalloc(sk, size, 0, GFP_KERNEL);
if (skb == NULL) return(-ENOMEM);
- skb->lock = 0;
skb->mem_addr = skb;
skb->mem_len = size;
- skb->sk = NULL;
+ skb->sk = NULL; /* to avoid changing sk->saddr */
skb->free = 1;
skb->arp = 0;
@@ -228,6 +249,8 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
saddr, sin->sin_addr.s_addr, dev, IPPROTO_UDP, skb->mem_len));
tmp = sk->prot->build_header(skb, saddr, sin->sin_addr.s_addr,
&dev, IPPROTO_UDP, sk->opt, skb->mem_len);
+ skb->sk=sk; /* So memory is freed correctly */
+
if (tmp < 0 ) {
sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
return(tmp);
@@ -247,7 +270,7 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
if (len > dev->mtu) {
printk("UDP: send: length %d > mtu %d (ignored)\n", len, dev->mtu);
sk->prot->wfree(sk, skb->mem_addr, skb->mem_len);
- return(-EINVAL);
+ return(-EMSGSIZE);
}
/* Fill in the UDP header. */
@@ -258,9 +281,6 @@ udp_send(struct sock *sk, struct sockaddr_in *sin,
buff = (unsigned char *) (uh + 1);
/* Copy the user data. */
- err=verify_area(VERIFY_READ, from, len);
- if(err)
- return(err);
memcpy_fromfs(buff, from, len);
/* Set up the UDP checksum. */
@@ -284,9 +304,12 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
DPRINTF((DBG_UDP, "UDP: sendto(len=%d, flags=%X)\n", len, flags));
/* Check the flags. */
- if (flags) return(-EINVAL);
- if (len < 0) return(-EINVAL);
- if (len == 0) return(0);
+ if (flags)
+ return(-EINVAL);
+ if (len < 0)
+ return(-EINVAL);
+ if (len == 0)
+ return(0);
/* Get and verify the address. */
if (usin) {
@@ -295,14 +318,19 @@ udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock,
if(err)
return err;
memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL);
- if (sin.sin_port == 0) return(-EINVAL);
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EINVAL);
+ if (sin.sin_port == 0)
+ return(-EINVAL);
} else {
if (sk->state != TCP_ESTABLISHED) return(-EINVAL);
sin.sin_family = AF_INET;
sin.sin_port = sk->dummy_th.dest;
sin.sin_addr.s_addr = sk->daddr;
}
+
+ if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -ENETUNREACH; /* Must turn broadcast on first */
sk->inuse = 1;
/* Send the packet. */
@@ -353,7 +381,7 @@ udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
unsigned long amount;
if (sk->state == TCP_LISTEN) return(-EINVAL);
- amount = sk->prot->wspace(sk)/2;
+ amount = sk->prot->wspace(sk)/*/2*/;
err=verify_area(VERIFY_WRITE,(void *)arg,
sizeof(unsigned long));
if(err)
@@ -363,9 +391,6 @@ udp_ioctl(struct sock *sk, int cmd, unsigned long arg)
}
case TIOCINQ:
-#if 0 /* FIXME: */
- case FIONREAD:
-#endif
{
struct sk_buff *skb;
unsigned long amount;
@@ -409,8 +434,6 @@ udp_recvfrom(struct sock *sk, unsigned char *to, int len,
struct sk_buff *skb;
int er;
- if (len == 0) return(0);
- if (len < 0) return(-EINVAL);
/*
* This will pick up errors that occured while the program
@@ -423,6 +446,12 @@ udp_recvfrom(struct sock *sk, unsigned char *to, int len,
sk->err = 0;
return(err);
}
+
+ if (len == 0)
+ return(0);
+ if (len < 0)
+ return(-EINVAL);
+
if (addr_len) {
er=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len));
if(er)
@@ -438,42 +467,11 @@ udp_recvfrom(struct sock *sk, unsigned char *to, int len,
er=verify_area(VERIFY_WRITE,to,len);
if(er)
return er;
- sk->inuse = 1;
- while(sk->rqueue == NULL) {
- if (sk->shutdown & RCV_SHUTDOWN) {
- return(0);
- }
-
- if (noblock) {
- release_sock(sk);
- return(-EAGAIN);
- }
- release_sock(sk);
- cli();
- if (sk->rqueue == NULL) {
- interruptible_sleep_on(sk->sleep);
- if (current->signal & ~current->blocked) {
- return(-ERESTARTSYS);
- }
- }
- sk->inuse = 1;
- sti();
- }
- skb = sk->rqueue;
-
- if (!(flags & MSG_PEEK)) {
- if (skb->next == skb) {
- sk->rqueue = NULL;
- } else {
- sk->rqueue =(struct sk_buff *)sk->rqueue ->next;
- skb->prev->next = skb->next;
- skb->next->prev = skb->prev;
- }
- }
+ skb=skb_recv_datagram(sk,flags,noblock,&er);
+ if(skb==NULL)
+ return er;
copied = min(len, skb->len);
- /* This was checked in the wrong place
- verify_area(VERIFY_WRITE, to, copied);
- */
+ /* FIXME : should use udp header size info value */
memcpy_tofs(to, skb->h.raw + sizeof(struct udphdr), copied);
/* Copy the address. */
@@ -483,16 +481,10 @@ udp_recvfrom(struct sock *sk, unsigned char *to, int len,
addr.sin_family = AF_INET;
addr.sin_port = skb->h.uh->source;
addr.sin_addr.s_addr = skb->daddr;
- /* Also in the wrong place, jumping out here will lose
- a packet for good and leave the socket in use
- now tested above
- verify_area(VERIFY_WRITE, sin, sizeof(*sin));*/
memcpy_tofs(sin, &addr, sizeof(*sin));
}
- if (!(flags & MSG_PEEK)) {
- kfree_skb(skb, FREE_READ);
- }
+ kfree_skb(skb, FREE_READ);
release_sock(sk);
return(copied);
}
@@ -512,14 +504,20 @@ udp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len)
struct sockaddr_in sin;
int er;
- if (addr_len < sizeof(sin)) return(-EINVAL);
+ if (addr_len < sizeof(sin))
+ return(-EINVAL);
er=verify_area(VERIFY_READ, usin, sizeof(sin));
if(er)
return er;
memcpy_fromfs(&sin, usin, sizeof(sin));
- if (sin.sin_family && sin.sin_family != AF_INET) return(-EAFNOSUPPORT);
+ if (sin.sin_family && sin.sin_family != AF_INET)
+ return(-EAFNOSUPPORT);
+
+ if(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST)
+ return -ENETUNREACH; /* Must turn broadcast on first */
+
sk->daddr = sin.sin_addr.s_addr;
sk->dummy_th.dest = sin.sin_port;
sk->state = TCP_ESTABLISHED;
@@ -550,8 +548,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
sk = get_sock(&udp_prot, uh->dest, saddr, uh->source, daddr);
if (sk == NULL) {
if (chk_addr(daddr) == IS_MYADDR)
+ {
icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, dev);
-
+ }
/*
* Hmm. We got an UDP broadcast to a port to which we
* don't wanna listen. The only thing we can do now is
@@ -578,28 +577,10 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
skb->daddr = saddr;
skb->saddr = daddr;
- /* Now deal with the in use. */
- cli();
- if (sk->inuse) {
- if (sk->back_log == NULL) {
- sk->back_log = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- skb->next = sk->back_log;
- skb->prev = sk->back_log->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- }
- sti();
- return(0);
- }
- sk->inuse = 1;
- sti();
}
/* Charge it to the socket. */
- if (sk->rmem_alloc + skb->mem_len >= SK_RMEM_MAX) {
+ if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) {
skb->sk = NULL;
kfree_skb(skb, FREE_WRITE);
release_sock(sk);
@@ -612,16 +593,9 @@ udp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt,
print_udp(uh);
/* Now add it to the data chain and wake things up. */
- if (sk->rqueue == NULL) {
- sk->rqueue = skb;
- skb->next = skb;
- skb->prev = skb;
- } else {
- skb->next = sk->rqueue;
- skb->prev = sk->rqueue->prev;
- skb->prev->next = skb;
- skb->next->prev = skb;
- }
+
+ skb_queue_tail(&sk->rqueue,skb);
+
skb->len = len - sizeof(*uh);
if (!sk->dead) wake_up(sk->sleep);
@@ -651,7 +625,7 @@ struct proto udp_prot = {
NULL,
NULL,
udp_rcv,
- udp_select,
+ datagram_select,
udp_ioctl,
NULL,
NULL,
diff --git a/net/inet/udp.h b/net/inet/udp.h
index b6c72d6..6bfbb3c 100644
--- a/net/inet/udp.h
+++ b/net/inet/udp.h
@@ -10,6 +10,10 @@
* Authors: Ross Biro, <bir7@leland.Stanford.Edu>
* Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : Turned on udp checksums. I don't want to
+ * chase 'memory corruption' bugs that aren't!
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -21,13 +25,12 @@
#include <linux/udp.h>
-#define UDP_NO_CHECK 1
+#define UDP_NO_CHECK 0
extern struct proto udp_prot;
-extern int udp_select(struct sock *sk, int sel_type, select_table *wait);
extern void udp_err(int err, unsigned char *header, unsigned long daddr,
unsigned long saddr, struct inet_protocol *protocol);
extern int udp_recvfrom(struct sock *sk, unsigned char *to,
diff --git a/net/inet/utils.c b/net/inet/utils.c
index 58a6cd7..f9e81e3 100644
--- a/net/inet/utils.c
+++ b/net/inet/utils.c
@@ -10,6 +10,10 @@
*
* Author: Fred N. van Kempen, <waltje@uWalt.NL.Mugnet.ORG>
*
+ * Fixes:
+ * Alan Cox : verify_area check.
+ *
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version
@@ -100,9 +104,12 @@ int
dbg_ioctl(void *arg, int level)
{
int val;
-
+ int err;
+
if (!suser()) return(-EPERM);
- verify_area(VERIFY_WRITE, (void *)arg, sizeof(int));
+ err=verify_area(VERIFY_READ, (void *)arg, sizeof(int));
+ if(err)
+ return err;
val = get_fs_long((int *)arg);
switch(val) {
case 0: /* OFF */
diff --git a/net/socket.c b/net/socket.c
index ed50a10..8c72377 100644
--- a/net/socket.c
+++ b/net/socket.c
@@ -430,7 +430,8 @@ sock_socket(int family, int type, int protocol)
* protocol later.
*/
if ((type != SOCK_STREAM && type != SOCK_DGRAM &&
- type != SOCK_SEQPACKET && type != SOCK_RAW) || protocol < 0)
+ type != SOCK_SEQPACKET && type != SOCK_RAW &&
+ type != SOCK_PACKET) || protocol < 0)
return(-EINVAL);
/*
diff --git a/net/unix/sock.c b/net/unix/sock.c
index 97a9e25..eb82516 100644
--- a/net/unix/sock.c
+++ b/net/unix/sock.c
@@ -32,6 +32,7 @@
#include <linux/net.h>
#include <linux/fs.h>
#include <linux/ddi.h>
+#include <linux/malloc.h>
#include <stdarg.h>
#include "unix.h"
@@ -578,7 +579,7 @@ unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock)
if (avail <= 0) {
printk("UNIX: read: AVAIL IS NEGATIVE!!!\n");
send_sig(SIGKILL, current, 1);
- return(-EINTR);
+ return(-EPIPE);
}
if ((cando = todo) > avail) cando = avail;
@@ -613,7 +614,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
dprintf(1, "UNIX: write: socket not connected\n");
if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1);
- return(-EINTR);
+ return(-EPIPE);
}
return(-EINVAL);
}
@@ -630,7 +631,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if (sock->state == SS_DISCONNECTING) {
dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n");
send_sig(SIGPIPE, current, 1);
- return(-EINTR);
+ return(-EPIPE);
}
}
@@ -644,7 +645,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
if (space <= 0) {
printk("UNIX: write: SPACE IS NEGATIVE!!!\n");
send_sig(SIGKILL, current, 1);
- return(-EINTR);
+ return(-EPIPE);
}
/*
@@ -653,7 +654,7 @@ unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock)
*/
if (sock->state == SS_DISCONNECTING) {
send_sig(SIGPIPE, current, 1);
- return(-EINTR);
+ return(-EPIPE);
}
if ((cando = todo) > space) cando = space;
if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part;
diff --git a/zBoot/head.S b/zBoot/head.S
index 6481069..0a40e8b 100644
--- a/zBoot/head.S
+++ b/zBoot/head.S
@@ -18,7 +18,7 @@
startup_32:
cld
cli
- movl $KERNEL_DS,%eax
+ movl $(KERNEL_DS),%eax
mov %ax,%ds
mov %ax,%es
mov %ax,%fs
@@ -50,4 +50,4 @@ startup_32:
* Do the decompression, and jump to the new kernel..
*/
call _decompress_kernel
- ljmp $KERNEL_CS, $0x100000
+ ljmp $(KERNEL_CS), $0x100000