From 158065d7d0735898ce67b09d8ca1576797aa9fb1 Mon Sep 17 00:00:00 2001 From: ThatLinuxFan <9904667+NodeMixaholic@users.noreply.github.com> Date: Fri, 26 Jan 2024 17:19:05 -0600 Subject: [PATCH] add linux kernel source dependency/ignore compiler --- .gitignore | 1172 +++++ .../opt/cross/share/man/man7/fsf-funding.7 | 189 + .../opt/cross/share/man/man7/gfdl.7 | 647 +++ .../opt/cross/share/man/man7/gpl.7 | 846 ++++ .../source/THIRDPARTY/linux-old/CHANGES | 133 + .../source/THIRDPARTY/linux-old/COPYING | 351 ++ .../source/THIRDPARTY/linux-old/Configure | 242 + .../source/THIRDPARTY/linux-old/Makefile | 296 ++ .../source/THIRDPARTY/linux-old/README | 181 + .../THIRDPARTY/linux-old/boot/bootsect.S | 450 ++ .../source/THIRDPARTY/linux-old/boot/head.S | 354 ++ .../source/THIRDPARTY/linux-old/boot/setup.S | 869 ++++ .../source/THIRDPARTY/linux-old/config.in | 139 + .../linux-old/drivers/FPU-emu/Makefile | 50 + .../linux-old/drivers/FPU-emu/README | 312 ++ .../linux-old/drivers/FPU-emu/control_w.h | 44 + .../linux-old/drivers/FPU-emu/div_small.S | 50 + .../linux-old/drivers/FPU-emu/errors.c | 628 +++ .../linux-old/drivers/FPU-emu/exception.h | 53 + .../linux-old/drivers/FPU-emu/fpu_arith.c | 179 + .../linux-old/drivers/FPU-emu/fpu_asm.h | 30 + .../linux-old/drivers/FPU-emu/fpu_aux.c | 180 + .../linux-old/drivers/FPU-emu/fpu_emu.h | 166 + .../linux-old/drivers/FPU-emu/fpu_entry.c | 622 +++ .../linux-old/drivers/FPU-emu/fpu_etc.c | 127 + .../linux-old/drivers/FPU-emu/fpu_proto.h | 131 + .../linux-old/drivers/FPU-emu/fpu_system.h | 65 + .../linux-old/drivers/FPU-emu/fpu_trig.c | 1741 ++++++++ .../linux-old/drivers/FPU-emu/get_address.c | 197 + .../linux-old/drivers/FPU-emu/load_store.c | 237 + .../linux-old/drivers/FPU-emu/poly_2xm1.c | 85 + .../linux-old/drivers/FPU-emu/poly_atan.c | 204 + .../linux-old/drivers/FPU-emu/poly_div.S | 97 + .../linux-old/drivers/FPU-emu/poly_l2.c | 289 ++ .../linux-old/drivers/FPU-emu/poly_mul64.S | 72 + .../linux-old/drivers/FPU-emu/poly_sin.c | 150 + .../linux-old/drivers/FPU-emu/poly_tan.c | 149 + .../linux-old/drivers/FPU-emu/polynomial.S | 141 + .../linux-old/drivers/FPU-emu/reg_add_sub.c | 318 ++ .../linux-old/drivers/FPU-emu/reg_compare.c | 379 ++ .../linux-old/drivers/FPU-emu/reg_constant.c | 116 + .../linux-old/drivers/FPU-emu/reg_constant.h | 31 + .../linux-old/drivers/FPU-emu/reg_div.S | 251 ++ .../linux-old/drivers/FPU-emu/reg_ld_str.c | 1402 ++++++ .../linux-old/drivers/FPU-emu/reg_mul.c | 106 + .../linux-old/drivers/FPU-emu/reg_norm.S | 150 + .../linux-old/drivers/FPU-emu/reg_round.S | 666 +++ .../linux-old/drivers/FPU-emu/reg_u_add.S | 189 + .../linux-old/drivers/FPU-emu/reg_u_div.S | 477 ++ .../linux-old/drivers/FPU-emu/reg_u_mul.S | 163 + .../linux-old/drivers/FPU-emu/reg_u_sub.S | 292 ++ .../linux-old/drivers/FPU-emu/status_w.h | 65 + .../linux-old/drivers/FPU-emu/version.h | 13 + .../linux-old/drivers/FPU-emu/wm_shrx.S | 208 + .../linux-old/drivers/FPU-emu/wm_sqrt.S | 474 ++ .../THIRDPARTY/linux-old/drivers/Makefile | 49 + .../linux-old/drivers/block/Makefile | 72 + .../linux-old/drivers/block/README.sbpcd | 214 + .../THIRDPARTY/linux-old/drivers/block/blk.h | 310 ++ .../linux-old/drivers/block/cdu31a.c | 1852 ++++++++ .../linux-old/drivers/block/floppy.c | 1387 ++++++ .../linux-old/drivers/block/genhd.c | 216 + .../THIRDPARTY/linux-old/drivers/block/hd.c | 797 ++++ .../linux-old/drivers/block/ll_rw_blk.c | 503 +++ .../THIRDPARTY/linux-old/drivers/block/mcd.c | 1224 +++++ .../linux-old/drivers/block/ramdisk.c | 178 + .../linux-old/drivers/block/sbpcd.c | 2996 +++++++++++++ .../THIRDPARTY/linux-old/drivers/block/xd.c | 638 +++ .../linux-old/drivers/char/Makefile | 87 + .../linux-old/drivers/char/atixlmouse.c | 198 + .../linux-old/drivers/char/busmouse.c | 239 + .../linux-old/drivers/char/console.c | 1951 ++++++++ .../linux-old/drivers/char/defkeymap.c | 399 ++ .../linux-old/drivers/char/defkeymap.map | 321 ++ .../THIRDPARTY/linux-old/drivers/char/diacr.h | 8 + .../linux-old/drivers/char/kbd_kern.h | 107 + .../linux-old/drivers/char/keyboard.c | 870 ++++ .../THIRDPARTY/linux-old/drivers/char/lp.c | 461 ++ .../THIRDPARTY/linux-old/drivers/char/mem.c | 426 ++ .../THIRDPARTY/linux-old/drivers/char/mouse.c | 99 + .../linux-old/drivers/char/msbusmouse.c | 175 + .../THIRDPARTY/linux-old/drivers/char/psaux.c | 552 +++ .../THIRDPARTY/linux-old/drivers/char/pty.c | 114 + .../linux-old/drivers/char/serial.c | 2071 +++++++++ .../linux-old/drivers/char/tpqic02.c | 2622 +++++++++++ .../linux-old/drivers/char/tty_io.c | 1826 ++++++++ .../linux-old/drivers/char/tty_ioctl.c | 657 +++ .../THIRDPARTY/linux-old/drivers/char/vt.c | 591 +++ .../linux-old/drivers/char/vt_kern.h | 23 + .../THIRDPARTY/linux-old/drivers/net/3c501.c | 560 +++ .../THIRDPARTY/linux-old/drivers/net/3c503.c | 442 ++ .../THIRDPARTY/linux-old/drivers/net/3c503.h | 60 + .../THIRDPARTY/linux-old/drivers/net/3c507.c | 898 ++++ .../THIRDPARTY/linux-old/drivers/net/3c509.c | 692 +++ .../THIRDPARTY/linux-old/drivers/net/8390.c | 756 ++++ .../THIRDPARTY/linux-old/drivers/net/8390.h | 159 + .../THIRDPARTY/linux-old/drivers/net/CONFIG | 55 + .../linux-old/drivers/net/LICENSE.SRC | 15 + .../THIRDPARTY/linux-old/drivers/net/Makefile | 150 + .../linux-old/drivers/net/README.DLINK | 177 + .../linux-old/drivers/net/README1.PLIP | 113 + .../linux-old/drivers/net/README2.PLIP | 78 + .../THIRDPARTY/linux-old/drivers/net/Space.c | 267 ++ .../THIRDPARTY/linux-old/drivers/net/at1700.c | 660 +++ .../THIRDPARTY/linux-old/drivers/net/atp.c | 795 ++++ .../THIRDPARTY/linux-old/drivers/net/atp.h | 264 ++ .../linux-old/drivers/net/auto_irq.c | 115 + .../THIRDPARTY/linux-old/drivers/net/d_link.c | 766 ++++ .../linux-old/drivers/net/eexpress.c | 1026 +++++ .../THIRDPARTY/linux-old/drivers/net/hp.c | 328 ++ .../THIRDPARTY/linux-old/drivers/net/iow.h | 6 + .../THIRDPARTY/linux-old/drivers/net/lance.c | 844 ++++ .../THIRDPARTY/linux-old/drivers/net/ne.c | 422 ++ .../linux-old/drivers/net/net_init.c | 163 + .../THIRDPARTY/linux-old/drivers/net/plip.c | 835 ++++ .../linux-old/drivers/net/skeleton.c | 520 +++ .../THIRDPARTY/linux-old/drivers/net/slhc.c | 725 +++ .../THIRDPARTY/linux-old/drivers/net/slhc.h | 187 + .../THIRDPARTY/linux-old/drivers/net/slip.c | 1196 +++++ .../THIRDPARTY/linux-old/drivers/net/slip.h | 83 + .../linux-old/drivers/net/smc-ultra.c | 268 ++ .../THIRDPARTY/linux-old/drivers/net/wd.c | 369 ++ .../linux-old/drivers/scsi/Makefile | 136 + .../linux-old/drivers/scsi/NCR5380.c | 2447 ++++++++++ .../linux-old/drivers/scsi/NCR5380.h | 323 ++ .../linux-old/drivers/scsi/aha152x.c | 2377 ++++++++++ .../linux-old/drivers/scsi/aha152x.h | 334 ++ .../linux-old/drivers/scsi/aha1542.c | 924 ++++ .../linux-old/drivers/scsi/aha1542.h | 157 + .../linux-old/drivers/scsi/aha1740.c | 506 +++ .../linux-old/drivers/scsi/aha1740.h | 180 + .../linux-old/drivers/scsi/constants.c | 529 +++ .../linux-old/drivers/scsi/constants.h | 7 + .../linux-old/drivers/scsi/fdomain.c | 1480 +++++++ .../linux-old/drivers/scsi/fdomain.h | 42 + .../linux-old/drivers/scsi/g_NCR5380.c | 179 + .../linux-old/drivers/scsi/g_NCR5380.h | 84 + .../THIRDPARTY/linux-old/drivers/scsi/hosts.c | 304 ++ .../THIRDPARTY/linux-old/drivers/scsi/hosts.h | 246 ++ .../THIRDPARTY/linux-old/drivers/scsi/pas16.c | 483 ++ .../THIRDPARTY/linux-old/drivers/scsi/pas16.h | 191 + .../THIRDPARTY/linux-old/drivers/scsi/scsi.c | 1710 +++++++ .../THIRDPARTY/linux-old/drivers/scsi/scsi.h | 531 +++ .../linux-old/drivers/scsi/scsi_debug.c | 515 +++ .../linux-old/drivers/scsi/scsi_debug.h | 27 + .../linux-old/drivers/scsi/scsi_ioctl.c | 305 ++ .../linux-old/drivers/scsi/scsi_ioctl.h | 20 + .../THIRDPARTY/linux-old/drivers/scsi/sd.c | 970 ++++ .../THIRDPARTY/linux-old/drivers/scsi/sd.h | 46 + .../linux-old/drivers/scsi/sd_ioctl.c | 68 + .../linux-old/drivers/scsi/seagate.c | 1711 +++++++ .../linux-old/drivers/scsi/seagate.h | 137 + .../THIRDPARTY/linux-old/drivers/scsi/sg.c | 336 ++ .../THIRDPARTY/linux-old/drivers/scsi/sg.h | 33 + .../THIRDPARTY/linux-old/drivers/scsi/sr.c | 751 ++++ .../THIRDPARTY/linux-old/drivers/scsi/sr.h | 37 + .../linux-old/drivers/scsi/sr_ioctl.c | 386 ++ .../THIRDPARTY/linux-old/drivers/scsi/st.c | 1475 +++++++ .../THIRDPARTY/linux-old/drivers/scsi/st.h | 61 + .../THIRDPARTY/linux-old/drivers/scsi/t128.c | 391 ++ .../THIRDPARTY/linux-old/drivers/scsi/t128.h | 167 + .../linux-old/drivers/scsi/ultrastor.c | 1112 +++++ .../linux-old/drivers/scsi/ultrastor.h | 83 + .../linux-old/drivers/scsi/wd7000.c | 622 +++ .../linux-old/drivers/scsi/wd7000.h | 205 + .../THIRDPARTY/linux-old/drivers/sound/.blurb | 12 + .../linux-old/drivers/sound/.indent.pro | 8 + .../linux-old/drivers/sound/CHANGELOG | 55 + .../linux-old/drivers/sound/COPYING | 25 + .../linux-old/drivers/sound/Makefile | 74 + .../THIRDPARTY/linux-old/drivers/sound/Readme | 242 + .../linux-old/drivers/sound/Readme.linux | 253 ++ .../linux-old/drivers/sound/adlib_card.c | 51 + .../linux-old/drivers/sound/audio.c | 353 ++ .../linux-old/drivers/sound/configure.c | 550 +++ .../linux-old/drivers/sound/dev_table.c | 205 + .../linux-old/drivers/sound/dev_table.h | 269 ++ .../THIRDPARTY/linux-old/drivers/sound/dma.h | 266 ++ .../linux-old/drivers/sound/dmabuf.c | 901 ++++ .../linux-old/drivers/sound/finetune.h | 49 + .../linux-old/drivers/sound/gus_card.c | 142 + .../linux-old/drivers/sound/gus_hw.h | 35 + .../linux-old/drivers/sound/gus_midi.c | 283 ++ .../linux-old/drivers/sound/gus_vol.c | 112 + .../linux-old/drivers/sound/gus_wave.c | 3420 ++++++++++++++ .../linux-old/drivers/sound/midibuf.c | 123 + .../linux-old/drivers/sound/mpu401.c | 321 ++ .../THIRDPARTY/linux-old/drivers/sound/opl3.c | 943 ++++ .../THIRDPARTY/linux-old/drivers/sound/opl3.h | 260 ++ .../THIRDPARTY/linux-old/drivers/sound/os.h | 154 + .../THIRDPARTY/linux-old/drivers/sound/pas.h | 250 ++ .../linux-old/drivers/sound/pas2_card.c | 359 ++ .../linux-old/drivers/sound/pas2_midi.c | 295 ++ .../linux-old/drivers/sound/pas2_mixer.c | 500 +++ .../linux-old/drivers/sound/pas2_pcm.c | 428 ++ .../linux-old/drivers/sound/patmgr.c | 262 ++ .../THIRDPARTY/linux-old/drivers/sound/sb.h | 28 + .../linux-old/drivers/sound/sb16_dsp.c | 608 +++ .../linux-old/drivers/sound/sb16_midi.c | 314 ++ .../linux-old/drivers/sound/sb_card.c | 52 + .../linux-old/drivers/sound/sb_dsp.c | 739 ++++ .../linux-old/drivers/sound/sb_midi.c | 197 + .../linux-old/drivers/sound/sb_mixer.c | 353 ++ .../linux-old/drivers/sound/sb_mixer.h | 172 + .../linux-old/drivers/sound/sequencer.c | 1152 +++++ .../linux-old/drivers/sound/sound_calls.h | 203 + .../linux-old/drivers/sound/sound_config.h | 233 + .../linux-old/drivers/sound/sound_switch.c | 417 ++ .../linux-old/drivers/sound/soundcard.c | 355 ++ .../linux-old/drivers/sound/tuning.h | 29 + .../THIRDPARTY/linux-old/drivers/sound/ulaw.h | 69 + .../source/THIRDPARTY/linux-old/fs/Makefile | 84 + .../THIRDPARTY/linux-old/fs/binfmt_coff.c | 782 ++++ .../THIRDPARTY/linux-old/fs/binfmt_elf.c | 425 ++ .../THIRDPARTY/linux-old/fs/block_dev.c | 215 + .../source/THIRDPARTY/linux-old/fs/buffer.c | 1000 +++++ .../source/THIRDPARTY/linux-old/fs/devices.c | 193 + .../source/THIRDPARTY/linux-old/fs/exec.c | 905 ++++ .../THIRDPARTY/linux-old/fs/ext/Makefile | 31 + .../source/THIRDPARTY/linux-old/fs/ext/dir.c | 118 + .../source/THIRDPARTY/linux-old/fs/ext/file.c | 257 ++ .../THIRDPARTY/linux-old/fs/ext/freelists.c | 348 ++ .../THIRDPARTY/linux-old/fs/ext/fsync.c | 185 + .../THIRDPARTY/linux-old/fs/ext/inode.c | 444 ++ .../THIRDPARTY/linux-old/fs/ext/namei.c | 900 ++++ .../THIRDPARTY/linux-old/fs/ext/symlink.c | 108 + .../THIRDPARTY/linux-old/fs/ext/truncate.c | 252 ++ .../THIRDPARTY/linux-old/fs/ext2/CHANGES | 91 + .../THIRDPARTY/linux-old/fs/ext2/Makefile | 31 + .../source/THIRDPARTY/linux-old/fs/ext2/acl.c | 45 + .../THIRDPARTY/linux-old/fs/ext2/balloc.c | 656 +++ .../THIRDPARTY/linux-old/fs/ext2/bitmap.c | 25 + .../THIRDPARTY/linux-old/fs/ext2/dcache.c | 338 ++ .../source/THIRDPARTY/linux-old/fs/ext2/dir.c | 170 + .../THIRDPARTY/linux-old/fs/ext2/file.c | 301 ++ .../THIRDPARTY/linux-old/fs/ext2/fsync.c | 198 + .../THIRDPARTY/linux-old/fs/ext2/ialloc.c | 577 +++ .../THIRDPARTY/linux-old/fs/ext2/inode.c | 584 +++ .../THIRDPARTY/linux-old/fs/ext2/ioctl.c | 51 + .../THIRDPARTY/linux-old/fs/ext2/namei.c | 1120 +++++ .../THIRDPARTY/linux-old/fs/ext2/super.c | 673 +++ .../THIRDPARTY/linux-old/fs/ext2/symlink.c | 126 + .../THIRDPARTY/linux-old/fs/ext2/truncate.c | 345 ++ .../source/THIRDPARTY/linux-old/fs/fcntl.c | 103 + .../source/THIRDPARTY/linux-old/fs/fifo.c | 161 + .../THIRDPARTY/linux-old/fs/file_table.c | 89 + .../THIRDPARTY/linux-old/fs/filesystems.c | 76 + .../THIRDPARTY/linux-old/fs/hpfs/Makefile | 30 + .../THIRDPARTY/linux-old/fs/hpfs/hpfs.h | 494 +++ .../THIRDPARTY/linux-old/fs/hpfs/hpfs_fs.c | 1724 ++++++++ .../source/THIRDPARTY/linux-old/fs/inode.c | 504 +++ .../source/THIRDPARTY/linux-old/fs/ioctl.c | 99 + .../THIRDPARTY/linux-old/fs/isofs/Makefile | 30 + .../THIRDPARTY/linux-old/fs/isofs/dir.c | 239 + .../THIRDPARTY/linux-old/fs/isofs/file.c | 265 ++ .../THIRDPARTY/linux-old/fs/isofs/inode.c | 685 +++ .../THIRDPARTY/linux-old/fs/isofs/namei.c | 268 ++ .../THIRDPARTY/linux-old/fs/isofs/rock.c | 508 +++ .../THIRDPARTY/linux-old/fs/isofs/rock.h | 111 + .../THIRDPARTY/linux-old/fs/isofs/symlink.c | 106 + .../THIRDPARTY/linux-old/fs/isofs/util.c | 131 + .../source/THIRDPARTY/linux-old/fs/locks.c | 454 ++ .../THIRDPARTY/linux-old/fs/minix/Makefile | 31 + .../THIRDPARTY/linux-old/fs/minix/bitmap.c | 230 + .../THIRDPARTY/linux-old/fs/minix/dir.c | 100 + .../THIRDPARTY/linux-old/fs/minix/file.c | 249 ++ .../THIRDPARTY/linux-old/fs/minix/fsync.c | 159 + .../THIRDPARTY/linux-old/fs/minix/inode.c | 512 +++ .../THIRDPARTY/linux-old/fs/minix/namei.c | 828 ++++ .../THIRDPARTY/linux-old/fs/minix/symlink.c | 102 + .../THIRDPARTY/linux-old/fs/minix/truncate.c | 184 + .../THIRDPARTY/linux-old/fs/msdos/Makefile | 30 + .../THIRDPARTY/linux-old/fs/msdos/dir.c | 114 + .../THIRDPARTY/linux-old/fs/msdos/fat.c | 293 ++ .../THIRDPARTY/linux-old/fs/msdos/file.c | 223 + .../THIRDPARTY/linux-old/fs/msdos/inode.c | 447 ++ .../THIRDPARTY/linux-old/fs/msdos/misc.c | 523 +++ .../THIRDPARTY/linux-old/fs/msdos/namei.c | 592 +++ .../source/THIRDPARTY/linux-old/fs/namei.c | 741 ++++ .../THIRDPARTY/linux-old/fs/nfs/Makefile | 31 + .../source/THIRDPARTY/linux-old/fs/nfs/dir.c | 606 +++ .../source/THIRDPARTY/linux-old/fs/nfs/file.c | 163 + .../THIRDPARTY/linux-old/fs/nfs/inode.c | 233 + .../source/THIRDPARTY/linux-old/fs/nfs/mmap.c | 156 + .../source/THIRDPARTY/linux-old/fs/nfs/proc.c | 768 ++++ .../source/THIRDPARTY/linux-old/fs/nfs/sock.c | 185 + .../THIRDPARTY/linux-old/fs/nfs/symlink.c | 108 + .../source/THIRDPARTY/linux-old/fs/open.c | 494 +++ .../source/THIRDPARTY/linux-old/fs/pipe.c | 426 ++ .../THIRDPARTY/linux-old/fs/proc/Makefile | 30 + .../THIRDPARTY/linux-old/fs/proc/array.c | 548 +++ .../THIRDPARTY/linux-old/fs/proc/base.c | 164 + .../source/THIRDPARTY/linux-old/fs/proc/fd.c | 198 + .../THIRDPARTY/linux-old/fs/proc/inode.c | 199 + .../THIRDPARTY/linux-old/fs/proc/kmsg.c | 76 + .../THIRDPARTY/linux-old/fs/proc/link.c | 129 + .../source/THIRDPARTY/linux-old/fs/proc/mem.c | 170 + .../source/THIRDPARTY/linux-old/fs/proc/net.c | 210 + .../THIRDPARTY/linux-old/fs/proc/root.c | 179 + .../THIRDPARTY/linux-old/fs/read_write.c | 108 + .../source/THIRDPARTY/linux-old/fs/select.c | 253 ++ .../source/THIRDPARTY/linux-old/fs/stat.c | 201 + .../source/THIRDPARTY/linux-old/fs/super.c | 537 +++ .../source/THIRDPARTY/linux-old/fs/sysv/INTRO | 189 + .../THIRDPARTY/linux-old/fs/sysv/Makefile | 31 + .../THIRDPARTY/linux-old/fs/sysv/README | 37 + .../THIRDPARTY/linux-old/fs/sysv/balloc.c | 349 ++ .../source/THIRDPARTY/linux-old/fs/sysv/dir.c | 110 + .../THIRDPARTY/linux-old/fs/sysv/file.c | 313 ++ .../THIRDPARTY/linux-old/fs/sysv/fsync.c | 200 + .../THIRDPARTY/linux-old/fs/sysv/ialloc.c | 204 + .../THIRDPARTY/linux-old/fs/sysv/inode.c | 808 ++++ .../THIRDPARTY/linux-old/fs/sysv/namei.c | 836 ++++ .../THIRDPARTY/linux-old/fs/sysv/symlink.c | 110 + .../THIRDPARTY/linux-old/fs/sysv/truncate.c | 508 +++ .../THIRDPARTY/linux-old/fs/xiafs/Makefile | 31 + .../THIRDPARTY/linux-old/fs/xiafs/bitmap.c | 395 ++ .../THIRDPARTY/linux-old/fs/xiafs/dir.c | 123 + .../THIRDPARTY/linux-old/fs/xiafs/file.c | 251 ++ .../THIRDPARTY/linux-old/fs/xiafs/fsync.c | 159 + .../THIRDPARTY/linux-old/fs/xiafs/inode.c | 502 +++ .../THIRDPARTY/linux-old/fs/xiafs/namei.c | 847 ++++ .../THIRDPARTY/linux-old/fs/xiafs/symlink.c | 118 + .../THIRDPARTY/linux-old/fs/xiafs/truncate.c | 197 + .../THIRDPARTY/linux-old/fs/xiafs/xiafs_mac.h | 32 + .../source/THIRDPARTY/linux-old/ibcs/Makefile | 39 + .../THIRDPARTY/linux-old/ibcs/emulate.c | 27 + .../THIRDPARTY/linux-old/include/asm/bitops.h | 107 + .../THIRDPARTY/linux-old/include/asm/dma.h | 264 ++ .../THIRDPARTY/linux-old/include/asm/io.h | 146 + .../THIRDPARTY/linux-old/include/asm/irq.h | 165 + .../linux-old/include/asm/segment.h | 219 + .../THIRDPARTY/linux-old/include/asm/system.h | 107 + .../linux-old/include/linux/a.out.h | 270 ++ .../linux-old/include/linux/binfmts.h | 48 + .../linux-old/include/linux/busmouse.h | 100 + .../linux-old/include/linux/cdrom.h | 340 ++ .../linux-old/include/linux/cdu31a.h | 313 ++ .../THIRDPARTY/linux-old/include/linux/coff.h | 351 ++ .../linux-old/include/linux/config.h | 91 + .../linux-old/include/linux/ctype.h | 34 + .../THIRDPARTY/linux-old/include/linux/ddi.h | 79 + .../linux-old/include/linux/debugreg.h | 61 + .../linux-old/include/linux/delay.h | 37 + .../linux-old/include/linux/dirent.h | 13 + .../THIRDPARTY/linux-old/include/linux/elf.h | 153 + .../linux-old/include/linux/errno.h | 132 + .../linux-old/include/linux/ext2_fs.h | 447 ++ .../linux-old/include/linux/ext2_fs_i.h | 39 + .../linux-old/include/linux/ext2_fs_sb.h | 49 + .../linux-old/include/linux/ext_fs.h | 108 + .../linux-old/include/linux/ext_fs_i.h | 11 + .../linux-old/include/linux/ext_fs_sb.h | 21 + .../linux-old/include/linux/fcntl.h | 49 + .../THIRDPARTY/linux-old/include/linux/fd.h | 43 + .../linux-old/include/linux/fdreg.h | 73 + .../THIRDPARTY/linux-old/include/linux/fs.h | 411 ++ .../linux-old/include/linux/genhd.h | 52 + .../linux-old/include/linux/hdreg.h | 64 + .../THIRDPARTY/linux-old/include/linux/head.h | 20 + .../linux-old/include/linux/hpfs_fs.h | 12 + .../linux-old/include/linux/hpfs_fs_i.h | 24 + .../linux-old/include/linux/hpfs_fs_sb.h | 32 + .../THIRDPARTY/linux-old/include/linux/icmp.h | 81 + .../THIRDPARTY/linux-old/include/linux/if.h | 156 + .../linux-old/include/linux/if_arp.h | 83 + .../linux-old/include/linux/if_ether.h | 93 + .../THIRDPARTY/linux-old/include/linux/in.h | 184 + .../linux-old/include/linux/interrupt.h | 40 + .../linux-old/include/linux/ioctl.h | 47 + .../linux-old/include/linux/ioport.h | 28 + .../THIRDPARTY/linux-old/include/linux/ip.h | 81 + .../THIRDPARTY/linux-old/include/linux/ipc.h | 65 + .../linux-old/include/linux/iso_fs.h | 218 + .../linux-old/include/linux/iso_fs_i.h | 13 + .../linux-old/include/linux/iso_fs_sb.h | 30 + .../THIRDPARTY/linux-old/include/linux/kd.h | 209 + .../linux-old/include/linux/kernel.h | 78 + .../linux-old/include/linux/kernel_stat.h | 26 + .../linux-old/include/linux/keyboard.h | 140 + .../THIRDPARTY/linux-old/include/linux/ldt.h | 33 + .../linux-old/include/linux/limits.h | 17 + .../linux-old/include/linux/linkage.h | 10 + .../linux-old/include/linux/locks.h | 56 + .../THIRDPARTY/linux-old/include/linux/lp.h | 147 + .../linux-old/include/linux/major.h | 91 + .../linux-old/include/linux/malloc.h | 30 + .../linux-old/include/linux/math_emu.h | 58 + .../linux-old/include/linux/mc146818rtc.h | 104 + .../THIRDPARTY/linux-old/include/linux/mcd.h | 106 + .../linux-old/include/linux/minix_fs.h | 119 + .../linux-old/include/linux/minix_fs_i.h | 11 + .../linux-old/include/linux/minix_fs_sb.h | 24 + .../linux-old/include/linux/mktime.h | 13 + .../THIRDPARTY/linux-old/include/linux/mm.h | 195 + .../THIRDPARTY/linux-old/include/linux/mman.h | 15 + .../linux-old/include/linux/module.h | 58 + .../linux-old/include/linux/mouse.h | 11 + .../linux-old/include/linux/msdos_fs.h | 190 + .../linux-old/include/linux/msdos_fs_i.h | 20 + .../linux-old/include/linux/msdos_fs_sb.h | 27 + .../THIRDPARTY/linux-old/include/linux/msg.h | 74 + .../THIRDPARTY/linux-old/include/linux/mtio.h | 156 + .../THIRDPARTY/linux-old/include/linux/net.h | 130 + .../THIRDPARTY/linux-old/include/linux/nfs.h | 169 + .../linux-old/include/linux/nfs_fs.h | 124 + .../linux-old/include/linux/nfs_fs_i.h | 13 + .../linux-old/include/linux/nfs_fs_sb.h | 31 + .../linux-old/include/linux/nfs_mount.h | 48 + .../THIRDPARTY/linux-old/include/linux/page.h | 34 + .../linux-old/include/linux/param.h | 20 + .../linux-old/include/linux/pipe_fs_i.h | 35 + .../linux-old/include/linux/proc_fs.h | 36 + .../linux-old/include/linux/ptrace.h | 69 + .../linux-old/include/linux/resource.h | 71 + .../linux-old/include/linux/route.h | 46 + .../linux-old/include/linux/sbpcd.h | 473 ++ .../linux-old/include/linux/sched.h | 550 +++ .../linux-old/include/linux/segment.h | 10 + .../THIRDPARTY/linux-old/include/linux/sem.h | 96 + .../linux-old/include/linux/serial.h | 161 + .../THIRDPARTY/linux-old/include/linux/shm.h | 109 + .../linux-old/include/linux/signal.h | 92 + .../linux-old/include/linux/socket.h | 91 + .../linux-old/include/linux/sockios.h | 76 + .../linux-old/include/linux/soundcard.h | 743 ++++ .../THIRDPARTY/linux-old/include/linux/stat.h | 88 + .../linux-old/include/linux/stddef.h | 15 + .../linux-old/include/linux/string.h | 419 ++ .../THIRDPARTY/linux-old/include/linux/sys.h | 179 + .../linux-old/include/linux/sysv_fs.h | 437 ++ .../linux-old/include/linux/sysv_fs_i.h | 20 + .../linux-old/include/linux/sysv_fs_sb.h | 104 + .../linux-old/include/linux/tasks.h | 9 + .../THIRDPARTY/linux-old/include/linux/tcp.h | 61 + .../linux-old/include/linux/termios.h | 243 + .../THIRDPARTY/linux-old/include/linux/time.h | 35 + .../linux-old/include/linux/timer.h | 86 + .../linux-old/include/linux/times.h | 11 + .../linux-old/include/linux/timex.h | 142 + .../linux-old/include/linux/tpqic02.h | 374 ++ .../THIRDPARTY/linux-old/include/linux/tty.h | 448 ++ .../linux-old/include/linux/types.h | 126 + .../THIRDPARTY/linux-old/include/linux/udp.h | 29 + .../linux-old/include/linux/ultrasound.h | 121 + .../THIRDPARTY/linux-old/include/linux/un.h | 9 + .../linux-old/include/linux/unistd.h | 228 + .../THIRDPARTY/linux-old/include/linux/user.h | 77 + .../linux-old/include/linux/utime.h | 9 + .../linux-old/include/linux/utsname.h | 35 + .../THIRDPARTY/linux-old/include/linux/vfs.h | 21 + .../THIRDPARTY/linux-old/include/linux/vm86.h | 56 + .../THIRDPARTY/linux-old/include/linux/vt.h | 34 + .../THIRDPARTY/linux-old/include/linux/wait.h | 26 + .../THIRDPARTY/linux-old/include/linux/xd.h | 137 + .../linux-old/include/linux/xia_fs.h | 115 + .../linux-old/include/linux/xia_fs_i.h | 19 + .../linux-old/include/linux/xia_fs_sb.h | 36 + .../source/THIRDPARTY/linux-old/init/main.c | 514 +++ .../source/THIRDPARTY/linux-old/ipc/Makefile | 38 + .../source/THIRDPARTY/linux-old/ipc/msg.c | 420 ++ .../source/THIRDPARTY/linux-old/ipc/sem.c | 508 +++ .../source/THIRDPARTY/linux-old/ipc/shm.c | 728 +++ .../source/THIRDPARTY/linux-old/ipc/util.c | 156 + .../THIRDPARTY/linux-old/kernel/Makefile | 56 + .../source/THIRDPARTY/linux-old/kernel/dma.c | 87 + .../source/THIRDPARTY/linux-old/kernel/exit.c | 578 +++ .../source/THIRDPARTY/linux-old/kernel/fork.c | 232 + .../source/THIRDPARTY/linux-old/kernel/info.c | 42 + .../THIRDPARTY/linux-old/kernel/ioport.c | 184 + .../source/THIRDPARTY/linux-old/kernel/irq.c | 341 ++ .../THIRDPARTY/linux-old/kernel/itimer.c | 117 + .../THIRDPARTY/linux-old/kernel/ksyms.S | 28 + .../THIRDPARTY/linux-old/kernel/ksyms.sh | 37 + .../source/THIRDPARTY/linux-old/kernel/ldt.c | 102 + .../THIRDPARTY/linux-old/kernel/mktime.c | 58 + .../THIRDPARTY/linux-old/kernel/module.c | 277 ++ .../THIRDPARTY/linux-old/kernel/panic.c | 34 + .../THIRDPARTY/linux-old/kernel/printk.c | 230 + .../THIRDPARTY/linux-old/kernel/ptrace.c | 480 ++ .../THIRDPARTY/linux-old/kernel/sched.c | 828 ++++ .../THIRDPARTY/linux-old/kernel/signal.c | 414 ++ .../source/THIRDPARTY/linux-old/kernel/sys.c | 766 ++++ .../THIRDPARTY/linux-old/kernel/sys_call.S | 390 ++ .../source/THIRDPARTY/linux-old/kernel/time.c | 442 ++ .../THIRDPARTY/linux-old/kernel/traps.c | 211 + .../THIRDPARTY/linux-old/kernel/vsprintf.c | 274 ++ .../source/THIRDPARTY/linux-old/lib/Makefile | 32 + .../source/THIRDPARTY/linux-old/lib/_exit.c | 18 + .../source/THIRDPARTY/linux-old/lib/close.c | 11 + .../source/THIRDPARTY/linux-old/lib/ctype.c | 35 + .../source/THIRDPARTY/linux-old/lib/dup.c | 11 + .../source/THIRDPARTY/linux-old/lib/errno.c | 7 + .../source/THIRDPARTY/linux-old/lib/execve.c | 11 + .../source/THIRDPARTY/linux-old/lib/malloc.c | 540 +++ .../source/THIRDPARTY/linux-old/lib/open.c | 26 + .../source/THIRDPARTY/linux-old/lib/setsid.c | 12 + .../source/THIRDPARTY/linux-old/lib/string.c | 16 + .../source/THIRDPARTY/linux-old/lib/wait.c | 17 + .../source/THIRDPARTY/linux-old/lib/write.c | 12 + .../source/THIRDPARTY/linux-old/makever.sh | 13 + .../source/THIRDPARTY/linux-old/mm/Makefile | 30 + .../source/THIRDPARTY/linux-old/mm/kmalloc.c | 338 ++ .../source/THIRDPARTY/linux-old/mm/memory.c | 1227 ++++++ .../source/THIRDPARTY/linux-old/mm/mmap.c | 481 ++ .../source/THIRDPARTY/linux-old/mm/swap.c | 851 ++++ .../source/THIRDPARTY/linux-old/mm/vmalloc.c | 202 + .../source/THIRDPARTY/linux-old/net/Makefile | 51 + .../source/THIRDPARTY/linux-old/net/Space.c | 95 + .../source/THIRDPARTY/linux-old/net/ddi.c | 91 + .../THIRDPARTY/linux-old/net/inet/Makefile | 46 + .../THIRDPARTY/linux-old/net/inet/README | 44 + .../THIRDPARTY/linux-old/net/inet/arp.c | 951 ++++ .../THIRDPARTY/linux-old/net/inet/arp.h | 64 + .../THIRDPARTY/linux-old/net/inet/datagram.c | 205 + .../THIRDPARTY/linux-old/net/inet/dev.c | 1073 +++++ .../THIRDPARTY/linux-old/net/inet/dev.h | 191 + .../THIRDPARTY/linux-old/net/inet/eth.c | 187 + .../THIRDPARTY/linux-old/net/inet/eth.h | 35 + .../THIRDPARTY/linux-old/net/inet/icmp.c | 441 ++ .../THIRDPARTY/linux-old/net/inet/icmp.h | 36 + .../THIRDPARTY/linux-old/net/inet/inet.h | 97 + .../source/THIRDPARTY/linux-old/net/inet/ip.c | 1584 +++++++ .../source/THIRDPARTY/linux-old/net/inet/ip.h | 84 + .../THIRDPARTY/linux-old/net/inet/loopback.c | 137 + .../THIRDPARTY/linux-old/net/inet/packet.c | 275 ++ .../THIRDPARTY/linux-old/net/inet/proc.c | 133 + .../THIRDPARTY/linux-old/net/inet/protocol.c | 161 + .../THIRDPARTY/linux-old/net/inet/protocol.h | 59 + .../THIRDPARTY/linux-old/net/inet/raw.c | 410 ++ .../THIRDPARTY/linux-old/net/inet/raw.h | 36 + .../THIRDPARTY/linux-old/net/inet/route.c | 384 ++ .../THIRDPARTY/linux-old/net/inet/route.h | 47 + .../THIRDPARTY/linux-old/net/inet/skbuff.c | 489 ++ .../THIRDPARTY/linux-old/net/inet/skbuff.h | 112 + .../THIRDPARTY/linux-old/net/inet/sock.c | 1886 ++++++++ .../THIRDPARTY/linux-old/net/inet/sock.h | 278 ++ .../THIRDPARTY/linux-old/net/inet/tcp.c | 3918 +++++++++++++++++ .../THIRDPARTY/linux-old/net/inet/tcp.h | 131 + .../THIRDPARTY/linux-old/net/inet/timer.c | 237 + .../THIRDPARTY/linux-old/net/inet/udp.c | 646 +++ .../THIRDPARTY/linux-old/net/inet/udp.h | 50 + .../THIRDPARTY/linux-old/net/inet/utils.c | 147 + .../source/THIRDPARTY/linux-old/net/socket.c | 1094 +++++ .../THIRDPARTY/linux-old/net/unix/Makefile | 35 + .../THIRDPARTY/linux-old/net/unix/proc.c | 77 + .../THIRDPARTY/linux-old/net/unix/sock.c | 944 ++++ .../THIRDPARTY/linux-old/net/unix/unix.h | 65 + .../source/THIRDPARTY/linux-old/tools/build.c | 227 + .../THIRDPARTY/linux-old/tools/version.c | 21 + .../THIRDPARTY/linux-old/zBoot/Makefile | 32 + .../source/THIRDPARTY/linux-old/zBoot/crypt.h | 12 + .../source/THIRDPARTY/linux-old/zBoot/gzip.h | 284 ++ .../source/THIRDPARTY/linux-old/zBoot/head.S | 58 + .../THIRDPARTY/linux-old/zBoot/inflate.c | 818 ++++ .../source/THIRDPARTY/linux-old/zBoot/lzw.h | 42 + .../source/THIRDPARTY/linux-old/zBoot/misc.c | 437 ++ .../THIRDPARTY/linux-old/zBoot/piggyback.c | 81 + .../source/THIRDPARTY/linux-old/zBoot/unzip.c | 180 + .../THIRDPARTY/linux-old/zBoot/xtract.c | 82 + 560 files changed, 176105 insertions(+) create mode 100644 .gitignore create mode 100644 gems-kernel.git/opt/cross/share/man/man7/fsf-funding.7 create mode 100644 gems-kernel.git/opt/cross/share/man/man7/gfdl.7 create mode 100644 gems-kernel.git/opt/cross/share/man/man7/gpl.7 create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/CHANGES create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/COPYING create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/Configure create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/README create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/boot/bootsect.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/boot/head.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/boot/setup.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/config.in create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/README create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/control_w.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/div_small.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/errors.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/exception.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_arith.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_asm.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_aux.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_emu.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_entry.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_etc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_proto.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_system.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_trig.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/get_address.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/load_store.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_2xm1.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_atan.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_div.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_l2.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_mul64.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_sin.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_tan.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/polynomial.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_add_sub.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_compare.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_div.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_ld_str.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_mul.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_norm.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_round.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_add.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_div.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_mul.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_sub.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/status_w.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/version.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_shrx.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_sqrt.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/README.sbpcd create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/blk.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/cdu31a.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/floppy.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/genhd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/hd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ll_rw_blk.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/mcd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ramdisk.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/sbpcd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/xd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/atixlmouse.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/busmouse.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/console.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/defkeymap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/defkeymap.map create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/diacr.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/kbd_kern.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/keyboard.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/lp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mem.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mouse.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/msbusmouse.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/psaux.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/pty.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/serial.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tpqic02.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_io.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_ioctl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt_kern.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c501.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c507.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c509.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/CONFIG create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/LICENSE.SRC create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README.DLINK create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README1.PLIP create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README2.PLIP create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Space.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/at1700.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/auto_irq.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/d_link.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/eexpress.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/hp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/iow.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/lance.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/ne.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/net_init.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/plip.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/skeleton.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/smc-ultra.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/wd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/g_NCR5380.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/g_NCR5380.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/pas16.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/pas16.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd_ioctl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr_ioctl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/t128.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/t128.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.blurb create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.indent.pro create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/CHANGELOG create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/COPYING create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme.linux create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/adlib_card.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/audio.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/configure.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dev_table.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dev_table.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dma.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dmabuf.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/finetune.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_card.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_hw.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_midi.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_vol.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_wave.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/midibuf.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/mpu401.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/os.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_card.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_midi.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_mixer.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_pcm.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/patmgr.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_dsp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_midi.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_card.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_dsp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_midi.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sequencer.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_calls.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_config.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_switch.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/soundcard.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/tuning.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/ulaw.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_coff.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_elf.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/block_dev.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/buffer.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/devices.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/exec.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/freelists.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/fsync.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/truncate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/CHANGES create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/acl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/balloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/bitmap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dcache.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/fsync.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ialloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ioctl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/super.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/truncate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/fcntl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/fifo.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/file_table.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/filesystems.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs_fs.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/ioctl.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/util.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/locks.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/bitmap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/fsync.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/truncate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/fat.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/misc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/mmap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/proc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/sock.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/open.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/pipe.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/array.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/base.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/fd.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/kmsg.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/link.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/mem.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/net.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/root.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/read_write.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/select.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/stat.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/super.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/INTRO create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/README create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/balloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/fsync.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/ialloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/truncate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/bitmap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/dir.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/file.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/fsync.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/inode.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/namei.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/symlink.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/truncate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/xiafs_mac.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/emulate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/bitops.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/dma.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/io.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/irq.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/segment.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/system.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/a.out.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/binfmts.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/busmouse.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdrom.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdu31a.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/coff.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/config.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ctype.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ddi.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/debugreg.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/delay.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/dirent.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/elf.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/errno.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fcntl.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fdreg.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/genhd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hdreg.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/head.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/icmp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_arp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_ether.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/in.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/interrupt.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioctl.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioport.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ip.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ipc.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel_stat.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/keyboard.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ldt.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/limits.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/linkage.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/locks.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/lp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/major.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/malloc.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/math_emu.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mc146818rtc.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mcd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mktime.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mm.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mman.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/module.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mouse.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msg.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mtio.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/net.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_mount.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/page.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/param.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/pipe_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/proc_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ptrace.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/resource.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/route.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sbpcd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sched.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/segment.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sem.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/serial.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/shm.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/signal.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/socket.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sockios.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/soundcard.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stat.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stddef.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/string.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sys.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tasks.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tcp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/termios.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/time.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timer.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/times.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timex.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tpqic02.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tty.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/types.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/udp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ultrasound.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/un.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/unistd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/user.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utime.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utsname.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vfs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vm86.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vt.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/wait.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xd.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_i.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_sb.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/init/main.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ipc/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ipc/msg.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ipc/sem.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ipc/shm.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/ipc/util.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/dma.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/exit.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/fork.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/info.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ioport.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/irq.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/itimer.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.sh create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ldt.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/mktime.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/module.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/panic.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/printk.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ptrace.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sched.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/signal.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys_call.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/time.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/traps.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/kernel/vsprintf.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/_exit.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/close.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/ctype.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/dup.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/errno.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/execve.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/malloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/open.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/setsid.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/string.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/wait.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/lib/write.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/makever.sh create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/mm/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/mm/kmalloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/mm/memory.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/mm/mmap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/mm/swap.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/mm/vmalloc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/Space.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/ddi.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/README create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/datagram.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/inet.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/loopback.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/packet.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/proc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/timer.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/utils.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/socket.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/proc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/sock.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/unix.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/tools/build.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/tools/version.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/Makefile create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/crypt.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/gzip.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/head.S create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/inflate.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/lzw.h create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/misc.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/piggyback.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/unzip.c create mode 100644 gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/xtract.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..77e472242 --- /dev/null +++ b/.gitignore @@ -0,0 +1,1172 @@ + +gems-kernel.git/opt/cross/share/man/man1/i686-elf-windres.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-windmc.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-strip.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-strings.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-size.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-readelf.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-ranlib.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-objdump.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-objcopy.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-nm.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-nlmconv.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-ld.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-gprof.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-gcov.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-gcov-tool.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-gcov-dump.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-gcc.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-g++.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-elfedit.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-dlltool.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-cpp.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-c++filt.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-as.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-ar.1 +gems-kernel.git/opt/cross/share/man/man1/i686-elf-addr2line.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-windres.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-windmc.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-strip.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-strings.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-size.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-readelf.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-ranlib.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-objdump.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-objcopy.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-nm.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-nlmconv.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-ld.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-gprof.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-gcov.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-gcov-tool.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-gcov-dump.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-gcc.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-g++.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-elfedit.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-dlltool.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-cpp.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-c++filt.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-as.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-ar.1 +gems-kernel.git/opt/cross/share/man/man1/i386-elf-addr2line.1 +gems-kernel.git/opt/cross/share/info/ld.info +gems-kernel.git/opt/cross/share/info/gprof.info +gems-kernel.git/opt/cross/share/info/gccint.info +gems-kernel.git/opt/cross/share/info/gccinstall.info +gems-kernel.git/opt/cross/share/info/gcc.info +gems-kernel.git/opt/cross/share/info/dir +gems-kernel.git/opt/cross/share/info/cppinternals.info +gems-kernel.git/opt/cross/share/info/cpp.info +gems-kernel.git/opt/cross/share/info/binutils.info +gems-kernel.git/opt/cross/share/info/bfd.info +gems-kernel.git/opt/cross/share/info/as.info +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/plugin/gengtype +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/lto1 +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/lto-wrapper +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/liblto_plugin.so.0.0.0 +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/liblto_plugin.la +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/install-tools/mkinstalldirs +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/install-tools/mkheaders +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/install-tools/fixincl +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/install-tools/fixinc.sh +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/collect2 +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/cc1plus +gems-kernel.git/opt/cross/libexec/gcc/i686-elf/7.1.0/cc1 +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/plugin/gengtype +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/lto1 +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/lto-wrapper +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/liblto_plugin.so.0.0.0 +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/liblto_plugin.la +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/install-tools/mkinstalldirs +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/install-tools/mkheaders +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/install-tools/fixincl +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/install-tools/fixinc.sh +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/collect2 +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/cc1plus +gems-kernel.git/opt/cross/libexec/gcc/i386-elf/7.1.0/cc1 +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/xcoffout.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/xcoff.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/wide-int.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/wide-int-print.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/vtable-verify.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/vmsdbg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/version.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/vec.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/varasm.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/value-prof.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/valtrack.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ubsan.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/typed-splay-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/typeclass.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tsystem.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tsan.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/treestruct.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-vrp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-vectorizer.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-stdarg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssanames.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-threadupdate.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-threadedge.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-threadbackward.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-ter.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-scopedtables.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-sccvn.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-propagate.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-operands.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-loop.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-loop-niter.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-loop-manip.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-loop-ivopts.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-live.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-dom.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-coalesce.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-ccp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-alias.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-ssa-address.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-scalar-evolution.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-phinodes.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-pass.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-parloops.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-outof-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-object-size.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-nested.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-iterator.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-into-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-inline.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-if-conv.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-hasher.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-hash-traits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-eh.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-dump.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-diagnostic.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-dfa.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-data-ref.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-core.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-chrec.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-chkp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-check.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-cfgcleanup.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-cfg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tree-affine.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/trans-mem.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tracer.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/toplev.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tm_p.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tm.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/tm-preds.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/timevar.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/timevar.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/targhooks.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/target.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/target.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/target-insns.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/target-hooks-macros.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/target-globals.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/target-def.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/system.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sync-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/symtab.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/symbol-summary.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/substring-locations.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/stringpool.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/streamer-hooks.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/stor-layout.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/stmt.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/statistics.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/stab.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ssa.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ssa-iterators.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sreal.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/splay-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/spellcheck.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/spellcheck-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sparseset.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/signop.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/shrink-wrap.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sese.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/selftest.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/selftest-rtl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sel-sched.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sel-sched-ir.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sel-sched-dump.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sdbout.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sched-int.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sbitmap.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/sanitizer.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/safe-ctype.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/run-rtl-passes.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtlhooks-def.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtlhash.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtl.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtl-iter.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtl-error.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/rtl-chkp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/resource.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/reload.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/regset.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/regs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/regrename.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/regcprop.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/reg-notes.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/recog.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/realmpfr.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/real.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/read-rtl-function.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/read-md.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/profile.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/print-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/print-rtl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/prefix.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/predict.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/predict.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/plugin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/plugin.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/plugin-version.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/plugin-api.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/passes.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/pass_manager.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/pass-instances.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/params.list +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/params.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/params.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/params-options.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/params-list.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/params-enum.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/output.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/opts.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/opts-diagnostic.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/options.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/optabs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/optabs.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/optabs-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/optabs-query.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/optabs-libfuncs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/omp-offload.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/omp-low.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/omp-grid.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/omp-general.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/omp-expand.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/omp-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/obstack.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/objc/objc-tree.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/mode-classes.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/memory-block.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/memmodel.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/mem-stats.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/mem-stats-traits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/md5.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/machmode.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/machmode.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lto-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lto-section-names.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lto-compress.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lra.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lra-int.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lower-subreg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/loop-unroll.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/line-map.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/limity.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/limitx.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/libiberty.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/libfuncs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/lcm.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/langhooks.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/langhooks-def.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/is-a.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ira.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ira-int.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-utils.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-reference.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-ref.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-prop.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-inline.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-icf.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-icf-gimple.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ipa-chkp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/intl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/internal-fn.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/internal-fn.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/insn-notes.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/insn-modes.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/insn-flags.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/insn-constants.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/insn-codes.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/insn-addr.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/input.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/incpath.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/inchash.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ifcvt.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hwint.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hw-doloop.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hsa-common.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hsa-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hsa-brig-format.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hosthooks.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hosthooks-def.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hooks.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/highlev-plugin-common.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hashtab.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hash-traits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hash-table.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hash-set.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hash-map.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hash-map-traits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/hard-reg-set.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gtype-desc.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gtm-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gsyslimits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gsyms.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gstab.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gsstruct.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/graphite.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/graphds.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/graph.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/glimits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimplify.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimplify-me.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-walk.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-predict.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-match.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-low.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-iterator.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-fold.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-expr.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gimple-builder.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ggc.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ggc-internal.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gensupport.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/genrtl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gengtype.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/generic-match.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcse.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcse-common.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcov-io.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcov-counter.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcc.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcc-symtab.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcc-rich-location.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/gcc-plugin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/function.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/fold-const.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/fold-const-call.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/flags.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/flag-types.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/fixed-value.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/filenames.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/file-find.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/fibonacci_heap.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/expr.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/expmed.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/explow.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/except.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/et-forest.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/errors.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/emit-rtl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/edit-context.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dwarf2out.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dwarf2asm.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dumpfile.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/double-int.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/domwalk.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dominance.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dojump.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/diagnostic.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/diagnostic.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/diagnostic-core.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/diagnostic-color.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dfp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/df.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/defaults.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/debug.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ddg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dce.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dbxout.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dbgcnt.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/dbgcnt.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/data-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cselib.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cpplib.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cppdefault.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cppbuiltin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cp/type-utils.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cp/name-lookup.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cp/cxx-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cp/cp-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cp/cp-tree.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/coverage.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/coretypes.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/convert.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/context.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/configargs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/vxworks-dummy.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/newlib-stdint.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/initfini-array.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/x86-tune.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/unix.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/stringop.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/i386elf.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/i386.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/i386-protos.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/i386-opts.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/i386/att.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/elfos.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config/dbxelf.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/config.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/conditions.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/collect2.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/collect2-aix.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/collect-utils.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cilkplus.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cilk.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cilk-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cif-code.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/chkp-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cgraph.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfgrtl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfgloopmanip.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfgloop.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfghooks.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfgexpand.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfgcleanup.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfgbuild.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfganal.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/cfg-flags.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ccmp.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/calls.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/c-tree.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/c-family/c-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/c-family/c-pragma.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/c-family/c-objc.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/c-family/c-common.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/c-family/c-common.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/bversion.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/builtins.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/builtin-types.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/builtin-attrs.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/brig-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/bitmap.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/bb-reorder.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/basic-block.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/backend.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/b-header-vars +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/auto-profile.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/auto-host.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/attribs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/asan.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ansidecl.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/alloc-pool.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/all-tree.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/alias.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/addresses.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/include/ada/gcc-interface/ada-tree.def +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/plugin/gtype.state +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/libgcov.a +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/libgcc.a +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/install-tools/mkheaders.conf +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/install-tools/macro_list +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/install-tools/include/README +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/install-tools/include/limits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/install-tools/gsyslimits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/install-tools/fixinc_list +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xtestintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xsavesintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xsaveoptintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xsaveintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xsavecintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xopintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/xmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/x86intrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/wmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/varargs.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/unwind.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/tmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/tgmath.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/tbmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdnoreturn.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdint.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdint-gcc.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdfix.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stddef.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdbool.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdatomic.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdarg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/stdalign.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/smmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/shaintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/sgxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/rtmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/rdseedintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/prfchwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/popcntintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/pmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/pkuintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/nmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/mwaitxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/mmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/mm_malloc.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/mm3dnow.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/lzcntintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/lwpintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/iso646.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/immintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/ia32intrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/gcov.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/fxsrintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/fmaintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/fma4intrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/float.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/f16cintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/emmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/cross-stdarg.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/cpuid.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/clzerointrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/clwbintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/clflushoptintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/bmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/bmiintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/bmi2intrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512vpopcntdqintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512vlintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512vldqintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512vlbwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512vbmivlintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512vbmiintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512pfintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512ifmavlintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512ifmaintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512fintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512erintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512dqintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512cdintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx512bwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx5124vnniwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx5124fmapsintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/avx2intrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/ammintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include/adxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include-fixed/syslimits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include-fixed/README +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/include-fixed/limits.h +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/crtend.o +gems-kernel.git/opt/cross/lib/gcc/i686-elf/7.1.0/crtbegin.o +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/xcoffout.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/xcoff.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/wide-int.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/wide-int-print.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/vtable-verify.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/vmsdbg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/version.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/vec.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/varasm.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/value-prof.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/valtrack.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ubsan.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/typed-splay-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/typeclass.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tsystem.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tsan.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/treestruct.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-vrp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-vectorizer.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-stdarg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssanames.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-threadupdate.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-threadedge.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-threadbackward.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-ter.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-scopedtables.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-sccvn.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-propagate.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-operands.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-loop.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-loop-niter.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-loop-manip.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-loop-ivopts.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-live.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-dom.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-coalesce.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-ccp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-alias.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-ssa-address.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-scalar-evolution.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-phinodes.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-pass.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-parloops.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-outof-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-object-size.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-nested.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-iterator.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-into-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-inline.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-if-conv.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-hasher.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-hash-traits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-eh.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-dump.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-diagnostic.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-dfa.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-data-ref.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-core.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-chrec.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-chkp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-check.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-cfgcleanup.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-cfg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tree-affine.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/trans-mem.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tracer.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/toplev.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tm_p.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tm.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/tm-preds.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/timevar.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/timevar.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/targhooks.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/target.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/target.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/target-insns.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/target-hooks-macros.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/target-globals.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/target-def.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/system.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sync-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/symtab.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/symbol-summary.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/substring-locations.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/stringpool.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/streamer-hooks.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/stor-layout.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/stmt.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/statistics.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/stab.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ssa.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ssa-iterators.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sreal.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/splay-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/spellcheck.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/spellcheck-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sparseset.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/signop.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/shrink-wrap.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sese.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/selftest.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/selftest-rtl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sel-sched.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sel-sched-ir.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sel-sched-dump.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sdbout.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sched-int.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sbitmap.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/sanitizer.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/safe-ctype.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/run-rtl-passes.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtlhooks-def.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtlhash.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtl.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtl-iter.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtl-error.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/rtl-chkp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/resource.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/reload.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/regset.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/regs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/regrename.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/regcprop.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/reg-notes.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/recog.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/realmpfr.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/real.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/read-rtl-function.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/read-md.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/profile.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/print-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/print-rtl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/prefix.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/predict.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/predict.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/plugin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/plugin.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/plugin-version.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/plugin-api.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/passes.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/pass_manager.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/pass-instances.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/params.list +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/params.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/params.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/params-options.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/params-list.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/params-enum.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/output.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/opts.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/opts-diagnostic.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/options.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/optabs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/optabs.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/optabs-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/optabs-query.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/optabs-libfuncs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/omp-offload.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/omp-low.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/omp-grid.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/omp-general.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/omp-expand.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/omp-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/obstack.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/objc/objc-tree.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/mode-classes.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/memory-block.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/memmodel.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/mem-stats.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/mem-stats-traits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/md5.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/machmode.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/machmode.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lto-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lto-section-names.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lto-compress.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lra.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lra-int.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lower-subreg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/loop-unroll.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/line-map.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/limity.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/limitx.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/libiberty.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/libfuncs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/lcm.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/langhooks.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/langhooks-def.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/is-a.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ira.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ira-int.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-utils.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-reference.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-ref.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-prop.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-inline.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-icf.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-icf-gimple.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ipa-chkp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/intl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/internal-fn.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/internal-fn.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/insn-notes.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/insn-modes.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/insn-flags.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/insn-constants.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/insn-codes.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/insn-addr.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/input.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/incpath.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/inchash.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ifcvt.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hwint.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hw-doloop.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hsa-common.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hsa-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hsa-brig-format.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hosthooks.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hosthooks-def.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hooks.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/highlev-plugin-common.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hashtab.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hash-traits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hash-table.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hash-set.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hash-map.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hash-map-traits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/hard-reg-set.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gtype-desc.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gtm-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gsyslimits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gsyms.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gstab.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gsstruct.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/graphite.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/graphds.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/graph.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/glimits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimplify.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimplify-me.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-walk.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-ssa.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-predict.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-match.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-low.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-iterator.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-fold.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-expr.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gimple-builder.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ggc.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ggc-internal.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gensupport.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/genrtl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gengtype.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/generic-match.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcse.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcse-common.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcov-io.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcov-counter.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcc.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcc-symtab.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcc-rich-location.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/gcc-plugin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/function.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/fold-const.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/fold-const-call.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/flags.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/flag-types.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/fixed-value.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/filenames.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/file-find.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/fibonacci_heap.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/expr.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/expmed.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/explow.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/except.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/et-forest.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/errors.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/emit-rtl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/edit-context.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dwarf2out.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dwarf2asm.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dumpfile.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/double-int.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/domwalk.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dominance.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dojump.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/diagnostic.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/diagnostic.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/diagnostic-core.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/diagnostic-color.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dfp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/df.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/defaults.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/debug.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ddg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dce.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dbxout.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dbgcnt.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/dbgcnt.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/data-streamer.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cselib.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cpplib.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cppdefault.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cppbuiltin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cp/type-utils.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cp/name-lookup.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cp/cxx-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cp/cp-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cp/cp-tree.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/coverage.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/coretypes.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/convert.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/context.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/configargs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/vxworks-dummy.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/newlib-stdint.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/initfini-array.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/x86-tune.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/unix.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/stringop.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/i386elf.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/i386.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/i386-protos.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/i386-opts.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/i386/att.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/elfos.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config/dbxelf.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/config.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/conditions.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/collect2.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/collect2-aix.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/collect-utils.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cilkplus.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cilk.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cilk-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cif-code.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/chkp-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cgraph.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfgrtl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfgloopmanip.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfgloop.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfghooks.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfgexpand.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfgcleanup.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfgbuild.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfganal.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/cfg-flags.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ccmp.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/calls.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/c-tree.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/c-family/c-pretty-print.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/c-family/c-pragma.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/c-family/c-objc.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/c-family/c-common.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/c-family/c-common.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/bversion.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/builtins.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/builtin-types.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/builtin-attrs.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/brig-builtins.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/bitmap.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/bb-reorder.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/basic-block.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/backend.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/b-header-vars +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/auto-profile.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/auto-host.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/attribs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/asan.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ansidecl.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/alloc-pool.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/all-tree.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/alias.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/addresses.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/include/ada/gcc-interface/ada-tree.def +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/plugin/gtype.state +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/libgcov.a +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/libgcc.a +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/install-tools/mkheaders.conf +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/install-tools/macro_list +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/install-tools/include/README +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/install-tools/include/limits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/install-tools/gsyslimits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/install-tools/fixinc_list +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xtestintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xsavesintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xsaveoptintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xsaveintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xsavecintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xopintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/xmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/x86intrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/wmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/varargs.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/unwind.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/tmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/tgmath.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/tbmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdnoreturn.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdint.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdint-gcc.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdfix.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stddef.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdbool.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdatomic.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdarg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/stdalign.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/smmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/shaintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/sgxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/rtmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/rdseedintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/prfchwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/popcntintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/pmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/pkuintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/nmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/mwaitxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/mmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/mm_malloc.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/mm3dnow.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/lzcntintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/lwpintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/iso646.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/immintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/ia32intrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/gcov.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/fxsrintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/fmaintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/fma4intrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/float.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/f16cintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/emmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/cross-stdarg.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/cpuid.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/clzerointrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/clwbintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/clflushoptintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/bmmintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/bmiintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/bmi2intrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512vpopcntdqintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512vlintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512vldqintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512vlbwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512vbmivlintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512vbmiintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512pfintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512ifmavlintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512ifmaintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512fintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512erintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512dqintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512cdintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx512bwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx5124vnniwintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx5124fmapsintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/avx2intrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/ammintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include/adxintrin.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include-fixed/syslimits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include-fixed/README +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/include-fixed/limits.h +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/crtend.o +gems-kernel.git/opt/cross/lib/gcc/i386-elf/7.1.0/crtbegin.o +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xw +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xu +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xsw +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xsc +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xs +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xr +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xn +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xdw +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xdc +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xd +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xc +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.xbn +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_iamcu.x +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xw +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xu +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xsw +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xsc +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xs +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xr +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xn +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xdw +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xdc +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xd +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xc +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.xbn +gems-kernel.git/opt/cross/i686-elf/lib/ldscripts/elf_i386.x +gems-kernel.git/opt/cross/i686-elf/bin/strip +gems-kernel.git/opt/cross/i686-elf/bin/readelf +gems-kernel.git/opt/cross/i686-elf/bin/ranlib +gems-kernel.git/opt/cross/i686-elf/bin/objdump +gems-kernel.git/opt/cross/i686-elf/bin/objcopy +gems-kernel.git/opt/cross/i686-elf/bin/nm +gems-kernel.git/opt/cross/i686-elf/bin/ld.bfd +gems-kernel.git/opt/cross/i686-elf/bin/ld +gems-kernel.git/opt/cross/i686-elf/bin/as +gems-kernel.git/opt/cross/i686-elf/bin/ar +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xw +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xu +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xsw +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xsc +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xs +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xr +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xn +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xdw +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xdc +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xd +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xc +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.xbn +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_iamcu.x +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xw +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xu +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xsw +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xsc +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xs +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xr +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xn +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xdw +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xdc +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xd +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xc +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.xbn +gems-kernel.git/opt/cross/i386-elf/lib/ldscripts/elf_i386.x +gems-kernel.git/opt/cross/i386-elf/bin/strip +gems-kernel.git/opt/cross/i386-elf/bin/readelf +gems-kernel.git/opt/cross/i386-elf/bin/ranlib +gems-kernel.git/opt/cross/i386-elf/bin/objdump +gems-kernel.git/opt/cross/i386-elf/bin/objcopy +gems-kernel.git/opt/cross/i386-elf/bin/nm +gems-kernel.git/opt/cross/i386-elf/bin/ld.bfd +gems-kernel.git/opt/cross/i386-elf/bin/ld +gems-kernel.git/opt/cross/i386-elf/bin/as +gems-kernel.git/opt/cross/i386-elf/bin/ar +gems-kernel.git/opt/cross/bin/i686-elf-strip +gems-kernel.git/opt/cross/bin/i686-elf-strings +gems-kernel.git/opt/cross/bin/i686-elf-size +gems-kernel.git/opt/cross/bin/i686-elf-readelf +gems-kernel.git/opt/cross/bin/i686-elf-ranlib +gems-kernel.git/opt/cross/bin/i686-elf-objdump +gems-kernel.git/opt/cross/bin/i686-elf-objcopy +gems-kernel.git/opt/cross/bin/i686-elf-nm +gems-kernel.git/opt/cross/bin/i686-elf-ld.bfd +gems-kernel.git/opt/cross/bin/i686-elf-ld +gems-kernel.git/opt/cross/bin/i686-elf-gprof +gems-kernel.git/opt/cross/bin/i686-elf-gcov-tool +gems-kernel.git/opt/cross/bin/i686-elf-gcov-dump +gems-kernel.git/opt/cross/bin/i686-elf-gcov +gems-kernel.git/opt/cross/bin/i686-elf-gcc-ranlib +gems-kernel.git/opt/cross/bin/i686-elf-gcc-nm +gems-kernel.git/opt/cross/bin/i686-elf-gcc-ar +gems-kernel.git/opt/cross/bin/i686-elf-gcc-7.1.0 +gems-kernel.git/opt/cross/bin/i686-elf-gcc +gems-kernel.git/opt/cross/bin/i686-elf-g++ +gems-kernel.git/opt/cross/bin/i686-elf-elfedit +gems-kernel.git/opt/cross/bin/i686-elf-cpp +gems-kernel.git/opt/cross/bin/i686-elf-c++filt +gems-kernel.git/opt/cross/bin/i686-elf-c++ +gems-kernel.git/opt/cross/bin/i686-elf-as +gems-kernel.git/opt/cross/bin/i686-elf-ar +gems-kernel.git/opt/cross/bin/i686-elf-addr2line +gems-kernel.git/opt/cross/bin/i386-elf-strip +gems-kernel.git/opt/cross/bin/i386-elf-strings +gems-kernel.git/opt/cross/bin/i386-elf-size +gems-kernel.git/opt/cross/bin/i386-elf-readelf +gems-kernel.git/opt/cross/bin/i386-elf-ranlib +gems-kernel.git/opt/cross/bin/i386-elf-objdump +gems-kernel.git/opt/cross/bin/i386-elf-objcopy +gems-kernel.git/opt/cross/bin/i386-elf-nm +gems-kernel.git/opt/cross/bin/i386-elf-ld.bfd +gems-kernel.git/opt/cross/bin/i386-elf-ld +gems-kernel.git/opt/cross/bin/i386-elf-gprof +gems-kernel.git/opt/cross/bin/i386-elf-gcov-tool +gems-kernel.git/opt/cross/bin/i386-elf-gcov-dump +gems-kernel.git/opt/cross/bin/i386-elf-gcov +gems-kernel.git/opt/cross/bin/i386-elf-gcc-ranlib +gems-kernel.git/opt/cross/bin/i386-elf-gcc-nm +gems-kernel.git/opt/cross/bin/i386-elf-gcc-ar +gems-kernel.git/opt/cross/bin/i386-elf-gcc-7.1.0 +gems-kernel.git/opt/cross/bin/i386-elf-gcc +gems-kernel.git/opt/cross/bin/i386-elf-g++ +gems-kernel.git/opt/cross/bin/i386-elf-elfedit +gems-kernel.git/opt/cross/bin/i386-elf-cpp +gems-kernel.git/opt/cross/bin/i386-elf-c++filt +gems-kernel.git/opt/cross/bin/i386-elf-c++ +gems-kernel.git/opt/cross/bin/i386-elf-as +gems-kernel.git/opt/cross/bin/i386-elf-ar +gems-kernel.git/opt/cross/bin/i386-elf-addr2line diff --git a/gems-kernel.git/opt/cross/share/man/man7/fsf-funding.7 b/gems-kernel.git/opt/cross/share/man/man7/fsf-funding.7 new file mode 100644 index 000000000..7db7b99de --- /dev/null +++ b/gems-kernel.git/opt/cross/share/man/man7/fsf-funding.7 @@ -0,0 +1,189 @@ +.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "FSF-FUNDING 7" +.TH FSF-FUNDING 7 "2017-05-02" "gcc-7.1.0" "GNU" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +fsf\-funding \- Funding Free Software +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +.SS "Funding Free Software" +.IX Subsection "Funding Free Software" +If you want to have more free software a few years from now, it makes +sense for you to help encourage people to contribute funds for its +development. The most effective approach known is to encourage +commercial redistributors to donate. +.PP +Users of free software systems can boost the pace of development by +encouraging for-a-fee distributors to donate part of their selling price +to free software developers\-\-\-the Free Software Foundation, and others. +.PP +The way to convince distributors to do this is to demand it and expect +it from them. So when you compare distributors, judge them partly by +how much they give to free software development. Show distributors +they must compete to be the one who gives the most. +.PP +To make this approach work, you must insist on numbers that you can +compare, such as, \*(L"We will donate ten dollars to the Frobnitz project +for each disk sold.\*(R" Don't be satisfied with a vague promise, such as +\&\*(L"A portion of the profits are donated,\*(R" since it doesn't give a basis +for comparison. +.PP +Even a precise fraction \*(L"of the profits from this disk\*(R" is not very +meaningful, since creative accounting and unrelated business decisions +can greatly alter what fraction of the sales price counts as profit. +If the price you pay is \f(CW$50\fR, ten percent of the profit is probably +less than a dollar; it might be a few cents, or nothing at all. +.PP +Some redistributors do development work themselves. This is useful too; +but to keep everyone honest, you need to inquire how much they do, and +what kind. Some kinds of development make much more long-term +difference than others. For example, maintaining a separate version of +a program contributes very little; maintaining the standard version of a +program for the whole community contributes much. Easy new ports +contribute little, since someone else would surely do them; difficult +ports such as adding a new \s-1CPU\s0 to the \s-1GNU\s0 Compiler Collection contribute more; +major new features or packages contribute the most. +.PP +By establishing the idea that supporting further development is \*(L"the +proper thing to do\*(R" when distributing free software for a fee, we can +assure a steady flow of resources into making more free software. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIgpl\fR\|(7), \fIgfdl\fR\|(7). +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 1994 Free Software Foundation, Inc. +Verbatim copying and redistribution of this section is permitted +without royalty; alteration is not permitted. diff --git a/gems-kernel.git/opt/cross/share/man/man7/gfdl.7 b/gems-kernel.git/opt/cross/share/man/man7/gfdl.7 new file mode 100644 index 000000000..21eee00ba --- /dev/null +++ b/gems-kernel.git/opt/cross/share/man/man7/gfdl.7 @@ -0,0 +1,647 @@ +.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "GFDL 7" +.TH GFDL 7 "2017-05-02" "gcc-7.1.0" "GNU" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +gfdl \- GNU Free Documentation License +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +\&\f(CW@comment\fR For some cases, this default \f(CW@node\fR/@unnumbered is not applicable and +\&\f(CW@comment\fR causes warnings. In those cases, the including file can set +\&\f(CW@comment\fR nodefaultgnufreedocumentationlicensenode and provide it's own version. +\&\f(CW@comment\fR F.i., when this file is included in an \f(CW@raisesections\fR context, the +\&\f(CW@comment\fR including file can use an \f(CW@unnumberedsec\fR. +.SS "\s-1GNU\s0 Free Documentation License" +.IX Subsection "GNU Free Documentation License" +.SS "Version 1.3, 3 November 2008" +.IX Subsection "Version 1.3, 3 November 2008" +.Vb 2 +\& Copyright (c) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. +\& EBE +\& +\& Everyone is permitted to copy and distribute verbatim copies +\& of this license document, but changing it is not allowed. +.Ve +.IP "0." 4 +.IX Item "0." +\&\s-1PREAMBLE\s0 +.Sp +The purpose of this License is to make a manual, textbook, or other +functional and useful document \fIfree\fR in the sense of freedom: to +assure everyone the effective freedom to copy and redistribute it, +with or without modifying it, either commercially or noncommercially. +Secondarily, this License preserves for the author and publisher a way +to get credit for their work, while not being considered responsible +for modifications made by others. +.Sp +This License is a kind of \*(L"copyleft\*(R", which means that derivative +works of the document must themselves be free in the same sense. It +complements the \s-1GNU\s0 General Public License, which is a copyleft +license designed for free software. +.Sp +We have designed this License in order to use it for manuals for free +software, because free software needs free documentation: a free +program should come with manuals providing the same freedoms that the +software does. But this License is not limited to software manuals; +it can be used for any textual work, regardless of subject matter or +whether it is published as a printed book. We recommend this License +principally for works whose purpose is instruction or reference. +.IP "1." 4 +.IX Item "1." +\&\s-1APPLICABILITY AND DEFINITIONS\s0 +.Sp +This License applies to any manual or other work, in any medium, that +contains a notice placed by the copyright holder saying it can be +distributed under the terms of this License. Such a notice grants a +world-wide, royalty-free license, unlimited in duration, to use that +work under the conditions stated herein. The \*(L"Document\*(R", below, +refers to any such manual or work. Any member of the public is a +licensee, and is addressed as \*(L"you\*(R". You accept the license if you +copy, modify or distribute the work in a way requiring permission +under copyright law. +.Sp +A \*(L"Modified Version\*(R" of the Document means any work containing the +Document or a portion of it, either copied verbatim, or with +modifications and/or translated into another language. +.Sp +A \*(L"Secondary Section\*(R" is a named appendix or a front-matter section +of the Document that deals exclusively with the relationship of the +publishers or authors of the Document to the Document's overall +subject (or to related matters) and contains nothing that could fall +directly within that overall subject. (Thus, if the Document is in +part a textbook of mathematics, a Secondary Section may not explain +any mathematics.) The relationship could be a matter of historical +connection with the subject or with related matters, or of legal, +commercial, philosophical, ethical or political position regarding +them. +.Sp +The \*(L"Invariant Sections\*(R" are certain Secondary Sections whose titles +are designated, as being those of Invariant Sections, in the notice +that says that the Document is released under this License. If a +section does not fit the above definition of Secondary then it is not +allowed to be designated as Invariant. The Document may contain zero +Invariant Sections. If the Document does not identify any Invariant +Sections then there are none. +.Sp +The \*(L"Cover Texts\*(R" are certain short passages of text that are listed, +as Front-Cover Texts or Back-Cover Texts, in the notice that says that +the Document is released under this License. A Front-Cover Text may +be at most 5 words, and a Back-Cover Text may be at most 25 words. +.Sp +A \*(L"Transparent\*(R" copy of the Document means a machine-readable copy, +represented in a format whose specification is available to the +general public, that is suitable for revising the document +straightforwardly with generic text editors or (for images composed of +pixels) generic paint programs or (for drawings) some widely available +drawing editor, and that is suitable for input to text formatters or +for automatic translation to a variety of formats suitable for input +to text formatters. A copy made in an otherwise Transparent file +format whose markup, or absence of markup, has been arranged to thwart +or discourage subsequent modification by readers is not Transparent. +An image format is not Transparent if used for any substantial amount +of text. A copy that is not \*(L"Transparent\*(R" is called \*(L"Opaque\*(R". +.Sp +Examples of suitable formats for Transparent copies include plain +\&\s-1ASCII\s0 without markup, Texinfo input format, LaTeX input +format, \s-1SGML\s0 or \s-1XML\s0 using a publicly available +\&\s-1DTD,\s0 and standard-conforming simple \s-1HTML,\s0 +PostScript or \s-1PDF\s0 designed for human modification. Examples +of transparent image formats include \s-1PNG, XCF\s0 and +\&\s-1JPG.\s0 Opaque formats include proprietary formats that can be +read and edited only by proprietary word processors, \s-1SGML\s0 or +\&\s-1XML\s0 for which the \s-1DTD\s0 and/or processing tools are +not generally available, and the machine-generated \s-1HTML,\s0 +PostScript or \s-1PDF\s0 produced by some word processors for +output purposes only. +.Sp +The \*(L"Title Page\*(R" means, for a printed book, the title page itself, +plus such following pages as are needed to hold, legibly, the material +this License requires to appear in the title page. For works in +formats which do not have any title page as such, \*(L"Title Page\*(R" means +the text near the most prominent appearance of the work's title, +preceding the beginning of the body of the text. +.Sp +The \*(L"publisher\*(R" means any person or entity that distributes copies +of the Document to the public. +.Sp +A section \*(L"Entitled \s-1XYZ\*(R"\s0 means a named subunit of the Document whose +title either is precisely \s-1XYZ\s0 or contains \s-1XYZ\s0 in parentheses following +text that translates \s-1XYZ\s0 in another language. (Here \s-1XYZ\s0 stands for a +specific section name mentioned below, such as \*(L"Acknowledgements\*(R", +\&\*(L"Dedications\*(R", \*(L"Endorsements\*(R", or \*(L"History\*(R".) To \*(L"Preserve the Title\*(R" +of such a section when you modify the Document means that it remains a +section \*(L"Entitled \s-1XYZ\*(R"\s0 according to this definition. +.Sp +The Document may include Warranty Disclaimers next to the notice which +states that this License applies to the Document. These Warranty +Disclaimers are considered to be included by reference in this +License, but only as regards disclaiming warranties: any other +implication that these Warranty Disclaimers may have is void and has +no effect on the meaning of this License. +.IP "2." 4 +.IX Item "2." +\&\s-1VERBATIM COPYING\s0 +.Sp +You may copy and distribute the Document in any medium, either +commercially or noncommercially, provided that this License, the +copyright notices, and the license notice saying this License applies +to the Document are reproduced in all copies, and that you add no other +conditions whatsoever to those of this License. You may not use +technical measures to obstruct or control the reading or further +copying of the copies you make or distribute. However, you may accept +compensation in exchange for copies. If you distribute a large enough +number of copies you must also follow the conditions in section 3. +.Sp +You may also lend copies, under the same conditions stated above, and +you may publicly display copies. +.IP "3." 4 +.IX Item "3." +\&\s-1COPYING IN QUANTITY\s0 +.Sp +If you publish printed copies (or copies in media that commonly have +printed covers) of the Document, numbering more than 100, and the +Document's license notice requires Cover Texts, you must enclose the +copies in covers that carry, clearly and legibly, all these Cover +Texts: Front-Cover Texts on the front cover, and Back-Cover Texts on +the back cover. Both covers must also clearly and legibly identify +you as the publisher of these copies. The front cover must present +the full title with all words of the title equally prominent and +visible. You may add other material on the covers in addition. +Copying with changes limited to the covers, as long as they preserve +the title of the Document and satisfy these conditions, can be treated +as verbatim copying in other respects. +.Sp +If the required texts for either cover are too voluminous to fit +legibly, you should put the first ones listed (as many as fit +reasonably) on the actual cover, and continue the rest onto adjacent +pages. +.Sp +If you publish or distribute Opaque copies of the Document numbering +more than 100, you must either include a machine-readable Transparent +copy along with each Opaque copy, or state in or with each Opaque copy +a computer-network location from which the general network-using +public has access to download using public-standard network protocols +a complete Transparent copy of the Document, free of added material. +If you use the latter option, you must take reasonably prudent steps, +when you begin distribution of Opaque copies in quantity, to ensure +that this Transparent copy will remain thus accessible at the stated +location until at least one year after the last time you distribute an +Opaque copy (directly or through your agents or retailers) of that +edition to the public. +.Sp +It is requested, but not required, that you contact the authors of the +Document well before redistributing any large number of copies, to give +them a chance to provide you with an updated version of the Document. +.IP "4." 4 +.IX Item "4." +\&\s-1MODIFICATIONS\s0 +.Sp +You may copy and distribute a Modified Version of the Document under +the conditions of sections 2 and 3 above, provided that you release +the Modified Version under precisely this License, with the Modified +Version filling the role of the Document, thus licensing distribution +and modification of the Modified Version to whoever possesses a copy +of it. In addition, you must do these things in the Modified Version: +.RS 4 +.IP "A." 4 +.IX Item "A." +Use in the Title Page (and on the covers, if any) a title distinct +from that of the Document, and from those of previous versions +(which should, if there were any, be listed in the History section +of the Document). You may use the same title as a previous version +if the original publisher of that version gives permission. +.IP "B." 4 +.IX Item "B." +List on the Title Page, as authors, one or more persons or entities +responsible for authorship of the modifications in the Modified +Version, together with at least five of the principal authors of the +Document (all of its principal authors, if it has fewer than five), +unless they release you from this requirement. +.IP "C." 4 +.IX Item "C." +State on the Title page the name of the publisher of the +Modified Version, as the publisher. +.IP "D." 4 +.IX Item "D." +Preserve all the copyright notices of the Document. +.IP "E." 4 +.IX Item "E." +Add an appropriate copyright notice for your modifications +adjacent to the other copyright notices. +.IP "F." 4 +.IX Item "F." +Include, immediately after the copyright notices, a license notice +giving the public permission to use the Modified Version under the +terms of this License, in the form shown in the Addendum below. +.IP "G." 4 +.IX Item "G." +Preserve in that license notice the full lists of Invariant Sections +and required Cover Texts given in the Document's license notice. +.IP "H." 4 +.IX Item "H." +Include an unaltered copy of this License. +.IP "I." 4 +.IX Item "I." +Preserve the section Entitled \*(L"History\*(R", Preserve its Title, and add +to it an item stating at least the title, year, new authors, and +publisher of the Modified Version as given on the Title Page. If +there is no section Entitled \*(L"History\*(R" in the Document, create one +stating the title, year, authors, and publisher of the Document as +given on its Title Page, then add an item describing the Modified +Version as stated in the previous sentence. +.IP "J." 4 +.IX Item "J." +Preserve the network location, if any, given in the Document for +public access to a Transparent copy of the Document, and likewise +the network locations given in the Document for previous versions +it was based on. These may be placed in the \*(L"History\*(R" section. +You may omit a network location for a work that was published at +least four years before the Document itself, or if the original +publisher of the version it refers to gives permission. +.IP "K." 4 +.IX Item "K." +For any section Entitled \*(L"Acknowledgements\*(R" or \*(L"Dedications\*(R", Preserve +the Title of the section, and preserve in the section all the +substance and tone of each of the contributor acknowledgements and/or +dedications given therein. +.IP "L." 4 +.IX Item "L." +Preserve all the Invariant Sections of the Document, +unaltered in their text and in their titles. Section numbers +or the equivalent are not considered part of the section titles. +.IP "M." 4 +.IX Item "M." +Delete any section Entitled \*(L"Endorsements\*(R". Such a section +may not be included in the Modified Version. +.IP "N." 4 +.IX Item "N." +Do not retitle any existing section to be Entitled \*(L"Endorsements\*(R" or +to conflict in title with any Invariant Section. +.IP "O." 4 +.IX Item "O." +Preserve any Warranty Disclaimers. +.RE +.RS 4 +.Sp +If the Modified Version includes new front-matter sections or +appendices that qualify as Secondary Sections and contain no material +copied from the Document, you may at your option designate some or all +of these sections as invariant. To do this, add their titles to the +list of Invariant Sections in the Modified Version's license notice. +These titles must be distinct from any other section titles. +.Sp +You may add a section Entitled \*(L"Endorsements\*(R", provided it contains +nothing but endorsements of your Modified Version by various +parties\-\-\-for example, statements of peer review or that the text has +been approved by an organization as the authoritative definition of a +standard. +.Sp +You may add a passage of up to five words as a Front-Cover Text, and a +passage of up to 25 words as a Back-Cover Text, to the end of the list +of Cover Texts in the Modified Version. Only one passage of +Front-Cover Text and one of Back-Cover Text may be added by (or +through arrangements made by) any one entity. If the Document already +includes a cover text for the same cover, previously added by you or +by arrangement made by the same entity you are acting on behalf of, +you may not add another; but you may replace the old one, on explicit +permission from the previous publisher that added the old one. +.Sp +The author(s) and publisher(s) of the Document do not by this License +give permission to use their names for publicity for or to assert or +imply endorsement of any Modified Version. +.RE +.IP "5." 4 +.IX Item "5." +\&\s-1COMBINING DOCUMENTS\s0 +.Sp +You may combine the Document with other documents released under this +License, under the terms defined in section 4 above for modified +versions, provided that you include in the combination all of the +Invariant Sections of all of the original documents, unmodified, and +list them all as Invariant Sections of your combined work in its +license notice, and that you preserve all their Warranty Disclaimers. +.Sp +The combined work need only contain one copy of this License, and +multiple identical Invariant Sections may be replaced with a single +copy. If there are multiple Invariant Sections with the same name but +different contents, make the title of each such section unique by +adding at the end of it, in parentheses, the name of the original +author or publisher of that section if known, or else a unique number. +Make the same adjustment to the section titles in the list of +Invariant Sections in the license notice of the combined work. +.Sp +In the combination, you must combine any sections Entitled \*(L"History\*(R" +in the various original documents, forming one section Entitled +\&\*(L"History\*(R"; likewise combine any sections Entitled \*(L"Acknowledgements\*(R", +and any sections Entitled \*(L"Dedications\*(R". You must delete all +sections Entitled \*(L"Endorsements.\*(R" +.IP "6." 4 +.IX Item "6." +\&\s-1COLLECTIONS OF DOCUMENTS\s0 +.Sp +You may make a collection consisting of the Document and other documents +released under this License, and replace the individual copies of this +License in the various documents with a single copy that is included in +the collection, provided that you follow the rules of this License for +verbatim copying of each of the documents in all other respects. +.Sp +You may extract a single document from such a collection, and distribute +it individually under this License, provided you insert a copy of this +License into the extracted document, and follow this License in all +other respects regarding verbatim copying of that document. +.IP "7." 4 +.IX Item "7." +\&\s-1AGGREGATION WITH INDEPENDENT WORKS\s0 +.Sp +A compilation of the Document or its derivatives with other separate +and independent documents or works, in or on a volume of a storage or +distribution medium, is called an \*(L"aggregate\*(R" if the copyright +resulting from the compilation is not used to limit the legal rights +of the compilation's users beyond what the individual works permit. +When the Document is included in an aggregate, this License does not +apply to the other works in the aggregate which are not themselves +derivative works of the Document. +.Sp +If the Cover Text requirement of section 3 is applicable to these +copies of the Document, then if the Document is less than one half of +the entire aggregate, the Document's Cover Texts may be placed on +covers that bracket the Document within the aggregate, or the +electronic equivalent of covers if the Document is in electronic form. +Otherwise they must appear on printed covers that bracket the whole +aggregate. +.IP "8." 4 +.IX Item "8." +\&\s-1TRANSLATION\s0 +.Sp +Translation is considered a kind of modification, so you may +distribute translations of the Document under the terms of section 4. +Replacing Invariant Sections with translations requires special +permission from their copyright holders, but you may include +translations of some or all Invariant Sections in addition to the +original versions of these Invariant Sections. You may include a +translation of this License, and all the license notices in the +Document, and any Warranty Disclaimers, provided that you also include +the original English version of this License and the original versions +of those notices and disclaimers. In case of a disagreement between +the translation and the original version of this License or a notice +or disclaimer, the original version will prevail. +.Sp +If a section in the Document is Entitled \*(L"Acknowledgements\*(R", +\&\*(L"Dedications\*(R", or \*(L"History\*(R", the requirement (section 4) to Preserve +its Title (section 1) will typically require changing the actual +title. +.IP "9." 4 +.IX Item "9." +\&\s-1TERMINATION\s0 +.Sp +You may not copy, modify, sublicense, or distribute the Document +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense, or distribute it is void, and +will automatically terminate your rights under this License. +.Sp +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. +.Sp +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. +.Sp +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, receipt of a copy of some or all of the same material does +not give you any rights to use it. +.IP "10." 4 +.IX Item "10." +\&\s-1FUTURE REVISIONS OF THIS LICENSE\s0 +.Sp +The Free Software Foundation may publish new, revised versions +of the \s-1GNU\s0 Free Documentation License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. See +<\fBhttp://www.gnu.org/copyleft/\fR>. +.Sp +Each version of the License is given a distinguishing version number. +If the Document specifies that a particular numbered version of this +License \*(L"or any later version\*(R" applies to it, you have the option of +following the terms and conditions either of that specified version or +of any later version that has been published (not as a draft) by the +Free Software Foundation. If the Document does not specify a version +number of this License, you may choose any version ever published (not +as a draft) by the Free Software Foundation. If the Document +specifies that a proxy can decide which future versions of this +License can be used, that proxy's public statement of acceptance of a +version permanently authorizes you to choose that version for the +Document. +.IP "11." 4 +.IX Item "11." +\&\s-1RELICENSING\s0 +.Sp +\&\*(L"Massive Multiauthor Collaboration Site\*(R" (or \*(L"\s-1MMC\s0 Site\*(R") means any +World Wide Web server that publishes copyrightable works and also +provides prominent facilities for anybody to edit those works. A +public wiki that anybody can edit is an example of such a server. A +\&\*(L"Massive Multiauthor Collaboration\*(R" (or \*(L"\s-1MMC\*(R"\s0) contained in the +site means any set of copyrightable works thus published on the \s-1MMC\s0 +site. +.Sp +\&\*(L"CC-BY-SA\*(R" means the Creative Commons Attribution-Share Alike 3.0 +license published by Creative Commons Corporation, a not-for-profit +corporation with a principal place of business in San Francisco, +California, as well as future copyleft versions of that license +published by that same organization. +.Sp +\&\*(L"Incorporate\*(R" means to publish or republish a Document, in whole or +in part, as part of another Document. +.Sp +An \s-1MMC\s0 is \*(L"eligible for relicensing\*(R" if it is licensed under this +License, and if all works that were first published under this License +somewhere other than this \s-1MMC,\s0 and subsequently incorporated in whole +or in part into the \s-1MMC,\s0 (1) had no cover texts or invariant sections, +and (2) were thus incorporated prior to November 1, 2008. +.Sp +The operator of an \s-1MMC\s0 Site may republish an \s-1MMC\s0 contained in the site +under CC-BY-SA on the same site at any time before August 1, 2009, +provided the \s-1MMC\s0 is eligible for relicensing. +.SS "\s-1ADDENDUM:\s0 How to use this License for your documents" +.IX Subsection "ADDENDUM: How to use this License for your documents" +To use this License in a document you have written, include a copy of +the License in the document and put the following copyright and +license notices just after the title page: +.PP +.Vb 7 +\& Copyright (C) . +\& Permission is granted to copy, distribute and/or modify this document +\& under the terms of the GNU Free Documentation License, Version 1.3 +\& or any later version published by the Free Software Foundation; +\& with no Invariant Sections, no Front\-Cover Texts, and no Back\-Cover +\& Texts. A copy of the license is included in the section entitled "GNU +\& Free Documentation License". +.Ve +.PP +If you have Invariant Sections, Front-Cover Texts and Back-Cover Texts, +replace the \*(L"with...Texts.\*(R" line with this: +.PP +.Vb 3 +\& with the Invariant Sections being , with +\& the Front\-Cover Texts being , and with the Back\-Cover Texts +\& being . +.Ve +.PP +If you have Invariant Sections without Cover Texts, or some other +combination of the three, merge those two alternatives to suit the +situation. +.PP +If your document contains nontrivial examples of program code, we +recommend releasing these examples in parallel under your choice of +free software license, such as the \s-1GNU\s0 General Public License, +to permit their use in free software. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIgpl\fR\|(7), \fIfsf\-funding\fR\|(7). +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 2000, 2001, 2002, 2007, 2008 Free Software Foundation, Inc. +<\fBhttp://fsf.org/\fR> +.PP +Everyone is permitted to copy and distribute verbatim copies +of this license document, but changing it is not allowed. diff --git a/gems-kernel.git/opt/cross/share/man/man7/gpl.7 b/gems-kernel.git/opt/cross/share/man/man7/gpl.7 new file mode 100644 index 000000000..77eccfc02 --- /dev/null +++ b/gems-kernel.git/opt/cross/share/man/man7/gpl.7 @@ -0,0 +1,846 @@ +.\" Automatically generated by Pod::Man 4.09 (Pod::Simple 3.35) +.\" +.\" Standard preamble: +.\" ======================================================================== +.de Sp \" Vertical space (when we can't use .PP) +.if t .sp .5v +.if n .sp +.. +.de Vb \" Begin verbatim text +.ft CW +.nf +.ne \\$1 +.. +.de Ve \" End verbatim text +.ft R +.fi +.. +.\" Set up some character translations and predefined strings. \*(-- will +.\" give an unbreakable dash, \*(PI will give pi, \*(L" will give a left +.\" double quote, and \*(R" will give a right double quote. \*(C+ will +.\" give a nicer C++. Capital omega is used to do unbreakable dashes and +.\" therefore won't be available. \*(C` and \*(C' expand to `' in nroff, +.\" nothing in troff, for use with C<>. +.tr \(*W- +.ds C+ C\v'-.1v'\h'-1p'\s-2+\h'-1p'+\s0\v'.1v'\h'-1p' +.ie n \{\ +. ds -- \(*W- +. ds PI pi +. if (\n(.H=4u)&(1m=24u) .ds -- \(*W\h'-12u'\(*W\h'-12u'-\" diablo 10 pitch +. if (\n(.H=4u)&(1m=20u) .ds -- \(*W\h'-12u'\(*W\h'-8u'-\" diablo 12 pitch +. ds L" "" +. ds R" "" +. ds C` "" +. ds C' "" +'br\} +.el\{\ +. ds -- \|\(em\| +. ds PI \(*p +. ds L" `` +. ds R" '' +. ds C` +. ds C' +'br\} +.\" +.\" Escape single quotes in literal strings from groff's Unicode transform. +.ie \n(.g .ds Aq \(aq +.el .ds Aq ' +.\" +.\" If the F register is >0, we'll generate index entries on stderr for +.\" titles (.TH), headers (.SH), subsections (.SS), items (.Ip), and index +.\" entries marked with X<> in POD. Of course, you'll have to process the +.\" output yourself in some meaningful fashion. +.\" +.\" Avoid warning from groff about undefined register 'F'. +.de IX +.. +.if !\nF .nr F 0 +.if \nF>0 \{\ +. de IX +. tm Index:\\$1\t\\n%\t"\\$2" +.. +. if !\nF==2 \{\ +. nr % 0 +. nr F 2 +. \} +.\} +.\" +.\" Accent mark definitions (@(#)ms.acc 1.5 88/02/08 SMI; from UCB 4.2). +.\" Fear. Run. Save yourself. No user-serviceable parts. +. \" fudge factors for nroff and troff +.if n \{\ +. ds #H 0 +. ds #V .8m +. ds #F .3m +. ds #[ \f1 +. ds #] \fP +.\} +.if t \{\ +. ds #H ((1u-(\\\\n(.fu%2u))*.13m) +. ds #V .6m +. ds #F 0 +. ds #[ \& +. ds #] \& +.\} +. \" simple accents for nroff and troff +.if n \{\ +. ds ' \& +. ds ` \& +. ds ^ \& +. ds , \& +. ds ~ ~ +. ds / +.\} +.if t \{\ +. ds ' \\k:\h'-(\\n(.wu*8/10-\*(#H)'\'\h"|\\n:u" +. ds ` \\k:\h'-(\\n(.wu*8/10-\*(#H)'\`\h'|\\n:u' +. ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'^\h'|\\n:u' +. ds , \\k:\h'-(\\n(.wu*8/10)',\h'|\\n:u' +. ds ~ \\k:\h'-(\\n(.wu-\*(#H-.1m)'~\h'|\\n:u' +. ds / \\k:\h'-(\\n(.wu*8/10-\*(#H)'\z\(sl\h'|\\n:u' +.\} +. \" troff and (daisy-wheel) nroff accents +.ds : \\k:\h'-(\\n(.wu*8/10-\*(#H+.1m+\*(#F)'\v'-\*(#V'\z.\h'.2m+\*(#F'.\h'|\\n:u'\v'\*(#V' +.ds 8 \h'\*(#H'\(*b\h'-\*(#H' +.ds o \\k:\h'-(\\n(.wu+\w'\(de'u-\*(#H)/2u'\v'-.3n'\*(#[\z\(de\v'.3n'\h'|\\n:u'\*(#] +.ds d- \h'\*(#H'\(pd\h'-\w'~'u'\v'-.25m'\f2\(hy\fP\v'.25m'\h'-\*(#H' +.ds D- D\\k:\h'-\w'D'u'\v'-.11m'\z\(hy\v'.11m'\h'|\\n:u' +.ds th \*(#[\v'.3m'\s+1I\s-1\v'-.3m'\h'-(\w'I'u*2/3)'\s-1o\s+1\*(#] +.ds Th \*(#[\s+2I\s-2\h'-\w'I'u*3/5'\v'-.3m'o\v'.3m'\*(#] +.ds ae a\h'-(\w'a'u*4/10)'e +.ds Ae A\h'-(\w'A'u*4/10)'E +. \" corrections for vroff +.if v .ds ~ \\k:\h'-(\\n(.wu*9/10-\*(#H)'\s-2\u~\d\s+2\h'|\\n:u' +.if v .ds ^ \\k:\h'-(\\n(.wu*10/11-\*(#H)'\v'-.4m'^\v'.4m'\h'|\\n:u' +. \" for low resolution devices (crt and lpr) +.if \n(.H>23 .if \n(.V>19 \ +\{\ +. ds : e +. ds 8 ss +. ds o a +. ds d- d\h'-1'\(ga +. ds D- D\h'-1'\(hy +. ds th \o'bp' +. ds Th \o'LP' +. ds ae ae +. ds Ae AE +.\} +.rm #[ #] #H #V #F C +.\" ======================================================================== +.\" +.IX Title "GPL 7" +.TH GPL 7 "2017-05-02" "gcc-7.1.0" "GNU" +.\" For nroff, turn off justification. Always turn off hyphenation; it makes +.\" way too many mistakes in technical documents. +.if n .ad l +.nh +.SH "NAME" +gpl \- GNU General Public License +.SH "DESCRIPTION" +.IX Header "DESCRIPTION" +.SS "\s-1GNU\s0 General Public License" +.IX Subsection "GNU General Public License" +.SS "Version 3, 29 June 2007" +.IX Subsection "Version 3, 29 June 2007" +.Vb 1 +\& Copyright (c) 2007 Free Software Foundation, Inc. +\& +\& Everyone is permitted to copy and distribute verbatim copies of this +\& license document, but changing it is not allowed. +.Ve +.SS "Preamble" +.IX Subsection "Preamble" +The \s-1GNU\s0 General Public License is a free, copyleft license for +software and other kinds of works. +.PP +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the \s-1GNU\s0 General Public License is intended to guarantee your freedom +to share and change all versions of a program\*(--to make sure it remains +free software for all its users. We, the Free Software Foundation, +use the \s-1GNU\s0 General Public License for most of our software; it +applies also to any other work released this way by its authors. You +can apply it to your programs, too. +.PP +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. +.PP +To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you +have certain responsibilities if you distribute copies of the +software, or if you modify it: responsibilities to respect the freedom +of others. +.PP +For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, +receive or can get the source code. And you must show them these +terms so they know their rights. +.PP +Developers that use the \s-1GNU GPL\s0 protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. +.PP +For the developers' and authors' protection, the \s-1GPL\s0 clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the \s-1GPL\s0 requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. +.PP +Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the +manufacturer can do so. This is fundamentally incompatible with the +aim of protecting users' freedom to change the software. The +systematic pattern of such abuse occurs in the area of products for +individuals to use, which is precisely where it is most unacceptable. +Therefore, we have designed this version of the \s-1GPL\s0 to prohibit the +practice for those products. If such problems arise substantially in +other domains, we stand ready to extend this provision to those +domains in future versions of the \s-1GPL,\s0 as needed to protect the +freedom of users. +.PP +Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish +to avoid the special danger that patents applied to a free program +could make it effectively proprietary. To prevent this, the \s-1GPL\s0 +assures that patents cannot be used to render the program non-free. +.PP +The precise terms and conditions for copying, distribution and +modification follow. +.SS "\s-1TERMS AND CONDITIONS\s0" +.IX Subsection "TERMS AND CONDITIONS" +.IP "0. Definitions." 4 +.IX Item "0. Definitions." +\&\*(L"This License\*(R" refers to version 3 of the \s-1GNU\s0 General Public License. +.Sp +\&\*(L"Copyright\*(R" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. +.Sp +\&\*(L"The Program\*(R" refers to any copyrightable work licensed under this +License. Each licensee is addressed as \*(L"you\*(R". \*(L"Licensees\*(R" and +\&\*(L"recipients\*(R" may be individuals or organizations. +.Sp +To \*(L"modify\*(R" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a \*(L"modified version\*(R" of +the earlier work or a work \*(L"based on\*(R" the earlier work. +.Sp +A \*(L"covered work\*(R" means either the unmodified Program or a work based +on the Program. +.Sp +To \*(L"propagate\*(R" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. +.Sp +To \*(L"convey\*(R" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. +.Sp +An interactive user interface displays \*(L"Appropriate Legal Notices\*(R" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. +.IP "1. Source Code." 4 +.IX Item "1. Source Code." +The \*(L"source code\*(R" for a work means the preferred form of the work for +making modifications to it. \*(L"Object code\*(R" means any non-source form +of a work. +.Sp +A \*(L"Standard Interface\*(R" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. +.Sp +The \*(L"System Libraries\*(R" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +\&\*(L"Major Component\*(R", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. +.Sp +The \*(L"Corresponding Source\*(R" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. +.Sp +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. +.Sp +The Corresponding Source for a work in source code form is that same +work. +.IP "2. Basic Permissions." 4 +.IX Item "2. Basic Permissions." +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. +.Sp +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. +.Sp +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. +.IP "3. Protecting Users' Legal Rights From Anti-Circumvention Law." 4 +.IX Item "3. Protecting Users' Legal Rights From Anti-Circumvention Law." +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the \s-1WIPO\s0 copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. +.Sp +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. +.IP "4. Conveying Verbatim Copies." 4 +.IX Item "4. Conveying Verbatim Copies." +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. +.Sp +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. +.IP "5. Conveying Modified Source Versions." 4 +.IX Item "5. Conveying Modified Source Versions." +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: +.RS 4 +.IP "a." 4 +.IX Item "a." +The work must carry prominent notices stating that you modified it, +and giving a relevant date. +.IP "b." 4 +.IX Item "b." +The work must carry prominent notices stating that it is released +under this License and any conditions added under section 7. This +requirement modifies the requirement in section 4 to \*(L"keep intact all +notices\*(R". +.IP "c." 4 +.IX Item "c." +You must license the entire work, as a whole, under this License to +anyone who comes into possession of a copy. This License will +therefore apply, along with any applicable section 7 additional terms, +to the whole of the work, and all its parts, regardless of how they +are packaged. This License gives no permission to license the work in +any other way, but it does not invalidate such permission if you have +separately received it. +.IP "d." 4 +.IX Item "d." +If the work has interactive user interfaces, each must display +Appropriate Legal Notices; however, if the Program has interactive +interfaces that do not display Appropriate Legal Notices, your work +need not make them do so. +.RE +.RS 4 +.Sp +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +\&\*(L"aggregate\*(R" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. +.RE +.IP "6. Conveying Non-Source Forms." 4 +.IX Item "6. Conveying Non-Source Forms." +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: +.RS 4 +.IP "a." 4 +.IX Item "a." +Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by the +Corresponding Source fixed on a durable physical medium customarily +used for software interchange. +.IP "b." 4 +.IX Item "b." +Convey the object code in, or embodied in, a physical product +(including a physical distribution medium), accompanied by a written +offer, valid for at least three years and valid for as long as you +offer spare parts or customer support for that product model, to give +anyone who possesses the object code either (1) a copy of the +Corresponding Source for all the software in the product that is +covered by this License, on a durable physical medium customarily used +for software interchange, for a price no more than your reasonable +cost of physically performing this conveying of source, or (2) access +to copy the Corresponding Source from a network server at no charge. +.IP "c." 4 +.IX Item "c." +Convey individual copies of the object code with a copy of the written +offer to provide the Corresponding Source. This alternative is +allowed only occasionally and noncommercially, and only if you +received the object code with such an offer, in accord with subsection +6b. +.IP "d." 4 +.IX Item "d." +Convey the object code by offering access from a designated place +(gratis or for a charge), and offer equivalent access to the +Corresponding Source in the same way through the same place at no +further charge. You need not require recipients to copy the +Corresponding Source along with the object code. If the place to copy +the object code is a network server, the Corresponding Source may be +on a different server (operated by you or a third party) that supports +equivalent copying facilities, provided you maintain clear directions +next to the object code saying where to find the Corresponding Source. +Regardless of what server hosts the Corresponding Source, you remain +obligated to ensure that it is available for as long as needed to +satisfy these requirements. +.IP "e." 4 +.IX Item "e." +Convey the object code using peer-to-peer transmission, provided you +inform other peers where the object code and Corresponding Source of +the work are being offered to the general public at no charge under +subsection 6d. +.RE +.RS 4 +.Sp +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. +.Sp +A \*(L"User Product\*(R" is either (1) a \*(L"consumer product\*(R", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +\&\*(L"normally used\*(R" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. +.Sp +\&\*(L"Installation Information\*(R" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. +.Sp +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in \s-1ROM\s0). +.Sp +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. +.Sp +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. +.RE +.IP "7. Additional Terms." 4 +.IX Item "7. Additional Terms." +\&\*(L"Additional permissions\*(R" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. +.Sp +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. +.Sp +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: +.RS 4 +.IP "a." 4 +.IX Item "a." +Disclaiming warranty or limiting liability differently from the terms +of sections 15 and 16 of this License; or +.IP "b." 4 +.IX Item "b." +Requiring preservation of specified reasonable legal notices or author +attributions in that material or in the Appropriate Legal Notices +displayed by works containing it; or +.IP "c." 4 +.IX Item "c." +Prohibiting misrepresentation of the origin of that material, or +requiring that modified versions of such material be marked in +reasonable ways as different from the original version; or +.IP "d." 4 +.IX Item "d." +Limiting the use for publicity purposes of names of licensors or +authors of the material; or +.IP "e." 4 +.IX Item "e." +Declining to grant rights under trademark law for use of some trade +names, trademarks, or service marks; or +.IP "f." 4 +.IX Item "f." +Requiring indemnification of licensors and authors of that material by +anyone who conveys the material (or modified versions of it) with +contractual assumptions of liability to the recipient, for any +liability that these contractual assumptions directly impose on those +licensors and authors. +.RE +.RS 4 +.Sp +All other non-permissive additional terms are considered \*(L"further +restrictions\*(R" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. +.Sp +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. +.Sp +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. +.RE +.IP "8. Termination." 4 +.IX Item "8. Termination." +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). +.Sp +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. +.Sp +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. +.Sp +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. +.IP "9. Acceptance Not Required for Having Copies." 4 +.IX Item "9. Acceptance Not Required for Having Copies." +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. +.IP "10. Automatic Licensing of Downstream Recipients." 4 +.IX Item "10. Automatic Licensing of Downstream Recipients." +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. +.Sp +An \*(L"entity transaction\*(R" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. +.Sp +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. +.IP "11. Patents." 4 +.IX Item "11. Patents." +A \*(L"contributor\*(R" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's \*(L"contributor version\*(R". +.Sp +A contributor's \*(L"essential patent claims\*(R" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, \*(L"control\*(R" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. +.Sp +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. +.Sp +In the following three paragraphs, a \*(L"patent license\*(R" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To \*(L"grant\*(R" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. +.Sp +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. \*(L"Knowingly relying\*(R" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. +.Sp +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. +.Sp +A patent license is \*(L"discriminatory\*(R" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. +.Sp +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. +.IP "12. No Surrender of Others' Freedom." 4 +.IX Item "12. No Surrender of Others' Freedom." +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey +a covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree +to terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. +.IP "13. Use with the \s-1GNU\s0 Affero General Public License." 4 +.IX Item "13. Use with the GNU Affero General Public License." +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the \s-1GNU\s0 Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the \s-1GNU\s0 Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. +.IP "14. Revised Versions of this License." 4 +.IX Item "14. Revised Versions of this License." +The Free Software Foundation may publish revised and/or new versions +of the \s-1GNU\s0 General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. +.Sp +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the \s-1GNU\s0 General Public +License \*(L"or any later version\*(R" applies to it, you have the option of +following the terms and conditions either of that numbered version or +of any later version published by the Free Software Foundation. If +the Program does not specify a version number of the \s-1GNU\s0 General +Public License, you may choose any version ever published by the Free +Software Foundation. +.Sp +If the Program specifies that a proxy can decide which future versions +of the \s-1GNU\s0 General Public License can be used, that proxy's public +statement of acceptance of a version permanently authorizes you to +choose that version for the Program. +.Sp +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. +.IP "15. Disclaimer of Warranty." 4 +.IX Item "15. Disclaimer of Warranty." +\&\s-1THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW.\s0 \s-1EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \*(L"AS IS\*(R" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE.\s0 \s-1THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU.\s0 \s-1SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION.\s0 +.IP "16. Limitation of Liability." 4 +.IX Item "16. Limitation of Liability." +\&\s-1IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM\s0 (\s-1INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS\s0), \s-1EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES.\s0 +.IP "17. Interpretation of Sections 15 and 16." 4 +.IX Item "17. Interpretation of Sections 15 and 16." +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. +.SS "\s-1END OF TERMS AND CONDITIONS\s0" +.IX Subsection "END OF TERMS AND CONDITIONS" +.SS "How to Apply These Terms to Your New Programs" +.IX Subsection "How to Apply These Terms to Your New Programs" +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. +.PP +To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the \*(L"copyright\*(R" line and a pointer to where the full notice is found. +.PP +.Vb 2 +\& +\& Copyright (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 3 of the License, or (at +\& your option) any later version. +\& +\& This program is distributed in the hope that it will be useful, but +\& WITHOUT ANY WARRANTY; without even the implied warranty of +\& MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +\& General Public License for more details. +\& +\& You should have received a copy of the GNU General Public License +\& along with this program. If not, see . +.Ve +.PP +Also add information on how to contact you by electronic and paper mail. +.PP +If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: +.PP +.Vb 4 +\& Copyright (C) +\& This program comes with ABSOLUTELY NO WARRANTY; for details type "show w". +\& This is free software, and you are welcome to redistribute it +\& under certain conditions; type "show c" for details. +.Ve +.PP +The hypothetical commands \fBshow w\fR and \fBshow c\fR should show +the appropriate parts of the General Public License. Of course, your +program's commands might be different; for a \s-1GUI\s0 interface, you would +use an \*(L"about box\*(R". +.PP +You should also get your employer (if you work as a programmer) or school, +if any, to sign a \*(L"copyright disclaimer\*(R" for the program, if necessary. +For more information on this, and how to apply and follow the \s-1GNU GPL,\s0 see +<\fBhttp://www.gnu.org/licenses/\fR>. +.PP +The \s-1GNU\s0 General Public License does not permit incorporating your +program into proprietary programs. If your program is a subroutine +library, you may consider it more useful to permit linking proprietary +applications with the library. If this is what you want to do, use +the \s-1GNU\s0 Lesser General Public License instead of this License. But +first, please read <\fBhttp://www.gnu.org/philosophy/why\-not\-lgpl.html\fR>. +.SH "SEE ALSO" +.IX Header "SEE ALSO" +\&\fIgfdl\fR\|(7), \fIfsf\-funding\fR\|(7). +.SH "COPYRIGHT" +.IX Header "COPYRIGHT" +Copyright (c) 2007 Free Software Foundation, Inc. +.PP +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/CHANGES b/gems-kernel.git/source/THIRDPARTY/linux-old/CHANGES new file mode 100644 index 000000000..4e74e16e3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/CHANGES @@ -0,0 +1,133 @@ +CHANGES since 0.99 patchlevel 13: + + - new kernel source layout: drivers separated + - lots of networking bugs fixed, and new network card drivers (Alan Cox, + Donald Becker &co) + - sound driver added to the default source distribution (Hannu + Savolainen) + - updated SCSI driver code (Eric Youngdale, Drew Eckhardt &co) + - readonly OS/2 filesystem support (HPFS) added (Chris Smith) + - NTP support (Philip Gladstone, Torsten Duwe, ??) + - fixed 16MB swap-area limit + - lots of minor cleanups, buxfixes etc. + +CHANGES since 0.99 patchlevel 12 and earlier: + + - the bad memory management one-liner bug in pl12 is naturally fixed. + - compiled with plain C by default instead of C++ + - ELF binary support (Eric Youngdale) + - Quickport mouse support (and some changes to the PS/2 mouse driver) + by Johan Myreen and co) + - core file name change ("core" -> "core.xxxx" where xxxx is the name + of the program that dumped code). Idea from ???. Also, core-files + now correctly truncate any existing core file before being written. + - some mmap() fixes: better error returns, and handling of non-fixed + maps for /dev/mem etc. + - one kludgy way to fix the wrong arp packets that have plagued net-2d + (resulting in arp packets that had the first four bytes of the + ethernet address as the IP address). + - I fixed the mount-point handling of 'rename()' and 'unlink()/rmdir()' + so that they should now work and/or give appropriate error messages. + An early version of this patch was already sent to the KERNEL + channel, which fixed the rename problem but not a similar bug with + unlink. + - packet mode fixes by Charles Hedrick. Sadly, these are likely to + break old telnet/rlogin binaries, but it had to be done in order to + communicate correctly with the rest of the world. + - FPU emulator patches from Bill Metzenthen. The fprem1 insn should be + correct now (not that anybody seems to have seen the incorrect + behaviour..) + - a few fixes for SCSI (Drew and Eric) + - signal.c changes to handle multiple segments (for Wine) correctly. + - updated drivers from Donald Becker: 3c509 and AT1500 drivers, but + also some other drivers have been edited, and some networking fixes. + +CHANGES since 0.99 patchlevel 11 and earlier: + + - The memory manager cleanup has continued, and seems to be mostly + ready, as proven by the ease of adding mmap() over NFS with the new + routines. So yes, the pl12 kernel will demand-load your binaries + over NFS, sharing code and clean data, as well as running shared + libraries over NFS. Memory management by Eric and me, while the NFS + mmap code was written by Jon Tombs, + + - ** IMPORTANT **: The keyboard driver has been enhanced even further, + and almost everything is completely re-mappable. This means that + there is a new version of 'loadkeys' and 'dumpkeys' that you must use + with this kernel or you'll have problems. The default keyboard is + still the US mapping, but if you want to create your own mappings + you'll have to load them with the new binaries. Get the 'kbd.tar.gz' + archive from the same place you get the kernel. + + The new keymappings allow things like function key string changes, + remapping of the control keys, and freedom to remap any of the normal + keyboard functions: including special features like rebooting, + console switching etc. The keyboard remapping code has been done + mostly by Risto Kankkunen (Risto.Kankkunen@Helsinki.FI). + + - updated network drivers by Donald Becker + + - updated serial drivers - tytso@Athena.mit.edu + + - updated 387 emulation (Bill Metzenthen). The updated emulator code + has more exact trigonometric functions and improved exception + handling. It now behaves very much like a real 486, with only small + changes (greater accuracy, slightly different denormal NaN handling + etc - hard to detect the differences even if you are looking for + them). + + - network timer fixes by Florian La Roche (much cleaned up net/inet/timer.c + and some bad race-conditions fixed). + + - Scsi code updates by Eric Youngdale and others + + - Sony CDU-31A CDROM driver by Corey Minyard added to the standard + kernel distribution. + + - The Mitsumi CDROM driver is now part of the standard kernel. Driver + by Martin Harriss with patches by stud11@cc4.kuleuven.ac.be (yes, he + probably has a real name, but no, I haven't found it) and Jon Tombs. + + - various other minor patches (preliminary ldt support etc) + +NOTABLE changes since patchlevel 10 or earlier: + + - The memory manager has been cleaned up substantially, and mmap() + works for MAP_PRIVATE. MAP_SHARED is still not supported for + anything else than /dev/mem, but even so it actually is usable for a + lot of applications. The shared library routines have been rewritten + to use mmap() instead of the old hardcoded behaviour. + + - The kernel is now compiled with C++ instead of plain C. Very few + actual C++ features are used, but even so C++ allows for more + type-checking and type-safe linkage. + + - The filesystem routines have been cleaned up for multiple block + sizes. None of the filesystems use it yet, but people are working on + it. + + - named pipes and normal pipes should hopefully have the right select() + semantics in the presense/absense of writers. + + - QIC-02 tape driver by Hennus Bergman + + - selection patches in the default kernel + + - fixed a bug in the pty code which led to busy waiting in some + circumstances instead of sleeping. + + - Compressed SLIP support (Charles Hedrick). See net/inet/CONFIG + + - the 'clear_bit()' function was changed to return the previous setting + of the bit instead of the old "error-code". This makes use of the + bit operations more logical. + + - udelay() function for short delays (busy-waiting) added. Used + currently only by the QIC driver. + + - fork() and sheduler changes to make task switches happen only from + kernel mode to kernel mode. Cleaner and more portable than the old + code which counted on being able to task-switch directly into user + mode. + + - debugging malloc code. diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/COPYING b/gems-kernel.git/source/THIRDPARTY/linux-old/COPYING new file mode 100644 index 000000000..c0ff68a2b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/COPYING @@ -0,0 +1,351 @@ + + NOTE! This copyright does *not* cover user programs that use kernel + services by normal system calls - this is merely considered normal use + of the kernel, and does *not* fall under the heading of "derived work". + Also note that the GPL below is copyrighted by the Free Software + Foundation, but the instance of code that it refers to (the linux + kernel) is copyrighted by me and others who actually wrote it. + + Linus Torvalds + +---------------------------------------- + + GNU GENERAL PUBLIC LICENSE + Version 2, June 1991 + + Copyright (C) 1989, 1991 Free Software Foundation, Inc. + 675 Mass Ave, Cambridge, MA 02139, USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +License is intended to guarantee your freedom to share and change free +software--to make sure the software is free for all its users. This +General Public License applies to most of the Free Software +Foundation's software and to any other program whose authors commit to +using it. (Some other Free Software Foundation software is covered by +the GNU Library General Public License instead.) You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +this service if you wish), that you receive source code or can get it +if you want it, that you can change the software or use pieces of it +in new free programs; and that you know you can do these things. + + To protect your rights, we need to make restrictions that forbid +anyone to deny you these rights or to ask you to surrender the rights. +These restrictions translate to certain responsibilities for you if you +distribute copies of the software, or if you modify it. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must give the recipients all the rights that +you have. You must make sure that they, too, receive or can get the +source code. And you must show them these terms so they know their +rights. + + We protect your rights with two steps: (1) copyright the software, and +(2) offer you this license which gives you legal permission to copy, +distribute and/or modify the software. + + Also, for each author's protection and ours, we want to make certain +that everyone understands that there is no warranty for this free +software. If the software is modified by someone else and passed on, we +want its recipients to know that what they have is not the original, so +that any problems introduced by others will not reflect on the original +authors' reputations. + + Finally, any free program is threatened constantly by software +patents. We wish to avoid the danger that redistributors of a free +program will individually obtain patent licenses, in effect making the +program proprietary. To prevent this, we have made it clear that any +patent must be licensed for everyone's free use or not licensed at all. + + The precise terms and conditions for copying, distribution and +modification follow. + + GNU GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License applies to any program or other work which contains +a notice placed by the copyright holder saying it may be distributed +under the terms of this General Public License. The "Program", below, +refers to any such program or work, and a "work based on the Program" +means either the Program or any derivative work under copyright law: +that is to say, a work containing the Program or a portion of it, +either verbatim or with modifications and/or translated into another +language. (Hereinafter, translation is included without limitation in +the term "modification".) Each licensee is addressed as "you". + +Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running the Program is not restricted, and the output from the Program +is covered only if its contents constitute a work based on the +Program (independent of having been made by running the Program). +Whether that is true depends on what the Program does. + + 1. You may copy and distribute verbatim copies of the Program's +source code as you receive it, in any medium, provided that you +conspicuously and appropriately publish on each copy an appropriate +copyright notice and disclaimer of warranty; keep intact all the +notices that refer to this License and to the absence of any warranty; +and give any other recipients of the Program a copy of this License +along with the Program. + +You may charge a fee for the physical act of transferring a copy, and +you may at your option offer warranty protection in exchange for a fee. + + 2. You may modify your copy or copies of the Program or any portion +of it, thus forming a work based on the Program, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) You must cause the modified files to carry prominent notices + stating that you changed the files and the date of any change. + + b) You must cause any work that you distribute or publish, that in + whole or in part contains or is derived from the Program or any + part thereof, to be licensed as a whole at no charge to all third + parties under the terms of this License. + + c) If the modified program normally reads commands interactively + when run, you must cause it, when started running for such + interactive use in the most ordinary way, to print or display an + announcement including an appropriate copyright notice and a + notice that there is no warranty (or else, saying that you provide + a warranty) and that users may redistribute the program under + these conditions, and telling the user how to view a copy of this + License. (Exception: if the Program itself is interactive but + does not normally print such an announcement, your work based on + the Program is not required to print an announcement.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Program, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Program, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Program. + +In addition, mere aggregation of another work not based on the Program +with the Program (or with a work based on the Program) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may copy and distribute the Program (or a work based on it, +under Section 2) in object code or executable form under the terms of +Sections 1 and 2 above provided that you also do one of the following: + + a) Accompany it with the complete corresponding machine-readable + source code, which must be distributed under the terms of Sections + 1 and 2 above on a medium customarily used for software interchange; or, + + b) Accompany it with a written offer, valid for at least three + years, to give any third party, for a charge no more than your + cost of physically performing source distribution, a complete + machine-readable copy of the corresponding source code, to be + distributed under the terms of Sections 1 and 2 above on a medium + customarily used for software interchange; or, + + c) Accompany it with the information you received as to the offer + to distribute corresponding source code. (This alternative is + allowed only for noncommercial distribution and only if you + received the program in object code or executable form with such + an offer, in accord with Subsection b above.) + +The source code for a work means the preferred form of the work for +making modifications to it. For an executable work, complete source +code means all the source code for all modules it contains, plus any +associated interface definition files, plus the scripts used to +control compilation and installation of the executable. However, as a +special exception, the source code distributed need not include +anything that is normally distributed (in either source or binary +form) with the major components (compiler, kernel, and so on) of the +operating system on which the executable runs, unless that component +itself accompanies the executable. + +If distribution of executable or object code is made by offering +access to copy from a designated place, then offering equivalent +access to copy the source code from the same place counts as +distribution of the source code, even though third parties are not +compelled to copy the source along with the object code. + + 4. You may not copy, modify, sublicense, or distribute the Program +except as expressly provided under this License. Any attempt +otherwise to copy, modify, sublicense or distribute the Program is +void, and will automatically terminate your rights under this License. +However, parties who have received copies, or rights, from you under +this License will not have their licenses terminated so long as such +parties remain in full compliance. + + 5. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Program or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Program (or any work based on the +Program), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Program or works based on it. + + 6. Each time you redistribute the Program (or any work based on the +Program), the recipient automatically receives a license from the +original licensor to copy, distribute or modify the Program subject to +these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties to +this License. + + 7. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Program at all. For example, if a patent +license would not permit royalty-free redistribution of the Program by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Program. + +If any portion of this section is held invalid or unenforceable under +any particular circumstance, the balance of the section is intended to +apply and the section as a whole is intended to apply in other +circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system, which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 8. If the distribution and/or use of the Program is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Program under this License +may add an explicit geographical distribution limitation excluding +those countries, so that distribution is permitted only in or among +countries not thus excluded. In such case, this License incorporates +the limitation as if written in the body of this License. + + 9. The Free Software Foundation may publish revised and/or new versions +of the General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies a version number of this License which applies to it and "any +later version", you have the option of following the terms and conditions +either of that version or of any later version published by the Free +Software Foundation. If the Program does not specify a version number of +this License, you may choose any version ever published by the Free Software +Foundation. + + 10. If you wish to incorporate parts of the Program into other free +programs whose distribution conditions are different, write to the author +to ask for permission. For software which is copyrighted by the Free +Software Foundation, write to the Free Software Foundation; we sometimes +make exceptions for this. Our decision will be guided by the two goals +of preserving the free status of all derivatives of our free software and +of promoting the sharing and reuse of software generally. + + NO WARRANTY + + 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY +FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN +OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES +PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED +OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS +TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE +PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, +REPAIR OR CORRECTION. + + 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR +REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING +OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED +TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY +YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER +PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE +POSSIBILITY OF SUCH DAMAGES. + + END OF TERMS AND CONDITIONS + + Appendix: How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) 19yy + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + +Also add information on how to contact you by electronic and paper mail. + +If the program is interactive, make it output a short notice like this +when it starts in an interactive mode: + + Gnomovision version 69, Copyright (C) 19yy name of author + Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, the commands you use may +be called something other than `show w' and `show c'; they could even be +mouse-clicks or menu items--whatever suits your program. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the program + `Gnomovision' (which makes passes at compilers) written by James Hacker. + + , 1 April 1989 + Ty Coon, President of Vice + +This General Public License does not permit incorporating your program into +proprietary programs. If your program is a subroutine library, you may +consider it more useful to permit linking proprietary applications with the +library. If this is what you want to do, use the GNU Library General +Public License instead of this License. diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/Configure b/gems-kernel.git/source/THIRDPARTY/linux-old/Configure new file mode 100644 index 000000000..77c8445d1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/Configure @@ -0,0 +1,242 @@ +#! /bin/sh +# +# This script is used to configure the linux kernel. +# +# It was inspired by the challenge in the original Configure script +# to ``do something better'', combined with the actual need to ``do +# something better'' because the old configure script wasn't flexible +# enough. +# +# Please send comments / questions / bug fixes to raymondc@microsoft.com. +# +# Each line in the config file is a command. +# +# # internal comment +# +# Lines beginning with a `#' are ignored. +# +# : message +# +# `:' causes the line to be echoed to the screen. +# +# * external comment +# +# `*' causes the line to be placed in the output +# configuration file as a comment as well as being +# echoed to the screen. +# +# if condition +# ... commands ... +# else +# ... commands ... +# fi +# +# This does the obvious thing. The `else' clause is +# optional. Conditionals can be nested. +# +# The `condition' can be any valid bash expression. +# They typically involve tests against environment +# variables set by configuration options. For example, +# +# if [ "$CONFIG_SCSI" = "y" ] +# ...More stuff... +# fi +# +# Note! That there is no `then' keyword. +# +# bool 'prompt' CONFIG_VARIABLE default +# +# This prompts the user for a boolean value. +# The prompt may not contain an apostrophe. +# `default' should be either `y' or `n'. +# The user's response is recorded in four places. +# +# In .config, if `y' +# CONFIG_VARIABLE = CONFIG_VARIABLE +# In .config, if `n' +# # CONFIG_VARIABLE is not set +# +# In autoconf.h, if `y' +# #define CONFIG_VARIABLE 1 +# In autoconf.h, if `n' +# #undef CONFIG_VARIABLE +# +# In config.in, if `y' +# bool 'prompt' CONFIG_VARIABLE y +# In config.in, if `n' +# bool 'prompt' CONFIG_VARIABLE n +# +# In the environment of the Configure script, if `y' +# CONFIG_VARIABLE = y +# In the environment of the Configure script, if `n' +# CONFIG_VARIABLE = n +# +# The value is placed into the environment of the Configure +# script so that later parts of config.in can use the `if' +# command to inspect the results of previous queries. +# +# int 'prompt' CONFIG_VARIABLE default +# +# This prompts the user for an integer value. +# The prompt may not contain an apostrophe. +# `default' should be an integer. +# +# The response is recorded as follows. +# +# In .config +# CONFIG_VARIABLE = response +# In autoconf.h +# #define CONFIG_VARIABLE (response) +# In config.in +# int 'prompt' CONFIG_VARIABLE response +# In the environment of the Configure script +# CONFIG_VARIABLE = response +# +# 050793 - use IFS='@' to get around a bug in a pre-version of bash-1.13 +# with an empty IFS. + +# +# Make sure we're really running bash. +# +# I would really have preferred to write this script in a language with +# better string handling, but alas, bash is the only scripting language +# that I can be reasonable sure everybody has on their linux machine. +# +[ -z "$BASH" ] && { echo "Configure requires bash" 1>&2; exit 1; } + +# Disable filename globbing once and for all. +# Enable function cacheing. +set -f -h + +# +# readln reads a line into $ans. +# +# readln prompt default +# +function readln () { + echo -n "$1" + IFS='@' read ans >$CONFIG + echo "#define $2 1" >>$CONFIG_H + else + echo "# $2 is not set" >>$CONFIG + echo "#undef $2" >>$CONFIG_H + fi + raw_input_line="bool '$1' $2 $ans" + eval "$2=$ans" +} + +# int processes an integer argument +# +# int tail +# +function int () { + # Slimier hack to get bash to rescan a line. + eval "set -- $1" + ans="x" + while [ $[$ans+0] != "$ans" ]; do + readln "$1 ($2) [$3] " "$3" + done + echo "$2 = $ans" >>$CONFIG + echo "#define $2 ($ans)" >>$CONFIG_H + raw_input_line="int '$1' $2 $ans" + eval "$2=$ans" +} + +CONFIG=.config~ +CONFIG_H=include/linux/autoconf.h + +# +# Make sure we start out with a clean slate. +# +> config.new +echo "#" > $CONFIG +echo "# Automatically generated make config: don't edit" >> $CONFIG +echo "#" >> $CONFIG + +echo "/*" > $CONFIG_H +echo " * Automatically generated C config: don't edit" >> $CONFIG_H +echo " */" >> $CONFIG_H + +stack='' +branch='t' + +while IFS='@' read raw_input_line +do + # Slimy hack to get bash to rescan a line. + read cmd rest <<-END_OF_COMMAND + $raw_input_line + END_OF_COMMAND + + if [ "$cmd" = "*" ]; then + if [ "$branch" = "t" ]; then + echo "$raw_input_line" + echo "# $rest" >>$CONFIG + if [ "$prevcmd" != "*" ]; then + echo >>$CONFIG_H + echo "/* $rest" >>$CONFIG_H + else + echo " * $rest" >>$CONFIG_H + fi + prevcmd="*" + fi + else + [ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H + prevcmd="" + case "$cmd" in + :) [ "$branch" = "t" ] && echo "$raw_input_line" ;; + int) [ "$branch" = "t" ] && int "$rest" ;; + bool) [ "$branch" = "t" ] && bool "$rest" ;; + exec) [ "$branch" = "t" ] && ( sh -c "$rest" ) ;; + if) stack="$branch $stack" + if [ "$branch" = "t" ] && eval "$rest"; then + branch=t + else + branch=f + fi ;; + else) if [ "$branch" = "t" ]; then + branch=f + else + read branch rest <<-END_OF_STACK + $stack + END_OF_STACK + fi ;; + fi) [ -z "$stack" ] && echo "Error! Extra fi." 1>&2 + read branch stack <<-END_OF_STACK + $stack + END_OF_STACK + ;; + esac + fi + echo "$raw_input_line" >>config.new +done +[ "$prevcmd" = "*" ] && echo " */" >>$CONFIG_H + +[ -z "$stack" ] || echo "Error! Untermiated if." 1>&2 + +mv config.in config.old +mv config.new config.in + +echo +echo "The linux kernel is now hopefully configured for your setup." +echo "Check the top-level Makefile for additional configuration," +echo "and do a 'make dep ; make clean' if you want to be sure all" +echo "the files are correctly re-made" +echo + +exit 0 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/Makefile new file mode 100644 index 000000000..06a544ed3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/Makefile @@ -0,0 +1,296 @@ +VERSION = 0.99 +PATCHLEVEL = 15 +ALPHA = + +all: Version zImage + +.EXPORT_ALL_VARIABLES: + +CONFIG_SHELL := $(shell if [ -x "$$BASH" ]; then echo $$BASH; \ + else if [ -x /bin/bash ]; then echo /bin/bash; \ + else echo sh; fi ; fi) + +# +# Make "config" the default target if there is no configuration file or +# "depend" the target if there is no top-level dependency information. +# +ifeq (.config,$(wildcard .config)) +include .config +ifeq (.depend,$(wildcard .depend)) +include .depend +else +CONFIGURATION = depend +endif +else +CONFIGURATION = config +endif + +ifdef CONFIGURATION +CONFIGURE = dummy +endif + +# +# ROOT_DEV specifies the default root-device when making the image. +# This can be either FLOPPY, CURRENT, /dev/xxxx or empty, in which case +# the default of FLOPPY is used by 'build'. +# + +ROOT_DEV = CURRENT + +# +# If you want to preset the SVGA mode, uncomment the next line and +# set SVGA_MODE to whatever number you want. +# Set it to -DSVGA_MODE=NORMAL_VGA if you just want the EGA/VGA mode. +# The number is the same as you would ordinarily press at bootup. +# + +SVGA_MODE= -DSVGA_MODE=NORMAL_VGA + +# +# standard CFLAGS +# + +CFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -pipe + +ifdef CONFIG_CPP +CFLAGS := $(CFLAGS) -x c++ +endif + +ifdef CONFIG_M486 +CFLAGS := $(CFLAGS) -m486 +else +CFLAGS := $(CFLAGS) -m386 +endif + +# +# if you want the ram-disk device, define this to be the +# size in blocks. +# + +#RAMDISK = -DRAMDISK=512 + +AS86 =as86 -0 -a +LD86 =ld86 -0 + +AS =as +LD =ld +HOSTCC =gcc +CC =gcc -D__KERNEL__ +MAKE =make +CPP =$(CC) -E +AR =ar +STRIP =strip + +ARCHIVES =kernel/kernel.o mm/mm.o fs/fs.o net/net.o ipc/ipc.o +FILESYSTEMS =fs/filesystems.a +DRIVERS =drivers/block/block.a \ + drivers/char/char.a \ + drivers/net/net.a \ + ibcs/ibcs.o +LIBS =lib/lib.a +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: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< + +Version: dummy + rm -f tools/version.h + +config: + $(CONFIG_SHELL) Configure $(OPTS) < config.in + @if grep -s '^CONFIG_SOUND' .config~ ; then \ + $(MAKE) -C drivers/sound config; \ + else : ; fi + mv .config~ .config + +linuxsubdirs: dummy + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done + +tools/./version.h: tools/version.h + +tools/version.h: $(CONFIGURE) Makefile + @./makever.sh + @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 + @echo \#define LINUX_COMPILE_HOST \"`hostname`\" >> tools/version.h + @echo \#define LINUX_COMPILE_DOMAIN \"`domainname`\" >> tools/version.h + +tools/build: tools/build.c $(CONFIGURE) + $(HOSTCC) $(CFLAGS) -o $@ $< + +boot/head.o: $(CONFIGURE) boot/head.s + +boot/head.s: boot/head.S $(CONFIGURE) include/linux/tasks.h + $(CPP) -traditional $< -o $@ + +tools/version.o: tools/version.c tools/version.h + +init/main.o: $(CONFIGURE) init/main.c + $(CC) $(CFLAGS) $(PROFILING) -c -o $*.o $< + +tools/system: boot/head.o init/main.o tools/version.o linuxsubdirs + $(LD) $(LDFLAGS) -T 1000 boot/head.o init/main.o tools/version.o \ + $(ARCHIVES) \ + $(FILESYSTEMS) \ + $(DRIVERS) \ + $(LIBS) \ + -o tools/system + nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \ + sort > System.map + +boot/setup: boot/setup.o + $(LD86) -s -o $@ $< + +boot/setup.o: boot/setup.s + $(AS86) -o $@ $< + +boot/setup.s: boot/setup.S $(CONFIGURE) include/linux/config.h Makefile + $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + +boot/bootsect: boot/bootsect.o + $(LD86) -s -o $@ $< + +boot/bootsect.o: boot/bootsect.s + $(AS86) -o $@ $< + +boot/bootsect.s: boot/bootsect.S $(CONFIGURE) include/linux/config.h Makefile + $(CPP) -traditional $(SVGA_MODE) $(RAMDISK) $< -o $@ + +zBoot/zSystem: zBoot/*.c zBoot/*.S tools/zSystem + $(MAKE) -C zBoot + +zImage: $(CONFIGURE) boot/bootsect boot/setup zBoot/zSystem tools/build + tools/build boot/bootsect boot/setup zBoot/zSystem $(ROOT_DEV) > zImage + sync + +zdisk: zImage + dd bs=8192 if=zImage of=/dev/fd0 + +zlilo: $(CONFIGURE) zImage + if [ -f /vmlinuz ]; then mv /vmlinuz /vmlinuz.old; fi + cat zImage > /vmlinuz + if [ -x /sbin/lilo ]; then /sbin/lilo; else /etc/lilo/install; fi + +tools/zSystem: boot/head.o init/main.o tools/version.o linuxsubdirs + $(LD) $(LDFLAGS) -T 100000 boot/head.o init/main.o tools/version.o \ + $(ARCHIVES) \ + $(FILESYSTEMS) \ + $(DRIVERS) \ + $(LIBS) \ + -o tools/zSystem + nm tools/zSystem | grep -v '\(compiled\)\|\(\.o$$\)\|\( a \)' | \ + sort > zSystem.map + +fs: dummy + $(MAKE) linuxsubdirs SUBDIRS=fs + +lib: dummy + $(MAKE) linuxsubdirs SUBDIRS=lib + +mm: dummy + $(MAKE) linuxsubdirs SUBDIRS=mm + +ipc: dummy + $(MAKE) linuxsubdirs SUBDIRS=ipc + +kernel: dummy + $(MAKE) linuxsubdirs SUBDIRS=kernel + +drivers: dummy + $(MAKE) linuxsubdirs SUBDIRS=drivers + +net: dummy + $(MAKE) linuxsubdirs SUBDIRS=net + +clean: + rm -f kernel/ksyms.lst + rm -f core `find . -name '*.[oas]' -print` + rm -f core `find . -name 'core' -print` + rm -f zImage zSystem.map tools/zSystem tools/system + rm -f Image System.map boot/bootsect boot/setup + rm -f zBoot/zSystem zBoot/xtract zBoot/piggyback + rm -f drivers/sound/configure + rm -f init/*.o tools/build boot/*.o tools/*.o + +mrproper: clean + rm -f include/linux/autoconf.h tools/version.h + rm -f drivers/sound/local.h + 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 + +depend dep: + touch tools/version.h + for i in init/*.c;do echo -n "init/";$(CPP) -M $$i;done > .depend~ + for i in tools/*.c;do echo -n "tools/";$(CPP) -M $$i;done >> .depend~ + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done + rm -f tools/version.h + mv .depend~ .depend + +ifdef CONFIGURATION +..$(CONFIGURATION): + @echo + @echo "You have a bad or nonexistent" .$(CONFIGURATION) ": running 'make" $(CONFIGURATION)"'" + @echo + $(MAKE) $(CONFIGURATION) + @echo + @echo "Successful. Try re-making (ignore the error that follows)" + @echo + exit 1 + +dummy: ..$(CONFIGURATION) + +else + +dummy: + +endif + +# +# Leave these dummy entries for now to tell people that they are going away.. +# +lilo: + @echo + @echo Uncompressed kernel images no longer supported. Use + @echo \"make zlilo\" instead. + @echo + @exit 1 + +Image: + @echo + @echo Uncompressed kernel images no longer supported. Use + @echo \"make zImage\" instead. + @echo + @exit 1 + +disk: + @echo + @echo Uncompressed kernel images no longer supported. Use + @echo \"make zdisk\" instead. + @echo + @exit 1 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/README b/gems-kernel.git/source/THIRDPARTY/linux-old/README new file mode 100644 index 000000000..c8d352336 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/README @@ -0,0 +1,181 @@ + + Linux kernel release 0.99 patchlevel 14 + +These are the release notes for linux version 0.99.14. Read them +carefully, as they tell you what's new, explain how to install the +kernel, and what to do if something goes wrong. + +INSTALLING the kernel: + + - if you install by patching, you need a *clean* 0.99.13 source tree, + which presumably exists in /usr/src/linux. If so, to get the kernel + patched, just do a + + cd /usr/src + patch -p0 < linux-0.99.patch14 + + and you should be ok. You may want to remove the backup files (xxx~ + or xxx.orig), and make sure that there are no failed patches (xxx# or + xxx.rej). + + - If you install the full sources, do a + + cd /usr/src + tar xvf linux-0.99.14.tar + + to get it all put in place. + + - make sure your /usr/include/linux and /usr/include/asm directories + are just symlinks to the kernel sources: + + cd /usr/include + rm -rf linux + rm -rf asm + ln -s /usr/src/linux/include/linux . + ln -s /usr/src/linux/include/asm . + + - make sure you have no stale .o files and dependencies lying around: + + cd /usr/src/linux + make mrproper + + You should now have the sources correctly installed. + +CONFIGURING the kernel: + + - do a "make config" to configure the basic kernel. "make config" + needs bash to work: it will search for bash in $BASH, /bin/bash and + /bin/sh (in that order), so hopefully one of those is correct. + + NOTES on "make config": + - compiling the kernel with "-m486" for a number of 486-specific + will result in a kernel that still works on a 386: it may be + slightly larger and possibly slower by an insignificant amount, + but it should not hurt performance. + - A kernel with math-emulation compiled in will still use the + coprocessor if one is present: the math emulation will just + never get used in that case. The kernel will be slighly larger, + but will work on different machines regardless of whether they + have a math coprocessor or not. + - the "kernel hacking" configuration details usually result in a + bigger or slower kernel (or both), and can even make the kernel + less stable by configuring some routines to actively try to + break bad code to find kernel problems (kmalloc()). Thus you + should probably answer 'n' to the questions for a "production" + kernel. + + - 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). + + - Finally, do a "make dep" to set up all the dependencies correctly. + +COMPILING the kernel: + + - make sure you have gcc-2.4.5 or newer available with g++. It seems + older gcc versions can have problems compiling linux 0.99.10 and + newer versions. If you upgrade, remember to get the new binutils + package too (for as/ld/nm and company) + + - do a "make zImage" to create a compressed kernel image. If you want + to make a bootdisk (without root filesystem or lilo), insert a floppy + in your A: drive, and do a "make zdisk". It is also possible to do + "make zlilo" if you have lilo installed to suit the kernel makefiles, + but you may want to check your particular lilo setup first. + + - keep a backup kernel handy in case something goes wrong. + + - In order to boot your new kernel, you'll need to copy the kernel + image (found in /usr/src/linux/zImage after compilation) to the place + where your regular bootable kernel is found. + + For some, this is on a floppy disk, in which case you can "cp + /usr/src/linux/zImage /dev/fd0" to make a bootable floppy. + + If you boot Linux from the hard drive, chances are you use LILO uses + the kernel image as specified in the file /etc/lilo/config. The + kernel image file is usually /vmlinux, or /Image, or /etc/Image. To + use the new kernel, copy the new image over the old one (save a + backup of the original!). Then, you MUST REINSTALL LILO!! If you + don't, you won't be able to boot the new kernel image. + + Reinstalling LILO is usually a matter of running /etc/lilo/install. + You may wish to edit /etc/lilo/config to specify an entry for your + old kernel image (say, /vmlinux.old) in case the new one does not + work. See the LILO docs for more information. + + After reinstalling LILO, you should be all set. Shutdown the system, + reboot, and enjoy! + + If you ever need to change the default root device, video mode, + ramdisk size, etc. in the kernel image, use the 'rdev' program (or + alternatively the LILO boot options when appropriate). No need to + recompile the kernel to change these parameters. + + - reboot with the new kernel and enjoy. + +IF SOMETHING GOES WRONG: + + - if you have problems that seem to be due to kernel bugs, please mail + them to me (Linus.Torvalds@Helsinki.FI), and possibly to any other + relevant mailing-list or to the newsgroup. The mailing-lists are + useful especially for SCSI and NETworking problems, as I can't test + either of those personally anyway. + + - In all bug-reports, *please* tell what kernel you are talking about, + how to duplicate the problem, and what your setup is (use your common + sense). If the problem is new, tell me so, and if the problem is + old, please try to tell me when you first noticed it. + + - if the bug results in a message like + + unable to handle kernel paging request at address C0000010 + Oops: 0002 + EIP: 0010:xxxxxxxx + eax: xxxxxxxx ebx: xxxxxxxx ecx: xxxxxxxx edx: xxxxxxxx + esi: xxxxxxxx edi: xxxxxxxx ebp: xxxxxxxx + ds: xxxx es: xxxx fs: xxxx gs: xxxx + Pid: xx, process nr: xx + xx xx xx xx xx xx xx xx xx xx + + or similar kernel debugging information on your screen or in your + system log, please duplicate it *exactly*. The dump may look + incomprehensible to you, but it does contain information that may + help debugging the problem. The text above the dump is also + important: it tells something about why the kernel dumped code (in + the above example it's due to a bad kernel pointer) + + - in debugging dumps like the above, it helps enourmously if you can + look up what the EIP value means. The hex value as such doesn't help + me or anybody else very much: it will depend on your particular + kernel setup. What you should do is take the hex value from the EIP + line (ignore the "0010:"), and look it up in the kernel namelist to + see which kernel function contains the offending address. + + To find out the kernel function name, you'll need to find the system + binary associated with the kernel that exhibited the symptom. In the + case of compressed kernels, this will be 'linux/tools/zSystem', while + uncompressed kernels use the file 'tools/system'. To extract the + namelist and match it against the EIP from the kernel crash, do: + + nm tools/zSystem | sort | less + + This will give you a list of kernel addresses sorted in ascending + order, from which it is simple to find the function that contains the + offending address. Note that the address given by the kernel + debugging messages will not necessarily match exactly with the + function addresses (in fact, that is very unlikely), so you can't + just 'grep' the list: the list will, however, give you the starting + point of each kernel function, so by looking for the function that + has a starting address lower than the one you are searching for but + is followed by a function with a higher address you will find the one + you want. In fact, it may be a good idea to include a bit of + "context" in your problem report, giving a few lines around the + interesting one. + + If you for some reason cannot do the above (you have a pre-compiled + kernel image or similar), telling me as much about your setup as + possible will help. + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/boot/bootsect.S b/gems-kernel.git/source/THIRDPARTY/linux-old/boot/bootsect.S new file mode 100644 index 000000000..261d5a1c1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/boot/bootsect.S @@ -0,0 +1,450 @@ +! +! SYS_SIZE is the number of clicks (16 bytes) to be loaded. +! 0x7F00 is 0x7F000 bytes = 508kB, more than enough for current +! versions of linux which compress the kernel +! +#include +SYSSIZE = DEF_SYSSIZE +! +! bootsect.s Copyright (C) 1991, 1992 Linus Torvalds +! modified by Drew Eckhardt +! modified by Bruce Evans (bde) +! +! bootsect.s is loaded at 0x7c00 by the bios-startup routines, and moves +! itself out of the way to address 0x90000, and jumps there. +! +! bde - should not jump blindly, there may be systems with only 512K low +! memory. Use int 0x12 to get the top of memory, etc. +! +! It then loads 'setup' directly after itself (0x90200), and the system +! at 0x10000, using BIOS interrupts. +! +! NOTE! currently system is at most (8*65536-4096) bytes long. This should +! be no problem, even in the future. I want to keep it simple. This 508 kB +! kernel size should be enough, especially as this doesn't contain the +! buffer cache as in minix (and especially now that the kernel is +! compressed :-) +! +! The loader has been made as simple as possible, and continuos +! read errors will result in a unbreakable loop. Reboot by hand. It +! loads pretty fast by getting whole tracks at a time whenever possible. + +.text + +SETUPSECS = 4 ! nr of setup-sectors +BOOTSEG = 0x07C0 ! original address of boot-sector +INITSEG = DEF_INITSEG ! we move boot here - out of the way +SETUPSEG = DEF_SETUPSEG ! setup starts here +SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). + +! ROOT_DEV & SWAP_DEV are now written by "build". +ROOT_DEV = 0 +SWAP_DEV = 0 +#ifndef SVGA_MODE +#define SVGA_MODE ASK_VGA +#endif +#ifndef RAMDISK +#define RAMDISK 0 +#endif +#ifndef CONFIG_ROOT_RDONLY +#define CONFIG_ROOT_RDONLY 0 +#endif + +! ld86 requires an entry symbol. This may as well be the usual one. +.globl _main +_main: +#if 0 /* hook for debugger, harmless unless BIOS is fussy (old HP) */ + int 3 +#endif + mov ax,#BOOTSEG + mov ds,ax + mov ax,#INITSEG + mov es,ax + mov cx,#256 + sub si,si + sub di,di + cld + rep + movsw + jmpi go,INITSEG + +go: mov ax,cs + mov dx,#0x4000-12 ! 0x4000 is arbitrary value >= length of + ! bootsect + length of setup + room for stack + ! 12 is disk parm size + +! bde - changed 0xff00 to 0x4000 to use debugger at 0x6400 up (bde). We +! wouldn't have to worry about this if we checked the top of memory. Also +! my BIOS can be configured to put the wini drive tables in high memory +! instead of in the vector table. The old stack might have clobbered the +! drive table. + + mov ds,ax + mov es,ax + mov ss,ax ! put stack at INITSEG:0x4000-12. + mov sp,dx +/* + * Many BIOS's default disk parameter tables will not + * recognize multi-sector reads beyond the maximum sector number + * specified in the default diskette parameter tables - this may + * mean 7 sectors in some cases. + * + * Since single sector reads are slow and out of the question, + * we must take care of this by creating new parameter tables + * (for the first disk) in RAM. We will set the maximum sector + * count to 18 - the most we will encounter on an HD 1.44. + * + * High doesn't hurt. Low does. + * + * Segments are as follows: ds=es=ss=cs - INITSEG, + * fs = 0, gs = parameter table segment + */ + + push #0 + pop fs + mov bx,#0x78 ! fs:bx is parameter table address + seg fs + lgs si,(bx) ! gs:si is source + + mov di,dx ! es:di is destination + mov cx,#6 ! copy 12 bytes + cld + + rep + seg gs + movsw + + mov di,dx + movb 4(di),*18 ! patch sector count + + seg fs + mov (bx),di + seg fs + mov 2(bx),es + + mov ax,cs + mov fs,ax + mov gs,ax + + xor ah,ah ! reset FDC + xor dl,dl + int 0x13 + +! load the setup-sectors directly after the bootblock. +! Note that 'es' is already set up. + +load_setup: + xor dx, dx ! drive 0, head 0 + mov cx,#0x0002 ! sector 2, track 0 + mov bx,#0x0200 ! address = 512, in INITSEG + mov ax,#0x0200+SETUPSECS ! service 2, nr of sectors + ! (assume all on head 0, track 0) + int 0x13 ! read it + jnc ok_load_setup ! ok - continue + + push ax ! dump error code + call print_nl + mov bp, sp + call print_hex + pop ax + + xor dl, dl ! reset FDC + xor ah, ah + int 0x13 + jmp load_setup + +ok_load_setup: + +! Get disk drive parameters, specifically nr of sectors/track + +#if 0 + +! bde - the Phoenix BIOS manual says function 0x08 only works for fixed +! disks. It doesn't work for one of my BIOS's (1987 Award). It was +! fatal not to check the error code. + + xor dl,dl + mov ah,#0x08 ! AH=8 is get drive parameters + int 0x13 + xor ch,ch +#else + +! It seems that there is no BIOS call to get the number of sectors. Guess +! 18 sectors if sector 18 can be read, 15 if sector 15 can be read. +! Otherwise guess 9. + + xor dx, dx ! drive 0, head 0 + mov cx,#0x0012 ! sector 18, track 0 + mov bx,#0x0200+SETUPSECS*0x200 ! address after setup (es = cs) + mov ax,#0x0201 ! service 2, 1 sector + int 0x13 + jnc got_sectors + mov cl,#0x0f ! sector 15 + mov ax,#0x0201 ! service 2, 1 sector + int 0x13 + jnc got_sectors + mov cl,#0x09 + +#endif + +got_sectors: + seg cs + mov sectors,cx + mov ax,#INITSEG + mov es,ax + +! Print some inane message + + mov ah,#0x03 ! read cursor pos + xor bh,bh + int 0x10 + + mov cx,#9 + mov bx,#0x0007 ! page 0, attribute 7 (normal) + mov bp,#msg1 + mov ax,#0x1301 ! write string, move cursor + int 0x10 + +! ok, we've written the message, now +! we want to load the system (at 0x10000) + + mov ax,#SYSSEG + mov es,ax ! segment of 0x010000 + call read_it + call kill_motor + call print_nl + +! After that we check which root-device to use. If the device is +! defined (!= 0), nothing is done and the given device is used. +! Otherwise, either /dev/PS0 (2,28) or /dev/at0 (2,8), depending +! on the number of sectors that the BIOS reports currently. + + seg cs + mov ax,root_dev + or ax,ax + jne root_defined + seg cs + mov bx,sectors + mov ax,#0x0208 ! /dev/ps0 - 1.2Mb + cmp bx,#15 + je root_defined + mov ax,#0x021c ! /dev/PS0 - 1.44Mb + cmp bx,#18 + je root_defined + mov ax,#0x0200 ! /dev/fd0 - autodetect +root_defined: + seg cs + mov root_dev,ax + +! after that (everyting loaded), we jump to +! the setup-routine loaded directly after +! the bootblock: + + jmpi 0,SETUPSEG + +! This routine loads the system at address 0x10000, making sure +! no 64kB boundaries are crossed. We try to load it as fast as +! possible, loading whole tracks whenever we can. +! +! in: es - starting address segment (normally 0x1000) +! +sread: .word 1+SETUPSECS ! sectors read of current track +head: .word 0 ! current head +track: .word 0 ! current track + +read_it: + mov ax,es + test ax,#0x0fff +die: jne die ! es must be at 64kB boundary + xor bx,bx ! bx is starting address within segment +rp_read: + mov ax,es + sub ax,#SYSSEG + cmp ax,syssize ! have we loaded all yet? + jbe ok1_read + ret +ok1_read: + seg cs + mov ax,sectors + sub ax,sread + mov cx,ax + shl cx,#9 + add cx,bx + jnc ok2_read + je ok2_read + xor ax,ax + sub ax,bx + shr ax,#9 +ok2_read: + call read_track + mov cx,ax + add ax,sread + seg cs + cmp ax,sectors + jne ok3_read + mov ax,#1 + sub ax,head + jne ok4_read + inc track +ok4_read: + mov head,ax + xor ax,ax +ok3_read: + mov sread,ax + shl cx,#9 + add bx,cx + jnc rp_read + mov ax,es + add ah,#0x10 + mov es,ax + xor bx,bx + jmp rp_read + +read_track: + pusha + pusha + mov ax, #0xe2e ! loading... message 2e = . + mov bx, #7 + int 0x10 + popa + + mov dx,track + mov cx,sread + inc cx + mov ch,dl + mov dx,head + mov dh,dl + and dx,#0x0100 + mov ah,#2 + + push dx ! save for error dump + push cx + push bx + push ax + + int 0x13 + jc bad_rt + add sp, #8 + popa + ret + +bad_rt: push ax ! save error code + call print_all ! ah = error, al = read + + + xor ah,ah + xor dl,dl + int 0x13 + + + add sp, #10 + popa + jmp read_track + +/* + * print_all is for debugging purposes. + * It will print out all of the registers. The assumption is that this is + * called from a routine, with a stack frame like + * dx + * cx + * bx + * ax + * error + * ret <- sp + * +*/ + +print_all: + mov cx, #5 ! error code + 4 registers + mov bp, sp + +print_loop: + push cx ! save count left + call print_nl ! nl for readability + + cmp cl, 5 + jae no_reg ! see if register name is needed + + mov ax, #0xe05 + 'A - 1 + sub al, cl + int 0x10 + + mov al, #'X + int 0x10 + + mov al, #': + int 0x10 + +no_reg: + add bp, #2 ! next register + call print_hex ! print it + pop cx + loop print_loop + ret + +print_nl: + mov ax, #0xe0d ! CR + int 0x10 + mov al, #0xa ! LF + int 0x10 + ret + +/* + * print_hex is for debugging purposes, and prints the word + * pointed to by ss:bp in hexadecmial. +*/ + +print_hex: + mov cx, #4 ! 4 hex digits + mov dx, (bp) ! load word into dx +print_digit: + rol dx, #4 ! rotate so that lowest 4 bits are used + mov ah, #0xe + mov al, dl ! mask off so we have only next nibble + and al, #0xf + add al, #'0 ! convert to 0-based digit + cmp al, #'9 ! check for overflow + jbe good_digit + add al, #'A - '0 - 10 + +good_digit: + int 0x10 + loop print_digit + ret + + +/* + * This procedure turns off the floppy drive motor, so + * that we enter the kernel in a known state, and + * don't have to worry about it later. + */ +kill_motor: + push dx + mov dx,#0x3f2 + xor al, al + outb + pop dx + ret + +sectors: + .word 0 + +msg1: + .byte 13,10 + .ascii "Loading" + +.org 498 +root_flags: + .word CONFIG_ROOT_RDONLY +syssize: + .word SYSSIZE +swap_dev: + .word SWAP_DEV +ram_size: + .word RAMDISK +vid_mode: + .word SVGA_MODE +root_dev: + .word ROOT_DEV +boot_flag: + .word 0xAA55 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/boot/head.S b/gems-kernel.git/source/THIRDPARTY/linux-old/boot/head.S new file mode 100644 index 000000000..493fcbc16 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/boot/head.S @@ -0,0 +1,354 @@ +/* + * linux/boot/head.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * head.S contains the 32-bit startup code. + */ + +.text +.globl _idt,_gdt, +.globl _swapper_pg_dir,_pg0 +.globl _empty_bad_page +.globl _empty_bad_page_table +.globl _empty_zero_page +.globl _tmp_floppy_area,_floppy_track_buffer + +#include +#include + +#define CL_MAGIC_ADDR 0x90020 +#define CL_MAGIC 0xA33F +#define CL_BASE_ADDR 0x90000 +#define CL_OFFSET 0x90022 + +/* + * swapper_pg_dir is the main page directory, address 0x00001000 (or at + * address 0x00101000 for a compressed boot). + */ +startup_32: + cld + movl $(KERNEL_DS),%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp +/* + * Clear BSS first so that there are no surprises... + */ + xorl %eax,%eax + movl $__edata,%edi + movl $__end,%ecx + subl %edi,%ecx + cld + rep + stosb +/* + * start system 32-bit setup. We need to re-do some of the things done + * in 16-bit mode for the "real" operations. + */ + call setup_idt + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* + * Initialize eflags. Some BIOS's leave bits like NT set. This would + * confuse the debugger if this code is traced. + * XXX - best to initialize before switching to protected mode. + */ + pushl $0 + popfl +/* + * Copy bootup parameters out of the way. First 2kB of + * _empty_zero_page is for boot parameters, second 2kB + * is for the command line. + */ + movl $0x90000,%esi + movl $_empty_zero_page,%edi + movl $512,%ecx + cld + rep + movsl + xorl %eax,%eax + movl $512,%ecx + rep + stosl + cmpw $(CL_MAGIC),CL_MAGIC_ADDR + jne 1f + movl $_empty_zero_page+2048,%edi + movzwl CL_OFFSET,%esi + addl $(CL_BASE_ADDR),%esi + movl $2048,%ecx + rep + movsb +1: +/* check if it is 486 or 386. */ +/* + * XXX - this does a lot of unnecessary setup. Alignment checks don't + * apply at our cpl of 0 and the stack ought to be aligned already, and + * we don't need to preserve eflags. + */ + movl %esp,%edi # save stack pointer + andl $0xfffffffc,%esp # align stack to avoid AC fault + movl $3,_x86 + pushfl # push EFLAGS + popl %eax # get EFLAGS + movl %eax,%ecx # save original EFLAGS + xorl $0x40000,%eax # flip AC bit in EFLAGS + pushl %eax # copy to EFLAGS + popfl # set EFLAGS + pushfl # get new EFLAGS + popl %eax # put it in eax + xorl %ecx,%eax # change in flags + andl $0x40000,%eax # check if AC bit changed + je is386 + movl $4,_x86 + movl %ecx,%eax + xorl $0x200000,%eax # check ID flag + pushl %eax + popfl # if we are on a straight 486DX, SX, or + pushfl # 487SX we can't change it + popl %eax + xorl %ecx,%eax + andl $0x200000,%eax + je is486 +isnew: pushl %ecx # restore original EFLAGS + popfl + movl $1, %eax # Use the CPUID instruction to + .byte 0x0f, 0xa2 # check the processor type + andl $0xf00, %eax # Set _x86 with the family + shrl $8, %eax # returned. + movl %eax, _x86 + movl %edi,%esp # restore esp + movl %cr0,%eax # 486+ + andl $0x80000011,%eax # Save PG,PE,ET + orl $0x50022,%eax # set AM, WP, NE and MP + jmp 2f +is486: pushl %ecx # restore original EFLAGS + popfl + movl %edi,%esp # restore esp + movl %cr0,%eax # 486 + andl $0x80000011,%eax # Save PG,PE,ET + orl $0x50022,%eax # set AM, WP, NE and MP + jmp 2f +is386: pushl %ecx # restore original EFLAGS + popfl + movl %edi,%esp # restore esp + movl %cr0,%eax # 386 + andl $0x80000011,%eax # Save PG,PE,ET + orl $2,%eax # set MP +2: movl %eax,%cr0 + call check_x87 + call setup_paging + lgdt gdt_descr + lidt idt_descr + ljmp $(KERNEL_CS),$1f +1: movl $(KERNEL_DS),%eax # reload all the segment registers + mov %ax,%ds # after changing gdt. + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + xorl %eax,%eax + lldt %ax + pushl %eax # These are the parameters to main :-) + pushl %eax + pushl %eax + cld # gcc2 wants the direction flag cleared at all times + call _start_kernel +L6: + jmp L6 # main should never return here, but + # just in case, we know what happens. + +/* + * We depend on ET to be correct. This checks for 287/387. + */ +check_x87: + movl $0,_hard_math + clts + fninit + fstsw %ax + cmpb $0,%al + je 1f + movl %cr0,%eax /* no coprocessor: have to set bits */ + xorl $4,%eax /* set EM */ + movl %eax,%cr0 + ret +.align 2 +1: movl $1,_hard_math + .byte 0xDB,0xE4 /* fsetpm for 287, ignored by 387 */ + ret + +/* + * setup_idt + * + * sets up a idt with 256 entries pointing to + * ignore_int, interrupt gates. It doesn't actually load + * idt - that can be done only after paging has been enabled + * and the kernel moved to 0xC0000000. Interrupts + * are enabled elsewhere, when we can be relatively + * sure everything is ok. + */ +setup_idt: + lea ignore_int,%edx + movl $(KERNEL_CS << 16),%eax + movw %dx,%ax /* selector = 0x0010 = cs */ + movw $0x8E00,%dx /* interrupt gate - dpl=0, present */ + + lea _idt,%edi + mov $256,%ecx +rp_sidt: + movl %eax,(%edi) + movl %edx,4(%edi) + addl $8,%edi + dec %ecx + jne rp_sidt + ret + + +/* + * Setup_paging + * + * This routine sets up paging by setting the page bit + * in cr0. The page tables are set up, identity-mapping + * the first 4MB. The rest are initialized later. + * + * (ref: added support for up to 32mb, 17Apr92) -- Rik Faith + * (ref: update, 25Sept92) -- croutons@crunchy.uucp + * (ref: 92.10.11 - Linus Torvalds. Corrected 16M limit - no upper memory limit) + */ +.align 2 +setup_paging: + movl $1024*2,%ecx /* 2 pages - swapper_pg_dir+1 page table */ + xorl %eax,%eax + movl $_swapper_pg_dir,%edi /* swapper_pg_dir is at 0x1000 */ + cld;rep;stosl +/* Identity-map the kernel in low 4MB memory for ease of transition */ + movl $_pg0+7,_swapper_pg_dir /* set present bit/user r/w */ +/* But the real place is at 0xC0000000 */ + movl $_pg0+7,_swapper_pg_dir+3072 /* set present bit/user r/w */ + movl $_pg0+4092,%edi + movl $0x03ff007,%eax /* 4Mb - 4096 + 7 (r/w user,p) */ + std +1: stosl /* fill the page backwards - more efficient :-) */ + subl $0x1000,%eax + jge 1b + cld + movl $_swapper_pg_dir,%eax + movl %eax,%cr3 /* cr3 - page directory start */ + movl %cr0,%eax + orl $0x80000000,%eax + movl %eax,%cr0 /* set paging (PG) bit */ + ret /* this also flushes the prefetch-queue */ + +/* + * page 0 is made non-existent, so that kernel NULL pointer references get + * caught. Thus the swapper page directory has been moved to 0x1000 + * + * XXX Actually, the swapper page directory is at 0x1000 plus 1 megabyte, + * with the introduction of the compressed boot code. Theoretically, + * the original design of overlaying the startup code with the swapper + * page directory is still possible --- it would reduce the size of the kernel + * by 2-3k. This would be a good thing to do at some point..... + */ +.org 0x1000 +_swapper_pg_dir: +/* + * The page tables are initialized to only 4MB here - the final page + * tables are set up later depending on memory size. + */ +.org 0x2000 +_pg0: + +.org 0x3000 +_empty_bad_page: + +.org 0x4000 +_empty_bad_page_table: + +.org 0x5000 +_empty_zero_page: + +.org 0x6000 +/* + * tmp_floppy_area is used by the floppy-driver when DMA cannot + * reach to a buffer-block. It needs to be aligned, so that it isn't + * on a 64kB border. + */ +_tmp_floppy_area: + .fill 1024,1,0 +/* + * floppy_track_buffer is used to buffer one track of floppy data: it + * has to be separate from the tmp_floppy area, as otherwise a single- + * sector read/write can mess it up. It can contain one full track of + * data (18*2*512 bytes). + */ +_floppy_track_buffer: + .fill 512*2*18,1,0 + +/* This is the default interrupt "handler" :-) */ +int_msg: + .asciz "Unknown interrupt\n" +.align 2 +ignore_int: + cld + pushl %eax + pushl %ecx + pushl %edx + push %ds + push %es + push %fs + movl $(KERNEL_DS),%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + pushl $int_msg + call _printk + popl %eax + pop %fs + pop %es + pop %ds + popl %edx + popl %ecx + popl %eax + iret + +/* + * The interrupt descriptor table has room for 256 idt's + */ +.align 4 +.word 0 +idt_descr: + .word 256*8-1 # idt contains 256 entries + .long 0xc0000000+_idt + +.align 4 +_idt: + .fill 256,8,0 # idt is uninitialized + +.align 4 +.word 0 +gdt_descr: + .word (8+2*NR_TASKS)*8-1 + .long 0xc0000000+_gdt + +/* + * This gdt setup gives the kernel a 1GB address space at virtual + * address 0xC0000000 - space enough for expansion, I hope. + */ +.align 4 +_gdt: + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x0000000000000000 /* not used */ + .quad 0xc0c39a000000ffff /* 0x10 kernel 1GB code at 0xC0000000 */ + .quad 0xc0c392000000ffff /* 0x18 kernel 1GB data at 0xC0000000 */ + .quad 0x00cbfa000000ffff /* 0x23 user 3GB code at 0x00000000 */ + .quad 0x00cbf2000000ffff /* 0x2b user 3GB data at 0x00000000 */ + .quad 0x0000000000000000 /* not used */ + .quad 0x0000000000000000 /* not used */ + .fill 2*NR_TASKS,8,0 /* space for LDT's and TSS's etc */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/boot/setup.S b/gems-kernel.git/source/THIRDPARTY/linux-old/boot/setup.S new file mode 100644 index 000000000..2ba710ff2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/boot/setup.S @@ -0,0 +1,869 @@ +! +! setup.S Copyright (C) 1991, 1992 Linus Torvalds +! +! setup.s is responsible for getting the system data from the BIOS, +! and putting them into the appropriate places in system memory. +! both setup.s and system has been loaded by the bootblock. +! +! This code asks the bios for memory/disk/other parameters, and +! puts them in a "safe" place: 0x90000-0x901FF, ie where the +! boot-block used to be. It is then up to the protected mode +! system to read them from there before the area is overwritten +! for buffer-blocks. +! +! Move PS/2 aux init code to psaux.c +! (troyer@saifr00.cfsat.Honeywell.COM) 03Oct92 +! +! some changes and additional features by Christoph Niemann, March 1993 +! (niemann@rubdv15.ETDV.Ruhr-Uni-Bochum.De) +! + +! NOTE! These had better be the same as in bootsect.s! +#include +#include + +#ifndef SVGA_MODE +#define SVGA_MODE ASK_VGA +#endif + +INITSEG = DEF_INITSEG ! we move boot here - out of the way +SYSSEG = DEF_SYSSEG ! system loaded at 0x10000 (65536). +SETUPSEG = DEF_SETUPSEG ! this is the current segment + +.globl begtext, begdata, begbss, endtext, enddata, endbss +.text +begtext: +.data +begdata: +.bss +begbss: +.text + +entry start +start: + +! ok, the read went well so we get current cursor position and save it for +! posterity. + + mov ax,#INITSEG ! this is done in bootsect already, but... + mov ds,ax + +! Get memory size (extended mem, kB) + + mov ah,#0x88 + int 0x15 + mov [2],ax + +! set the keyboard repeat rate to the max + + mov ax,#0x0305 + xor bx,bx ! clear bx + int 0x16 + +! check for EGA/VGA and some config parameters + + mov ah,#0x12 + mov bl,#0x10 + int 0x10 + mov [8],ax + mov [10],bx + mov [12],cx + mov ax,#0x5019 + cmp bl,#0x10 + je novga + mov ax,#0x1a00 ! Added check for EGA/VGA discrimination + int 0x10 + mov bx,ax + mov ax,#0x5019 + cmp bl,#0x1a ! 1a means VGA, anything else EGA or lower + jne novga + call chsvga +novga: mov [14],ax + mov ah,#0x03 ! read cursor pos + xor bh,bh ! clear bh + int 0x10 ! save it in known place, con_init fetches + mov [0],dx ! it from 0x90000. + +! Get video-card data: + + mov ah,#0x0f + int 0x10 + mov [4],bx ! bh = display page + mov [6],ax ! al = video mode, ah = window width + +! Get hd0 data + + xor ax,ax ! clear ax + mov ds,ax + lds si,[4*0x41] + mov ax,#INITSEG + mov es,ax + mov di,#0x0080 + mov cx,#0x10 + cld + rep + movsb + +! Get hd1 data + + xor ax,ax ! clear ax + mov ds,ax + lds si,[4*0x46] + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + cld + rep + movsb + +! Check that there IS a hd1 :-) + + mov ax,#0x01500 + mov dl,#0x81 + int 0x13 + jc no_disk1 + cmp ah,#3 + je is_disk1 +no_disk1: + mov ax,#INITSEG + mov es,ax + mov di,#0x0090 + mov cx,#0x10 + xor ax,ax ! clear ax + cld + rep + stosb +is_disk1: + +! check for PS/2 pointing device + + mov ax,#INITSEG + mov ds,ax + mov [0x1ff],#0 ! default is no pointing device + int 0x11 ! int 0x11: equipment determination + test al,#0x04 ! check if pointing device installed + jz no_psmouse + mov [0x1ff],#0xaa ! device present +no_psmouse: +! now we want to move to protected mode ... + + cli ! no interrupts allowed ! + mov al,#0x80 ! disable NMI for the bootup sequence + out #0x70,al + +! first we move the system to its rightful place + + mov ax,#0x100 ! start of destination segment + mov bx,#0x1000 ! start of source segment + cld ! 'direction'=0, movs moves forward +do_move: + mov es,ax ! destination segment + add ax,#0x100 + cmp ax,#0x9000 + jz end_move + mov ds,bx ! source segment + add bx,#0x100 + sub di,di + sub si,si + mov cx,#0x800 + rep + movsw + jmp do_move + +! then we load the segment descriptors + +end_move: + mov ax,#SETUPSEG ! right, forgot this at first. didn't work :-) + mov ds,ax + lidt idt_48 ! load idt with 0,0 + lgdt gdt_48 ! load gdt with whatever appropriate + +! that was painless, now we enable A20 + + call empty_8042 + mov al,#0xD1 ! command write + out #0x64,al + call empty_8042 + mov al,#0xDF ! A20 on + out #0x60,al + call empty_8042 + +! make sure any possible coprocessor is properly reset.. + + xor ax,ax + out #0xf0,al + call delay + out #0xf1,al + call delay + +! well, that went ok, I hope. Now we have to reprogram the interrupts :-( +! we put them right after the intel-reserved hardware interrupts, at +! int 0x20-0x2F. There they won't mess up anything. Sadly IBM really +! messed this up with the original PC, and they haven't been able to +! rectify it afterwards. Thus the bios puts interrupts at 0x08-0x0f, +! which is used for the internal hardware interrupts as well. We just +! have to reprogram the 8259's, and it isn't fun. + + mov al,#0x11 ! initialization sequence + out #0x20,al ! send it to 8259A-1 + call delay + out #0xA0,al ! and to 8259A-2 + call delay + mov al,#0x20 ! start of hardware int's (0x20) + out #0x21,al + call delay + mov al,#0x28 ! start of hardware int's 2 (0x28) + out #0xA1,al + call delay + mov al,#0x04 ! 8259-1 is master + out #0x21,al + call delay + mov al,#0x02 ! 8259-2 is slave + out #0xA1,al + call delay + mov al,#0x01 ! 8086 mode for both + out #0x21,al + call delay + out #0xA1,al + call delay + mov al,#0xFF ! mask off all interrupts for now + out #0xA1,al + call delay + mov al,#0xFB ! mask all irq's but irq2 which + out #0x21,al ! is cascaded + +! well, that certainly wasn't fun :-(. Hopefully it works, and we don't +! need no steenking BIOS anyway (except for the initial loading :-). +! The BIOS-routine wants lots of unnecessary data, and it's less +! "interesting" anyway. This is how REAL programmers do it. +! +! Well, now's the time to actually move into protected mode. To make +! things as simple as possible, we do no register set-up or anything, +! we let the gnu-compiled 32-bit programs do that. We just jump to +! absolute address 0x00000, in 32-bit protected mode. +! +! Note that the short jump isn't strictly needed, althought there are +! reasons why it might be a good idea. It won't hurt in any case. +! + mov ax,#0x0001 ! protected mode (PE) bit + lmsw ax ! This is it! + jmp flush_instr +flush_instr: + jmpi 0x1000,KERNEL_CS ! jmp offset 1000 of segment 0x10 (cs) + +! This routine checks that the keyboard command queue is empty +! (after emptying the output buffers) +! +! No timeout is used - if this hangs there is something wrong with +! the machine, and we probably couldn't proceed anyway. +empty_8042: + call delay + in al,#0x64 ! 8042 status port + test al,#1 ! output buffer? + jz no_output + call delay + in al,#0x60 ! read it + jmp empty_8042 +no_output: + test al,#2 ! is input buffer full? + jnz empty_8042 ! yes - loop + ret +! +! Read a key and return the (US-)ascii code in al, scan code in ah +! +getkey: + xor ah,ah + int 0x16 + ret + +! +! Read a key with a timeout of 30 seconds. The cmos clock is used to get +! the time. +! +getkt: + call gettime + add al,#30 ! wait 30 seconds + cmp al,#60 + jl lminute + sub al,#60 +lminute: + mov cl,al +again: mov ah,#0x01 + int 0x16 + jnz getkey ! key pressed, so get it + call gettime + cmp al,cl + jne again + mov al,#0x20 ! timeout, return default char `space' + ret + +! +! Flush the keyboard buffer +! +flush: mov ah,#0x01 + int 0x16 + jz empty + xor ah,ah + int 0x16 + jmp flush +empty: ret + +! +! Read the cmos clock. Return the seconds in al +! +gettime: + push cx + mov ah,#0x02 + int 0x1a + mov al,dh ! dh contains the seconds + and al,#0x0f + mov ah,dh + mov cl,#0x04 + shr ah,cl + aad + pop cx + ret + +! +! Delay is needed after doing i/o +! +delay: + .word 0x00eb ! jmp $+2 + ret + +! Routine trying to recognize type of SVGA-board present (if any) +! and if it recognize one gives the choices of resolution it offers. +! If one is found the resolution chosen is given by al,ah (rows,cols). + +chsvga: cld + push ds + push cs + mov ax,[0x01fa] + pop ds + mov modesave,ax + mov ax,#0xc000 + mov es,ax + mov ax,modesave + cmp ax,#NORMAL_VGA + je defvga + cmp ax,#EXTENDED_VGA + je vga50 + cmp ax,#ASK_VGA + jne svga + lea si,msg1 + call prtstr + call flush +nokey: call getkt + cmp al,#0x0d ! enter ? + je svga ! yes - svga selection + cmp al,#0x20 ! space ? + je defvga ! no - repeat + call beep + jmp nokey +defvga: mov ax,#0x5019 + pop ds + ret +/* extended vga mode: 80x50 */ +vga50: + mov ax,#0x1112 + xor bl,bl + int 0x10 ! use 8x8 font set (50 lines on VGA) + mov ax,#0x1200 + mov bl,#0x20 + int 0x10 ! use alternate print screen + mov ax,#0x1201 + mov bl,#0x34 + int 0x10 ! turn off cursor emulation + mov ah,#0x01 + mov cx,#0x0607 + int 0x10 ! turn on cursor (scan lines 6 to 7) + pop ds + mov ax,#0x5032 ! return 80x50 + ret +/* extended vga mode: 80x28 */ +vga28: + pop ax ! clean the stack + mov ax,#0x1111 + xor bl,bl + int 0x10 ! use 9x14 fontset (28 lines on VGA) + mov ah, #0x01 + mov cx,#0x0b0c + int 0x10 ! turn on cursor (scan lines 11 to 12) + pop ds + mov ax,#0x501c ! return 80x28 + ret +/* svga modes */ +svga: cld + lea si,id9GXE ! Check for the #9GXE (jyanowit@orixa.mtholyoke.edu,thanks dlm40629@uxa.cso.uiuc.edu) + mov di,#0x49 ! id string is at c000:049 + mov cx,#0x11 ! length of "Graphics Power By" + repe + cmpsb + jne of1280 +is9GXE: lea si,dsc9GXE ! table of descriptions of video modes for BIOS + lea di,mo9GXE ! table of sizes of video modes for my BIOS + br selmod ! go ask for video mode +of1280: cld + lea si,idf1280 ! Check for Orchid F1280 (dingbat@diku.dk) + mov di,#0x10a ! id string is at c000:010a + mov cx,#0x21 ! length + repe + cmpsb + jne nf1280 +isVRAM: lea si,dscf1280 + lea di,mof1280 + br selmod +nf1280: lea si,idVRAM + mov di,#0x10a + mov cx,#0x0c + repe + cmpsb + je isVRAM + cld + lea si,idati ! Check ATI 'clues' + mov di,#0x31 + mov cx,#0x09 + repe + cmpsb + jne noati + lea si,dscati + lea di,moati + br selmod +noati: mov ax,#0x200f ! Check Ahead 'clues' + mov dx,#0x3ce + out dx,ax + inc dx + in al,dx + cmp al,#0x20 + je isahed + cmp al,#0x21 + jne noahed +isahed: lea si,dscahead + lea di,moahead + br selmod +noahed: mov dx,#0x3c3 ! Check Chips & Tech. 'clues' + in al,dx + or al,#0x10 + out dx,al + mov dx,#0x104 + in al,dx + mov bl,al + mov dx,#0x3c3 + in al,dx + and al,#0xef + out dx,al + cmp bl,[idcandt] + jne nocant + lea si,dsccandt + lea di,mocandt + br selmod +nocant: mov dx,#0x3d4 ! Check Cirrus 'clues' + mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + xor al,al + out dx,al + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + xor ah,ah + shl al,#4 + mov cx,ax + mov al,bh + shr al,#4 + add cx,ax + shl cx,#8 + add cx,#6 + mov ax,cx + mov dx,#0x3c4 + out dx,ax + inc dx + in al,dx + and al,al + jnz nocirr + mov al,bh + out dx,al + in al,dx + cmp al,#0x01 + jne nocirr + call rst3d4 + lea si,dsccirrus + lea di,mocirrus + br selmod +rst3d4: mov dx,#0x3d4 + mov al,bl + xor ah,ah + shl ax,#8 + add ax,#0x0c + out dx,ax + ret +nocirr: call rst3d4 ! Check Everex 'clues' + mov ax,#0x7000 + xor bx,bx + int 0x10 + cmp al,#0x70 + jne noevrx + shr dx,#4 + cmp dx,#0x678 + je istrid + cmp dx,#0x236 + je istrid + lea si,dsceverex + lea di,moeverex + br selmod +istrid: lea cx,ev2tri + jmp cx +noevrx: lea si,idgenoa ! Check Genoa 'clues' + xor ax,ax + seg es + mov al,[0x37] + mov di,ax + mov cx,#0x04 + dec si + dec di +l1: inc si + inc di + mov al,(si) + test al,al + jz l2 + seg es + cmp al,(di) +l2: loope l1 + cmp cx,#0x00 + jne nogen + lea si,dscgenoa + lea di,mogenoa + br selmod +nogen: cld + lea si,idoakvga + mov di,#0x08 + mov cx,#0x08 + repe + cmpsb + jne nooak + lea si,dscoakvga + lea di,mooakvga + br selmod +nooak: cld + lea si,idparadise ! Check Paradise 'clues' + mov di,#0x7d + mov cx,#0x04 + repe + cmpsb + jne nopara + lea si,dscparadise + lea di,moparadise + br selmod +nopara: mov dx,#0x3c4 ! Check Trident 'clues' + mov al,#0x0e + out dx,al + inc dx + in al,dx + xchg ah,al + xor al,al + out dx,al + in al,dx + xchg al,ah + mov bl,al ! Strange thing ... in the book this wasn't + and bl,#0x02 ! necessary but it worked on my card which + jz setb2 ! is a trident. Without it the screen goes + and al,#0xfd ! blurred ... + jmp clrb2 ! +setb2: or al,#0x02 ! +clrb2: out dx,al + and ah,#0x0f + cmp ah,#0x02 + jne notrid +ev2tri: lea si,dsctrident + lea di,motrident + jmp selmod +notrid: mov dx,#0x3cd ! Check Tseng 'clues' + in al,dx ! Could things be this simple ! :-) + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + mov ah,al + mov al,bl + out dx,al + cmp ah,#0x55 + jne notsen + lea si,dsctseng + lea di,motseng + jmp selmod +notsen: mov dx,#0x3cc ! Check Video7 'clues' + in al,dx + mov dx,#0x3b4 + and al,#0x01 + jz even7 + mov dx,#0x3d4 +even7: mov al,#0x0c + out dx,al + inc dx + in al,dx + mov bl,al + mov al,#0x55 + out dx,al + in al,dx + dec dx + mov al,#0x1f + out dx,al + inc dx + in al,dx + mov bh,al + dec dx + mov al,#0x0c + out dx,al + inc dx + mov al,bl + out dx,al + mov al,#0x55 + xor al,#0xea + cmp al,bh + jne novid7 + lea si,dscvideo7 + lea di,movideo7 + jmp selmod +novid7: lea si,dsunknown + lea di,mounknown +selmod: xor cx,cx + mov cl,(di) + mov ax,modesave + cmp ax,#ASK_VGA + je askmod + cmp ax,#NORMAL_VGA + je askmod + cmp al,cl + jl gotmode + push si + lea si,msg4 + call prtstr + pop si +askmod: push si + lea si,msg2 + call prtstr + pop si + push si + push cx +tbl: pop bx + push bx + mov al,bl + sub al,cl + call modepr + lodsw + xchg al,ah + call dprnt + xchg ah,al + push ax + mov al,#0x78 + call prnt1 + pop ax + call dprnt + push si + lea si,crlf ! print CR+LF + call prtstr + pop si + loop tbl + pop cx + lea si,msg3 + call prtstr + pop si + add cl,#0x30 + jmp nonum +nonumb: call beep +nonum: call getkey + cmp al,#0x30 ! ascii `0' + jb nonumb + cmp al,#0x3a ! ascii `9' + jbe number + cmp al,#0x61 ! ascii `a' + jb nonumb + cmp al,#0x7a ! ascii `z' + ja nonumb + sub al,#0x27 + cmp al,cl + jae nonumb + sub al,#0x30 + jmp gotmode +number: cmp al,cl + jae nonumb + sub al,#0x30 +gotmode: xor ah,ah + or al,al + beq vga50 + push ax + dec ax + beq vga28 + add di,ax + mov al,(di) + int 0x10 + pop ax + shl ax,#1 + add si,ax + lodsw + pop ds + ret + +! Routine to print asciiz-string at DS:SI + +prtstr: lodsb + and al,al + jz fin + call prnt1 + jmp prtstr +fin: ret + +! Routine to print a decimal value on screen, the value to be +! printed is put in al (i.e 0-255). + +dprnt: push ax + push cx + xor ah,ah ! Clear ah + mov cl,#0x0a + idiv cl + cmp al,#0x09 + jbe lt100 + call dprnt + jmp skip10 +lt100: add al,#0x30 + call prnt1 +skip10: mov al,ah + add al,#0x30 + call prnt1 + pop cx + pop ax + ret + +! +! Routine to print the mode number key on screen. Mode numbers +! 0-9 print the ascii values `0' to '9', 10-35 are represented by +! the letters `a' to `z'. This routine prints some spaces around the +! mode no. +! + +modepr: push ax + cmp al,#0x0a + jb digit ! Here is no check for number > 35 + add al,#0x27 +digit: add al,#0x30 + mov modenr, al + push si + lea si, modestring + call prtstr + pop si + pop ax + ret + +! Part of above routine, this one just prints ascii al + +prnt1: push ax + push cx + xor bh,bh + mov cx,#0x01 + mov ah,#0x0e + int 0x10 + pop cx + pop ax + ret + +beep: mov al,#0x07 + jmp prnt1 + +gdt: + .word 0,0,0,0 ! dummy + + .word 0,0,0,0 ! unused + + .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) + .word 0x0000 ! base address=0 + .word 0x9A00 ! code read/exec + .word 0x00C0 ! granularity=4096, 386 + + .word 0x07FF ! 8Mb - limit=2047 (2048*4096=8Mb) + .word 0x0000 ! base address=0 + .word 0x9200 ! data read/write + .word 0x00C0 ! granularity=4096, 386 + +idt_48: + .word 0 ! idt limit=0 + .word 0,0 ! idt base=0L + +gdt_48: + .word 0x800 ! gdt limit=2048, 256 GDT entries + .word 512+gdt,0x9 ! gdt base = 0X9xxxx + +msg1: .ascii "Press to see SVGA-modes available, to continue or wait 30 secs." + db 0x0d, 0x0a, 0x0a, 0x00 +msg2: .ascii "Mode: COLSxROWS:" + db 0x0d, 0x0a, 0x0a, 0x00 +msg3: db 0x0d, 0x0a + .ascii "Choose mode by pressing the corresponding number or letter." +crlf: db 0x0d, 0x0a, 0x00 +msg4: .ascii "You passed an undefined mode number to setup. Please choose a new mode." + db 0x0d, 0x0a, 0x0a, 0x07, 0x00 +modestring: .ascii " " +modenr: db 0x00 ! mode number + .ascii ": " + db 0x00 + +idati: .ascii "761295520" +idcandt: .byte 0xa5 +idgenoa: .byte 0x77, 0x00, 0x99, 0x66 +idparadise: .ascii "VGA=" +idoakvga: .ascii "OAK VGA " +idf1280: .ascii "Orchid Technology Fahrenheit 1280" +id9GXE: .ascii "Graphics Power By" +idVRAM: .ascii "Stealth VRAM" + +! Manufacturer: Numofmodes+2: Mode: +! Number of modes is the number of chip-specific svga modes plus the extended +! modes available on any vga (currently 2) + +moati: .byte 0x04, 0x23, 0x33 +moahead: .byte 0x07, 0x22, 0x23, 0x24, 0x2f, 0x34 +mocandt: .byte 0x04, 0x60, 0x61 +mocirrus: .byte 0x06, 0x1f, 0x20, 0x22, 0x31 +moeverex: .byte 0x0c, 0x03, 0x04, 0x07, 0x08, 0x0a, 0x0b, 0x16, 0x18, 0x21, 0x40 +mogenoa: .byte 0x0c, 0x58, 0x5a, 0x60, 0x61, 0x62, 0x63, 0x64, 0x72, 0x74, 0x78 +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 0x08, 0x00, 0x07, 0x4e, 0x4f, 0x50, 0x51 +mo9GXE: .byte 0x04, 0x54, 0x55 +mof1280: .byte 0x04, 0x54, 0x55 +mounknown: .byte 0x02 + +! msb = Cols lsb = Rows: +! The first two modes are standard vga modes available on any vga. +! mode 0 is 80x50 and mode 1 is 80x28 + +dscati: .word 0x5032, 0x501c, 0x8419, 0x842c +dscahead: .word 0x5032, 0x501c, 0x842c, 0x8419, 0x841c, 0xa032, 0x5042 +dsccandt: .word 0x5032, 0x501c, 0x8419, 0x8432 +dsccirrus: .word 0x5032, 0x501c, 0x8419, 0x842c, 0x841e, 0x6425 +dsceverex: .word 0x5032, 0x501c, 0x5022, 0x503c, 0x642b, 0x644b, 0x8419, 0x842c, 0x501e, 0x641b, 0xa040, 0x841e +dscgenoa: .word 0x5032, 0x501c, 0x5020, 0x642a, 0x8419, 0x841d, 0x8420, 0x842c, 0x843c, 0x503c, 0x5042, 0x644b +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, 0x503c, 0x843c, 0x8419, 0x842b +dscf1280: .word 0x5032, 0x501c, 0x842b, 0x8419 +dsc9GXE: .word 0x5032, 0x501c, 0x842b, 0x8419 +dsunknown: .word 0x5032, 0x501c +modesave: .word SVGA_MODE + + +.text +endtext: +.data +enddata: +.bss +endbss: diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/config.in b/gems-kernel.git/source/THIRDPARTY/linux-old/config.in new file mode 100644 index 000000000..61146caeb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/config.in @@ -0,0 +1,139 @@ +# +# For a description of the syntax of this configuration file, +# see the Configure script. +# +* +* General setup +* +bool 'Kernel math emulation' CONFIG_MATH_EMULATION y +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 'System V IPC' CONFIG_SYSVIPC y +bool 'Use -m486 flag for 486-specific optimizations' CONFIG_M486 y +* +* Program binary formats +* +bool 'Elf executables' CONFIG_BINFMT_ELF y +bool 'COFF executables' CONFIG_BINFMT_COFF y +* +* SCSI support +* +bool 'SCSI support?' CONFIG_SCSI n +if [ "$CONFIG_SCSI" = "n" ] +: +: Skipping SCSI configuration options... +: +else + * + * SCSI support type (disk, tape, CDrom) + * +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 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 +if [ "$CONFIG_ETHERCARDS" = "n" ] +: +: Skipping ethercard configuration options... +: +else +bool 'SLIP (serial line) support' CONFIG_SLIP n +if [ "$CONFIG_SLIP" = "y" ] + bool ' CSLIP compressed headers' SL_COMPRESSED y +# bool ' SLIP debugging on' SL_DUMP y +fi +#bool 'PPP (point-to-point) support' CONFIG_PPP n +bool 'PLIP (parallel port) support' CONFIG_PLIP n +bool 'NE2000/NE1000 support' CONFIG_NE2000 n +bool 'WD80*3 support' CONFIG_WD80x3 y +bool 'SMC Ultra support' CONFIG_ULTRA n +bool '3c501 support' CONFIG_EL1 n +bool '3c503 support' CONFIG_EL2 n +#bool '3c505 support' CONFIG_ELPLUS n +#bool '3c507 support' CONFIG_EL16 n +bool '3c509/3c579 support' CONFIG_EL3 n +bool 'HP PCLAN support' CONFIG_HPLAN n +bool 'AT1500 and NE2100 (LANCE and PCnet-ISA) support' CONFIG_LANCE n +bool 'AT1700 support' CONFIG_AT1700 n +#bool 'Zenith Z-Note support' CONFIG_ZNET n +#bool 'EtherExpress support' CONFIG_EEXPRESS n +#bool 'DEPCA support' CONFIG_DEPCA n +#bool 'NI52** support' CONFIG_NI52 n +#bool 'NI65** support' CONFIG_NI65 n +#bool 'Ansel Communications EISA 3200 support' CONFIG_AC3200 n +#bool 'Cabletron E21xx support (not recommended)' CONFIG_E21 n +bool 'D-Link DE600 pocket adaptor support' CONFIG_DE600 n +bool 'AT-LAN-TEC/RealTek pocket adaptor support' CONFIG_ATP n +fi +* +bool 'Sony CDU31A CDROM driver support' CONFIG_CDU31A n +bool 'Mitsumi CDROM driver support' CONFIG_MCD n +bool 'Matsushita/Panasonic CDROM driver support' CONFIG_SBPCD n +* +* Filesystems +* +bool 'Standard (minix) fs support' CONFIG_MINIX_FS y +bool 'Extended fs support' CONFIG_EXT_FS n +bool 'Second extended fs support' CONFIG_EXT2_FS y +bool 'xiafs filesystem support' CONFIG_XIA_FS n +bool 'msdos fs support' CONFIG_MSDOS_FS y +bool '/proc filesystem support' CONFIG_PROC_FS y +bool 'NFS filesystem support' CONFIG_NFS_FS y +bool 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS n +bool 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS n +bool 'System V and Coherent filesystem support' CONFIG_SYSV_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 'Parallel printer support' CONFIG_PRINTER y +bool 'Logitech busmouse support' CONFIG_BUSMOUSE n +bool 'PS/2 mouse (aka "auxiliary device") support' CONFIG_PSMOUSE y +if [ "$CONFIG_PSMOUSE" = "y" ] +bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE y +fi +bool 'Microsoft busmouse support' CONFIG_MS_BUSMOUSE n +bool 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE n +bool 'Selection (cut and paste for virtual consoles)' CONFIG_SELECTION y +bool 'QIC-02 tape support' CONFIG_TAPE_QIC02 n +bool 'QIC-117 tape support' CONFIG_FTAPE n +if [ "$CONFIG_FTAPE" = "y" ] +int ' number of ftape buffers' NR_FTAPE_BUFFERS 3 +fi +* +* Sound +* +bool 'Sound card support' CONFIG_SOUND n +* +* Kernel hacking +* +#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 y +fi +if [ "$CONFIG_SOUND" = "y" ] + exec touch .makesound +else + exec rm -f .makesound +fi diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/Makefile new file mode 100644 index 000000000..3563c1d4b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/Makefile @@ -0,0 +1,50 @@ +# +# Makefile for wm-FPU-emu +# + +#DEBUG = -DDEBUGGING +DEBUG = +PARANOID = -DPARANOID +REENTRANT = -DREENTRANT_FPU +CFLAGS := $(CFLAGS) $(PARANOID) $(DEBUG) -fno-builtin + +.c.o: + $(CC) $(CFLAGS) $(MATH_EMULATION) -c $< + +.S.o: + $(CC) -D__ASSEMBLER__ $(PARANOID) $(REENTRANT) -c $< + +.s.o: + $(CC) -c $< + +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 \ + poly_div.o poly_mul64.o polynomial.o \ + reg_add_sub.o reg_compare.o reg_constant.o reg_ld_str.o \ + reg_div.o reg_mul.o reg_norm.o \ + reg_u_add.o reg_u_div.o reg_u_mul.o reg_u_sub.o \ + reg_round.o \ + wm_shrx.o wm_sqrt.o + +math.a: $(OBJS) + rm -f math.a + $(AR) rcs math.a $(OBJS) + sync + +dep: + $(CPP) -M *.c > .depend + $(CPP) -D__ASSEMBLER__ -M *.S >> .depend + +proto: + cproto -e -DMAKING_PROTO *.c >fpu_proto.h + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/README b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/README new file mode 100644 index 000000000..849355887 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/README @@ -0,0 +1,312 @@ + +---------------------------------------------------------------------------+ + | wm-FPU-emu an FPU emulator for 80386 and 80486SX microprocessors. | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | This program is free software; you can redistribute it and/or modify | + | it under the terms of the GNU General Public License version 2 as | + | published by the Free Software Foundation. | + | | + | 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. | + | | + +---------------------------------------------------------------------------+ + + + +wm-FPU-emu is an FPU emulator for Linux. It is derived from wm-emu387 +which is my 80387 emulator for djgpp (gcc under msdos); wm-emu387 was +in turn based upon emu387 which was written by DJ Delorie for djgpp. +The interface to the Linux kernel is based upon the original Linux +math emulator by Linus Torvalds. + +My target FPU for wm-FPU-emu is that described in the Intel486 +Programmer's Reference Manual (1992 edition). Unfortunately, numerous +facets of the functioning of the FPU are not well covered in the +Reference Manual. The information in the manual has been supplemented +with measurements on real 80486's. Unfortunately, it is simply not +possible to be sure that all of the peculiarities of the 80486 have +been discovered, so there is always likely to be obscure differences +in the detailed behaviour of the emulator and a real 80486. + +wm-FPU-emu does not implement all of the behaviour of the 80486 FPU. +See "Limitations" later in this file for a list of some differences. + +Please report bugs, etc to me at: + billm@vaxc.cc.monash.edu.au + or at: + billm@jacobi.maths.monash.edu.au + + +--Bill Metzenthen + Jan 1994 + + +----------------------- Internals of wm-FPU-emu ----------------------- + +Numeric algorithms: +(1) Add, subtract, and multiply. Nothing remarkable in these. +(2) Divide has been tuned to get reasonable performance. The algorithm + is not the obvious one which most people seem to use, but is designed + to take advantage of the characteristics of the 80386. I expect that + it has been invented many times before I discovered it, but I have not + seen it. It is based upon one of those ideas which one carries around + for years without ever bothering to check it out. +(3) The sqrt function has been tuned to get good performance. It is based + upon Newton's classic method. Performance was improved by capitalizing + upon the properties of Newton's method, and the code is once again + structured taking account of the 80386 characteristics. +(4) The trig, log, and exp functions are based in each case upon quasi- + "optimal" polynomial approximations. My definition of "optimal" was + based upon getting good accuracy with reasonable speed. +(5) The argument reducing code for the trig function effectively uses + a value of pi which is accurate to more than 128 bits. As a consequence, + the reduced argument is accurate to more than 64 bits for arguments up + to a few pi, and accurate to more than 64 bits for most arguments, + even for arguments approaching 2^63. This is far superior to an + 80486, which uses a value of pi which is accurate to 66 bits. + +The code of the emulator is complicated slightly by the need to +account for a limited form of re-entrancy. Normally, the emulator will +emulate each FPU instruction to completion without interruption. +However, it may happen that when the emulator is accessing the user +memory space, swapping may be needed. In this case the emulator may be +temporarily suspended while disk i/o takes place. During this time +another process may use the emulator, thereby changing some static +variables (eg FPU_st0_ptr, etc). The code which accesses user memory +is confined to five files: + fpu_entry.c + reg_ld_str.c + load_store.c + get_address.c + errors.c + +----------------------- Limitations of wm-FPU-emu ----------------------- + +There are a number of differences between the current wm-FPU-emu +(version beta 1.5) and the 80486 FPU (apart from bugs). Some of the +more important differences are listed below: + +Segment overrides don't do anything yet. + +All internal computations are performed at 64 bit or higher precision +and the results rounded etc as required by the PC bits of the FPU +control word. Under the crt0 version for Linux current at June 1993, +the FPU PC bits specify 64 bits precision. + +The precision flag (PE of the FPU status word) and the Roundup flag +(C1 of the status word) are now implemented. Does anyone write code +which uses these features? The Roundup flag does not have much meaning +for the transcendental functions and its 80486 value with these +functions is likely to differ from its emulator value. + +In a few rare cases the Underflow flag obtained with the emulator will +be different from that obtained with an 80486. This occurs when the +following conditions apply simultaneously: +(a) the operands have a higher precision than the current setting of the + precision control (PC) flags. +(b) the underflow exception is masked. +(c) the magnitude of the exact result (before rounding) is less than 2^-16382. +(d) the magnitude of the final result (after rounding) is exactly 2^-16382. +(e) the magnitude of the exact result would be exactly 2^-16382 if the + operands were rounded to the current precision before the arithmetic + operation was performed. +If all of these apply, the emulator will set the Underflow flag but a real +80486 will not. + +NOTE: Certain formats of Extended Real are UNSUPPORTED. They are +unsupported by the 80486. They are the Pseudo-NaNs, Pseudoinfinities, +and Unnormals. None of these will be generated by an 80486 or by the +emulator. Do not use them. The emulator treats them differently in +detail from the way an 80486 does. + +The emulator treats PseudoDenormals differently from an 80486. These +numbers are in fact properly normalised numbers with the exponent +offset by 1, and the emulator treats them as such. Unlike the 80486, +the emulator does not generate a Denormal Operand exception for these +numbers. The arithmetical results produced when using such a number as +an operand are the same for the emulator and a real 80486 (apart from +any slight precision difference for the transcendental functions). +Neither the emulator nor an 80486 produces one of these numbers as the +result of any arithmetic operation. An 80486 can keep one of these +numbers in an FPU register with its identity as a PseudoDenormal, but +the emulator will not; they are always converted to a valid number. + +----------------------- Performance of wm-FPU-emu ----------------------- + +Speed. +----- + +The speed of floating point computation with the emulator will depend +upon instruction mix. Relative performance is best for the instructions +which require most computation. The simple instructions are adversely +affected by the fpu instruction trap overhead. + + +Timing: Some simple timing tests have been made on the emulator functions. +The times include load/store instructions. All times are in microseconds +measured on a 33MHz 386 with 64k cache. The Turbo C tests were under +ms-dos, the next two columns are for emulators running with the djgpp +ms-dos extender. The final column is for wm-FPU-emu in Linux 0.97, +using libm4.0 (hard). + +function Turbo C djgpp 1.06 WM-emu387 wm-FPU-emu + + + 60.5 154.8 76.5 139.4 + - 61.1-65.5 157.3-160.8 76.2-79.5 142.9-144.7 + * 71.0 190.8 79.6 146.6 + / 61.2-75.0 261.4-266.9 75.3-91.6 142.2-158.1 + + sin() 310.8 4692.0 319.0 398.5 + cos() 284.4 4855.2 308.0 388.7 + tan() 495.0 8807.1 394.9 504.7 + atan() 328.9 4866.4 601.1 419.5-491.9 + + sqrt() 128.7 crashed 145.2 227.0 + log() 413.1-419.1 5103.4-5354.21 254.7-282.2 409.4-437.1 + exp() 479.1 6619.2 469.1 850.8 + + +The performance under Linux is improved by the use of look-ahead code. +The following results show the improvement which is obtained under +Linux due to the look-ahead code. Also given are the times for the +original Linux emulator with the 4.1 'soft' lib. + + [ Linus' note: I changed look-ahead to be the default under linux, as + there was no reason not to use it after I had edited it to be + disabled during tracing ] + + wm-FPU-emu w original w + look-ahead 'soft' lib + + 106.4 190.2 + - 108.6-111.6 192.4-216.2 + * 113.4 193.1 + / 108.8-124.4 700.1-706.2 + + sin() 390.5 2642.0 + cos() 381.5 2767.4 + tan() 496.5 3153.3 + atan() 367.2-435.5 2439.4-3396.8 + + sqrt() 195.1 4732.5 + log() 358.0-387.5 3359.2-3390.3 + exp() 619.3 4046.4 + + +These figures are now somewhat out-of-date. The emulator has become +progressively slower for most functions as more of the 80486 features +have been implemented. + + +----------------------- Accuracy of wm-FPU-emu ----------------------- + + +Accuracy: The following table gives the accuracy of the sqrt(), trig +and log functions. Each function was tested at about 400 points. Ideal +results would be 64 bits. The reduced accuracy of cos() and tan() for +arguments greater than pi/4 can be thought of as being due to the +precision of the argument x; e.g. an argument of pi/2-(1e-10) which is +accurate to 64 bits can result in a relative accuracy in cos() of about +64 + log2(cos(x)) = 31 bits. Results for the Turbo C emulator are given +in the last column. + + +Function Tested x range Worst result Turbo C + (relative bits) + +sqrt(x) 1 .. 2 64.1 63.2 +atan(x) 1e-10 .. 200 62.6 62.8 +cos(x) 0 .. pi/2-(1e-10) 63.2 (x <= pi/4) 62.4 + 35.2 (x = pi/2-(1e-10)) 31.9 +sin(x) 1e-10 .. pi/2 63.0 62.8 +tan(x) 1e-10 .. pi/2-(1e-10) 62.4 (x <= pi/4) 62.1 + 35.2 (x = pi/2-(1e-10)) 31.9 +exp(x) 0 .. 1 63.1 62.9 +log(x) 1+1e-6 .. 2 62.4 62.1 + + +As of version 1.3 of the emulator, the accuracy of the basic +arithmetic has been improved (by a small fraction of a bit). Care has +been taken to ensure full accuracy of the rounding of the basic +arithmetic functions (+,-,*,/,and fsqrt), and they all now produce +results which are exact to the 64th bit (unless there are any bugs +left). To ensure this, it was necessary to effectively get information +of up to about 128 bits precision. The emulator now passes the +"paranoia" tests (compiled with gcc 2.3.3) for 'float' variables (24 +bit precision numbers) when precision control is set to 24, 53 or 64 +bits, and for 'double' variables (53 bit precision numbers) when +precision control is set to 53 bits (a properly performing FPU cannot +pass the 'paranoia' tests for 'double' variables when precision +control is set to 64 bits). + +For version 1.5, the accuracy of fprem and fprem1 has been improved. +These functions now produce exact results. The code for reducing the +argument for the trig functions (fsin, fcos, fptan and fsincos) has +been improved and now effectively uses a value for pi which is +accurate to more than 128 bits precision. As a consquence, the +accuracy of these functions for large arguments has been dramatically +improved (and is now very much better than an 80486 FPU). There is +also now no degradation of accuracy for fcos and ftan for operands +close to pi/2. Measured results are (note that the definition of +accuracy has changed slightly from that used for the above table): + +Function Tested x range Worst result + (absolute bits) + +cos(x) 0 .. 9.22e+18 62.0 +sin(x) 1e-16 .. 9.22e+18 62.1 +tan(x) 1e-16 .. 9.22e+18 61.8 + +It is possible with some effort to find very large arguments which +give much degraded precision. For example, the integer number + 8227740058411162616.0 +is within about 10e-7 of a multiple of pi. To find the tan (for +example) of this number to 64 bits precision it would be necessary to +have a value of pi which had about 150 bits precision. The FPU +emulator computes the result to about 42.6 bits precision (the correct +result is about -9.739715e-8). On the other hand, an 80486 FPU returns +0.01059, which in relative terms is hopelessly inaccurate. + +For arguments close to critical angles (which occur at multiples of +pi/2) the emulator is more accurate than an 80486 FPU. For very large +arguments, the emulator is far more accurate. + +------------------------- Contributors ------------------------------- + +A number of people have contributed to the development of the +emulator, often by just reporting bugs, sometimes with suggested +fixes, and a few kind people have provided me with access in one way +or another to an 80486 machine. Contributors include (to those people +who I may have forgotten, please forgive me): + +Linus Torvalds +Tommy.Thorn@daimi.aau.dk +Andrew.Tridgell@anu.edu.au +Nick Holloway, alfie@dcs.warwick.ac.uk +Hermano Moura, moura@dcs.gla.ac.uk +Jon Jagger, J.Jagger@scp.ac.uk +Lennart Benschop +Brian Gallew, geek+@CMU.EDU +Thomas Staniszewski, ts3v+@andrew.cmu.edu +Martin Howell, mph@plasma.apana.org.au +M Saggaf, alsaggaf@athena.mit.edu +Peter Barker, PETER@socpsy.sci.fau.edu +tom@vlsivie.tuwien.ac.at +Dan Russel, russed@rpi.edu +Daniel Carosone, danielce@ee.mu.oz.au +cae@jpmorgan.com +Hamish Coleman, t933093@minyos.xx.rmit.oz.au +Bruce Evans, bde@kralizec.zeta.org.au +Timo Korvola, Timo.Korvola@hut.fi + +...and numerous others who responded to my request for help with +a real 80486. + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/control_w.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/control_w.h new file mode 100644 index 000000000..683032125 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/control_w.h @@ -0,0 +1,44 @@ +/*---------------------------------------------------------------------------+ + | control_w.h | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + +#ifndef _CONTROLW_H_ +#define _CONTROLW_H_ + +#ifdef __ASSEMBLER__ +#define _Const_(x) $##x +#else +#define _Const_(x) x +#endif + +#define CW_RC _Const_(0x0C00) /* rounding control */ +#define CW_PC _Const_(0x0300) /* precision control */ + +#define CW_Precision Const_(0x0020) /* loss of precision mask */ +#define CW_Underflow Const_(0x0010) /* underflow mask */ +#define CW_Overflow Const_(0x0008) /* overflow mask */ +#define CW_ZeroDiv Const_(0x0004) /* divide by zero mask */ +#define CW_Denormal Const_(0x0002) /* denormalized operand mask */ +#define CW_Invalid Const_(0x0001) /* invalid operation mask */ + +#define CW_Exceptions _Const_(0x003f) /* all masks */ + +#define RC_RND _Const_(0x0000) +#define RC_DOWN _Const_(0x0400) +#define RC_UP _Const_(0x0800) +#define RC_CHOP _Const_(0x0C00) + +/* p 15-5: Precision control bits affect only the following: + ADD, SUB(R), MUL, DIV(R), and SQRT */ +#define PR_24_BITS _Const_(0x000) +#define PR_53_BITS _Const_(0x200) +#define PR_64_BITS _Const_(0x300) +/* FULL_PRECISION simulates all exceptions masked */ +#define FULL_PRECISION (PR_64_BITS | RC_RND | 0x3f) + +#endif _CONTROLW_H_ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/div_small.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/div_small.S new file mode 100644 index 000000000..0225a96d4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/div_small.S @@ -0,0 +1,50 @@ + .file "div_small.S" +/*---------------------------------------------------------------------------+ + | div_small.S | + | | + | Divide a 64 bit integer by a 32 bit integer & return remainder. | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | unsigned long div_small(unsigned long long *x, unsigned long y) | + +---------------------------------------------------------------------------*/ + +#include "fpu_asm.h" + +.text + .align 2,144 + +.globl _div_small + +_div_small: + pushl %ebp + movl %esp,%ebp + + pushl %esi + + movl PARAM1,%esi /* pointer to num */ + movl PARAM2,%ecx /* The denominator */ + + movl 4(%esi),%eax /* Get the current num msw */ + xorl %edx,%edx + divl %ecx + + movl %eax,4(%esi) + + movl (%esi),%eax /* Get the num lsw */ + divl %ecx + + movl %eax,(%esi) + + movl %edx,%eax /* Return the remainder in eax */ + + popl %esi + + leave + ret + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/errors.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/errors.c new file mode 100644 index 000000000..d34e5e9e4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/errors.c @@ -0,0 +1,628 @@ +/*---------------------------------------------------------------------------+ + | errors.c | + | | + | The error handling functions for wm-FPU-emu | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Note: | + | The file contains code which accesses user memory. | + | Emulator static data may change when user memory is accessed, due to | + | other processes using the emulator while swapping is in progress. | + +---------------------------------------------------------------------------*/ + +#include + +#include + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" +#include "status_w.h" +#include "control_w.h" +#include "reg_constant.h" +#include "version.h" + +/* */ +#undef PRINT_MESSAGES +/* */ + + +void Un_impl(void) +{ + unsigned char byte1, FPU_modrm; + unsigned long address = FPU_ORIG_EIP; + + RE_ENTRANT_CHECK_OFF; + /* No need to verify_area(), we have previously fetched these bytes. */ + printk("Unimplemented FPU Opcode at eip=%p : ", (void *) address); + while ( 1 ) + { + byte1 = get_fs_byte((unsigned char *) address); + if ( (byte1 & 0xf8) == 0xd8 ) break; + printk("[%02x]", byte1); + address++; + } + printk("%02x ", byte1); + FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + + if (FPU_modrm >= 0300) + printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); + else + printk("/%d\n", (FPU_modrm >> 3) & 7); + RE_ENTRANT_CHECK_ON; + + EXCEPTION(EX_Invalid); + +} + + +/* + Called for opcodes which are illegal and which are known to result in a + SIGILL with a real 80486. + */ +void FPU_illegal(void) +{ + math_abort(FPU_info,SIGILL); +} + + + +void emu_printall() +{ + int i; + static char *tag_desc[] = { "Valid", "Zero", "ERROR", "ERROR", + "DeNorm", "Inf", "NaN", "Empty" }; + unsigned char byte1, FPU_modrm; + unsigned long address = FPU_ORIG_EIP; + + RE_ENTRANT_CHECK_OFF; + /* No need to verify_area(), we have previously fetched these bytes. */ + printk("At %p: ", (void *) address); + while ( 1 ) + { + byte1 = get_fs_byte((unsigned char *) address); + if ( (byte1 & 0xf8) == 0xd8 ) break; + printk("[%02x]", byte1); + address++; + } + printk("%02x ", byte1); + FPU_modrm = get_fs_byte(1 + (unsigned char *) address); + partial_status = status_word(); + +#ifdef DEBUGGING +if ( partial_status & SW_Backward ) printk("SW: backward compatibility\n"); +if ( partial_status & SW_C3 ) printk("SW: condition bit 3\n"); +if ( partial_status & SW_C2 ) printk("SW: condition bit 2\n"); +if ( partial_status & SW_C1 ) printk("SW: condition bit 1\n"); +if ( partial_status & SW_C0 ) printk("SW: condition bit 0\n"); +if ( partial_status & SW_Summary ) printk("SW: exception summary\n"); +if ( partial_status & SW_Stack_Fault ) printk("SW: stack fault\n"); +if ( partial_status & SW_Precision ) printk("SW: loss of precision\n"); +if ( partial_status & SW_Underflow ) printk("SW: underflow\n"); +if ( partial_status & SW_Overflow ) printk("SW: overflow\n"); +if ( partial_status & SW_Zero_Div ) printk("SW: divide by zero\n"); +if ( partial_status & SW_Denorm_Op ) printk("SW: denormalized operand\n"); +if ( partial_status & SW_Invalid ) printk("SW: invalid operation\n"); +#endif DEBUGGING + + if (FPU_modrm >= 0300) + printk("%02x (%02x+%d)\n", FPU_modrm, FPU_modrm & 0xf8, FPU_modrm & 7); + else + printk("/%d, mod=%d rm=%d\n", + (FPU_modrm >> 3) & 7, (FPU_modrm >> 6) & 3, FPU_modrm & 7); + + printk(" SW: b=%d st=%ld es=%d sf=%d cc=%d%d%d%d ef=%d%d%d%d%d%d\n", + partial_status & 0x8000 ? 1 : 0, /* busy */ + (partial_status & 0x3800) >> 11, /* stack top pointer */ + partial_status & 0x80 ? 1 : 0, /* Error summary status */ + partial_status & 0x40 ? 1 : 0, /* Stack flag */ + partial_status & SW_C3?1:0, partial_status & SW_C2?1:0, /* cc */ + partial_status & SW_C1?1:0, partial_status & SW_C0?1:0, /* cc */ + partial_status & SW_Precision?1:0, partial_status & SW_Underflow?1:0, + partial_status & SW_Overflow?1:0, partial_status & SW_Zero_Div?1:0, + partial_status & SW_Denorm_Op?1:0, partial_status & SW_Invalid?1:0); + +printk(" CW: ic=%d rc=%ld%ld pc=%ld%ld iem=%d ef=%d%d%d%d%d%d\n", + control_word & 0x1000 ? 1 : 0, + (control_word & 0x800) >> 11, (control_word & 0x400) >> 10, + (control_word & 0x200) >> 9, (control_word & 0x100) >> 8, + control_word & 0x80 ? 1 : 0, + control_word & SW_Precision?1:0, control_word & SW_Underflow?1:0, + control_word & SW_Overflow?1:0, control_word & SW_Zero_Div?1:0, + control_word & SW_Denorm_Op?1:0, control_word & SW_Invalid?1:0); + + for ( i = 0; i < 8; i++ ) + { + FPU_REG *r = &st(i); + switch (r->tag) + { + case TW_Empty: + continue; + break; + case TW_Zero: +#if 0 + printk("st(%d) %c .0000 0000 0000 0000 ", + i, r->sign ? '-' : '+'); + break; +#endif + case TW_Valid: + case TW_NaN: +/* case TW_Denormal: */ + case TW_Infinity: + printk("st(%d) %c .%04lx %04lx %04lx %04lx e%+-6ld ", i, + r->sign ? '-' : '+', + (long)(r->sigh >> 16), + (long)(r->sigh & 0xFFFF), + (long)(r->sigl >> 16), + (long)(r->sigl & 0xFFFF), + r->exp - EXP_BIAS + 1); + break; + default: + printk("Whoops! Error in errors.c "); + break; + } + printk("%s\n", tag_desc[(int) (unsigned) r->tag]); + } + + printk("[data] %c .%04lx %04lx %04lx %04lx e%+-6ld ", + FPU_loaded_data.sign ? '-' : '+', + (long)(FPU_loaded_data.sigh >> 16), + (long)(FPU_loaded_data.sigh & 0xFFFF), + (long)(FPU_loaded_data.sigl >> 16), + (long)(FPU_loaded_data.sigl & 0xFFFF), + FPU_loaded_data.exp - EXP_BIAS + 1); + printk("%s\n", tag_desc[(int) (unsigned) FPU_loaded_data.tag]); + RE_ENTRANT_CHECK_ON; + +} + +static struct { + int type; + char *name; +} exception_names[] = { + { EX_StackOver, "stack overflow" }, + { EX_StackUnder, "stack underflow" }, + { EX_Precision, "loss of precision" }, + { EX_Underflow, "underflow" }, + { EX_Overflow, "overflow" }, + { EX_ZeroDiv, "divide by zero" }, + { EX_Denormal, "denormalized operand" }, + { EX_Invalid, "invalid operation" }, + { EX_INTERNAL, "INTERNAL BUG in "FPU_VERSION }, + { 0, NULL } +}; + +/* + EX_INTERNAL is always given with a code which indicates where the + error was detected. + + Internal error types: + 0 in load_store.c + 0x14 in fpu_etc.c + 0x1nn in a *.c file: + 0x101 in reg_add_sub.c + 0x102 in reg_mul.c + 0x103 in poly_sin.c + 0x104 in poly_atan.c + 0x105 in reg_mul.c + 0x106 in reg_ld_str.c + 0x107 in fpu_trig.c + 0x108 in reg_compare.c + 0x109 in reg_compare.c + 0x110 in reg_add_sub.c + 0x111 in fpe_entry.c + 0x112 in fpu_trig.c + 0x113 in errors.c + 0x114 in reg_ld_str.c + 0x115 in fpu_trig.c + 0x116 in fpu_trig.c + 0x117 in fpu_trig.c + 0x118 in fpu_trig.c + 0x119 in fpu_trig.c + 0x120 in poly_atan.c + 0x121 in reg_compare.c + 0x122 in reg_compare.c + 0x123 in reg_compare.c + 0x125 in fpu_trig.c + 0x126 in fpu_entry.c + 0x127 in poly_2xm1.c + 0x128 in fpu_entry.c + 0x2nn in an *.S file: + 0x201 in reg_u_add.S, reg_round.S + 0x202 in reg_u_div.S + 0x203 in reg_u_div.S + 0x204 in reg_u_div.S + 0x205 in reg_u_mul.S + 0x206 in reg_u_sub.S + 0x207 in wm_sqrt.S + 0x208 in reg_div.S + 0x209 in reg_u_sub.S + 0x210 in reg_u_sub.S + 0x211 in reg_u_sub.S + 0x212 in reg_u_sub.S + 0x213 in wm_sqrt.S + 0x214 in wm_sqrt.S + 0x215 in wm_sqrt.S + 0x216 in reg_round.S + 0x217 in reg_round.S + 0x218 in reg_round.S + 0x220 in reg_norm.S + 0x221 in reg_norm.S + */ + +void exception(int n) +{ + int i, int_type; + + int_type = 0; /* Needed only to stop compiler warnings */ + if ( n & EX_INTERNAL ) + { + int_type = n - EX_INTERNAL; + n = EX_INTERNAL; + /* Set lots of exception bits! */ + partial_status |= (SW_Exc_Mask | SW_Summary | SW_Backward); + } + else + { + /* Extract only the bits which we use to set the status word */ + n &= (SW_Exc_Mask); + /* Set the corresponding exception bit */ + partial_status |= n; + /* Set summary bits iff exception isn't masked */ + if ( partial_status & ~control_word & CW_Exceptions ) + partial_status |= (SW_Summary | SW_Backward); + if ( n & (SW_Stack_Fault | EX_Precision) ) + { + if ( !(n & SW_C1) ) + /* This bit distinguishes over- from underflow for a stack fault, + and roundup from round-down for precision loss. */ + partial_status &= ~SW_C1; + } + } + + RE_ENTRANT_CHECK_OFF; + if ( (~control_word & n & CW_Exceptions) || (n == EX_INTERNAL) ) + { +#ifdef PRINT_MESSAGES + /* My message from the sponsor */ + printk(FPU_VERSION" "__DATE__" (C) W. Metzenthen.\n"); +#endif PRINT_MESSAGES + + /* Get a name string for error reporting */ + for (i=0; exception_names[i].type; i++) + if ( (exception_names[i].type & n) == exception_names[i].type ) + break; + + if (exception_names[i].type) + { +#ifdef PRINT_MESSAGES + printk("FP Exception: %s!\n", exception_names[i].name); +#endif PRINT_MESSAGES + } + else + printk("FP emulator: Unknown Exception: 0x%04x!\n", n); + + if ( n == EX_INTERNAL ) + { + printk("FP emulator: Internal error type 0x%04x\n", int_type); + emu_printall(); + } +#ifdef PRINT_MESSAGES + else + emu_printall(); +#endif PRINT_MESSAGES + + /* + * The 80486 generates an interrupt on the next non-control FPU + * instruction. So we need some means of flagging it. + * We use the ES (Error Summary) bit for this, assuming that + * this is the way a real FPU does it (until I can check it out), + * if not, then some method such as the following kludge might + * be needed. + */ +/* regs[0].tag |= TW_FPU_Interrupt; */ + } + RE_ENTRANT_CHECK_ON; + +#ifdef __DEBUG__ + math_abort(FPU_info,SIGFPE); +#endif __DEBUG__ + +} + + +/* Real operation attempted on two operands, one a NaN. */ +/* Returns nz if the exception is unmasked */ +asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest) +{ + FPU_REG const *x; + int signalling; + + /* The default result for the case of two "equal" NaNs (signs may + differ) is chosen to reproduce 80486 behaviour */ + x = a; + if (a->tag == TW_NaN) + { + if (b->tag == TW_NaN) + { + signalling = !(a->sigh & b->sigh & 0x40000000); + /* find the "larger" */ + if ( significand(a) < significand(b) ) + x = b; + } + else + { + /* return the quiet version of the NaN in a */ + signalling = !(a->sigh & 0x40000000); + } + } + else +#ifdef PARANOID + if (b->tag == TW_NaN) +#endif PARANOID + { + signalling = !(b->sigh & 0x40000000); + x = b; + } +#ifdef PARANOID + else + { + signalling = 0; + EXCEPTION(EX_INTERNAL|0x113); + x = &CONST_QNaN; + } +#endif PARANOID + + if ( !signalling ) + { + if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */ + x = &CONST_QNaN; + reg_move(x, dest); + return 0; + } + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + if ( !(x->sigh & 0x80000000) ) /* pseudo-NaN ? */ + x = &CONST_QNaN; + reg_move(x, dest); + /* ensure a Quiet NaN */ + dest->sigh |= 0x40000000; + } + + EXCEPTION(EX_Invalid); + + return !(control_word & CW_Invalid); +} + + +/* Invalid arith operation on Valid registers */ +/* Returns nz if the exception is unmasked */ +asmlinkage int arith_invalid(FPU_REG *dest) +{ + + EXCEPTION(EX_Invalid); + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + reg_move(&CONST_QNaN, dest); + } + + return !(control_word & CW_Invalid); + +} + + +/* Divide a finite number by zero */ +asmlinkage int divide_by_zero(int sign, FPU_REG *dest) +{ + + if ( control_word & CW_ZeroDiv ) + { + /* The masked response */ + reg_move(&CONST_INF, dest); + dest->sign = (unsigned char)sign; + } + + EXCEPTION(EX_ZeroDiv); + + return !(control_word & CW_ZeroDiv); + +} + + +/* This may be called often, so keep it lean */ +int set_precision_flag(int flags) +{ + if ( control_word & CW_Precision ) + { + partial_status &= ~(SW_C1 & flags); + partial_status |= flags; /* The masked response */ + return 0; + } + else + { + exception(flags); + return 1; + } +} + + +/* This may be called often, so keep it lean */ +asmlinkage void set_precision_flag_up(void) +{ + if ( control_word & CW_Precision ) + partial_status |= (SW_Precision | SW_C1); /* The masked response */ + else + exception(EX_Precision | SW_C1); + +} + + +/* This may be called often, so keep it lean */ +asmlinkage void set_precision_flag_down(void) +{ + if ( control_word & CW_Precision ) + { /* The masked response */ + partial_status &= ~SW_C1; + partial_status |= SW_Precision; + } + else + exception(EX_Precision); +} + + +asmlinkage int denormal_operand(void) +{ + if ( control_word & CW_Denormal ) + { /* The masked response */ + partial_status |= SW_Denorm_Op; + return 0; + } + else + { + exception(EX_Denormal); + return 1; + } +} + + +asmlinkage int arith_overflow(FPU_REG *dest) +{ + + if ( control_word & CW_Overflow ) + { + char sign; + /* The masked response */ +/* ###### The response here depends upon the rounding mode */ + sign = dest->sign; + reg_move(&CONST_INF, dest); + dest->sign = sign; + } + else + { + /* Subtract the magic number from the exponent */ + dest->exp -= (3 * (1 << 13)); + } + + EXCEPTION(EX_Overflow); + if ( control_word & CW_Overflow ) + { + /* The overflow exception is masked. */ + /* By definition, precision is lost. + The roundup bit (C1) is also set because we have + "rounded" upwards to Infinity. */ + EXCEPTION(EX_Precision | SW_C1); + return !(control_word & CW_Precision); + } + + return !(control_word & CW_Overflow); + +} + + +asmlinkage int arith_underflow(FPU_REG *dest) +{ + + if ( control_word & CW_Underflow ) + { + /* The masked response */ + if ( dest->exp <= EXP_UNDER - 63 ) + { + reg_move(&CONST_Z, dest); + partial_status &= ~SW_C1; /* Round down. */ + } + } + else + { + /* Add the magic number to the exponent. */ + dest->exp += (3 * (1 << 13)); + } + + EXCEPTION(EX_Underflow); + if ( control_word & CW_Underflow ) + { + /* The underflow exception is masked. */ + EXCEPTION(EX_Precision); + return !(control_word & CW_Precision); + } + + return !(control_word & CW_Underflow); + +} + + +void stack_overflow(void) +{ + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + top--; + reg_move(&CONST_QNaN, FPU_st0_ptr = &st(0)); + } + + EXCEPTION(EX_StackOver); + + return; + +} + + +void stack_underflow(void) +{ + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + reg_move(&CONST_QNaN, FPU_st0_ptr); + } + + EXCEPTION(EX_StackUnder); + + return; + +} + + +void stack_underflow_i(int i) +{ + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + reg_move(&CONST_QNaN, &(st(i))); + } + + EXCEPTION(EX_StackUnder); + + return; + +} + + +void stack_underflow_pop(int i) +{ + + if ( control_word & CW_Invalid ) + { + /* The masked response */ + reg_move(&CONST_QNaN, &(st(i))); + pop(); + } + + EXCEPTION(EX_StackUnder); + + return; + +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/exception.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/exception.h new file mode 100644 index 000000000..2e629a30c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/exception.h @@ -0,0 +1,53 @@ +/*---------------------------------------------------------------------------+ + | exception.h | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + +#ifndef _EXCEPTION_H_ +#define _EXCEPTION_H_ + + +#ifdef __ASSEMBLER__ +#define Const_(x) $##x +#else +#define Const_(x) x +#endif + +#ifndef SW_C1 +#include "fpu_emu.h" +#endif SW_C1 + +#define FPU_BUSY Const_(0x8000) /* FPU busy bit (8087 compatibility) */ +#define EX_ErrorSummary Const_(0x0080) /* Error summary status */ +/* Special exceptions: */ +#define EX_INTERNAL Const_(0x8000) /* Internal error in wm-FPU-emu */ +#define EX_StackOver Const_(0x0041|SW_C1) /* stack overflow */ +#define EX_StackUnder Const_(0x0041) /* stack underflow */ +/* Exception flags: */ +#define EX_Precision Const_(0x0020) /* loss of precision */ +#define EX_Underflow Const_(0x0010) /* underflow */ +#define EX_Overflow Const_(0x0008) /* overflow */ +#define EX_ZeroDiv Const_(0x0004) /* divide by zero */ +#define EX_Denormal Const_(0x0002) /* denormalized operand */ +#define EX_Invalid Const_(0x0001) /* invalid operation */ + + +#define PRECISION_LOST_UP Const_((EX_Precision | SW_C1)) +#define PRECISION_LOST_DOWN Const_(EX_Precision) + + +#ifndef __ASSEMBLER__ + +#ifdef DEBUG +#define EXCEPTION(x) { printk("exception in %s at line %d\n", \ + __FILE__, __LINE__); exception(x); } +#else +#define EXCEPTION(x) exception(x) +#endif + +#endif __ASSEMBLER__ + +#endif _EXCEPTION_H_ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_arith.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_arith.c new file mode 100644 index 000000000..3871a56a7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_arith.c @@ -0,0 +1,179 @@ +/*---------------------------------------------------------------------------+ + | fpu_arith.c | + | | + | Code to implement the FPU register/register arithmetic instructions | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_system.h" +#include "fpu_emu.h" +#include "control_w.h" +#include "status_w.h" + + +void fadd__() +{ + /* fadd st,st(i) */ + clear_C1(); + reg_add(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); +} + + +void fmul__() +{ + /* fmul st,st(i) */ + clear_C1(); + reg_mul(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); +} + + + +void fsub__() +{ + /* fsub st,st(i) */ + clear_C1(); + reg_sub(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); +} + + +void fsubr_() +{ + /* fsubr st,st(i) */ + clear_C1(); + reg_sub(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word); +} + + +void fdiv__() +{ + /* fdiv st,st(i) */ + clear_C1(); + reg_div(FPU_st0_ptr, &st(FPU_rm), FPU_st0_ptr, control_word); +} + + +void fdivr_() +{ + /* fdivr st,st(i) */ + clear_C1(); + reg_div(&st(FPU_rm), FPU_st0_ptr, FPU_st0_ptr, control_word); +} + + + +void fadd_i() +{ + /* fadd st(i),st */ + clear_C1(); + reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); +} + + +void fmul_i() +{ + /* fmul st(i),st */ + clear_C1(); + reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); +} + + +void fsubri() +{ + /* fsubr st(i),st */ + /* This is the sense of the 80486 manual + reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */ + clear_C1(); + reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); +} + + +void fsub_i() +{ + /* fsub st(i),st */ + /* This is the sense of the 80486 manual + reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */ + clear_C1(); + reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); +} + + +void fdivri() +{ + /* fdivr st(i),st */ + clear_C1(); + reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); +} + + +void fdiv_i() +{ + /* fdiv st(i),st */ + clear_C1(); + reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); +} + + + +void faddp_() +{ + /* faddp st(i),st */ + clear_C1(); + if ( !reg_add(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + pop(); +} + + +void fmulp_() +{ + /* fmulp st(i),st */ + clear_C1(); + if ( !reg_mul(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + pop(); +} + + + +void fsubrp() +{ + /* fsubrp st(i),st */ + /* This is the sense of the 80486 manual + reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word); */ + clear_C1(); + if ( !reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + pop(); +} + + +void fsubp_() +{ + /* fsubp st(i),st */ + /* This is the sense of the 80486 manual + reg_sub(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word); */ + clear_C1(); + if ( !reg_sub(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) ) + pop(); +} + + +void fdivrp() +{ + /* fdivrp st(i),st */ + clear_C1(); + if ( !reg_div(FPU_st0_ptr, &st(FPU_rm), &st(FPU_rm), control_word) ) + pop(); +} + + +void fdivp_() +{ + /* fdivp st(i),st */ + clear_C1(); + if ( !reg_div(&st(FPU_rm), FPU_st0_ptr, &st(FPU_rm), control_word) ) + pop(); +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_asm.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_asm.h new file mode 100644 index 000000000..8eb60148d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_asm.h @@ -0,0 +1,30 @@ +/*---------------------------------------------------------------------------+ + | fpu_asm.h | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + +#ifndef _FPU_ASM_H_ +#define _FPU_ASM_H_ + +#include "fpu_emu.h" + +#define EXCEPTION _exception + + +#define PARAM1 8(%ebp) +#define PARAM2 12(%ebp) +#define PARAM3 16(%ebp) +#define PARAM4 20(%ebp) + +#define SIGL_OFFSET 8 +#define SIGN(x) (x) +#define TAG(x) 1(x) +#define EXP(x) 4(x) +#define SIG(x) SIGL_OFFSET##(x) +#define SIGL(x) SIGL_OFFSET##(x) +#define SIGH(x) 12(x) + +#endif _FPU_ASM_H_ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_aux.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_aux.c new file mode 100644 index 000000000..c1835d4a8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_aux.c @@ -0,0 +1,180 @@ +/*---------------------------------------------------------------------------+ + | fpu_aux.c | + | | + | Code to implement some of the FPU auxiliary instructions. | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" +#include "status_w.h" +#include "control_w.h" + + + +void fclex(void) +{ + partial_status &= ~(SW_Backward|SW_Summary|SW_Stack_Fault|SW_Precision| + SW_Underflow|SW_Overflow|SW_Zero_Div|SW_Denorm_Op| + SW_Invalid); + NO_NET_DATA_EFFECT; + FPU_entry_eip = ip_offset; /* We want no net effect */ +} + +/* Needs to be externally visible */ +void finit() +{ + int r; + control_word = 0x037f; + partial_status = 0; + top = 0; /* We don't keep top in the status word internally. */ + for (r = 0; r < 8; r++) + { + regs[r].tag = TW_Empty; + } + /* The behaviour is different to that detailed in + Section 15.1.6 of the Intel manual */ + data_operand_offset = 0; + operand_selector = 0; + NO_NET_DATA_EFFECT; + FPU_entry_op_cs = 0; + FPU_entry_eip = ip_offset = 0; +} + +static FUNC const finit_table[] = { + Un_impl, Un_impl, fclex, finit, + Un_impl, FPU_illegal, FPU_illegal, FPU_illegal +}; + +void finit_() +{ + (finit_table[FPU_rm])(); +} + + +static void fstsw_ax(void) +{ + *(short *) &FPU_EAX = status_word(); + NO_NET_INSTR_EFFECT; +} + +static FUNC const fstsw_table[] = { + fstsw_ax, FPU_illegal, FPU_illegal, FPU_illegal, + FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal +}; + +void fstsw_() +{ + (fstsw_table[FPU_rm])(); +} + + + +static void fnop(void) +{ +} + +static FUNC const fp_nop_table[] = { + fnop, FPU_illegal, FPU_illegal, FPU_illegal, + FPU_illegal, FPU_illegal, FPU_illegal, FPU_illegal +}; + +void fp_nop() +{ + (fp_nop_table[FPU_rm])(); +} + + +void fld_i_() +{ + FPU_REG *st_new_ptr; + + if ( STACK_OVERFLOW ) + { stack_overflow(); return; } + + /* fld st(i) */ + if ( NOT_EMPTY(FPU_rm) ) + { reg_move(&st(FPU_rm), st_new_ptr); push(); } + else + { + if ( control_word & EX_Invalid ) + { + /* The masked response */ + push(); + stack_underflow(); + } + else + EXCEPTION(EX_StackUnder); + } + +} + + +void fxch_i() +{ + /* fxch st(i) */ + FPU_REG t; + register FPU_REG *sti_ptr = &st(FPU_rm); + + if ( FPU_st0_tag == TW_Empty ) + { + if ( sti_ptr->tag == TW_Empty ) + { + stack_underflow(); + stack_underflow_i(FPU_rm); + return; + } + if ( control_word & CW_Invalid ) + reg_move(sti_ptr, FPU_st0_ptr); /* Masked response */ + stack_underflow_i(FPU_rm); + return; + } + if ( sti_ptr->tag == TW_Empty ) + { + if ( control_word & CW_Invalid ) + reg_move(FPU_st0_ptr, sti_ptr); /* Masked response */ + stack_underflow(); + return; + } + clear_C1(); + reg_move(FPU_st0_ptr, &t); + reg_move(sti_ptr, FPU_st0_ptr); + reg_move(&t, sti_ptr); +} + + +void ffree_() +{ + /* ffree st(i) */ + st(FPU_rm).tag = TW_Empty; +} + + +void ffreep() +{ + /* ffree st(i) + pop - unofficial code */ + st(FPU_rm).tag = TW_Empty; + pop(); +} + + +void fst_i_() +{ + /* fst st(i) */ + reg_move(FPU_st0_ptr, &st(FPU_rm)); +} + + +void fstp_i() +{ + /* fstp st(i) */ + reg_move(FPU_st0_ptr, &st(FPU_rm)); + pop(); +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_emu.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_emu.h new file mode 100644 index 000000000..7b1a7e8ad --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_emu.h @@ -0,0 +1,166 @@ +/*---------------------------------------------------------------------------+ + | fpu_emu.h | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + + +#ifndef _FPU_EMU_H_ +#define _FPU_EMU_H_ + +/* + * Define DENORM_OPERAND to make the emulator detect denormals + * and use the denormal flag of the status word. Note: this only + * affects the flag and corresponding interrupt, the emulator + * will always generate denormals and operate upon them as required. + */ +#define DENORM_OPERAND + +/* + * Define PECULIAR_486 to get a closer approximation to 80486 behaviour, + * rather than behaviour which appears to be cleaner. + * This is a matter of opinion: for all I know, the 80486 may simply + * be complying with the IEEE spec. Maybe one day I'll get to see the + * spec... + */ +#define PECULIAR_486 + +#ifdef __ASSEMBLER__ +#include "fpu_asm.h" +#define Const(x) $##x +#else +#define Const(x) x +#endif + +#define EXP_BIAS Const(0) +#define EXP_OVER Const(0x4000) /* smallest invalid large exponent */ +#define EXP_UNDER Const(-0x3fff) /* largest invalid small exponent */ +#define EXP_Infinity EXP_OVER +#define EXP_NaN EXP_OVER + +#define SIGN_POS Const(0) +#define SIGN_NEG Const(1) + +/* Keep the order TW_Valid, TW_Zero, TW_Denormal */ +#define TW_Valid Const(0) /* valid */ +#define TW_Zero Const(1) /* zero */ +/* The following fold to 2 (Special) in the Tag Word */ +/* #define TW_Denormal Const(4) */ /* De-normal */ +#define TW_Infinity Const(5) /* + or - infinity */ +#define TW_NaN Const(6) /* Not a Number */ + +#define TW_Empty Const(7) /* empty */ + + +#ifndef __ASSEMBLER__ + +#include +#include + +#ifdef PARANOID +extern char emulating; +# define RE_ENTRANT_CHECK_OFF emulating = 0 +# define RE_ENTRANT_CHECK_ON emulating = 1 +#else +# define RE_ENTRANT_CHECK_OFF +# define RE_ENTRANT_CHECK_ON +#endif PARANOID + +#define FWAIT_OPCODE 0x9b +#define OP_SIZE_PREFIX 0x66 +#define ADDR_SIZE_PREFIX 0x67 +#define PREFIX_CS 0x2e +#define PREFIX_DS 0x3e +#define PREFIX_ES 0x26 +#define PREFIX_SS 0x36 +#define PREFIX_FS 0x64 +#define PREFIX_GS 0x65 +#define PREFIX_REPE 0xf3 +#define PREFIX_REPNE 0xf2 +#define PREFIX_LOCK 0xf0 + +/* These are to defeat the default action, giving the instruction + no net effect: */ +#define NO_NET_DATA_EFFECT \ + { FPU_data_address = (void *)data_operand_offset; \ + FPU_data_selector = operand_selector; } +#define NO_NET_INSTR_EFFECT \ + { FPU_entry_eip = ip_offset; \ + FPU_entry_op_cs = cs_selector; } + + +typedef void (*FUNC)(void); +typedef struct fpu_reg FPU_REG; +typedef struct { unsigned char address_size, segment; } overrides; + +#define st(x) ( regs[((top+x) &7 )] ) + +#define STACK_OVERFLOW (st_new_ptr = &st(-1), st_new_ptr->tag != TW_Empty) +#define NOT_EMPTY(i) (st(i).tag != TW_Empty) +#define NOT_EMPTY_0 (FPU_st0_tag ^ TW_Empty) + +extern unsigned char FPU_rm; + +extern char FPU_st0_tag; +extern FPU_REG *FPU_st0_ptr; + +/* ###### These need to be shifted to somewhere safe. */ +/* extern void *FPU_data_address; has been shifted */ +extern unsigned short FPU_data_selector; +extern unsigned long FPU_entry_op_cs; + +extern FPU_REG FPU_loaded_data; + +#define pop() { FPU_st0_ptr->tag = TW_Empty; top++; } + +/* push() does not affect the tags */ +#define push() { top--; FPU_st0_ptr = st_new_ptr; } + + +#define reg_move(x, y) { \ + *(short *)&((y)->sign) = *(short *)&((x)->sign); \ + *(long *)&((y)->exp) = *(long *)&((x)->exp); \ + *(long long *)&((y)->sigl) = *(long long *)&((x)->sigl); } + +#define significand(x) ( ((unsigned long long *)&((x)->sigl))[0] ) + + +/*----- Prototypes for functions written in assembler -----*/ +/* extern void reg_move(FPU_REG *a, FPU_REG *b); */ + +asmlinkage void mul64(unsigned long long const *a, unsigned long long const *b, + unsigned long long *result); +asmlinkage void poly_div2(unsigned long long *x); +asmlinkage void poly_div4(unsigned long long *x); +asmlinkage void poly_div16(unsigned long long *x); +asmlinkage void polynomial(unsigned accum[], unsigned const x[], + unsigned short const terms[][4], int const n); +asmlinkage void normalize(FPU_REG *x); +asmlinkage void normalize_nuo(FPU_REG *x); +asmlinkage int reg_div(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w); +asmlinkage int reg_u_sub(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w); +asmlinkage int reg_u_mul(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w); +asmlinkage int reg_u_div(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w); +asmlinkage int reg_u_add(FPU_REG const *arg1, FPU_REG const *arg2, + FPU_REG *answ, unsigned int control_w); +asmlinkage int wm_sqrt(FPU_REG *n, unsigned int control_w); +asmlinkage unsigned shrx(void *l, unsigned x); +asmlinkage unsigned shrxs(void *v, unsigned x); +asmlinkage unsigned long div_small(unsigned long long *x, unsigned long y); +asmlinkage void round_reg(FPU_REG *arg, unsigned int extent, + unsigned int control_w); + +#ifndef MAKING_PROTO +#include "fpu_proto.h" +#endif + +#endif __ASSEMBLER__ + +#endif _FPU_EMU_H_ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_entry.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_entry.c new file mode 100644 index 000000000..8b9a0860e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_entry.c @@ -0,0 +1,622 @@ +/*---------------------------------------------------------------------------+ + | fpu_entry.c | + | | + | The entry function for wm-FPU-emu | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | See the files "README" and "COPYING" for further copyright and warranty | + | information. | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Note: | + | The file contains code which accesses user memory. | + | Emulator static data may change when user memory is accessed, due to | + | other processes using the emulator while swapping is in progress. | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | math_emulate() is the sole entry point for wm-FPU-emu | + +---------------------------------------------------------------------------*/ + +#include +#include + +#include "fpu_system.h" +#include "fpu_emu.h" +#include "exception.h" +#include "control_w.h" +#include "status_w.h" + +#include + +#define __BAD__ FPU_illegal /* Illegal on an 80486, causes SIGILL */ + +#ifndef NO_UNDOC_CODE /* Un-documented FPU op-codes supported by default. */ + +/* WARNING: These codes are not documented by Intel in their 80486 manual + and may not work on FPU clones or later Intel FPUs. */ + +/* Changes to support the un-doc codes provided by Linus Torvalds. */ + +#define _d9_d8_ fstp_i /* unofficial code (19) */ +#define _dc_d0_ fcom_st /* unofficial code (14) */ +#define _dc_d8_ fcompst /* unofficial code (1c) */ +#define _dd_c8_ fxch_i /* unofficial code (0d) */ +#define _de_d0_ fcompst /* unofficial code (16) */ +#define _df_c0_ ffreep /* unofficial code (07) ffree + pop */ +#define _df_c8_ fxch_i /* unofficial code (0f) */ +#define _df_d0_ fstp_i /* unofficial code (17) */ +#define _df_d8_ fstp_i /* unofficial code (1f) */ + +static FUNC const st_instr_table[64] = { + fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, _df_c0_, + fmul__, fxch_i, __BAD__, __BAD__, fmul_i, _dd_c8_, fmulp_, _df_c8_, + fcom_st, fp_nop, __BAD__, __BAD__, _dc_d0_, fst_i_, _de_d0_, _df_d0_, + fcompst, _d9_d8_, __BAD__, __BAD__, _dc_d8_, fstp_i, fcompp, _df_d8_, + fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, + fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, + fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, + fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, +}; + +#else /* Support only documented FPU op-codes */ + +static FUNC const st_instr_table[64] = { + fadd__, fld_i_, __BAD__, __BAD__, fadd_i, ffree_, faddp_, __BAD__, + fmul__, fxch_i, __BAD__, __BAD__, fmul_i, __BAD__, fmulp_, __BAD__, + fcom_st, fp_nop, __BAD__, __BAD__, __BAD__, fst_i_, __BAD__, __BAD__, + fcompst, __BAD__, __BAD__, __BAD__, __BAD__, fstp_i, fcompp, __BAD__, + fsub__, fp_etc, __BAD__, finit_, fsubri, fucom_, fsubrp, fstsw_, + fsubr_, fconst, fucompp, __BAD__, fsub_i, fucomp, fsubp_, __BAD__, + fdiv__, trig_a, __BAD__, __BAD__, fdivri, __BAD__, fdivrp, __BAD__, + fdivr_, trig_b, __BAD__, __BAD__, fdiv_i, __BAD__, fdivp_, __BAD__, +}; + +#endif NO_UNDOC_CODE + + +#define _NONE_ 0 /* Take no special action */ +#define _REG0_ 1 /* Need to check for not empty st(0) */ +#define _REGI_ 2 /* Need to check for not empty st(0) and st(rm) */ +#define _REGi_ 0 /* Uses st(rm) */ +#define _PUSH_ 3 /* Need to check for space to push onto stack */ +#define _null_ 4 /* Function illegal or not implemented */ +#define _REGIi 5 /* Uses st(0) and st(rm), result to st(rm) */ +#define _REGIp 6 /* Uses st(0) and st(rm), result to st(rm) then pop */ +#define _REGIc 0 /* Compare st(0) and st(rm) */ +#define _REGIn 0 /* Uses st(0) and st(rm), but handle checks later */ + +#ifndef NO_UNDOC_CODE + +/* Un-documented FPU op-codes supported by default. (see above) */ + +static unsigned char const type_table[64] = { + _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _REGi_, + _REGI_, _REGIn, _null_, _null_, _REGIi, _REGI_, _REGIp, _REGI_, + _REGIc, _NONE_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, + _REGIc, _REG0_, _null_, _null_, _REGIc, _REG0_, _REGIc, _REG0_, + _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, + _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, + _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, + _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ +}; + +#else /* Support only documented FPU op-codes */ + +static unsigned char const type_table[64] = { + _REGI_, _NONE_, _null_, _null_, _REGIi, _REGi_, _REGIp, _null_, + _REGI_, _REGIn, _null_, _null_, _REGIi, _null_, _REGIp, _null_, + _REGIc, _NONE_, _null_, _null_, _null_, _REG0_, _null_, _null_, + _REGIc, _null_, _null_, _null_, _null_, _REG0_, _REGIc, _null_, + _REGI_, _NONE_, _null_, _NONE_, _REGIi, _REGIc, _REGIp, _NONE_, + _REGI_, _NONE_, _REGIc, _null_, _REGIi, _REGIc, _REGIp, _null_, + _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_, + _REGI_, _NONE_, _null_, _null_, _REGIi, _null_, _REGIp, _null_ +}; + +#endif NO_UNDOC_CODE + + +/* Be careful when using any of these global variables... + they might change if swapping is triggered */ +unsigned char FPU_rm; +char FPU_st0_tag; +FPU_REG *FPU_st0_ptr; + +/* ######## To be shifted */ +unsigned long FPU_entry_op_cs; +unsigned short FPU_data_selector; + + +#ifdef PARANOID +char emulating=0; +#endif PARANOID + +static int valid_prefix(unsigned char *byte, overrides *override); + + +asmlinkage void math_emulate(long arg) +{ + unsigned char FPU_modrm, byte1; + overrides override; + int unmasked; + +#ifdef PARANOID + if ( emulating ) + { + printk("ERROR: wm-FPU-emu is not RE-ENTRANT!\n"); + } + RE_ENTRANT_CHECK_ON; +#endif PARANOID + + if (!current->used_math) + { + int i; + for ( i = 0; i < 8; i++ ) + { + /* Make sure that the registers are compatible + with the assumptions of the emulator. */ + regs[i].exp = 0; + regs[i].sigh = 0x80000000; + } + finit(); + current->used_math = 1; + } + + SETUP_DATA_AREA(arg); + + FPU_ORIG_EIP = FPU_EIP; + + /* We cannot handle emulation in v86-mode */ + if (FPU_EFLAGS & 0x00020000) + { + math_abort(FPU_info,SIGILL); + } + + /* user code space? */ + if (FPU_CS == KERNEL_CS) + { + printk("math_emulate: %04x:%08lx\n",FPU_CS,FPU_EIP); + panic("Math emulation needed in kernel"); + } + + /* We cannot handle multiple segments yet */ + if (FPU_CS != USER_CS || FPU_DS != USER_DS) + { + math_abort(FPU_info,SIGILL); + } + + FPU_lookahead = 1; + if (current->flags & PF_PTRACED) + FPU_lookahead = 0; + + if ( !valid_prefix(&byte1, &override) ) + { + RE_ENTRANT_CHECK_OFF; + printk("FPU emulator: Unknown prefix byte 0x%02x\n", byte1); + RE_ENTRANT_CHECK_ON; + EXCEPTION(EX_INTERNAL|0x126); + math_abort(FPU_info,SIGILL); + } + +do_another_FPU_instruction: + + FPU_EIP++; /* We have fetched the prefix and first code bytes. */ + +#ifdef PECULIAR_486 + /* It would be more logical to do this only in get_address(), + but although it is supposed to be undefined for many fpu + instructions, an 80486 behaves as if this were done here: */ + FPU_data_selector = FPU_DS; +#endif PECULIAR_486 + + if ( (byte1 & 0xf8) != 0xd8 ) + { + if ( byte1 == FWAIT_OPCODE ) + { + if (partial_status & SW_Summary) + goto do_the_FPU_interrupt; + else + goto FPU_fwait_done; + } +#ifdef PARANOID + EXCEPTION(EX_INTERNAL|0x128); + math_abort(FPU_info,SIGILL); +#endif PARANOID + } + + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + FPU_modrm = get_fs_byte((unsigned short *) FPU_EIP); + RE_ENTRANT_CHECK_ON; + FPU_EIP++; + + if (partial_status & SW_Summary) + { + /* Ignore the error for now if the current instruction is a no-wait + control instruction */ + /* The 80486 manual contradicts itself on this topic, + but a real 80486 uses the following instructions: + fninit, fnstenv, fnsave, fnstsw, fnstenv, fnclex. + */ + unsigned short code = (FPU_modrm << 8) | byte1; + if ( ! ( (((code & 0xf803) == 0xe003) || /* fnclex, fninit, fnstsw */ + (((code & 0x3003) == 0x3001) && /* fnsave, fnstcw, fnstenv, + fnstsw */ + ((code & 0xc000) != 0xc000))) ) ) + { + /* + * We need to simulate the action of the kernel to FPU + * interrupts here. + * Currently, the "real FPU" part of the kernel (0.99.10) + * clears the exception flags, sets the registers to empty, + * and passes information back to the interrupted process + * via the cs selector and operand selector, so we do the same. + */ + do_the_FPU_interrupt: + cs_selector &= 0xffff0000; + cs_selector |= status_word(); + operand_selector = tag_word(); + partial_status = 0; + top = 0; + { + int r; + for (r = 0; r < 8; r++) + { + regs[r].tag = TW_Empty; + } + } + + RE_ENTRANT_CHECK_OFF; + current->tss.trap_no = 16; + current->tss.error_code = 0; + send_sig(SIGFPE, current, 1); + return; + } + } + + FPU_entry_eip = FPU_ORIG_EIP; + + FPU_entry_op_cs = (byte1 << 24) | (FPU_modrm << 16) | (FPU_CS & 0xffff) ; + + FPU_rm = FPU_modrm & 7; + + if ( FPU_modrm < 0300 ) + { + /* All of these instructions use the mod/rm byte to get a data address */ + get_address(FPU_modrm, override); + if ( !(byte1 & 1) ) + { + unsigned short status1 = partial_status; + FPU_st0_ptr = &st(0); + FPU_st0_tag = FPU_st0_ptr->tag; + + /* Stack underflow has priority */ + if ( NOT_EMPTY_0 ) + { + unmasked = 0; /* Do this here to stop compiler warnings. */ + switch ( (byte1 >> 1) & 3 ) + { + case 0: + unmasked = reg_load_single(override); + break; + case 1: + reg_load_int32(override); + break; + case 2: + unmasked = reg_load_double(override); + break; + case 3: + reg_load_int16(override); + break; + } + + /* No more access to user memory, it is safe + to use static data now */ + FPU_st0_ptr = &st(0); + FPU_st0_tag = FPU_st0_ptr->tag; + + /* NaN operands have the next priority. */ + /* We have to delay looking at st(0) until after + loading the data, because that data might contain an SNaN */ + if ( (FPU_st0_tag == TW_NaN) || + (FPU_loaded_data.tag == TW_NaN) ) + { + /* Restore the status word; we might have loaded a + denormal. */ + partial_status = status1; + if ( (FPU_modrm & 0x30) == 0x10 ) + { + /* fcom or fcomp */ + EXCEPTION(EX_Invalid); + setcc(SW_C3 | SW_C2 | SW_C0); + if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) ) + pop(); /* fcomp, masked, so we pop. */ + } + else + { +#ifdef PECULIAR_486 + /* This is not really needed, but gives behaviour + identical to an 80486 */ + if ( (FPU_modrm & 0x28) == 0x20 ) + /* fdiv or fsub */ + real_2op_NaN(&FPU_loaded_data, FPU_st0_ptr, + FPU_st0_ptr); + else +#endif PECULIAR_486 + /* fadd, fdivr, fmul, or fsubr */ + real_2op_NaN(FPU_st0_ptr, &FPU_loaded_data, + FPU_st0_ptr); + } + goto reg_mem_instr_done; + } + + if ( unmasked && !((FPU_modrm & 0x30) == 0x10) ) + { + /* Is not a comparison instruction. */ + if ( (FPU_modrm & 0x38) == 0x38 ) + { + /* fdivr */ + if ( (FPU_st0_tag == TW_Zero) && + (FPU_loaded_data.tag == TW_Valid) ) + { + if ( divide_by_zero(FPU_loaded_data.sign, + FPU_st0_ptr) ) + { + /* We use the fact here that the unmasked + exception in the loaded data was for a + denormal operand */ + /* Restore the state of the denormal op bit */ + partial_status &= ~SW_Denorm_Op; + partial_status |= status1 & SW_Denorm_Op; + } + } + } + goto reg_mem_instr_done; + } + + switch ( (FPU_modrm >> 3) & 7 ) + { + case 0: /* fadd */ + clear_C1(); + reg_add(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + control_word); + break; + case 1: /* fmul */ + clear_C1(); + reg_mul(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + control_word); + break; + case 2: /* fcom */ + compare_st_data(); + break; + case 3: /* fcomp */ + if ( !compare_st_data() && !unmasked ) + pop(); + break; + case 4: /* fsub */ + clear_C1(); + reg_sub(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + control_word); + break; + case 5: /* fsubr */ + clear_C1(); + reg_sub(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, + control_word); + break; + case 6: /* fdiv */ + clear_C1(); + reg_div(FPU_st0_ptr, &FPU_loaded_data, FPU_st0_ptr, + control_word); + break; + case 7: /* fdivr */ + clear_C1(); + if ( FPU_st0_tag == TW_Zero ) + partial_status = status1; /* Undo any denorm tag, + zero-divide has priority. */ + reg_div(&FPU_loaded_data, FPU_st0_ptr, FPU_st0_ptr, + control_word); + break; + } + } + else + { + if ( (FPU_modrm & 0x30) == 0x10 ) + { + /* The instruction is fcom or fcomp */ + EXCEPTION(EX_StackUnder); + setcc(SW_C3 | SW_C2 | SW_C0); + if ( (FPU_modrm & 0x08) && (control_word & CW_Invalid) ) + pop(); /* fcomp */ + } + else + stack_underflow(); + } + } + else + { + load_store_instr(((FPU_modrm & 0x38) | (byte1 & 6)) >> 1, override); + } + + reg_mem_instr_done: + +#ifndef PECULIAR_486 + *(unsigned short *)&operand_selector = FPU_data_selector; +#endif PECULIAR_486 + ; + } + else + { + /* None of these instructions access user memory */ + unsigned char instr_index = (FPU_modrm & 0x38) | (byte1 & 7); + +#ifdef PECULIAR_486 + /* This is supposed to be undefined, but a real 80486 seems + to do this: */ + FPU_data_address = 0; +#endif PECULIAR_486 + + FPU_st0_ptr = &st(0); + FPU_st0_tag = FPU_st0_ptr->tag; + switch ( type_table[(int) instr_index] ) + { + case _NONE_: /* also _REGIc: _REGIn */ + break; + case _REG0_: + if ( !NOT_EMPTY_0 ) + { + stack_underflow(); + goto FPU_instruction_done; + } + break; + case _REGIi: + if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) + { + stack_underflow_i(FPU_rm); + goto FPU_instruction_done; + } + break; + case _REGIp: + if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) + { + stack_underflow_pop(FPU_rm); + goto FPU_instruction_done; + } + break; + case _REGI_: + if ( !NOT_EMPTY_0 || !NOT_EMPTY(FPU_rm) ) + { + stack_underflow(); + goto FPU_instruction_done; + } + break; + case _PUSH_: /* Only used by the fld st(i) instruction */ + break; + case _null_: + FPU_illegal(); + goto FPU_instruction_done; + default: + EXCEPTION(EX_INTERNAL|0x111); + goto FPU_instruction_done; + } + (*st_instr_table[(int) instr_index])(); + } + +FPU_instruction_done: + + ip_offset = FPU_entry_eip; + cs_selector = FPU_entry_op_cs; + data_operand_offset = (unsigned long)FPU_data_address; +#ifdef PECULIAR_486 + *(unsigned short *)&operand_selector = FPU_data_selector; +#endif PECULIAR_486 + +FPU_fwait_done: + +#ifdef DEBUG + RE_ENTRANT_CHECK_OFF; + emu_printall(); + RE_ENTRANT_CHECK_ON; +#endif DEBUG + + if (FPU_lookahead && !need_resched) + { + FPU_ORIG_EIP = FPU_EIP; + if ( valid_prefix(&byte1, &override) ) + goto do_another_FPU_instruction; + } + + RE_ENTRANT_CHECK_OFF; +} + + +/* Support for prefix bytes is not yet complete. To properly handle + all prefix bytes, further changes are needed in the emulator code + which accesses user address space. Access to separate segments is + important for msdos emulation. */ +static int valid_prefix(unsigned char *Byte, overrides *override) +{ + unsigned char byte; + unsigned long ip = FPU_EIP; + + *override = (overrides) { 0, PREFIX_DS }; /* defaults */ + + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + byte = get_fs_byte((unsigned char *) FPU_EIP); + RE_ENTRANT_CHECK_ON; + + while ( 1 ) + { + switch ( byte ) + { + case ADDR_SIZE_PREFIX: + override->address_size = ADDR_SIZE_PREFIX; + goto do_next_byte; + case PREFIX_CS: + override->segment = PREFIX_CS; + goto do_next_byte; + case PREFIX_ES: + override->segment = PREFIX_ES; + goto do_next_byte; + case PREFIX_SS: + override->segment = PREFIX_SS; + goto do_next_byte; + case PREFIX_FS: + override->segment = PREFIX_FS; + goto do_next_byte; + case PREFIX_GS: + override->segment = PREFIX_GS; + goto do_next_byte; + + case PREFIX_DS: /* Redundant unless preceded by another override. */ + override->segment = PREFIX_DS; + + /* rep.. prefixes have no meaning for FPU instructions */ + case PREFIX_LOCK: + case PREFIX_REPE: + case PREFIX_REPNE: + case OP_SIZE_PREFIX: /* Used often by gcc, but has no effect. */ + do_next_byte: + FPU_EIP++; + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + byte = get_fs_byte((unsigned char *) (FPU_EIP)); + RE_ENTRANT_CHECK_ON; + break; + case FWAIT_OPCODE: + *Byte = byte; + return 1; + default: + if ( (byte & 0xf8) == 0xd8 ) + { + *Byte = byte; + return 1; + } + else + { + FPU_EIP = ip; + return 0; + } + } + } +} + + +void __math_abort(struct info * info, unsigned int signal) +{ + FPU_EIP = FPU_ORIG_EIP; + current->tss.trap_no = 16; + current->tss.error_code = 0; + send_sig(signal,current,1); + RE_ENTRANT_CHECK_OFF; + __asm__("movl %0,%%esp ; ret": :"g" (((long) info)-4)); +#ifdef PARANOID + printk("ERROR: wm-FPU-emu math_abort failed!\n"); +#endif PARANOID +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_etc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_etc.c new file mode 100644 index 000000000..b7e1154cb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_etc.c @@ -0,0 +1,127 @@ +/*---------------------------------------------------------------------------+ + | fpu_etc.c | + | | + | Implement a few FPU instructions. | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" +#include "status_w.h" +#include "reg_constant.h" + + +static void fchs(void) +{ + if ( NOT_EMPTY_0 ) + { + FPU_st0_ptr->sign ^= SIGN_POS^SIGN_NEG; + clear_C1(); + } + else + stack_underflow(); +} + +static void fabs(void) +{ + if ( FPU_st0_tag ^ TW_Empty ) + { + FPU_st0_ptr->sign = SIGN_POS; + clear_C1(); + } + else + stack_underflow(); +} + + +static void ftst_(void) +{ + switch (FPU_st0_tag) + { + case TW_Zero: + setcc(SW_C3); + break; + case TW_Valid: + if (FPU_st0_ptr->sign == SIGN_POS) + setcc(0); + else + setcc(SW_C0); + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + { +#ifdef PECULIAR_486 + /* This is wierd! */ + if (FPU_st0_ptr->sign == SIGN_POS) + setcc(SW_C3); +#endif PECULIAR_486 + return; + } +#endif DENORM_OPERAND + + break; + case TW_NaN: + setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ + EXCEPTION(EX_Invalid); + break; + case TW_Infinity: + if (FPU_st0_ptr->sign == SIGN_POS) + setcc(0); + else + setcc(SW_C0); + break; + case TW_Empty: + setcc(SW_C0|SW_C2|SW_C3); + EXCEPTION(EX_StackUnder); + break; + default: + setcc(SW_C0|SW_C2|SW_C3); /* Operand is not comparable */ + EXCEPTION(EX_INTERNAL|0x14); + break; + } +} + +static void fxam(void) +{ + int c=0; + switch (FPU_st0_tag) + { + case TW_Empty: + c = SW_C3|SW_C0; + break; + case TW_Zero: + c = SW_C3; + break; + case TW_Valid: + /* This will need to be changed if TW_Denormal is ever used. */ + if ( FPU_st0_ptr->exp <= EXP_UNDER ) + c = SW_C2|SW_C3; /* Denormal */ + else + c = SW_C2; + break; + case TW_NaN: + c = SW_C0; + break; + case TW_Infinity: + c = SW_C2|SW_C0; + break; + } + if (FPU_st0_ptr->sign == SIGN_NEG) + c |= SW_C1; + setcc(c); +} + +static FUNC const fp_etc_table[] = { + fchs, fabs, FPU_illegal, FPU_illegal, ftst_, fxam, FPU_illegal, FPU_illegal +}; + +void fp_etc() +{ + (fp_etc_table[FPU_rm])(); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_proto.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_proto.h new file mode 100644 index 000000000..ca659a246 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_proto.h @@ -0,0 +1,131 @@ +/* errors.c */ +extern void Un_impl(void); +extern void FPU_illegal(void); +extern void emu_printall(void); +extern void stack_overflow(void); +extern void stack_underflow(void); +extern void stack_underflow_i(int i); +extern void stack_underflow_pop(int i); +extern int set_precision_flag(int flags); +asmlinkage void exception(int n); +asmlinkage int real_2op_NaN(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest); +asmlinkage int arith_invalid(FPU_REG *dest); +asmlinkage int divide_by_zero(int sign, FPU_REG *dest); +asmlinkage void set_precision_flag_up(void); +asmlinkage void set_precision_flag_down(void); +asmlinkage int denormal_operand(void); +asmlinkage int arith_overflow(FPU_REG *dest); +asmlinkage int arith_underflow(FPU_REG *dest); + +/* fpu_arith.c */ +extern void fadd__(void); +extern void fmul__(void); +extern void fsub__(void); +extern void fsubr_(void); +extern void fdiv__(void); +extern void fdivr_(void); +extern void fadd_i(void); +extern void fmul_i(void); +extern void fsubri(void); +extern void fsub_i(void); +extern void fdivri(void); +extern void fdiv_i(void); +extern void faddp_(void); +extern void fmulp_(void); +extern void fsubrp(void); +extern void fsubp_(void); +extern void fdivrp(void); +extern void fdivp_(void); + +/* fpu_aux.c */ +extern void fclex(void); +extern void finit(void); +extern void finit_(void); +extern void fstsw_(void); +extern void fp_nop(void); +extern void fld_i_(void); +extern void fxch_i(void); +extern void ffree_(void); +extern void ffreep(void); +extern void fst_i_(void); +extern void fstp_i(void); + +/* fpu_entry.c */ +asmlinkage void math_emulate(long arg); +extern void __math_abort(struct info *info, unsigned int signal); + +/* fpu_etc.c */ +extern void fp_etc(void); + +/* fpu_trig.c */ +extern void convert_l2reg(long const *arg, FPU_REG *dest); +extern void trig_a(void); +extern void trig_b(void); + +/* get_address.c */ +extern void get_address(unsigned char FPU_modrm, overrides override); + +/* load_store.c */ +extern void load_store_instr(char type, overrides override); + +/* poly_2xm1.c */ +extern int poly_2xm1(FPU_REG const *arg, FPU_REG *result); + +/* poly_atan.c */ +extern void poly_atan(FPU_REG *arg); +extern void poly_add_1(FPU_REG *src); + +/* poly_l2.c */ +extern void poly_l2(FPU_REG const *arg, FPU_REG *result); +extern int poly_l2p1(FPU_REG const *arg, FPU_REG *result); + +/* poly_sin.c */ +extern void poly_sine(FPU_REG const *arg, FPU_REG *result); + +/* poly_tan.c */ +extern void poly_tan(FPU_REG const *arg, FPU_REG *result, int invert); + +/* reg_add_sub.c */ +extern int reg_add(FPU_REG const *a, FPU_REG const *b, + FPU_REG *dest, int control_w); +extern int reg_sub(FPU_REG const *a, FPU_REG const *b, + FPU_REG *dest, int control_w); + +/* reg_compare.c */ +extern int compare(FPU_REG const *b); +extern int compare_st_data(void); +extern void fcom_st(void); +extern void fcompst(void); +extern void fcompp(void); +extern void fucom_(void); +extern void fucomp(void); +extern void fucompp(void); + +/* reg_constant.c */ +extern void fconst(void); + +/* reg_ld_str.c */ +extern int reg_load_extended(overrides override); +extern int reg_load_double(overrides override); +extern int reg_load_single(overrides override); +extern void reg_load_int64(overrides override); +extern void reg_load_int32(overrides override); +extern void reg_load_int16(overrides override); +extern void reg_load_bcd(overrides override); +extern int reg_store_extended(overrides override); +extern int reg_store_double(overrides override); +extern int reg_store_single(overrides override); +extern int reg_store_int64(overrides override); +extern int reg_store_int32(overrides override); +extern int reg_store_int16(overrides override); +extern int reg_store_bcd(overrides override); +extern int round_to_int(FPU_REG *r); +extern char *fldenv(void); +extern void frstor(void); +extern unsigned short tag_word(void); +extern char *fstenv(void); +extern void fsave(void); + +/* reg_mul.c */ +extern int reg_mul(FPU_REG const *a, FPU_REG const *b, + FPU_REG *dest, unsigned int control_w); diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_system.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_system.h new file mode 100644 index 000000000..52ae0f7d2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_system.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------------+ + | fpu_system.h | + | | + | Copyright (C) 1992,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + +#ifndef _FPU_SYSTEM_H +#define _FPU_SYSTEM_H + +/* system dependent definitions */ + +#include +#include + +/* This sets the pointer FPU_info to point to the argument part + of the stack frame of math_emulate() */ +#define SETUP_DATA_AREA(arg) FPU_info = (struct info *) &arg + +#define I387 (current->tss.i387) +#define FPU_info (I387.soft.info) + +#define FPU_CS (*(unsigned short *) &(FPU_info->___cs)) +#define FPU_DS (*(unsigned short *) &(FPU_info->___ds)) +#define FPU_EAX (FPU_info->___eax) +#define FPU_EFLAGS (FPU_info->___eflags) +#define FPU_EIP (FPU_info->___eip) +#define FPU_ORIG_EIP (FPU_info->___orig_eip) + +#define FPU_lookahead (I387.soft.lookahead) +#define FPU_entry_eip (I387.soft.entry_eip) + +#define partial_status (I387.soft.swd) +#define control_word (I387.soft.cwd) +#define regs (I387.soft.regs) +#define top (I387.soft.top) + +#define ip_offset (I387.soft.fip) +#define cs_selector (I387.soft.fcs) +#define data_operand_offset (I387.soft.foo) +#define operand_selector (I387.soft.fos) + +#define FPU_verify_area(x,y,z) if ( verify_area(x,y,z) ) \ + math_abort(FPU_info,SIGSEGV) + +#undef FPU_IGNORE_CODE_SEGV +#ifdef FPU_IGNORE_CODE_SEGV +/* verify_area() is very expensive, and causes the emulator to run + about 20% slower if applied to the code. Anyway, errors due to bad + code addresses should be much rarer than errors due to bad data + addresses. */ +#define FPU_code_verify_area(z) +#else +/* A simpler test than verify_area() can probably be done for + FPU_code_verify_area() because the only possible error is to step + past the upper boundary of a legal code area. */ +#define FPU_code_verify_area(z) FPU_verify_area(VERIFY_READ,(void *)FPU_EIP,z) +#endif + +/* ######## temporary and ugly ;-) */ +#define FPU_data_address ((void *)(I387.soft.twd)) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_trig.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_trig.c new file mode 100644 index 000000000..1de4317a5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/fpu_trig.c @@ -0,0 +1,1741 @@ +/*---------------------------------------------------------------------------+ + | fpu_trig.c | + | | + | Implementation of the FPU "transcendental" functions. | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" +#include "status_w.h" +#include "control_w.h" +#include "reg_constant.h" + + +static void rem_kernel(unsigned long long st0, unsigned long long *y, + unsigned long long st1, + unsigned long long q, int n); + +#define BETTER_THAN_486 + +#define FCOS 4 +#define FPTAN 1 + + +/* Used only by fptan, fsin, fcos, and fsincos. */ +/* This routine produces very accurate results, similar to + using a value of pi with more than 128 bits precision. */ +/* Limited measurements show no results worse than 64 bit precision + except for the results for arguments close to 2^63, where the + precision of the result sometimes degrades to about 63.9 bits */ +static int trig_arg(FPU_REG *X, int even) +{ + FPU_REG tmp; + unsigned long long q; + int old_cw = control_word, saved_status = partial_status; + + if ( X->exp >= EXP_BIAS + 63 ) + { + partial_status |= SW_C2; /* Reduction incomplete. */ + return -1; + } + + control_word &= ~CW_RC; + control_word |= RC_CHOP; + + reg_div(X, &CONST_PI2, &tmp, PR_64_BITS | RC_CHOP | 0x3f); + round_to_int(&tmp); /* Fortunately, this can't overflow + to 2^64 */ + q = significand(&tmp); + if ( q ) + { + rem_kernel(significand(X), + &significand(&tmp), + significand(&CONST_PI2), + q, X->exp - CONST_PI2.exp); + tmp.exp = CONST_PI2.exp; + normalize(&tmp); + reg_move(&tmp, X); + } + + if ( even == FPTAN ) + { + if ( ((X->exp >= EXP_BIAS) || + ((X->exp == EXP_BIAS-1) + && (X->sigh >= 0xc90fdaa2))) ^ (q & 1) ) + even = FCOS; + else + even = 0; + } + + if ( (even && !(q & 1)) || (!even && (q & 1)) ) + { + reg_sub(&CONST_PI2, X, X, FULL_PRECISION); +#ifdef BETTER_THAN_486 + /* So far, the results are exact but based upon a 64 bit + precision approximation to pi/2. The technique used + now is equivalent to using an approximation to pi/2 which + is accurate to about 128 bits. */ + if ( (X->exp <= CONST_PI2extra.exp + 64) || (q > 1) ) + { + /* This code gives the effect of having p/2 to better than + 128 bits precision. */ + significand(&tmp) = q + 1; + tmp.exp = EXP_BIAS + 63; + tmp.tag = TW_Valid; + normalize(&tmp); + reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION); + reg_add(X, &tmp, X, FULL_PRECISION); + if ( X->sign == SIGN_NEG ) + { + /* CONST_PI2extra is negative, so the result of the addition + can be negative. This means that the argument is actually + in a different quadrant. The correction is always < pi/2, + so it can't overflow into yet another quadrant. */ + X->sign = SIGN_POS; + q++; + } + } +#endif BETTER_THAN_486 + } +#ifdef BETTER_THAN_486 + else + { + /* So far, the results are exact but based upon a 64 bit + precision approximation to pi/2. The technique used + now is equivalent to using an approximation to pi/2 which + is accurate to about 128 bits. */ + if ( ((q > 0) && (X->exp <= CONST_PI2extra.exp + 64)) || (q > 1) ) + { + /* This code gives the effect of having p/2 to better than + 128 bits precision. */ + significand(&tmp) = q; + tmp.exp = EXP_BIAS + 63; + tmp.tag = TW_Valid; + normalize(&tmp); + reg_mul(&CONST_PI2extra, &tmp, &tmp, FULL_PRECISION); + reg_sub(X, &tmp, X, FULL_PRECISION); + if ( (X->exp == CONST_PI2.exp) && + ((X->sigh > CONST_PI2.sigh) + || ((X->sigh == CONST_PI2.sigh) + && (X->sigl > CONST_PI2.sigl))) ) + { + /* CONST_PI2extra is negative, so the result of the + subtraction can be larger than pi/2. This means + that the argument is actually in a different quadrant. + The correction is always < pi/2, so it can't overflow + into yet another quadrant. */ + reg_sub(&CONST_PI, X, X, FULL_PRECISION); + q++; + } + } + } +#endif BETTER_THAN_486 + + control_word = old_cw; + partial_status = saved_status & ~SW_C2; /* Reduction complete. */ + + return (q & 3) | even; +} + + +/* Convert a long to register */ +void convert_l2reg(long const *arg, FPU_REG *dest) +{ + long num = *arg; + + if (num == 0) + { reg_move(&CONST_Z, dest); return; } + + if (num > 0) + dest->sign = SIGN_POS; + else + { num = -num; dest->sign = SIGN_NEG; } + + dest->sigh = num; + dest->sigl = 0; + dest->exp = EXP_BIAS + 31; + dest->tag = TW_Valid; + normalize(dest); +} + + +static void single_arg_error(void) +{ + switch ( FPU_st0_tag ) + { + case TW_NaN: + if ( !(FPU_st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ + { + EXCEPTION(EX_Invalid); + if ( control_word & CW_Invalid ) + FPU_st0_ptr->sigh |= 0x40000000; /* Convert to a QNaN */ + } + break; /* return with a NaN in st(0) */ + case TW_Empty: + stack_underflow(); /* Puts a QNaN in st(0) */ + break; +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL|0x0112); +#endif PARANOID + } +} + + +static void single_arg_2_error(void) +{ + FPU_REG *st_new_ptr; + + switch ( FPU_st0_tag ) + { + case TW_NaN: + if ( !(FPU_st0_ptr->sigh & 0x40000000) ) /* Signaling ? */ + { + EXCEPTION(EX_Invalid); + if ( control_word & CW_Invalid ) + { + /* The masked response */ + /* Convert to a QNaN */ + FPU_st0_ptr->sigh |= 0x40000000; + st_new_ptr = &st(-1); + push(); + reg_move(&st(1), FPU_st0_ptr); + } + } + else + { + /* A QNaN */ + st_new_ptr = &st(-1); + push(); + reg_move(&st(1), FPU_st0_ptr); + } + break; /* return with a NaN in st(0) */ +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL|0x0112); +#endif PARANOID + } +} + + +/*---------------------------------------------------------------------------*/ + +static void f2xm1(void) +{ + clear_C1(); + switch ( FPU_st0_tag ) + { + case TW_Valid: + { + FPU_REG rv, tmp; + + if ( FPU_st0_ptr->exp >= 0 ) + { + /* For an 80486 FPU, the result is undefined. */ + } + else if ( FPU_st0_ptr->exp >= -64 ) + { + if ( FPU_st0_ptr->sign == SIGN_POS ) + { + /* poly_2xm1(x) requires 0 < x < 1. */ + poly_2xm1(FPU_st0_ptr, &rv); + reg_mul(&rv, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); + } + else + { + /* poly_2xm1(x) doesn't handle negative numbers yet. */ + /* So we compute z=poly_2xm1(-x), and the answer is + then -z/(1+z) */ + FPU_st0_ptr->sign = SIGN_POS; + poly_2xm1(FPU_st0_ptr, &rv); + reg_mul(&rv, FPU_st0_ptr, &rv, FULL_PRECISION); + reg_add(&rv, &CONST_1, &tmp, FULL_PRECISION); + reg_div(&rv, &tmp, FPU_st0_ptr, FULL_PRECISION); + FPU_st0_ptr->sign = SIGN_NEG; + } + } + else + { +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + /* For very small arguments, this is accurate enough. */ + reg_mul(&CONST_LN2, FPU_st0_ptr, FPU_st0_ptr, FULL_PRECISION); + } + set_precision_flag_up(); + return; + } + case TW_Zero: + return; + case TW_Infinity: + if ( FPU_st0_ptr->sign == SIGN_NEG ) + { + /* -infinity gives -1 (p16-10) */ + reg_move(&CONST_1, FPU_st0_ptr); + FPU_st0_ptr->sign = SIGN_NEG; + } + return; + default: + single_arg_error(); + } +} + + +static void fptan(void) +{ + FPU_REG *st_new_ptr; + int q; + char arg_sign = FPU_st0_ptr->sign; + + /* Stack underflow has higher priority */ + if ( FPU_st0_tag == TW_Empty ) + { + stack_underflow(); /* Puts a QNaN in st(0) */ + if ( control_word & CW_Invalid ) + { + st_new_ptr = &st(-1); + push(); + stack_underflow(); /* Puts a QNaN in the new st(0) */ + } + return; + } + + if ( STACK_OVERFLOW ) + { stack_overflow(); return; } + + switch ( FPU_st0_tag ) + { + case TW_Valid: + + if ( FPU_st0_ptr->exp > EXP_BIAS - 40 ) + { + FPU_st0_ptr->sign = SIGN_POS; + if ( (q = trig_arg(FPU_st0_ptr, FPTAN)) != -1 ) + { + reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr, + FULL_PRECISION); + poly_tan(FPU_st0_ptr, FPU_st0_ptr, q & FCOS); + FPU_st0_ptr->sign = (q & 1) ^ arg_sign; + } + else + { + /* Operand is out of range */ + FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ + return; + } + } + else + { + /* For a small arg, the result == the argument */ + /* Underflow may happen */ + + if ( FPU_st0_ptr->exp <= EXP_UNDER ) + { +#ifdef DENORM_OPERAND + if ( denormal_operand() ) + return; +#endif DENORM_OPERAND + /* A denormal result has been produced. + Precision must have been lost, this is always + an underflow. */ + if ( arith_underflow(FPU_st0_ptr) ) + return; + } + else + set_precision_flag_up(); /* Must be up. */ + } + push(); + reg_move(&CONST_1, FPU_st0_ptr); + return; + break; + case TW_Infinity: + /* The 80486 treats infinity as an invalid operand */ + arith_invalid(FPU_st0_ptr); + if ( control_word & CW_Invalid ) + { + st_new_ptr = &st(-1); + push(); + arith_invalid(FPU_st0_ptr); + } + return; + case TW_Zero: + push(); + reg_move(&CONST_1, FPU_st0_ptr); + setcc(0); + break; + default: + single_arg_2_error(); + break; + } +} + + +static void fxtract(void) +{ + FPU_REG *st_new_ptr; + register FPU_REG *st1_ptr = FPU_st0_ptr; /* anticipate */ + + if ( STACK_OVERFLOW ) + { stack_overflow(); return; } + clear_C1(); + if ( !(FPU_st0_tag ^ TW_Valid) ) + { + long e; + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + push(); + reg_move(st1_ptr, FPU_st0_ptr); + FPU_st0_ptr->exp = EXP_BIAS; + e = st1_ptr->exp - EXP_BIAS; + convert_l2reg(&e, st1_ptr); + return; + } + else if ( FPU_st0_tag == TW_Zero ) + { + char sign = FPU_st0_ptr->sign; + if ( divide_by_zero(SIGN_NEG, FPU_st0_ptr) ) + return; + push(); + reg_move(&CONST_Z, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + return; + } + else if ( FPU_st0_tag == TW_Infinity ) + { + char sign = FPU_st0_ptr->sign; + FPU_st0_ptr->sign = SIGN_POS; + push(); + reg_move(&CONST_INF, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + return; + } + else if ( FPU_st0_tag == TW_NaN ) + { + if ( real_2op_NaN(FPU_st0_ptr, FPU_st0_ptr, FPU_st0_ptr) ) + return; + push(); + reg_move(st1_ptr, FPU_st0_ptr); + return; + } + else if ( FPU_st0_tag == TW_Empty ) + { + /* Is this the correct behaviour? */ + if ( control_word & EX_Invalid ) + { + stack_underflow(); + push(); + stack_underflow(); + } + else + EXCEPTION(EX_StackUnder); + } +#ifdef PARANOID + else + EXCEPTION(EX_INTERNAL | 0x119); +#endif PARANOID +} + + +static void fdecstp(void) +{ + clear_C1(); + top--; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */ +} + +static void fincstp(void) +{ + clear_C1(); + top++; /* FPU_st0_ptr will be fixed in math_emulate() before the next instr */ +} + + +static void fsqrt_(void) +{ + clear_C1(); + if ( !(FPU_st0_tag ^ TW_Valid) ) + { + int expon; + + if (FPU_st0_ptr->sign == SIGN_NEG) + { + arith_invalid(FPU_st0_ptr); /* sqrt(negative) is invalid */ + return; + } + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + expon = FPU_st0_ptr->exp - EXP_BIAS; + FPU_st0_ptr->exp = EXP_BIAS + (expon & 1); /* make st(0) in [1.0 .. 4.0) */ + + wm_sqrt(FPU_st0_ptr, control_word); /* Do the computation */ + + FPU_st0_ptr->exp += expon >> 1; + FPU_st0_ptr->sign = SIGN_POS; + } + else if ( FPU_st0_tag == TW_Zero ) + return; + else if ( FPU_st0_tag == TW_Infinity ) + { + if ( FPU_st0_ptr->sign == SIGN_NEG ) + arith_invalid(FPU_st0_ptr); /* sqrt(-Infinity) is invalid */ + return; + } + else + { single_arg_error(); return; } + +} + + +static void frndint_(void) +{ + int flags; + + if ( !(FPU_st0_tag ^ TW_Valid) ) + { + if (FPU_st0_ptr->exp > EXP_BIAS+63) + return; + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + /* Fortunately, this can't overflow to 2^64 */ + if ( (flags = round_to_int(FPU_st0_ptr)) ) + set_precision_flag(flags); + + FPU_st0_ptr->exp = EXP_BIAS + 63; + normalize(FPU_st0_ptr); + return; + } + else if ( (FPU_st0_tag == TW_Zero) || (FPU_st0_tag == TW_Infinity) ) + return; + else + single_arg_error(); +} + + +static void fsin(void) +{ + char arg_sign = FPU_st0_ptr->sign; + + if ( FPU_st0_tag == TW_Valid ) + { + FPU_REG rv; + int q; + + if ( FPU_st0_ptr->exp > EXP_BIAS - 40 ) + { + FPU_st0_ptr->sign = SIGN_POS; + if ( (q = trig_arg(FPU_st0_ptr, 0)) != -1 ) + { + reg_div(FPU_st0_ptr, &CONST_PI2, FPU_st0_ptr, FULL_PRECISION); + + poly_sine(FPU_st0_ptr, &rv); + + if (q & 2) + rv.sign ^= SIGN_POS ^ SIGN_NEG; + rv.sign ^= arg_sign; + reg_move(&rv, FPU_st0_ptr); + + /* We do not really know if up or down */ + set_precision_flag_up(); + return; + } + else + { + /* Operand is out of range */ + FPU_st0_ptr->sign = arg_sign; /* restore st(0) */ + return; + } + } + else + { + /* For a small arg, the result == the argument */ + /* Underflow may happen */ + + if ( FPU_st0_ptr->exp <= EXP_UNDER ) + { +#ifdef DENORM_OPERAND + if ( denormal_operand() ) + return; +#endif DENORM_OPERAND + /* A denormal result has been produced. + Precision must have been lost, this is always + an underflow. */ + arith_underflow(FPU_st0_ptr); + return; + } + + set_precision_flag_up(); /* Must be up. */ + } + } + else if ( FPU_st0_tag == TW_Zero ) + { + setcc(0); + return; + } + else if ( FPU_st0_tag == TW_Infinity ) + { + /* The 80486 treats infinity as an invalid operand */ + arith_invalid(FPU_st0_ptr); + return; + } + else + single_arg_error(); +} + + +static int f_cos(FPU_REG *arg) +{ + char arg_sign = arg->sign; + + if ( arg->tag == TW_Valid ) + { + FPU_REG rv; + int q; + + if ( arg->exp > EXP_BIAS - 40 ) + { + arg->sign = SIGN_POS; + if ( (q = trig_arg(arg, FCOS)) != -1 ) + { + reg_div(arg, &CONST_PI2, arg, FULL_PRECISION); + + poly_sine(arg, &rv); + + if ((q+1) & 2) + rv.sign ^= SIGN_POS ^ SIGN_NEG; + reg_move(&rv, arg); + + /* We do not really know if up or down */ + set_precision_flag_down(); + + return 0; + } + else + { + /* Operand is out of range */ + arg->sign = arg_sign; /* restore st(0) */ + return 1; + } + } + else + { +#ifdef DENORM_OPERAND + if ( (arg->exp <= EXP_UNDER) && (denormal_operand()) ) + return 1; +#endif DENORM_OPERAND + + setcc(0); + reg_move(&CONST_1, arg); +#ifdef PECULIAR_486 + set_precision_flag_down(); /* 80486 appears to do this. */ +#else + set_precision_flag_up(); /* Must be up. */ +#endif PECULIAR_486 + return 0; + } + } + else if ( arg->tag == TW_Zero ) + { + reg_move(&CONST_1, arg); + setcc(0); + return 0; + } + else if ( FPU_st0_tag == TW_Infinity ) + { + /* The 80486 treats infinity as an invalid operand */ + arith_invalid(FPU_st0_ptr); + return 1; + } + else + { + single_arg_error(); /* requires arg == &st(0) */ + return 1; + } +} + + +static void fcos(void) +{ + f_cos(FPU_st0_ptr); +} + + +static void fsincos(void) +{ + FPU_REG *st_new_ptr; + FPU_REG arg; + + /* Stack underflow has higher priority */ + if ( FPU_st0_tag == TW_Empty ) + { + stack_underflow(); /* Puts a QNaN in st(0) */ + if ( control_word & CW_Invalid ) + { + st_new_ptr = &st(-1); + push(); + stack_underflow(); /* Puts a QNaN in the new st(0) */ + } + return; + } + + if ( STACK_OVERFLOW ) + { stack_overflow(); return; } + + if ( FPU_st0_tag == TW_NaN ) + { + single_arg_2_error(); + return; + } + else if ( FPU_st0_tag == TW_Infinity ) + { + /* The 80486 treats infinity as an invalid operand */ + if ( !arith_invalid(FPU_st0_ptr) ) + { + /* unmasked response */ + push(); + arith_invalid(FPU_st0_ptr); + } + return; + } + + reg_move(FPU_st0_ptr,&arg); + if ( !f_cos(&arg) ) + { + fsin(); + push(); + reg_move(&arg,FPU_st0_ptr); + } + +} + + +/*---------------------------------------------------------------------------*/ +/* The following all require two arguments: st(0) and st(1) */ + +/* A lean, mean kernel for the fprem instructions. This relies upon + the division and rounding to an integer in do_fprem giving an + exact result. Because of this, rem_kernel() needs to deal only with + the least significant 64 bits, the more significant bits of the + result must be zero. + */ +static void rem_kernel(unsigned long long st0, unsigned long long *y, + unsigned long long st1, + unsigned long long q, int n) +{ + unsigned long long x; + + x = st0 << n; + + /* Do the required multiplication and subtraction in the one operation */ + asm volatile ("movl %2,%%eax; mull %4; subl %%eax,%0; sbbl %%edx,%1; + movl %3,%%eax; mull %4; subl %%eax,%1; + movl %2,%%eax; mull %5; subl %%eax,%1;" + :"=m" (x), "=m" (((unsigned *)&x)[1]) + :"m" (st1),"m" (((unsigned *)&st1)[1]), + "m" (q),"m" (((unsigned *)&q)[1]) + :"%ax","%dx"); + + *y = x; +} + + +/* Remainder of st(0) / st(1) */ +/* This routine produces exact results, i.e. there is never any + rounding or truncation, etc of the result. */ +static void do_fprem(int round) +{ + FPU_REG *st1_ptr = &st(1); + char st1_tag = st1_ptr->tag; + char sign = FPU_st0_ptr->sign; + + if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + { + FPU_REG tmp; + int old_cw = control_word; + int expdif = FPU_st0_ptr->exp - st1_ptr->exp; + long long q; + unsigned short saved_status; + int cc = 0; + +#ifdef DENORM_OPERAND + if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + /* We want the status following the denorm tests, but don't want + the status changed by the arithmetic operations. */ + saved_status = partial_status; + control_word &= ~CW_RC; + control_word |= RC_CHOP; + + if (expdif < 64) + { + /* This should be the most common case */ + + if ( expdif > -2 ) + { + reg_div(FPU_st0_ptr, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f); + + if ( tmp.exp >= EXP_BIAS ) + { + round_to_int(&tmp); /* Fortunately, this can't overflow + to 2^64 */ + q = significand(&tmp); + + rem_kernel(significand(FPU_st0_ptr), + &significand(&tmp), + significand(st1_ptr), + q, expdif); + + tmp.exp = st1_ptr->exp; + } + else + { + reg_move(FPU_st0_ptr, &tmp); + q = 0; + } + tmp.sign = sign; + + if ( (round == RC_RND) && (tmp.sigh & 0xc0000000) ) + { + /* We may need to subtract st(1) once more, + to get a result <= 1/2 of st(1). */ + unsigned long long x; + expdif = st1_ptr->exp - tmp.exp; + if ( expdif <= 1 ) + { + if ( expdif == 0 ) + x = significand(st1_ptr) - significand(&tmp); + else /* expdif is 1 */ + x = (significand(st1_ptr) << 1) - significand(&tmp); + if ( (x < significand(&tmp)) || + /* or equi-distant (from 0 & st(1)) and q is odd */ + ((x == significand(&tmp)) && (q & 1) ) ) + { + tmp.sign ^= (SIGN_POS^SIGN_NEG); + significand(&tmp) = x; + q++; + } + } + } + + if (q & 4) cc |= SW_C0; + if (q & 2) cc |= SW_C3; + if (q & 1) cc |= SW_C1; + } + else + { + control_word = old_cw; + setcc(0); + return; + } + } + else + { + /* There is a large exponent difference ( >= 64 ) */ + /* To make much sense, the code in this section should + be done at high precision. */ + int exp_1; + + /* prevent overflow here */ + /* N is 'a number between 32 and 63' (p26-113) */ + reg_move(FPU_st0_ptr, &tmp); + tmp.exp = EXP_BIAS + 56; + exp_1 = st1_ptr->exp; st1_ptr->exp = EXP_BIAS; + expdif -= 56; + + reg_div(&tmp, st1_ptr, &tmp, PR_64_BITS | RC_CHOP | 0x3f); + st1_ptr->exp = exp_1; + + round_to_int(&tmp); /* Fortunately, this can't overflow to 2^64 */ + + rem_kernel(significand(FPU_st0_ptr), + &significand(&tmp), + significand(st1_ptr), + significand(&tmp), + tmp.exp - EXP_BIAS + ); + tmp.exp = exp_1 + expdif; + tmp.sign = sign; + + /* It is possible for the operation to be complete here. + What does the IEEE standard say? The Intel 80486 manual + implies that the operation will never be completed at this + point, and the behaviour of a real 80486 confirms this. + */ + if ( !(tmp.sigh | tmp.sigl) ) + { + /* The result is zero */ + control_word = old_cw; + partial_status = saved_status; + reg_move(&CONST_Z, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; +#ifdef PECULIAR_486 + setcc(SW_C2); +#else + setcc(0); +#endif PECULIAR_486 + return; + } + cc = SW_C2; + } + + control_word = old_cw; + partial_status = saved_status; + normalize_nuo(&tmp); + reg_move(&tmp, FPU_st0_ptr); + setcc(cc); + + /* The only condition to be looked for is underflow, + and it can occur here only if underflow is unmasked. */ + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (FPU_st0_ptr->tag != TW_Zero) + && !(control_word & CW_Underflow) ) + arith_underflow(FPU_st0_ptr); + + return; + } + else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) + { + stack_underflow(); + return; + } + else if ( FPU_st0_tag == TW_Zero ) + { + if ( st1_tag == TW_Valid ) + { +#ifdef DENORM_OPERAND + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + setcc(0); return; + } + else if ( st1_tag == TW_Zero ) + { arith_invalid(FPU_st0_ptr); return; } /* fprem(?,0) always invalid */ + else if ( st1_tag == TW_Infinity ) + { setcc(0); return; } + } + else if ( FPU_st0_tag == TW_Valid ) + { + if ( st1_tag == TW_Zero ) + { + arith_invalid(FPU_st0_ptr); /* fprem(Valid,Zero) is invalid */ + return; + } + else if ( st1_tag != TW_NaN ) + { +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + if ( st1_tag == TW_Infinity ) + { + /* fprem(Valid,Infinity) is o.k. */ + setcc(0); return; + } + } + } + else if ( FPU_st0_tag == TW_Infinity ) + { + if ( st1_tag != TW_NaN ) + { + arith_invalid(FPU_st0_ptr); /* fprem(Infinity,?) is invalid */ + return; + } + } + + /* One of the registers must contain a NaN is we got here. */ + +#ifdef PARANOID + if ( (FPU_st0_tag != TW_NaN) && (st1_tag != TW_NaN) ) + EXCEPTION(EX_INTERNAL | 0x118); +#endif PARANOID + + real_2op_NaN(st1_ptr, FPU_st0_ptr, FPU_st0_ptr); + +} + + +/* ST(1) <- ST(1) * log ST; pop ST */ +static void fyl2x(void) +{ + FPU_REG *st1_ptr = &st(1); + char st1_tag = st1_ptr->tag; + + clear_C1(); + if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + { + if ( FPU_st0_ptr->sign == SIGN_POS ) + { + int saved_control, saved_status; + +#ifdef DENORM_OPERAND + if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + /* We use the general purpose arithmetic, + so we need to save these. */ + saved_status = partial_status; + saved_control = control_word; + control_word = FULL_PRECISION; + + poly_l2(FPU_st0_ptr, FPU_st0_ptr); + + /* Enough of the basic arithmetic is done now */ + control_word = saved_control; + partial_status = saved_status; + + /* Let the multiply set the flags */ + reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); + + pop(); FPU_st0_ptr = &st(0); + } + else + { + /* negative */ + if ( !arith_invalid(st1_ptr) ) + pop(); + return; + } + } + else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) + { + stack_underflow_pop(1); + return; + } + else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) + { + if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + pop(); + return; + } + else if ( (FPU_st0_tag <= TW_Zero) && (st1_tag <= TW_Zero) ) + { + /* one of the args is zero, the other valid, or both zero */ + if ( FPU_st0_tag == TW_Zero ) + { + if ( st1_tag == TW_Zero ) + { + /* Both args zero is invalid */ + if ( !arith_invalid(st1_ptr) ) + pop(); + } +#ifdef PECULIAR_486 + /* This case is not specifically covered in the manual, + but divide-by-zero would seem to be the best response. + However, a real 80486 does it this way... */ + else if ( FPU_st0_ptr->tag == TW_Infinity ) + { + reg_move(&CONST_INF, st1_ptr); + pop(); + } +#endif PECULIAR_486 + else + { + if ( !divide_by_zero(st1_ptr->sign^SIGN_NEG^SIGN_POS, st1_ptr) ) + pop(); + } + return; + } + else + { + /* st(1) contains zero, st(0) valid <> 0 */ + /* Zero is the valid answer */ + char sign = st1_ptr->sign; + + if ( FPU_st0_ptr->sign == SIGN_NEG ) + { + /* log(negative) */ + if ( !arith_invalid(st1_ptr) ) + pop(); + return; + } + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + if ( FPU_st0_ptr->exp < EXP_BIAS ) sign ^= SIGN_NEG^SIGN_POS; + pop(); FPU_st0_ptr = &st(0); + reg_move(&CONST_Z, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + return; + } + } + /* One or both arg must be an infinity */ + else if ( FPU_st0_tag == TW_Infinity ) + { + if ( (FPU_st0_ptr->sign == SIGN_NEG) || (st1_tag == TW_Zero) ) + { + /* log(-infinity) or 0*log(infinity) */ + if ( !arith_invalid(st1_ptr) ) + pop(); + return; + } + else + { + char sign = st1_ptr->sign; + +#ifdef DENORM_OPERAND + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + pop(); FPU_st0_ptr = &st(0); + reg_move(&CONST_INF, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + return; + } + } + /* st(1) must be infinity here */ + else if ( (FPU_st0_tag == TW_Valid) && (FPU_st0_ptr->sign == SIGN_POS) ) + { + if ( FPU_st0_ptr->exp >= EXP_BIAS ) + { + if ( (FPU_st0_ptr->exp == EXP_BIAS) && + (FPU_st0_ptr->sigh == 0x80000000) && + (FPU_st0_ptr->sigl == 0) ) + { + /* st(0) holds 1.0 */ + /* infinity*log(1) */ + if ( !arith_invalid(st1_ptr) ) + pop(); + return; + } + /* st(0) is positive and > 1.0 */ + pop(); + } + else + { + /* st(0) is positive and < 1.0 */ + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + st1_ptr->sign ^= SIGN_NEG; + pop(); + } + return; + } + else + { + /* st(0) must be zero or negative */ + if ( FPU_st0_ptr->tag == TW_Zero ) + { + /* This should be invalid, but a real 80486 is happy with it. */ +#ifndef PECULIAR_486 + if ( !divide_by_zero(st1_ptr->sign, st1_ptr) ) +#endif PECULIAR_486 + { + st1_ptr->sign ^= SIGN_NEG^SIGN_POS; + pop(); + } + } + else + { + /* log(negative) */ + if ( !arith_invalid(st1_ptr) ) + pop(); + } + return; + } +} + + +static void fpatan(void) +{ + FPU_REG *st1_ptr = &st(1); + char st1_tag = st1_ptr->tag; + char st1_sign = st1_ptr->sign, st0_sign = FPU_st0_ptr->sign; + + clear_C1(); + if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + { + int saved_control, saved_status; + FPU_REG sum; + char inverted; + +#ifdef DENORM_OPERAND + if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + /* We use the general purpose arithmetic so we need to save these. */ + saved_status = partial_status; + saved_control = control_word; + control_word = FULL_PRECISION; + + st1_ptr->sign = FPU_st0_ptr->sign = SIGN_POS; + if ( (compare(st1_ptr) & ~COMP_Denormal) == COMP_A_lt_B ) + { + inverted = 1; + reg_div(FPU_st0_ptr, st1_ptr, &sum, FULL_PRECISION); + } + else + { + inverted = 0; + if ( (st0_sign == 0) && + (st1_ptr->exp - FPU_st0_ptr->exp < -64) ) + { + control_word = saved_control; + partial_status = saved_status; + reg_div(st1_ptr, FPU_st0_ptr, st1_ptr, + control_word | PR_64_BITS); + st1_ptr->sign = st1_sign; + pop(); + set_precision_flag_down(); + return; + } + reg_div(st1_ptr, FPU_st0_ptr, &sum, FULL_PRECISION); + } + + poly_atan(&sum); + + if ( inverted ) + { + reg_sub(&CONST_PI2, &sum, &sum, FULL_PRECISION); + } + if ( st0_sign ) + { + reg_sub(&CONST_PI, &sum, &sum, FULL_PRECISION); + } + sum.sign = st1_sign; + + /* All of the basic arithmetic is done now */ + control_word = saved_control; + partial_status = saved_status; + + reg_move(&sum, st1_ptr); + } + else if ( (FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty) ) + { + stack_underflow_pop(1); + return; + } + else if ( (FPU_st0_tag == TW_NaN) || (st1_tag == TW_NaN) ) + { + if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + pop(); + return; + } + else if ( (FPU_st0_tag == TW_Infinity) || (st1_tag == TW_Infinity) ) + { + char sign = st1_ptr->sign; + if ( FPU_st0_tag == TW_Infinity ) + { + if ( st1_tag == TW_Infinity ) + { + if ( FPU_st0_ptr->sign == SIGN_POS ) + { reg_move(&CONST_PI4, st1_ptr); } + else + reg_add(&CONST_PI4, &CONST_PI2, st1_ptr, FULL_PRECISION); + } + else + { +#ifdef DENORM_OPERAND + if ( st1_tag != TW_Zero ) + { + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; + } +#endif DENORM_OPERAND + + if ( FPU_st0_ptr->sign == SIGN_POS ) + { + reg_move(&CONST_Z, st1_ptr); + st1_ptr->sign = sign; /* An 80486 preserves the sign */ + pop(); + return; + } + else + reg_move(&CONST_PI, st1_ptr); + } + } + else + { + /* st(1) is infinity, st(0) not infinity */ +#ifdef DENORM_OPERAND + if ( FPU_st0_tag != TW_Zero ) + { + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; + } +#endif DENORM_OPERAND + + reg_move(&CONST_PI2, st1_ptr); + } + st1_ptr->sign = sign; + } + else if ( st1_tag == TW_Zero ) + { + /* st(0) must be valid or zero */ + char sign = st1_ptr->sign; + +#ifdef DENORM_OPERAND + if ( FPU_st0_tag != TW_Zero ) + { + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; + } +#endif DENORM_OPERAND + + if ( FPU_st0_ptr->sign == SIGN_POS ) + { /* An 80486 preserves the sign */ pop(); return; } + else + reg_move(&CONST_PI, st1_ptr); + st1_ptr->sign = sign; + } + else if ( FPU_st0_tag == TW_Zero ) + { + /* st(1) must be TW_Valid here */ + char sign = st1_ptr->sign; + +#ifdef DENORM_OPERAND + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + reg_move(&CONST_PI2, st1_ptr); + st1_ptr->sign = sign; + } +#ifdef PARANOID + else + EXCEPTION(EX_INTERNAL | 0x125); +#endif PARANOID + + pop(); + set_precision_flag_up(); /* We do not really know if up or down */ +} + + +static void fprem(void) +{ + do_fprem(RC_CHOP); +} + + +static void fprem1(void) +{ + do_fprem(RC_RND); +} + + +static void fyl2xp1(void) +{ + FPU_REG *st1_ptr = &st(1); + char st1_tag = st1_ptr->tag; + + clear_C1(); + if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + { + int saved_control, saved_status; + +#ifdef DENORM_OPERAND + if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + (st1_ptr->exp <= EXP_UNDER)) && denormal_operand() ) + return; +#endif DENORM_OPERAND + + /* We use the general purpose arithmetic so we need to save these. */ + saved_status = partial_status; + saved_control = control_word; + control_word = FULL_PRECISION; + + if ( poly_l2p1(FPU_st0_ptr, FPU_st0_ptr) ) + { +#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ + st1_ptr->sign ^= SIGN_POS^SIGN_NEG; + control_word = saved_control; + partial_status = saved_status; + set_precision_flag_down(); +#else + if ( arith_invalid(st1_ptr) ) /* poly_l2p1() returned invalid */ + return; +#endif PECULIAR_486 + pop(); return; + } + + /* Enough of the basic arithmetic is done now */ + control_word = saved_control; + partial_status = saved_status; + + /* Let the multiply set the flags */ + reg_mul(FPU_st0_ptr, st1_ptr, st1_ptr, FULL_PRECISION); + + pop(); + } + else if ( (FPU_st0_tag == TW_Empty) | (st1_tag == TW_Empty) ) + { + stack_underflow_pop(1); + return; + } + else if ( FPU_st0_tag == TW_Zero ) + { + if ( st1_tag <= TW_Zero ) + { +#ifdef DENORM_OPERAND + if ( (st1_tag == TW_Valid) && (st1_ptr->exp <= EXP_UNDER) && + (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + FPU_st0_ptr->sign ^= st1_ptr->sign; + reg_move(FPU_st0_ptr, st1_ptr); + } + else if ( st1_tag == TW_Infinity ) + { + /* Infinity*log(1) */ + if ( !arith_invalid(st1_ptr) ) + pop(); + return; + } + else if ( st1_tag == TW_NaN ) + { + if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + pop(); + return; + } +#ifdef PARANOID + else + { + EXCEPTION(EX_INTERNAL | 0x116); + return; + } +#endif PARANOID + pop(); return; + } + else if ( FPU_st0_tag == TW_Valid ) + { + if ( st1_tag == TW_Zero ) + { + if ( FPU_st0_ptr->sign == SIGN_NEG ) + { + if ( FPU_st0_ptr->exp >= EXP_BIAS ) + { + /* st(0) holds <= -1.0 */ +#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ + st1_ptr->sign ^= SIGN_POS^SIGN_NEG; +#else + if ( arith_invalid(st1_ptr) ) return; +#endif PECULIAR_486 + pop(); return; + } +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + st1_ptr->sign ^= SIGN_POS^SIGN_NEG; + pop(); return; + } +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + pop(); return; + } + if ( st1_tag == TW_Infinity ) + { + if ( FPU_st0_ptr->sign == SIGN_NEG ) + { + if ( (FPU_st0_ptr->exp >= EXP_BIAS) && + !((FPU_st0_ptr->sigh == 0x80000000) && + (FPU_st0_ptr->sigl == 0)) ) + { + /* st(0) holds < -1.0 */ +#ifdef PECULIAR_486 /* Stupid 80486 doesn't worry about log(negative). */ + st1_ptr->sign ^= SIGN_POS^SIGN_NEG; +#else + if ( arith_invalid(st1_ptr) ) return; +#endif PECULIAR_486 + pop(); return; + } +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + st1_ptr->sign ^= SIGN_POS^SIGN_NEG; + pop(); return; + } +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + pop(); return; + } + if ( st1_tag == TW_NaN ) + { + if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + pop(); + return; + } + } + else if ( FPU_st0_tag == TW_NaN ) + { + if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + pop(); + return; + } + else if ( FPU_st0_tag == TW_Infinity ) + { + if ( st1_tag == TW_NaN ) + { + if ( !real_2op_NaN(FPU_st0_ptr, st1_ptr, st1_ptr) ) + pop(); + return; + } + else if ( FPU_st0_ptr->sign == SIGN_NEG ) + { + int exponent = st1_ptr->exp; +#ifndef PECULIAR_486 + /* This should have higher priority than denormals, but... */ + if ( arith_invalid(st1_ptr) ) /* log(-infinity) */ + return; +#endif PECULIAR_486 +#ifdef DENORM_OPERAND + if ( st1_tag != TW_Zero ) + { + if ( (exponent <= EXP_UNDER) && (denormal_operand()) ) + return; + } +#endif DENORM_OPERAND +#ifdef PECULIAR_486 + /* Denormal operands actually get higher priority */ + if ( arith_invalid(st1_ptr) ) /* log(-infinity) */ + return; +#endif PECULIAR_486 + pop(); + return; + } + else if ( st1_tag == TW_Zero ) + { + /* log(infinity) */ + if ( !arith_invalid(st1_ptr) ) + pop(); + return; + } + + /* st(1) must be valid here. */ + +#ifdef DENORM_OPERAND + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + /* The Manual says that log(Infinity) is invalid, but a real + 80486 sensibly says that it is o.k. */ + { char sign = st1_ptr->sign; + reg_move(&CONST_INF, st1_ptr); + st1_ptr->sign = sign; + } + pop(); + return; + } +#ifdef PARANOID + else + { + EXCEPTION(EX_INTERNAL | 0x117); + } +#endif PARANOID +} + + +static void fscale(void) +{ + FPU_REG *st1_ptr = &st(1); + char st1_tag = st1_ptr->tag; + int old_cw = control_word; + char sign = FPU_st0_ptr->sign; + + clear_C1(); + if ( !((FPU_st0_tag ^ TW_Valid) | (st1_tag ^ TW_Valid)) ) + { + long scale; + FPU_REG tmp; + +#ifdef DENORM_OPERAND + if ( ((FPU_st0_ptr->exp <= EXP_UNDER) || + (st1_ptr->exp <= EXP_UNDER)) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + if ( st1_ptr->exp > EXP_BIAS + 30 ) + { + /* 2^31 is far too large, would require 2^(2^30) or 2^(-2^30) */ + char sign; + + if ( st1_ptr->sign == SIGN_POS ) + { + EXCEPTION(EX_Overflow); + sign = FPU_st0_ptr->sign; + reg_move(&CONST_INF, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + } + else + { + EXCEPTION(EX_Underflow); + sign = FPU_st0_ptr->sign; + reg_move(&CONST_Z, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + } + return; + } + + control_word &= ~CW_RC; + control_word |= RC_CHOP; + reg_move(st1_ptr, &tmp); + round_to_int(&tmp); /* This can never overflow here */ + control_word = old_cw; + scale = st1_ptr->sign ? -tmp.sigl : tmp.sigl; + scale += FPU_st0_ptr->exp; + FPU_st0_ptr->exp = scale; + + /* Use round_reg() to properly detect under/overflow etc */ + round_reg(FPU_st0_ptr, 0, control_word); + + return; + } + else if ( FPU_st0_tag == TW_Valid ) + { + if ( st1_tag == TW_Zero ) + { + +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + return; + } + if ( st1_tag == TW_Infinity ) + { +#ifdef DENORM_OPERAND + if ( (FPU_st0_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + if ( st1_ptr->sign == SIGN_POS ) + { reg_move(&CONST_INF, FPU_st0_ptr); } + else + reg_move(&CONST_Z, FPU_st0_ptr); + FPU_st0_ptr->sign = sign; + return; + } + if ( st1_tag == TW_NaN ) + { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + } + else if ( FPU_st0_tag == TW_Zero ) + { + if ( st1_tag == TW_Valid ) + { + +#ifdef DENORM_OPERAND + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + return; + } + else if ( st1_tag == TW_Zero ) { return; } + else if ( st1_tag == TW_Infinity ) + { + if ( st1_ptr->sign == SIGN_NEG ) + return; + else + { + arith_invalid(FPU_st0_ptr); /* Zero scaled by +Infinity */ + return; + } + } + else if ( st1_tag == TW_NaN ) + { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + } + else if ( FPU_st0_tag == TW_Infinity ) + { + if ( st1_tag == TW_Valid ) + { + +#ifdef DENORM_OPERAND + if ( (st1_ptr->exp <= EXP_UNDER) && (denormal_operand()) ) + return; +#endif DENORM_OPERAND + + return; + } + if ( ((st1_tag == TW_Infinity) && (st1_ptr->sign == SIGN_POS)) + || (st1_tag == TW_Zero) ) + return; + else if ( st1_tag == TW_Infinity ) + { + arith_invalid(FPU_st0_ptr); /* Infinity scaled by -Infinity */ + return; + } + else if ( st1_tag == TW_NaN ) + { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + } + else if ( FPU_st0_tag == TW_NaN ) + { + if ( st1_tag != TW_Empty ) + { real_2op_NaN(FPU_st0_ptr, st1_ptr, FPU_st0_ptr); return; } + } + +#ifdef PARANOID + if ( !((FPU_st0_tag == TW_Empty) || (st1_tag == TW_Empty)) ) + { + EXCEPTION(EX_INTERNAL | 0x115); + return; + } +#endif + + /* At least one of st(0), st(1) must be empty */ + stack_underflow(); + +} + + +/*---------------------------------------------------------------------------*/ + +static FUNC const trig_table_a[] = { + f2xm1, fyl2x, fptan, fpatan, fxtract, fprem1, fdecstp, fincstp +}; + +void trig_a(void) +{ + (trig_table_a[FPU_rm])(); +} + + +static FUNC const trig_table_b[] = + { + fprem, fyl2xp1, fsqrt_, fsincos, frndint_, fscale, fsin, fcos + }; + +void trig_b(void) +{ + (trig_table_b[FPU_rm])(); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/get_address.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/get_address.c new file mode 100644 index 000000000..f2b00b5b1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/get_address.c @@ -0,0 +1,197 @@ +/*---------------------------------------------------------------------------+ + | get_address.c | + | | + | Get the effective address from an FPU instruction. | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Note: | + | The file contains code which accesses user memory. | + | Emulator static data may change when user memory is accessed, due to | + | other processes using the emulator while swapping is in progress. | + +---------------------------------------------------------------------------*/ + + +#include + +#include + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" + +static int reg_offset[] = { + offsetof(struct info,___eax), + offsetof(struct info,___ecx), + offsetof(struct info,___edx), + offsetof(struct info,___ebx), + offsetof(struct info,___esp), + offsetof(struct info,___ebp), + offsetof(struct info,___esi), + offsetof(struct info,___edi) +}; + +#define REG_(x) (*(long *)(reg_offset[(x)]+(char *) FPU_info)) + + +/* Decode the SIB byte. This function assumes mod != 0 */ +static void *sib(int mod) +{ + unsigned char ss,index,base; + long offset; + + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + base = get_fs_byte((char *) FPU_EIP); /* The SIB byte */ + RE_ENTRANT_CHECK_ON; + FPU_EIP++; + ss = base >> 6; + index = (base >> 3) & 7; + base &= 7; + + if ((mod == 0) && (base == 5)) + offset = 0; /* No base register */ + else + offset = REG_(base); + + if (index == 4) + { + /* No index register */ + /* A non-zero ss is illegal */ + if ( ss ) + EXCEPTION(EX_Invalid); + } + else + { + offset += (REG_(index)) << ss; + } + + if (mod == 1) + { + /* 8 bit signed displacement */ + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + offset += (signed char) get_fs_byte((char *) FPU_EIP); + RE_ENTRANT_CHECK_ON; + FPU_EIP++; + } + else if (mod == 2 || base == 5) /* The second condition also has mod==0 */ + { + /* 32 bit displacment */ + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(4); + offset += (signed) get_fs_long((unsigned long *) FPU_EIP); + RE_ENTRANT_CHECK_ON; + FPU_EIP += 4; + } + + return (void *) offset; +} + + +/* + MOD R/M byte: MOD == 3 has a special use for the FPU + SIB byte used iff R/M = 100b + + 7 6 5 4 3 2 1 0 + ..... ......... ......... + MOD OPCODE(2) R/M + + + SIB byte + + 7 6 5 4 3 2 1 0 + ..... ......... ......... + SS INDEX BASE + +*/ + +void get_address(unsigned char FPU_modrm, overrides override) +{ + unsigned char mod; + long *cpu_reg_ptr; + int offset = 0; /* Initialized just to stop compiler warnings. */ + +#ifndef PECULIAR_486 + /* This is a reasonable place to do this */ + FPU_data_selector = FPU_DS; +#endif PECULIAR_486 + + mod = (FPU_modrm >> 6) & 3; + + if (FPU_rm == 4 && mod != 3) + { + FPU_data_address = sib(mod); + return; + } + + cpu_reg_ptr = & REG_(FPU_rm); + switch (mod) + { + case 0: + if (FPU_rm == 5) + { + /* Special case: disp16 or disp32 */ + RE_ENTRANT_CHECK_OFF; + if ( override.address_size == ADDR_SIZE_PREFIX ) + { + FPU_code_verify_area(2); + offset = get_fs_word((unsigned short *) FPU_EIP); + FPU_EIP += 2; + } + else + { + FPU_code_verify_area(4); + offset = get_fs_long((unsigned long *) FPU_EIP); + FPU_EIP += 4; + } + RE_ENTRANT_CHECK_ON; + FPU_data_address = (void *) offset; + return; + } + else + { + FPU_data_address = (void *)*cpu_reg_ptr; /* Just return the contents + of the cpu register */ + return; + } + case 1: + /* 8 bit signed displacement */ + RE_ENTRANT_CHECK_OFF; + FPU_code_verify_area(1); + offset = (signed char) get_fs_byte((char *) FPU_EIP); + RE_ENTRANT_CHECK_ON; + FPU_EIP++; + break; + case 2: + /* 16 or 32 bit displacement */ + RE_ENTRANT_CHECK_OFF; + if ( override.address_size == ADDR_SIZE_PREFIX ) + { + FPU_code_verify_area(2); + offset = (signed) get_fs_word((unsigned short *) FPU_EIP); + FPU_EIP += 2; + } + else + { + FPU_code_verify_area(4); + offset = (signed) get_fs_long((unsigned long *) FPU_EIP); + FPU_EIP += 4; + } + RE_ENTRANT_CHECK_ON; + break; + case 3: + /* Not legal for the FPU */ + EXCEPTION(EX_Invalid); + } + + FPU_data_address = offset + (char *)*cpu_reg_ptr; + if ( override.address_size == ADDR_SIZE_PREFIX ) + FPU_data_address = (void *)((long)FPU_data_address & 0xffff); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/load_store.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/load_store.c new file mode 100644 index 000000000..5b5737b61 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/load_store.c @@ -0,0 +1,237 @@ +/*---------------------------------------------------------------------------+ + | load_store.c | + | | + | This file contains most of the code to interpret the FPU instructions | + | which load and store from user memory. | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Note: | + | The file contains code which accesses user memory. | + | Emulator static data may change when user memory is accessed, due to | + | other processes using the emulator while swapping is in progress. | + +---------------------------------------------------------------------------*/ + +#include + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" +#include "status_w.h" +#include "control_w.h" + + +#define _NONE_ 0 /* FPU_st0_ptr etc not needed */ +#define _REG0_ 1 /* Will be storing st(0) */ +#define _PUSH_ 3 /* Need to check for space to push onto stack */ +#define _null_ 4 /* Function illegal or not implemented */ + +#define pop_0() { pop_ptr->tag = TW_Empty; top++; } + + +static unsigned char const type_table[32] = { + _PUSH_, _PUSH_, _PUSH_, _PUSH_, + _null_, _null_, _null_, _null_, + _REG0_, _REG0_, _REG0_, _REG0_, + _REG0_, _REG0_, _REG0_, _REG0_, + _NONE_, _null_, _NONE_, _PUSH_, + _NONE_, _PUSH_, _null_, _PUSH_, + _NONE_, _null_, _NONE_, _REG0_, + _NONE_, _REG0_, _NONE_, _REG0_ + }; + +void load_store_instr(char type, overrides override) +{ + FPU_REG *pop_ptr; /* We need a version of FPU_st0_ptr which won't + change if the emulator is re-entered. */ + + pop_ptr = NULL; /* Initialized just to stop compiler warnings. */ + switch ( type_table[(int) (unsigned) type] ) + { + case _NONE_: + break; + case _REG0_: + pop_ptr = &st(0); /* Some of these instructions pop after + storing */ + + FPU_st0_ptr = pop_ptr; /* Set the global variables. */ + FPU_st0_tag = FPU_st0_ptr->tag; + break; + case _PUSH_: + { + pop_ptr = &st(-1); + if ( pop_ptr->tag != TW_Empty ) + { stack_overflow(); return; } + top--; + } + break; + case _null_: + FPU_illegal(); + return; +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL); + return; +#endif PARANOID + } + +switch ( type ) + { + case 000: /* fld m32real */ + clear_C1(); + reg_load_single(override); + if ( (FPU_loaded_data.tag == TW_NaN) && + real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) + { + top++; + break; + } + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 001: /* fild m32int */ + clear_C1(); + reg_load_int32(override); + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 002: /* fld m64real */ + clear_C1(); + reg_load_double(override); + if ( (FPU_loaded_data.tag == TW_NaN) && + real_2op_NaN(&FPU_loaded_data, &FPU_loaded_data, &FPU_loaded_data) ) + { + top++; + break; + } + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 003: /* fild m16int */ + clear_C1(); + reg_load_int16(override); + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 010: /* fst m32real */ + clear_C1(); + reg_store_single(override); + break; + case 011: /* fist m32int */ + clear_C1(); + reg_store_int32(override); + break; + case 012: /* fst m64real */ + clear_C1(); + reg_store_double(override); + break; + case 013: /* fist m16int */ + clear_C1(); + reg_store_int16(override); + break; + case 014: /* fstp m32real */ + clear_C1(); + if ( reg_store_single(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 015: /* fistp m32int */ + clear_C1(); + if ( reg_store_int32(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 016: /* fstp m64real */ + clear_C1(); + if ( reg_store_double(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 017: /* fistp m16int */ + clear_C1(); + if ( reg_store_int16(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 020: /* fldenv m14/28byte */ + fldenv(); + break; + case 022: /* frstor m94/108byte */ + frstor(); + break; + case 023: /* fbld m80dec */ + clear_C1(); + reg_load_bcd(override); + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 024: /* fldcw */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, FPU_data_address, 2); + control_word = get_fs_word((unsigned short *) FPU_data_address); + RE_ENTRANT_CHECK_ON; + if ( partial_status & ~control_word & CW_Exceptions ) + partial_status |= (SW_Summary | SW_Backward); + else + partial_status &= ~(SW_Summary | SW_Backward); +#ifdef PECULIAR_486 + control_word |= 0x40; /* An 80486 appears to always set this bit */ +#endif PECULIAR_486 + NO_NET_DATA_EFFECT; + NO_NET_INSTR_EFFECT; + break; + case 025: /* fld m80real */ + clear_C1(); + reg_load_extended(override); + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 027: /* fild m64int */ + clear_C1(); + reg_load_int64(override); + reg_move(&FPU_loaded_data, pop_ptr); + break; + case 030: /* fstenv m14/28byte */ + fstenv(); + NO_NET_DATA_EFFECT; + break; + case 032: /* fsave */ + fsave(); + NO_NET_DATA_EFFECT; + break; + case 033: /* fbstp m80dec */ + clear_C1(); + if ( reg_store_bcd(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 034: /* fstcw m16int */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,FPU_data_address,2); + put_fs_word(control_word, (short *) FPU_data_address); + RE_ENTRANT_CHECK_ON; + NO_NET_DATA_EFFECT; + NO_NET_INSTR_EFFECT; + break; + case 035: /* fstp m80real */ + clear_C1(); + if ( reg_store_extended(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + case 036: /* fstsw m2byte */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,FPU_data_address,2); + put_fs_word(status_word(),(short *) FPU_data_address); + RE_ENTRANT_CHECK_ON; + NO_NET_DATA_EFFECT; + NO_NET_INSTR_EFFECT; + break; + case 037: /* fistp m64int */ + clear_C1(); + if ( reg_store_int64(override) ) + pop_0(); /* pop only if the number was actually stored + (see the 80486 manual p16-28) */ + break; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_2xm1.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_2xm1.c new file mode 100644 index 000000000..4844aa722 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_2xm1.c @@ -0,0 +1,85 @@ +/*---------------------------------------------------------------------------+ + | poly_2xm1.c | + | | + | Function to compute 2^x-1 by a polynomial approximation. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" + + + +#define HIPOWER 13 +static unsigned short const lterms[HIPOWER][4] = + { + { 0x79b5, 0xd1cf, 0x17f7, 0xb172 }, + { 0x1b56, 0x058b, 0x7bff, 0x3d7f }, + { 0x8bb0, 0x8250, 0x846b, 0x0e35 }, + { 0xbc65, 0xf747, 0x556d, 0x0276 }, + { 0x17cb, 0x9e39, 0x61ff, 0x0057 }, + { 0xe018, 0x9776, 0x1848, 0x000a }, + { 0x66f2, 0xff30, 0xffe5, 0x0000 }, + { 0x682f, 0xffb6, 0x162b, 0x0000 }, + { 0xb7ca, 0x2956, 0x01b5, 0x0000 }, + { 0xcd3e, 0x4817, 0x001e, 0x0000 }, + { 0xb7e2, 0xecbe, 0x0001, 0x0000 }, + { 0x0ed5, 0x1a27, 0x0000, 0x0000 }, + { 0x101d, 0x0222, 0x0000, 0x0000 }, + }; + + +/*--- poly_2xm1() -----------------------------------------------------------+ + | Requires a positive argument which is TW_Valid and < 1. | + +---------------------------------------------------------------------------*/ +int poly_2xm1(FPU_REG const *arg, FPU_REG *result) +{ + short exponent; + long long Xll; + FPU_REG accum; + + + exponent = arg->exp - EXP_BIAS; + +#ifdef PARANOID + if ( (arg->sign != SIGN_POS) /* Can't hack a number < 0.0 */ + || (exponent >= 0) /* or a |number| >= 1.0 */ + || (arg->tag != TW_Valid) ) + { + /* Number negative, too large, or not Valid. */ + EXCEPTION(EX_INTERNAL|0x127); + return 1; + } +#endif PARANOID + + *(unsigned *)&Xll = arg->sigl; + *(((unsigned *)&Xll)+1) = arg->sigh; + if ( exponent < -1 ) + { + /* Shift the argument right by the required places. */ + if ( shrx(&Xll, -1-exponent) >= 0x80000000U ) + Xll++; /* round up */ + } + + *(short *)&(accum.sign) = 0; /* Will be a valid positive nr with expon = 0 */ + accum.exp = 0; + + /* Do the basic fixed point polynomial evaluation */ + polynomial((unsigned *)&accum.sigl, (unsigned *)&Xll, lterms, HIPOWER-1); + + /* Convert to 64 bit signed-compatible */ + accum.exp += EXP_BIAS - 1; + + reg_move(&accum, result); + + normalize(result); + + return 0; + +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_atan.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_atan.c new file mode 100644 index 000000000..ea606f976 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_atan.c @@ -0,0 +1,204 @@ +/*---------------------------------------------------------------------------+ + | p_atan.c | + | | + | Compute the tan of a FPU_REG, using a polynomial approximation. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "control_w.h" + + +#define HIPOWERon 6 /* odd poly, negative terms */ +static unsigned const oddnegterms[HIPOWERon][2] = +{ + { 0x00000000, 0x00000000 }, /* for + 1.0 */ + { 0x763b6f3d, 0x1adc4428 }, + { 0x20f0630b, 0x0502909d }, + { 0x4e825578, 0x0198ce38 }, + { 0x22b7cb87, 0x008da6e3 }, + { 0x9b30ca03, 0x00239c79 } +} ; + +#define HIPOWERop 6 /* odd poly, positive terms */ +static unsigned const oddplterms[HIPOWERop][2] = +{ + { 0xa6f67cb8, 0x94d910bd }, + { 0xa02ffab4, 0x0a43cb45 }, + { 0x04265e6b, 0x02bf5655 }, + { 0x0a728914, 0x00f280f7 }, + { 0x6d640e01, 0x004d6556 }, + { 0xf1dd2dbf, 0x000a530a } +}; + +static unsigned long long const denomterm = 0xea2e6612fc4bd208LL; + + +/*--- poly_atan() -----------------------------------------------------------+ + | | + +---------------------------------------------------------------------------*/ +void poly_atan(FPU_REG *arg) +{ + char recursions = 0; + short exponent; + FPU_REG odd_poly, even_poly, pos_poly, neg_poly, ratio; + FPU_REG argSq; + unsigned long long arg_signif, argSqSq; + + +#ifdef PARANOID + if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */ + { arith_invalid(arg); return; } /* Need a positive number */ +#endif PARANOID + + exponent = arg->exp - EXP_BIAS; + + if ( arg->tag == TW_Zero ) + { + /* Return 0.0 */ + reg_move(&CONST_Z, arg); + return; + } + + if ( exponent >= -2 ) + { + /* argument is in the range [0.25 .. 1.0] */ + if ( exponent >= 0 ) + { +#ifdef PARANOID + if ( (exponent == 0) && + (arg->sigl == 0) && (arg->sigh == 0x80000000) ) +#endif PARANOID + { + reg_move(&CONST_PI4, arg); + return; + } +#ifdef PARANOID + EXCEPTION(EX_INTERNAL|0x104); /* There must be a logic error */ + return; +#endif PARANOID + } + + /* If the argument is greater than sqrt(2)-1 (=0.414213562...) */ + /* convert the argument by an identity for atan */ + if ( (exponent >= -1) || (arg->sigh > 0xd413ccd0) ) + { + FPU_REG numerator, denom; + + recursions++; + + arg_signif = significand(arg); + if ( exponent < -1 ) + { + if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U ) + arg_signif++; /* round up */ + } + significand(&numerator) = -arg_signif; + numerator.exp = EXP_BIAS - 1; + normalize(&numerator); /* 1 - arg */ + + arg_signif = significand(arg); + if ( shrx(&arg_signif, -exponent) >= 0x80000000U ) + arg_signif++; /* round up */ + significand(&denom) = arg_signif; + denom.sigh |= 0x80000000; /* 1 + arg */ + + arg->exp = numerator.exp; + reg_u_div(&numerator, &denom, arg, FULL_PRECISION); + + exponent = arg->exp - EXP_BIAS; + } + } + + arg_signif = significand(arg); + +#ifdef PARANOID + /* This must always be true */ + if ( exponent >= -1 ) + { + EXCEPTION(EX_INTERNAL|0x120); /* There must be a logic error */ + } +#endif PARANOID + + /* shift the argument right by the required places */ + if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U ) + arg_signif++; /* round up */ + + /* Now have arg_signif with binary point at the left + .1xxxxxxxx */ + mul64(&arg_signif, &arg_signif, &significand(&argSq)); + mul64(&significand(&argSq), &significand(&argSq), &argSqSq); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(pos_poly.sign) = 0; + pos_poly.exp = EXP_BIAS; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&pos_poly.sigl, (unsigned *)&argSqSq, + (unsigned short (*)[4])oddplterms, HIPOWERop-1); + mul64(&significand(&argSq), &significand(&pos_poly), + &significand(&pos_poly)); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(neg_poly.sign) = 0; + neg_poly.exp = EXP_BIAS; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, + (unsigned short (*)[4])oddnegterms, HIPOWERon-1); + + /* Subtract the mantissas */ + significand(&pos_poly) -= significand(&neg_poly); + + reg_move(&pos_poly, &odd_poly); + poly_add_1(&odd_poly); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(even_poly.sign) = 0; + + mul64(&significand(&argSq), &denomterm, &significand(&even_poly)); + + poly_add_1(&even_poly); + + reg_div(&odd_poly, &even_poly, &ratio, FULL_PRECISION); + + reg_u_mul(&ratio, arg, arg, FULL_PRECISION); + + if ( recursions ) + reg_sub(&CONST_PI4, arg, arg, FULL_PRECISION); + +} + + +/* The argument to this function must be polynomial() compatible, + i.e. have an exponent (not checked) of EXP_BIAS-1 but need not + be normalized. + This function adds 1.0 to the (assumed positive) argument. */ +void poly_add_1(FPU_REG *src) +{ +/* Rounding in a consistent direction produces better results + for the use of this function in poly_atan. Simple truncation + is used here instead of round-to-nearest. */ + +#ifdef OBSOLETE +char round = (src->sigl & 3) == 3; +#endif OBSOLETE + +shrx(&src->sigl, 1); + +#ifdef OBSOLETE +if ( round ) significand(src)++; /* Round to even */ +#endif OBSOLETE + +src->sigh |= 0x80000000; + +src->exp = EXP_BIAS; + +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_div.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_div.S new file mode 100644 index 000000000..a67293316 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_div.S @@ -0,0 +1,97 @@ + .file "poly_div.S" +/*---------------------------------------------------------------------------+ + | poly_div.S | + | | + | A set of functions to divide 64 bit integers by fixed numbers. | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void poly_div2(unsigned long long *x) | + | void poly_div4(unsigned long long *x) | + | void poly_div16(unsigned long long *x) | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_asm.h" + +.text + +/*---------------------------------------------------------------------------*/ + .align 2,144 +.globl _poly_div2 +_poly_div2: + pushl %ebp + movl %esp,%ebp + + movl PARAM1,%ecx + movw (%ecx),%ax + + shrl $1,4(%ecx) + rcrl $1,(%ecx) + + testw $1,%ax + je poly_div2_exit + + addl $1,(%ecx) + adcl $0,4(%ecx) +poly_div2_exit: + + leave + ret +/*---------------------------------------------------------------------------*/ + .align 2,144 +.globl _poly_div4 +_poly_div4: + pushl %ebp + movl %esp,%ebp + + movl PARAM1,%ecx + movw (%ecx),%ax + + movl 4(%ecx),%edx + shll $30,%edx + + shrl $2,4(%ecx) + shrl $2,(%ecx) + + orl %edx,(%ecx) + + testw $2,%ax + je poly_div4_exit + + addl $1,(%ecx) + adcl $0,4(%ecx) +poly_div4_exit: + + leave + ret +/*---------------------------------------------------------------------------*/ + .align 2,144 +.globl _poly_div16 +_poly_div16: + pushl %ebp + movl %esp,%ebp + + movl PARAM1,%ecx + movw (%ecx),%ax + + movl 4(%ecx),%edx + shll $28,%edx + + shrl $4,4(%ecx) + shrl $4,(%ecx) + + orl %edx,(%ecx) + + testw $8,%ax + je poly_div16_exit + + addl $1,(%ecx) + adcl $0,4(%ecx) +poly_div16_exit: + + leave + ret +/*---------------------------------------------------------------------------*/ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_l2.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_l2.c new file mode 100644 index 000000000..6d36fefb2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_l2.c @@ -0,0 +1,289 @@ +/*---------------------------------------------------------------------------+ + | poly_l2.c | + | | + | Compute the base 2 log of a FPU_REG, using a polynomial approximation. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "control_w.h" + + + +#define HIPOWER 9 +static unsigned short const lterms[HIPOWER][4] = + { + /* Ideal computation with these coeffs gives about + 64.6 bit rel accuracy. */ + { 0xe177, 0xb82f, 0x7652, 0x7154 }, + { 0xee0f, 0xe80f, 0x2770, 0x7b1c }, + { 0x0fc0, 0xbe87, 0xb143, 0x49dd }, + { 0x78b9, 0xdadd, 0xec54, 0x34c2 }, + { 0x003a, 0x5de9, 0x628b, 0x2909 }, + { 0x5588, 0xed16, 0x4abf, 0x2193 }, + { 0xb461, 0x85f7, 0x347a, 0x1c6a }, + { 0x0975, 0x87b3, 0xd5bf, 0x1876 }, + { 0xe85c, 0xcec9, 0x84e7, 0x187d } + }; + + + + +/*--- poly_l2() -------------------------------------------------------------+ + | Base 2 logarithm by a polynomial approximation. | + +---------------------------------------------------------------------------*/ +void poly_l2(FPU_REG const *arg, FPU_REG *result) +{ + short exponent; + char zero; /* flag for an Xx == 0 */ + unsigned short bits, shift; + unsigned long long Xsq; + FPU_REG accum, denom, num, Xx; + + + exponent = arg->exp - EXP_BIAS; + + accum.tag = TW_Valid; /* set the tags to Valid */ + + if ( arg->sigh > (unsigned)0xb504f334 ) + { + /* This is good enough for the computation of the polynomial + sum, but actually results in a loss of precision for + the computation of Xx. This will matter only if exponent + becomes zero. */ + exponent++; + accum.sign = 1; /* sign to negative */ + num.exp = EXP_BIAS; /* needed to prevent errors in div routine */ + reg_u_div(&CONST_1, arg, &num, FULL_PRECISION); + } + else + { + accum.sign = 0; /* set the sign to positive */ + num.sigl = arg->sigl; /* copy the mantissa */ + num.sigh = arg->sigh; + } + + + /* shift num left, lose the ms bit */ + num.sigh <<= 1; + if ( num.sigl & 0x80000000 ) num.sigh |= 1; + num.sigl <<= 1; + + denom.sigl = num.sigl; + denom.sigh = num.sigh; + poly_div4(&significand(&denom)); + denom.sigh += 0x80000000; /* set the msb */ + Xx.exp = EXP_BIAS; /* needed to prevent errors in div routine */ + reg_u_div(&num, &denom, &Xx, FULL_PRECISION); + + zero = !(Xx.sigh | Xx.sigl); + + mul64(&significand(&Xx), &significand(&Xx), &Xsq); + poly_div16(&Xsq); + + accum.exp = -1; /* exponent of accum */ + + /* Do the basic fixed point polynomial evaluation */ + polynomial((unsigned *)&accum.sigl, (unsigned *)&Xsq, lterms, HIPOWER-1); + + if ( !exponent ) + { + /* If the exponent is zero, then we would lose precision by + sticking to fixed point computation here */ + /* We need to re-compute Xx because of loss of precision. */ + FPU_REG lXx; + char sign; + + sign = accum.sign; + accum.sign = 0; + + /* make accum compatible and normalize */ + accum.exp = EXP_BIAS + accum.exp; + normalize(&accum); + + if ( zero ) + { + reg_move(&CONST_Z, result); + } + else + { + /* we need to re-compute lXx to better accuracy */ + num.tag = TW_Valid; /* set the tags to Vaild */ + num.sign = 0; /* set the sign to positive */ + num.exp = EXP_BIAS - 1; + if ( sign ) + { + /* The argument is of the form 1-x */ + /* Use 1-1/(1-x) = x/(1-x) */ + significand(&num) = - significand(arg); + normalize(&num); + reg_div(&num, arg, &num, FULL_PRECISION); + } + else + { + normalize(&num); + } + + denom.tag = TW_Valid; /* set the tags to Valid */ + denom.sign = SIGN_POS; /* set the sign to positive */ + denom.exp = EXP_BIAS; + + reg_div(&num, &denom, &lXx, FULL_PRECISION); + + reg_u_mul(&lXx, &accum, &accum, FULL_PRECISION); + + reg_u_add(&lXx, &accum, result, FULL_PRECISION); + + normalize(result); + } + + result->sign = sign; + return; + } + + mul64(&significand(&accum), + &significand(&Xx), &significand(&accum)); + + significand(&accum) += significand(&Xx); + + if ( Xx.sigh > accum.sigh ) + { + /* There was an overflow */ + + poly_div2(&significand(&accum)); + accum.sigh |= 0x80000000; + accum.exp++; + } + + /* When we add the exponent to the accum result later, we will + require that their signs are the same. Here we ensure that + this is so. */ + if ( exponent && ((exponent < 0) ^ (accum.sign)) ) + { + /* signs are different */ + + accum.sign = !accum.sign; + + /* An exceptional case is when accum is zero */ + if ( accum.sigl | accum.sigh ) + { + /* find 1-accum */ + /* Shift to get exponent == 0 */ + if ( accum.exp < 0 ) + { + poly_div2(&significand(&accum)); + accum.exp++; + } + /* Just negate, but throw away the sign */ + significand(&accum) = - significand(&accum); + if ( exponent < 0 ) + exponent++; + else + exponent--; + } + } + + shift = exponent >= 0 ? exponent : -exponent ; + bits = 0; + if ( shift ) + { + if ( accum.exp ) + { + accum.exp++; + poly_div2(&significand(&accum)); + } + while ( shift ) + { + poly_div2(&significand(&accum)); + if ( shift & 1) + accum.sigh |= 0x80000000; + shift >>= 1; + bits++; + } + } + + /* Convert to 64 bit signed-compatible */ + accum.exp += bits + EXP_BIAS - 1; + + reg_move(&accum, result); + normalize(result); + + return; +} + + +/*--- poly_l2p1() -----------------------------------------------------------+ + | Base 2 logarithm by a polynomial approximation. | + | log2(x+1) | + +---------------------------------------------------------------------------*/ +int poly_l2p1(FPU_REG const *arg, FPU_REG *result) +{ + char sign = 0; + unsigned long long Xsq; + FPU_REG arg_pl1, denom, accum, local_arg, poly_arg; + + + sign = arg->sign; + + reg_add(arg, &CONST_1, &arg_pl1, FULL_PRECISION); + + if ( (arg_pl1.sign) | (arg_pl1.tag) ) + { /* We need a valid positive number! */ + return 1; + } + + reg_add(&CONST_1, &arg_pl1, &denom, FULL_PRECISION); + reg_div(arg, &denom, &local_arg, FULL_PRECISION); + local_arg.sign = 0; /* Make the sign positive */ + + /* Now we need to check that |local_arg| is less than + 3-2*sqrt(2) = 0.17157.. = .0xafb0ccc0 * 2^-2 */ + + if ( local_arg.exp >= EXP_BIAS - 3 ) + { + if ( (local_arg.exp > EXP_BIAS - 3) || + (local_arg.sigh > (unsigned)0xafb0ccc0) ) + { + /* The argument is large */ + poly_l2(&arg_pl1, result); return 0; + } + } + + /* Make a copy of local_arg */ + reg_move(&local_arg, &poly_arg); + + /* Get poly_arg bits aligned as required */ + shrx((unsigned *)&(poly_arg.sigl), -(poly_arg.exp - EXP_BIAS + 3)); + + mul64(&significand(&poly_arg), &significand(&poly_arg), &Xsq); + poly_div16(&Xsq); + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&(accum.sigl), (unsigned *)&Xsq, lterms, HIPOWER-1); + + accum.tag = TW_Valid; /* set the tags to Valid */ + accum.sign = SIGN_POS; /* and make accum positive */ + + /* make accum compatible and normalize */ + accum.exp = EXP_BIAS - 1; + normalize(&accum); + + reg_u_mul(&local_arg, &accum, &accum, FULL_PRECISION); + + reg_u_add(&local_arg, &accum, result, FULL_PRECISION); + + /* Multiply the result by 2 */ + result->exp++; + + result->sign = sign; + + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_mul64.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_mul64.S new file mode 100644 index 000000000..d62e24ddb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_mul64.S @@ -0,0 +1,72 @@ +/*---------------------------------------------------------------------------+ + | poly_mul64.S | + | | + | Multiply two 64 bit integers. | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void mul64(long long *a, long long *b, long long *result) | + | | + +---------------------------------------------------------------------------*/ + + +#include "fpu_asm.h" + +.text + .align 2,144 +.globl _mul64 +_mul64: + pushl %ebp + movl %esp,%ebp + subl $16,%esp + pushl %esi + pushl %ebx + + movl PARAM1,%esi + movl PARAM2,%ecx + movl PARAM3,%ebx + + xor %eax,%eax + movl %eax,-4(%ebp) + movl %eax,-8(%ebp) + + movl (%esi),%eax + mull (%ecx) + movl %eax,-16(%ebp) /* Not used */ + movl %edx,-12(%ebp) + + movl (%esi),%eax + mull 4(%ecx) + addl %eax,-12(%ebp) + adcl %edx,-8(%ebp) + adcl $0,-4(%ebp) + + movl 4(%esi),%eax + mull (%ecx) + addl %eax,-12(%ebp) + adcl %edx,-8(%ebp) + adcl $0,-4(%ebp) + + movl 4(%esi),%eax + mull 4(%ecx) + addl %eax,-8(%ebp) + adcl %edx,-4(%ebp) + + testb $128,-9(%ebp) + je L_no_round + + addl $1,-8(%ebp) + adcl $0,-4(%ebp) + +L_no_round: + movl -8(%ebp),%esi + movl %esi,(%ebx) + movl -4(%ebp),%esi + movl %esi,4(%ebx) + + popl %ebx + popl %esi + leave + ret diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_sin.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_sin.c new file mode 100644 index 000000000..aa43448a1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_sin.c @@ -0,0 +1,150 @@ +/*---------------------------------------------------------------------------+ + | poly_sin.c | + | | + | Computation of an approximation of the sin function by a polynomial | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "control_w.h" + + +#define HIPOWER 5 +static unsigned short const lterms[HIPOWER][4] = + { + { 0x846a, 0x42d1, 0xb544, 0x921f}, + { 0xe110, 0x75aa, 0xbc67, 0x1466}, + { 0x503d, 0xa43f, 0x83c1, 0x000a}, + { 0x8f9d, 0x7a19, 0x00f4, 0x0000}, + { 0xda03, 0x06aa, 0x0000, 0x0000}, + }; + +static unsigned short const negterms[HIPOWER][4] = + { + { 0x95ed, 0x2df2, 0xe731, 0xa55d}, + { 0xd159, 0xe62b, 0xd2cc, 0x0132}, + { 0x6342, 0xe9fb, 0x3c60, 0x0000}, + { 0x6256, 0xdf5a, 0x0002, 0x0000}, + { 0xf279, 0x000b, 0x0000, 0x0000}, + }; + + +/*--- poly_sine() -----------------------------------------------------------+ + | | + +---------------------------------------------------------------------------*/ +void poly_sine(FPU_REG const *arg, FPU_REG *result) +{ + short exponent; + FPU_REG fixed_arg, arg_sqrd, arg_to_4, accum, negaccum; + + + exponent = arg->exp - EXP_BIAS; + + if ( arg->tag == TW_Zero ) + { + /* Return 0.0 */ + reg_move(&CONST_Z, result); + return; + } + +#ifdef PARANOID + if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */ + { + EXCEPTION(EX_Invalid); + reg_move(&CONST_QNaN, result); + return; + } + + if ( exponent >= 0 ) /* Can't hack a number > 1.0 */ + { + if ( (exponent == 0) && (arg->sigl == 0) && (arg->sigh == 0x80000000) ) + { + reg_move(&CONST_1, result); + return; + } + EXCEPTION(EX_Invalid); + reg_move(&CONST_QNaN, result); + return; + } +#endif PARANOID + + fixed_arg.sigl = arg->sigl; + fixed_arg.sigh = arg->sigh; + if ( exponent < -1 ) + { + /* shift the argument right by the required places */ + if ( shrx(&(fixed_arg.sigl), -1-exponent) >= 0x80000000U ) + significand(&fixed_arg)++; /* round up */ + } + + mul64(&significand(&fixed_arg), &significand(&fixed_arg), + &significand(&arg_sqrd)); + mul64(&significand(&arg_sqrd), &significand(&arg_sqrd), + &significand(&arg_to_4)); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(accum.sign) = 0; + accum.exp = 0; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&(accum.sigl), &(arg_to_4.sigl), lterms, HIPOWER-1); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(negaccum.sign) = 0; + negaccum.exp = 0; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&(negaccum.sigl), &(arg_to_4.sigl), negterms, HIPOWER-1); + mul64(&significand(&arg_sqrd), &significand(&negaccum), + &significand(&negaccum)); + + /* Subtract the mantissas */ + significand(&accum) -= significand(&negaccum); + + /* Convert to 64 bit signed-compatible */ + accum.exp = EXP_BIAS - 1 + accum.exp; + + reg_move(&accum, result); + + normalize(result); + + reg_mul(result, arg, result, FULL_PRECISION); + reg_u_add(result, arg, result, FULL_PRECISION); + + if ( result->exp >= EXP_BIAS ) + { + /* A small overflow may be possible... but an illegal result. */ + if ( (result->exp > EXP_BIAS) /* Larger or equal 2.0 */ + || (result->sigl > 1) /* Larger than 1.0+msb */ + || (result->sigh != 0x80000000) /* Much > 1.0 */ + ) + { +#ifdef DEBUGGING + RE_ENTRANT_CHECK_OFF; + printk("\nEXP=%d, MS=%08x, LS=%08x\n", result->exp, + result->sigh, result->sigl); + RE_ENTRANT_CHECK_ON; +#endif DEBUGGING + EXCEPTION(EX_INTERNAL|0x103); + } + +#ifdef DEBUGGING + RE_ENTRANT_CHECK_OFF; + printk("\n***CORRECTING ILLEGAL RESULT*** in poly_sin() computation\n"); + printk("EXP=%d, MS=%08x, LS=%08x\n", result->exp, + result->sigh, result->sigl); + RE_ENTRANT_CHECK_ON; +#endif DEBUGGING + + result->sigl = 0; /* Truncate the result to 1.00 */ + } + +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_tan.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_tan.c new file mode 100644 index 000000000..6b11988dc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/poly_tan.c @@ -0,0 +1,149 @@ +/*---------------------------------------------------------------------------+ + | poly_tan.c | + | | + | Compute the tan of a FPU_REG, using a polynomial approximation. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "control_w.h" + + +#define HIPOWERop 3 /* odd poly, positive terms */ +static unsigned short const oddplterms[HIPOWERop][4] = + { + { 0x846a, 0x42d1, 0xb544, 0x921f}, + { 0x6fb2, 0x0215, 0x95c0, 0x099c}, + { 0xfce6, 0x0cc8, 0x1c9a, 0x0000} + }; + +#define HIPOWERon 2 /* odd poly, negative terms */ +static unsigned short const oddnegterms[HIPOWERon][4] = + { + { 0x6906, 0xe205, 0x25c8, 0x8838}, + { 0x1dd7, 0x3fe3, 0x944e, 0x002c} + }; + +#define HIPOWERep 2 /* even poly, positive terms */ +static unsigned short const evenplterms[HIPOWERep][4] = + { + { 0xdb8f, 0x3761, 0x1432, 0x2acf}, + { 0x16eb, 0x13c1, 0x3099, 0x0003} + }; + +#define HIPOWERen 2 /* even poly, negative terms */ +static unsigned short const evennegterms[HIPOWERen][4] = + { + { 0x3a7c, 0xe4c5, 0x7f87, 0x2945}, + { 0x572b, 0x664c, 0xc543, 0x018c} + }; + + +/*--- poly_tan() ------------------------------------------------------------+ + | | + +---------------------------------------------------------------------------*/ +void poly_tan(FPU_REG const *arg, FPU_REG *result, int invert) +{ + short exponent; + FPU_REG odd_poly, even_poly, pos_poly, neg_poly; + FPU_REG argSq; + unsigned long long arg_signif, argSqSq; + + + exponent = arg->exp - EXP_BIAS; + +#ifdef PARANOID + if ( arg->sign != 0 ) /* Can't hack a number < 0.0 */ + { arith_invalid(result); return; } /* Need a positive number */ +#endif PARANOID + + arg_signif = significand(arg); + if ( exponent < -1 ) + { + /* shift the argument right by the required places */ + if ( shrx(&arg_signif, -1-exponent) >= 0x80000000U ) + arg_signif++; /* round up */ + } + + mul64(&arg_signif, &arg_signif, &significand(&argSq)); + mul64(&significand(&argSq), &significand(&argSq), &argSqSq); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(pos_poly.sign) = 0; + pos_poly.exp = EXP_BIAS; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&pos_poly.sigl, (unsigned *)&argSqSq, oddplterms, HIPOWERop-1); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(neg_poly.sign) = 0; + neg_poly.exp = EXP_BIAS; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, oddnegterms, HIPOWERon-1); + mul64(&significand(&argSq), &significand(&neg_poly), + &significand(&neg_poly)); + + /* Subtract the mantissas */ + significand(&pos_poly) -= significand(&neg_poly); + + /* Convert to 64 bit signed-compatible */ + pos_poly.exp -= 1; + + reg_move(&pos_poly, &odd_poly); + normalize(&odd_poly); + + reg_mul(&odd_poly, arg, &odd_poly, FULL_PRECISION); + /* Complete the odd polynomial. */ + reg_u_add(&odd_poly, arg, &odd_poly, FULL_PRECISION); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(pos_poly.sign) = 0; + pos_poly.exp = EXP_BIAS; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&pos_poly.sigl, (unsigned *)&argSqSq, evenplterms, HIPOWERep-1); + mul64(&significand(&argSq), + &significand(&pos_poly), &significand(&pos_poly)); + + /* will be a valid positive nr with expon = 0 */ + *(short *)&(neg_poly.sign) = 0; + neg_poly.exp = EXP_BIAS; + + /* Do the basic fixed point polynomial evaluation */ + polynomial(&neg_poly.sigl, (unsigned *)&argSqSq, evennegterms, HIPOWERen-1); + + /* Subtract the mantissas */ + significand(&neg_poly) -= significand(&pos_poly); + /* and multiply by argSq */ + + /* Convert argSq to a valid reg number */ + *(short *)&(argSq.sign) = 0; + argSq.exp = EXP_BIAS - 1; + normalize(&argSq); + + /* Convert to 64 bit signed-compatible */ + neg_poly.exp -= 1; + + reg_move(&neg_poly, &even_poly); + normalize(&even_poly); + + reg_mul(&even_poly, &argSq, &even_poly, FULL_PRECISION); + reg_add(&even_poly, &argSq, &even_poly, FULL_PRECISION); + /* Complete the even polynomial */ + reg_sub(&CONST_1, &even_poly, &even_poly, FULL_PRECISION); + + /* Now ready to copy the results */ + if ( invert ) + { reg_div(&even_poly, &odd_poly, result, FULL_PRECISION); } + else + { reg_div(&odd_poly, &even_poly, result, FULL_PRECISION); } + +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/polynomial.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/polynomial.S new file mode 100644 index 000000000..fa4da12c6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/polynomial.S @@ -0,0 +1,141 @@ +/*---------------------------------------------------------------------------+ + | polynomial.S | + | | + | Fixed point arithmetic polynomial evaluation. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void polynomial(unsigned accum[], unsigned x[], unsigned terms[][2], | + | int n) | + | | + | Computes: | + | terms[0] + (terms[1] + (terms[2] + ... + (terms[n-1]*x)*x)*x)*x) ... )*x | + | The result is returned in accum. | + | | + +---------------------------------------------------------------------------*/ + + .file "fpolynom.s" + +#include "fpu_asm.h" + + +/* #define EXTRA_PRECISE // Do not use: not complete */ + +#define TERM_SIZE $8 +#define SUM_MS -20(%ebp) /* sum ms long */ +#define SUM_MIDDLE -24(%ebp) /* sum middle long */ +#define SUM_LS -28(%ebp) /* sum ls long */ +#define SUM_LS_HI -25(%ebp) /* high byte of sum ls */ +#define ACCUM_MS -4(%ebp) /* accum ms long */ +#define ACCUM_MIDDLE -8(%ebp) /* accum middle long */ +#define ACCUM_LS -12(%ebp) /* accum ls long */ +#define ACCUM_LS_HI -9(%ebp) /* high byte of accum ls */ + +.text + .align 2,144 +.globl _polynomial +_polynomial: + pushl %ebp + movl %esp,%ebp + subl $32,%esp + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM2,%esi /* x */ + movl PARAM3,%edi /* terms */ + + movl TERM_SIZE,%eax + mull PARAM4 /* n */ + addl %eax,%edi + + movl 4(%edi),%edx /* terms[n] */ + movl %edx,SUM_MS + movl (%edi),%edx /* terms[n] */ + movl %edx,SUM_MIDDLE + xor %eax,%eax + movl %eax,SUM_LS + + subl TERM_SIZE,%edi + decl PARAM4 + js L_accum_done + +L_accum_loop: + xor %eax,%eax + movl %eax,ACCUM_MS + movl %eax,ACCUM_MIDDLE + + movl SUM_MIDDLE,%eax + 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 */ + addl %eax,ACCUM_LS + adcl %edx,ACCUM_MIDDLE + adcl $0,ACCUM_MS + + movl SUM_MS,%eax + 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 */ + addl %eax,ACCUM_MIDDLE + adcl %edx,ACCUM_MS + +/* + * Now put the sum of next term and the accumulator + * into the sum register + */ + movl ACCUM_MIDDLE,%eax + addl (%edi),%eax /* term ls long */ + movl %eax,SUM_MIDDLE + movl ACCUM_MS,%eax + 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 */ + je L_no_poly_round + + addl $1,SUM_MIDDLE + adcl $0,SUM_MS +L_no_poly_round: +#endif EXTRA_PRECISE + + subl TERM_SIZE,%edi + decl PARAM4 + jns L_accum_loop + +L_accum_done: +#ifdef EXTRA_PRECISE +/* Round the result */ + testb $128,SUM_LS_HI + je L_poly_done + + addl $1,SUM_MIDDLE + adcl $0,SUM_MS +#endif EXTRA_PRECISE + +L_poly_done: + movl PARAM1,%edi /* accum */ + movl SUM_MIDDLE,%eax + movl %eax,(%edi) + movl SUM_MS,%eax + movl %eax,4(%edi) + + popl %ebx + popl %edi + popl %esi + leave + ret diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_add_sub.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_add_sub.c new file mode 100644 index 000000000..d70889b40 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_add_sub.c @@ -0,0 +1,318 @@ +/*---------------------------------------------------------------------------+ + | reg_add_sub.c | + | | + | Functions to add or subtract two registers and put the result in a third. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | For each function, the destination may be any FPU_REG, including one of | + | the source FPU_REGs. | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "control_w.h" +#include "fpu_system.h" + + +int reg_add(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w) +{ + char saved_sign = dest->sign; + int diff; + + if ( !(a->tag | b->tag) ) + { + /* Both registers are valid */ + if (!(a->sign ^ b->sign)) + { + /* signs are the same */ + dest->sign = a->sign; + if ( reg_u_add(a, b, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + return 0; + } + + /* The signs are different, so do a subtraction */ + diff = a->exp - b->exp; + if (!diff) + { + diff = a->sigh - b->sigh; /* Works only if ms bits are identical */ + if (!diff) + { + diff = a->sigl > b->sigl; + if (!diff) + diff = -(a->sigl < b->sigl); + } + } + + if (diff > 0) + { + dest->sign = a->sign; + if ( reg_u_sub(a, b, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + } + else if ( diff == 0 ) + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(&CONST_Z, dest); + /* sign depends upon rounding mode */ + dest->sign = ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG; + } + else + { + dest->sign = b->sign; + if ( reg_u_sub(b, a, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + } + return 0; + } + else + { + if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) ) + { return real_2op_NaN(a, b, dest); } + else if (a->tag == TW_Zero) + { + if (b->tag == TW_Zero) + { + char different_signs = a->sign ^ b->sign; + /* Both are zero, result will be zero. */ + reg_move(a, dest); + if (different_signs) + { + /* Signs are different. */ + /* Sign of answer depends upon rounding mode. */ + dest->sign = ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG; + } + } + else + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(b, dest); + } + return 0; + } + else if (b->tag == TW_Zero) + { +#ifdef DENORM_OPERAND + if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(a, dest); return 0; + } + else if (a->tag == TW_Infinity) + { + if (b->tag != TW_Infinity) + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(a, dest); return 0; + } + if (a->sign == b->sign) + { + /* They are both + or - infinity */ + reg_move(a, dest); return 0; + } + return arith_invalid(dest); /* Infinity-Infinity is undefined. */ + } + else if (b->tag == TW_Infinity) + { +#ifdef DENORM_OPERAND + if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(b, dest); return 0; + } + } +#ifdef PARANOID + EXCEPTION(EX_INTERNAL|0x101); +#endif + return 1; +} + + +/* Subtract b from a. (a-b) -> dest */ +int reg_sub(FPU_REG const *a, FPU_REG const *b, FPU_REG *dest, int control_w) +{ + char saved_sign = dest->sign; + int diff; + + if ( !(a->tag | b->tag) ) + { + /* Both registers are valid */ + diff = a->exp - b->exp; + if (!diff) + { + diff = a->sigh - b->sigh; /* Works only if ms bits are identical */ + if (!diff) + { + diff = a->sigl > b->sigl; + if (!diff) + diff = -(a->sigl < b->sigl); + } + } + + switch (a->sign*2 + b->sign) + { + case 0: /* P - P */ + case 3: /* N - N */ + if (diff > 0) + { + /* |a| > |b| */ + dest->sign = a->sign; + if ( reg_u_sub(a, b, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + return 0; + } + else if ( diff == 0 ) + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(&CONST_Z, dest); + /* sign depends upon rounding mode */ + dest->sign = ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG; + } + else + { + dest->sign = a->sign ^ SIGN_POS^SIGN_NEG; + if ( reg_u_sub(b, a, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + } + break; + case 1: /* P - N */ + dest->sign = SIGN_POS; + if ( reg_u_add(a, b, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + break; + case 2: /* N - P */ + dest->sign = SIGN_NEG; + if ( reg_u_add(a, b, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + break; + } + return 0; + } + else + { + if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) ) + { return real_2op_NaN(b, a, dest); } + else if (b->tag == TW_Zero) + { + if (a->tag == TW_Zero) + { + char same_signs = !(a->sign ^ b->sign); + /* Both are zero, result will be zero. */ + reg_move(a, dest); /* Answer for different signs. */ + if (same_signs) + { + /* Sign depends upon rounding mode */ + dest->sign = ((control_w & CW_RC) != RC_DOWN) + ? SIGN_POS : SIGN_NEG; + } + } + else + { +#ifdef DENORM_OPERAND + if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(a, dest); + } + return 0; + } + else if (a->tag == TW_Zero) + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(b, dest); + dest->sign ^= SIGN_POS^SIGN_NEG; + return 0; + } + else if (a->tag == TW_Infinity) + { + if (b->tag != TW_Infinity) + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(a, dest); return 0; + } + /* Both args are Infinity */ + if (a->sign == b->sign) + { + /* Infinity-Infinity is undefined. */ + return arith_invalid(dest); + } + reg_move(a, dest); + return 0; + } + else if (b->tag == TW_Infinity) + { +#ifdef DENORM_OPERAND + if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(b, dest); + dest->sign ^= SIGN_POS^SIGN_NEG; + return 0; + } + } +#ifdef PARANOID + EXCEPTION(EX_INTERNAL|0x110); +#endif + return 1; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_compare.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_compare.c new file mode 100644 index 000000000..020030119 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_compare.c @@ -0,0 +1,379 @@ +/*---------------------------------------------------------------------------+ + | reg_compare.c | + | | + | Compare two floating point registers | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | compare() is the core FPU_REG comparison function | + +---------------------------------------------------------------------------*/ + +#include "fpu_system.h" +#include "exception.h" +#include "fpu_emu.h" +#include "control_w.h" +#include "status_w.h" + + +int compare(FPU_REG const *b) +{ + int diff; + + if ( FPU_st0_ptr->tag | b->tag ) + { + if ( FPU_st0_ptr->tag == TW_Zero ) + { + if ( b->tag == TW_Zero ) return COMP_A_eq_B; + if ( b->tag == TW_Valid ) + { + return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) +#ifdef DENORM_OPERAND + | ((b->exp <= EXP_UNDER) ? + COMP_Denormal : 0) +#endif DENORM_OPERAND + ; + } + } + else if ( b->tag == TW_Zero ) + { + if ( FPU_st0_ptr->tag == TW_Valid ) + { + return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B + : COMP_A_lt_B) +#ifdef DENORM_OPERAND + | ((FPU_st0_ptr->exp <= EXP_UNDER ) + ? COMP_Denormal : 0 ) +#endif DENORM_OPERAND + ; + } + } + + if ( FPU_st0_ptr->tag == TW_Infinity ) + { + if ( (b->tag == TW_Valid) || (b->tag == TW_Zero) ) + { + return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B + : COMP_A_lt_B) +#ifdef DENORM_OPERAND + | (((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) ? + COMP_Denormal : 0 ) +#endif DENORM_OPERAND +; + } + else if ( b->tag == TW_Infinity ) + { + /* The 80486 book says that infinities can be equal! */ + return (FPU_st0_ptr->sign == b->sign) ? COMP_A_eq_B : + ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B); + } + /* Fall through to the NaN code */ + } + else if ( b->tag == TW_Infinity ) + { + if ( (FPU_st0_ptr->tag == TW_Valid) || (FPU_st0_ptr->tag == TW_Zero) ) + { + return ((b->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) +#ifdef DENORM_OPERAND + | (((FPU_st0_ptr->tag == TW_Valid) + && (FPU_st0_ptr->exp <= EXP_UNDER)) ? + COMP_Denormal : 0) +#endif DENORM_OPERAND + ; + } + /* Fall through to the NaN code */ + } + + /* The only possibility now should be that one of the arguments + is a NaN */ + if ( (FPU_st0_ptr->tag == TW_NaN) || (b->tag == TW_NaN) ) + { + if ( ((FPU_st0_ptr->tag == TW_NaN) && !(FPU_st0_ptr->sigh & 0x40000000)) + || ((b->tag == TW_NaN) && !(b->sigh & 0x40000000)) ) + /* At least one arg is a signaling NaN */ + return COMP_No_Comp | COMP_SNaN | COMP_NaN; + else + /* Neither is a signaling NaN */ + return COMP_No_Comp | COMP_NaN; + } + + EXCEPTION(EX_Invalid); + } + +#ifdef PARANOID + if (!(FPU_st0_ptr->sigh & 0x80000000)) EXCEPTION(EX_Invalid); + if (!(b->sigh & 0x80000000)) EXCEPTION(EX_Invalid); +#endif PARANOID + + + if (FPU_st0_ptr->sign != b->sign) + { + return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) +#ifdef DENORM_OPERAND + | + ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + COMP_Denormal : 0) +#endif DENORM_OPERAND + ; + } + + diff = FPU_st0_ptr->exp - b->exp; + if ( diff == 0 ) + { + diff = FPU_st0_ptr->sigh - b->sigh; /* Works only if ms bits are + identical */ + if ( diff == 0 ) + { + diff = FPU_st0_ptr->sigl > b->sigl; + if ( diff == 0 ) + diff = -(FPU_st0_ptr->sigl < b->sigl); + } + } + + if ( diff > 0 ) + { + return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_gt_B : COMP_A_lt_B) +#ifdef DENORM_OPERAND + | + ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + COMP_Denormal : 0) +#endif DENORM_OPERAND + ; + } + if ( diff < 0 ) + { + return ((FPU_st0_ptr->sign == SIGN_POS) ? COMP_A_lt_B : COMP_A_gt_B) +#ifdef DENORM_OPERAND + | + ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + COMP_Denormal : 0) +#endif DENORM_OPERAND + ; + } + + return COMP_A_eq_B +#ifdef DENORM_OPERAND + | + ( ((FPU_st0_ptr->exp <= EXP_UNDER) || (b->exp <= EXP_UNDER)) ? + COMP_Denormal : 0) +#endif DENORM_OPERAND + ; + +} + + +/* This function requires that st(0) is not empty */ +int compare_st_data(void) +{ + int f, c; + + c = compare(&FPU_loaded_data); + + if (c & COMP_NaN) + { + EXCEPTION(EX_Invalid); + f = SW_C3 | SW_C2 | SW_C0; + } + else + switch (c & 7) + { + case COMP_A_lt_B: + f = SW_C0; + break; + case COMP_A_eq_B: + f = SW_C3; + break; + case COMP_A_gt_B: + f = 0; + break; + case COMP_No_Comp: + f = SW_C3 | SW_C2 | SW_C0; + break; +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL|0x121); + f = SW_C3 | SW_C2 | SW_C0; + break; +#endif PARANOID + } + setcc(f); + if (c & COMP_Denormal) + { + return denormal_operand(); + } + return 0; +} + + +static int compare_st_st(int nr) +{ + int f, c; + + if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) ) + { + setcc(SW_C3 | SW_C2 | SW_C0); + /* Stack fault */ + EXCEPTION(EX_StackUnder); + return !(control_word & CW_Invalid); + } + + c = compare(&st(nr)); + if (c & COMP_NaN) + { + setcc(SW_C3 | SW_C2 | SW_C0); + EXCEPTION(EX_Invalid); + return !(control_word & CW_Invalid); + } + else + switch (c & 7) + { + case COMP_A_lt_B: + f = SW_C0; + break; + case COMP_A_eq_B: + f = SW_C3; + break; + case COMP_A_gt_B: + f = 0; + break; + case COMP_No_Comp: + f = SW_C3 | SW_C2 | SW_C0; + break; +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL|0x122); + f = SW_C3 | SW_C2 | SW_C0; + break; +#endif PARANOID + } + setcc(f); + if (c & COMP_Denormal) + { + return denormal_operand(); + } + return 0; +} + + +static int compare_u_st_st(int nr) +{ + int f, c; + + if ( !NOT_EMPTY_0 || !NOT_EMPTY(nr) ) + { + setcc(SW_C3 | SW_C2 | SW_C0); + /* Stack fault */ + EXCEPTION(EX_StackUnder); + return !(control_word & CW_Invalid); + } + + c = compare(&st(nr)); + if (c & COMP_NaN) + { + setcc(SW_C3 | SW_C2 | SW_C0); + if (c & COMP_SNaN) /* This is the only difference between + un-ordered and ordinary comparisons */ + { + EXCEPTION(EX_Invalid); + return !(control_word & CW_Invalid); + } + return 0; + } + else + switch (c & 7) + { + case COMP_A_lt_B: + f = SW_C0; + break; + case COMP_A_eq_B: + f = SW_C3; + break; + case COMP_A_gt_B: + f = 0; + break; + case COMP_No_Comp: + f = SW_C3 | SW_C2 | SW_C0; + break; +#ifdef PARANOID + default: + EXCEPTION(EX_INTERNAL|0x123); + f = SW_C3 | SW_C2 | SW_C0; + break; +#endif PARANOID + } + setcc(f); + if (c & COMP_Denormal) + { + return denormal_operand(); + } + return 0; +} + +/*---------------------------------------------------------------------------*/ + +void fcom_st() +{ + /* fcom st(i) */ + compare_st_st(FPU_rm); +} + + +void fcompst() +{ + /* fcomp st(i) */ + if ( !compare_st_st(FPU_rm) ) + pop(); +} + + +void fcompp() +{ + /* fcompp */ + if (FPU_rm != 1) + { + FPU_illegal(); + return; + } + if ( !compare_st_st(1) ) + { + pop(); FPU_st0_ptr = &st(0); + pop(); + } +} + + +void fucom_() +{ + /* fucom st(i) */ + compare_u_st_st(FPU_rm); + +} + + +void fucomp() +{ + /* fucomp st(i) */ + if ( !compare_u_st_st(FPU_rm) ) + pop(); +} + + +void fucompp() +{ + /* fucompp */ + if (FPU_rm == 1) + { + if ( !compare_u_st_st(1) ) + { + pop(); FPU_st0_ptr = &st(0); + pop(); + } + } + else + FPU_illegal(); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.c new file mode 100644 index 000000000..29d157c8b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.c @@ -0,0 +1,116 @@ +/*---------------------------------------------------------------------------+ + | reg_constant.c | + | | + | All of the constant FPU_REGs | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_system.h" +#include "fpu_emu.h" +#include "status_w.h" +#include "reg_constant.h" + + +FPU_REG const CONST_1 = { SIGN_POS, TW_Valid, EXP_BIAS, + 0x00000000, 0x80000000 }; +FPU_REG const CONST_2 = { SIGN_POS, TW_Valid, EXP_BIAS+1, + 0x00000000, 0x80000000 }; +FPU_REG const CONST_HALF = { SIGN_POS, TW_Valid, EXP_BIAS-1, + 0x00000000, 0x80000000 }; +FPU_REG const CONST_L2T = { SIGN_POS, TW_Valid, EXP_BIAS+1, + 0xcd1b8afe, 0xd49a784b }; +FPU_REG const CONST_L2E = { SIGN_POS, TW_Valid, EXP_BIAS, + 0x5c17f0bc, 0xb8aa3b29 }; +FPU_REG const CONST_PI = { SIGN_POS, TW_Valid, EXP_BIAS+1, + 0x2168c235, 0xc90fdaa2 }; +FPU_REG const CONST_PI2 = { SIGN_POS, TW_Valid, EXP_BIAS, + 0x2168c235, 0xc90fdaa2 }; +FPU_REG const CONST_PI4 = { SIGN_POS, TW_Valid, EXP_BIAS-1, + 0x2168c235, 0xc90fdaa2 }; +FPU_REG const CONST_LG2 = { SIGN_POS, TW_Valid, EXP_BIAS-2, + 0xfbcff799, 0x9a209a84 }; +FPU_REG const CONST_LN2 = { SIGN_POS, TW_Valid, EXP_BIAS-1, + 0xd1cf79ac, 0xb17217f7 }; + +/* Extra bits to take pi/2 to more than 128 bits precision. */ +FPU_REG const CONST_PI2extra = { SIGN_NEG, TW_Valid, EXP_BIAS-66, + 0xfc8f8cbb, 0xece675d1 }; + +/* Only the sign (and tag) is used in internal zeroes */ +FPU_REG const CONST_Z = { SIGN_POS, TW_Zero, EXP_UNDER, 0x0, 0x0 }; + +/* Only the sign and significand (and tag) are used in internal NaNs */ +/* The 80486 never generates one of these +FPU_REG const CONST_SNAN = { SIGN_POS, TW_NaN, EXP_OVER, 0x00000001, 0x80000000 }; + */ +/* This is the real indefinite QNaN */ +FPU_REG const CONST_QNaN = { SIGN_NEG, TW_NaN, EXP_OVER, 0x00000000, 0xC0000000 }; + +/* Only the sign (and tag) is used in internal infinities */ +FPU_REG const CONST_INF = { SIGN_POS, TW_Infinity, EXP_OVER, 0x00000000, 0x80000000 }; + + + +static void fld_const(FPU_REG const *c) +{ + FPU_REG *st_new_ptr; + + if ( STACK_OVERFLOW ) + { + stack_overflow(); + return; + } + push(); + reg_move(c, FPU_st0_ptr); + clear_C1(); +} + + +static void fld1(void) +{ + fld_const(&CONST_1); +} + +static void fldl2t(void) +{ + fld_const(&CONST_L2T); +} + +static void fldl2e(void) +{ + fld_const(&CONST_L2E); +} + +static void fldpi(void) +{ + fld_const(&CONST_PI); +} + +static void fldlg2(void) +{ + fld_const(&CONST_LG2); +} + +static void fldln2(void) +{ + fld_const(&CONST_LN2); +} + +static void fldz(void) +{ + fld_const(&CONST_Z); +} + +static FUNC constants_table[] = { + fld1, fldl2t, fldl2e, fldpi, fldlg2, fldln2, fldz, FPU_illegal +}; + +void fconst(void) +{ + (constants_table[FPU_rm])(); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.h new file mode 100644 index 000000000..b7db97e34 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_constant.h @@ -0,0 +1,31 @@ +/*---------------------------------------------------------------------------+ + | reg_constant.h | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + +#ifndef _REG_CONSTANT_H_ +#define _REG_CONSTANT_H_ + +#include "fpu_emu.h" + +extern FPU_REG const CONST_1; +extern FPU_REG const CONST_2; +extern FPU_REG const CONST_HALF; +extern FPU_REG const CONST_L2T; +extern FPU_REG const CONST_L2E; +extern FPU_REG const CONST_PI; +extern FPU_REG const CONST_PI2; +extern FPU_REG const CONST_PI2extra; +extern FPU_REG const CONST_PI4; +extern FPU_REG const CONST_LG2; +extern FPU_REG const CONST_LN2; +extern FPU_REG const CONST_Z; +extern FPU_REG const CONST_PINF; +extern FPU_REG const CONST_INF; +extern FPU_REG const CONST_MINF; +extern FPU_REG const CONST_QNaN; + +#endif _REG_CONSTANT_H_ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_div.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_div.S new file mode 100644 index 000000000..2727cfaff --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_div.S @@ -0,0 +1,251 @@ + .file "reg_div.S" +/*---------------------------------------------------------------------------+ + | reg_div.S | + | | + | Divide one FPU_REG by another and put the result in a destination FPU_REG.| + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void reg_div(FPU_REG *a, FPU_REG *b, FPU_REG *dest, | + | unsigned int control_word) | + | | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "fpu_asm.h" + + +.text + .align 2 + +.globl _reg_div +_reg_div: + pushl %ebp + movl %esp,%ebp +#ifdef REENTRANT_FPU + subl $28,%esp /* Needed by divide_kernel */ +#endif REENTRANT_FPU + + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%esi + movl PARAM2,%ebx + movl PARAM3,%edi + + movb TAG(%esi),%al + orb TAG(%ebx),%al + + jne L_div_special /* Not (both numbers TW_Valid) */ + +#ifdef DENORM_OPERAND +/* Check for denormals */ + cmpl EXP_UNDER,EXP(%esi) + jg xL_arg1_not_denormal + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xL_arg1_not_denormal: + cmpl EXP_UNDER,EXP(%ebx) + jg xL_arg2_not_denormal + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xL_arg2_not_denormal: +#endif DENORM_OPERAND + +/* Both arguments are TW_Valid */ + movb TW_Valid,TAG(%edi) + + movb SIGN(%esi),%cl + cmpb %cl,SIGN(%ebx) + setne (%edi) /* Set the sign, requires SIGN_NEG=1, SIGN_POS=0 */ + + movl EXP(%esi),%edx + movl EXP(%ebx),%eax + subl %eax,%edx + addl EXP_BIAS,%edx + movl %edx,EXP(%edi) + + jmp _divide_kernel + + +/*-----------------------------------------------------------------------*/ +L_div_special: + cmpb TW_NaN,TAG(%esi) /* A NaN with anything to give NaN */ + je L_arg1_NaN + + cmpb TW_NaN,TAG(%ebx) /* A NaN with anything to give NaN */ + jne L_no_NaN_arg + +/* Operations on NaNs */ +L_arg1_NaN: +L_arg2_NaN: + pushl %edi /* Destination */ + pushl %esi + pushl %ebx /* Ordering is important here */ + call _real_2op_NaN + jmp LDiv_exit + +/* Invalid operations */ +L_zero_zero: +L_inf_inf: + pushl %edi /* Destination */ + call _arith_invalid /* 0/0 or Infinity/Infinity */ + jmp LDiv_exit + +L_no_NaN_arg: + cmpb TW_Infinity,TAG(%esi) + jne L_arg1_not_inf + + cmpb TW_Infinity,TAG(%ebx) + je L_inf_inf /* invalid operation */ + + cmpb TW_Valid,TAG(%ebx) + je L_inf_valid + +#ifdef PARANOID + /* arg2 must be zero or valid */ + cmpb TW_Zero,TAG(%ebx) + ja L_unknown_tags +#endif PARANOID + + /* Note that p16-9 says that infinity/0 returns infinity */ + jmp L_copy_arg1 /* Answer is Inf */ + +L_inf_valid: +#ifdef DENORM_OPERAND + cmpl EXP_UNDER,EXP(%ebx) + jg L_copy_arg1 /* Answer is Inf */ + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit +#endif DENORM_OPERAND + + jmp L_copy_arg1 /* Answer is Inf */ + +L_arg1_not_inf: + cmpb TW_Zero,TAG(%ebx) /* Priority to div-by-zero error */ + jne L_arg2_not_zero + + cmpb TW_Zero,TAG(%esi) + je L_zero_zero /* invalid operation */ + +#ifdef PARANOID + /* arg1 must be valid */ + cmpb TW_Valid,TAG(%esi) + ja L_unknown_tags +#endif PARANOID + +/* Division by zero error */ + pushl %edi /* destination */ + movb SIGN(%esi),%al + xorb SIGN(%ebx),%al + pushl %eax /* lower 8 bits have the sign */ + call _divide_by_zero + jmp LDiv_exit + +L_arg2_not_zero: + cmpb TW_Infinity,TAG(%ebx) + jne L_arg2_not_inf + +#ifdef DENORM_OPERAND + cmpb TW_Valid,TAG(%esi) + jne L_return_zero + + cmpl EXP_UNDER,EXP(%esi) + jg L_return_zero /* Answer is zero */ + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit +#endif DENORM_OPERAND + + jmp L_return_zero /* Answer is zero */ + +L_arg2_not_inf: + +#ifdef PARANOID + cmpb TW_Zero,TAG(%esi) + jne L_unknown_tags +#endif PARANOID + + /* arg1 is zero, arg2 is not Infinity or a NaN */ + +#ifdef DENORM_OPERAND + cmpl EXP_UNDER,EXP(%ebx) + jg L_copy_arg1 /* Answer is zero */ + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit +#endif DENORM_OPERAND + +L_copy_arg1: + movb TAG(%esi),%ax + movb %ax,TAG(%edi) + movl EXP(%esi),%eax + movl %eax,EXP(%edi) + movl SIGL(%esi),%eax + movl %eax,SIGL(%edi) + movl SIGH(%esi),%eax + movl %eax,SIGH(%edi) + +LDiv_set_result_sign: + movb SIGN(%esi),%cl + cmpb %cl,SIGN(%ebx) + jne LDiv_negative_result + + movb SIGN_POS,SIGN(%edi) + xorl %eax,%eax /* Valid result */ + jmp LDiv_exit + +LDiv_negative_result: + movb SIGN_NEG,SIGN(%edi) + xorl %eax,%eax /* Valid result */ + +LDiv_exit: +#ifdef REENTRANT_FPU + leal -40(%ebp),%esp +#else + leal -12(%ebp),%esp +#endif REENTRANT_FPU + + popl %ebx + popl %edi + popl %esi + leave + ret + + +L_return_zero: + xorl %eax,%eax + movl %eax,SIGH(%edi) + movl %eax,SIGL(%edi) + movl EXP_UNDER,EXP(%edi) + movb TW_Zero,TAG(%edi) + jmp LDiv_set_result_sign + +#ifdef PARANOID +L_unknown_tags: + pushl EX_INTERNAL | 0x208 + call EXCEPTION + + /* Generate a NaN for unknown tags */ + movl _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 */ +#endif PARANOID diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_ld_str.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_ld_str.c new file mode 100644 index 000000000..e8a55be7b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_ld_str.c @@ -0,0 +1,1402 @@ +/*---------------------------------------------------------------------------+ + | reg_ld_str.c | + | | + | All of the functions which transfer data between user memory and FPU_REGs.| + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Note: | + | The file contains code which accesses user memory. | + | Emulator static data may change when user memory is accessed, due to | + | other processes using the emulator while swapping is in progress. | + +---------------------------------------------------------------------------*/ + +#include + +#include "fpu_system.h" +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "control_w.h" +#include "status_w.h" + + +#define EXTENDED_Ebias 0x3fff +#define EXTENDED_Emin (-0x3ffe) /* smallest valid exponent */ + +#define DOUBLE_Emax 1023 /* largest valid exponent */ +#define DOUBLE_Ebias 1023 +#define DOUBLE_Emin (-1022) /* smallest valid exponent */ + +#define SINGLE_Emax 127 /* largest valid exponent */ +#define SINGLE_Ebias 127 +#define SINGLE_Emin (-126) /* smallest valid exponent */ + +static void write_to_extended(FPU_REG *rp, char *d); + +FPU_REG FPU_loaded_data; + + +/* Get a long double from user memory */ +int reg_load_extended(overrides override) +{ + long double *s = (long double *)FPU_data_address; + unsigned long sigl, sigh, exp; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 10); + /* Use temporary variables here because FPU_loaded data is + static and hence re-entrancy problems can arise */ + sigl = get_fs_long((unsigned long *) s); + sigh = get_fs_long(1 + (unsigned long *) s); + exp = get_fs_word(4 + (unsigned short *) s); + RE_ENTRANT_CHECK_ON; + + FPU_loaded_data.tag = TW_Valid; /* Default */ + FPU_loaded_data.sigl = sigl; + FPU_loaded_data.sigh = sigh; + if (exp & 0x8000) + FPU_loaded_data.sign = SIGN_NEG; + else + FPU_loaded_data.sign = SIGN_POS; + exp &= 0x7fff; + FPU_loaded_data.exp = exp - EXTENDED_Ebias + EXP_BIAS; + + /* Assume that optimisation can keep sigl, sigh, and exp in + registers, otherwise it would be more efficient to work + with FPU_loaded_data (which is static) here. */ + if ( exp == 0 ) + { + if ( !(sigh | sigl) ) + { + FPU_loaded_data.tag = TW_Zero; + return 0; + } + /* The number is a de-normal or pseudodenormal. */ + if (sigh & 0x80000000) + { + /* Is a pseudodenormal. */ + /* Convert it for internal use. */ + /* This is non-80486 behaviour because the number + loses its 'denormal' identity. */ + FPU_loaded_data.exp++; + return 1; + } + else + { + /* Is a denormal. */ + /* Convert it for internal use. */ + FPU_loaded_data.exp++; + normalize_nuo(&FPU_loaded_data); + return 0; + } + } + else if ( exp == 0x7fff ) + { + if ( !((sigh ^ 0x80000000) | sigl) ) + { + /* Matches the bit pattern for Infinity. */ + FPU_loaded_data.exp = EXP_Infinity; + FPU_loaded_data.tag = TW_Infinity; + return 0; + } + + FPU_loaded_data.exp = EXP_NaN; + FPU_loaded_data.tag = TW_NaN; + if ( !(sigh & 0x80000000) ) + { + /* NaNs have the ms bit set to 1. */ + /* This is therefore an Unsupported NaN data type. */ + /* This is non 80486 behaviour */ + /* This should generate an Invalid Operand exception + later, so we convert it to a SNaN */ + FPU_loaded_data.sigh = 0x80000000; + FPU_loaded_data.sigl = 0x00000001; + FPU_loaded_data.sign = SIGN_NEG; + return 1; + } + return 0; + } + + if ( !(sigh & 0x80000000) ) + { + /* Unsupported data type. */ + /* Valid numbers have the ms bit set to 1. */ + /* Unnormal. */ + /* Convert it for internal use. */ + /* This is non-80486 behaviour */ + /* This should generate an Invalid Operand exception + later, so we convert it to a SNaN */ + FPU_loaded_data.sigh = 0x80000000; + FPU_loaded_data.sigl = 0x00000001; + FPU_loaded_data.sign = SIGN_NEG; + FPU_loaded_data.exp = EXP_NaN; + FPU_loaded_data.tag = TW_NaN; + return 1; + } + return 0; +} + + +/* Get a double from user memory */ +int reg_load_double(overrides override) +{ + double *dfloat = (double *)FPU_data_address; + int exp; + unsigned m64, l64; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, dfloat, 8); + m64 = get_fs_long(1 + (unsigned long *) dfloat); + l64 = get_fs_long((unsigned long *) dfloat); + RE_ENTRANT_CHECK_ON; + + if (m64 & 0x80000000) + FPU_loaded_data.sign = SIGN_NEG; + else + FPU_loaded_data.sign = SIGN_POS; + exp = ((m64 & 0x7ff00000) >> 20) - DOUBLE_Ebias; + m64 &= 0xfffff; + if (exp > DOUBLE_Emax) + { + /* Infinity or NaN */ + if ((m64 == 0) && (l64 == 0)) + { + /* +- infinity */ + FPU_loaded_data.sigh = 0x80000000; + FPU_loaded_data.sigl = 0x00000000; + FPU_loaded_data.exp = EXP_Infinity; + FPU_loaded_data.tag = TW_Infinity; + return 0; + } + else + { + /* Must be a signaling or quiet NaN */ + FPU_loaded_data.exp = EXP_NaN; + FPU_loaded_data.tag = TW_NaN; + FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; + FPU_loaded_data.sigh |= l64 >> 21; + FPU_loaded_data.sigl = l64 << 11; + return 0; /* The calling function must look for NaNs */ + } + } + else if ( exp < DOUBLE_Emin ) + { + /* Zero or de-normal */ + if ((m64 == 0) && (l64 == 0)) + { + /* Zero */ + int c = FPU_loaded_data.sign; + reg_move(&CONST_Z, &FPU_loaded_data); + FPU_loaded_data.sign = c; + return 0; + } + else + { + /* De-normal */ + FPU_loaded_data.exp = DOUBLE_Emin + EXP_BIAS; + FPU_loaded_data.tag = TW_Valid; + FPU_loaded_data.sigh = m64 << 11; + FPU_loaded_data.sigh |= l64 >> 21; + FPU_loaded_data.sigl = l64 << 11; + normalize_nuo(&FPU_loaded_data); + return denormal_operand(); + } + } + else + { + FPU_loaded_data.exp = exp + EXP_BIAS; + FPU_loaded_data.tag = TW_Valid; + FPU_loaded_data.sigh = (m64 << 11) | 0x80000000; + FPU_loaded_data.sigh |= l64 >> 21; + FPU_loaded_data.sigl = l64 << 11; + + return 0; + } +} + + +/* Get a float from user memory */ +int reg_load_single(overrides override) +{ + float *single = (float *)FPU_data_address; + unsigned m32; + int exp; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, single, 4); + m32 = get_fs_long((unsigned long *) single); + RE_ENTRANT_CHECK_ON; + + if (m32 & 0x80000000) + FPU_loaded_data.sign = SIGN_NEG; + else + FPU_loaded_data.sign = SIGN_POS; + if (!(m32 & 0x7fffffff)) + { + /* Zero */ + int c = FPU_loaded_data.sign; + reg_move(&CONST_Z, &FPU_loaded_data); + FPU_loaded_data.sign = c; + return 0; + } + exp = ((m32 & 0x7f800000) >> 23) - SINGLE_Ebias; + m32 = (m32 & 0x7fffff) << 8; + if ( exp < SINGLE_Emin ) + { + /* De-normals */ + FPU_loaded_data.exp = SINGLE_Emin + EXP_BIAS; + FPU_loaded_data.tag = TW_Valid; + FPU_loaded_data.sigh = m32; + FPU_loaded_data.sigl = 0; + normalize_nuo(&FPU_loaded_data); + return denormal_operand(); + } + else if ( exp > SINGLE_Emax ) + { + /* Infinity or NaN */ + if ( m32 == 0 ) + { + /* +- infinity */ + FPU_loaded_data.sigh = 0x80000000; + FPU_loaded_data.sigl = 0x00000000; + FPU_loaded_data.exp = EXP_Infinity; + FPU_loaded_data.tag = TW_Infinity; + return 0; + } + else + { + /* Must be a signaling or quiet NaN */ + FPU_loaded_data.exp = EXP_NaN; + FPU_loaded_data.tag = TW_NaN; + FPU_loaded_data.sigh = m32 | 0x80000000; + FPU_loaded_data.sigl = 0; + return 0; /* The calling function must look for NaNs */ + } + } + else + { + FPU_loaded_data.exp = exp + EXP_BIAS; + FPU_loaded_data.sigh = m32 | 0x80000000; + FPU_loaded_data.sigl = 0; + FPU_loaded_data.tag = TW_Valid; + return 0; + } +} + + +/* Get a long long from user memory */ +void reg_load_int64(overrides override) +{ + long long *_s = (long long *)FPU_data_address; + int e; + long long s; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, _s, 8); + ((unsigned long *)&s)[0] = get_fs_long((unsigned long *) _s); + ((unsigned long *)&s)[1] = get_fs_long(1 + (unsigned long *) _s); + RE_ENTRANT_CHECK_ON; + + if (s == 0) + { reg_move(&CONST_Z, &FPU_loaded_data); return; } + + if (s > 0) + FPU_loaded_data.sign = SIGN_POS; + else + { + s = -s; + FPU_loaded_data.sign = SIGN_NEG; + } + + e = EXP_BIAS + 63; + significand(&FPU_loaded_data) = s; + FPU_loaded_data.exp = e; + FPU_loaded_data.tag = TW_Valid; + normalize_nuo(&FPU_loaded_data); +} + + +/* Get a long from user memory */ +void reg_load_int32(overrides override) +{ + long *_s = (long *)FPU_data_address; + long s; + int e; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, _s, 4); + s = (long)get_fs_long((unsigned long *) _s); + RE_ENTRANT_CHECK_ON; + + if (s == 0) + { reg_move(&CONST_Z, &FPU_loaded_data); return; } + + if (s > 0) + FPU_loaded_data.sign = SIGN_POS; + else + { + s = -s; + FPU_loaded_data.sign = SIGN_NEG; + } + + e = EXP_BIAS + 31; + FPU_loaded_data.sigh = s; + FPU_loaded_data.sigl = 0; + FPU_loaded_data.exp = e; + FPU_loaded_data.tag = TW_Valid; + normalize_nuo(&FPU_loaded_data); +} + + +/* Get a short from user memory */ +void reg_load_int16(overrides override) +{ + short *_s = (short *)FPU_data_address; + int s, e; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, _s, 2); + /* Cast as short to get the sign extended. */ + s = (short)get_fs_word((unsigned short *) _s); + RE_ENTRANT_CHECK_ON; + + if (s == 0) + { reg_move(&CONST_Z, &FPU_loaded_data); return; } + + if (s > 0) + FPU_loaded_data.sign = SIGN_POS; + else + { + s = -s; + FPU_loaded_data.sign = SIGN_NEG; + } + + e = EXP_BIAS + 15; + FPU_loaded_data.sigh = s << 16; + + FPU_loaded_data.sigl = 0; + FPU_loaded_data.exp = e; + FPU_loaded_data.tag = TW_Valid; + normalize_nuo(&FPU_loaded_data); +} + + +/* Get a packed bcd array from user memory */ +void reg_load_bcd(overrides override) +{ + char *s = (char *)FPU_data_address; + int pos; + unsigned char bcd; + long long l=0; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 10); + RE_ENTRANT_CHECK_ON; + for ( pos = 8; pos >= 0; pos--) + { + l *= 10; + RE_ENTRANT_CHECK_OFF; + bcd = (unsigned char)get_fs_byte((unsigned char *) s+pos); + RE_ENTRANT_CHECK_ON; + l += bcd >> 4; + l *= 10; + l += bcd & 0x0f; + } + + /* Finish all access to user memory before putting stuff into + the static FPU_loaded_data */ + RE_ENTRANT_CHECK_OFF; + FPU_loaded_data.sign = + ((unsigned char)get_fs_byte((unsigned char *) s+9)) & 0x80 ? + SIGN_NEG : SIGN_POS; + RE_ENTRANT_CHECK_ON; + + if (l == 0) + { + char sign = FPU_loaded_data.sign; + reg_move(&CONST_Z, &FPU_loaded_data); + FPU_loaded_data.sign = sign; + } + else + { + significand(&FPU_loaded_data) = l; + FPU_loaded_data.exp = EXP_BIAS + 63; + FPU_loaded_data.tag = TW_Valid; + normalize_nuo(&FPU_loaded_data); + } +} + +/*===========================================================================*/ + +/* Put a long double into user memory */ +int reg_store_extended(overrides override) +{ + /* + The only exception raised by an attempt to store to an + extended format is the Invalid Stack exception, i.e. + attempting to store from an empty register. + */ + long double *d = (long double *)FPU_data_address; + + if ( FPU_st0_tag != TW_Empty ) + { + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE, d, 10); + RE_ENTRANT_CHECK_ON; + write_to_extended(FPU_st0_ptr, (char *) FPU_data_address); + return 1; + } + + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + if ( control_word & CW_Invalid ) + { + /* The masked response */ + /* Put out the QNaN indefinite */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,10); + put_fs_long(0, (unsigned long *) d); + put_fs_long(0xc0000000, 1 + (unsigned long *) d); + put_fs_word(0xffff, 4 + (short *) d); + RE_ENTRANT_CHECK_ON; + return 1; + } + else + return 0; + +} + + +/* Put a double into user memory */ +int reg_store_double(overrides override) +{ + double *dfloat = (double *)FPU_data_address; + unsigned long l[2]; + unsigned long increment = 0; /* avoid gcc warnings */ + + if (FPU_st0_tag == TW_Valid) + { + int exp; + FPU_REG tmp; + + reg_move(FPU_st0_ptr, &tmp); + exp = tmp.exp - EXP_BIAS; + + if ( exp < DOUBLE_Emin ) /* It may be a denormal */ + { + int precision_loss; + + /* A denormal will always underflow. */ +#ifndef PECULIAR_486 + /* An 80486 is supposed to be able to generate + a denormal exception here, but... */ + if ( FPU_st0_ptr->exp <= EXP_UNDER ) + { + /* Underflow has priority. */ + if ( control_word & CW_Underflow ) + denormal_operand(); + } +#endif PECULIAR_486 + + tmp.exp += -DOUBLE_Emin + 52; /* largest exp to be 51 */ + + if ( (precision_loss = round_to_int(&tmp)) ) + { +#ifdef PECULIAR_486 + /* Did it round to a non-denormal ? */ + /* This behaviour might be regarded as peculiar, it appears + that the 80486 rounds to the dest precision, then + converts to decide underflow. */ + if ( !((tmp.sigh == 0x00100000) && (tmp.sigl == 0) && + (FPU_st0_ptr->sigl & 0x000007ff)) ) +#endif PECULIAR_486 + { + EXCEPTION(EX_Underflow); + /* This is a special case: see sec 16.2.5.1 of + the 80486 book */ + if ( !(control_word & CW_Underflow) ) + return 0; + } + EXCEPTION(precision_loss); + if ( !(control_word & CW_Precision) ) + return 0; + } + l[0] = tmp.sigl; + l[1] = tmp.sigh; + } + else + { + if ( tmp.sigl & 0x000007ff ) + { + switch (control_word & CW_RC) + { + case RC_RND: + /* Rounding can get a little messy.. */ + increment = ((tmp.sigl & 0x7ff) > 0x400) | /* nearest */ + ((tmp.sigl & 0xc00) == 0xc00); /* odd -> even */ + break; + case RC_DOWN: /* towards -infinity */ + increment = (tmp.sign == SIGN_POS) ? 0 : tmp.sigl & 0x7ff; + break; + case RC_UP: /* towards +infinity */ + increment = (tmp.sign == SIGN_POS) ? tmp.sigl & 0x7ff : 0; + break; + case RC_CHOP: + increment = 0; + break; + } + + /* Truncate the mantissa */ + tmp.sigl &= 0xfffff800; + + if ( increment ) + { + set_precision_flag_up(); + + if ( tmp.sigl >= 0xfffff800 ) + { + /* the sigl part overflows */ + if ( tmp.sigh == 0xffffffff ) + { + /* The sigh part overflows */ + tmp.sigh = 0x80000000; + exp++; + if (exp >= EXP_OVER) + goto overflow; + } + else + { + tmp.sigh ++; + } + tmp.sigl = 0x00000000; + } + else + { + /* We only need to increment sigl */ + tmp.sigl += 0x00000800; + } + } + else + set_precision_flag_down(); + } + + l[0] = (tmp.sigl >> 11) | (tmp.sigh << 21); + l[1] = ((tmp.sigh >> 11) & 0xfffff); + + if ( exp > DOUBLE_Emax ) + { + overflow: + EXCEPTION(EX_Overflow); + if ( !(control_word & CW_Overflow) ) + return 0; + set_precision_flag_up(); + if ( !(control_word & CW_Precision) ) + return 0; + + /* This is a special case: see sec 16.2.5.1 of the 80486 book */ + /* Overflow to infinity */ + l[0] = 0x00000000; /* Set to */ + l[1] = 0x7ff00000; /* + INF */ + } + else + { + /* Add the exponent */ + l[1] |= (((exp+DOUBLE_Ebias) & 0x7ff) << 20); + } + } + } + else if (FPU_st0_tag == TW_Zero) + { + /* Number is zero */ + l[0] = 0; + l[1] = 0; + } + else if (FPU_st0_tag == TW_Infinity) + { + l[0] = 0; + l[1] = 0x7ff00000; + } + else if (FPU_st0_tag == TW_NaN) + { + /* See if we can get a valid NaN from the FPU_REG */ + l[0] = (FPU_st0_ptr->sigl >> 11) | (FPU_st0_ptr->sigh << 21); + l[1] = ((FPU_st0_ptr->sigh >> 11) & 0xfffff); + if ( !(FPU_st0_ptr->sigh & 0x40000000) ) + { + /* It is a signalling NaN */ + EXCEPTION(EX_Invalid); + if ( !(control_word & CW_Invalid) ) + return 0; + l[1] |= (0x40000000 >> 11); + } + l[1] |= 0x7ff00000; + } + else if ( FPU_st0_tag == TW_Empty ) + { + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + if ( control_word & CW_Invalid ) + { + /* The masked response */ + /* Put out the QNaN indefinite */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); + put_fs_long(0, (unsigned long *) dfloat); + put_fs_long(0xfff80000, 1 + (unsigned long *) dfloat); + RE_ENTRANT_CHECK_ON; + return 1; + } + else + return 0; + } + if (FPU_st0_ptr->sign) + l[1] |= 0x80000000; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)dfloat,8); + put_fs_long(l[0], (unsigned long *)dfloat); + put_fs_long(l[1], 1 + (unsigned long *)dfloat); + RE_ENTRANT_CHECK_ON; + + return 1; +} + + +/* Put a float into user memory */ +int reg_store_single(overrides override) +{ + float *single = (float *)FPU_data_address; + long templ; + unsigned long increment = 0; /* avoid gcc warnings */ + + if (FPU_st0_tag == TW_Valid) + { + int exp; + FPU_REG tmp; + + reg_move(FPU_st0_ptr, &tmp); + exp = tmp.exp - EXP_BIAS; + + if ( exp < SINGLE_Emin ) + { + int precision_loss; + + /* A denormal will always underflow. */ +#ifndef PECULIAR_486 + /* An 80486 is supposed to be able to generate + a denormal exception here, but... */ + if ( FPU_st0_ptr->exp <= EXP_UNDER ) + { + /* Underflow has priority. */ + if ( control_word & CW_Underflow ) + denormal_operand(); + } +#endif PECULIAR_486 + + tmp.exp += -SINGLE_Emin + 23; /* largest exp to be 22 */ + + if ( (precision_loss = round_to_int(&tmp)) ) + { +#ifdef PECULIAR_486 + /* Did it round to a non-denormal ? */ + /* This behaviour might be regarded as peculiar, it appears + that the 80486 rounds to the dest precision, then + converts to decide underflow. */ + if ( !((tmp.sigl == 0x00800000) && + ((FPU_st0_ptr->sigh & 0x000000ff) || FPU_st0_ptr->sigl)) ) +#endif PECULIAR_486 + { + EXCEPTION(EX_Underflow); + /* This is a special case: see sec 16.2.5.1 of + the 80486 book */ + if ( !(control_word & EX_Underflow) ) + return 0; + } + EXCEPTION(precision_loss); + if ( !(control_word & EX_Precision) ) + return 0; + } + templ = tmp.sigl; + } + else + { + if ( tmp.sigl | (tmp.sigh & 0x000000ff) ) + { + unsigned long sigh = tmp.sigh; + unsigned long sigl = tmp.sigl; + + switch (control_word & CW_RC) + { + case RC_RND: + increment = ((sigh & 0xff) > 0x80) /* more than half */ + || (((sigh & 0xff) == 0x80) && sigl) /* more than half */ + || ((sigh & 0x180) == 0x180); /* round to even */ + break; + case RC_DOWN: /* towards -infinity */ + increment = (tmp.sign == SIGN_POS) + ? 0 : (sigl | (sigh & 0xff)); + break; + case RC_UP: /* towards +infinity */ + increment = (tmp.sign == SIGN_POS) + ? (sigl | (sigh & 0xff)) : 0; + break; + case RC_CHOP: + increment = 0; + break; + } + + /* Truncate part of the mantissa */ + tmp.sigl = 0; + + if (increment) + { + set_precision_flag_up(); + + if ( sigh >= 0xffffff00 ) + { + /* The sigh part overflows */ + tmp.sigh = 0x80000000; + exp++; + if ( exp >= EXP_OVER ) + goto overflow; + } + else + { + tmp.sigh &= 0xffffff00; + tmp.sigh += 0x100; + } + } + else + { + set_precision_flag_down(); + tmp.sigh &= 0xffffff00; /* Finish the truncation */ + } + } + + templ = (tmp.sigh >> 8) & 0x007fffff; + + if ( exp > SINGLE_Emax ) + { + overflow: + EXCEPTION(EX_Overflow); + if ( !(control_word & CW_Overflow) ) + return 0; + set_precision_flag_up(); + if ( !(control_word & CW_Precision) ) + return 0; + + /* This is a special case: see sec 16.2.5.1 of the 80486 book. */ + /* Masked respose is overflow to infinity. */ + templ = 0x7f800000; + } + else + templ |= ((exp+SINGLE_Ebias) & 0xff) << 23; + } + } + else if (FPU_st0_tag == TW_Zero) + { + templ = 0; + } + else if (FPU_st0_tag == TW_Infinity) + { + templ = 0x7f800000; + } + else if (FPU_st0_tag == TW_NaN) + { + /* See if we can get a valid NaN from the FPU_REG */ + templ = FPU_st0_ptr->sigh >> 8; + if ( !(FPU_st0_ptr->sigh & 0x40000000) ) + { + /* It is a signalling NaN */ + EXCEPTION(EX_Invalid); + if ( !(control_word & CW_Invalid) ) + return 0; + templ |= (0x40000000 >> 8); + } + templ |= 0x7f800000; + } + else if ( FPU_st0_tag == TW_Empty ) + { + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + if ( control_word & EX_Invalid ) + { + /* The masked response */ + /* Put out the QNaN indefinite */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)single,4); + put_fs_long(0xffc00000, (unsigned long *) single); + RE_ENTRANT_CHECK_ON; + return 1; + } + else + return 0; + } +#ifdef PARANOID + else + { + EXCEPTION(EX_INTERNAL|0x106); + return 0; + } +#endif + if (FPU_st0_ptr->sign) + templ |= 0x80000000; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)single,4); + put_fs_long(templ,(unsigned long *) single); + RE_ENTRANT_CHECK_ON; + + return 1; +} + + +/* Put a long long into user memory */ +int reg_store_int64(overrides override) +{ + long long *d = (long long *)FPU_data_address; + FPU_REG t; + long long tll; + int precision_loss; + + if ( FPU_st0_tag == TW_Empty ) + { + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + goto invalid_operand; + } + else if ( (FPU_st0_tag == TW_Infinity) || + (FPU_st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } + + reg_move(FPU_st0_ptr, &t); + precision_loss = round_to_int(&t); + ((long *)&tll)[0] = t.sigl; + ((long *)&tll)[1] = t.sigh; + if ( (precision_loss == 1) || + ((t.sigh & 0x80000000) && + !((t.sigh == 0x80000000) && (t.sigl == 0) && + (t.sign == SIGN_NEG))) ) + { + EXCEPTION(EX_Invalid); + /* This is a special case: see sec 16.2.5.1 of the 80486 book */ + invalid_operand: + if ( control_word & EX_Invalid ) + { + /* Produce something like QNaN "indefinite" */ + tll = 0x8000000000000000LL; + } + else + return 0; + } + else + { + if ( precision_loss ) + set_precision_flag(precision_loss); + if ( t.sign ) + tll = - tll; + } + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,(void *)d,8); + put_fs_long(((long *)&tll)[0],(unsigned long *) d); + put_fs_long(((long *)&tll)[1],1 + (unsigned long *) d); + RE_ENTRANT_CHECK_ON; + + return 1; +} + + +/* Put a long into user memory */ +int reg_store_int32(overrides override) +{ + long *d = (long *)FPU_data_address; + FPU_REG t; + int precision_loss; + + if ( FPU_st0_tag == TW_Empty ) + { + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + goto invalid_operand; + } + else if ( (FPU_st0_tag == TW_Infinity) || + (FPU_st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } + + reg_move(FPU_st0_ptr, &t); + precision_loss = round_to_int(&t); + if (t.sigh || + ((t.sigl & 0x80000000) && + !((t.sigl == 0x80000000) && (t.sign == SIGN_NEG))) ) + { + EXCEPTION(EX_Invalid); + /* This is a special case: see sec 16.2.5.1 of the 80486 book */ + invalid_operand: + if ( control_word & EX_Invalid ) + { + /* Produce something like QNaN "indefinite" */ + t.sigl = 0x80000000; + } + else + return 0; + } + else + { + if ( precision_loss ) + set_precision_flag(precision_loss); + if ( t.sign ) + t.sigl = -(long)t.sigl; + } + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,4); + put_fs_long(t.sigl, (unsigned long *) d); + RE_ENTRANT_CHECK_ON; + + return 1; +} + + +/* Put a short into user memory */ +int reg_store_int16(overrides override) +{ + short *d = (short *)FPU_data_address; + FPU_REG t; + int precision_loss; + + if ( FPU_st0_tag == TW_Empty ) + { + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + goto invalid_operand; + } + else if ( (FPU_st0_tag == TW_Infinity) || + (FPU_st0_tag == TW_NaN) ) + { + EXCEPTION(EX_Invalid); + goto invalid_operand; + } + + reg_move(FPU_st0_ptr, &t); + precision_loss = round_to_int(&t); + if (t.sigh || + ((t.sigl & 0xffff8000) && + !((t.sigl == 0x8000) && (t.sign == SIGN_NEG))) ) + { + EXCEPTION(EX_Invalid); + /* This is a special case: see sec 16.2.5.1 of the 80486 book */ + invalid_operand: + if ( control_word & EX_Invalid ) + { + /* Produce something like QNaN "indefinite" */ + t.sigl = 0x8000; + } + else + return 0; + } + else + { + if ( precision_loss ) + set_precision_flag(precision_loss); + if ( t.sign ) + t.sigl = -t.sigl; + } + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,2); + put_fs_word((short)t.sigl,(short *) d); + RE_ENTRANT_CHECK_ON; + + return 1; +} + + +/* Put a packed bcd array into user memory */ +int reg_store_bcd(overrides override) +{ + char *d = (char *)FPU_data_address; + FPU_REG t; + unsigned long long ll; + unsigned char b; + int i, precision_loss; + unsigned char sign = (FPU_st0_ptr->sign == SIGN_NEG) ? 0x80 : 0; + + if ( FPU_st0_tag == TW_Empty ) + { + /* Empty register (stack underflow) */ + EXCEPTION(EX_StackUnder); + goto invalid_operand; + } + + reg_move(FPU_st0_ptr, &t); + precision_loss = round_to_int(&t); + ll = significand(&t); + + /* Check for overflow, by comparing with 999999999999999999 decimal. */ + if ( (t.sigh > 0x0de0b6b3) || + ((t.sigh == 0x0de0b6b3) && (t.sigl > 0xa763ffff)) ) + { + EXCEPTION(EX_Invalid); + /* This is a special case: see sec 16.2.5.1 of the 80486 book */ + invalid_operand: + if ( control_word & CW_Invalid ) + { + /* Produce the QNaN "indefinite" */ + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,10); + for ( i = 0; i < 7; i++) + put_fs_byte(0, (unsigned char *) d+i); /* These bytes "undefined" */ + put_fs_byte(0xc0, (unsigned char *) d+7); /* This byte "undefined" */ + put_fs_byte(0xff, (unsigned char *) d+8); + put_fs_byte(0xff, (unsigned char *) d+9); + RE_ENTRANT_CHECK_ON; + return 1; + } + else + return 0; + } + else if ( precision_loss ) + { + /* Precision loss doesn't stop the data transfer */ + set_precision_flag(precision_loss); + } + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,10); + RE_ENTRANT_CHECK_ON; + for ( i = 0; i < 9; i++) + { + b = div_small(&ll, 10); + b |= (div_small(&ll, 10)) << 4; + RE_ENTRANT_CHECK_OFF; + put_fs_byte(b,(unsigned char *) d+i); + RE_ENTRANT_CHECK_ON; + } + RE_ENTRANT_CHECK_OFF; + put_fs_byte(sign,(unsigned char *) d+9); + RE_ENTRANT_CHECK_ON; + + return 1; +} + +/*===========================================================================*/ + +/* r gets mangled such that sig is int, sign: + it is NOT normalized */ +/* The return value (in eax) is zero if the result is exact, + if bits are changed due to rounding, truncation, etc, then + a non-zero value is returned */ +/* Overflow is signalled by a non-zero return value (in eax). + In the case of overflow, the returned significand always has the + the largest possible value */ +int round_to_int(FPU_REG *r) +{ + char very_big; + unsigned eax; + + if (r->tag == TW_Zero) + { + /* Make sure that zero is returned */ + significand(r) = 0; + return 0; /* o.k. */ + } + + if (r->exp > EXP_BIAS + 63) + { + r->sigl = r->sigh = ~0; /* The largest representable number */ + return 1; /* overflow */ + } + + eax = shrxs(&r->sigl, EXP_BIAS + 63 - r->exp); + very_big = !(~(r->sigh) | ~(r->sigl)); /* test for 0xfff...fff */ +#define half_or_more (eax & 0x80000000) +#define frac_part (eax) +#define more_than_half ((eax & 0x80000001) == 0x80000001) + switch (control_word & CW_RC) + { + case RC_RND: + if ( more_than_half /* nearest */ + || (half_or_more && (r->sigl & 1)) ) /* odd -> even */ + { + if ( very_big ) return 1; /* overflow */ + significand(r) ++; + return PRECISION_LOST_UP; + } + break; + case RC_DOWN: + if (frac_part && r->sign) + { + if ( very_big ) return 1; /* overflow */ + significand(r) ++; + return PRECISION_LOST_UP; + } + break; + case RC_UP: + if (frac_part && !r->sign) + { + if ( very_big ) return 1; /* overflow */ + significand(r) ++; + return PRECISION_LOST_UP; + } + break; + case RC_CHOP: + break; + } + + return eax ? PRECISION_LOST_DOWN : 0; + +} + +/*===========================================================================*/ + +char *fldenv(void) +{ + char *s = (char *)FPU_data_address; + unsigned short tag_word = 0; + unsigned char tag; + int i; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_READ, s, 0x1c); + control_word = get_fs_word((unsigned short *) s); + partial_status = get_fs_word((unsigned short *) (s+4)); + tag_word = get_fs_word((unsigned short *) (s+8)); + ip_offset = get_fs_long((unsigned long *) (s+0x0c)); + cs_selector = get_fs_long((unsigned long *) (s+0x10)); + data_operand_offset = get_fs_long((unsigned long *) (s+0x14)); + operand_selector = get_fs_long((unsigned long *) (s+0x18)); + RE_ENTRANT_CHECK_ON; + + top = (partial_status >> SW_Top_Shift) & 7; + + if ( partial_status & ~control_word & CW_Exceptions ) + partial_status |= (SW_Summary | SW_Backward); + else + partial_status &= ~(SW_Summary | SW_Backward); + + for ( i = 0; i < 8; i++ ) + { + tag = tag_word & 3; + tag_word >>= 2; + + if ( tag == 3 ) + /* New tag is empty. Accept it */ + regs[i].tag = TW_Empty; + else if ( regs[i].tag == TW_Empty ) + { + /* Old tag is empty and new tag is not empty. New tag is determined + by old reg contents */ + if ( regs[i].exp == EXP_BIAS - EXTENDED_Ebias ) + { + if ( !(regs[i].sigl | regs[i].sigh) ) + regs[i].tag = TW_Zero; + else + regs[i].tag = TW_Valid; + } + else if ( regs[i].exp == 0x7fff + EXP_BIAS - EXTENDED_Ebias ) + { + if ( !((regs[i].sigh & ~0x80000000) | regs[i].sigl) ) + regs[i].tag = TW_Infinity; + else + regs[i].tag = TW_NaN; + } + else + regs[i].tag = TW_Valid; + } + /* Else old tag is not empty and new tag is not empty. Old tag + remains correct */ + } + + /* Ensure that the values just loaded are not changed by + fix-up operations. */ + NO_NET_DATA_EFFECT; + NO_NET_INSTR_EFFECT; + + return s + 0x1c; +} + + +void frstor(void) +{ + int i, stnr; + unsigned char tag; + char *s = fldenv(); + + for ( i = 0; i < 8; i++ ) + { + /* Load each register. */ + FPU_data_address = (void *)(s+i*10); + reg_load_extended((overrides){0,0}); + stnr = (i+top) & 7; + tag = regs[stnr].tag; /* Derived from the loaded tag word. */ + reg_move(&FPU_loaded_data, ®s[stnr]); + if ( tag == TW_Empty ) /* The loaded data over-rides all other cases. */ + regs[stnr].tag = tag; + } + + /* Reverse the effect which loading the registers had on the + data pointer */ + NO_NET_DATA_EFFECT; + +} + + +unsigned short tag_word(void) +{ + unsigned short word = 0; + unsigned char tag; + int i; + + for ( i = 7; i >= 0; i-- ) + { + switch ( tag = regs[i].tag ) + { + case TW_Valid: + if ( regs[i].exp <= (EXP_BIAS - EXTENDED_Ebias) ) + tag = 2; + break; + case TW_Infinity: + case TW_NaN: + tag = 2; + break; + case TW_Empty: + tag = 3; + break; + /* TW_Zero already has the correct value */ + } + word <<= 2; + word |= tag; + } + return word; +} + + +char *fstenv(void) +{ + char *d = (char *)FPU_data_address; + + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,28); +#ifdef PECULIAR_486 + /* An 80486 sets all the reserved bits to 1. */ + put_fs_long(0xffff0040 | (control_word & ~0xe080), (unsigned long *) d); + put_fs_long(0xffff0000 | status_word(), (unsigned long *) (d+4)); + put_fs_long(0xffff0000 | tag_word(), (unsigned long *) (d+8)); +#else + put_fs_word(control_word, (unsigned short *) d); + put_fs_word(status_word(), (unsigned short *) (d+4)); + put_fs_word(tag_word(), (unsigned short *) (d+8)); +#endif PECULIAR_486 + put_fs_long(ip_offset, (unsigned long *) (d+0x0c)); + put_fs_long(cs_selector & ~0xf8000000, (unsigned long *) (d+0x10)); + put_fs_long(data_operand_offset, (unsigned long *) (d+0x14)); +#ifdef PECULIAR_486 + /* An 80486 sets all the reserved bits to 1. */ + put_fs_long(0xffff0000 | operand_selector, (unsigned long *) (d+0x18)); +#else + put_fs_long(operand_selector, (unsigned long *) (d+0x18)); +#endif PECULIAR_486 + RE_ENTRANT_CHECK_ON; + + control_word |= CW_Exceptions; + partial_status &= ~(SW_Summary | SW_Backward); + + return d + 0x1c; +} + + +void fsave(void) +{ + char *d; + int i; + + d = fstenv(); + RE_ENTRANT_CHECK_OFF; + FPU_verify_area(VERIFY_WRITE,d,80); + RE_ENTRANT_CHECK_ON; + for ( i = 0; i < 8; i++ ) + write_to_extended(®s[(top + i) & 7], d + 10 * i); + + finit(); + +} + +/*===========================================================================*/ + +/* + A call to this function must be preceeded by a call to + FPU_verify_area() to verify access to the 10 bytes at d + */ +static void write_to_extended(FPU_REG *rp, char *d) +{ + long e; + FPU_REG tmp; + + e = rp->exp - EXP_BIAS + EXTENDED_Ebias; + +#ifdef PARANOID + switch ( rp->tag ) + { + case TW_Zero: + if ( rp->sigh | rp->sigl | e ) + EXCEPTION(EX_INTERNAL | 0x114); + break; + case TW_Infinity: + case TW_NaN: + if ( (e ^ 0x7fff) | !(rp->sigh & 0x80000000) ) + EXCEPTION(EX_INTERNAL | 0x114); + break; + default: + if (e > 0x7fff || e < -63) + EXCEPTION(EX_INTERNAL | 0x114); + } +#endif PARANOID + + /* + All numbers except denormals are stored internally in a + format which is compatible with the extended real number + format. + */ + if ( e > 0 ) + { + /* just copy the reg */ + RE_ENTRANT_CHECK_OFF; + put_fs_long(rp->sigl, (unsigned long *) d); + put_fs_long(rp->sigh, (unsigned long *) (d + 4)); + RE_ENTRANT_CHECK_ON; + } + else + { + /* + The number is a de-normal stored as a normal using our + extra exponent range, or is Zero. + Convert it back to a de-normal, or leave it as Zero. + */ + reg_move(rp, &tmp); + tmp.exp += -EXTENDED_Emin + 63; /* largest exp to be 63 */ + round_to_int(&tmp); + e = 0; + RE_ENTRANT_CHECK_OFF; + put_fs_long(tmp.sigl, (unsigned long *) d); + put_fs_long(tmp.sigh, (unsigned long *) (d + 4)); + RE_ENTRANT_CHECK_ON; + } + e |= rp->sign == SIGN_POS ? 0 : 0x8000; + RE_ENTRANT_CHECK_OFF; + put_fs_word(e, (unsigned short *) (d + 8)); + RE_ENTRANT_CHECK_ON; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_mul.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_mul.c new file mode 100644 index 000000000..cd21bebd1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_mul.c @@ -0,0 +1,106 @@ +/*---------------------------------------------------------------------------+ + | reg_mul.c | + | | + | Multiply one FPU_REG by another, put the result in a destination FPU_REG. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | The destination may be any FPU_REG, including one of the source FPU_REGs. | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "reg_constant.h" +#include "fpu_emu.h" +#include "fpu_system.h" + + +/* This routine must be called with non-empty source registers */ +int reg_mul(FPU_REG const *a, FPU_REG const *b, + FPU_REG *dest, unsigned int control_w) +{ + char saved_sign = dest->sign; + char sign = (a->sign ^ b->sign); + + if (!(a->tag | b->tag)) + { + /* Both regs Valid, this should be the most common case. */ + dest->sign = sign; + if ( reg_u_mul(a, b, dest, control_w) ) + { + dest->sign = saved_sign; + return 1; + } + return 0; + } + else if ((a->tag <= TW_Zero) && (b->tag <= TW_Zero)) + { +#ifdef DENORM_OPERAND + if ( ((b->tag == TW_Valid) && (b->exp <= EXP_UNDER)) || + ((a->tag == TW_Valid) && (a->exp <= EXP_UNDER)) ) + { + if ( denormal_operand() ) return 1; + } +#endif DENORM_OPERAND + /* Must have either both arguments == zero, or + one valid and the other zero. + The result is therefore zero. */ + reg_move(&CONST_Z, dest); +#ifdef PECULIAR_486 + /* The 80486 book says that the answer is +0, but a real + 80486 appears to behave this way... */ + dest->sign = sign; +#endif PECULIAR_486 + return 0; + } + else + { + /* Must have infinities, NaNs, etc */ + if ( (a->tag == TW_NaN) || (b->tag == TW_NaN) ) + { return real_2op_NaN(a, b, dest); } + else if (a->tag == TW_Infinity) + { + if (b->tag == TW_Zero) + { return arith_invalid(dest); } /* Zero*Infinity is invalid */ + else + { +#ifdef DENORM_OPERAND + if ( (b->tag == TW_Valid) && (b->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(a, dest); + dest->sign = sign; + } + return 0; + } + else if (b->tag == TW_Infinity) + { + if (a->tag == TW_Zero) + { return arith_invalid(dest); } /* Zero*Infinity is invalid */ + else + { +#ifdef DENORM_OPERAND + if ( (a->tag == TW_Valid) && (a->exp <= EXP_UNDER) && + denormal_operand() ) + return 1; +#endif DENORM_OPERAND + reg_move(b, dest); + dest->sign = sign; + } + return 0; + } +#ifdef PARANOID + else + { + EXCEPTION(EX_INTERNAL|0x102); + return 1; + } +#endif PARANOID + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_norm.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_norm.S new file mode 100644 index 000000000..9b7a9d77d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_norm.S @@ -0,0 +1,150 @@ +/*---------------------------------------------------------------------------+ + | reg_norm.S | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Normalize the value in a FPU_REG. | + | | + | Call from C as: | + | void normalize(FPU_REG *n) | + | | + | void normalize_nuo(FPU_REG *n) | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_asm.h" + + +.text + + .align 2,144 +.globl _normalize + +_normalize: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl PARAM1,%ebx + +#ifdef PARANOID + cmpb TW_Valid,TAG(%ebx) + je L_ok + + pushl $0x220 + call _exception + addl $4,%esp + +L_ok: +#endif PARANOID + + 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 %eax,%eax + jz L_zero /* The contents are zero */ + + movl %eax,%edx + xorl %eax,%eax + subl $32,EXP(%ebx) /* This can cause an underflow */ + +/* We need to shift left by 1 - 31 bits */ +L_shift_1: + bsrl %edx,%ecx /* get the required shift in %ecx */ + subl $31,%ecx + negl %ecx + shld %cl,%eax,%edx + shl %cl,%eax + subl %ecx,EXP(%ebx) /* This can cause an underflow */ + + movl %edx,SIGH(%ebx) + movl %eax,SIGL(%ebx) + +L_done: + cmpl EXP_OVER,EXP(%ebx) + jge L_overflow + + cmpl EXP_UNDER,EXP(%ebx) + jle L_underflow + +L_exit: + popl %ebx + leave + ret + + +L_zero: + movl EXP_UNDER,EXP(%ebx) + movb TW_Zero,TAG(%ebx) + jmp L_exit + +L_underflow: + push %ebx + call _arith_underflow + pop %ebx + jmp L_exit + +L_overflow: + push %ebx + call _arith_overflow + pop %ebx + jmp L_exit + + + +/* Normalise without reporting underflow or overflow */ + .align 2,144 +.globl _normalize_nuo + +_normalize_nuo: + pushl %ebp + movl %esp,%ebp + pushl %ebx + + movl PARAM1,%ebx + +#ifdef PARANOID + cmpb TW_Valid,TAG(%ebx) + je L_ok_nuo + + pushl $0x221 + call _exception + addl $4,%esp + +L_ok_nuo: +#endif PARANOID + + movl SIGH(%ebx),%edx + movl SIGL(%ebx),%eax + + orl %edx,%edx /* ms bits */ + js L_exit /* Already normalized */ + jnz L_nuo_shift_1 /* Shift left 1 - 31 bits */ + + orl %eax,%eax + jz L_zero /* The contents are zero */ + + movl %eax,%edx + xorl %eax,%eax + subl $32,EXP(%ebx) /* This can cause an underflow */ + +/* We need to shift left by 1 - 31 bits */ +L_nuo_shift_1: + bsrl %edx,%ecx /* get the required shift in %ecx */ + subl $31,%ecx + negl %ecx + shld %cl,%eax,%edx + shl %cl,%eax + subl %ecx,EXP(%ebx) /* This can cause an underflow */ + + movl %edx,SIGH(%ebx) + movl %eax,SIGL(%ebx) + jmp L_exit + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_round.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_round.S new file mode 100644 index 000000000..32f2b2ebb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_round.S @@ -0,0 +1,666 @@ + .file "reg_round.S" +/*---------------------------------------------------------------------------+ + | reg_round.S | + | | + | Rounding/truncation/etc for FPU basic arithmetic functions. | + | | + | Copyright (C) 1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | This code has four possible entry points. | + | The following must be entered by a jmp intruction: | + | fpu_reg_round, fpu_reg_round_sqrt, and fpu_Arith_exit. | + | | + | The _round_reg entry point is intended to be used by C code. | + | From C, call as: | + | void round_reg(FPU_REG *arg, unsigned int extent, unsigned int control_w) | + | | + | For correct "up" and "down" rounding, the argument must have the correct | + | sign. | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Four entry points. | + | | + | Needed by both the fpu_reg_round and fpu_reg_round_sqrt entry points: | + | %eax:%ebx 64 bit significand | + | %edx 32 bit extension of the significand | + | %edi pointer to an FPU_REG for the result to be stored | + | stack calling function must have set up a C stack frame and | + | pushed %esi, %edi, and %ebx | + | | + | Needed just for the fpu_reg_round_sqrt entry point: | + | %cx A control word in the same format as the FPU control word. | + | Otherwise, PARAM4 must give such a value. | + | | + | | + | The significand and its extension are assumed to be exact in the | + | following sense: | + | If the significand by itself is the exact result then the significand | + | extension (%edx) must contain 0, otherwise the significand extension | + | must be non-zero. | + | If the significand extension is non-zero then the significand is | + | smaller than the magnitude of the correct exact result by an amount | + | greater than zero and less than one ls bit of the significand. | + | The significand extension is only required to have three possible | + | non-zero values: | + | less than 0x80000000 <=> the significand is less than 1/2 an ls | + | bit smaller than the magnitude of the | + | true exact result. | + | exactly 0x80000000 <=> the significand is exactly 1/2 an ls bit | + | smaller than the magnitude of the true | + | exact result. | + | greater than 0x80000000 <=> the significand is more than 1/2 an ls | + | bit smaller than the magnitude of the | + | true exact result. | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | The code in this module has become quite complex, but it should handle | + | all of the FPU flags which are set at this stage of the basic arithmetic | + | computations. | + | There are a few rare cases where the results are not set identically to | + | a real FPU. These require a bit more thought because at this stage the | + | results of the code here appear to be more consistent... | + | This may be changed in a future version. | + +---------------------------------------------------------------------------*/ + + +#include "fpu_asm.h" +#include "exception.h" +#include "control_w.h" + +/* Flags for FPU_bits_lost */ +#define LOST_DOWN $1 +#define LOST_UP $2 + +/* Flags for FPU_denormal */ +#define DENORMAL $1 +#define UNMASKED_UNDERFLOW $2 + + +#ifdef REENTRANT_FPU +/* Make the code re-entrant by putting + local storage on the stack: */ +#define FPU_bits_lost (%esp) +#define FPU_denormal 1(%esp) + +#else +/* Not re-entrant, so we can gain speed by putting + local storage in a static area: */ +.data + .align 2,0 +FPU_bits_lost: + .byte 0 +FPU_denormal: + .byte 0 +#endif REENTRANT_FPU + + +.text + .align 2,144 +.globl fpu_reg_round +.globl fpu_reg_round_sqrt +.globl fpu_Arith_exit +.globl _round_reg + +/* Entry point when called from C */ +_round_reg: + pushl %ebp + movl %esp,%ebp + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%edi + movl SIGH(%edi),%eax + movl SIGL(%edi),%ebx + movl PARAM2,%edx + movl PARAM3,%ecx + jmp fpu_reg_round_sqrt + +fpu_reg_round: /* Normal entry point */ + movl PARAM4,%ecx + +fpu_reg_round_sqrt: /* Entry point from wm_sqrt.S */ + +#ifdef REENTRANT_FPU + pushl %ebx /* adjust the stack pointer */ +#endif REENTRANT_FPU + +#ifdef PARANOID +/* 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 */ + + movb $0,FPU_denormal /* 0 -> not a de-normal */ + +xDenorm_done: + movb $0,FPU_bits_lost /* No bits yet lost in rounding */ + + movl %ecx,%esi + andl CW_PC,%ecx + cmpl PR_64_BITS,%ecx + je LRound_To_64 + + cmpl PR_53_BITS,%ecx + je LRound_To_53 + + cmpl PR_24_BITS,%ecx + je LRound_To_24 + +#ifdef PARANOID + jmp L_bugged /* There is no bug, just a bad control word */ +#endif PARANOID + + +/* Round etc to 24 bit precision */ +LRound_To_24: + movl %esi,%ecx + andl CW_RC,%ecx + cmpl RC_RND,%ecx + je LRound_nearest_24 + + cmpl RC_CHOP,%ecx + je LCheck_truncate_24 + + cmpl RC_UP,%ecx /* Towards +infinity */ + je LUp_24 + + cmpl RC_DOWN,%ecx /* Towards -infinity */ + je LDown_24 + +#ifdef PARANOID + jmp L_bugged +#endif PARANOID + +LUp_24: + cmpb SIGN_POS,SIGN(%edi) + 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 */ + +LCheck_24_round_up: + movl %eax,%ecx + andl $0x000000ff,%ecx + orl %ebx,%ecx + orl %edx,%ecx + jnz LDo_24_round_up + jmp LRe_normalise + +LRound_nearest_24: + /* 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 */ + + jne LGreater_Half_24 /* greater than half, increment needed */ + + /* Possibly half, we need to check the ls bits */ + orl %ebx,%ebx + jnz LGreater_Half_24 /* greater than half, increment needed */ + + orl %edx,%edx + jnz LGreater_Half_24 /* greater than half, increment needed */ + + /* 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 */ +LDo_24_round_up: + andl $0xffffff00,%eax /* Truncate to 24 bits */ + xorl %ebx,%ebx + movb LOST_UP,FPU_bits_lost + addl $0x00000100,%eax + jmp LCheck_Round_Overflow + +LCheck_truncate_24: + movl %eax,%ecx + andl $0x000000ff,%ecx + orl %ebx,%ecx + orl %edx,%ecx + jz LRe_normalise /* No truncation needed */ + +LDo_truncate_24: + andl $0xffffff00,%eax /* Truncate to 24 bits */ + xorl %ebx,%ebx + movb LOST_DOWN,FPU_bits_lost + jmp LRe_normalise + + +/* Round etc to 53 bit precision */ +LRound_To_53: + movl %esi,%ecx + andl CW_RC,%ecx + cmpl RC_RND,%ecx + je LRound_nearest_53 + + cmpl RC_CHOP,%ecx + je LCheck_truncate_53 + + cmpl RC_UP,%ecx /* Towards +infinity */ + je LUp_53 + + cmpl RC_DOWN,%ecx /* Towards -infinity */ + je LDown_53 + +#ifdef PARANOID + jmp L_bugged +#endif PARANOID + +LUp_53: + cmpb SIGN_POS,SIGN(%edi) + 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 */ + +LCheck_53_round_up: + movl %ebx,%ecx + andl $0x000007ff,%ecx + orl %edx,%ecx + jnz LDo_53_round_up + jmp LRe_normalise + +LRound_nearest_53: + /* 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 */ + + jnz LGreater_Half_53 /* greater than half, increment needed */ + + /* Possibly half, we need to check the ls bits */ + orl %edx,%edx + jnz LGreater_Half_53 /* greater than half, increment needed */ + + /* 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 */ +LDo_53_round_up: + movb LOST_UP,FPU_bits_lost + andl $0xfffff800,%ebx /* Truncate to 53 bits */ + addl $0x00000800,%ebx + adcl $0,%eax + jmp LCheck_Round_Overflow + +LCheck_truncate_53: + movl %ebx,%ecx + andl $0x000007ff,%ecx + orl %edx,%ecx + jz LRe_normalise + +LTruncate_53: + movb LOST_DOWN,FPU_bits_lost + andl $0xfffff800,%ebx /* Truncate to 53 bits */ + jmp LRe_normalise + + +/* Round etc to 64 bit precision */ +LRound_To_64: + movl %esi,%ecx + andl CW_RC,%ecx + cmpl RC_RND,%ecx + je LRound_nearest_64 + + cmpl RC_CHOP,%ecx + je LCheck_truncate_64 + + cmpl RC_UP,%ecx /* Towards +infinity */ + je LUp_64 + + cmpl RC_DOWN,%ecx /* Towards -infinity */ + je LDown_64 + +#ifdef PARANOID + jmp L_bugged +#endif PARANOID + +LUp_64: + cmpb SIGN_POS,SIGN(%edi) + jne LCheck_truncate_64 /* If negative then up==truncate */ + + orl %edx,%edx + jnz LDo_64_round_up + jmp LRe_normalise + +LDown_64: + cmpb SIGN_POS,SIGN(%edi) + je LCheck_truncate_64 /* If positive then down==truncate */ + + orl %edx,%edx + jnz LDo_64_round_up + jmp LRe_normalise + +LRound_nearest_64: + cmpl $0x80000000,%edx + jc LCheck_truncate_64 + + jne LDo_64_round_up + + /* Now test for round-to-even */ + testb $1,%ebx + jz LCheck_truncate_64 + +LDo_64_round_up: + movb LOST_UP,FPU_bits_lost + addl $1,%ebx + adcl $0,%eax + +LCheck_Round_Overflow: + jnc LRe_normalise + + /* Overflow, adjust the result (significand to 1.0) */ + rcrl $1,%eax + rcrl $1,%ebx + incl EXP(%edi) + jmp LRe_normalise + +LCheck_truncate_64: + orl %edx,%edx + jz LRe_normalise + +LTruncate_64: + movb LOST_DOWN,FPU_bits_lost + +LRe_normalise: + testb $0xff,FPU_denormal + jnz xNormalise_result + +xL_Normalised: + cmpb LOST_UP,FPU_bits_lost + je xL_precision_lost_up + + cmpb LOST_DOWN,FPU_bits_lost + je xL_precision_lost_down + +xL_no_precision_loss: + /* store the result */ + movb TW_Valid,TAG(%edi) + +xL_Store_significand: + movl %eax,SIGH(%edi) + movl %ebx,SIGL(%edi) + + xorl %eax,%eax /* No errors detected. */ + + cmpl EXP_OVER,EXP(%edi) + jge L_overflow + +fpu_reg_round_exit: +#ifdef REENTRANT_FPU + popl %ebx /* adjust the stack pointer */ +#endif REENTRANT_FPU + +fpu_Arith_exit: + popl %ebx + popl %edi + popl %esi + leave + ret + + +/* + * 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. + */ +xL_precision_lost_down: + push %eax + call _set_precision_flag_down + popl %eax + 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... + */ +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. */ + + movb DENORMAL,FPU_denormal + + pushl %ecx /* Save */ + movl EXP_UNDER+1,%ecx + subl EXP(%edi),%ecx + + cmpl $64,%ecx /* shrd only works for 0..31 bits */ + jnc xDenorm_shift_more_than_63 + + 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 + */ + addl %ecx,EXP(%edi) + orl %edx,%edx /* extension */ + setne %ch /* Save whether %edx is non-zero */ + xorl %edx,%edx + shrd %cl,%ebx,%edx + shrd %cl,%eax,%ebx + shr %cl,%eax + orb %ch,%dl + popl %ecx + jmp xDenorm_done + +/* Shift by [32..63] bits */ +xDenorm_shift_more_than_32: + addl %ecx,EXP(%edi) + subb $32,%cl + orl %edx,%edx + setne %ch + orb %ch,%bl + xorl %edx,%edx + shrd %cl,%ebx,%edx + shrd %cl,%eax,%ebx + shr %cl,%eax + orl %edx,%edx /* test these 32 bits */ + setne %cl + orb %ch,%bl + orb %cl,%bl + movl %ebx,%edx + movl %eax,%ebx + xorl %eax,%eax + popl %ecx + jmp xDenorm_done + +/* Shift by [64..) bits */ +xDenorm_shift_more_than_63: + cmpl $64,%ecx + jne xDenorm_shift_more_than_64 + +/* Exactly 64 bit shift */ + addl %ecx,EXP(%edi) + xorl %ecx,%ecx + orl %edx,%edx + setne %cl + orl %ebx,%ebx + setne %ch + orb %ch,%cl + orb %cl,%al + movl %eax,%edx + xorl %eax,%eax + xorl %ebx,%ebx + popl %ecx + jmp xDenorm_done + +xDenorm_shift_more_than_64: + movl EXP_UNDER+1,EXP(%edi) +/* This is easy, %eax must be non-zero, so.. */ + movl $1,%edx + xorl %eax,%eax + xorl %ebx,%ebx + popl %ecx + jmp xDenorm_done + + +xUnmasked_underflow: + movb UNMASKED_UNDERFLOW,FPU_denormal + jmp xDenorm_done + + +/* Undo the de-normalisation. */ +xNormalise_result: + cmpb UNMASKED_UNDERFLOW,FPU_denormal + je xSignal_underflow + +/* The number must be a denormal if we got here. */ +#ifdef PARANOID + /* But check it... just in case. */ + cmpl EXP_UNDER+1,EXP(%edi) + 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 */ +#endif PECULIAR_486 + + orl %eax,%eax /* ms bits */ + js xL_Normalised /* No longer a denormal */ + + jnz LNormalise_shift_up_to_31 /* Shift left 0 - 31 bits */ + + orl %ebx,%ebx + jz L_underflow_to_zero /* The contents are zero */ + +/* Shift left 32 - 63 bits */ + movl %ebx,%eax + xorl %ebx,%ebx + subl $32,EXP(%edi) + +LNormalise_shift_up_to_31: + bsrl %eax,%ecx /* get the required shift in %ecx */ + subl $31,%ecx + negl %ecx + shld %cl,%ebx,%eax + shl %cl,%ebx + subl %ecx,EXP(%edi) + +LNormalise_shift_done: + testb $0xff,FPU_bits_lost /* bits lost == underflow */ + jz xL_Normalised + + /* There must be a masked underflow */ + push %eax + pushl EX_Underflow + call _exception + popl %eax + popl %eax + jmp xL_Normalised + + +/* + * The operations resulted in a number too small to represent. + * Masked response. + */ +L_underflow_to_zero: + push %eax + call _set_precision_flag_down + popl %eax + + push %eax + pushl EX_Underflow + call _exception + popl %eax + popl %eax + +/* Reduce the exponent to EXP_UNDER */ + movl EXP_UNDER,EXP(%edi) + movb TW_Zero,TAG(%edi) + jmp xL_Store_significand + + +/* The operations resulted in a number too large to represent. */ +L_overflow: + push %edi + call _arith_overflow + pop %edi + jmp fpu_reg_round_exit + + +xSignal_underflow: + /* 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 */ + addl $(3*(1<<13)),EXP(%edi) + push %eax + pushl EX_Underflow + call EXCEPTION + popl %eax + popl %eax + jmp xL_Normalised + + +#ifdef PARANOID +/* If we ever get here then we have problems! */ +L_bugged: + pushl EX_INTERNAL|0x201 + call EXCEPTION + popl %ebx + jmp L_exception_exit + +L_norm_bugged: + pushl EX_INTERNAL|0x216 + call EXCEPTION + popl %ebx + jmp L_exception_exit + +L_entry_bugged: + pushl EX_INTERNAL|0x217 + call EXCEPTION + popl %ebx +L_exception_exit: + mov $1,%eax + jmp fpu_reg_round_exit +#endif PARANOID diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_add.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_add.S new file mode 100644 index 000000000..4410f8fd4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_add.S @@ -0,0 +1,189 @@ + .file "reg_u_add.S" +/*---------------------------------------------------------------------------+ + | reg_u_add.S | + | | + | Add two valid (TW_Valid) FPU_REG numbers, of the same sign, and put the | + | result in a destination FPU_REG. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void reg_u_add(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | + | int control_w) | + | | + +---------------------------------------------------------------------------*/ + +/* + | Kernel addition routine reg_u_add(reg *arg1, reg *arg2, reg *answ). + | Takes two valid reg f.p. numbers (TW_Valid), which are + | treated as unsigned numbers, + | and returns their sum as a TW_Valid or TW_S f.p. number. + | The returned number is normalized. + | Basic checks are performed if PARANOID is defined. + */ + +#include "exception.h" +#include "fpu_asm.h" +#include "control_w.h" + +.text + .align 2,144 +.globl _reg_u_add +_reg_u_add: + pushl %ebp + movl %esp,%ebp + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%esi /* source 1 */ + movl PARAM2,%edi /* source 2 */ + +#ifdef DENORM_OPERAND + cmpl EXP_UNDER,EXP(%esi) + jg xOp1_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp1_not_denorm: + cmpl EXP_UNDER,EXP(%edi) + jg xOp2_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp2_not_denorm: +#endif DENORM_OPERAND + + movl EXP(%esi),%ecx + subl EXP(%edi),%ecx /* exp1 - exp2 */ + jge L_arg1_larger + + /* num1 is smaller */ + movl SIGL(%esi),%ebx + movl SIGH(%esi),%eax + + movl %edi,%esi + negw %cx + jmp L_accum_loaded + +L_arg1_larger: + /* num1 has larger or equal exponent */ + movl SIGL(%edi),%ebx + movl SIGH(%edi),%eax + +L_accum_loaded: + movl PARAM3,%edi /* destination */ +/* movb SIGN(%esi),%dl + movb %dl,SIGN(%edi) */ /* Copy the sign from the first arg */ + + + movl EXP(%esi),%edx + movl %edx,EXP(%edi) /* Copy exponent to destination */ + + xorl %edx,%edx /* clear the extension */ + +#ifdef PARANOID + testl $0x80000000,%eax + je L_bugged + + testl $0x80000000,SIGH(%esi) + je L_bugged +#endif PARANOID + +/* 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 + +/* less than 32 bits */ + shrd %cl,%ebx,%edx + shrd %cl,%eax,%ebx + shr %cl,%eax + jmp L_shift_done + +L_more_than_31: + cmpw $64,%cx + jnc L_more_than_63 + + subb $32,%cl + jz L_exactly_32 + + shrd %cl,%eax,%edx + shr %cl,%eax + orl %ebx,%ebx + jz L_more_31_no_low /* none of the lowest bits is set */ + + orl $1,%edx /* record the fact in the extension */ + +L_more_31_no_low: + movl %eax,%ebx + xorl %eax,%eax + jmp L_shift_done + +L_exactly_32: + movl %ebx,%edx + movl %eax,%ebx + xorl %eax,%eax + jmp L_shift_done + +L_more_than_63: + cmpw $65,%cx + jnc L_more_than_64 + + movl %eax,%edx + orl %ebx,%ebx + jz L_more_63_no_low + + orl $1,%edx + jmp L_more_63_no_low + +L_more_than_64: + movl $1,%edx /* The shifted nr always at least one '1' */ + +L_more_63_no_low: + xorl %ebx,%ebx + xorl %eax,%eax + +L_shift_done: + /* Now do the addition */ + addl SIGL(%esi),%ebx + adcl SIGH(%esi),%eax + jnc L_round_the_result + + /* Overflow, adjust the result */ + rcrl $1,%eax + rcrl $1,%ebx + rcrl $1,%edx + jnc L_no_bit_lost + + orl $1,%edx + +L_no_bit_lost: + incl EXP(%edi) + +L_round_the_result: + jmp fpu_reg_round /* Round the result */ + + + +#ifdef PARANOID +/* If we ever get here then we have problems! */ +L_bugged: + pushl EX_INTERNAL|0x201 + call EXCEPTION + pop %ebx + jmp L_exit +#endif PARANOID + + +L_exit: + popl %ebx + popl %edi + popl %esi + leave + ret diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_div.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_div.S new file mode 100644 index 000000000..0098324d6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_div.S @@ -0,0 +1,477 @@ + .file "reg_u_div.S" +/*---------------------------------------------------------------------------+ + | reg_u_div.S | + | | + | Core division routines | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Kernel for the division routines. | + | | + | void reg_u_div(FPU_REG *a, FPU_REG *a, | + | FPU_REG *dest, unsigned int control_word) | + | | + | Does not compute the destination exponent, but does adjust it. | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "fpu_asm.h" +#include "control_w.h" + + +/* #define dSIGL(x) (x) */ +/* #define dSIGH(x) 4(x) */ + + +#ifdef REENTRANT_FPU +/* + Local storage on the stack: + Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 + Overflow flag: ovfl_flag + */ +#define FPU_accum_3 -4(%ebp) +#define FPU_accum_2 -8(%ebp) +#define FPU_accum_1 -12(%ebp) +#define FPU_accum_0 -16(%ebp) +#define FPU_result_1 -20(%ebp) +#define FPU_result_2 -24(%ebp) +#define FPU_ovfl_flag -28(%ebp) + +#else +.data +/* + Local storage in a static area: + Result: FPU_accum_3:FPU_accum_2:FPU_accum_1:FPU_accum_0 + Overflow flag: ovfl_flag + */ + .align 2,0 +FPU_accum_3: + .long 0 +FPU_accum_2: + .long 0 +FPU_accum_1: + .long 0 +FPU_accum_0: + .long 0 +FPU_result_1: + .long 0 +FPU_result_2: + .long 0 +FPU_ovfl_flag: + .byte 0 +#endif REENTRANT_FPU + + +.text + .align 2,144 + +.globl _reg_u_div + +.globl _divide_kernel + +_reg_u_div: + pushl %ebp + movl %esp,%ebp +#ifdef REENTRANT_FPU + subl $28,%esp +#endif REENTRANT_FPU + + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%esi /* pointer to num */ + movl PARAM2,%ebx /* pointer to denom */ + movl PARAM3,%edi /* pointer to answer */ + +#ifdef DENORM_OPERAND + movl EXP(%esi),%eax + cmpl EXP_UNDER,%eax + jg xOp1_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp1_not_denorm: + movl EXP(%ebx),%eax + cmpl EXP_UNDER,%eax + jg xOp2_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp2_not_denorm: +#endif DENORM_OPERAND + +_divide_kernel: +#ifdef PARANOID +/* testl $0x80000000, SIGH(%esi) // Dividend */ +/* je L_bugged */ + testl $0x80000000, SIGH(%ebx) /* Divisor */ + je L_bugged +#endif PARANOID + +/* Check if the divisor can be treated as having just 32 bits */ + cmpl $0,SIGL(%ebx) + jnz L_Full_Division /* Can't do a quick divide */ + +/* We should be able to zip through the division here */ + movl SIGH(%ebx),%ecx /* The divisor */ + movl SIGH(%esi),%edx /* Dividend */ + movl SIGL(%esi),%eax /* Dividend */ + + cmpl %ecx,%edx + setaeb FPU_ovfl_flag /* Keep a record */ + jb L_no_adjust + + subl %ecx,%edx /* Prevent the overflow */ + +L_no_adjust: + /* Divide the 64 bit number by the 32 bit denominator */ + divl %ecx + movl %eax,FPU_result_2 + + /* Work on the remainder of the first division */ + xorl %eax,%eax + divl %ecx + movl %eax,FPU_result_1 + + /* Work on the remainder of the 64 bit division */ + xorl %eax,%eax + divl %ecx + + testb $255,FPU_ovfl_flag /* was the num > denom ? */ + je L_no_overflow + + /* Do the shifting here */ + /* increase the exponent */ + incl EXP(%edi) + + /* shift the mantissa right one bit */ + stc /* To set the ms bit */ + rcrl FPU_result_2 + rcrl FPU_result_1 + rcrl %eax + +L_no_overflow: + jmp LRound_precision /* Do the rounding as required */ + + +/*---------------------------------------------------------------------------+ + | Divide: Return arg1/arg2 to arg3. | + | | + | This routine does not use the exponents of arg1 and arg2, but does | + | adjust the exponent of arg3. | + | | + | The maximum returned value is (ignoring exponents) | + | .ffffffff ffffffff | + | ------------------ = 1.ffffffff fffffffe | + | .80000000 00000000 | + | and the minimum is | + | .80000000 00000000 | + | ------------------ = .80000000 00000001 (rounded) | + | .ffffffff ffffffff | + | | + +---------------------------------------------------------------------------*/ + + +L_Full_Division: + /* Save extended dividend in local register */ + movl SIGL(%esi),%eax + movl %eax,FPU_accum_2 + movl SIGH(%esi),%eax + movl %eax,FPU_accum_3 + xorl %eax,%eax + movl %eax,FPU_accum_1 /* zero the extension */ + movl %eax,FPU_accum_0 /* zero the extension */ + + movl SIGL(%esi),%eax /* Get the current num */ + movl SIGH(%esi),%edx + +/*----------------------------------------------------------------------*/ +/* Initialization done. + Do the first 32 bits. */ + + movb $0,FPU_ovfl_flag + cmpl SIGH(%ebx),%edx /* Test for imminent overflow */ + jb LLess_than_1 + ja LGreater_than_1 + + cmpl SIGL(%ebx),%eax + jb LLess_than_1 + +LGreater_than_1: +/* The dividend is greater or equal, would cause overflow */ + setaeb FPU_ovfl_flag /* Keep a record */ + + subl SIGL(%ebx),%eax + sbbl SIGH(%ebx),%edx /* Prevent the overflow */ + movl %eax,FPU_accum_2 + movl %edx,FPU_accum_3 + +LLess_than_1: +/* At this point, we have a dividend < divisor, with a record of + adjustment in FPU_ovfl_flag */ + + /* We will divide by a number which is too large */ + movl SIGH(%ebx),%ecx + addl $1,%ecx + jnc LFirst_div_not_1 + + /* here we need to divide by 100000000h, + i.e., no division at all.. */ + mov %edx,%eax + jmp LFirst_div_done + +LFirst_div_not_1: + divl %ecx /* Divide the numerator by the augmented + denom ms dw */ + +LFirst_div_done: + movl %eax,FPU_result_2 /* Put the result in the answer */ + + mull SIGH(%ebx) /* mul by the ms dw of the denom */ + + subl %eax,FPU_accum_2 /* Subtract from the num local reg */ + sbbl %edx,FPU_accum_3 + + movl FPU_result_2,%eax /* Get the result back */ + mull SIGL(%ebx) /* now mul the ls dw of the denom */ + + subl %eax,FPU_accum_1 /* Subtract from the num local reg */ + sbbl %edx,FPU_accum_2 + sbbl $0,FPU_accum_3 + je LDo_2nd_32_bits /* Must check for non-zero result here */ + +#ifdef PARANOID + jb L_bugged_1 +#endif PARANOID + + /* need to subtract another once of the denom */ + incl FPU_result_2 /* Correct the answer */ + + movl SIGL(%ebx),%eax + movl SIGH(%ebx),%edx + subl %eax,FPU_accum_1 /* Subtract from the num local reg */ + sbbl %edx,FPU_accum_2 + +#ifdef PARANOID + sbbl $0,FPU_accum_3 + jne L_bugged_1 /* Must check for non-zero result here */ +#endif PARANOID + +/*----------------------------------------------------------------------*/ +/* Half of the main problem is done, there is just a reduced numerator + to handle now. + Work with the second 32 bits, FPU_accum_0 not used from now on */ +LDo_2nd_32_bits: + movl FPU_accum_2,%edx /* get the reduced num */ + movl FPU_accum_1,%eax + + /* need to check for possible subsequent overflow */ + cmpl SIGH(%ebx),%edx + jb LDo_2nd_div + ja LPrevent_2nd_overflow + + cmpl SIGL(%ebx),%eax + jb LDo_2nd_div + +LPrevent_2nd_overflow: +/* The numerator is greater or equal, would cause overflow */ + /* prevent overflow */ + subl SIGL(%ebx),%eax + sbbl SIGH(%ebx),%edx + movl %edx,FPU_accum_2 + movl %eax,FPU_accum_1 + + incl FPU_result_2 /* Reflect the subtraction in the answer */ + +#ifdef PARANOID + je L_bugged_2 /* Can't bump the result to 1.0 */ +#endif PARANOID + +LDo_2nd_div: + cmpl $0,%ecx /* augmented denom msw */ + jnz LSecond_div_not_1 + + /* %ecx == 0, we are dividing by 1.0 */ + mov %edx,%eax + jmp LSecond_div_done + +LSecond_div_not_1: + divl %ecx /* Divide the numerator by the denom ms dw */ + +LSecond_div_done: + movl %eax,FPU_result_1 /* Put the result in the answer */ + + mull SIGH(%ebx) /* mul by the ms dw of the denom */ + + subl %eax,FPU_accum_1 /* Subtract from the num local reg */ + sbbl %edx,FPU_accum_2 + +#ifdef PARANOID + jc L_bugged_2 +#endif PARANOID + + movl FPU_result_1,%eax /* Get the result back */ + mull SIGL(%ebx) /* now mul the ls dw of the denom */ + + subl %eax,FPU_accum_0 /* Subtract from the num local reg */ + sbbl %edx,FPU_accum_1 /* Subtract from the num local reg */ + sbbl $0,FPU_accum_2 + +#ifdef PARANOID + jc L_bugged_2 +#endif PARANOID + + jz LDo_3rd_32_bits + +#ifdef PARANOID + cmpl $1,FPU_accum_2 + jne L_bugged_2 +#endif PARANOID + + /* need to subtract another once of the denom */ + movl SIGL(%ebx),%eax + movl SIGH(%ebx),%edx + subl %eax,FPU_accum_0 /* Subtract from the num local reg */ + sbbl %edx,FPU_accum_1 + sbbl $0,FPU_accum_2 + +#ifdef PARANOID + jc L_bugged_2 + jne L_bugged_2 +#endif PARANOID + + addl $1,FPU_result_1 /* Correct the answer */ + adcl $0,FPU_result_2 + +#ifdef PARANOID + jc L_bugged_2 /* Must check for non-zero result here */ +#endif PARANOID + +/*----------------------------------------------------------------------*/ +/* The division is essentially finished here, we just need to perform + tidying operations. + Deal with the 3rd 32 bits */ +LDo_3rd_32_bits: + movl FPU_accum_1,%edx /* get the reduced num */ + movl FPU_accum_0,%eax + + /* need to check for possible subsequent overflow */ + cmpl SIGH(%ebx),%edx /* denom */ + jb LRound_prep + ja LPrevent_3rd_overflow + + cmpl SIGL(%ebx),%eax /* denom */ + jb LRound_prep + +LPrevent_3rd_overflow: + /* prevent overflow */ + subl SIGL(%ebx),%eax + sbbl SIGH(%ebx),%edx + movl %edx,FPU_accum_1 + movl %eax,FPU_accum_0 + + addl $1,FPU_result_1 /* Reflect the subtraction in the answer */ + adcl $0,FPU_result_2 + jne LRound_prep + jnc LRound_prep + + /* This is a tricky spot, there is an overflow of the answer */ + movb $255,FPU_ovfl_flag /* Overflow -> 1.000 */ + +LRound_prep: +/* + * Prepare for rounding. + * To test for rounding, we just need to compare 2*accum with the + * denom. + */ + movl FPU_accum_0,%ecx + movl FPU_accum_1,%edx + movl %ecx,%eax + orl %edx,%eax + jz LRound_ovfl /* The accumulator contains zero. */ + + /* Multiply by 2 */ + clc + rcll $1,%ecx + rcll $1,%edx + 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 */ + jmp LRound_ovfl + +LRound_not_small: + jnz LRound_large + + movl $0x80000000,%eax /* Remainder was exactly 1/2 denom */ + jmp LRound_ovfl + +LRound_large: + movl $0xff000000,%eax /* Denom was smaller */ + +LRound_ovfl: +/* We are now ready to deal with rounding, but first we must get + the bits properly aligned */ + testb $255,FPU_ovfl_flag /* was the num > denom ? */ + je LRound_precision + + incl EXP(%edi) + + /* shift the mantissa right one bit */ + stc /* Will set the ms bit */ + rcrl FPU_result_2 + rcrl FPU_result_1 + rcrl %eax + +/* Round the result as required */ +LRound_precision: + decl EXP(%edi) /* binary point between 1st & 2nd bits */ + + movl %eax,%edx + movl FPU_result_1,%ebx + movl FPU_result_2,%eax + jmp fpu_reg_round + + +#ifdef PARANOID +/* The logic is wrong if we got here */ +L_bugged: + pushl EX_INTERNAL|0x202 + call EXCEPTION + pop %ebx + jmp L_exit + +L_bugged_1: + pushl EX_INTERNAL|0x203 + call EXCEPTION + pop %ebx + jmp L_exit + +L_bugged_2: + pushl EX_INTERNAL|0x204 + call EXCEPTION + pop %ebx + jmp L_exit + +L_exit: + popl %ebx + popl %edi + popl %esi + + leave + ret +#endif PARANOID diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_mul.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_mul.S new file mode 100644 index 000000000..d041bf3e4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_mul.S @@ -0,0 +1,163 @@ + .file "reg_u_mul.S" +/*---------------------------------------------------------------------------+ + | reg_u_mul.S | + | | + | Core multiplication routine | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | Basic multiplication routine. | + | Does not check the resulting exponent for overflow/underflow | + | | + | reg_u_mul(FPU_REG *a, FPU_REG *b, FPU_REG *c, unsigned int cw); | + | | + | Internal working is at approx 128 bits. | + | Result is rounded to nearest 53 or 64 bits, using "nearest or even". | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "fpu_asm.h" +#include "control_w.h" + + + +#ifdef REENTRANT_FPU +/* Local storage on the stack: */ +#define FPU_accum_0 -4(%ebp) /* ms word */ +#define FPU_accum_1 -8(%ebp) + +#else +/* Local storage in a static area: */ +.data + .align 4,0 +FPU_accum_0: + .long 0 +FPU_accum_1: + .long 0 +#endif REENTRANT_FPU + + +.text + .align 2,144 + +.globl _reg_u_mul +_reg_u_mul: + pushl %ebp + movl %esp,%ebp +#ifdef REENTRANT_FPU + subl $8,%esp +#endif REENTRANT_FPU + + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%esi + movl PARAM2,%edi + +#ifdef PARANOID + testl $0x80000000,SIGH(%esi) + jz L_bugged + testl $0x80000000,SIGH(%edi) + jz L_bugged +#endif PARANOID + +#ifdef DENORM_OPERAND + movl EXP(%esi),%eax + cmpl EXP_UNDER,%eax + jg xOp1_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp1_not_denorm: + movl EXP(%edi),%eax + cmpl EXP_UNDER,%eax + jg xOp2_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp2_not_denorm: +#endif DENORM_OPERAND + + xorl %ecx,%ecx + xorl %ebx,%ebx + + movl SIGL(%esi),%eax + mull SIGL(%edi) + movl %eax,FPU_accum_0 + movl %edx,FPU_accum_1 + + movl SIGL(%esi),%eax + mull SIGH(%edi) + addl %eax,FPU_accum_1 + adcl %edx,%ebx +/* adcl $0,%ecx // overflow here is not possible */ + + movl SIGH(%esi),%eax + mull SIGL(%edi) + addl %eax,FPU_accum_1 + adcl %edx,%ebx + adcl $0,%ecx + + movl SIGH(%esi),%eax + mull SIGH(%edi) + addl %eax,%ebx + adcl %edx,%ecx + + 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 */ + movl %eax,EXP(%edi) + +/* Now make sure that the result is normalized */ + testl $0x80000000,%ecx + jnz LResult_Normalised + + /* Normalize by shifting left one bit */ + shll $1,FPU_accum_0 + rcll $1,FPU_accum_1 + rcll $1,%ebx + rcll $1,%ecx + decl EXP(%edi) + +LResult_Normalised: + movl FPU_accum_0,%eax + movl FPU_accum_1,%edx + orl %eax,%eax + jz L_extent_zero + + orl $1,%edx + +L_extent_zero: + movl %ecx,%eax + jmp fpu_reg_round + + +#ifdef PARANOID +L_bugged: + pushl EX_INTERNAL|0x205 + call EXCEPTION + pop %ebx + jmp L_exit + +L_exit: + popl %ebx + popl %edi + popl %esi + leave + ret +#endif PARANOID + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_sub.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_sub.S new file mode 100644 index 000000000..fbec17dfb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/reg_u_sub.S @@ -0,0 +1,292 @@ + .file "reg_u_sub.S" +/*---------------------------------------------------------------------------+ + | reg_u_sub.S | + | | + | Core floating point subtraction routine. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void reg_u_sub(FPU_REG *arg1, FPU_REG *arg2, FPU_REG *answ, | + | int control_w) | + | | + +---------------------------------------------------------------------------*/ + +/* + | Kernel subtraction routine reg_u_sub(reg *arg1, reg *arg2, reg *answ). + | Takes two valid reg f.p. numbers (TW_Valid), which are + | treated as unsigned numbers, + | and returns their difference as a TW_Valid or TW_Zero f.p. + | number. + | The first number (arg1) must be the larger. + | The returned number is normalized. + | Basic checks are performed if PARANOID is defined. + */ + +#include "exception.h" +#include "fpu_asm.h" +#include "control_w.h" + +.text + .align 2,144 +.globl _reg_u_sub +_reg_u_sub: + pushl %ebp + movl %esp,%ebp + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%esi /* source 1 */ + movl PARAM2,%edi /* source 2 */ + +#ifdef DENORM_OPERAND + cmpl EXP_UNDER,EXP(%esi) + jg xOp1_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp1_not_denorm: + cmpl EXP_UNDER,EXP(%edi) + jg xOp2_not_denorm + + call _denormal_operand + orl %eax,%eax + jnz fpu_Arith_exit + +xOp2_not_denorm: +#endif DENORM_OPERAND + + movl EXP(%esi),%ecx + subl EXP(%edi),%ecx /* exp1 - exp2 */ + +#ifdef PARANOID + /* source 2 is always smaller than source 1 */ + js L_bugged_1 + + testl $0x80000000,SIGH(%edi) /* The args are assumed to be be normalized */ + je L_bugged_2 + + testl $0x80000000,SIGH(%esi) + je L_bugged_2 +#endif PARANOID + +/*--------------------------------------+ + | Form a register holding the | + | smaller number | + +--------------------------------------*/ + 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 */ + + xorl %edx,%edx /* register extension */ + +/*--------------------------------------+ + | Shift the temporary register | + | right the required number of | + | places. | + +--------------------------------------*/ +L_shift_r: + cmpl $32,%ecx /* shrd only works for 0..31 bits */ + jnc L_more_than_31 + +/* less than 32 bits */ + shrd %cl,%ebx,%edx + shrd %cl,%eax,%ebx + shr %cl,%eax + jmp L_shift_done + +L_more_than_31: + cmpl $64,%ecx + jnc L_more_than_63 + + subb $32,%cl + jz L_exactly_32 + + shrd %cl,%eax,%edx + shr %cl,%eax + orl %ebx,%ebx + jz L_more_31_no_low /* none of the lowest bits is set */ + + orl $1,%edx /* record the fact in the extension */ + +L_more_31_no_low: + movl %eax,%ebx + xorl %eax,%eax + jmp L_shift_done + +L_exactly_32: + movl %ebx,%edx + movl %eax,%ebx + xorl %eax,%eax + jmp L_shift_done + +L_more_than_63: + cmpw $65,%cx + jnc L_more_than_64 + + /* Shift right by 64 bits */ + movl %eax,%edx + orl %ebx,%ebx + jz L_more_63_no_low + + orl $1,%edx + jmp L_more_63_no_low + +L_more_than_64: + jne L_more_than_65 + + /* Shift right by 65 bits */ + /* Carry is clear if we get here */ + movl %eax,%edx + rcrl %edx + jnc L_shift_65_nc + + orl $1,%edx + jmp L_more_63_no_low + +L_shift_65_nc: + orl %ebx,%ebx + jz L_more_63_no_low + + orl $1,%edx + jmp L_more_63_no_low + +L_more_than_65: + movl $1,%edx /* The shifted nr always at least one '1' */ + +L_more_63_no_low: + xorl %ebx,%ebx + xorl %eax,%eax + +L_shift_done: +L_subtr: +/*------------------------------+ + | Do the subtraction | + +------------------------------*/ + xorl %ecx,%ecx + subl %edx,%ecx + movl %ecx,%edx + movl SIGL(%esi),%ecx + sbbl %ebx,%ecx + movl %ecx,%ebx + movl SIGH(%esi),%ecx + sbbl %eax,%ecx + movl %ecx,%eax + +#ifdef PARANOID + /* We can never get a borrow */ + jc L_bugged +#endif PARANOID + +/*--------------------------------------+ + | Normalize the result | + +--------------------------------------*/ + testl $0x80000000,%eax + jnz L_round /* no shifting needed */ + + orl %eax,%eax + jnz L_shift_1 /* shift left 1 - 31 bits */ + + 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 + */ + + cmpl $0x80000000,%edx + jnz L_must_be_zero + + /* Shift left 64 bits */ + subl $64,EXP(%edi) + xchg %edx,%eax + jmp fpu_reg_round + +L_must_be_zero: +#ifdef PARANOID + orl %edx,%edx + jnz L_bugged_3 +#endif PARANOID + + /* The result is zero */ + movb TW_Zero,TAG(%edi) + movl $0,EXP(%edi) /* exponent */ + movl $0,SIGL(%edi) + movl $0,SIGH(%edi) + jmp L_exit /* %eax contains zero */ + +L_shift_32: + movl %ebx,%eax + movl %edx,%ebx + movl $0,%edx + subl $32,EXP(%edi) /* Can get underflow here */ + +/* We need to shift left by 1 - 31 bits */ +L_shift_1: + bsrl %eax,%ecx /* get the required shift in %ecx */ + subl $31,%ecx + negl %ecx + shld %cl,%ebx,%eax + shld %cl,%edx,%ebx + shl %cl,%edx + subl %ecx,EXP(%edi) /* Can get underflow here */ + +L_round: + jmp fpu_reg_round /* Round the result */ + + +#ifdef PARANOID +L_bugged_1: + pushl EX_INTERNAL|0x206 + call EXCEPTION + pop %ebx + jmp L_error_exit + +L_bugged_2: + pushl EX_INTERNAL|0x209 + call EXCEPTION + pop %ebx + jmp L_error_exit + +L_bugged_3: + pushl EX_INTERNAL|0x210 + call EXCEPTION + pop %ebx + jmp L_error_exit + +L_bugged_4: + pushl EX_INTERNAL|0x211 + call EXCEPTION + pop %ebx + jmp L_error_exit + +L_bugged: + pushl EX_INTERNAL|0x212 + call EXCEPTION + pop %ebx + jmp L_error_exit +#endif PARANOID + + +L_error_exit: + movl $1,%eax +L_exit: + popl %ebx + popl %edi + popl %esi + leave + ret diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/status_w.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/status_w.h new file mode 100644 index 000000000..96607d0e1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/status_w.h @@ -0,0 +1,65 @@ +/*---------------------------------------------------------------------------+ + | status_w.h | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + +---------------------------------------------------------------------------*/ + +#ifndef _STATUS_H_ +#define _STATUS_H_ + +#include "fpu_emu.h" /* for definition of PECULIAR_486 */ + +#ifdef __ASSEMBLER__ +#define Const__(x) $##x +#else +#define Const__(x) x +#endif + +#define SW_Backward Const__(0x8000) /* backward compatibility */ +#define SW_C3 Const__(0x4000) /* condition bit 3 */ +#define SW_Top Const__(0x3800) /* top of stack */ +#define SW_Top_Shift Const__(11) /* shift for top of stack bits */ +#define SW_C2 Const__(0x0400) /* condition bit 2 */ +#define SW_C1 Const__(0x0200) /* condition bit 1 */ +#define SW_C0 Const__(0x0100) /* condition bit 0 */ +#define SW_Summary Const__(0x0080) /* exception summary */ +#define SW_Stack_Fault Const__(0x0040) /* stack fault */ +#define SW_Precision Const__(0x0020) /* loss of precision */ +#define SW_Underflow Const__(0x0010) /* underflow */ +#define SW_Overflow Const__(0x0008) /* overflow */ +#define SW_Zero_Div Const__(0x0004) /* divide by zero */ +#define SW_Denorm_Op Const__(0x0002) /* denormalized operand */ +#define SW_Invalid Const__(0x0001) /* invalid operation */ + +#define SW_Exc_Mask Const__(0x27f) /* Status word exception bit mask */ + +#ifndef __ASSEMBLER__ + +#define COMP_A_gt_B 1 +#define COMP_A_eq_B 2 +#define COMP_A_lt_B 3 +#define COMP_No_Comp 4 +#define COMP_Denormal 0x20 +#define COMP_NaN 0x40 +#define COMP_SNaN 0x80 + +#define status_word() \ + ((partial_status & ~SW_Top & 0xffff) | ((top << SW_Top_Shift) & SW_Top)) +#define setcc(cc) ({ \ + partial_status &= ~(SW_C0|SW_C1|SW_C2|SW_C3); \ + partial_status |= (cc) & (SW_C0|SW_C1|SW_C2|SW_C3); }) + +#ifdef PECULIAR_486 + /* Default, this conveys no information, but an 80486 does it. */ + /* Clear the SW_C1 bit, "other bits undefined". */ +# define clear_C1() { partial_status &= ~SW_C1; } +# else +# define clear_C1() +#endif PECULIAR_486 + +#endif __ASSEMBLER__ + +#endif _STATUS_H_ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/version.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/version.h new file mode 100644 index 000000000..d2c264d69 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/version.h @@ -0,0 +1,13 @@ +/*---------------------------------------------------------------------------+ + | version.h | + | | + | | + | Copyright (C) 1992,1993,1994 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | | + +---------------------------------------------------------------------------*/ + +#define FPU_VERSION "wm-FPU-emu version Beta 1.9" + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_shrx.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_shrx.S new file mode 100644 index 000000000..bef0e1963 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_shrx.S @@ -0,0 +1,208 @@ + .file "wm_shrx.S" +/*---------------------------------------------------------------------------+ + | wm_shrx.S | + | | + | 64 bit right shift functions | + | | + | Copyright (C) 1992 W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | unsigned shrx(void *arg1, unsigned arg2) | + | and | + | unsigned shrxs(void *arg1, unsigned arg2) | + | | + +---------------------------------------------------------------------------*/ + +#include "fpu_asm.h" + +.text + .align 2,144 + +/*---------------------------------------------------------------------------+ + | unsigned shrx(void *arg1, unsigned arg2) | + | | + | Extended shift right function. | + | Fastest for small shifts. | + | Shifts the 64 bit quantity pointed to by the first arg (arg1) | + | right by the number of bits specified by the second arg (arg2). | + | Forms a 96 bit quantity from the 64 bit arg and eax: | + | [ 64 bit arg ][ eax ] | + | shift right ---------> | + | The eax register is initialized to 0 before the shifting. | + | Results returned in the 64 bit arg and eax. | + +---------------------------------------------------------------------------*/ + + .globl _shrx + +_shrx: + push %ebp + movl %esp,%ebp + pushl %esi + movl PARAM2,%ecx + movl PARAM1,%esi + cmpl $32,%ecx /* shrd only works for 0..31 bits */ + jnc L_more_than_31 + +/* less than 32 bits */ + pushl %ebx + movl (%esi),%ebx /* lsl */ + movl 4(%esi),%edx /* msl */ + xorl %eax,%eax /* extension */ + shrd %cl,%ebx,%eax + shrd %cl,%edx,%ebx + shr %cl,%edx + movl %ebx,(%esi) + movl %edx,4(%esi) + popl %ebx + popl %esi + leave + ret + +L_more_than_31: + cmpl $64,%ecx + jnc L_more_than_63 + + subb $32,%cl + movl (%esi),%eax /* lsl */ + movl 4(%esi),%edx /* msl */ + shrd %cl,%edx,%eax + shr %cl,%edx + movl %edx,(%esi) + movl $0,4(%esi) + popl %esi + leave + ret + +L_more_than_63: + cmpl $96,%ecx + jnc L_more_than_95 + + subb $64,%cl + movl 4(%esi),%eax /* msl */ + shr %cl,%eax + xorl %edx,%edx + movl %edx,(%esi) + movl %edx,4(%esi) + popl %esi + leave + ret + +L_more_than_95: + xorl %eax,%eax + movl %eax,(%esi) + movl %eax,4(%esi) + popl %esi + leave + ret + + +/*---------------------------------------------------------------------------+ + | unsigned shrxs(void *arg1, unsigned arg2) | + | | + | Extended shift right function (optimized for small floating point | + | integers). | + | Shifts the 64 bit quantity pointed to by the first arg (arg1) | + | right by the number of bits specified by the second arg (arg2). | + | Forms a 96 bit quantity from the 64 bit arg and eax: | + | [ 64 bit arg ][ eax ] | + | shift right ---------> | + | The eax register is initialized to 0 before the shifting. | + | The lower 8 bits of eax are lost and replaced by a flag which is | + | set (to 0x01) if any bit, apart from the first one, is set in the | + | part which has been shifted out of the arg. | + | Results returned in the 64 bit arg and eax. | + +---------------------------------------------------------------------------*/ + .globl _shrxs +_shrxs: + push %ebp + movl %esp,%ebp + pushl %esi + pushl %ebx + movl PARAM2,%ecx + movl PARAM1,%esi + cmpl $64,%ecx /* shrd only works for 0..31 bits */ + jnc Ls_more_than_63 + + cmpl $32,%ecx /* shrd only works for 0..31 bits */ + jc Ls_less_than_32 + +/* We got here without jumps by assuming that the most common requirement + is for small integers */ +/* Shift by [32..63] bits */ + subb $32,%cl + movl (%esi),%eax /* lsl */ + movl 4(%esi),%edx /* msl */ + xorl %ebx,%ebx + shrd %cl,%eax,%ebx + shrd %cl,%edx,%eax + shr %cl,%edx + orl %ebx,%ebx /* test these 32 bits */ + setne %bl + test $0x7fffffff,%eax /* and 31 bits here */ + setne %bh + orw %bx,%bx /* Any of the 63 bit set ? */ + setne %al + movl %edx,(%esi) + movl $0,4(%esi) + popl %ebx + popl %esi + leave + ret + +/* Shift by [0..31] bits */ +Ls_less_than_32: + movl (%esi),%ebx /* lsl */ + movl 4(%esi),%edx /* msl */ + xorl %eax,%eax /* extension */ + shrd %cl,%ebx,%eax + shrd %cl,%edx,%ebx + shr %cl,%edx + test $0x7fffffff,%eax /* only need to look at eax here */ + setne %al + movl %ebx,(%esi) + movl %edx,4(%esi) + popl %ebx + popl %esi + leave + ret + +/* Shift by [64..95] bits */ +Ls_more_than_63: + cmpl $96,%ecx + jnc Ls_more_than_95 + + subb $64,%cl + movl (%esi),%ebx /* lsl */ + movl 4(%esi),%eax /* msl */ + xorl %edx,%edx /* extension */ + shrd %cl,%ebx,%edx + shrd %cl,%eax,%ebx + shr %cl,%eax + orl %ebx,%edx + setne %bl + test $0x7fffffff,%eax /* only need to look at eax here */ + setne %bh + orw %bx,%bx + setne %al + xorl %edx,%edx + movl %edx,(%esi) /* set to zero */ + movl %edx,4(%esi) /* set to zero */ + popl %ebx + popl %esi + leave + ret + +Ls_more_than_95: +/* Shift by [96..inf) bits */ + xorl %eax,%eax + movl (%esi),%ebx + orl 4(%esi),%ebx + setne %al + xorl %ebx,%ebx + movl %ebx,(%esi) + movl %ebx,4(%esi) + popl %ebx + popl %esi + leave + ret diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_sqrt.S b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_sqrt.S new file mode 100644 index 000000000..7f8b6c60a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/FPU-emu/wm_sqrt.S @@ -0,0 +1,474 @@ + .file "wm_sqrt.S" +/*---------------------------------------------------------------------------+ + | wm_sqrt.S | + | | + | Fixed point arithmetic square root evaluation. | + | | + | Copyright (C) 1992,1993 | + | W. Metzenthen, 22 Parker St, Ormond, Vic 3163, | + | Australia. E-mail billm@vaxc.cc.monash.edu.au | + | | + | Call from C as: | + | void wm_sqrt(FPU_REG *n, unsigned int control_word) | + | | + +---------------------------------------------------------------------------*/ + +/*---------------------------------------------------------------------------+ + | wm_sqrt(FPU_REG *n, unsigned int control_word) | + | returns the square root of n in n. | + | | + | Use Newton's method to compute the square root of a number, which must | + | be in the range [1.0 .. 4.0), to 64 bits accuracy. | + | Does not check the sign or tag of the argument. | + | Sets the exponent, but not the sign or tag of the result. | + | | + | The guess is kept in %esi:%edi | + +---------------------------------------------------------------------------*/ + +#include "exception.h" +#include "fpu_asm.h" + + +#ifdef REENTRANT_FPU +/* Local storage on the stack: */ +#define FPU_accum_3 -4(%ebp) /* ms word */ +#define FPU_accum_2 -8(%ebp) +#define FPU_accum_1 -12(%ebp) +#define FPU_accum_0 -16(%ebp) + +/* + * 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 + */ +#define FPU_fsqrt_arg_2 -20(%ebp) /* ms word */ +#define FPU_fsqrt_arg_1 -24(%ebp) +#define FPU_fsqrt_arg_0 -28(%ebp) /* ls word, at most the ms bit is set */ + +#else +/* Local storage in a static area: */ +.data + .align 4,0 +FPU_accum_3: + .long 0 /* ms word */ +FPU_accum_2: + .long 0 +FPU_accum_1: + .long 0 +FPU_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 + */ +FPU_fsqrt_arg_2: + .long 0 /* ms word */ +FPU_fsqrt_arg_1: + .long 0 +FPU_fsqrt_arg_0: + .long 0 /* ls word, at most the ms bit is set */ +#endif REENTRANT_FPU + + +.text + .align 2,144 + +.globl _wm_sqrt +_wm_sqrt: + pushl %ebp + movl %esp,%ebp +#ifdef REENTRANT_FPU + subl $28,%esp +#endif REENTRANT_FPU + pushl %esi + pushl %edi + pushl %ebx + + movl PARAM1,%esi + + movl SIGH(%esi),%eax + movl SIGL(%esi),%ecx + xorl %edx,%edx + +/* We use a rough linear estimate for the first guess.. */ + + cmpl EXP_BIAS,EXP(%esi) + jnz sqrt_arg_ge_2 + + shrl $1,%eax /* arg is in the range [1.0 .. 2.0) */ + rcrl $1,%ecx + rcrl $1,%edx + +sqrt_arg_ge_2: +/* From here on, n is never accessed directly again until it is + replaced by the answer. */ + + movl %eax,FPU_fsqrt_arg_2 /* ms word of n */ + movl %ecx,FPU_fsqrt_arg_1 + movl %edx,FPU_fsqrt_arg_0 + +/* Make a linear first estimate */ + shrl $1,%eax + addl $0x40000000,%eax + movl $0xaaaaaaaa,%ecx + mull %ecx + shll %edx /* max result was 7fff... */ + testl $0x80000000,%edx /* but min was 3fff... */ + jnz sqrt_prelim_no_adjust + + movl $0x80000000,%edx /* round up */ + +sqrt_prelim_no_adjust: + 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 FPU_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. + */ + +/* 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 + divl %esi + shrl %esi + addl %eax,%esi + + movl %ecx,%edx + divl %esi + 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) + */ + +/* First, find the square of the guess */ + movl %esi,%eax + mull %esi +/* guess^2 now in %edx:%eax */ + + movl FPU_fsqrt_arg_1,%ecx + subl %ecx,%eax + movl FPU_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. */ + notl %edx + notl %eax + addl $1,%eax + adcl $0,%edx + + divl %esi + movl %eax,%ecx + + movl %edx,%eax + divl %esi + jmp sqrt_stage_2_finish + +sqrt_stage_2_positive: + divl %esi + movl %eax,%ecx + + movl %edx,%eax + divl %esi + + notl %ecx + notl %eax + addl $1,%eax + adcl $0,%ecx + +sqrt_stage_2_finish: + sarl $1,%ecx /* divide by 2 */ + rcrl $1,%eax + + /* Form the new estimate in %esi:%edi */ + movl %eax,%edi + addl %ecx,%esi + + 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 */ + cmp $0xffffffff,FPU_fsqrt_arg_1 + jnz sqrt_stage_2_error +#endif PARANOID + +/* The best rounded result. */ + xorl %eax,%eax + decl %eax + movl %eax,%edi + movl %eax,%esi + movl $0x7fffffff,%eax + jmp sqrt_round_result + +#ifdef PARANOID +sqrt_stage_2_error: + pushl EX_INTERNAL|0x213 + call EXCEPTION +#endif PARANOID + +sqrt_stage_2_done: + +/* 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 */ + mull %edi + movl %edx,FPU_accum_1 + + movl %esi,%eax + mull %esi + movl %edx,FPU_accum_3 + movl %eax,FPU_accum_2 + + movl %edi,%eax + mull %esi + addl %eax,FPU_accum_1 + adcl %edx,FPU_accum_2 + adcl $0,FPU_accum_3 + +/* movl %esi,%eax */ +/* mull %edi */ + addl %eax,FPU_accum_1 + adcl %edx,FPU_accum_2 + adcl $0,FPU_accum_3 + +/* guess^2 now in FPU_accum_3:FPU_accum_2:FPU_accum_1 */ + + movl FPU_fsqrt_arg_0,%eax /* get normalized n */ + subl %eax,FPU_accum_1 + movl FPU_fsqrt_arg_1,%eax + sbbl %eax,FPU_accum_2 + movl FPU_fsqrt_arg_2,%eax /* ms word of normalized n */ + sbbl %eax,FPU_accum_3 + jnc sqrt_stage_3_positive + +/* Subtraction gives a negative result, + negate the result before division */ + notl FPU_accum_1 + notl FPU_accum_2 + notl FPU_accum_3 + addl $1,FPU_accum_1 + adcl $0,FPU_accum_2 + +#ifdef PARANOID + adcl $0,FPU_accum_3 /* This must be zero */ + jz sqrt_stage_3_no_error + +sqrt_stage_3_error: + pushl EX_INTERNAL|0x207 + call EXCEPTION + +sqrt_stage_3_no_error: +#endif PARANOID + + movl FPU_accum_2,%edx + movl FPU_accum_1,%eax + divl %esi + movl %eax,%ecx + + movl %edx,%eax + divl %esi + + sarl $1,%ecx /* divide by 2 */ + rcrl $1,%eax + + /* prepare to round the result */ + + addl %ecx,%edi + adcl $0,%esi + + jmp sqrt_stage_3_finished + +sqrt_stage_3_positive: + movl FPU_accum_2,%edx + movl FPU_accum_1,%eax + divl %esi + movl %eax,%ecx + + movl %edx,%eax + divl %esi + + sarl $1,%ecx /* divide by 2 */ + rcrl $1,%eax + + /* prepare to round the result */ + + notl %eax /* Negate the correction term */ + notl %ecx + addl $1,%eax + adcl $0,%ecx /* carry here ==> correction == 0 */ + adcl $0xffffffff,%esi + + addl %ecx,%edi + adcl $0,%esi + +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. + */ + cmpl $0xffffffe0,%eax + ja sqrt_near_exact_x + + cmpl $0x00000020,%eax + jb sqrt_near_exact + + cmpl $0x7fffffe0,%eax + jb sqrt_round_result + + cmpl $0x80000020,%eax + jb sqrt_get_more_precision + +sqrt_round_result: +/* 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 PARAM2,%ecx + jmp fpu_reg_round_sqrt + + +sqrt_near_exact_x: +/* 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 */ + mull %edi + 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 + +#ifdef PARANOID + cmp $0xffffffb0,%ebx + jb sqrt_near_exact_ok + + cmp $0x00000050,%ebx + ja sqrt_near_exact_ok + + pushl EX_INTERNAL|0x214 + call EXCEPTION + +sqrt_near_exact_ok: +#endif PARANOID + + or %ebx,%ebx + js sqrt_near_exact_small + + jnz sqrt_near_exact_large + + or %ebx,%edx + jnz sqrt_near_exact_large + +/* Our estimate is exactly the right answer */ + xorl %eax,%eax + jmp sqrt_round_result + +sqrt_near_exact_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 */ + subl $1,%edi + sbbl $0,%esi + movl $0xffffff00,%eax + jmp sqrt_round_result + + +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 */ + rcll $1,%esi + + 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 %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 */ + rcrl $1,%edi + +#ifdef PARANOID + cmp $0xffffff60,%ebx + jb sqrt_more_prec_ok + + cmp $0x000000a0,%ebx + ja sqrt_more_prec_ok + + pushl EX_INTERNAL|0x215 + call EXCEPTION + +sqrt_more_prec_ok: +#endif PARANOID + + or %ebx,%ebx + js sqrt_more_prec_small + + jnz sqrt_more_prec_large + + or %ebx,%ecx + jnz sqrt_more_prec_large + +/* Our estimate is exactly the right answer */ + movl $0x80000000,%eax + jmp sqrt_round_result + +sqrt_more_prec_small: +/* Our estimate is too small */ + movl $0x800000ff,%eax + jmp sqrt_round_result + +sqrt_more_prec_large: +/* Our estimate is too large */ + movl $0x7fffff00,%eax + jmp sqrt_round_result diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/Makefile new file mode 100644 index 000000000..a30e4a764 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/Makefile @@ -0,0 +1,49 @@ +# +# 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 in the main makefile... + +.S.s: + $(CPP) -traditional $< -o $*.s +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< + +SUBDIRS = block char net + +ifdef CONFIG_MATH_EMULATION +SUBDIRS := $(SUBDIRS) FPU-emu +endif + +ifdef CONFIG_SCSI +SUBDIRS := $(SUBDIRS) scsi +endif + +ifdef CONFIG_SOUND +SUBDIRS := $(SUBDIRS) sound +endif + +all: driversubdirs + +driversubdirs: dummy + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done + +dep: + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/Makefile new file mode 100644 index 000000000..bc0dfc55f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/Makefile @@ -0,0 +1,72 @@ +# +# 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_SBPCD +OBJS := $(OBJS) sbpcd.o +SRCS := $(SRCS) sbpcd.c +ifdef PATCHLEVEL +CFLAGS := $(CFLAGS) -DPATCHLEVEL=$(PATCHLEVEL) +endif +endif #CONFIG_SBPCD + +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 + +dep: + $(CPP) -M $(SRCS) > .depend + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/README.sbpcd b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/README.sbpcd new file mode 100644 index 000000000..5b5dd1c9c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/README.sbpcd @@ -0,0 +1,214 @@ +This is release 1.2 of the SoundBlaster Pro (Matsushita, Kotobuki, +Panasonic, CreativeLabs, Aztech) CD-ROM driver for Linux. + +The driver is able to drive the whole family of IDE-style +Matsushita/Kotobuki/Panasonic drives (the "double speed" versions +like CR-562 and CR-563, too), and it will work with the soundcard +interfaces (SB Pro, SB 16, Galaxy, SoundFX, ...) and/or with +the "no-sound" cards (Panasonic CI-101P, LaserMate, Aztech, ...). +The interface type has to get configured, because the behavior +is different. + +The driver respects different drive firmware releases - my drive +is a 2.11, but it should work with "old" drives <2.01 ... >3.00 +and with "new" drives (which count the releases around 0.75 or +1.00). + +Up to 4 drives are supported. CR-52x and CR-56x drives can be mixed, +but the CR-521 ones are hard-wired to drive ID 0. The drives have +to use different drive IDs, but the same controller (it will be a +little bit harder to support up to four interface cards - but I plan +to do it the day somebody wishes to connect a fifth drive). +Each drive has to get a unique minor number (0...3), corresponding +to it's drive ID. The drive IDs may be selected freely from 0 to 3 - +they must not be in consecutive order. + +If this driver doesn't work with your equipment, mail me a +description, please. + +The driver supports reading of data from the CD and playing of +audio tracks. The audio part should run with WorkMan, xcdplayer, +with the "non-X11" products CDplayer and WorkBone - tell me if +it is not compatible with other software. + +MultiSession is supported, "ManySession" (see below) alternatively. +Photo CDs should work, too. At ftp.gwdg.de:/pub/linux/hpcdtoppm +is a package to convert photo CD image files. + +I did not have a chance to play with XA or mixed mode CDs yet. +Send one over, if you would like sbpcd to support that. + +The transfer rate will reach 150 kB/sec with standard drives and +the full 300 kB/sec with double-speed drives. + +This release is part of the standard kernel and consists of +- this README file +- the driver file linux/drivers/block/sbpcd.c +- the header file linux/include/linux/sbpcd.h. + + +To install: +----------- + +1. Setup your hardware parameters. Though the driver does "auto-probing" + now, this step is recommended for every-day use. + a. Go into /usr/src/linux/include/linux/sbpcd.h and configure + it for your hardware (near the beginning): + a1. Set it up for the appropriate type of interface board. + Most "compatible" sound boards (for example "Highscreen", + "SoundFX" and "Galaxy") need the "SBPRO 0" setup. The + "no-sound" board from OmniCd needs the "SBPRO 1" setup. + sbpcd.c holds some examples in it's auto-probe list. + a2. Tell the address of your CDROM_PORT. + b. Additionally for 2.a1 and 2.a2, the setup may be done during + boot time (via the "kernel command line" or "LILO option"): + sbpcd=0x230,SoundBlaster + or + sbpcd=0x320,LaserMate + (these strings are case sensitive!). + +2. Do a "make config" and select "yes" for Matsushita CD-ROM + support and for ISO9660 FileSystem support. + SCSI and/or SCSI CD-ROM support is not needed. + +3. Then do a "make dep", then make the kernel image ("make zlilo" + or else). + +4. Make the device file(s). The driver uses definitely and exclusive + the MAJOR 25, so do + + mknod /dev/sbpcd b 25 0 (if you have only drive #0) +and/or + mknod /dev/sbpcd0 b 25 0 + mknod /dev/sbpcd1 b 25 1 + mknod /dev/sbpcd2 b 25 2 + mknod /dev/sbpcd3 b 25 3 + + to make the node(s). + Take care that you create a node with the same MINOR as your drive + id is. So, if the DOS driver tells you have drive id #3, you have to + mknod /dev/ b 25 3 + + If you further make a link like + ln -s sbpcd /dev/cdrom + you can use the name /dev/cdrom, too. + +5. Reboot with the new kernel. + +You should now be able to do "mount -t iso9660 /dev/sbpcd /mnt" +and see the contents of your CD in the /mnt directory, and/or +hear music with "workman -c /dev/sbpcd &". + + +Things of interest: +------------------- + +The driver is configured to try the SoundBlaster Pro type of +interface at I/O port 0x0230 first. If this is not appropriate, +sbpcd.h should get changed (you will find the right place - +just at the beginning). + +No DMA and no IRQ is used, so the IRQ adjusting is not necessary, +and the IRQ line stays free for the SB Pro sound drivers. + +To reduce or increase the amount of kernel messages, edit +sbpcd.c and change the initialization of the variable +"sbpcd_debug". This is the way to get rid of the initial +warning message block, too. + +With "#define MANY_SESSION 1" (sbpcd.c), the driver can use +"many-session" CDs. This will work only with "new" drives like +CR-562 or CR-563. That is NOT multisession - it is a CD +with multiple independent sessions, each containing block +addresses as if it were the only session. With this feature +enabled, the driver will read the LAST session. Without it, +the FIRST session gets read. +If you would like the support of reading "in-between" sessions, +drop me a mail and some food for the soul. :-) +Those "many-session" CDs can get made by CDROM writers like +Philips CDD 521. +With this feature enabled, it is impossible to read true +multisession CDs. + + +Auto-probing at boot time: +-------------------------- + +The driver does auto-probing at all well-known interface card +addresses now. The idea to do that came from Adam J. Richter +(YGGDRASIL). + +This auto-probing looks first at the configured address resp. +the address submitted by the kernel command line. With this, +it is possible to use this driver within installation boot +floppies, and for any non-standard address, too. + +Auto-probing will make an assumption about the interface type +("SBPRO" or not), based upon the address. That assumption may +be wrong (initialization will be o.k., but you will get I/O +errors during mount). In that case, use the "kernel command +line" feature and specify address & type at boot time to find +out the right setup. + +SBPCD's auto-probing happens before the initialization of the +net drivers. That makes a hang possible if an ethernet card +gets touched. + +For every-day use, address and type should get configured +within sbpcd.h. That will stop the auto-probing due to success +with the first try. + + +Setting up address and interface type: +-------------------------------------- + +If your I/O port address is not 0x0230 or if you use a "no-sound" +interface other than OmniCD, you have to look for the #defines +near the beginning of sbpcd.h and configure them: set SBPRO to +0 or 1, and change CDROM_PORT to the address of your CDROM I/O port. + +Most of the "SoundBlaster compatible" cards behave like the +no-sound interfaces! + +With "original" SB Pro cards, an initial setting of CD_volume +through the sound cards MIXER register gets done. That happens +at the end of "sbpcd_init". If you are using a "compatible" +sound card of type "LaserMate", you can change that code to get +it done with your card, too... + + +Using audio CDs: +---------------- + +Workman, WorkBone, xcdplayer and cdplayer should work good now, +even with the double-speed drives. + +The program CDplayer likes to talk to "/dev/mcd" only, xcdplayer +wants "/dev/rsr0", workman loves "/dev/sr0" - so, do the appropriate +links for using them without the need of supplying parameters. + + +Known problems: +--------------- + +Currently, the detection of disk change or removal does not +work as good as it should. + +Further, I do not know if this driver can live together with a +SCSI CD-ROM driver and/or device, but I hope so. + + + +Bug reports, comments, wishes, donations (technical information +is a donation, too :-) etc. to + emoenke@gwdg.de + or to eberhard_moenkeberg@rollo.central.de + or to my FIDO address: Eberhard Moenkeberg, 2:2437/210.27 + + +SnailMail address, preferable for CD editors if they want to submit +a free "cooperation" copy: + Eberhard Moenkeberg + Reinholdstr. 14 + D-37083 Goettingen + Germany diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/blk.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/blk.h new file mode 100644 index 000000000..faa5adfc5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/blk.h @@ -0,0 +1,310 @@ +#ifndef _BLK_H +#define _BLK_H + +#include +#include +#include +#include + +/* + * NR_REQUEST is the number of entries in the request-queue. + * NOTE that writes may use only the low 2/3 of these: reads + * take precedence. + * + * 32 seems to be a reasonable number: enough to get some benefit + * from the elevator-mechanism, but not so much as to lock a lot of + * buffers when they are in the queue. 64 seems to be too many (easily + * long pauses in reading when heavy writing/syncing is going on) + */ +#define NR_REQUEST 64 + +/* + * Ok, this is an expanded form so that we can use the same + * request for paging requests when that is implemented. In + * paging, 'bh' is NULL, and 'waiting' is used to wait for + * read/write completion. + */ +struct request { + int dev; /* -1 if no request */ + int cmd; /* READ or WRITE */ + int errors; + unsigned long sector; + unsigned long nr_sectors; + unsigned long current_nr_sectors; + char * buffer; + struct task_struct * waiting; + struct buffer_head * bh; + struct buffer_head * bhtail; + struct request * next; +}; + +/* + * This is used in the elevator algorithm: Note that + * reads always go before writes. This is natural: reads + * are much more time-critical than writes. + */ +#define IN_ORDER(s1,s2) \ +((s1)->cmd < (s2)->cmd || ((s1)->cmd == (s2)->cmd && \ +((s1)->dev < (s2)->dev || (((s1)->dev == (s2)->dev && \ +(s1)->sector < (s2)->sector))))) + +struct blk_dev_struct { + void (*request_fn)(void); + struct request * current_request; +}; + + +struct sec_size { + unsigned block_size; + unsigned block_size_bits; +}; + +/* + * These will have to be changed to be aware of different buffer + * sizes etc.. It actually needs a major cleanup. + */ +#define SECTOR_MASK (blksize_size[MAJOR_NR] && \ + blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] ? \ + ((blksize_size[MAJOR_NR][MINOR(CURRENT->dev)] >> 9) - 1) : \ + ((BLOCK_SIZE >> 9) - 1)) + +#define SUBSECTOR(block) (CURRENT->current_nr_sectors > 0) + +extern struct sec_size * blk_sec[MAX_BLKDEV]; +extern struct blk_dev_struct blk_dev[MAX_BLKDEV]; +extern struct wait_queue * wait_for_request; +extern void resetup_one_dev(struct gendisk *dev, int drive); + +extern int * blk_size[MAX_BLKDEV]; + +extern int * blksize_size[MAX_BLKDEV]; + +extern unsigned long hd_init(unsigned long mem_start, unsigned long mem_end); +extern unsigned long cdu31a_init(unsigned long mem_start, unsigned long mem_end); +extern unsigned long mcd_init(unsigned long mem_start, unsigned long mem_end); +extern int is_read_only(int dev); +extern void set_device_ro(int dev,int flag); + +extern void rd_load(void); +extern long rd_init(long mem_start, int length); +extern int ramdisk_size; + +extern unsigned long xd_init(unsigned long mem_start, unsigned long mem_end); + +#define RO_IOCTLS(dev,where) \ + case BLKROSET: if (!suser()) return -EPERM; \ + set_device_ro((dev),get_fs_long((long *) (where))); return 0; \ + case BLKROGET: { int __err = verify_area(VERIFY_WRITE, (void *) (where), sizeof(long)); \ + if (!__err) put_fs_long(is_read_only(dev),(long *) (where)); return __err; } + +#ifdef MAJOR_NR + +/* + * Add entries as needed. Currently the only block devices + * supported are hard-disks and floppies. + */ + +#if (MAJOR_NR == MEM_MAJOR) + +/* ram disk */ +#define DEVICE_NAME "ramdisk" +#define DEVICE_REQUEST do_rd_request +#define DEVICE_NR(device) ((device) & 7) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == FLOPPY_MAJOR) + +static void floppy_on(unsigned int nr); +static void floppy_off(unsigned int nr); + +#define DEVICE_NAME "floppy" +#define DEVICE_INTR do_floppy +#define DEVICE_REQUEST do_fd_request +#define DEVICE_NR(device) ((device) & 3) +#define DEVICE_ON(device) floppy_on(DEVICE_NR(device)) +#define DEVICE_OFF(device) floppy_off(DEVICE_NR(device)) + +#elif (MAJOR_NR == HD_MAJOR) + +/* harddisk: timeout is 6 seconds.. */ +#define DEVICE_NAME "harddisk" +#define DEVICE_INTR do_hd +#define DEVICE_TIMEOUT HD_TIMER +#define TIMEOUT_VALUE 600 +#define DEVICE_REQUEST do_hd_request +#define DEVICE_NR(device) (MINOR(device)>>6) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == SCSI_DISK_MAJOR) + +#define DEVICE_NAME "scsidisk" +#define DEVICE_INTR do_sd +#define TIMEOUT_VALUE 200 +#define DEVICE_REQUEST do_sd_request +#define DEVICE_NR(device) (MINOR(device) >> 4) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == SCSI_TAPE_MAJOR) + +#define DEVICE_NAME "scsitape" +#define DEVICE_INTR do_st +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == SCSI_CDROM_MAJOR) + +#define DEVICE_NAME "CD-ROM" +#define DEVICE_INTR do_sr +#define DEVICE_REQUEST do_sr_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == XT_DISK_MAJOR) + +#define DEVICE_NAME "xt disk" +#define DEVICE_REQUEST do_xd_request +#define DEVICE_NR(device) (MINOR(device) >> 6) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == CDU31A_CDROM_MAJOR) + +#define DEVICE_NAME "CDU31A" +#define DEVICE_REQUEST do_cdu31a_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == MITSUMI_CDROM_MAJOR) + +#define DEVICE_NAME "Mitsumi CD-ROM" +/* #define DEVICE_INTR do_mcd */ +#define DEVICE_REQUEST do_mcd_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#elif (MAJOR_NR == MATSUSHITA_CDROM_MAJOR) + +#define DEVICE_NAME "Matsushita CD-ROM" +#define DEVICE_REQUEST do_sbpcd_request +#define DEVICE_NR(device) (MINOR(device)) +#define DEVICE_ON(device) +#define DEVICE_OFF(device) + +#else + +#error "unknown blk device" + +#endif + +#if (MAJOR_NR != SCSI_TAPE_MAJOR) + +#ifndef CURRENT +#define CURRENT (blk_dev[MAJOR_NR].current_request) +#endif + +#define CURRENT_DEV DEVICE_NR(CURRENT->dev) + +#ifdef DEVICE_INTR +void (*DEVICE_INTR)(void) = NULL; +#endif +#ifdef DEVICE_TIMEOUT + +#define SET_TIMER \ +((timer_table[DEVICE_TIMEOUT].expires = jiffies + TIMEOUT_VALUE), \ +(timer_active |= 1<errors = 0; + if (!uptodate) { + printk(DEVICE_NAME " I/O error\n"); + printk("dev %04lX, sector %lu\n", + (unsigned long)req->dev, req->sector); + req->nr_sectors--; + req->nr_sectors &= ~SECTOR_MASK; + req->sector += (BLOCK_SIZE / 512); + req->sector &= ~SECTOR_MASK; + } + + if ((bh = req->bh) != NULL) { + req->bh = bh->b_reqnext; + bh->b_reqnext = NULL; + bh->b_uptodate = uptodate; + unlock_buffer(bh); + if ((bh = req->bh) != NULL) { + req->current_nr_sectors = bh->b_size >> 9; + if (req->nr_sectors < req->current_nr_sectors) { + req->nr_sectors = req->current_nr_sectors; + printk("end_request: buffer-list destroyed\n"); + } + req->buffer = bh->b_data; + return; + } + } + DEVICE_OFF(req->dev); + CURRENT = req->next; + if ((p = req->waiting) != NULL) { + req->waiting = NULL; + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } + req->dev = -1; + wake_up(&wait_for_request); +} +#endif + +#ifdef DEVICE_INTR +#define CLEAR_INTR SET_INTR(NULL) +#else +#define CLEAR_INTR +#endif + +#define INIT_REQUEST \ + if (!CURRENT) {\ + CLEAR_INTR; \ + return; \ + } \ + if (MAJOR(CURRENT->dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + } + +#endif + +#endif +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/cdu31a.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/cdu31a.c new file mode 100644 index 000000000..063da6266 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/cdu31a.c @@ -0,0 +1,1852 @@ +/* + * Sony CDU-31A CDROM interface device driver. + * + * Corey Minyard (minyard@wf-rch.cirr.com) + * + * Colossians 3:17 + * + * The Sony interface device driver handles Sony interface CDROM + * drives and provides a complete block-level interface as well as an + * ioctl() interface compatible with the Sun (as specified in + * include/linux/cdrom.h). With this interface, CDROMs can be + * accessed and standard audio CDs can be played back normally. + * + * This interface is (unfortunatly) a polled interface. This is + * because most Sony interfaces are set up with DMA and interrupts + * disables. Some (like mine) do not even have the capability to + * handle interrupts or DMA. For this reason you will see a lot of + * the following: + * + * retry_count = jiffies+ SONY_JIFFIES_TIMEOUT; + * while ((retry_count > jiffies) && (! +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#define MAJOR_NR CDU31A_CDROM_MAJOR +#include "blk.h" + +#define CDU31A_MAX_CONSECUTIVE_ATTENTIONS 10 + +static unsigned short cdu31a_addresses[] = +{ + 0x340, /* Standard configuration Sony Interface */ + 0x1f88, /* Fusion CD-16 */ + 0x230, /* SoundBlaster 16 card */ + 0x360, /* Secondary standard Sony Interface */ + 0x320, /* Secondary standard Sony Interface */ + 0x330, /* Secondary standard Sony Interface */ + 0 +}; + + +static int handle_sony_cd_attention(void); +static int read_subcode(void); +static void sony_get_toc(void); +static int scd_open(struct inode *inode, struct file *filp); +static void do_sony_cd_cmd(unsigned char cmd, + unsigned char *params, + unsigned int num_params, + unsigned char *result_buffer, + unsigned int *result_size); +static void size_to_buf(unsigned int size, + unsigned char *buf); + + +/* The base I/O address of the Sony Interface. This is a variable (not a + #define) so it can be easily changed via some future ioctl() */ +static unsigned short sony_cd_base_io = 0; + +/* + * The following are I/O addresses of the various registers for the drive. The + * comment for the base address also applies here. + */ +static volatile unsigned short sony_cd_cmd_reg; +static volatile unsigned short sony_cd_param_reg; +static volatile unsigned short sony_cd_write_reg; +static volatile unsigned short sony_cd_control_reg; +static volatile unsigned short sony_cd_status_reg; +static volatile unsigned short sony_cd_result_reg; +static volatile unsigned short sony_cd_read_reg; +static volatile unsigned short sony_cd_fifost_reg; + + +static int sony_disc_changed = 1; /* Has the disk been changed + since the last check? */ +static int sony_toc_read = 0; /* Has the table of contents been + read? */ +static int sony_spun_up = 0; /* Has the drive been spun up? */ +static unsigned int sony_buffer_size; /* Size in bytes of the read-ahead + buffer. */ +static unsigned int sony_buffer_sectors; /* Size (in 2048 byte records) of + the read-ahead buffer. */ +static unsigned int sony_usage = 0; /* How many processes have the + drive open. */ + +static volatile int sony_first_block = -1; /* First OS block (512 byte) in + the read-ahead buffer */ +static volatile int sony_last_block = -1; /* Last OS block (512 byte) in + the read-ahead buffer */ + +static struct s_sony_toc *sony_toc; /* Points to the table of + contents. */ +static struct s_sony_subcode * volatile last_sony_subcode; /* Points to the last + subcode address read */ +static unsigned char * volatile sony_buffer; /* Points to the read-ahead + buffer */ + +static volatile int sony_inuse = 0; /* Is the drive in use? Only one operation at a time + allowed */ + +static struct wait_queue * sony_wait = NULL; + +static struct task_struct *has_cd_task = NULL; /* The task that is currently using the + CDROM drive, or NULL if none. */ + +/* + * The audio status uses the values from read subchannel data as specified + * in include/linux/cdrom.h. + */ +static volatile int sony_audio_status = CDROM_AUDIO_NO_STATUS; + +/* + * The following are a hack for pausing and resuming audio play. The drive + * does not work as I would expect it, if you stop it then start it again, + * the drive seeks back to the beginning and starts over. This holds the + * position during a pause so a resume can restart it. It uses the + * audio status variable above to tell if it is paused. + */ +unsigned volatile char cur_pos_msf[3] = { 0, 0, 0 }; +unsigned volatile char final_pos_msf[3] = { 0, 0, 0 }; + +/* + * This routine returns 1 if the disk has been changed since the last + * check or 0 if it hasn't. Setting flag to 0 resets the changed flag. + */ +int +check_cdu31a_media_change(int full_dev, int flag) +{ + int retval, target; + + + target = MINOR(full_dev); + + if (target > 0) { + printk("Sony CD-ROM request error: invalid device.\n"); + return 0; + } + + retval = sony_disc_changed; + if (!flag) + { + sony_disc_changed = 0; + } + + return retval; +} + + +/* + * Wait a little while (used for polling the drive). If in initialization, + * setting a timeout doesn't work, so just loop for a while. + */ +static inline void +sony_sleep(void) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies; + schedule(); +} + + +/* + * The following are convenience routine to read various status and set + * various conditions in the drive. + */ +static inline int +is_attention(void) +{ + return((inb(sony_cd_status_reg) & SONY_ATTN_BIT) != 0); +} + +static inline int +is_busy(void) +{ + return((inb(sony_cd_status_reg) & SONY_BUSY_BIT) != 0); +} + +static inline int +is_data_ready(void) +{ + return((inb(sony_cd_status_reg) & SONY_DATA_RDY_BIT) != 0); +} + +static inline int +is_data_requested(void) +{ + return((inb(sony_cd_status_reg) & SONY_DATA_REQUEST_BIT) != 0); +} + +static inline int +is_result_ready(void) +{ + return((inb(sony_cd_status_reg) & SONY_RES_RDY_BIT) != 0); +} + +static inline int +is_param_write_rdy(void) +{ + return((inb(sony_cd_fifost_reg) & SONY_PARAM_WRITE_RDY_BIT) != 0); +} + +static inline void +reset_drive(void) +{ + outb(SONY_DRIVE_RESET_BIT, sony_cd_control_reg); +} + +static inline void +clear_attention(void) +{ + outb(SONY_ATTN_CLR_BIT, sony_cd_control_reg); +} + +static inline void +clear_result_ready(void) +{ + outb(SONY_RES_RDY_CLR_BIT, sony_cd_control_reg); +} + +static inline void +clear_data_ready(void) +{ + outb(SONY_DATA_RDY_CLR_BIT, sony_cd_control_reg); +} + +static inline void +clear_param_reg(void) +{ + outb(SONY_PARAM_CLR_BIT, sony_cd_control_reg); +} + +static inline unsigned char +read_status_register(void) +{ + return(inb(sony_cd_status_reg)); +} + +static inline unsigned char +read_result_register(void) +{ + return(inb(sony_cd_result_reg)); +} + +static inline unsigned char +read_data_register(void) +{ + return(inb(sony_cd_read_reg)); +} + +static inline void +write_param(unsigned char param) +{ + outb(param, sony_cd_param_reg); +} + +static inline void +write_cmd(unsigned char cmd) +{ + outb(cmd, sony_cd_cmd_reg); + outb(SONY_RES_RDY_INT_EN_BIT, sony_cd_control_reg); +} + +/* + * Set the drive parameters so the drive will auto-spin-up when a + * disk is inserted. + */ +static void +set_drive_params(void) +{ + unsigned char res_reg[2]; + unsigned int res_size; + unsigned char params[3]; + + + params[0] = SONY_SD_MECH_CONTROL; + params[1] = 0x03; + do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, + params, + 2, + res_reg, + &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk(" Unable to set mechanical parameters: 0x%2.2x\n", res_reg[1]); + } +} + +/* + * This code will reset the drive and attempt to restore sane parameters. + */ +static void +restart_on_error(void) +{ + unsigned char res_reg[2]; + unsigned int res_size; + unsigned int retry_count; + + + printk("cdu31a: Resetting drive on error\n"); + reset_drive(); + retry_count = jiffies + SONY_RESET_TIMEOUT; + while ((retry_count > jiffies) && (!is_attention())) + { + sony_sleep(); + } + set_drive_params(); + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("cdu31a: Unable to spin up drive: 0x%2.2x\n", res_reg[1]); + } + + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 200; + schedule(); + + do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("cdu31a: Unable to read TOC: 0x%2.2x\n", res_reg[1]); + } + sony_get_toc(); + if (!sony_toc_read) + { + printk("cdu31a: Unable to get TOC data\n"); + } +} + +/* + * This routine writes data to the parameter register. Since this should + * happen fairly fast, it is polled with no OS waits between. + */ +static int +write_params(unsigned char *params, + int num_params) +{ + unsigned int retry_count; + + + retry_count = SONY_READY_RETRIES; + while ((retry_count > 0) && (!is_param_write_rdy())) + { + retry_count--; + } + if (!is_param_write_rdy()) + { + return -EIO; + } + + while (num_params > 0) + { + write_param(*params); + params++; + num_params--; + } + + return 0; +} + + +/* + * The following reads data from the command result register. It is a + * fairly complex routine, all status info flows back through this + * interface. The algorithm is stolen directly from the flowcharts in + * the drive manual. + */ +static void +get_result(unsigned char *result_buffer, + unsigned int *result_size) +{ + unsigned char a, b; + int i; + unsigned int retry_count; + + + while (handle_sony_cd_attention()) + ; + /* Wait for the result data to be ready */ + retry_count = jiffies + SONY_JIFFIES_TIMEOUT; + while ((retry_count > jiffies) && (is_busy() || (!(is_result_ready())))) + { + sony_sleep(); + + while (handle_sony_cd_attention()) + ; + } + if (is_busy() || (!(is_result_ready()))) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + return; + } + + /* + * Get the first two bytes. This determines what else needs + * to be done. + */ + clear_result_ready(); + a = read_result_register(); + *result_buffer = a; + result_buffer++; + b = read_result_register(); + *result_buffer = b; + result_buffer++; + *result_size = 2; + + /* + * 0x20 means an error occured. Byte 2 will have the error code. + * Otherwise, the command succeded, byte 2 will have the count of + * how many more status bytes are coming. + * + * The result register can be read 10 bytes at a time, a wait for + * result ready to be asserted must be done between every 10 bytes. + */ + if ((a & 0xf0) != 0x20) + { + if (b > 8) + { + for (i=0; i<8; i++) + { + *result_buffer = read_result_register(); + result_buffer++; + (*result_size)++; + } + b = b - 8; + + while (b > 10) + { + retry_count = SONY_READY_RETRIES; + while ((retry_count > 0) && (!is_result_ready())) + { + retry_count--; + } + if (!is_result_ready()) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + return; + } + + clear_result_ready(); + + for (i=0; i<10; i++) + { + *result_buffer = read_result_register(); + result_buffer++; + (*result_size)++; + } + b = b - 10; + } + + if (b > 0) + { + retry_count = SONY_READY_RETRIES; + while ((retry_count > 0) && (!is_result_ready())) + { + retry_count--; + } + if (!is_result_ready()) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + return; + } + } + } + + while (b > 0) + { + *result_buffer = read_result_register(); + result_buffer++; + (*result_size)++; + b--; + } + } +} + +/* + * Read in a 2048 byte block of data. + */ +static void +read_data_block(unsigned char *data, + unsigned char *result_buffer, + unsigned int *result_size) +{ + int i; + unsigned int retry_count; + + for (i=0; i<2048; i++) + { + retry_count = jiffies + SONY_JIFFIES_TIMEOUT; + while ((retry_count > jiffies) && (!is_data_requested())) + { + while (handle_sony_cd_attention()) + ; + + sony_sleep(); + } + if (!is_data_requested()) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + return; + } + + *data = read_data_register(); + data++; + } +} + +/* + * This routine issues a read data command and gets the data. I don't + * really like the way this is done (I would prefer for do_sony_cmd() to + * handle it automatically) but I found that the drive returns status + * when it finishes reading (not when the host has read all the data) + * or after it gets an error. This means that the status can be + * received at any time and should be handled immediately (at least + * between every 2048 byte block) to check for errors, we can't wait + * until all the data is read. + * + * This routine returns the total number of sectors read. It will + * not return an error if it reads at least one sector successfully. + */ +static unsigned int +get_data(unsigned char *orig_data, + unsigned char *params, /* 6 bytes with the MSF start address + and number of sectors to read. */ + unsigned int orig_data_size, + unsigned char *result_buffer, + unsigned int *result_size) +{ + unsigned int cur_offset; + unsigned int retry_count; + int result_read; + int num_retries; + unsigned int num_sectors_read = 0; + unsigned char *data = orig_data; + unsigned int data_size = orig_data_size; + + + cli(); + while (sony_inuse) + { + interruptible_sleep_on(&sony_wait); + if (current->signal & ~current->blocked) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_SIGNAL_OP_ERR; + *result_size = 2; + return 0; + } + } + sony_inuse = 1; + has_cd_task = current; + sti(); + + num_retries = 0; +retry_data_operation: + result_buffer[0] = 0; + result_buffer[1] = 0; + + /* + * Clear any outstanding attentions and wait for the drive to + * complete any pending operations. + */ + while (handle_sony_cd_attention()) + ; + + retry_count = jiffies + SONY_JIFFIES_TIMEOUT; + while ((retry_count > jiffies) && (is_busy())) + { + sony_sleep(); + + while (handle_sony_cd_attention()) + ; + } + + if (is_busy()) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + } + else + { + /* Issue the command */ + clear_result_ready(); + clear_param_reg(); + + write_params(params, 6); + write_cmd(SONY_READ_CMD); + + /* + * Read the data from the drive one 2048 byte sector at a time. Handle + * any results received between sectors, if an error result is returned + * terminate the operation immediately. + */ + cur_offset = 0; + result_read = 0; + while ((data_size > 0) && (result_buffer[0] == 0)) + { + /* Wait for the drive to tell us we have something */ + retry_count = jiffies + SONY_JIFFIES_TIMEOUT; + while ((retry_count > jiffies) && (!(is_result_ready() || is_data_ready()))) + { + while (handle_sony_cd_attention()) + ; + + sony_sleep(); + } + if (!(is_result_ready() || is_data_ready())) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + } + + /* Handle results first */ + else if (is_result_ready()) + { + result_read = 1; + get_result(result_buffer, result_size); + } + else /* Handle data next */ + { + /* + * The drive has to be polled for status on a byte-by-byte basis + * to know if the data is ready. Yuck. I really wish I could use DMA. + */ + clear_data_ready(); + read_data_block(data, result_buffer, result_size); + data += 2048; + data_size -= 2048; + cur_offset = cur_offset + 2048; + num_sectors_read++; + } + } + + /* Make sure the result has been read */ + if (!result_read) + { + get_result(result_buffer, result_size); + } + } + + if ( ((result_buffer[0] & 0x20) == 0x20) + && (result_buffer[1] != SONY_NOT_SPIN_ERR) /* No retry when not spin */ + && (num_retries < MAX_CDU31A_RETRIES)) + { + /* + * If an error occurs, go back and only read one sector at the + * given location. Hopefully the error occurred on an unused + * sector after the first one. It is hard to say which sector + * the error occurred on because the drive returns status before + * the data transfer is finished and doesn't say which sector. + */ + data_size = 2048; + data = orig_data; + num_sectors_read = 0; + size_to_buf(1, ¶ms[3]); + + num_retries++; + /* Issue a reset on an error (the second time), othersize just delay */ + if (num_retries == 2) + { + restart_on_error(); + } + else + { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 10; + schedule(); + } + + /* Restart the operation. */ + goto retry_data_operation; + } + + has_cd_task = NULL; + sony_inuse = 0; + wake_up_interruptible(&sony_wait); + + return(num_sectors_read); +} + + +/* + * Do a command that does not involve data transfer. This routine must + * be re-entrant from the same task to support being called from the + * data operation code when an error occurs. + */ +static void +do_sony_cd_cmd(unsigned char cmd, + unsigned char *params, + unsigned int num_params, + unsigned char *result_buffer, + unsigned int *result_size) +{ + unsigned int retry_count; + int num_retries; + int recursive_call; + + + cli(); + if (current != has_cd_task) /* Allow recursive calls to this routine */ + { + while (sony_inuse) + { + interruptible_sleep_on(&sony_wait); + if (current->signal & ~current->blocked) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_SIGNAL_OP_ERR; + *result_size = 2; + return; + } + } + sony_inuse = 1; + has_cd_task = current; + recursive_call = 0; + } + else + { + recursive_call = 1; + } + sti(); + + num_retries = 0; +retry_cd_operation: + + while (handle_sony_cd_attention()) + ; + + retry_count = jiffies + SONY_JIFFIES_TIMEOUT; + while ((retry_count > jiffies) && (is_busy())) + { + sony_sleep(); + + while (handle_sony_cd_attention()) + ; + } + if (is_busy()) + { + result_buffer[0] = 0x20; + result_buffer[1] = SONY_TIMEOUT_OP_ERR; + *result_size = 2; + } + else + { + clear_result_ready(); + clear_param_reg(); + + write_params(params, num_params); + write_cmd(cmd); + + get_result(result_buffer, result_size); + } + + if ( ((result_buffer[0] & 0x20) == 0x20) + && (num_retries < MAX_CDU31A_RETRIES)) + { + num_retries++; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 10; /* Wait .1 seconds on retries */ + schedule(); + goto retry_cd_operation; + } + + if (!recursive_call) + { + has_cd_task = NULL; + sony_inuse = 0; + wake_up_interruptible(&sony_wait); + } +} + + +/* + * Handle an attention from the drive. This will return 1 if it found one + * or 0 if not (if one is found, the caller might want to call again). + * + * This routine counts the number of consecutive times it is called + * (since this is always called from a while loop until it returns + * a 0), and returns a 0 if it happens too many times. This will help + * prevent a lockup. + */ +static int +handle_sony_cd_attention(void) +{ + unsigned char atten_code; + static int num_consecutive_attentions = 0; + + + if (is_attention()) + { + if (num_consecutive_attentions > CDU31A_MAX_CONSECUTIVE_ATTENTIONS) + { + printk("cdu31a: Too many consecutive attentions: %d\n", + num_consecutive_attentions); + num_consecutive_attentions = 0; + return(0); + } + + clear_attention(); + atten_code = read_result_register(); + + switch (atten_code) + { + /* Someone changed the CD. Mark it as changed */ + case SONY_MECH_LOADED_ATTN: + sony_disc_changed = 1; + sony_toc_read = 0; + sony_audio_status = CDROM_AUDIO_NO_STATUS; + sony_first_block = -1; + sony_last_block = -1; + break; + + case SONY_AUDIO_PLAY_DONE_ATTN: + sony_audio_status = CDROM_AUDIO_COMPLETED; + read_subcode(); + break; + + case SONY_EJECT_PUSHED_ATTN: + sony_audio_status = CDROM_AUDIO_INVALID; + break; + + case SONY_LEAD_IN_ERR_ATTN: + case SONY_LEAD_OUT_ERR_ATTN: + case SONY_DATA_TRACK_ERR_ATTN: + case SONY_AUDIO_PLAYBACK_ERR_ATTN: + sony_audio_status = CDROM_AUDIO_ERROR; + break; + } + + num_consecutive_attentions++; + return(1); + } + + num_consecutive_attentions = 0; + return(0); +} + + +/* Convert from an integer 0-99 to BCD */ +static inline unsigned int +int_to_bcd(unsigned int val) +{ + int retval; + + + retval = (val / 10) << 4; + retval = retval | val % 10; + return(retval); +} + + +/* Convert from BCD to an integer from 0-99 */ +static unsigned int +bcd_to_int(unsigned int bcd) +{ + return((((bcd >> 4) & 0x0f) * 10) + (bcd & 0x0f)); +} + + +/* + * Convert a logical sector value (like the OS would want to use for + * a block device) to an MSF format. + */ +static void +log_to_msf(unsigned int log, unsigned char *msf) +{ + log = log + LOG_START_OFFSET; + msf[0] = int_to_bcd(log / 4500); + log = log % 4500; + msf[1] = int_to_bcd(log / 75); + msf[2] = int_to_bcd(log % 75); +} + + +/* + * Convert an MSF format to a logical sector. + */ +static unsigned int +msf_to_log(unsigned char *msf) +{ + unsigned int log; + + + log = bcd_to_int(msf[2]); + log += bcd_to_int(msf[1]) * 75; + log += bcd_to_int(msf[0]) * 4500; + log = log - LOG_START_OFFSET; + + return log; +} + + +/* + * Take in integer size value and put it into a buffer like + * the drive would want to see a number-of-sector value. + */ +static void +size_to_buf(unsigned int size, + unsigned char *buf) +{ + buf[0] = size / 65536; + size = size % 65536; + buf[1] = size / 256; + buf[2] = size % 256; +} + + +/* + * The OS calls this to perform a read or write operation to the drive. + * Write obviously fail. Reads to a read ahead of sony_buffer_size + * bytes to help speed operations. This especially helps since the OS + * uses 1024 byte blocks and the drive uses 2048 byte blocks. Since most + * data access on a CD is done sequentially, this saves a lot of operations. + */ +static void +do_cdu31a_request(void) +{ + int block; + unsigned int dev; + int nsect; + unsigned char params[10]; + unsigned char res_reg[2]; + unsigned int res_size; + int copyoff; + int spin_up_retry; + unsigned int read_size; + + + if (!sony_spun_up) + { + scd_open (NULL,NULL); + } + + while (1) + { +cdu31a_request_startover: + /* + * The beginning here is stolen from the hard disk driver. I hope + * its right. + */ + if (!(CURRENT) || CURRENT->dev < 0) + { + return; + } + + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + if (dev != 0) + { + end_request(0); + goto cdu31a_request_startover; + } + + switch(CURRENT->cmd) + { + case READ: + /* + * If the block address is invalid or the request goes beyond the end of + * the media, return an error. + */ + if ((block / 4) >= sony_toc->lead_out_start_lba) + { + end_request(0); + goto cdu31a_request_startover; + } + if (((block + nsect) / 4) >= sony_toc->lead_out_start_lba) + { + end_request(0); + goto cdu31a_request_startover; + } + + while (nsect > 0) + { + /* + * If the requested sector is not currently in the read-ahead buffer, + * it must be read in. + */ + if ((block < sony_first_block) || (block > sony_last_block)) + { + sony_first_block = (block / 4) * 4; + log_to_msf(block/4, params); + + /* + * If the full read-ahead would go beyond the end of the media, trim + * it back to read just till the end of the media. + */ + if (((block / 4) + sony_buffer_sectors) >= sony_toc->lead_out_start_lba) + { + read_size = sony_toc->lead_out_start_lba - (block / 4); + } + else + { + read_size = sony_buffer_sectors; + } + size_to_buf(read_size, ¶ms[3]); + + /* + * Read the data. If the drive was not spinning, spin it up and try + * once more. I know, the goto is ugly, but I am too lazy to fix it. + */ + spin_up_retry = 0; +try_read_again: + sony_last_block = sony_first_block + + (get_data(sony_buffer, + params, + (read_size * 2048), + res_reg, + &res_size) * 4) - 1; + if ((res_size < 2) || (res_reg[0] != 0)) + { + if ((res_reg[1] == SONY_NOT_SPIN_ERR) && (!spin_up_retry)) + { + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + spin_up_retry = 1; + goto try_read_again; + } + + printk("Sony CDROM Read error: 0x%2.2x\n", res_reg[1]); + sony_first_block = -1; + sony_last_block = -1; + end_request(0); + goto cdu31a_request_startover; + } + } + + /* + * The data is in memory now, copy it to the buffer and advance to the + * next block to read. + */ + copyoff = (block - sony_first_block) * 512; + memcpy(CURRENT->buffer, sony_buffer+copyoff, 512); + + block += 1; + nsect -= 1; + CURRENT->buffer += 512; + } + + end_request(1); + break; + + case WRITE: + end_request(0); + break; + + default: + panic("Unkown SONY CD cmd"); + } + } +} + + +/* + * Read the table of contents from the drive and set sony_toc_read if + * successful. + */ +static void +sony_get_toc(void) +{ + unsigned int res_size; + + + if (!sony_toc_read) + { + do_sony_cd_cmd(SONY_REQ_TOC_DATA_CMD, + NULL, + 0, + (unsigned char *) sony_toc, + &res_size); + if ((res_size < 2) || ((sony_toc->exec_status[0] & 0x20) == 0x20)) + { + return; + } + sony_toc->lead_out_start_lba = msf_to_log(sony_toc->lead_out_start_msf); + sony_toc_read = 1; + } +} + + +/* + * Search for a specific track in the table of contents. + */ +static int +find_track(int track) +{ + int i; + int num_tracks; + + + num_tracks = sony_toc->last_track_num + sony_toc->first_track_num + 1; + for (i = 0; i < num_tracks; i++) + { + if (sony_toc->tracks[i].track == track) + { + return i; + } + } + + return -1; +} + + +/* + * Read the subcode and put it int last_sony_subcode for future use. + */ +static int +read_subcode(void) +{ + unsigned int res_size; + + + do_sony_cd_cmd(SONY_REQ_SUBCODE_ADDRESS_CMD, + NULL, + 0, + (unsigned char *) last_sony_subcode, + &res_size); + if ((res_size < 2) || ((last_sony_subcode->exec_status[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (read_subcode)\n", + last_sony_subcode->exec_status[1]); + return -EIO; + } + + return 0; +} + + +/* + * Get the subchannel info like the CDROMSUBCHNL command wants to see it. If + * the drive is playing, the subchannel needs to be read (since it would be + * changing). If the drive is paused or completed, the subcode information has + * already been stored, just use that. The ioctl call wants things in decimal + * (not BCD), so all the conversions are done. + */ +static int +sony_get_subchnl_info(long arg) +{ + struct cdrom_subchnl schi; + + + /* Get attention stuff */ + while (handle_sony_cd_attention()) + ; + + sony_get_toc(); + if (!sony_toc_read) + { + return -EIO; + } + + verify_area(VERIFY_READ, (char *) arg, sizeof(schi)); + verify_area(VERIFY_WRITE, (char *) arg, sizeof(schi)); + + memcpy_fromfs(&schi, (char *) arg, sizeof(schi)); + + switch (sony_audio_status) + { + case CDROM_AUDIO_PLAY: + if (read_subcode() < 0) + { + return -EIO; + } + break; + + case CDROM_AUDIO_PAUSED: + case CDROM_AUDIO_COMPLETED: + break; + + case CDROM_AUDIO_NO_STATUS: + schi.cdsc_audiostatus = sony_audio_status; + memcpy_tofs((char *) arg, &schi, sizeof(schi)); + return 0; + break; + + case CDROM_AUDIO_INVALID: + case CDROM_AUDIO_ERROR: + default: + return -EIO; + } + + schi.cdsc_audiostatus = sony_audio_status; + schi.cdsc_adr = last_sony_subcode->address; + schi.cdsc_ctrl = last_sony_subcode->control; + schi.cdsc_trk = bcd_to_int(last_sony_subcode->track_num); + schi.cdsc_ind = bcd_to_int(last_sony_subcode->index_num); + if (schi.cdsc_format == CDROM_MSF) + { + schi.cdsc_absaddr.msf.minute = bcd_to_int(last_sony_subcode->abs_msf[0]); + schi.cdsc_absaddr.msf.second = bcd_to_int(last_sony_subcode->abs_msf[1]); + schi.cdsc_absaddr.msf.frame = bcd_to_int(last_sony_subcode->abs_msf[2]); + + schi.cdsc_reladdr.msf.minute = bcd_to_int(last_sony_subcode->rel_msf[0]); + schi.cdsc_reladdr.msf.second = bcd_to_int(last_sony_subcode->rel_msf[1]); + schi.cdsc_reladdr.msf.frame = bcd_to_int(last_sony_subcode->rel_msf[2]); + } + else if (schi.cdsc_format == CDROM_LBA) + { + schi.cdsc_absaddr.lba = msf_to_log(last_sony_subcode->abs_msf); + schi.cdsc_reladdr.lba = msf_to_log(last_sony_subcode->rel_msf); + } + + memcpy_tofs((char *) arg, &schi, sizeof(schi)); + return 0; +} + + +/* + * The big ugly ioctl handler. + */ +static int +scd_ioctl(struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + unsigned int dev; + unsigned char res_reg[2]; + unsigned int res_size; + unsigned char params[7]; + int i; + + + if (!inode) + { + return -EINVAL; + } + dev = MINOR(inode->i_rdev) >> 6; + if (dev != 0) + { + return -EINVAL; + } + + switch (cmd) + { + case CDROMSTART: /* Spin up the drive */ + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (CDROMSTART)\n", res_reg[1]); + return -EIO; + } + return 0; + break; + + case CDROMSTOP: /* Spin down the drive */ + do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size); + + /* + * Spin the drive down, ignoring the error if the disk was + * already not spinning. + */ + sony_audio_status = CDROM_AUDIO_NO_STATUS; + do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size); + if ( ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + && (res_reg[1] != SONY_NOT_SPIN_ERR)) + { + printk("Sony CDROM error 0x%2.2x (CDROMSTOP)\n", res_reg[1]); + return -EIO; + } + + return 0; + break; + + case CDROMPAUSE: /* Pause the drive */ + do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (CDROMPAUSE)\n", res_reg[1]); + return -EIO; + } + + /* Get the current position and save it for resuming */ + if (read_subcode() < 0) + { + return -EIO; + } + cur_pos_msf[0] = last_sony_subcode->abs_msf[0]; + cur_pos_msf[1] = last_sony_subcode->abs_msf[1]; + cur_pos_msf[2] = last_sony_subcode->abs_msf[2]; + sony_audio_status = CDROM_AUDIO_PAUSED; + return 0; + break; + + case CDROMRESUME: /* Start the drive after being paused */ + if (sony_audio_status != CDROM_AUDIO_PAUSED) + { + return -EINVAL; + } + + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + + /* Start the drive at the saved position. */ + params[1] = cur_pos_msf[0]; + params[2] = cur_pos_msf[1]; + params[3] = cur_pos_msf[2]; + params[4] = final_pos_msf[0]; + params[5] = final_pos_msf[1]; + params[6] = final_pos_msf[2]; + params[0] = 0x03; + do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (CDROMRESUME)\n", res_reg[1]); + return -EIO; + } + sony_audio_status = CDROM_AUDIO_PLAY; + return 0; + break; + + case CDROMPLAYMSF: /* Play starting at the given MSF address. */ + verify_area(VERIFY_READ, (char *) arg, 6); + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + memcpy_fromfs(&(params[1]), (void *) arg, 6); + + /* The parameters are given in int, must be converted */ + for (i=1; i<7; i++) + { + params[i] = int_to_bcd(params[i]); + } + params[0] = 0x03; + do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (CDROMPLAYMSF)\n", res_reg[1]); + return -EIO; + } + + /* Save the final position for pauses and resumes */ + final_pos_msf[0] = params[4]; + final_pos_msf[1] = params[5]; + final_pos_msf[2] = params[6]; + sony_audio_status = CDROM_AUDIO_PLAY; + return 0; + break; + + case CDROMREADTOCHDR: /* Read the table of contents header */ + { + struct cdrom_tochdr *hdr; + struct cdrom_tochdr loc_hdr; + + sony_get_toc(); + if (!sony_toc_read) + { + return -EIO; + } + + hdr = (struct cdrom_tochdr *) arg; + verify_area(VERIFY_WRITE, hdr, sizeof(*hdr)); + loc_hdr.cdth_trk0 = bcd_to_int(sony_toc->first_track_num); + loc_hdr.cdth_trk1 = bcd_to_int(sony_toc->last_track_num); + memcpy_tofs(hdr, &loc_hdr, sizeof(*hdr)); + } + return 0; + break; + + case CDROMREADTOCENTRY: /* Read a given table of contents entry */ + { + struct cdrom_tocentry *entry; + struct cdrom_tocentry loc_entry; + int track_idx; + unsigned char *msf_val = NULL; + + sony_get_toc(); + if (!sony_toc_read) + { + return -EIO; + } + + entry = (struct cdrom_tocentry *) arg; + verify_area(VERIFY_READ, entry, sizeof(*entry)); + verify_area(VERIFY_WRITE, entry, sizeof(*entry)); + + memcpy_fromfs(&loc_entry, entry, sizeof(loc_entry)); + + /* Lead out is handled separately since it is special. */ + if (loc_entry.cdte_track == CDROM_LEADOUT) + { + loc_entry.cdte_adr = sony_toc->address2; + loc_entry.cdte_ctrl = sony_toc->control2; + msf_val = sony_toc->lead_out_start_msf; + } + else + { + track_idx = find_track(int_to_bcd(loc_entry.cdte_track)); + if (track_idx < 0) + { + return -EINVAL; + } + + loc_entry.cdte_adr = sony_toc->tracks[track_idx].address; + loc_entry.cdte_ctrl = sony_toc->tracks[track_idx].control; + msf_val = sony_toc->tracks[track_idx].track_start_msf; + } + + /* Logical buffer address or MSF format requested? */ + if (loc_entry.cdte_format == CDROM_LBA) + { + loc_entry.cdte_addr.lba = msf_to_log(msf_val); + } + else if (loc_entry.cdte_format == CDROM_MSF) + { + loc_entry.cdte_addr.msf.minute = bcd_to_int(*msf_val); + loc_entry.cdte_addr.msf.second = bcd_to_int(*(msf_val+1)); + loc_entry.cdte_addr.msf.frame = bcd_to_int(*(msf_val+2)); + } + memcpy_tofs(entry, &loc_entry, sizeof(*entry)); + } + return 0; + break; + + case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ + { + struct cdrom_ti ti; + int track_idx; + + sony_get_toc(); + if (!sony_toc_read) + { + return -EIO; + } + + verify_area(VERIFY_READ, (char *) arg, sizeof(ti)); + + memcpy_fromfs(&ti, (char *) arg, sizeof(ti)); + if ( (ti.cdti_trk0 < sony_toc->first_track_num) + || (ti.cdti_trk0 > sony_toc->last_track_num) + || (ti.cdti_trk1 < ti.cdti_trk0)) + { + return -EINVAL; + } + + track_idx = find_track(int_to_bcd(ti.cdti_trk0)); + if (track_idx < 0) + { + return -EINVAL; + } + params[1] = sony_toc->tracks[track_idx].track_start_msf[0]; + params[2] = sony_toc->tracks[track_idx].track_start_msf[1]; + params[3] = sony_toc->tracks[track_idx].track_start_msf[2]; + + /* + * If we want to stop after the last track, use the lead-out + * MSF to do that. + */ + if (ti.cdti_trk1 >= bcd_to_int(sony_toc->last_track_num)) + { + log_to_msf(msf_to_log(sony_toc->lead_out_start_msf)-1, + &(params[4])); + } + else + { + track_idx = find_track(int_to_bcd(ti.cdti_trk1+1)); + if (track_idx < 0) + { + return -EINVAL; + } + log_to_msf(msf_to_log(sony_toc->tracks[track_idx].track_start_msf)-1, + &(params[4])); + } + params[0] = 0x03; + + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + + do_sony_cd_cmd(SONY_AUDIO_PLAYBACK_CMD, params, 7, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Params: %x %x %x %x %x %x %x\n", params[0], params[1], + params[2], params[3], params[4], params[5], params[6]); + printk("Sony CDROM error 0x%2.2x (CDROMPLAYTRKIND\n", res_reg[1]); + return -EIO; + } + + /* Save the final position for pauses and resumes */ + final_pos_msf[0] = params[4]; + final_pos_msf[1] = params[5]; + final_pos_msf[2] = params[6]; + sony_audio_status = CDROM_AUDIO_PLAY; + return 0; + } + + case CDROMSUBCHNL: /* Get subchannel info */ + return sony_get_subchnl_info(arg); + + case CDROMVOLCTRL: /* Volume control. What volume does this change, anyway? */ + { + struct cdrom_volctrl volctrl; + + verify_area(VERIFY_READ, (char *) arg, sizeof(volctrl)); + + memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); + params[0] = SONY_SD_AUDIO_VOLUME; + params[1] = volctrl.channel0; + params[2] = volctrl.channel1; + do_sony_cd_cmd(SONY_SET_DRIVE_PARAM_CMD, params, 3, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (CDROMVOLCTRL)\n", res_reg[1]); + return -EIO; + } + } + return 0; + + case CDROMEJECT: /* Eject the drive */ + do_sony_cd_cmd(SONY_AUDIO_STOP_CMD, NULL, 0, res_reg, &res_size); + do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size); + + sony_audio_status = CDROM_AUDIO_INVALID; + do_sony_cd_cmd(SONY_EJECT_CMD, NULL, 0, res_reg, &res_size); + if ((res_size < 2) || ((res_reg[0] & 0x20) == 0x20)) + { + printk("Sony CDROM error 0x%2.2x (CDROMEJECT)\n", res_reg[1]); + return -EIO; + } + return 0; + break; + + default: + return -EINVAL; + } +} + + +/* + * Open the drive for operations. Spin the drive up and read the table of + * contents if these have not already been done. + */ +static int +scd_open(struct inode *inode, + struct file *filp) +{ + unsigned char res_reg[2]; + unsigned int res_size; + int num_spin_ups; + + + if (!sony_spun_up) + { + num_spin_ups = 0; + +respinup_on_open: + do_sony_cd_cmd(SONY_SPIN_UP_CMD, NULL, 0, res_reg, &res_size); + + /* The drive sometimes returns error 0. I don't know why, but ignore + it. It seems to mean the drive has already done the operation. */ + if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) + { + printk("Sony CDROM error 0x%2.2x (scd_open, spin up)\n", res_reg[1]); + return -EIO; + } + + do_sony_cd_cmd(SONY_READ_TOC_CMD, NULL, 0, res_reg, &res_size); + + /* The drive sometimes returns error 0. I don't know why, but ignore + it. It seems to mean the drive has already done the operation. */ + if ((res_size < 2) || ((res_reg[0] != 0) && (res_reg[1] != 0))) + { + /* If the drive is already playing, its ok. */ + if ((res_reg[1] == SONY_AUDIO_PLAYING_ERR) || (res_reg[1] == 0)) + { + goto drive_spinning; + } + + /* If the drive says it is not spun up (even though we just did it!) + then retry the operation at least a few times. */ + if ( (res_reg[1] == SONY_NOT_SPIN_ERR) + && (num_spin_ups < MAX_CDU31A_RETRIES)) + { + num_spin_ups++; + goto respinup_on_open; + } + + printk("Sony CDROM error 0x%2.2x (scd_open, read toc)\n", res_reg[1]); + do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size); + + return -EIO; + } + + sony_get_toc(); + if (!sony_toc_read) + { + do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size); + return -EIO; + } + + sony_spun_up = 1; + } + +drive_spinning: + + if (inode) + { + check_disk_change(inode->i_rdev); + } + + sony_usage++; + + return 0; +} + + +/* + * Close the drive. Spin it down if no task is using it. The spin + * down will fail if playing audio, so audio play is OK. + */ +static void +scd_release(struct inode *inode, + struct file *filp) +{ + unsigned char res_reg[2]; + unsigned int res_size; + + + if (sony_usage > 0) + { + sony_usage--; + } + if (sony_usage == 0) + { + sync_dev(inode->i_rdev); + do_sony_cd_cmd(SONY_SPIN_DOWN_CMD, NULL, 0, res_reg, &res_size); + + sony_spun_up = 0; + } +} + + +static struct file_operations scd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + scd_ioctl, /* ioctl */ + NULL, /* mmap */ + scd_open, /* open */ + scd_release, /* release */ + NULL /* fsync */ +}; + + +/* The different types of disc loading mechanisms supported */ +static char *load_mech[] = { "caddy", "tray", "pop-up", "unknown" }; + +/* Read-ahead buffer sizes for different drives. These are just arbitrary + values, I don't know what is really optimum. */ +static unsigned int mem_size[] = { 16384, 16384, 16384, 2048 }; + +void +get_drive_configuration(unsigned short base_io, + unsigned char res_reg[], + unsigned int *res_size) +{ + int retry_count; + + + /* Set the base address */ + sony_cd_base_io = base_io; + + /* Set up all the register locations */ + sony_cd_cmd_reg = sony_cd_base_io + SONY_CMD_REG_OFFSET; + sony_cd_param_reg = sony_cd_base_io + SONY_PARAM_REG_OFFSET; + sony_cd_write_reg = sony_cd_base_io + SONY_WRITE_REG_OFFSET; + sony_cd_control_reg = sony_cd_base_io + SONY_CONTROL_REG_OFFSET; + sony_cd_status_reg = sony_cd_base_io + SONY_STATUS_REG_OFFSET; + sony_cd_result_reg = sony_cd_base_io + SONY_RESULT_REG_OFFSET; + sony_cd_read_reg = sony_cd_base_io + SONY_READ_REG_OFFSET; + sony_cd_fifost_reg = sony_cd_base_io + SONY_FIFOST_REG_OFFSET; + + /* + * Check to see if anything exists at the status register location. + * I don't know if this is a good way to check, but it seems to work + * ok for me. + */ + if (read_status_register() != 0xff) + { + /* + * Reset the drive and wait for attention from it (to say its reset). + * If you don't wait, the next operation will probably fail. + */ + reset_drive(); + retry_count = jiffies + SONY_RESET_TIMEOUT; + while ((retry_count > jiffies) && (!is_attention())) + { + sony_sleep(); + } + + /* If attention is never seen probably not a CDU31a present */ + if (!is_attention()) + { + res_reg[0] = 0x20; + return; + } + + /* + * Get the drive configuration. + */ + do_sony_cd_cmd(SONY_REQ_DRIVE_CONFIG_CMD, + NULL, + 0, + (unsigned char *) res_reg, + res_size); + return; + } + + /* Return an error */ + res_reg[0] = 0x20; +} + + +/* + * Initialize the driver. + */ +unsigned long +cdu31a_init(unsigned long mem_start, unsigned long mem_end) +{ + struct s_sony_drive_config drive_config; + unsigned int res_size; + int i; + int drive_found; + + + /* + * According to Alex Freed (freed@europa.orion.adobe.com), this is + * required for the Fusion CD-16 package. If the sound driver is + * loaded, it should work fine, but just in case... + * + * The following turn on the CD-ROM interface for a Fusion CD-16. + */ + outb(0xbc, 0x9a01); + outb(0xe2, 0x9a01); + + i = 0; + drive_found = 0; + while ( (cdu31a_addresses[i] != 0) + && (!drive_found)) + { + if (check_region(cdu31a_addresses[i], 4)) { + i++; + continue; + } + get_drive_configuration(cdu31a_addresses[i], + drive_config.exec_status, + &res_size); + if ((res_size > 2) && ((drive_config.exec_status[0] & 0x20) == 0x00)) + { + drive_found = 1; + snarf_region(cdu31a_addresses[i], 4); + + if (register_blkdev(MAJOR_NR,"cdu31a",&scd_fops)) + { + printk("Unable to get major %d for CDU-31a\n", MAJOR_NR); + return mem_start; + } + + sony_buffer_size = mem_size[SONY_HWC_GET_BUF_MEM_SIZE(drive_config)]; + sony_buffer_sectors = sony_buffer_size / 2048; + + printk("Sony I/F CDROM : %8.8s %16.16s %8.8s with %s load mechanism\n", + drive_config.vendor_id, + drive_config.product_id, + drive_config.product_rev_level, + load_mech[SONY_HWC_GET_LOAD_MECH(drive_config)]); + printk(" using %d byte buffer", sony_buffer_size); + if (SONY_HWC_AUDIO_PLAYBACK(drive_config)) + { + printk(", capable of audio playback"); + } + printk("\n"); + + set_drive_params(); + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ + + sony_toc = (struct s_sony_toc *) mem_start; + mem_start += sizeof(*sony_toc); + last_sony_subcode = (struct s_sony_subcode *) mem_start; + mem_start += sizeof(*last_sony_subcode); + sony_buffer = (unsigned char *) mem_start; + mem_start += sony_buffer_size; + } + + i++; + } + + return mem_start; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/floppy.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/floppy.c new file mode 100644 index 000000000..ff9b04a3f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/floppy.c @@ -0,0 +1,1387 @@ +/* + * linux/kernel/floppy.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 02.12.91 - Changed to static variables to indicate need for reset + * and recalibrate. This makes some things easier (output_byte reset + * checking etc), and means less interrupt jumping in case of errors, + * so the code is hopefully easier to understand. + */ + +/* + * This file is certainly a mess. I've tried my best to get it working, + * but I don't like programming floppies, and I have only one anyway. + * Urgel. I should check for more errors, and do more graceful error + * recovery. Seems there are problems with several drives. I've tried to + * correct them. No promises. + */ + +/* + * As with hd.c, all routines within this file can (and will) be called + * by interrupts, so extreme caution is needed. A hardware interrupt + * handler may not sleep, or a kernel panic will happen. Thus I cannot + * call "floppy-on" directly, but have to set a special timer interrupt + * etc. + */ + +/* + * 28.02.92 - made track-buffering routines, based on the routines written + * by entropy@wintermute.wpi.edu (Lawrence Foard). Linus. + */ + +/* + * Automatic floppy-detection and formatting written by Werner Almesberger + * (almesber@nessie.cs.id.ethz.ch), who also corrected some problems with + * the floppy-change signal detection. + */ + +/* + * 1992/7/22 -- Hennus Bergman: Added better error reporting, fixed + * FDC data overrun bug, added some preliminary stuff for vertical + * recording support. + * + * 1992/9/17: Added DMA allocation & DMA functions. -- hhb. + * + * TODO: Errors are still not counted properly. + */ + +/* 1992/9/20 + * Modifications for ``Sector Shifting'' by Rob Hooft (hooft@chem.ruu.nl) + * modelled after the freeware MS/DOS program fdformat/88 V1.8 by + * Christoph H. Hochst\"atter. + * I have fixed the shift values to the ones I always use. Maybe a new + * ioctl() should be created to be able to modify them. + * There is a bug in the driver that makes it impossible to format a + * floppy as the first thing after bootup. + */ + +/* + * 1993/4/29 -- Linus -- cleaned up the timer handling in the kernel, and + * this helped the floppy driver as well. Much cleaner, and still seems to + * work. + */ + +#define REALLY_SLOW_IO +#define FLOPPY_IRQ 6 +#define FLOPPY_DMA 2 + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAJOR_NR FLOPPY_MAJOR +#include "blk.h" + +static unsigned int changed_floppies = 0, fake_change = 0; + +static int initial_reset_flag = 0; +static int need_configure = 1; /* for 82077 */ +static int recalibrate = 0; +static int reset = 0; +static int recover = 0; /* recalibrate immediately after resetting */ +static int seek = 0; + +static unsigned char current_DOR = 0x0C; +static unsigned char running = 0; + +#define TYPE(x) ((x)>>2) +#define DRIVE(x) ((x)&0x03) + +/* + * Note that MAX_ERRORS=X doesn't imply that we retry every bad read + * max X times - some types of errors increase the errorcount by 2 or + * even 3, so we might actually retry only X/2 times before giving up. + */ +#define MAX_ERRORS 12 + +/* + * Maximum disk size (in kilobytes). This default is used whenever the + * current disk size is unknown. + */ +#define MAX_DISK_SIZE 1440 + +/* + * Maximum number of sectors in a track buffer. Track buffering is disabled + * if tracks are bigger. + */ +#define MAX_BUFFER_SECTORS 18 + +/* + * The DMA channel used by the floppy controller cannot access data at + * addresses >= 16MB + * + * Went back to the 1MB limit, as some people had problems with the floppy + * driver otherwise. It doesn't matter much for performance anyway, as most + * floppy accesses go through the track buffer. + */ +#define LAST_DMA_ADDR (0x100000 - BLOCK_SIZE) + +/* + * globals used by 'result()' + */ +#define MAX_REPLIES 7 +static unsigned char reply_buffer[MAX_REPLIES]; +#define ST0 (reply_buffer[0]) +#define ST1 (reply_buffer[1]) +#define ST2 (reply_buffer[2]) +#define ST3 (reply_buffer[3]) + +/* + * This struct defines the different floppy types. + * + * The 'stretch' tells if the tracks need to be doubled for some + * types (ie 360kB diskette in 1.2MB drive etc). Others should + * be self-explanatory. + */ +static struct floppy_struct floppy_type[] = { + { 0, 0,0, 0,0,0x00,0x00,0x00,0x00,NULL }, /* no testing */ + { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,NULL }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,NULL }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x2A,0x02,0xDF,0x50,NULL }, /* 360kB in 720kB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,NULL }, /* 3.5" 720kB diskette */ + { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,NULL }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x23,0x01,0xDF,0x50,NULL }, /* 720kB in 1.2MB drive */ + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,NULL }, /* 1.44MB diskette */ +}; + +/* + * Auto-detection. Each drive type has a pair of formats which are + * used in succession to try to read the disk. If the FDC cannot lock onto + * the disk, the next format is tried. This uses the variable 'probing'. + */ +static struct floppy_struct floppy_types[] = { + { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */ + { 720, 9,2,40,0,0x2A,0x02,0xDF,0x50,"360k/PC" }, /* 360kB PC diskettes */ + { 2400,15,2,80,0,0x1B,0x00,0xDF,0x54,"1.2M" }, /* 1.2 MB AT-diskettes */ + { 720, 9,2,40,1,0x23,0x01,0xDF,0x50,"360k/AT" }, /* 360kB in 1.2MB drive */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k" }, /* 3.5" 720kB diskette */ + { 2880,18,2,80,0,0x1B,0x00,0xCF,0x6C,"1.44M" }, /* 1.44MB diskette */ + { 1440, 9,2,80,0,0x2A,0x02,0xDF,0x50,"720k/AT" }, /* 3.5" 720kB diskette */ +}; + +/* Auto-detection: Disk type used until the next media change occurs. */ +struct floppy_struct *current_type[4] = { NULL, NULL, NULL, NULL }; + +/* This type is tried first. */ +struct floppy_struct *base_type[4]; + +/* + * User-provided type information. current_type points to + * the respective entry of this array. + */ +struct floppy_struct user_params[4]; + +static int floppy_sizes[] ={ + MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, MAX_DISK_SIZE, + 360, 360 ,360, 360, + 1200,1200,1200,1200, + 360, 360, 360, 360, + 720, 720, 720, 720, + 360, 360, 360, 360, + 720, 720, 720, 720, + 1440,1440,1440,1440 +}; + +/* + * The driver is trying to determine the correct media format + * while probing is set. rw_interrupt() clears it after a + * successful access. + */ +static int probing = 0; + +/* + * (User-provided) media information is _not_ discarded after a media change + * if the corresponding keep_data flag is non-zero. Positive values are + * decremented after each probe. + */ +static int keep_data[4] = { 0,0,0,0 }; + +/* + * Announce successful media type detection and media information loss after + * disk changes. + * Also used to enable/disable printing of overrun warnings. + */ +static ftd_msg[4] = { 0,0,0,0 }; + +/* Prevent "aliased" accesses. */ + +static fd_ref[4] = { 0,0,0,0 }; +static fd_device[4] = { 0,0,0,0 }; + +/* Synchronization of FDC access. */ +static volatile int format_status = FORMAT_NONE, fdc_busy = 0; +static struct wait_queue *fdc_wait = NULL, *format_done = NULL; + +/* Errors during formatting are counted here. */ +static int format_errors; + +/* Format request descriptor. */ +static struct format_descr format_req; + +/* + * Current device number. Taken either from the block header or from the + * format request descriptor. + */ +#define CURRENT_DEVICE (format_status == FORMAT_BUSY ? format_req.device : \ + (CURRENT->dev)) + +/* Current error count. */ +#define CURRENT_ERRORS (format_status == FORMAT_BUSY ? format_errors : \ + (CURRENT->errors)) + +/* + * Threshold for reporting FDC errors to the console. + * Setting this to zero may flood your screen when using + * ultra cheap floppies ;-) + */ +static unsigned short min_report_error_cnt[4] = {2, 2, 2, 2}; + +/* + * Rate is 0 for 500kb/s, 1 for 300kbps, 2 for 250kbps + * Spec1 is 0xSH, where S is stepping rate (F=1ms, E=2ms, D=3ms etc), + * H is head unload time (1=16ms, 2=32ms, etc) + * + * Spec2 is (HLD<<1 | ND), where HLD is head load time (1=2ms, 2=4 ms etc) + * and ND is set means no DMA. Hardcoded to 6 (HLD=6ms, use DMA). + */ + +/* + * Track buffer and block buffer (in case track buffering doesn't work). + * Because these are written to by the DMA controller, they must + * not contain a 64k byte boundary crossing, or data will be + * corrupted/lost. Alignment of these is enforced in boot/head.s. + * Note that you must not change the sizes below without updating head.s. + */ +extern char tmp_floppy_area[BLOCK_SIZE]; +extern char floppy_track_buffer[512*2*MAX_BUFFER_SECTORS]; + +static void redo_fd_request(void); + +/* + * These are global variables, as that's the easiest way to give + * information to interrupts. They are the data used for the current + * request. + */ +#define NO_TRACK 255 + +static int read_track = 0; /* flag to indicate if we want to read entire track */ +static int buffer_track = -1; +static int buffer_drive = -1; +static int cur_spec1 = -1; +static int cur_rate = -1; +static struct floppy_struct * floppy = floppy_type; +static unsigned char current_drive = 255; +static unsigned char sector = 0; +static unsigned char head = 0; +static unsigned char track = 0; +static unsigned char seek_track = 0; +static unsigned char current_track = NO_TRACK; +static unsigned char command = 0; +static unsigned char fdc_version = FDC_TYPE_STD; /* FDC version code */ + +static void floppy_ready(void); + +static void select_callback(unsigned long unused) +{ + floppy_ready(); +} + +static void floppy_select(unsigned int nr) +{ + static struct timer_list select = { NULL, 0, 0, select_callback }; + + if (current_drive == (current_DOR & 3)) { + floppy_ready(); + return; + } + seek = 1; + current_track = NO_TRACK; + current_DOR &= 0xFC; + current_DOR |= current_drive; + outb(current_DOR,FD_DOR); + del_timer(&select); + select.expires = 2; + add_timer(&select); +} + +static void motor_on_callback(unsigned long nr) +{ + running |= 0x10 << nr; + floppy_select(nr); +} + +static struct timer_list motor_on_timer[4] = { + { NULL, 0, 0, motor_on_callback }, + { NULL, 0, 1, motor_on_callback }, + { NULL, 0, 2, motor_on_callback }, + { NULL, 0, 3, motor_on_callback } +}; + +static void motor_off_callback(unsigned long nr) +{ + unsigned char mask = ~(0x10 << nr); + cli(); + running &= mask; + current_DOR &= mask; + outb(current_DOR,FD_DOR); + sti(); +} + +static struct timer_list motor_off_timer[4] = { + { NULL, 0, 0, motor_off_callback }, + { NULL, 0, 1, motor_off_callback }, + { NULL, 0, 2, motor_off_callback }, + { NULL, 0, 3, motor_off_callback } +}; + +static void floppy_on(unsigned int nr) +{ + unsigned char mask = 0x10 << nr; + + del_timer(motor_off_timer + nr); + if (mask & running) + floppy_select(nr); + if (!(mask & current_DOR)) { + del_timer(motor_on_timer + nr); + motor_on_timer[nr].expires = HZ; + add_timer(motor_on_timer + nr); + } + current_DOR &= 0xFC; + current_DOR |= mask; + current_DOR |= nr; + outb(current_DOR,FD_DOR); +} + +static void floppy_off(unsigned int nr) +{ + del_timer(motor_off_timer+nr); + motor_off_timer[nr].expires = 3*HZ; + add_timer(motor_off_timer+nr); +} + +void request_done(int uptodate) +{ + timer_active &= ~(1 << FLOPPY_TIMER); + if (format_status != FORMAT_BUSY) + end_request(uptodate); + else { + format_status = uptodate ? FORMAT_OKAY : FORMAT_ERROR; + wake_up(&format_done); + } +} + +/* + * floppy-change is never called from an interrupt, so we can relax a bit + * here, sleep etc. Note that floppy-on tries to set current_DOR to point + * to the desired drive, but it will probably not survive the sleep if + * several floppies are used at the same time: thus the loop. + */ +int floppy_change(struct buffer_head * bh) +{ + unsigned int mask = 1 << (bh->b_dev & 0x03); + + if (MAJOR(bh->b_dev) != MAJOR_NR) { + printk("floppy_changed: not a floppy\n"); + return 0; + } + if (fake_change & mask) { + buffer_track = -1; + fake_change &= ~mask; +/* omitting the next line breaks formatting in a horrible way ... */ + changed_floppies &= ~mask; + return 1; + } + if (changed_floppies & mask) { + buffer_track = -1; + changed_floppies &= ~mask; + recalibrate = 1; + return 1; + } + if (!bh) + return 0; + if (bh->b_dirt) + ll_rw_block(WRITE, 1, &bh); + else { + buffer_track = -1; + bh->b_uptodate = 0; + ll_rw_block(READ, 1, &bh); + } + wait_on_buffer(bh); + if (changed_floppies & mask) { + changed_floppies &= ~mask; + recalibrate = 1; + return 1; + } + return 0; +} + +#define copy_buffer(from,to) \ +__asm__("cld ; rep ; movsl" \ + : \ + :"c" (BLOCK_SIZE/4),"S" ((long)(from)),"D" ((long)(to)) \ + :"cx","di","si") + +static void setup_DMA(void) +{ + unsigned long addr,count; + unsigned char dma_code; + + dma_code = DMA_WRITE; + if (command == FD_READ) + dma_code = DMA_READ; + if (command == FD_FORMAT) { + addr = (long) tmp_floppy_area; + count = floppy->sect*4; + } else { + addr = (long) CURRENT->buffer; + count = 1024; + } + if (read_track) { +/* mark buffer-track bad, in case all this fails.. */ + buffer_drive = buffer_track = -1; + count = floppy->sect*floppy->head*512; + addr = (long) floppy_track_buffer; + } else if (addr >= LAST_DMA_ADDR) { + addr = (long) tmp_floppy_area; + if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,tmp_floppy_area); + } + cli(); + disable_dma(FLOPPY_DMA); + clear_dma_ff(FLOPPY_DMA); + set_dma_mode(FLOPPY_DMA, (command == FD_READ)? DMA_MODE_READ : DMA_MODE_WRITE); + set_dma_addr(FLOPPY_DMA, addr); + set_dma_count(FLOPPY_DMA, count); + enable_dma(FLOPPY_DMA); + sti(); +} + +static void output_byte(char byte) +{ + int counter; + unsigned char status; + + if (reset) + return; + for(counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS) & (STATUS_READY | STATUS_DIR); + if (status == STATUS_READY) { + outb(byte,FD_DATA); + return; + } + } + current_track = NO_TRACK; + reset = 1; + printk("Unable to send byte to FDC\n"); +} + +static int result(void) +{ + int i = 0, counter, status; + + if (reset) + return -1; + for (counter = 0 ; counter < 10000 ; counter++) { + status = inb_p(FD_STATUS)&(STATUS_DIR|STATUS_READY|STATUS_BUSY); + if (status == STATUS_READY) { + return i; + } + if (status == (STATUS_DIR|STATUS_READY|STATUS_BUSY)) { + if (i >= MAX_REPLIES) { + printk("floppy_stat reply overrun\n"); + break; + } + reply_buffer[i++] = inb_p(FD_DATA); + } + } + reset = 1; + current_track = NO_TRACK; + printk("Getstatus times out\n"); + return -1; +} + +static void bad_flp_intr(void) +{ + int errors; + + current_track = NO_TRACK; + if (format_status == FORMAT_BUSY) + errors = ++format_errors; + else if (!CURRENT) { + printk(DEVICE_NAME ": no current request\n"); + reset = recalibrate = 1; + return; + } else + errors = ++CURRENT->errors; + if (errors > MAX_ERRORS) { + request_done(0); + } + if (errors > MAX_ERRORS/2) + reset = 1; + else + recalibrate = 1; +} + + +/* Set perpendicular mode as required, based on data rate, if supported. + * 82077 Untested! 1Mbps data rate only possible with 82077-1. + * TODO: increase MAX_BUFFER_SECTORS, add floppy_type entries. + */ +static inline void perpendicular_mode(unsigned char rate) +{ + if (fdc_version == FDC_TYPE_82077) { + output_byte(FD_PERPENDICULAR); + if (rate & 0x40) { + unsigned char r = rate & 0x03; + if (r == 0) + output_byte(2); /* perpendicular, 500 kbps */ + else if (r == 3) + output_byte(3); /* perpendicular, 1Mbps */ + else { + printk(DEVICE_NAME ": Invalid data rate for perpendicular mode!\n"); + reset = 1; + } + } else + output_byte(0); /* conventional mode */ + } else { + if (rate & 0x40) { + printk(DEVICE_NAME ": perpendicular mode not supported by this FDC.\n"); + reset = 1; + } + } +} /* perpendicular_mode */ + + +/* + * This has only been tested for the case fdc_version == FDC_TYPE_STD. + * In case you have a 82077 and want to test it, you'll have to compile + * with `FDC_FIFO_UNTESTED' defined. You may also want to add support for + * recognizing drives with vertical recording support. + */ +static void configure_fdc_mode(void) +{ + if (need_configure && (fdc_version == FDC_TYPE_82077)) { + /* Enhanced version with FIFO & vertical recording. */ + output_byte(FD_CONFIGURE); + output_byte(0); + output_byte(0x1A); /* FIFO on, polling off, 10 byte threshold */ + output_byte(0); /* precompensation from track 0 upwards */ + need_configure = 0; + printk(DEVICE_NAME ": FIFO enabled\n"); + } + if (cur_spec1 != floppy->spec1) { + cur_spec1 = floppy->spec1; + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + } + if (cur_rate != floppy->rate) { + /* use bit 6 of floppy->rate to indicate perpendicular mode */ + perpendicular_mode(floppy->rate); + outb_p((cur_rate = (floppy->rate)) & ~0x40, FD_DCR); + } +} /* configure_fdc_mode */ + + +static void tell_sector(int nr) +{ + if (nr!=7) { + printk(" -- FDC reply errror"); + reset = 1; + } else + printk(": track %d, head %d, sector %d", reply_buffer[3], + reply_buffer[4], reply_buffer[5]); +} /* tell_sector */ + + +/* + * Ok, this interrupt is called after a DMA read/write has succeeded + * or failed, so we check the results, and copy any buffers. + * hhb: Added better error reporting. + */ +static void rw_interrupt(void) +{ + char * buffer_area; + int nr; + char bad; + + nr = result(); + /* check IC to find cause of interrupt */ + switch ((ST0 & ST0_INTR)>>6) { + case 1: /* error occured during command execution */ + bad = 1; + if (ST1 & ST1_WP) { + printk(DEVICE_NAME ": Drive %d is write protected\n", current_drive); + request_done(0); + bad = 0; + } else if (ST1 & ST1_OR) { + if (ftd_msg[ST0 & ST0_DS]) + printk(DEVICE_NAME ": Over/Underrun - retrying\n"); + /* could continue from where we stopped, but ... */ + bad = 0; + } else if (CURRENT_ERRORS > min_report_error_cnt[ST0 & ST0_DS]) { + printk(DEVICE_NAME " %d: ", ST0 & ST0_DS); + if (ST0 & ST0_ECE) { + printk("Recalibrate failed!"); + } else if (ST2 & ST2_CRC) { + printk("data CRC error"); + tell_sector(nr); + } else if (ST1 & ST1_CRC) { + printk("CRC error"); + tell_sector(nr); + } else if ((ST1 & (ST1_MAM|ST1_ND)) || (ST2 & ST2_MAM)) { + if (!probing) { + printk("sector not found"); + tell_sector(nr); + } else + printk("probe failed..."); + } else if (ST2 & ST2_WC) { /* seek error */ + printk("wrong cylinder"); + } else if (ST2 & ST2_BC) { /* cylinder marked as bad */ + printk("bad cylinder"); + } else { + printk("unknown error. ST[0..3] are: 0x%x 0x%x 0x%x 0x%x\n", ST0, ST1, ST2, ST3); + } + printk("\n"); + + } + if (bad) + bad_flp_intr(); + redo_fd_request(); + return; + case 2: /* invalid command given */ + printk(DEVICE_NAME ": Invalid FDC command given!\n"); + request_done(0); + return; + case 3: + printk(DEVICE_NAME ": Abnormal termination caused by polling\n"); + bad_flp_intr(); + redo_fd_request(); + return; + default: /* (0) Normal command termination */ + break; + } + + if (probing) { + int drive = MINOR(CURRENT->dev); + + if (ftd_msg[drive]) + printk("Auto-detected floppy type %s in fd%d\n", + floppy->name,drive); + current_type[drive] = floppy; + floppy_sizes[drive] = floppy->size >> 1; + probing = 0; + } + if (read_track) { + buffer_track = seek_track; + buffer_drive = current_drive; + buffer_area = floppy_track_buffer + + ((sector-1 + head*floppy->sect)<<9); + copy_buffer(buffer_area,CURRENT->buffer); + } else if (command == FD_READ && + (unsigned long)(CURRENT->buffer) >= LAST_DMA_ADDR) + copy_buffer(tmp_floppy_area,CURRENT->buffer); + request_done(1); + redo_fd_request(); +} + +/* + * We try to read tracks, but if we get too many errors, we + * go back to reading just one sector at a time. + * + * This means we should be able to read a sector even if there + * are other bad sectors on this track. + */ +inline void setup_rw_floppy(void) +{ + setup_DMA(); + do_floppy = rw_interrupt; + output_byte(command); + if (command != FD_FORMAT) { + if (read_track) { + output_byte(current_drive); + output_byte(track); + output_byte(0); + output_byte(1); + } else { + output_byte(head<<2 | current_drive); + output_byte(track); + output_byte(head); + output_byte(sector); + } + output_byte(2); /* sector size = 512 */ + output_byte(floppy->sect); + output_byte(floppy->gap); + output_byte(0xFF); /* sector size (0xff when n!=0 ?) */ + } else { + output_byte(head<<2 | current_drive); + output_byte(2); + output_byte(floppy->sect); + output_byte(floppy->fmt_gap); + output_byte(FD_FILL_BYTE); + } + if (reset) + redo_fd_request(); +} + +/* + * This is the routine called after every seek (or recalibrate) interrupt + * from the floppy controller. Note that the "unexpected interrupt" routine + * also does a recalibrate, but doesn't come here. + */ +static void seek_interrupt(void) +{ +/* sense drive status */ + output_byte(FD_SENSEI); + if (result() != 2 || (ST0 & 0xF8) != 0x20 || ST1 != seek_track) { + printk(DEVICE_NAME ": seek failed\n"); + recalibrate = 1; + bad_flp_intr(); + redo_fd_request(); + return; + } + current_track = ST1; + setup_rw_floppy(); +} + + +/* + * This routine is called when everything should be correctly set up + * for the transfer (ie floppy motor is on and the correct floppy is + * selected). + */ +static void transfer(void) +{ + read_track = (command == FD_READ) && (CURRENT_ERRORS < 4) && + (floppy->sect <= MAX_BUFFER_SECTORS); + + configure_fdc_mode(); + + if (reset) { + redo_fd_request(); + return; + } + if (!seek) { + setup_rw_floppy(); + return; + } + + do_floppy = seek_interrupt; + output_byte(FD_SEEK); + if (read_track) + output_byte(current_drive); + else + output_byte((head<<2) | current_drive); + output_byte(seek_track); + if (reset) + redo_fd_request(); +} + +/* + * Special case - used after a unexpected interrupt (or reset) + */ + +static void recalibrate_floppy(void); + +static void recal_interrupt(void) +{ + output_byte(FD_SENSEI); + current_track = NO_TRACK; + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; +/* Recalibrate until track 0 is reached. Might help on some errors. */ + if ((ST0 & 0x10) == 0x10) + recalibrate_floppy(); /* FIXME: should limit nr of recalibrates */ + else + redo_fd_request(); +} + +static void unexpected_floppy_interrupt(void) +{ + current_track = NO_TRACK; + output_byte(FD_SENSEI); + printk(DEVICE_NAME ": unexpected interrupt\n"); + if (result()!=2 || (ST0 & 0xE0) == 0x60) + reset = 1; + else + recalibrate = 1; +} + +static void recalibrate_floppy(void) +{ + recalibrate = 0; + current_track = 0; + do_floppy = recal_interrupt; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + if (reset) + redo_fd_request(); +} + +/* + * Must do 4 FD_SENSEIs after reset because of ``drive polling''. + */ +static void reset_interrupt(void) +{ + short i; + + for (i=0; i<4; i++) { + output_byte(FD_SENSEI); + (void) result(); + } + output_byte(FD_SPECIFY); + output_byte(cur_spec1); /* hut etc */ + output_byte(6); /* Head load time =6ms, DMA */ + configure_fdc_mode(); /* reprogram fdc */ + if (initial_reset_flag) { + initial_reset_flag = 0; + recalibrate = 1; + reset = 0; + return; + } + if (!recover) + redo_fd_request(); + else { + recalibrate_floppy(); + recover = 0; + } +} + +/* + * reset is done by pulling bit 2 of DOR low for a while. + */ +static void reset_floppy(void) +{ + int i; + + do_floppy = reset_interrupt; + reset = 0; + current_track = NO_TRACK; + cur_spec1 = -1; + cur_rate = -1; + recalibrate = 1; + need_configure = 1; + if (!initial_reset_flag) + printk("Reset-floppy called\n"); + cli(); + outb_p(current_DOR & ~0x04, FD_DOR); + for (i=0 ; i<1000 ; i++) + __asm__("nop"); + outb(current_DOR, FD_DOR); + sti(); +} + +static void floppy_shutdown(void) +{ + cli(); + do_floppy = NULL; + request_done(0); + recover = 1; + reset_floppy(); + sti(); + redo_fd_request(); +} + +static void shake_done(void) +{ + current_track = NO_TRACK; + if (inb(FD_DIR) & 0x80) + request_done(0); + redo_fd_request(); +} + +static int retry_recal(void (*proc)(void)) +{ + output_byte(FD_SENSEI); + if (result() == 2 && (ST0 & 0x10) != 0x10) return 0; + do_floppy = proc; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + return 1; +} + +static void shake_zero(void) +{ + if (!retry_recal(shake_zero)) shake_done(); +} + +static void shake_one(void) +{ + if (retry_recal(shake_one)) return; + do_floppy = shake_done; + output_byte(FD_SEEK); + output_byte(head << 2 | current_drive); + output_byte(1); +} + +static void floppy_ready(void) +{ + if (inb(FD_DIR) & 0x80) { + changed_floppies |= 1< 0) + keep_data[current_drive]--; + } else { + if (ftd_msg[current_drive] && current_type[current_drive] != NULL) + printk("Disk type is undefined after disk " + "change in fd%d\n",current_drive); + current_type[current_drive] = NULL; + floppy_sizes[current_drive] = MAX_DISK_SIZE; + } +/* Forcing the drive to seek makes the "media changed" condition go away. + * There should be a cleaner solution for that ... + */ + if (!reset && !recalibrate) { + if (current_track && current_track != NO_TRACK) + do_floppy = shake_zero; + else + do_floppy = shake_one; + output_byte(FD_RECALIBRATE); + output_byte(head<<2 | current_drive); + return; + } + } + if (reset) { + reset_floppy(); + return; + } + if (recalibrate) { + recalibrate_floppy(); + return; + } + transfer(); +} + +static void setup_format_params(void) +{ + unsigned char *here = (unsigned char *) tmp_floppy_area; + int count,head_shift,track_shift,total_shift; + + /* allow for about 30ms for data transport per track */ + head_shift = floppy->sect / 6; + /* a ``cylinder'' is two tracks plus a little stepping time */ + track_shift = 2 * head_shift + 1; + /* count backwards */ + total_shift = floppy->sect - + ((track_shift * track + head_shift * head) % floppy->sect); + + /* XXX: should do a check to see this fits in tmp_floppy_area!! */ + for (count = 0; count < floppy->sect; count++) { + *here++ = track; + *here++ = head; + *here++ = 1 + (( count + total_shift ) % floppy->sect); + *here++ = 2; /* 512 bytes */ + } +} + +static void redo_fd_request(void) +{ + unsigned int block; + char * buffer_area; + int device; + + if (CURRENT && CURRENT->dev < 0) return; + +repeat: + if (format_status == FORMAT_WAIT) + format_status = FORMAT_BUSY; + if (format_status != FORMAT_BUSY) { + if (!CURRENT) { + if (!fdc_busy) + printk("FDC access conflict!"); + fdc_busy = 0; + wake_up(&fdc_wait); + CLEAR_INTR; + return; + } + if (MAJOR(CURRENT->dev) != MAJOR_NR) + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { + if (!CURRENT->bh->b_lock) + panic(DEVICE_NAME ": block not locked"); + } + } + seek = 0; + probing = 0; + device = MINOR(CURRENT_DEVICE); + if (device > 3) + floppy = (device >> 2) + floppy_type; + else { /* Auto-detection */ + floppy = current_type[device & 3]; + if (!floppy) { + probing = 1; + floppy = base_type[device & 3]; + if (!floppy) { + request_done(0); + goto repeat; + } + if (CURRENT_ERRORS & 1) + floppy++; + } + } + if (format_status != FORMAT_BUSY) { + if (current_drive != CURRENT_DEV) { + current_track = NO_TRACK; + current_drive = CURRENT_DEV; + } + block = CURRENT->sector; + if (block+2 > floppy->size) { + request_done(0); + goto repeat; + } + sector = block % floppy->sect; + block /= floppy->sect; + head = block % floppy->head; + track = block / floppy->head; + seek_track = track << floppy->stretch; + if (CURRENT->cmd == READ) + command = FD_READ; + else if (CURRENT->cmd == WRITE) + command = FD_WRITE; + else { + printk("do_fd_request: unknown command\n"); + request_done(0); + goto repeat; + } + } else { + if (current_drive != (format_req.device & 3)) + current_track = NO_TRACK; + current_drive = format_req.device & 3; + if (((unsigned) format_req.track) >= floppy->track || + (format_req.head & 0xfffe) || probing) { + request_done(0); + goto repeat; + } + head = format_req.head; + track = format_req.track; + seek_track = track << floppy->stretch; + if (seek_track == buffer_track) buffer_track = -1; + command = FD_FORMAT; + setup_format_params(); + } + timer_table[FLOPPY_TIMER].expires = jiffies+10*HZ; + timer_active |= 1 << FLOPPY_TIMER; + if ((seek_track == buffer_track) && + (current_drive == buffer_drive)) { + buffer_area = floppy_track_buffer + + ((sector + head*floppy->sect)<<9); + if (command == FD_READ) { + copy_buffer(buffer_area,CURRENT->buffer); + request_done(1); + goto repeat; + } else if (command == FD_WRITE) + copy_buffer(CURRENT->buffer,buffer_area); + } + if (seek_track != current_track) + seek = 1; + sector++; + del_timer(motor_off_timer + current_drive); + floppy_on(current_drive); +} + +void do_fd_request(void) +{ + cli(); + while (fdc_busy) sleep_on(&fdc_wait); + fdc_busy = 1; + sti(); + redo_fd_request(); +} + +static int fd_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, + unsigned long param) +{ + int i,drive,cnt,okay; + struct floppy_struct *this_floppy; + + switch (cmd) { + RO_IOCTLS(inode->i_rdev,param); + } + drive = MINOR(inode->i_rdev); + switch (cmd) { + case FDFMTBEG: + if (!suser()) + return -EPERM; + return 0; + case FDFMTEND: + if (!suser()) + return -EPERM; + cli(); + fake_change |= 1 << (drive & 3); + sti(); + drive &= 3; + cmd = FDCLRPRM; + break; + case FDGETPRM: + if (drive > 3) this_floppy = &floppy_type[drive >> 2]; + else if ((this_floppy = current_type[drive & 3]) == NULL) + return -ENODEV; + i = verify_area(VERIFY_WRITE,(void *) param,sizeof(struct floppy_struct)); + if (i) + return i; + for (cnt = 0; cnt < sizeof(struct floppy_struct); cnt++) + put_fs_byte(((char *) this_floppy)[cnt], + (char *) param+cnt); + return 0; + case FDFMTTRK: + if (!suser()) + return -EPERM; + if (fd_ref[drive & 3] != 1) + return -EBUSY; + cli(); + while (format_status != FORMAT_NONE) + sleep_on(&format_done); + for (cnt = 0; cnt < sizeof(struct format_descr); cnt++) + ((char *) &format_req)[cnt] = get_fs_byte( + (char *) param+cnt); + format_req.device = drive; + format_status = FORMAT_WAIT; + format_errors = 0; + while (format_status != FORMAT_OKAY && format_status != + FORMAT_ERROR) { + if (fdc_busy) sleep_on(&fdc_wait); + else { + fdc_busy = 1; + redo_fd_request(); + } + } + while (format_status != FORMAT_OKAY && format_status != + FORMAT_ERROR) + sleep_on(&format_done); + sti(); + okay = format_status == FORMAT_OKAY; + format_status = FORMAT_NONE; + floppy_off(drive & 3); + wake_up(&format_done); + return okay ? 0 : -EIO; + case FDFLUSH: + if (!permission(inode, 2)) + return -EPERM; + cli(); + fake_change |= 1 << (drive & 3); + sti(); + check_disk_change(inode->i_rdev); + return 0; + } + if (!suser()) + return -EPERM; + if (drive < 0 || drive > 3) + return -EINVAL; + switch (cmd) { + case FDCLRPRM: + current_type[drive] = NULL; + floppy_sizes[drive] = MAX_DISK_SIZE; + keep_data[drive] = 0; + break; + case FDSETPRM: + case FDDEFPRM: + memcpy_fromfs(user_params+drive, + (void *) param, + sizeof(struct floppy_struct)); + current_type[drive] = &user_params[drive]; + floppy_sizes[drive] = user_params[drive].size >> 1; + if (cmd == FDDEFPRM) + keep_data[drive] = -1; + else { + cli(); + while (fdc_busy) sleep_on(&fdc_wait); + fdc_busy = 1; + sti(); + outb_p((current_DOR & 0xfc) | drive | + (0x10 << drive),FD_DOR); + for (cnt = 0; cnt < 1000; cnt++) __asm__("nop"); + if (inb(FD_DIR) & 0x80) + keep_data[drive] = 1; + else + keep_data[drive] = 0; + outb_p(current_DOR,FD_DOR); + fdc_busy = 0; + wake_up(&fdc_wait); + } + break; + case FDMSGON: + ftd_msg[drive] = 1; + break; + case FDMSGOFF: + ftd_msg[drive] = 0; + break; + case FDSETEMSGTRESH: + min_report_error_cnt[drive] = (unsigned short) (param & 0x0f); + break; + default: + return -EINVAL; + } + return 0; +} + +#define CMOS_READ(addr) ({ \ +outb_p(addr,0x70); \ +inb_p(0x71); \ +}) + +static struct floppy_struct *find_base(int drive,int code) +{ + struct floppy_struct *base; + + if (code > 0 && code < 5) { + base = &floppy_types[(code-1)*2]; + printk("fd%d is %s",drive,base->name); + return base; + } + printk("fd%d is unknown type %d",drive,code); + return NULL; +} + +static void config_types(void) +{ + printk("Floppy drive(s): "); + base_type[0] = find_base(0,(CMOS_READ(0x10) >> 4) & 15); + if (((CMOS_READ(0x14) >> 6) & 1) == 0) + base_type[1] = NULL; + else { + printk(", "); + base_type[1] = find_base(1,CMOS_READ(0x10) & 15); + } + base_type[2] = base_type[3] = NULL; + printk("\n"); +} + +/* + * floppy_open check for aliasing (/dev/fd0 can be the same as + * /dev/PS0 etc), and disallows simultaneous access to the same + * drive with different device numbers. + */ +static int floppy_open(struct inode * inode, struct file * filp) +{ + int drive; + int old_dev; + + drive = inode->i_rdev & 3; + old_dev = fd_device[drive]; + if (fd_ref[drive]) + if (old_dev != inode->i_rdev) + return -EBUSY; + fd_ref[drive]++; + fd_device[drive] = inode->i_rdev; + buffer_drive = buffer_track = -1; + if (old_dev && old_dev != inode->i_rdev) + invalidate_buffers(old_dev); + if (filp && filp->f_mode) + check_disk_change(inode->i_rdev); + return 0; +} + +static void floppy_release(struct inode * inode, struct file * filp) +{ + sync_dev(inode->i_rdev); + if (!fd_ref[inode->i_rdev & 3]--) { + printk("floppy_release with fd_ref == 0"); + fd_ref[inode->i_rdev & 3] = 0; + } +} + +static struct file_operations floppy_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + fd_ioctl, /* ioctl */ + NULL, /* mmap */ + floppy_open, /* open */ + floppy_release, /* release */ + block_fsync /* fsync */ +}; + + +/* + * The version command is not supposed to generate an interrupt, but + * my FDC does, except when booting in SVGA screen mode. + * When it does generate an interrupt, it doesn't return any status bytes. + * It appears to have something to do with the version command... + * + * This should never be called, because of the reset after the version check. + */ +static void ignore_interrupt(void) +{ + printk(DEVICE_NAME ": weird interrupt ignored (%d)\n", result()); + reset = 1; + CLEAR_INTR; /* ignore only once */ +} + + +static void floppy_interrupt(int unused) +{ + void (*handler)(void) = DEVICE_INTR; + + DEVICE_INTR = NULL; + if (!handler) + handler = unexpected_floppy_interrupt; + handler(); +} + +/* + * This is the floppy IRQ description. The SA_INTERRUPT in sa_flags + * means we run the IRQ-handler with interrupts disabled. + */ +static struct sigaction floppy_sigaction = { + floppy_interrupt, + 0, + SA_INTERRUPT, + NULL +}; + +void floppy_init(void) +{ + outb(current_DOR,FD_DOR); + if (register_blkdev(MAJOR_NR,"fd",&floppy_fops)) { + printk("Unable to get major %d for floppy\n",MAJOR_NR); + return; + } + blk_size[MAJOR_NR] = floppy_sizes; + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + timer_table[FLOPPY_TIMER].fn = floppy_shutdown; + timer_active &= ~(1 << FLOPPY_TIMER); + config_types(); + if (irqaction(FLOPPY_IRQ,&floppy_sigaction)) + printk("Unable to grab IRQ%d for the floppy driver\n", FLOPPY_IRQ); + if (request_dma(FLOPPY_DMA)) + printk("Unable to grab DMA%d for the floppy driver\n", FLOPPY_DMA); + /* Try to determine the floppy controller type */ + DEVICE_INTR = ignore_interrupt; /* don't ask ... */ + output_byte(FD_VERSION); /* get FDC version code */ + if (result() != 1) { + printk(DEVICE_NAME ": FDC failed to return version byte\n"); + fdc_version = FDC_TYPE_STD; + } else + fdc_version = reply_buffer[0]; + if (fdc_version != FDC_TYPE_STD) + printk(DEVICE_NAME ": FDC version 0x%x\n", fdc_version); +#ifndef FDC_FIFO_UNTESTED + fdc_version = FDC_TYPE_STD; /* force std fdc type; can't test other. */ +#endif + + /* Not all FDCs seem to be able to handle the version command + * properly, so force a reset for the standard FDC clones, + * to avoid interrupt garbage. + */ + + if (fdc_version == FDC_TYPE_STD) { + initial_reset_flag = 1; + reset_floppy(); + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/genhd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/genhd.c new file mode 100644 index 000000000..1681d2b27 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/genhd.c @@ -0,0 +1,216 @@ +/* + * Code extracted from + * linux/kernel/hd.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug + * in the early extended-partition checks and added DM partitions + */ + +#include +#include +#include +#include + +struct gendisk *gendisk_head = NULL; + +static int current_minor = 0; +extern int *blk_size[]; +extern void rd_load(void); +extern int ramdisk_size; + +/* + * Create devices for each logical partition in an extended partition. + * The logical partitions form a linked list, with each entry being + * a partition table with two entries. The first entry + * is the real data partition (with a start relative to the partition + * table start). The second is a pointer to the next logical partition + * (with a start relative to the entire extended partition). + * We do not create a Linux partition for the partition tables, but + * only for the actual data partitions. + */ + +static void extended_partition(struct gendisk *hd, int dev) +{ + struct buffer_head *bh; + struct partition *p; + unsigned long first_sector, this_sector; + int mask = (1 << hd->minor_shift) - 1; + + first_sector = hd->part[MINOR(dev)].start_sect; + this_sector = first_sector; + + while (1) { + if ((current_minor & mask) >= (4 + hd->max_p)) + return; + if (!(bh = bread(dev,0,1024))) + return; + /* + * This block is from a device that we're about to stomp on. + * So make sure nobody thinks this block is usable. + */ + bh->b_dirt=0; + bh->b_uptodate=0; + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = (struct partition *) (0x1BE + bh->b_data); + /* + * Process the first entry, which should be the real + * data partition. + */ + if (p->sys_ind == EXTENDED_PARTITION || + !(hd->part[current_minor].nr_sects = p->nr_sects)) + goto done; /* shouldn't happen */ + hd->part[current_minor].start_sect = this_sector + p->start_sect; + printk(" %s%c%d", hd->major_name, + 'a'+(current_minor >> hd->minor_shift), + mask & current_minor); + current_minor++; + p++; + /* + * Process the second entry, which should be a link + * to the next logical partition. Create a minor + * for this just long enough to get the next partition + * table. The minor will be reused for the real + * data partition. + */ + if (p->sys_ind != EXTENDED_PARTITION || + !(hd->part[current_minor].nr_sects = p->nr_sects)) + goto done; /* no more logicals in this partition */ + hd->part[current_minor].start_sect = first_sector + p->start_sect; + this_sector = first_sector + p->start_sect; + dev = ((hd->major) << 8) | current_minor; + brelse(bh); + } else + goto done; + } +done: + brelse(bh); +} + +static void check_partition(struct gendisk *hd, unsigned int dev) +{ + static int first_time = 1; + int i, minor = current_minor; + struct buffer_head *bh; + struct partition *p; + unsigned long first_sector; + int mask = (1 << hd->minor_shift) - 1; + + if (first_time) + printk("Partition check:\n"); + first_time = 0; + first_sector = hd->part[MINOR(dev)].start_sect; + if (!(bh = bread(dev,0,1024))) { + printk(" unable to read partition table of device %04x\n",dev); + return; + } + printk(" %s%c:", hd->major_name, 'a'+(minor >> hd->minor_shift)); + current_minor += 4; /* first "extra" minor */ + if (*(unsigned short *) (bh->b_data+510) == 0xAA55) { + p = (struct partition *) (0x1BE + bh->b_data); + for (i=1 ; i<=4 ; minor++,i++,p++) { + if (!(hd->part[minor].nr_sects = p->nr_sects)) + continue; + hd->part[minor].start_sect = first_sector + p->start_sect; + printk(" %s%c%d", hd->major_name,'a'+(minor >> hd->minor_shift), i); + if ((current_minor & 0x3f) >= 60) + continue; + if (p->sys_ind == EXTENDED_PARTITION) { + printk(" <"); + extended_partition(hd, (hd->major << 8) | minor); + printk(" >"); + } + } + /* + * check for Disk Manager partition table + */ + if (*(unsigned short *) (bh->b_data+0xfc) == 0x55AA) { + p = (struct partition *) (0x1BE + bh->b_data); + for (i = 4 ; i < 16 ; i++, current_minor++) { + p--; + if ((current_minor & mask) >= mask-2) + break; + if (!(p->start_sect && p->nr_sects)) + continue; + hd->part[current_minor].start_sect = p->start_sect; + hd->part[current_minor].nr_sects = p->nr_sects; + printk(" %s%c%d", hd->major_name, + 'a'+(current_minor >> hd->minor_shift), + current_minor & mask); + } + } + } else + printk(" bad partition table"); + printk("\n"); + brelse(bh); +} + +/* This function is used to re-read partition tables for removable disks. + Much of the cleanup from the old partition tables should have already been + done */ + +/* This function will re-read the partition tables for a given device, +and set things back up again. There are some important caveats, +however. You must ensure that no one is using the device, and no one +can start using the device while this function is being executed. */ + +void resetup_one_dev(struct gendisk *dev, int drive) +{ + int i; + int start = drive<minor_shift; + int j = start + dev->max_p; + int major = dev->major << 8; + + current_minor = 1+(drive<minor_shift); + check_partition(dev, major+(drive<minor_shift)); + + for (i=start ; i < j ; i++) + dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); +} + +static void setup_dev(struct gendisk *dev) +{ + int i; + int j = dev->max_nr * dev->max_p; + int major = dev->major << 8; + int drive; + + + for (i = 0 ; i < j; i++) { + dev->part[i].start_sect = 0; + dev->part[i].nr_sects = 0; + } + dev->init(); + for (drive=0 ; drivenr_real ; drive++) { + current_minor = 1+(drive<minor_shift); + check_partition(dev, major+(drive<minor_shift)); + } + for (i=0 ; i < j ; i++) + dev->sizes[i] = dev->part[i].nr_sects >> (BLOCK_SIZE_BITS - 9); + blk_size[dev->major] = dev->sizes; +} + +/* This may be used only once, enforced by 'static int callable' */ +asmlinkage int sys_setup(void * BIOS) +{ + static int callable = 1; + struct gendisk *p; + int nr=0; + + if (!callable) + return -1; + callable = 0; + + for (p = gendisk_head ; p ; p=p->next) { + setup_dev(p); + nr += p->nr_real; + } + + if (ramdisk_size) + rd_load(); + mount_root(); + return (0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/hd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/hd.c new file mode 100644 index 000000000..c26348f0e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/hd.c @@ -0,0 +1,797 @@ +/* + * linux/kernel/hd.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This is the low-level hd interrupt support. It traverses the + * request-list, using interrupts to jump between functions. As + * all the functions are called within interrupts, we may not + * sleep. Special care is recommended. + * + * modified by Drew Eckhardt to check nr of hd's from the CMOS. + * + * Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug + * in the early extended-partition checks and added DM partitions + */ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define REALLY_SLOW_IO +#include +#include +#include + +#define MAJOR_NR HD_MAJOR +#include "blk.h" + +#define HD_IRQ 14 + +static int revalidate_hddisk(int, int); + +static inline unsigned char CMOS_READ(unsigned char addr) +{ + outb_p(addr,0x70); + return inb_p(0x71); +} + +#define HD_DELAY 0 + +#define MAX_ERRORS 16 /* Max read/write errors/sector */ +#define RESET_FREQ 8 /* Reset controller every 8th retry */ +#define RECAL_FREQ 4 /* Recalibrate every 4th retry */ +#define MAX_HD 2 + +static void recal_intr(void); +static void bad_rw_intr(void); + +static char recalibrate[ MAX_HD ] = { 0, }; +static int access_count[MAX_HD] = {0, }; +static char busy[MAX_HD] = {0, }; +static struct wait_queue * busy_wait = NULL; + +static int reset = 0; +static int hd_error = 0; + +#if (HD_DELAY > 0) +unsigned long last_req, read_timer(); +#endif + +/* + * This struct defines the HD's and their types. + */ +struct hd_i_struct { + unsigned int head,sect,cyl,wpcom,lzone,ctl; + }; +#ifdef HD_TYPE +struct hd_i_struct hd_info[] = { HD_TYPE }; +static int NR_HD = ((sizeof (hd_info))/(sizeof (struct hd_i_struct))); +#else +struct hd_i_struct hd_info[] = { {0,0,0,0,0,0},{0,0,0,0,0,0} }; +static int NR_HD = 0; +#endif + +static struct hd_struct hd[MAX_HD<<6]={{0,0},}; +static int hd_sizes[MAX_HD<<6] = {0, }; +static int hd_blocksizes[MAX_HD<<6] = {0, }; + +#if (HD_DELAY > 0) +unsigned long read_timer(void) +{ + unsigned long t; + int i; + + cli(); + t = jiffies * 11932; + outb_p(0, 0x43); + i = inb_p(0x40); + i |= inb(0x40) << 8; + sti(); + return(t - i); +} +#endif + +void hd_setup(char *str, int *ints) +{ + int hdind = 0; + + if (ints[0] != 3) + return; + if (hd_info[0].head != 0) + hdind=1; + hd_info[hdind].head = ints[2]; + hd_info[hdind].sect = ints[3]; + hd_info[hdind].cyl = ints[1]; + hd_info[hdind].wpcom = 0; + hd_info[hdind].lzone = ints[1]; + hd_info[hdind].ctl = (ints[2] > 8 ? 8 : 0); + NR_HD = hdind+1; +} + +static int win_result(void) +{ + int i=inb_p(HD_STATUS); + + if ((i & (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT)) + == (READY_STAT | SEEK_STAT)) { + hd_error = 0; + return 0; /* ok */ + } + printk("HD: win_result: status = 0x%02x\n",i); + if (i&1) { + hd_error = inb(HD_ERROR); + printk("HD: win_result: error = 0x%02x\n",hd_error); + } + return 1; +} + +static int controller_busy(void); +static int status_ok(void); + +static int controller_ready(unsigned int drive, unsigned int head) +{ + int retry = 100; + + do { + if (controller_busy() & BUSY_STAT) + return 0; + outb_p(0xA0 | (drive<<4) | head, HD_CURRENT); + if (status_ok()) + return 1; + } while (--retry); + return 0; +} + +static int status_ok(void) +{ + unsigned char status = inb_p(HD_STATUS); + + if (status & BUSY_STAT) + return 1; + if (status & WRERR_STAT) + return 0; + if (!(status & READY_STAT)) + return 0; + if (!(status & SEEK_STAT)) + return 0; + return 1; +} + +static int controller_busy(void) +{ + int retries = 100000; + unsigned char status; + + do { + status = inb_p(HD_STATUS); + } while ((status & BUSY_STAT) && --retries); + return status; +} + +static void hd_out(unsigned int drive,unsigned int nsect,unsigned int sect, + unsigned int head,unsigned int cyl,unsigned int cmd, + void (*intr_addr)(void)) +{ + unsigned short port; + + if (drive>1 || head>15) + panic("Trying to write bad sector"); +#if (HD_DELAY > 0) + while (read_timer() - last_req < HD_DELAY) + /* nothing */; +#endif + if (reset) + return; + if (!controller_ready(drive, head)) { + reset = 1; + return; + } + SET_INTR(intr_addr); + outb_p(hd_info[drive].ctl,HD_CMD); + port=HD_DATA; + outb_p(hd_info[drive].wpcom>>2,++port); + outb_p(nsect,++port); + outb_p(sect,++port); + outb_p(cyl,++port); + outb_p(cyl>>8,++port); + outb_p(0xA0|(drive<<4)|head,++port); + outb_p(cmd,++port); +} + +static int drive_busy(void) +{ + unsigned int i; + unsigned char c; + + for (i = 0; i < 500000 ; i++) { + c = inb_p(HD_STATUS); + c &= (BUSY_STAT | READY_STAT | SEEK_STAT); + if (c == (READY_STAT | SEEK_STAT)) + return 0; + } + printk("HD controller times out, status = 0x%02x\n",c); + return 1; +} + +static void reset_controller(void) +{ + int i; + + printk(KERN_DEBUG "HD-controller reset\n"); + outb_p(4,HD_CMD); + for(i = 0; i < 1000; i++) nop(); + outb(hd_info[0].ctl & 0x0f ,HD_CMD); + if (drive_busy()) + printk("HD-controller still busy\n"); + if ((hd_error = inb(HD_ERROR)) != 1) + printk("HD-controller reset failed: %02x\n",hd_error); +} + +static void reset_hd(void) +{ + static int i; + +repeat: + if (reset) { + reset = 0; + i = -1; + reset_controller(); + } else if (win_result()) { + bad_rw_intr(); + if (reset) + goto repeat; + } + i++; + if (i < NR_HD) { + hd_out(i,hd_info[i].sect,hd_info[i].sect,hd_info[i].head-1, + hd_info[i].cyl,WIN_SPECIFY,&reset_hd); + if (reset) + goto repeat; + } else + do_hd_request(); +} + +/* + * Ok, don't know what to do with the unexpected interrupts: on some machines + * doing a reset and a retry seems to result in an eternal loop. Right now I + * ignore it, and just set the timeout. + */ +void unexpected_hd_interrupt(void) +{ + sti(); + printk(KERN_DEBUG "Unexpected HD interrupt\n"); + SET_TIMER; +} + +/* + * bad_rw_intr() now tries to be a bit smarter and does things + * according to the error returned by the controller. + * -Mika Liljeberg (liljeber@cs.Helsinki.FI) + */ +static void bad_rw_intr(void) +{ + int dev; + + if (!CURRENT) + return; + dev = MINOR(CURRENT->dev) >> 6; + if (++CURRENT->errors >= MAX_ERRORS || (hd_error & BBD_ERR)) { + end_request(0); + recalibrate[dev] = 1; + } else if (CURRENT->errors % RESET_FREQ == 0) + reset = 1; + else if ((hd_error & TRK0_ERR) || CURRENT->errors % RECAL_FREQ == 0) + recalibrate[dev] = 1; + /* Otherwise just retry */ +} + +static inline int wait_DRQ(void) +{ + int retries = 100000; + + while (--retries > 0) + if (inb_p(HD_STATUS) & DRQ_STAT) + return 0; + return -1; +} + +#define STAT_MASK (BUSY_STAT | READY_STAT | WRERR_STAT | SEEK_STAT | ERR_STAT) +#define STAT_OK (READY_STAT | SEEK_STAT) + +static void read_intr(void) +{ + int i; + int retries = 100000; + + do { + i = (unsigned) inb_p(HD_STATUS); + if (i & BUSY_STAT) + continue; + if ((i & STAT_MASK) != STAT_OK) + break; + if (i & DRQ_STAT) + goto ok_to_read; + } while (--retries > 0); + sti(); + printk("HD: read_intr: status = 0x%02x\n",i); + if (i & ERR_STAT) { + hd_error = (unsigned) inb(HD_ERROR); + printk("HD: read_intr: error = 0x%02x\n",hd_error); + } + bad_rw_intr(); + cli(); + do_hd_request(); + return; +ok_to_read: + insw(HD_DATA,CURRENT->buffer,256); + CURRENT->errors = 0; + CURRENT->buffer += 512; + CURRENT->sector++; + i = --CURRENT->nr_sectors; + --CURRENT->current_nr_sectors; +#ifdef DEBUG + printk("hd%d : sector = %d, %d remaining to buffer = %08x\n", + MINOR(CURRENT->dev), CURRENT->sector, i, CURRENT-> + buffer); +#endif + if (!i || (CURRENT->bh && !SUBSECTOR(i))) + end_request(1); + if (i > 0) { + SET_INTR(&read_intr); + sti(); + return; + } + (void) inb_p(HD_STATUS); +#if (HD_DELAY > 0) + last_req = read_timer(); +#endif + do_hd_request(); + return; +} + +static void write_intr(void) +{ + int i; + int retries = 100000; + + do { + i = (unsigned) inb_p(HD_STATUS); + if (i & BUSY_STAT) + continue; + if ((i & STAT_MASK) != STAT_OK) + break; + if ((CURRENT->nr_sectors <= 1) || (i & DRQ_STAT)) + goto ok_to_write; + } while (--retries > 0); + sti(); + printk("HD: write_intr: status = 0x%02x\n",i); + if (i & ERR_STAT) { + hd_error = (unsigned) inb(HD_ERROR); + printk("HD: write_intr: error = 0x%02x\n",hd_error); + } + bad_rw_intr(); + cli(); + do_hd_request(); + return; +ok_to_write: + CURRENT->sector++; + i = --CURRENT->nr_sectors; + --CURRENT->current_nr_sectors; + CURRENT->buffer += 512; + if (!i || (CURRENT->bh && !SUBSECTOR(i))) + end_request(1); + if (i > 0) { + SET_INTR(&write_intr); + outsw(HD_DATA,CURRENT->buffer,256); + sti(); + } else { +#if (HD_DELAY > 0) + last_req = read_timer(); +#endif + do_hd_request(); + } + return; +} + +static void recal_intr(void) +{ + if (win_result()) + bad_rw_intr(); + do_hd_request(); +} + +/* + * This is another of the error-routines I don't know what to do with. The + * best idea seems to just set reset, and start all over again. + */ +static void hd_times_out(void) +{ + DEVICE_INTR = NULL; + sti(); + reset = 1; + if (!CURRENT) + return; + printk(KERN_DEBUG "HD timeout\n"); + cli(); + if (++CURRENT->errors >= MAX_ERRORS) { +#ifdef DEBUG + printk("hd : too many errors.\n"); +#endif + end_request(0); + } + + do_hd_request(); +} + +/* + * The driver has been modified to enable interrupts a bit more: in order to + * do this we first (a) disable the timeout-interrupt and (b) clear the + * device-interrupt. This way the interrupts won't mess with out code (the + * worst that can happen is that an unexpected HD-interrupt comes in and + * sets the "reset" variable and starts the timer) + */ +static void do_hd_request(void) +{ + unsigned int block,dev; + unsigned int sec,head,cyl,track; + unsigned int nsect; + + if (CURRENT && CURRENT->dev < 0) return; + + if (DEVICE_INTR) + return; +repeat: + timer_active &= ~(1<dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + if (dev >= (NR_HD<<6) || block >= hd[dev].nr_sects) { +#ifdef DEBUG + printk("hd%d : attempted read for sector %d past end of device at sector %d.\n", + block, hd[dev].nr_sects); +#endif + end_request(0); + goto repeat; + } + block += hd[dev].start_sect; + dev >>= 6; + sec = block % hd_info[dev].sect + 1; + track = block / hd_info[dev].sect; + head = track % hd_info[dev].head; + cyl = track / hd_info[dev].head; +#ifdef DEBUG + printk("hd%d : cyl = %d, head = %d, sector = %d, buffer = %08x\n", + dev, cyl, head, sec, CURRENT->buffer); +#endif + cli(); + if (reset) { + int i; + + for (i=0; i < NR_HD; i++) + recalibrate[i] = 1; + reset_hd(); + sti(); + return; + } + if (recalibrate[dev]) { + recalibrate[dev] = 0; + hd_out(dev,hd_info[dev].sect,0,0,0,WIN_RESTORE,&recal_intr); + if (reset) + goto repeat; + sti(); + return; + } + if (CURRENT->cmd == WRITE) { + hd_out(dev,nsect,sec,head,cyl,WIN_WRITE,&write_intr); + if (reset) + goto repeat; + if (wait_DRQ()) { + printk("HD: do_hd_request: no DRQ\n"); + bad_rw_intr(); + goto repeat; + } + outsw(HD_DATA,CURRENT->buffer,256); + sti(); + return; + } + if (CURRENT->cmd == READ) { + hd_out(dev,nsect,sec,head,cyl,WIN_READ,&read_intr); + if (reset) + goto repeat; + sti(); + return; + } + panic("unknown hd-command"); +} + +static int hd_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct hd_geometry *loc = (struct hd_geometry *) arg; + int dev, err; + + if (!inode) + return -EINVAL; + dev = MINOR(inode->i_rdev) >> 6; + if (dev >= NR_HD) + return -EINVAL; + switch (cmd) { + case HDIO_GETGEO: + if (!loc) return -EINVAL; + err = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); + if (err) + return err; + put_fs_byte(hd_info[dev].head, + (char *) &loc->heads); + put_fs_byte(hd_info[dev].sect, + (char *) &loc->sectors); + put_fs_word(hd_info[dev].cyl, + (short *) &loc->cylinders); + put_fs_long(hd[MINOR(inode->i_rdev)].start_sect, + (long *) &loc->start); + return 0; + case BLKGETSIZE: /* Return device size */ + if (!arg) return -EINVAL; + err = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (err) + return err; + put_fs_long(hd[MINOR(inode->i_rdev)].nr_sects, + (long *) arg); + return 0; + case BLKFLSBUF: + if(!suser()) return -EACCES; + if(!inode->i_rdev) return -EINVAL; + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + return 0; + + case BLKRRPART: /* Re-read partition tables */ + return revalidate_hddisk(inode->i_rdev, 1); + RO_IOCTLS(inode->i_rdev,arg); + default: + return -EINVAL; + } +} + +static int hd_open(struct inode * inode, struct file * filp) +{ + int target; + target = DEVICE_NR(MINOR(inode->i_rdev)); + + while (busy[target]) + sleep_on(&busy_wait); + access_count[target]++; + return 0; +} + +/* + * Releasing a block device means we sync() it, so that it can safely + * be forgotten about... + */ +static void hd_release(struct inode * inode, struct file * file) +{ + int target; + sync_dev(inode->i_rdev); + + target = DEVICE_NR(MINOR(inode->i_rdev)); + access_count[target]--; + +} + +static void hd_geninit(void); + +static struct gendisk hd_gendisk = { + MAJOR_NR, /* Major number */ + "hd", /* Major name */ + 6, /* Bits to shift to get real from partition */ + 1 << 6, /* Number of partitions per real */ + MAX_HD, /* maximum number of real */ + hd_geninit, /* init function */ + hd, /* hd struct */ + hd_sizes, /* block sizes */ + 0, /* number */ + (void *) hd_info, /* internal */ + NULL /* next */ +}; + +static void hd_interrupt(int unused) +{ + void (*handler)(void) = DEVICE_INTR; + + DEVICE_INTR = NULL; + timer_active &= ~(1< are the primary drives in the system, and + the ones reflected as drive 1 or 2. + + The first drive is stored in the high nibble of CMOS + byte 0x12, the second in the low nibble. This will be + either a 4 bit drive type or 0xf indicating use byte 0x19 + for an 8 bit type, drive 1, 0x1a for drive 2 in CMOS. + + Needless to say, a non-zero value means we have + an AT controller hard disk for that drive. + + + */ + + if ((cmos_disks = CMOS_READ(0x12)) & 0xf0) + if (cmos_disks & 0x0f) + NR_HD = 2; + else + NR_HD = 1; + } + i = NR_HD; + while (i-- > 0) { + hd[i<<6].nr_sects = 0; + if (hd_info[i].head > 16) { + printk("hd.c: ST-506 interface disk with more than 16 heads detected,\n"); + printk(" probably due to non-standard sector translation. Giving up.\n"); + printk(" (disk %d: cyl=%d, sect=%d, head=%d)\n", i, + hd_info[i].cyl, + hd_info[i].sect, + hd_info[i].head); + if (i+1 == NR_HD) + NR_HD--; + continue; + } + hd[i<<6].nr_sects = hd_info[i].head* + hd_info[i].sect*hd_info[i].cyl; + } + if (NR_HD) { + if (irqaction(HD_IRQ,&hd_sigaction)) { + printk("hd.c: unable to get IRQ%d for the harddisk driver\n",HD_IRQ); + NR_HD = 0; + } + } + hd_gendisk.nr_real = NR_HD; + + for(i=0;i<(MAX_HD << 6);i++) hd_blocksizes[i] = 1024; + blksize_size[MAJOR_NR] = hd_blocksizes; +} + +static struct file_operations hd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + hd_ioctl, /* ioctl */ + NULL, /* mmap */ + hd_open, /* open */ + hd_release, /* release */ + block_fsync /* fsync */ +}; + +unsigned long hd_init(unsigned long mem_start, unsigned long mem_end) +{ + if (register_blkdev(MAJOR_NR,"hd",&hd_fops)) { + printk("Unable to get major %d for harddisk\n",MAJOR_NR); + return mem_start; + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read-ahead */ + hd_gendisk.next = gendisk_head; + gendisk_head = &hd_gendisk; + timer_table[HD_TIMER].fn = hd_times_out; + return mem_start; +} + +#define DEVICE_BUSY busy[target] +#define USAGE access_count[target] +#define CAPACITY (hd_info[target].head*hd_info[target].sect*hd_info[target].cyl) +/* We assume that the the bios parameters do not change, so the disk capacity + will not change */ +#undef MAYBE_REINIT +#define GENDISK_STRUCT hd_gendisk + +/* + * This routine is called to flush all partitions and partition tables + * for a changed scsi disk, and then re-read the new partition table. + * If we are revalidating a disk because of a media change, then we + * enter with usage == 0. If we are using an ioctl, we automatically have + * usage == 1 (we need an open channel to use an ioctl :-), so this + * is our limit. + */ +static int revalidate_hddisk(int dev, int maxusage) +{ + int target, major; + struct gendisk * gdev; + int max_p; + int start; + int i; + + target = DEVICE_NR(MINOR(dev)); + gdev = &GENDISK_STRUCT; + + cli(); + if (DEVICE_BUSY || USAGE > maxusage) { + sti(); + return -EBUSY; + }; + DEVICE_BUSY = 1; + sti(); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + major = MAJOR_NR << 8; + + for (i=max_p - 1; i >=0 ; i--) { + sync_dev(major | start | i); + invalidate_inodes(major | start | i); + invalidate_buffers(major | start | i); + gdev->part[start+i].start_sect = 0; + gdev->part[start+i].nr_sects = 0; + }; + +#ifdef MAYBE_REINIT + MAYBE_REINIT; +#endif + + gdev->part[start].nr_sects = CAPACITY; + resetup_one_dev(gdev, target); + + DEVICE_BUSY = 0; + wake_up(&busy_wait); + return 0; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ll_rw_blk.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ll_rw_blk.c new file mode 100644 index 000000000..5e42788dd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ll_rw_blk.c @@ -0,0 +1,503 @@ +/* + * linux/kernel/blk_dev/ll_rw.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This handles all read/write requests to block devices + */ +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "blk.h" + +#ifdef CONFIG_SBPCD +extern u_long sbpcd_init(u_long, u_long); +#endif CONFIG_SBPCD + +/* + * The request-struct contains all necessary data + * to load a nr of sectors into memory + */ +static struct request all_requests[NR_REQUEST]; + +/* + * used to wait on when there are no free requests + */ +struct wait_queue * wait_for_request = NULL; + +/* This specifies how many sectors to read ahead on the disk. */ + +int read_ahead[MAX_BLKDEV] = {0, }; + +/* blk_dev_struct is: + * do_request-address + * next-request + */ +struct blk_dev_struct blk_dev[MAX_BLKDEV] = { + { NULL, NULL }, /* no_dev */ + { NULL, NULL }, /* dev mem */ + { NULL, NULL }, /* dev fd */ + { NULL, NULL }, /* dev hd */ + { NULL, NULL }, /* dev ttyx */ + { NULL, NULL }, /* dev tty */ + { NULL, NULL }, /* dev lp */ + { NULL, NULL }, /* dev pipes */ + { NULL, NULL }, /* dev sd */ + { NULL, NULL } /* dev st */ +}; + +/* + * blk_size contains the size of all block-devices in units of 1024 byte + * sectors: + * + * blk_size[MAJOR][MINOR] + * + * if (!blk_size[MAJOR]) then no minor size checking is done. + */ +int * blk_size[MAX_BLKDEV] = { NULL, NULL, }; + +/* + * blksize_size contains the size of all block-devices: + * + * blksize_size[MAJOR][MINOR] + * + * if (!blksize_size[MAJOR]) then 1024 bytes is assumed. + */ +int * blksize_size[MAX_BLKDEV] = { NULL, NULL, }; + +/* + * look for a free request in the first N entries. + * NOTE: interrupts must be disabled on the way in, and will still + * be disabled on the way out. + */ +static inline struct request * get_request(int n, int dev) +{ + static struct request *prev_found = NULL, *prev_limit = NULL; + register struct request *req, *limit; + + if (n <= 0) + panic("get_request(%d): impossible!\n", n); + + limit = all_requests + n; + if (limit != prev_limit) { + prev_limit = limit; + prev_found = all_requests; + } + req = prev_found; + for (;;) { + req = ((req > all_requests) ? req : limit) - 1; + if (req->dev < 0) + break; + if (req == prev_found) + return NULL; + } + prev_found = req; + req->dev = dev; + return req; +} + +/* + * wait until a free request in the first N entries is available. + * NOTE: interrupts must be disabled on the way in, and will still + * be disabled on the way out. + */ +static inline struct request * get_request_wait(int n, int dev) +{ + register struct request *req; + + while ((req = get_request(n, dev)) == NULL) + sleep_on(&wait_for_request); + return req; +} + +/* RO fail safe mechanism */ + +static long ro_bits[MAX_BLKDEV][8]; + +int is_read_only(int dev) +{ + int minor,major; + + major = MAJOR(dev); + minor = MINOR(dev); + if (major < 0 || major >= MAX_BLKDEV) return 0; + return ro_bits[major][minor >> 5] & (1 << (minor & 31)); +} + +void set_device_ro(int dev,int flag) +{ + int minor,major; + + major = MAJOR(dev); + minor = MINOR(dev); + if (major < 0 || major >= MAX_BLKDEV) return; + if (flag) ro_bits[major][minor >> 5] |= 1 << (minor & 31); + else ro_bits[major][minor >> 5] &= ~(1 << (minor & 31)); +} + +/* + * add-request adds a request to the linked list. + * It disables interrupts so that it can muck with the + * request-lists in peace. + */ +static void add_request(struct blk_dev_struct * dev, struct request * req) +{ + struct request * tmp; + + req->next = NULL; + cli(); + if (req->bh) + req->bh->b_dirt = 0; + if (!(tmp = dev->current_request)) { + dev->current_request = req; + (dev->request_fn)(); + sti(); + return; + } + for ( ; tmp->next ; tmp = tmp->next) { + if ((IN_ORDER(tmp,req) || + !IN_ORDER(tmp,tmp->next)) && + IN_ORDER(req,tmp->next)) + break; + } + req->next = tmp->next; + tmp->next = req; + +/* for SCSI devices, call request_fn unconditionally */ + if (scsi_major(MAJOR(req->dev))) + (dev->request_fn)(); + + sti(); +} + +static void make_request(int major,int rw, struct buffer_head * bh) +{ + unsigned int sector, count; + struct request * req; + int rw_ahead, max_req; + +/* WRITEA/READA is special case - it is not really needed, so if the */ +/* buffer is locked, we just forget about it, else it's a normal read */ + rw_ahead = (rw == READA || rw == WRITEA); + if (rw_ahead) { + if (bh->b_lock) + return; + if (rw == READA) + rw = READ; + else + rw = WRITE; + } + if (rw!=READ && rw!=WRITE) { + printk("Bad block dev command, must be R/W/RA/WA\n"); + return; + } + count = bh->b_size >> 9; + sector = bh->b_blocknr * count; + if (blk_size[major]) + if (blk_size[major][MINOR(bh->b_dev)] < (sector + count)>>1) { + bh->b_dirt = bh->b_uptodate = 0; + return; + } + lock_buffer(bh); + if ((rw == WRITE && !bh->b_dirt) || (rw == READ && bh->b_uptodate)) { + unlock_buffer(bh); + return; + } + +/* we don't allow the write-requests to fill up the queue completely: + * we want some room for reads: they take precedence. The last third + * of the requests are only for reads. + */ + max_req = (rw == READ) ? NR_REQUEST : ((NR_REQUEST*2)/3); + +/* big loop: look for a free request. */ + +repeat: + cli(); + +/* The scsi disk drivers completely remove the request from the queue when + * they start processing an entry. For this reason it is safe to continue + * to add links to the top entry for scsi devices. + */ + if ((major == HD_MAJOR + || major == SCSI_DISK_MAJOR + || major == SCSI_CDROM_MAJOR) + && (req = blk_dev[major].current_request)) + { + if (major == HD_MAJOR) + req = req->next; + while (req) { + if (req->dev == bh->b_dev && + !req->waiting && + req->cmd == rw && + req->sector + req->nr_sectors == sector && + req->nr_sectors < 254) + { + req->bhtail->b_reqnext = bh; + req->bhtail = bh; + req->nr_sectors += count; + bh->b_dirt = 0; + sti(); + return; + } + + if (req->dev == bh->b_dev && + !req->waiting && + req->cmd == rw && + req->sector - count == sector && + req->nr_sectors < 254) + { + req->nr_sectors += count; + bh->b_reqnext = req->bh; + req->buffer = bh->b_data; + req->current_nr_sectors = count; + req->sector = sector; + bh->b_dirt = 0; + req->bh = bh; + sti(); + return; + } + + req = req->next; + } + } + +/* find an unused request. */ + req = get_request(max_req, bh->b_dev); + +/* if no request available: if rw_ahead, forget it; otherwise try again. */ + if (! req) { + if (rw_ahead) { + sti(); + unlock_buffer(bh); + return; + } + sleep_on(&wait_for_request); + sti(); + goto repeat; + } + +/* we found a request. */ + sti(); + +/* fill up the request-info, and add it to the queue */ + req->cmd = rw; + req->errors = 0; + req->sector = sector; + req->nr_sectors = count; + req->current_nr_sectors = count; + req->buffer = bh->b_data; + req->waiting = NULL; + req->bh = bh; + req->bhtail = bh; + req->next = NULL; + add_request(major+blk_dev,req); +} + +void ll_rw_page(int rw, int dev, int page, char * buffer) +{ + struct request * req; + unsigned int major = MAJOR(dev); + + if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) { + printk("Trying to read nonexistent block-device %04x (%d)\n",dev,page*8); + return; + } + if (rw!=READ && rw!=WRITE) + panic("Bad block dev command, must be R/W"); + if (rw == WRITE && is_read_only(dev)) { + printk("Can't page to read-only device 0x%X\n",dev); + return; + } + cli(); + req = get_request_wait(NR_REQUEST, dev); + sti(); +/* fill up the request-info, and add it to the queue */ + req->cmd = rw; + req->errors = 0; + req->sector = page<<3; + req->nr_sectors = 8; + req->current_nr_sectors = 8; + req->buffer = buffer; + req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_SWAPPING; + add_request(major+blk_dev,req); + schedule(); +} + +/* This function can be used to request a number of buffers from a block + device. Currently the only restriction is that all buffers must belong to + the same device */ + +void ll_rw_block(int rw, int nr, struct buffer_head * bh[]) +{ + unsigned int major; + struct request plug; + int plugged; + int correct_size; + struct blk_dev_struct * dev; + int i; + + /* Make sure that the first block contains something reasonable */ + while (!*bh) { + bh++; + if (--nr <= 0) + return; + }; + + dev = NULL; + if ((major = MAJOR(bh[0]->b_dev)) < MAX_BLKDEV) + dev = blk_dev + major; + if (!dev || !dev->request_fn) { + printk( + "ll_rw_block: Trying to read nonexistent block-device %04lX (%ld)\n", + (unsigned long) bh[0]->b_dev, bh[0]->b_blocknr); + goto sorry; + } + + /* Determine correct block size for this device. */ + correct_size = BLOCK_SIZE; + if (blksize_size[major]) { + i = blksize_size[major][MINOR(bh[0]->b_dev)]; + if (i) + correct_size = i; + } + + /* Verify requested block sizees. */ + for (i = 0; i < nr; i++) { + if (bh[i] && bh[i]->b_size != correct_size) { + printk( + "ll_rw_block: only %d-char blocks implemented (%lu)\n", + correct_size, bh[i]->b_size); + goto sorry; + } + } + + if ((rw == WRITE || rw == WRITEA) && is_read_only(bh[0]->b_dev)) { + printk("Can't write to read-only device 0x%X\n",bh[0]->b_dev); + goto sorry; + } + + /* If there are no pending requests for this device, then we insert + a dummy request for that device. This will prevent the request + from starting until we have shoved all of the blocks into the + queue, and then we let it rip. */ + + plugged = 0; + cli(); + if (!dev->current_request && nr > 1) { + dev->current_request = &plug; + plug.dev = -1; + plug.next = NULL; + plugged = 1; + } + sti(); + for (i = 0; i < nr; i++) { + if (bh[i]) { + bh[i]->b_req = 1; + make_request(major, rw, bh[i]); + if (rw == READ || rw == READA) + kstat.pgpgin++; + else + kstat.pgpgout++; + } + } + if (plugged) { + cli(); + dev->current_request = plug.next; + (dev->request_fn)(); + sti(); + } + return; + + sorry: + for (i = 0; i < nr; i++) { + if (bh[i]) + bh[i]->b_dirt = bh[i]->b_uptodate = 0; + } + return; +} + +void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buf) +{ + int i; + int buffersize; + struct request * req; + unsigned int major = MAJOR(dev); + + if (major >= MAX_BLKDEV || !(blk_dev[major].request_fn)) { + printk("ll_rw_swap_file: trying to swap nonexistent block-device\n"); + return; + } + + if (rw!=READ && rw!=WRITE) { + printk("ll_rw_swap: bad block dev command, must be R/W"); + return; + } + if (rw == WRITE && is_read_only(dev)) { + printk("Can't swap to read-only device 0x%X\n",dev); + return; + } + + buffersize = PAGE_SIZE / nb; + + for (i=0; icmd = rw; + req->errors = 0; + req->sector = (b[i] * buffersize) >> 9; + req->nr_sectors = buffersize >> 9; + req->current_nr_sectors = buffersize >> 9; + req->buffer = buf; + req->waiting = current; + req->bh = NULL; + req->next = NULL; + current->state = TASK_UNINTERRUPTIBLE; + add_request(major+blk_dev,req); + schedule(); + } +} + +long blk_dev_init(long mem_start, long mem_end) +{ + struct request * req; + + req = all_requests + NR_REQUEST; + while (--req >= all_requests) { + req->dev = -1; + req->next = NULL; + } + memset(ro_bits,0,sizeof(ro_bits)); +#ifdef CONFIG_BLK_DEV_HD + mem_start = hd_init(mem_start,mem_end); +#endif +#ifdef CONFIG_BLK_DEV_XD + mem_start = xd_init(mem_start,mem_end); +#endif +#ifdef CONFIG_CDU31A + mem_start = cdu31a_init(mem_start,mem_end); +#endif +#ifdef CONFIG_MCD + mem_start = mcd_init(mem_start,mem_end); +#endif +#ifdef CONFIG_SBPCD + mem_start = sbpcd_init(mem_start, mem_end); +#endif CONFIG_SBPCD + if (ramdisk_size) + mem_start += rd_init(mem_start, ramdisk_size*1024); + return mem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/mcd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/mcd.c new file mode 100644 index 000000000..44119ea9e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/mcd.c @@ -0,0 +1,1224 @@ +/* + linux/kernel/blk_drv/mcd.c - Mitsumi CDROM driver + + Copyright (C) 1992 Martin Harriss + + martin@bdsi.com + + 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. + + HISTORY + + 0.1 First attempt - internal use only + 0.2 Cleaned up delays and use of timer - alpha release + 0.3 Audio support added + 0.3.1 Changes for mitsumi CRMC LU005S march version + (stud11@cc4.kuleuven.ac.be) + 0.3.2 bug fixes to the ioclts and merged with ALPHA0.99-pl12 + (Jon Tombs ) + 0.3.3 Added more #defines and mcd_setup() + (Jon Tombs ) +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include + +/* #define REALLY_SLOW_IO */ +#include +#include +#include + +#define MAJOR_NR MITSUMI_CDROM_MAJOR +#include "blk.h" +#include + +#if 0 +static int mcd_sizes[] = { 0 }; +#endif + +static int mcdPresent = 0; + +static char mcd_buf[2048]; /* buffer for block size conversion */ +static int mcd_bn = -1; +static short mcd_port = MCD_BASE_ADDR; +static int mcd_irq = MCD_INTR_NR; + +static int McdTimeout, McdTries; +static struct wait_queue *mcd_waitq = NULL; + +static struct mcd_DiskInfo DiskInfo; +static struct mcd_Toc Toc[MAX_TRACKS]; +static struct mcd_Play_msf mcd_Play; + +static int audioStatus; +static char mcdDiskChanged; +static char tocUpToDate; +static char mcdVersion; + +static void mcd_transfer(void); +static void mcd_start(void); +static void mcd_status(void); +static void mcd_read_cmd(void); +static void mcd_data(void); +static void do_mcd_request(void); +static void hsg2msf(long hsg, struct msf *msf); +static void bin2bcd(unsigned char *p); +static int bcd2bin(unsigned char bcd); +static int mcdStatus(void); +static void sendMcdCmd(int cmd, struct mcd_Play_msf *params); +static int getMcdStatus(int timeout); +static int GetQChannelInfo(struct mcd_Toc *qp); +static int updateToc(void); +static int GetDiskInfo(void); +static int GetToc(void); +static int getValue(unsigned char *result); + + +void mcd_setup(char *str, int *ints) +{ + if (ints[0] > 0) + mcd_port = ints[1]; + if (ints[0] > 1) + mcd_irq = ints[2]; +} + + +int +check_mcd_media_change(int full_dev, int flag) +{ + int retval, target; + + +#if 1 /* the below is not reliable */ + return 0; +#endif + target = MINOR(full_dev); + + if (target > 0) { + printk("mcd: Mitsumi CD-ROM request error: invalid device.\n"); + return 0; + } + + retval = mcdDiskChanged; + if (!flag) + { + mcdDiskChanged = 0; + } + + return retval; +} + + +/* + * Do a 'get status' command and get the result. Only use from the top half + * because it calls 'getMcdStatus' which sleeps. + */ + +static int +statusCmd(void) +{ + int st, retry; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + + outb(MCMD_GET_STATUS, MCDPORT(0)); /* send get-status cmd */ + st = getMcdStatus(MCD_STATUS_DELAY); + if (st != -1) + break; + } + + return st; +} + + +/* + * Send a 'Play' command and get the status. Use only from the top half. + */ + +static int +mcdPlay(struct mcd_Play_msf *arg) +{ + int retry, st; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + sendMcdCmd(MCMD_PLAY_READ, arg); + st = getMcdStatus(2 * MCD_STATUS_DELAY); + if (st != -1) + break; + } + + return st; +} + + +long +msf2hsg(struct msf *mp) +{ + return bcd2bin(mp -> frame) + + bcd2bin(mp -> sec) * 75 + + bcd2bin(mp -> min) * 4500 + - 150; +} + + +static int +mcd_ioctl(struct inode *ip, struct file *fp, unsigned int cmd, + unsigned long arg) +{ + int i, st; + struct mcd_Toc qInfo; + struct cdrom_ti ti; + struct cdrom_tochdr tocHdr; + struct cdrom_msf msf; + struct cdrom_tocentry entry; + struct mcd_Toc *tocPtr; + struct cdrom_subchnl subchnl; +#if 0 + struct cdrom_volctrl volctrl; +#endif + + if (!ip) + return -EINVAL; + + st = statusCmd(); + if (st < 0) + return -EIO; + + if (!tocUpToDate) + { + i = updateToc(); + if (i < 0) + return i; /* error reading TOC */ + } + + switch (cmd) + { + case CDROMSTART: /* Spin up the drive */ + /* Don't think we can do this. Even if we could, + * I think the drive times out and stops after a while + * anyway. For now, ignore it. + */ + + return 0; + + case CDROMSTOP: /* Spin down the drive */ + outb(MCMD_STOP, MCDPORT(0)); + i = getMcdStatus(MCD_STATUS_DELAY); + + /* should we do anything if it fails? */ + + audioStatus = CDROM_AUDIO_NO_STATUS; + return 0; + + case CDROMPAUSE: /* Pause the drive */ + if (audioStatus != CDROM_AUDIO_PLAY) + return -EINVAL; + + outb(MCMD_STOP, MCDPORT(0)); + i = getMcdStatus(MCD_STATUS_DELAY); + + if (GetQChannelInfo(&qInfo) < 0) + { + /* didn't get q channel info */ + + audioStatus = CDROM_AUDIO_NO_STATUS; + return 0; + } + + mcd_Play.start = qInfo.diskTime; /* remember restart point */ + + audioStatus = CDROM_AUDIO_PAUSED; + return 0; + + case CDROMRESUME: /* Play it again, Sam */ + if (audioStatus != CDROM_AUDIO_PAUSED) + return -EINVAL; + + /* restart the drive at the saved position. */ + + i = mcdPlay(&mcd_Play); + if (i < 0) + { + audioStatus = CDROM_AUDIO_ERROR; + return -EIO; + } + + audioStatus = CDROM_AUDIO_PLAY; + return 0; + + case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ + + st = verify_area(VERIFY_READ, (void *) arg, sizeof ti); + if (st) + return st; + + memcpy_fromfs(&ti, (void *) arg, sizeof ti); + + if (ti.cdti_trk0 < DiskInfo.first + || ti.cdti_trk0 > DiskInfo.last + || ti.cdti_trk1 < ti.cdti_trk0) + { + return -EINVAL; + } + + if (ti.cdti_trk1 > DiskInfo.last) + ti. cdti_trk1 = DiskInfo.last; + + mcd_Play.start = Toc[ti.cdti_trk0].diskTime; + mcd_Play.end = Toc[ti.cdti_trk1 + 1].diskTime; + +#ifdef MCD_DEBUG +printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n", + mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame, + mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame); +#endif + + i = mcdPlay(&mcd_Play); + if (i < 0) + { + audioStatus = CDROM_AUDIO_ERROR; + return -EIO; + } + + audioStatus = CDROM_AUDIO_PLAY; + return 0; + + case CDROMPLAYMSF: /* Play starting at the given MSF address. */ + + if (audioStatus == CDROM_AUDIO_PLAY) { + outb(MCMD_STOP, MCDPORT(0)); + i = getMcdStatus(MCD_STATUS_DELAY); + audioStatus = CDROM_AUDIO_NO_STATUS; + } + + st = verify_area(VERIFY_READ, (void *) arg, sizeof msf); + if (st) + return st; + + memcpy_fromfs(&msf, (void *) arg, sizeof msf); + + /* convert to bcd */ + + bin2bcd(&msf.cdmsf_min0); + bin2bcd(&msf.cdmsf_sec0); + bin2bcd(&msf.cdmsf_frame0); + bin2bcd(&msf.cdmsf_min1); + bin2bcd(&msf.cdmsf_sec1); + bin2bcd(&msf.cdmsf_frame1); + + mcd_Play.start.min = msf.cdmsf_min0; + mcd_Play.start.sec = msf.cdmsf_sec0; + mcd_Play.start.frame = msf.cdmsf_frame0; + mcd_Play.end.min = msf.cdmsf_min1; + mcd_Play.end.sec = msf.cdmsf_sec1; + mcd_Play.end.frame = msf.cdmsf_frame1; + +#ifdef MCD_DEBUG +printk("play: %02x:%02x.%02x to %02x:%02x.%02x\n", +mcd_Play.start.min, mcd_Play.start.sec, mcd_Play.start.frame, +mcd_Play.end.min, mcd_Play.end.sec, mcd_Play.end.frame); +#endif + + i = mcdPlay(&mcd_Play); + if (i < 0) + { + audioStatus = CDROM_AUDIO_ERROR; + return -EIO; + } + + audioStatus = CDROM_AUDIO_PLAY; + return 0; + + case CDROMREADTOCHDR: /* Read the table of contents header */ + st = verify_area(VERIFY_WRITE, (void *) arg, sizeof tocHdr); + if (st) + return st; + + tocHdr.cdth_trk0 = DiskInfo.first; + tocHdr.cdth_trk1 = DiskInfo.last; + memcpy_tofs((void *) arg, &tocHdr, sizeof tocHdr); + return 0; + + case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ + + st = verify_area(VERIFY_WRITE, (void *) arg, sizeof entry); + if (st) + return st; + + memcpy_fromfs(&entry, (void *) arg, sizeof entry); + if (entry.cdte_track == CDROM_LEADOUT) + /* XXX */ + tocPtr = &Toc[DiskInfo.last + 1]; + + else if (entry.cdte_track > DiskInfo.last + || entry.cdte_track < DiskInfo.first) + return -EINVAL; + + else + tocPtr = &Toc[entry.cdte_track]; + + entry.cdte_adr = tocPtr -> ctrl_addr; + entry.cdte_ctrl = tocPtr -> ctrl_addr >> 4; + + if (entry.cdte_format == CDROM_LBA) + entry.cdte_addr.lba = msf2hsg(&tocPtr -> diskTime); + + else if (entry.cdte_format == CDROM_MSF) + { + entry.cdte_addr.msf.minute = bcd2bin(tocPtr -> diskTime.min); + entry.cdte_addr.msf.second = bcd2bin(tocPtr -> diskTime.sec); + entry.cdte_addr.msf.frame = bcd2bin(tocPtr -> diskTime.frame); + } + + else + return -EINVAL; + + memcpy_tofs((void *) arg, &entry, sizeof entry); + return 0; + + case CDROMSUBCHNL: /* Get subchannel info */ + + st = verify_area(VERIFY_WRITE, (void *) arg, sizeof subchnl); + if (st) + return st; + + memcpy_fromfs(&subchnl, (void *) arg, sizeof subchnl); + + if (GetQChannelInfo(&qInfo) < 0) + return -EIO; + + subchnl.cdsc_audiostatus = audioStatus; + subchnl.cdsc_adr = qInfo.ctrl_addr; + subchnl.cdsc_ctrl = qInfo.ctrl_addr >> 4; + subchnl.cdsc_trk = bcd2bin(qInfo.track); + subchnl.cdsc_ind = bcd2bin(qInfo.pointIndex); + + if (subchnl.cdsc_format == CDROM_LBA) + { + subchnl.cdsc_absaddr.lba = msf2hsg(&qInfo.diskTime); + subchnl.cdsc_reladdr.lba = msf2hsg(&qInfo.trackTime); + } + + else if (subchnl.cdsc_format == CDROM_MSF) + { + subchnl.cdsc_absaddr.msf.minute = bcd2bin(qInfo.diskTime.min); + subchnl.cdsc_absaddr.msf.second = bcd2bin(qInfo.diskTime.sec); + subchnl.cdsc_absaddr.msf.frame = bcd2bin(qInfo.diskTime.frame); + + subchnl.cdsc_reladdr.msf.minute = bcd2bin(qInfo.trackTime.min); + subchnl.cdsc_reladdr.msf.second = bcd2bin(qInfo.trackTime.sec); + subchnl.cdsc_reladdr.msf.frame = bcd2bin(qInfo.trackTime.frame); + } + + else + return -EINVAL; + + memcpy_tofs((void *) arg, &subchnl, sizeof subchnl); + return 0; + + case CDROMVOLCTRL: /* Volume control */ + /* + * This is not working yet. Setting the volume by itself does + * nothing. Following the 'set' by a 'play' results in zero + * volume. Something to work on for the next release. + */ +#if 0 + st = verify_area(VERIFY_READ, (void *) arg, sizeof(volctrl)); + if (st) + return st; + + memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); +printk("VOL %d %d\n", volctrl.channel0 & 0xFF, volctrl.channel1 & 0xFF); + outb(MCMD_SET_VOLUME, MCDPORT(0)); + outb(volctrl.channel0, MCDPORT(0)); + outb(0, MCDPORT(0)); + outb(volctrl.channel1, MCDPORT(0)); + outb(1, MCDPORT(0)); + + i = getMcdStatus(MCD_STATUS_DELAY); + if (i < 0) + return -EIO; + + { + int a, b, c, d; + + getValue(&a); + getValue(&b); + getValue(&c); + getValue(&d); + printk("%02X %02X %02X %02X\n", a, b, c, d); + } + + outb(0xF8, MCDPORT(0)); + i = getMcdStatus(MCD_STATUS_DELAY); + printk("F8 -> %02X\n", i & 0xFF); +#endif + return 0; + + case CDROMEJECT: /* Eject the drive - N/A */ + return 0; + + default: + return -EINVAL; + } +} + + +/* + * Take care of the different block sizes between cdrom and Linux. + * When Linux gets variable block sizes this will probably go away. + */ + +static void +mcd_transfer(void) +{ + long offs; + + while (CURRENT -> nr_sectors > 0 && mcd_bn == CURRENT -> sector / 4) + { + offs = (CURRENT -> sector & 3) * 512; + memcpy(CURRENT -> buffer, mcd_buf + offs, 512); + CURRENT -> nr_sectors--; + CURRENT -> sector++; + CURRENT -> buffer += 512; + } +} + + +/* + * We only seem to get interrupts after an error. + * Just take the interrupt and clear out the status reg. + */ + +static void +mcd_interrupt(int unused) +{ + int st; + + st = inb(MCDPORT(1)) & 0xFF; + if (st != 0xFF) + { + st = inb(MCDPORT(0)) & 0xFF; +#if 0 + printk("", st); +#endif + } +} + + +/* + * I/O request routine called from Linux kernel. + */ + +static void +do_mcd_request(void) +{ + unsigned int block,dev; + unsigned int nsect; + +repeat: + if (!(CURRENT) || CURRENT->dev < 0) return; + INIT_REQUEST; + dev = MINOR(CURRENT->dev); + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + + if (CURRENT == NULL || CURRENT -> sector == -1) + return; + + if (CURRENT -> cmd != READ) + { + printk("mcd: bad cmd %d\n", CURRENT -> cmd); + end_request(0); + goto repeat; + } + + mcd_transfer(); + + /* if we satisfied the request from the buffer, we're done. */ + + if (CURRENT -> nr_sectors == 0) + { + end_request(1); + goto repeat; + } + + McdTries = MCD_RETRY_ATTEMPTS; + mcd_start(); +} + + +/* + * Start the I/O for the cdrom. Handle retry count. + */ + +static void +mcd_start() +{ + if (McdTries == 0) + { + printk("mcd: read failed after %d tries\n", MCD_RETRY_ATTEMPTS); + end_request(0); + SET_TIMER(do_mcd_request, 1); /* wait a bit, try again */ + return; + } + + McdTries--; + outb(0x40, MCDPORT(0)); /* get status */ + McdTimeout = MCD_STATUS_DELAY; + SET_TIMER(mcd_status, 1); +} + + +/* + * Called from the timer to check the results of the get-status cmd. + * On success, send the set-mode command. + */ + +static void +mcd_status() +{ + int st; + + McdTimeout--; + st = mcdStatus(); + if (st == -1) + { + if (McdTimeout == 0) + { + printk("mcd: status timed out\n"); + SET_TIMER(mcd_start, 1); /* wait a bit, try again */ + return; + } + + SET_TIMER(mcd_status, 1); + return; + } + + if (st & MST_DSK_CHG) + { + mcdDiskChanged = 1; + } + + if ((st & MST_READY) == 0) + { + printk("mcd: disk removed\n"); + mcdDiskChanged = 1; + end_request(0); + do_mcd_request(); + return; + } + + outb(0x50, MCDPORT(0)); /* set mode */ + outb(0x01, MCDPORT(0)); /* mode = cooked data */ + McdTimeout = 100; + SET_TIMER(mcd_read_cmd, 1); +} + + +/* + * Check the result of the set-mode command. On success, send the + * read-data command. + */ + +static void +mcd_read_cmd() +{ + int st; + long block; + struct mcd_Play_msf mcdcmd; + + McdTimeout--; + st = mcdStatus(); + + if (st & MST_DSK_CHG) + { + mcdDiskChanged = 1; + } + + if (st == -1) + { + if (McdTimeout == 0) + { + printk("mcd: set mode timed out\n"); + SET_TIMER(mcd_start, 1); /* wait a bit, try again */ + return; + } + + SET_TIMER(mcd_read_cmd, 1); + return; + } + + mcd_bn = -1; /* purge our buffer */ + block = CURRENT -> sector / 4; + hsg2msf(block, &mcdcmd.start); /* cvt to msf format */ + + mcdcmd.end.min = 0; + mcdcmd.end.sec = 0; + mcdcmd.end.frame = 1; + + sendMcdCmd(MCMD_PLAY_READ, &mcdcmd); /* read command */ + McdTimeout = 200; + SET_TIMER(mcd_data, 1); +} + + +/* + * Check the completion of the read-data command. On success, read + * the 2048 bytes of data from the disk into our buffer. + */ + +static void +mcd_data() +{ + int i; + + McdTimeout--; + cli(); + i =inb(MCDPORT(1)) & (MFL_STATUS | MFL_DATA); + if (i == MFL_DATA) + { + printk("mcd: read failed\n"); +#ifdef MCD_DEBUG + printk("got 0xB %02X\n", inb(MCDPORT(0)) & 0xFF); +#endif + SET_TIMER(mcd_start, 1); + sti(); + return; + } + + if (i == (MFL_STATUS | MFL_DATA)) + { + if (McdTimeout == 0) + { + printk("mcd: data timeout, retrying\n"); + SET_TIMER(mcd_start, 1); + } + + else + SET_TIMER(mcd_data, 1); + + sti(); + return; + } + + CLEAR_TIMER; + READ_DATA(MCDPORT(0), &mcd_buf[0], 2048); + sti(); + + mcd_bn = CURRENT -> sector / 4; + mcd_transfer(); + end_request(1); + SET_TIMER(do_mcd_request, 1); +} + + +/* + * Open the device special file. Check that a disk is in. + */ + +int +mcd_open(struct inode *ip, struct file *fp) +{ + int st; + + if (mcdPresent == 0) + return -ENXIO; /* no hardware */ + + st = statusCmd(); /* check drive status */ + if (st == -1) + return -EIO; /* drive doesn't respond */ + + if ((st & MST_READY) == 0) /* no disk in drive */ + { + printk("mcd: no disk in drive\n"); + return -EIO; + } + + if (updateToc() < 0) + return -EIO; + + return 0; +} + + +/* + * On close, we flush all mcd blocks from the buffer cache. + */ + +static void +mcd_release(struct inode * inode, struct file * file) +{ + mcd_bn = -1; + sync_dev(inode->i_rdev); + invalidate_buffers(inode -> i_rdev); +} + + +static struct file_operations mcd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + mcd_ioctl, /* ioctl */ + NULL, /* mmap */ + mcd_open, /* open */ + mcd_release /* release */ +}; + + +/* + * MCD interrupt descriptor + */ + +static struct sigaction mcd_sigaction = { + mcd_interrupt, + 0, + SA_INTERRUPT, + NULL +}; + + +/* + * Test for presence of drive and initialize it. Called at boot time. + */ + +unsigned long +mcd_init(unsigned long mem_start, unsigned long mem_end) +{ + int count; + unsigned char result[3]; + + if (register_blkdev(MAJOR_NR, "mcd", &mcd_fops) != 0) + { + printk("mcd: Unable to get major %d for Mitsumi CD-ROM\n", + MAJOR_NR); + return mem_start; + } + + if (check_region(mcd_port, 4)) { + printk("mcd: Init failed, I/O port (%X) already in use\n", + mcd_port); + return mem_start; + } + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 4; + + /* check for card */ + + outb(0, MCDPORT(1)); /* send reset */ + for (count = 0; count < 1000000; count++) + (void) inb(MCDPORT(1)); /* delay a bit */ + + outb(0x40, MCDPORT(0)); /* send get-stat cmd */ + for (count = 0; count < 1000000; count++) + if (!(inb(MCDPORT(1)) & MFL_STATUS)) + break; + + if (count >= 1000000) { + printk("mcd: Init failed. No mcd device at 0x%x irq %d\n", + mcd_port, mcd_irq); + return mem_start; + } + count = inb(MCDPORT(0)); /* pick up the status */ + + outb(MCMD_GET_VERSION,MCDPORT(0)); + for(count=0;count<3;count++) + if(getValue(result+count)) { + printk("mcd: mitsumi get version failed at 0x%d\n", + mcd_port); + return mem_start; + } + + printk("mcd: Mitsumi version : %02X %c %x\n", + result[0],result[1],result[2]); + + + mcdVersion=result[2]; + + if (mcdVersion >=4) + outb(4,MCDPORT(2)); /* magic happens */ + + /* don't get the IRQ until we know for sure the drive is there */ + + if (irqaction(MCD_INTR_NR, &mcd_sigaction)) + { + printk("mcd: Unable to get IRQ%d for Mitsumi CD-ROM\n", MCD_INTR_NR); + return mem_start; + } + snarf_region(mcd_port, 4); + mcdPresent = 1; + printk("mcd: Mitsumi CD-ROM Drive present at addr %x, irq %d\n", + mcd_port, mcd_irq); + return mem_start; +} + + +static void +hsg2msf(long hsg, struct msf *msf) +{ + hsg += 150; + msf -> min = hsg / 4500; + hsg %= 4500; + msf -> sec = hsg / 75; + msf -> frame = hsg % 75; + + bin2bcd(&msf -> min); /* convert to BCD */ + bin2bcd(&msf -> sec); + bin2bcd(&msf -> frame); +} + + +static void +bin2bcd(unsigned char *p) +{ + int u, t; + + u = *p % 10; + t = *p / 10; + *p = u | (t << 4); +} + +static int +bcd2bin(unsigned char bcd) +{ + return (bcd >> 4) * 10 + (bcd & 0xF); +} + + +/* + * See if a status is ready from the drive and return it + * if it is ready. + */ + +static int +mcdStatus(void) +{ + int i; + int st; + + st = inb(MCDPORT(1)) & MFL_STATUS; + if (!st) + { + i = inb(MCDPORT(0)) & 0xFF; + return i; + } + else + return -1; +} + + +/* + * Send a play or read command to the drive + */ + +static void +sendMcdCmd(int cmd, struct mcd_Play_msf *params) +{ + outb(cmd, MCDPORT(0)); + outb(params -> start.min, MCDPORT(0)); + outb(params -> start.sec, MCDPORT(0)); + outb(params -> start.frame, MCDPORT(0)); + outb(params -> end.min, MCDPORT(0)); + outb(params -> end.sec, MCDPORT(0)); + outb(params -> end.frame, MCDPORT(0)); +} + + +/* + * Timer interrupt routine to test for status ready from the drive. + * (see the next routine) + */ + +static void +mcdStatTimer(void) +{ + if (!(inb(MCDPORT(1)) & MFL_STATUS)) + { + wake_up(&mcd_waitq); + return; + } + + McdTimeout--; + if (McdTimeout <= 0) + { + wake_up(&mcd_waitq); + return; + } + + SET_TIMER(mcdStatTimer, 1); +} + + +/* + * Wait for a status to be returned from the drive. The actual test + * (see routine above) is done by the timer interrupt to avoid + * excessive rescheduling. + */ + +static int +getMcdStatus(int timeout) +{ + int st; + + McdTimeout = timeout; + SET_TIMER(mcdStatTimer, 1); + sleep_on(&mcd_waitq); + if (McdTimeout <= 0) + return -1; + + st = inb(MCDPORT(0)) & 0xFF; + if (st == 0xFF) + return -1; + + if ((st & MST_BUSY) == 0 && audioStatus == CDROM_AUDIO_PLAY) + /* XXX might be an error? look at q-channel? */ + audioStatus = CDROM_AUDIO_COMPLETED; + + if (st & MST_DSK_CHG) + { + mcdDiskChanged = 1; + tocUpToDate = 0; + audioStatus = CDROM_AUDIO_NO_STATUS; + } + + return st; +} + + +/* + * Read a value from the drive. Should return quickly, so a busy wait + * is used to avoid excessive rescheduling. + */ + +static int +getValue(unsigned char *result) +{ + int count; + int s; + + for (count = 0; count < 2000; count++) + if (!(inb(MCDPORT(1)) & MFL_STATUS)) + break; + + if (count >= 2000) + { + printk("mcd: getValue timeout\n"); + return -1; + } + + s = inb(MCDPORT(0)) & 0xFF; + *result = (unsigned char) s; + return 0; +} + + +/* + * Read the current Q-channel info. Also used for reading the + * table of contents. + */ + +int +GetQChannelInfo(struct mcd_Toc *qp) +{ + unsigned char notUsed; + int retry; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + outb(MCMD_GET_Q_CHANNEL, MCDPORT(0)); + if (getMcdStatus(MCD_STATUS_DELAY) != -1) + break; + } + + if (retry >= MCD_RETRY_ATTEMPTS) + return -1; + + if (getValue(&qp -> ctrl_addr) < 0) return -1; + if (getValue(&qp -> track) < 0) return -1; + if (getValue(&qp -> pointIndex) < 0) return -1; + if (getValue(&qp -> trackTime.min) < 0) return -1; + if (getValue(&qp -> trackTime.sec) < 0) return -1; + if (getValue(&qp -> trackTime.frame) < 0) return -1; + if (getValue(¬Used) < 0) return -1; + if (getValue(&qp -> diskTime.min) < 0) return -1; + if (getValue(&qp -> diskTime.sec) < 0) return -1; + if (getValue(&qp -> diskTime.frame) < 0) return -1; + + return 0; +} + + +/* + * Read the table of contents (TOC) and TOC header if neccessary + */ + +static int +updateToc() +{ + if (tocUpToDate) + return 0; + + if (GetDiskInfo() < 0) + return -EIO; + + if (GetToc() < 0) + return -EIO; + + tocUpToDate = 1; + return 0; +} + + +/* + * Read the table of contents header + */ + +static int +GetDiskInfo() +{ + int retry; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + outb(MCMD_GET_DISK_INFO, MCDPORT(0)); + if (getMcdStatus(MCD_STATUS_DELAY) != -1) + break; + } + + if (retry >= MCD_RETRY_ATTEMPTS) + return -1; + + if (getValue(&DiskInfo.first) < 0) return -1; + if (getValue(&DiskInfo.last) < 0) return -1; + + DiskInfo.first = bcd2bin(DiskInfo.first); + DiskInfo.last = bcd2bin(DiskInfo.last); + + if (getValue(&DiskInfo.diskLength.min) < 0) return -1; + if (getValue(&DiskInfo.diskLength.sec) < 0) return -1; + if (getValue(&DiskInfo.diskLength.frame) < 0) return -1; + if (getValue(&DiskInfo.firstTrack.min) < 0) return -1; + if (getValue(&DiskInfo.firstTrack.sec) < 0) return -1; + if (getValue(&DiskInfo.firstTrack.frame) < 0) return -1; + +#ifdef MCD_DEBUG +printk("Disk Info: first %d last %d length %02x:%02x.%02x first %02x:%02x.%02x\n", + DiskInfo.first, + DiskInfo.last, + DiskInfo.diskLength.min, + DiskInfo.diskLength.sec, + DiskInfo.diskLength.frame, + DiskInfo.firstTrack.min, + DiskInfo.firstTrack.sec, + DiskInfo.firstTrack.frame); +#endif + + return 0; +} + + +/* + * Read the table of contents (TOC) + */ + +static int +GetToc() +{ + int i, px; + int limit; + int retry; + struct mcd_Toc qInfo; + + for (i = 0; i < MAX_TRACKS; i++) + Toc[i].pointIndex = 0; + + i = DiskInfo.last + 3; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + outb(MCMD_STOP, MCDPORT(0)); + if (getMcdStatus(MCD_STATUS_DELAY) != -1) + break; + } + + if (retry >= MCD_RETRY_ATTEMPTS) + return -1; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + outb(MCMD_SET_MODE, MCDPORT(0)); + outb(0x05, MCDPORT(0)); /* mode: toc */ + if (getMcdStatus(MCD_STATUS_DELAY) != -1) + break; + } + + if (retry >= MCD_RETRY_ATTEMPTS) + return -1; + + for (limit = 300; limit > 0; limit--) + { + if (GetQChannelInfo(&qInfo) < 0) + break; + + px = bcd2bin(qInfo.pointIndex); + if (px > 0 && px < MAX_TRACKS && qInfo.track == 0) + if (Toc[px].pointIndex == 0) + { + Toc[px] = qInfo; + i--; + } + + if (i <= 0) + break; + } + + Toc[DiskInfo.last + 1].diskTime = DiskInfo.diskLength; + + for (retry = 0; retry < MCD_RETRY_ATTEMPTS; retry++) + { + outb(MCMD_SET_MODE, MCDPORT(0)); + outb(0x01, MCDPORT(0)); + if (getMcdStatus(MCD_STATUS_DELAY) != -1) + break; + } + +#ifdef MCD_DEBUG +for (i = 1; i <= DiskInfo.last; i++) +printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n", +i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, +Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame, +Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame); +for (i = 100; i < 103; i++) +printk("i = %2d ctl-adr = %02X track %2d px %02X %02X:%02X.%02X %02X:%02X.%02X\n", +i, Toc[i].ctrl_addr, Toc[i].track, Toc[i].pointIndex, +Toc[i].trackTime.min, Toc[i].trackTime.sec, Toc[i].trackTime.frame, +Toc[i].diskTime.min, Toc[i].diskTime.sec, Toc[i].diskTime.frame); +#endif + + return limit > 0 ? 0 : -1; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ramdisk.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ramdisk.c new file mode 100644 index 000000000..4904409df --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/ramdisk.c @@ -0,0 +1,178 @@ +/* + * linux/kernel/blk_drv/ramdisk.c + * + * Written by Theodore Ts'o, 12/2/91 + * + * Modifications by Fred N. van Kempen to allow for bootable root + * disks (which are used in LINUX/Pro). Also some cleanups. 03/03/93 + */ + + +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR MEM_MAJOR +#include "blk.h" + +#define RAMDISK_MINOR 1 + + +char *rd_start; +int rd_length = 0; +static int rd_blocksizes[2] = {0, 0}; + +static void do_rd_request(void) +{ + int len; + char *addr; + +repeat: + INIT_REQUEST; + addr = rd_start + (CURRENT->sector << 9); + len = CURRENT->current_nr_sectors << 9; + + if ((MINOR(CURRENT->dev) != RAMDISK_MINOR) || + (addr+len > rd_start+rd_length)) { + end_request(0); + goto repeat; + } + if (CURRENT-> cmd == WRITE) { + (void ) memcpy(addr, + CURRENT->buffer, + len); + } else if (CURRENT->cmd == READ) { + (void) memcpy(CURRENT->buffer, + addr, + len); + } else + panic("RAMDISK: unknown RAM disk command !\n"); + end_request(1); + goto repeat; +} + +static struct file_operations rd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + block_fsync /* fsync */ +}; + +/* + * Returns amount of memory which needs to be reserved. + */ +long rd_init(long mem_start, int length) +{ + int i; + char *cp; + + if (register_blkdev(MEM_MAJOR,"rd",&rd_fops)) { + printk("RAMDISK: Unable to get major %d.\n", MEM_MAJOR); + return 0; + } + blk_dev[MEM_MAJOR].request_fn = DEVICE_REQUEST; + rd_start = (char *) mem_start; + rd_length = length; + cp = rd_start; + for (i=0; i < length; i++) + *cp++ = '\0'; + + for(i=0;i<2;i++) rd_blocksizes[i] = 1024; + blksize_size[MAJOR_NR] = rd_blocksizes; + + return(length); +} + +/* + * If the root device is the RAM disk, try to load it. + * In order to do this, the root device is originally set to the + * floppy, and we later change it to be RAM disk. + */ +void rd_load(void) +{ + struct buffer_head *bh; + struct minix_super_block s; + int block, tries; + int i = 1; + int nblocks; + char *cp; + + /* If no RAM disk specified, give up early. */ + if (!rd_length) return; + printk("RAMDISK: %d bytes, starting at 0x%x\n", + rd_length, (int) rd_start); + + /* If we are doing a diskette boot, we might have to pre-load it. */ + if (MAJOR(ROOT_DEV) != FLOPPY_MAJOR) return; + + /* + * Check for a super block on the diskette. + * The old-style boot/root diskettes had their RAM image + * starting at block 512 of the boot diskette. LINUX/Pro + * uses the enire diskette as a file system, so in that + * case, we have to look at block 0. Be intelligent about + * this, and check both... - FvK + */ + for (tries = 0; tries < 1000; tries += 512) { + block = tries; + bh = breada(ROOT_DEV,block+1,block,block+2,-1); + if (!bh) { + printk("RAMDISK: I/O error while looking for super block!\n"); + return; + } + + /* This is silly- why do we require it to be a MINIX FS? */ + *((struct minix_super_block *) &s) = + *((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 && + s.s_magic != MINIX_SUPER_MAGIC2) { + printk("RAMDISK: trying old-style RAM image.\n"); + continue; + } + + if (nblocks > (rd_length >> BLOCK_SIZE_BITS)) { + printk("RAMDISK: image too big! (%d/%d blocks)\n", + nblocks, rd_length >> BLOCK_SIZE_BITS); + return; + } + printk("RAMDISK: Loading %d blocks into RAM disk", nblocks); + + /* We found an image file system. Load it into core! */ + cp = rd_start; + while (nblocks) { + if (nblocks > 2) + bh = breada(ROOT_DEV, block, block+1, block+2, -1); + else + bh = bread(ROOT_DEV, block, BLOCK_SIZE); + if (!bh) { + printk("RAMDISK: I/O error on block %d, aborting!\n", + block); + return; + } + (void) memcpy(cp, bh->b_data, BLOCK_SIZE); + brelse(bh); + if (!(nblocks-- & 15)) printk("."); + cp += BLOCK_SIZE; + block++; + i++; + } + printk("\ndone\n"); + + /* We loaded the file system image. Prepare for mounting it. */ + ROOT_DEV = ((MEM_MAJOR << 8) | RAMDISK_MINOR); + return; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/sbpcd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/sbpcd.c new file mode 100644 index 000000000..3312e7f29 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/block/sbpcd.c @@ -0,0 +1,2996 @@ +/* + * sbpcd.c CD-ROM device driver for the whole family of IDE-style + * Kotobuki/Matsushita/Panasonic CR-5xx drives for + * SoundBlaster ("Pro" or "16 ASP" or compatible) cards + * and for "no-sound" interfaces like Lasermate and the + * Panasonic CI-101P. + * + * NOTE: This is release 1.2. + * It works with my SbPro & drive CR-521 V2.11 from 2/92 + * and with the new CR-562-B V0.75 on a "naked" Panasonic + * CI-101P interface. And vice versa. + * + * + * VERSION HISTORY + * + * 0.1 initial release, April/May 93, after mcd.c + * + * 0.2 the "repeat:"-loop in do_sbpcd_request did not check for + * end-of-request_queue (resulting in kernel panic). + * Flow control seems stable, but throughput is not better. + * + * 0.3 interrupt locking totally eliminated (maybe "inb" and "outb" + * are still locking) - 0.2 made keyboard-type-ahead losses. + * check_sbpcd_media_change added (to use by isofs/inode.c) + * - but it detects almost nothing. + * + * 0.4 use MAJOR 25 definitely. + * Almost total re-design to support double-speed drives and + * "naked" (no sound) interface cards. + * Flow control should be exact now (tell me if not). + * Don't occupy the SbPro IRQ line (not needed either); will + * live together with Hannu Savolainen's sndkit now. + * Speeded up data transfer to 150 kB/sec, with help from Kai + * Makisara, the "provider" of the "mt" tape utility. + * Give "SpinUp" command if necessary. + * First steps to support up to 4 drives (but currently only one). + * Implemented audio capabilities - workman should work, xcdplayer + * gives some problems. + * This version is still consuming too much CPU time, and + * sleeping still has to be worked on. + * During "long" implied seeks, it seems possible that a + * ReadStatus command gets ignored. That gives the message + * "ResponseStatus timed out" (happens about 6 times here during + * a "ls -alR" of the YGGDRASIL LGX-Beta CD). Such a case is + * handled without data error, but it should get done better. + * + * 0.5 Free CPU during waits (again with help from Kai Makisara). + * Made it work together with the LILO/kernel setup standard. + * Included auto-probing code, as suggested by YGGDRASIL. + * Formal redesign to add DDI debugging. + * There are still flaws in IOCTL (workman with double speed drive). + * + * 1.0 Added support for all drive ids (0...3, no longer only 0) + * and up to 4 drives on one controller. + * Added "#define MANY_SESSION" for "old" multi session CDs. + * + * 1.1 Do SpinUp for new drives, too. + * Revised for clean compile under "old" kernels (pl9). + * + * 1.2 Found the "workman with double-speed drive" bug: use the driver's + * audio_state, not what the drive is reporting with ReadSubQ. + * + * + * + * special thanks to Kai Makisara (kai.makisara@vtt.fi) for his fine + * elaborated speed-up experiments (and the fabulous results!), for + * the "push" towards load-free wait loops, and for the extensive mail + * thread which brought additional hints and bug fixes. + * + * + * Copyright (C) 1993, 1994 Eberhard Moenkeberg + * or + * + * The FTP-home of this driver is + * ftp.gwdg.de:/pub/linux/cdrom/drivers/sbpcd/. + * + * If you change this software, you should mail a .diff + * file with some description lines to emoenke@gwdg.de. + * I want to know about it. + * + * If you are the editor of a Linux CD, you should + * enable sbpcd.c within your boot floppy kernel and + * send me one of your CDs for free. + * + * 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. + * + * You should have received a copy of the GNU General Public License + * (for example /usr/src/linux/COPYING); if not, write to the Free + * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ +#ifndef PATCHLEVEL +#define PATCHLEVEL 9 +#endif + +#include +#include + +#if SBPCD_USE_IRQ +#include +#endif SBPCD_USE_IRQ + +#include +#include +#include +#include +#include +#include +#include + +#if PATCHLEVEL>13 +#include +#include +#else +#define DDIOCSDBG 0x9000 +#define MATSUSHITA_CDROM_MAJOR 25 +#endif + +#include +#include +#include +#include + +#define MAJOR_NR MATSUSHITA_CDROM_MAJOR +#include "blk.h" + +#define VERSION "1.2" + +#define SBPCD_DEBUG + +#ifndef CONFIG_SBPCD +#error "SBPCD: \"make config\" again. Enable Matsushita/Panasonic CDROM support" +#endif + +#ifndef CONFIG_ISO9660_FS +#error "SBPCD: \"make config\" again. File system iso9660 is necessary." +#endif + +/* + * still testing around... + */ +#define MANY_SESSION 0 +#define CDMKE +#undef FUTURE +#define WORKMAN 0 /* some testing stuff to make it better */ + +/*==========================================================================*/ +/*==========================================================================*/ +/* + * auto-probing address list + * inspired by Adam J. Richter from Yggdrasil + * + * still not good enough - can cause a hang. + * example: a NE 2000 ehernet card at 300 will cause a hang probing 310. + * if that happens, reboot and use the LILO (kernel) command line. + * the conflicting possible ethernet card addresses get probed last - to + * minimize the hang possibilities. + * + * The SB Pro addresses get "mirrored" at 0x6xx - to avoid a type error, + * the 0x2xx-addresses must get checked before 0x6xx. + * + * what are other cards' default and range ??? + * what about ESCOM PowerSound??? + * what about HighScreen??? + */ +static int autoprobe[] = +{ + CDROM_PORT, SBPRO, /* probe with user's setup first */ + 0x230, 1, /* Soundblaster Pro and 16 (default) */ + 0x300, 0, /* CI-101P (default), Galaxy (default), Reveal (one default) */ + 0x250, 1, /* OmniCD default, Soundblaster Pro and 16 */ + 0x260, 1, /* OmniCD */ + 0x320, 0, /* Lasermate, CI-101P, Galaxy, Reveal (other default) */ + 0x340, 0, /* Lasermate, CI-101P */ + 0x360, 0, /* Lasermate, CI-101P */ + 0x270, 1, /* Soundblaster 16 */ + 0x630, 0, /* "sound card #9" (default) */ + 0x650, 0, /* "sound card #9" */ + 0x670, 0, /* "sound card #9" */ + 0x690, 0, /* "sound card #9" */ + 0x330, 0, /* Lasermate, CI-101P */ + 0x350, 0, /* Lasermate, CI-101P */ + 0x370, 0, /* Lasermate, CI-101P */ + 0x290, 1, /* Soundblaster 16 */ + 0x310, 0, /* Lasermate, CI-101P */ +}; + +#define NUM_AUTOPROBE (sizeof(autoprobe) / sizeof(int)) + + +/*==========================================================================*/ +/* + * the forward references: + */ +static void sbp_read_cmd(void); +static int sbp_data(void); + +/*==========================================================================*/ + +/* + * pattern for printk selection: + * + * (1<= 128) sbpcd_debug &= ~(1 << (val - 128)); + else sbpcd_debug |= (1 << val); + } + return(0); +} + + +/*==========================================================================*/ +/*==========================================================================*/ +/* + * Wait a little while (used for polling the drive). If in initialization, + * setting a timeout doesn't work, so just loop for a while. + */ +static inline void sbp_sleep(u_int jifs) +{ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + jifs; + schedule(); +} + +/*==========================================================================*/ +/*==========================================================================*/ +/* + * convert logical_block_address to m-s-f_number (3 bytes only) + */ +static void lba2msf(int lba, u_char *msf) +{ + lba += CD_BLOCK_OFFSET; + msf[0] = lba / (CD_SECS*CD_FRAMES); + lba %= CD_SECS*CD_FRAMES; + msf[1] = lba / CD_FRAMES; + msf[2] = lba % CD_FRAMES; +} +/*==========================================================================*/ +/*==========================================================================*/ +/* + * convert msf-bin to msf-bcd + */ +static void bin2bcdx(u_char *p) /* must work only up to 75 or 99 */ +{ + *p=((*p/10)<<4)|(*p%10); +} +/*==========================================================================*/ +static u_int blk2msf(u_int blk) +{ + MSF msf; + u_int mm; + + msf.c[3] = 0; + msf.c[2] = (blk + CD_BLOCK_OFFSET) / (CD_SECS * CD_FRAMES); + mm = (blk + CD_BLOCK_OFFSET) % (CD_SECS * CD_FRAMES); + msf.c[1] = mm / CD_FRAMES; + msf.c[0] = mm % CD_FRAMES; + return (msf.n); +} +/*==========================================================================*/ +static u_int make16(u_char rh, u_char rl) +{ + return ((rh<<8)|rl); +} +/*==========================================================================*/ +static u_int make32(u_int rh, u_int rl) +{ + return ((rh<<16)|rl); +} +/*==========================================================================*/ +static u_char swap_nibbles(u_char i) +{ + return ((i<<4)|(i>>4)); +} +/*==========================================================================*/ +static u_char byt2bcd(u_char i) +{ + return (((i/10)<<4)+i%10); +} +/*==========================================================================*/ +static u_char bcd2bin(u_char bcd) +{ + return ((bcd>>4)*10+(bcd&0x0F)); +} +/*==========================================================================*/ +static int msf2blk(int msfx) +{ + MSF msf; + int i; + + msf.n=msfx; + i=(msf.c[2] * CD_SECS + msf.c[1]) * CD_FRAMES + msf.c[0] - CD_BLOCK_OFFSET; + if (i<0) return (0); + return (i); +} +/*==========================================================================*/ +/* evaluate xx_ReadError code (still mysterious) */ +static int sta2err(int sta) +{ + if (sta<=2) return (sta); + if (sta==0x05) return (-4); + if (sta==0x06) return (-6); + if (sta==0x0d) return (-6); + if (sta==0x0e) return (-3); + if (sta==0x14) return (-3); + if (sta==0x0c) return (-11); + if (sta==0x0f) return (-11); + if (sta==0x10) return (-11); + if (sta>=0x16) return (-12); + DS[d].CD_changed=0xFF; + if (sta==0x11) return (-15); + return (-2); +} +/*==========================================================================*/ +static void clr_cmdbuf(void) +{ + int i; + + for (i=0;i<7;i++) drvcmd[i]=0; + cmd_type=0; +} +/*==========================================================================*/ +static void mark_timeout(void) +{ + timed_out=1; + DPRINTF((DBG_TIM,"SBPCD: timer stopped.\n")); +} +/*==========================================================================*/ +static void flush_status(void) +{ +#ifdef CDMKE + int i; + + if (current == task[0]) + for (i=maxtim02;i!=0;i--) inb(CDi_status); + else + { + sbp_sleep(150); + for (i=maxtim_data;i!=0;i--) inb(CDi_status); + } +#else + timed_out=0; + SET_TIMER(mark_timeout,150); + do { } + while (!timed_out); + CLEAR_TIMER; + inb(CDi_status); +#endif CDMKE +} +/*==========================================================================*/ +static int CDi_stat_loop(void) +{ + int i,j; + u_long timeout; + + if (current == task[0]) + for(i=maxtim16;i!=0;i--) + { + j=inb(CDi_status); + if (!(j&s_not_data_ready)) return (j); + if (!(j&s_not_result_ready)) return (j); + if (!new_drive) if (j&s_attention) return (j); + } + else + for(timeout = jiffies + 1000, i=maxtim_data; timeout > jiffies; ) + { + for ( ;i!=0;i--) + { + j=inb(CDi_status); + if (!(j&s_not_data_ready)) return (j); + if (!(j&s_not_result_ready)) return (j); + if (!new_drive) if (j&s_attention) return (j); + } + sbp_sleep(1); + i = 1; + } + return (-1); +} +/*==========================================================================*/ +static int ResponseInfo(void) +{ + int i,j, st=0; + u_long timeout; + + if (current == task[0]) + for (i=0;i1) return (-3); + if (!new_drive) + { + if (f_blk_msf==1) pos=msf2blk(pos); + drvcmd[2]=(pos>>16)&0x00FF; + drvcmd[3]=(pos>>8)&0x00FF; + drvcmd[4]=pos&0x00FF; + flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | + f_ResponseStatus | f_obey_p_check | f_bit1; + } + else + { + if (f_blk_msf==0) pos=blk2msf(pos); + drvcmd[1]=(pos>>16)&0x00FF; + drvcmd[2]=(pos>>8)&0x00FF; + drvcmd[3]=pos&0x00FF; + flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; + } + drvcmd[0]=0x01; + response_count=0; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +static int xx_SpinUp(void) +{ + int i; + + DPRINTF((DBG_SPI,"SBPCD: SpinUp.\n")); + DS[d].in_SpinUp = 1; + clr_cmdbuf(); + if (!new_drive) + { + drvcmd[0]=0x05; + flags_cmd_out=f_putcmd|f_respo2|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; + } + else + { + drvcmd[0]=0x02; + flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; + } + response_count=0; + i=cmd_out(); + DS[d].in_SpinUp = 0; + return (i); +} +/*==========================================================================*/ +static int yy_SpinDown(void) +{ + int i; + + if (!new_drive) return (-3); + clr_cmdbuf(); + drvcmd[0]=0x06; + flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; + response_count=0; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +static int yy_SetSpeed(u_char speed, u_char x1, u_char x2) +{ + int i; + + if (!new_drive) return (-3); + clr_cmdbuf(); + drvcmd[0]=0x09; + drvcmd[1]=0x03; + drvcmd[2]=speed; + drvcmd[3]=x1; + drvcmd[4]=x2; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + response_count=0; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +static int xx_SetVolume(void) +{ + int i; + u_char channel0,channel1,volume0,volume1; + u_char control0,value0,control1,value1; + + DS[d].diskstate_flags &= ~volume_bit; + clr_cmdbuf(); + channel0=DS[d].vol_chan0; + volume0=DS[d].vol_ctrl0; + channel1=control1=DS[d].vol_chan1; + volume1=value1=DS[d].vol_ctrl1; + control0=value0=0; + + if (((DS[d].drv_options&sax_a)!=0)&&(DS[d].drv_type>=drv_211)) + { + if ((volume0!=0)&&(volume1==0)) + { + volume1=volume0; + channel1=channel0; + } + else if ((volume0==0)&&(volume1!=0)) + { + volume0=volume1; + channel0=channel1; + } + } + if (channel0>1) + { + channel0=0; + volume0=0; + } + if (channel1>1) + { + channel1=1; + volume1=0; + } + + if (new_drive) + { + control0=channel0+1; + control1=channel1+1; + value0=(volume0>volume1)?volume0:volume1; + value1=value0; + if (volume0==0) control0=0; + if (volume1==0) control1=0; + drvcmd[0]=0x09; + drvcmd[1]=0x05; + drvcmd[3]=control0; + drvcmd[4]=value0; + drvcmd[5]=control1; + drvcmd[6]=value1; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + if (DS[d].drv_type>=drv_300) + { + control0=volume0&0xFC; + value0=volume1&0xFC; + if ((volume0!=0)&&(volume0<4)) control0 |= 0x04; + if ((volume1!=0)&&(volume1<4)) value0 |= 0x04; + if (channel0!=0) control0 |= 0x01; + if (channel1==1) value0 |= 0x01; + } + else + { + value0=(volume0>volume1)?volume0:volume1; + if (DS[d].drv_type=drv_201) + { + if (volume0==0) control0 |= 0x80; + if (volume1==0) control0 |= 0x40; + } + if (DS[d].drv_type>=drv_211) + { + if (channel0!=0) control0 |= 0x20; + if (channel1!=1) control0 |= 0x10; + } + } + drvcmd[0]=0x84; + drvcmd[1]=0x83; + drvcmd[4]=control0; + drvcmd[5]=value0; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + } + + response_count=0; + i=cmd_out(); + if (i>0) return (i); + DS[d].diskstate_flags |= volume_bit; + return (0); +} +/*==========================================================================*/ +static int GetStatus(void) +{ + int i; + + flags_cmd_out=f_getsta|f_ResponseStatus|f_obey_p_check; + response_count=0; + cmd_type=0; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +static int xy_DriveReset(void) +{ + int i; + + DPRINTF((DBG_RES,"SBPCD: xy_DriveReset called.\n")); + if (!new_drive) OUT(CDo_reset,0x00); + else + { + clr_cmdbuf(); + drvcmd[0]=0x0A; + flags_cmd_out=f_putcmd; + response_count=0; + i=cmd_out(); + } + flush_status(); + i=GetStatus(); + if (i>=0) return -1; + if (DS[d].error_byte!=aud_12) return -1; + return (0); +} +/*==========================================================================*/ +static int SetSpeed(void) +{ + int i, speed; + + if (!(DS[d].drv_options&(speed_auto|speed_300|speed_150))) return (0); + speed=0x80; + if (!(DS[d].drv_options&speed_auto)) + { + speed |= 0x40; + if (!(DS[d].drv_options&speed_300)) speed=0; + } + i=yy_SetSpeed(speed,0,0); + return (i); +} +/*==========================================================================*/ +static int DriveReset(void) +{ + int i; + + i=xy_DriveReset(); + if (i<0) return (-2); + do + { + i=GetStatus(); + if ((i<0)&&(i!=-15)) return (-2); /* i!=-15 is from sta2err */ + if (!st_caddy_in) break; + } + while (!st_diskok); + DS[d].CD_changed=1; + i=SetSpeed(); + if (i<0) return (-2); + return (0); +} +/*==========================================================================*/ +static int xx_Pause_Resume(int pau_res) +{ + int i; + + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x0D; + flags_cmd_out=f_putcmd|f_respo2|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x8D; + flags_cmd_out=f_putcmd|f_respo2|f_getsta|f_ResponseStatus|f_obey_p_check; + } + if (pau_res!=1) drvcmd[1]=0x80; + response_count=0; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +#if 000 +static int yy_LockDoor(char lock) +{ + int i; + + if (!new_drive) return (-3); + clr_cmdbuf(); + drvcmd[0]=0x0C; + if (lock==1) drvcmd[1]=0x01; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + response_count=0; + i=cmd_out(); + return (i); +} +#endif 000 +/*==========================================================================*/ +static int xx_ReadSubQ(void) +{ + int i,j; + + DS[d].diskstate_flags &= ~subq_bit; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x87; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + response_count=11; + } + else + { + drvcmd[0]=0x89; + drvcmd[1]=0x02; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + response_count=13; + } + for (j=0;j<255;j++) + { + i=cmd_out(); + if (i<0) return (i); + if (infobuf[0]!=0) break; + if (!st_spinning) + { + DS[d].SubQ_ctl_adr=DS[d].SubQ_trk=DS[d].SubQ_pnt_idx=DS[d].SubQ_whatisthis=0; + DS[d].SubQ_run_tot=DS[d].SubQ_run_trk=0; + return (0); + } + } + DS[d].SubQ_audio=infobuf[0]; + DS[d].SubQ_ctl_adr=swap_nibbles(infobuf[1]); + DS[d].SubQ_trk=byt2bcd(infobuf[2]); + DS[d].SubQ_pnt_idx=byt2bcd(infobuf[3]); + i=4; + if (!new_drive) i=5; + DS[d].SubQ_run_tot=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ + i=7; + if (!new_drive) i=9; + DS[d].SubQ_run_trk=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); /* msf-bin */ + DS[d].SubQ_whatisthis=infobuf[i+3]; + DS[d].diskstate_flags |= subq_bit; + return (0); +} +/*==========================================================================*/ +static int xx_ModeSense(void) +{ + int i; + + DS[d].diskstate_flags &= ~frame_size_bit; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x84; + drvcmd[1]=0x00; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + response_count=5; + } + else + { + drvcmd[0]=0x85; + drvcmd[1]=0x00; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + response_count=2; + } + i=cmd_out(); + if (i<0) return (i); + i=0; + if (new_drive) DS[d].sense_byte=infobuf[i++]; + DS[d].frame_size=make16(infobuf[i],infobuf[i+1]); + DS[d].diskstate_flags |= frame_size_bit; + return (0); +} +/*==========================================================================*/ +#if 0000 +static int xx_TellVolume(void) +{ + int i; + u_char switches; + u_char chan0,vol0,chan1,vol1; + + DS[d].diskstate_flags &= ~volume_bit; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x84; + drvcmd[1]=0x05; + response_count=5; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x85; + drvcmd[1]=0x03; + response_count=2; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + } + i=cmd_out(); + if (i<0) return (i); + if (new_drive) + { + chan0=infobuf[1]&0x0F; + vol0=infobuf[2]; + chan1=infobuf[3]&0x0F; + vol1=infobuf[4]; + if (chan0==0) + { + chan0=1; + vol0=0; + } + if (chan1==0) + { + chan1=2; + vol1=0; + } + chan0 >>= 1; + chan1 >>= 1; + } + else + { + chan0=0; + chan1=1; + vol0=vol1=infobuf[1]; + if (DS[d].drv_type>=drv_201) + { + if (DS[d].drv_type=drv_211) + { + if ((switches&0x20)!=0) chan0=1; + if ((switches&0x10)!=0) chan1=0; + } + } + else + { + vol0=infobuf[0]; + if ((vol0&0x01)!=0) chan0=1; + if ((vol1&0x01)==0) chan1=0; + vol0 &= 0xFC; + vol1 &= 0xFC; + if (vol0!=0) vol0 += 3; + if (vol1!=0) vol1 += 3; + } + } + } + DS[d].vol_chan0=chan0; + DS[d].vol_ctrl0=vol0; + DS[d].vol_chan1=chan1; + DS[d].vol_ctrl1=vol1; + DS[d].vol_chan2=2; + DS[d].vol_ctrl2=0xFF; + DS[d].vol_chan3=3; + DS[d].vol_ctrl3=0xFF; + DS[d].diskstate_flags |= volume_bit; + return (0); +} +#endif +/*==========================================================================*/ +static int xx_ReadCapacity(void) +{ + int i; + + DS[d].diskstate_flags &= ~cd_size_bit; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x85; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x88; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + } + response_count=5; + i=cmd_out(); + if (i<0) return (i); + DS[d].CDsize_blk=make32(make16(0,infobuf[0]),make16(infobuf[1],infobuf[2])); + if (new_drive) DS[d].CDsize_blk=msf2blk(DS[d].CDsize_blk); + DS[d].CDsize_frm = (DS[d].CDsize_blk * make16(infobuf[3],infobuf[4])) / CD_FRAMESIZE; + DS[d].CDsize_blk += 151; + DS[d].diskstate_flags |= cd_size_bit; + return (0); +} +/*==========================================================================*/ +static int xx_ReadTocDescr(void) +{ + int i; + + DS[d].diskstate_flags &= ~toc_bit; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x8B; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x8B; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + } + response_count=6; + i=cmd_out(); + if (i<0) return (i); + DS[d].xa_byte=infobuf[0]; + DS[d].n_first_track=infobuf[1]; + DS[d].n_last_track=infobuf[2]; + DS[d].size_msf=make32(make16(0,infobuf[3]),make16(infobuf[4],infobuf[5])); + DS[d].size_blk=msf2blk(DS[d].size_msf); + DS[d].diskstate_flags |= toc_bit; + DPRINTF((DBG_TOC,"SBPCD: TocDesc: %02X %02X %02X %08X\n", + DS[d].xa_byte,DS[d].n_first_track,DS[d].n_last_track,DS[d].size_msf)); + return (0); +} +/*==========================================================================*/ +static int xx_ReadTocEntry(int num) +{ + int i; + + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x8C; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x8C; + drvcmd[1]=0x02; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + } + drvcmd[2]=num; + response_count=8; + i=cmd_out(); + if (i<0) return (i); + DS[d].TocEnt_nixbyte=infobuf[0]; + DS[d].TocEnt_ctl_adr=swap_nibbles(infobuf[1]); + DS[d].TocEnt_number=infobuf[2]; + DS[d].TocEnt_format=infobuf[3]; + if (new_drive) i=4; + else i=5; + DS[d].TocEnt_address=make32(make16(0,infobuf[i]),make16(infobuf[i+1],infobuf[i+2])); + DPRINTF((DBG_TOC,"SBPCD: TocEntry: %02X %02X %02X %02X %08X\n", + DS[d].TocEnt_nixbyte,DS[d].TocEnt_ctl_adr,DS[d].TocEnt_number, + DS[d].TocEnt_format,DS[d].TocEnt_address)); + return (0); +} +/*==========================================================================*/ +static int xx_ReadPacket(void) +{ + int i; + + clr_cmdbuf(); + drvcmd[0]=0x8E; + drvcmd[1]=response_count; + flags_cmd_out=f_putcmd|f_getsta|f_ResponseStatus|f_obey_p_check; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +static int convert_UPC(u_char *p) +{ + int i; + + p++; + if (!new_drive) p[13]=0; + for (i=0;i<7;i++) + { + if (new_drive) DS[d].UPC_buf[i]=swap_nibbles(*p++); + else + { + DS[d].UPC_buf[i]=((*p++)<<4)&0xFF; + DS[d].UPC_buf[i] |= *p++; + } + } + DS[d].UPC_buf[6] &= 0xF0; + return (0); +} +/*==========================================================================*/ +static int xx_ReadUPC(void) +{ + int i; + + DS[d].diskstate_flags &= ~upc_bit; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x88; + response_count=8; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + } + else + { + drvcmd[0]=0x08; + response_count=0; + flags_cmd_out=f_putcmd|f_lopsta|f_getsta|f_ResponseStatus|f_obey_p_check|f_bit1; + } + i=cmd_out(); + if (i<0) return (i); + if (!new_drive) + { + response_count=16; + i=xx_ReadPacket(); + if (i<0) return (i); + } + DS[d].UPC_ctl_adr=0; + if (new_drive) i=0; + else i=2; + if ((infobuf[i]&0x80)!=0) + { + convert_UPC(&infobuf[i]); + DS[d].UPC_ctl_adr &= 0xF0; + DS[d].UPC_ctl_adr |= 0x02; + } + DS[d].diskstate_flags |= upc_bit; + return (0); +} +/*==========================================================================*/ +static int yy_CheckMultiSession(void) +{ + int i; + + DS[d].diskstate_flags &= ~multisession_bit; + DS[d].f_multisession=0; + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x8D; + response_count=6; + flags_cmd_out=f_putcmd|f_ResponseStatus|f_obey_p_check; + i=cmd_out(); + if (i<0) return (i); + if ((infobuf[0]&0x80)!=0) + { + DPRINTF((DBG_MUL,"SBPCD: MultiSession CD detected: %02X %02X %02X %02X %02X %02X\n", + infobuf[0], infobuf[1], infobuf[2], + infobuf[3], infobuf[4], infobuf[5])); + DS[d].f_multisession=1; + DS[d].lba_multi=msf2blk(make32(make16(0,infobuf[1]), + make16(infobuf[2],infobuf[3]))); + } + } + DS[d].diskstate_flags |= multisession_bit; + return (0); +} +/*==========================================================================*/ +static void check_datarate(void) +{ +#ifdef CDMKE + int i=0; + + timed_out=0; + datarate=0; + + /* set a timer to make (timed_out!=0) after 1.1 seconds */ + + DPRINTF((DBG_TIM,"SBPCD: timer started (110).\n")); + sti(); /* to avoid possible "printf" bug */ + + SET_TIMER(mark_timeout,110); + do + { + i=inb(CDi_status); + datarate++; + +#if 00000 + if (datarate>0x0FFFFFFF) break; +#endif 00000 + + } + while (!timed_out); /* originally looping for 1.1 seconds */ + CLEAR_TIMER; + DPRINTF((DBG_TIM,"SBPCD: datarate: %d\n", datarate)); + if (datarate<65536) datarate=65536; + + maxtim16=datarate*16; + maxtim04=datarate*4; + maxtim02=datarate*2; + maxtim_8=datarate/32; +#if MANY_SESSION + maxtim_data=datarate/100; +#else + maxtim_data=datarate/300; +#endif MANY_SESSION + DPRINTF((DBG_TIM,"SBPCD: maxtim_8 %d, maxtim_data %d.\n", + maxtim_8, maxtim_data)); +#endif CDMKE +} +/*==========================================================================*/ +static int check_version(void) +{ + int i, j; + + /* clear any pending error state */ + clr_cmdbuf(); + drvcmd[0]=0x82; + response_count=9; + flags_cmd_out=f_putcmd; + cmd_out(); + + /* read drive version */ + clr_cmdbuf(); + for (i=0;i<12;i++) infobuf[i]=0; + drvcmd[0]=0x83; + response_count=12; + flags_cmd_out=f_putcmd; + i=cmd_out(); + if (i<0) DPRINTF((DBG_INI,"SBPCD: cmd_83 returns %d\n",i)); + + DPRINTF((DBG_INI,"SBPCD: infobuf = \"")); + for (i=0;i<12;i++) DPRINTF((DBG_INI,"%c",infobuf[i])); + DPRINTF((DBG_INI,"\"\n")); + + for (i=0;i<4;i++) if (infobuf[i]!=drive_family[i]) break; + if (i==4) + { + DS[d].drive_model[0]=infobuf[i++]; + DS[d].drive_model[1]=infobuf[i++]; + DS[d].drive_model[2]='-'; + DS[d].drive_model[3]='x'; + DS[d].drv_type=drv_new; + } + else + { + for (i=0;i<8;i++) if (infobuf[i]!=drive_vendor[i]) break; + if (i!=8) return (-1); + DS[d].drive_model[0]='2'; + DS[d].drive_model[1]='x'; + DS[d].drive_model[2]='-'; + DS[d].drive_model[3]='x'; + DS[d].drv_type=drv_old; + } + for (j=0;j<4;j++) DS[d].firmware_version[j]=infobuf[i+j]; + j = (DS[d].firmware_version[0] & 0x0F) * 100 + + (DS[d].firmware_version[2] & 0x0F) *10 + + (DS[d].firmware_version[3] & 0x0F); + if (new_drive) + { + if (j<100) DS[d].drv_type=drv_099; + else DS[d].drv_type=drv_100; + } + else if (j<200) DS[d].drv_type=drv_199; + else if (j<201) DS[d].drv_type=drv_200; + else if (j<210) DS[d].drv_type=drv_201; + else if (j<211) DS[d].drv_type=drv_210; + else if (j<300) DS[d].drv_type=drv_211; + else DS[d].drv_type=drv_300; + return (0); +} +/*==========================================================================*/ +static int switch_drive(int num) +{ + int i; + + d=num; + + i=num; + if (sbpro_type) i=(i&0x01)<<1|(i&0x02)>>1; + OUT(CDo_enable,i); + DPRINTF((DBG_DID,"SBPCD: switch_drive: drive %d activated.\n",DS[d].drv_minor)); + return (0); +} +/*==========================================================================*/ +/* + * probe for the presence of drives on the selected controller + */ +static int check_drives(void) +{ + int i, j; + char *printk_header=""; + + DPRINTF((DBG_INI,"SBPCD: check_drives entered.\n")); + + ndrives=0; + for (j=0;j=0) + { + ndrives++; + DS[d].drv_options=drv_pattern[j]; + if (!new_drive) DS[d].drv_options&=~(speed_auto|speed_300|speed_150); + printk("%sDrive %d: %s%.4s (%.4s)\n", printk_header, + DS[d].drv_minor, + drive_family, + DS[d].drive_model, + DS[d].firmware_version); + printk_header=" - "; + } + else DS[d].drv_minor=-1; + } + if (ndrives==0) return (-1); + return (0); +} +/*==========================================================================*/ +#if 000 +static void timewait(void) +{ + int i; + for (i=0; i<65500; i++); +} +#endif 000 +/*==========================================================================*/ +#if FUTURE +/* + * obtain if requested service disturbs current audio state + */ +static int obey_audio_state(u_char audio_state, u_char func,u_char subfunc) +{ + switch (audio_state) /* audio status from controller */ + { + case aud_11: /* "audio play in progress" */ + case audx11: + switch (func) /* DOS command code */ + { + case cmd_07: /* input flush */ + case cmd_0d: /* open device */ + case cmd_0e: /* close device */ + case cmd_0c: /* ioctl output */ + return (1); + case cmd_03: /* ioctl input */ + switch (subfunc) + /* DOS ioctl input subfunction */ + { + case cxi_00: + case cxi_06: + case cxi_09: + return (1); + default: + return (ERROR15); + } + return (1); + default: + return (ERROR15); + } + return (1); + case aud_12: /* "audio play paused" */ + case audx12: + return (1); + default: + return (2); + } +} +#endif FUTURE +/*==========================================================================*/ +/* allowed is only + * ioctl_o, flush_input, open_device, close_device, + * tell_address, tell_volume, tell_capabiliti, + * tell_framesize, tell_CD_changed, tell_audio_posi + */ +static int check_allowed1(u_char func1, u_char func2) +{ +#if 000 + if (func1==ioctl_o) return (0); + if (func1==read_long) return (-1); + if (func1==read_long_prefetch) return (-1); + if (func1==seek) return (-1); + if (func1==audio_play) return (-1); + if (func1==audio_pause) return (-1); + if (func1==audio_resume) return (-1); + if (func1!=ioctl_i) return (0); + if (func2==tell_SubQ_run_tot) return (-1); + if (func2==tell_cdsize) return (-1); + if (func2==tell_TocDescrip) return (-1); + if (func2==tell_TocEntry) return (-1); + if (func2==tell_subQ_info) return (-1); + if (new_drive) if (func2==tell_SubChanInfo) return (-1); + if (func2==tell_UPC) return (-1); +#else + return (0); +#endif 000 +} +/*==========================================================================*/ +static int check_allowed2(u_char func1, u_char func2) +{ +#if 000 + if (func1==read_long) return (-1); + if (func1==read_long_prefetch) return (-1); + if (func1==seek) return (-1); + if (func1==audio_play) return (-1); + if (func1!=ioctl_o) return (0); + if (new_drive) + { + if (func2==EjectDisk) return (-1); + if (func2==CloseTray) return (-1); + } +#else + return (0); +#endif 000 +} +/*==========================================================================*/ +static int check_allowed3(u_char func1, u_char func2) +{ +#if 000 + if (func1==ioctl_i) + { + if (func2==tell_address) return (0); + if (func2==tell_capabiliti) return (0); + if (func2==tell_CD_changed) return (0); + if (!new_drive) if (func2==tell_SubChanInfo) return (0); + return (-1); + } + if (func1==ioctl_o) + { + if (func2==DriveReset) return (0); + if (!new_drive) + { + if (func2==EjectDisk) return (0); + if (func2==LockDoor) return (0); + if (func2==CloseTray) return (0); + } + return (-1); + } + if (func1==flush_input) return (-1); + if (func1==read_long) return (-1); + if (func1==read_long_prefetch) return (-1); + if (func1==seek) return (-1); + if (func1==audio_play) return (-1); + if (func1==audio_pause) return (-1); + if (func1==audio_resume) return (-1); +#else + return (0); +#endif 000 +} +/*==========================================================================*/ +static int seek_pos_audio_end(void) +{ + int i; + + i=msf2blk(DS[d].pos_audio_end)-1; + if (i<0) return (-1); + i=xx_Seek(i,0); + return (i); +} +/*==========================================================================*/ +static int ReadToC(void) +{ + int i, j; + DS[d].diskstate_flags &= ~toc_bit; + DS[d].ored_ctl_adr=0; + for (j=DS[d].n_first_track;j<=DS[d].n_last_track;j++) + { + i=xx_ReadTocEntry(j); + if (i<0) return (i); + DS[d].TocBuffer[j].nixbyte=DS[d].TocEnt_nixbyte; + DS[d].TocBuffer[j].ctl_adr=DS[d].TocEnt_ctl_adr; + DS[d].TocBuffer[j].number=DS[d].TocEnt_number; + DS[d].TocBuffer[j].format=DS[d].TocEnt_format; + DS[d].TocBuffer[j].address=DS[d].TocEnt_address; + DS[d].ored_ctl_adr |= DS[d].TocEnt_ctl_adr; + } +/* fake entry for LeadOut Track */ + DS[d].TocBuffer[j].nixbyte=0; + DS[d].TocBuffer[j].ctl_adr=0; + DS[d].TocBuffer[j].number=0; + DS[d].TocBuffer[j].format=0; + DS[d].TocBuffer[j].address=DS[d].size_msf; + + DS[d].diskstate_flags |= toc_bit; + return (0); +} +/*==========================================================================*/ +static int DiskInfo(void) +{ + int i; + + i=SetSpeed(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: first SetSpeed returns %d\n", i)); + i=SetSpeed(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: second SetSpeed returns %d\n", i)); + return (i); + } + } + i=xx_ModeSense(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: first xx_ModeSense returns %d\n", i)); + i=xx_ModeSense(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: second xx_ModeSense returns %d\n", i)); + return (i); + } + return (i); + } + i=xx_ReadCapacity(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: first ReadCapacity returns %d\n", i)); + i=xx_ReadCapacity(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: second ReadCapacity returns %d\n", i)); + return (i); + } + return (i); + } + i=xx_ReadTocDescr(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadTocDescr returns %d\n", i)); + return (i); + } + i=ReadToC(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: ReadToC returns %d\n", i)); + return (i); + } + i=yy_CheckMultiSession(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: yy_CheckMultiSession returns %d\n", i)); + return (i); + } + i=xx_ReadTocEntry(DS[d].n_first_track); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadTocEntry(1) returns %d\n", i)); + return (i); + } + i=xx_ReadUPC(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: DiskInfo: xx_ReadUPC returns %d\n", i)); + return (i); + } + return (0); +} +/*==========================================================================*/ +/* + * called always if driver gets entered + * returns 0 or ERROR2 or ERROR15 + */ +static int prepare(u_char func, u_char subfunc) +{ + int i; + + if (!new_drive) + { + i=inb(CDi_status); + if (i&s_attention) GetStatus(); + } + else GetStatus(); + if (DS[d].CD_changed==0xFF) + { +#if MANY_SESSION +#else + DS[d].diskstate_flags=0; +#endif MANY_SESSION + DS[d].audio_state=0; + if (!st_diskok) + { + i=check_allowed1(func,subfunc); + if (i<0) return (-2); + } + else + { + i=check_allowed3(func,subfunc); + if (i<0) + { + DS[d].CD_changed=1; + return (-15); + } + } + } + else + { + if (!st_diskok) + { +#if MANY_SESSION +#else + DS[d].diskstate_flags=0; +#endif MANY_SESSION + DS[d].audio_state=0; + i=check_allowed1(func,subfunc); + if (i<0) return (-2); + } + else + { + if (st_busy) + { + if (DS[d].audio_state!=audio_pausing) + { + i=check_allowed2(func,subfunc); + if (i<0) return (-2); + } + } + else + { + if (DS[d].audio_state==audio_playing) seek_pos_audio_end(); + DS[d].audio_state=0; + } + if (!frame_size_valid) + { + i=DiskInfo(); + if (i<0) + { +#if MANY_SESSION +#else + DS[d].diskstate_flags=0; +#endif MANY_SESSION + DS[d].audio_state=0; + i=check_allowed1(func,subfunc); + if (i<0) return (-2); + } + } + } + } + return (0); +} +/*==========================================================================*/ +static int xx_PlayAudioMSF(int pos_audio_start,int pos_audio_end) +{ + int i; + + if (DS[d].audio_state==audio_playing) return (-EINVAL); + clr_cmdbuf(); + if (new_drive) + { + drvcmd[0]=0x0E; + flags_cmd_out = f_putcmd | f_respo2 | f_ResponseStatus | + f_obey_p_check | f_wait_if_busy; + } + else + { + drvcmd[0]=0x0B; + flags_cmd_out = f_putcmd | f_respo2 | f_lopsta | f_getsta | + f_ResponseStatus | f_obey_p_check | f_wait_if_busy; + } + drvcmd[1]=(pos_audio_start>>16)&0x00FF; + drvcmd[2]=(pos_audio_start>>8)&0x00FF; + drvcmd[3]=pos_audio_start&0x00FF; + drvcmd[4]=(pos_audio_end>>16)&0x00FF; + drvcmd[5]=(pos_audio_end>>8)&0x00FF; + drvcmd[6]=pos_audio_end&0x00FF; + response_count=0; + i=cmd_out(); + return (i); +} +/*==========================================================================*/ +/*==========================================================================*/ + +/*==========================================================================*/ +/*==========================================================================*/ +/* + * ioctl support, adopted from scsi/sr_ioctl.c and mcd.c + */ +static int sbpcd_ioctl(struct inode *inode,struct file *file, + u_int cmd, u_long arg) +{ + int i, st; + + DPRINTF((DBG_IOC,"SBPCD: ioctl(%d, 0x%08lX, 0x%08lX)\n", + MINOR(inode->i_rdev), cmd, arg)); + if (!inode) return (-EINVAL); + st=GetStatus(); + if (st<0) return (-EIO); + + if (!toc_valid) + { + i=DiskInfo(); + if (i<0) return (-EIO); /* error reading TOC */ + } + + i=MINOR(inode->i_rdev); + if ( (i<0) || (i>=NR_SBPCD) ) + { + DPRINTF((DBG_INF,"SBPCD: ioctl: bad device: %d\n", i)); + return (-ENODEV); /* no such drive */ + } + switch_drive(i); + + + DPRINTF((DBG_IOC,"SBPCD: ioctl: device %d, request %04X\n",i,cmd)); + switch (cmd) /* Sun-compatible */ + { + case DDIOCSDBG: /* DDI Debug */ + if (! suser()) return (-EPERM); + i = verify_area(VERIFY_READ, (int *) arg, sizeof(int)); + if (i>=0) i=sbpcd_dbg_ioctl(arg,1); + return (i); + + case CDROMPAUSE: /* Pause the drive */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPAUSE entered.\n")); + /* pause the drive unit when it is currently in PLAY mode, */ + /* or reset the starting and ending locations when in PAUSED mode. */ + /* If applicable, at the next stopping point it reaches */ + /* the drive will discontinue playing. */ + switch (DS[d].audio_state) + { + case audio_playing: + i=xx_Pause_Resume(1); + if (i<0) return (-EIO); + DS[d].audio_state=audio_pausing; + i=xx_ReadSubQ(); + if (i<0) return (-EIO); + DS[d].pos_audio_start=DS[d].SubQ_run_tot; + return (0); + case audio_pausing: + i=xx_Seek(DS[d].pos_audio_start,1); + if (i<0) return (-EIO); + return (0); + default: + return (-EINVAL); + } + + case CDROMRESUME: /* resume paused audio play */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMRESUME entered.\n")); + /* resume playing audio tracks when a previous PLAY AUDIO call has */ + /* been paused with a PAUSE command. */ + /* It will resume playing from the location saved in SubQ_run_tot. */ + if (DS[d].audio_state!=audio_pausing) return -EINVAL; + i=xx_Pause_Resume(3); + if (i<0) return (-EIO); + DS[d].audio_state=audio_playing; + return (0); + + case CDROMPLAYMSF: + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYMSF entered.\n")); + if (DS[d].audio_state==audio_playing) + { + i=xx_Pause_Resume(1); + if (i<0) return (-EIO); + i=xx_ReadSubQ(); + if (i<0) return (-EIO); + DS[d].pos_audio_start=DS[d].SubQ_run_tot; + i=xx_Seek(DS[d].pos_audio_start,1); + } + st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_msf)); + if (st) return (st); + memcpy_fromfs(&msf, (void *) arg, sizeof(struct cdrom_msf)); + /* values come as msf-bin */ + DS[d].pos_audio_start = (msf.cdmsf_min0<<16) | + (msf.cdmsf_sec0<<8) | + msf.cdmsf_frame0; + DS[d].pos_audio_end = (msf.cdmsf_min1<<16) | + (msf.cdmsf_sec1<<8) | + msf.cdmsf_frame1; + DPRINTF((DBG_IOX,"SBPCD: ioctl: CDROMPLAYMSF %08X %08X\n", + DS[d].pos_audio_start,DS[d].pos_audio_end)); + i=xx_PlayAudioMSF(DS[d].pos_audio_start,DS[d].pos_audio_end); + DPRINTF((DBG_IOC,"SBPCD: ioctl: xx_PlayAudioMSF returns %d\n",i)); +#if 0 + if (i<0) return (-EIO); +#endif 0 + DS[d].audio_state=audio_playing; + return (0); + + case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMPLAYTRKIND entered.\n")); + if (DS[d].audio_state==audio_playing) + { + DPRINTF((DBG_IOX,"SBPCD: CDROMPLAYTRKIND: already audio_playing.\n")); + return (0); + return (-EINVAL); + } + st=verify_area(VERIFY_READ,(void *) arg,sizeof(struct cdrom_ti)); + if (st<0) + { + DPRINTF((DBG_IOX,"SBPCD: CDROMPLAYTRKIND: verify_area error.\n")); + return (st); + } + memcpy_fromfs(&ti,(void *) arg,sizeof(struct cdrom_ti)); + DPRINTF((DBG_IOX,"SBPCD: ioctl: trk0: %d, ind0: %d, trk1:%d, ind1:%d\n", + ti.cdti_trk0,ti.cdti_ind0,ti.cdti_trk1,ti.cdti_ind1)); + if (ti.cdti_trk0DS[d].n_last_track) return (-EINVAL); + if (ti.cdti_trk1DS[d].n_last_track) ti.cdti_trk1=DS[d].n_last_track; + DS[d].pos_audio_start=DS[d].TocBuffer[ti.cdti_trk0].address; + DS[d].pos_audio_end=DS[d].TocBuffer[ti.cdti_trk1+1].address; + i=xx_PlayAudioMSF(DS[d].pos_audio_start,DS[d].pos_audio_end); +#if 0 + if (i<0) return (-EIO); +#endif 0 + DS[d].audio_state=audio_playing; + return (0); + + case CDROMREADTOCHDR: /* Read the table of contents header */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADTOCHDR entered.\n")); + tochdr.cdth_trk0=DS[d].n_first_track; + tochdr.cdth_trk1=DS[d].n_last_track; + st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_tochdr)); + if (st) return (st); + memcpy_tofs((void *) arg, &tochdr, sizeof(struct cdrom_tochdr)); + return (0); + + case CDROMREADTOCENTRY: /* Read an entry in the table of contents */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADTOCENTRY entered.\n")); + st=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_tocentry)); + if (st) return (st); + memcpy_fromfs(&tocentry, (void *) arg, sizeof(struct cdrom_tocentry)); + i=tocentry.cdte_track; + if (i==CDROM_LEADOUT) i=DS[d].n_last_track+1; + else if (iDS[d].n_last_track) return (-EINVAL); + tocentry.cdte_adr=DS[d].TocBuffer[i].ctl_adr&0x0F; + tocentry.cdte_ctrl=(DS[d].TocBuffer[i].ctl_adr>>4)&0x0F; + tocentry.cdte_datamode=DS[d].TocBuffer[i].format; + if (tocentry.cdte_format==CDROM_MSF) /* MSF-bin required */ + { tocentry.cdte_addr.msf.minute=(DS[d].TocBuffer[i].address>>16)&0x00FF; + tocentry.cdte_addr.msf.second=(DS[d].TocBuffer[i].address>>8)&0x00FF; + tocentry.cdte_addr.msf.frame=DS[d].TocBuffer[i].address&0x00FF; + } + else if (tocentry.cdte_format==CDROM_LBA) /* blk required */ + tocentry.cdte_addr.lba=msf2blk(DS[d].TocBuffer[i].address); + else return (-EINVAL); + st=verify_area(VERIFY_WRITE,(void *) arg, sizeof(struct cdrom_tocentry)); + if (st) return (st); + memcpy_tofs((void *) arg, &tocentry, sizeof(struct cdrom_tocentry)); + return (0); + + case CDROMSTOP: /* Spin down the drive */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTOP entered.\n")); + i=DriveReset(); +#if WORKMAN + DS[d].CD_changed=0xFF; + DS[d].diskstate_flags=0; +#endif WORKMAN + DPRINTF((DBG_IOC,"SBPCD: ioctl: DriveReset returns %d\n",i)); + DS[d].audio_state=0; + i=DiskInfo(); + return (0); + + case CDROMSTART: /* Spin up the drive */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSTART entered.\n")); + i=xx_SpinUp(); + DS[d].audio_state=0; + return (0); + + case CDROMEJECT: + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMEJECT entered.\n")); + if (!new_drive) return (0); +#if WORKMAN + DS[d].CD_changed=0xFF; + DS[d].diskstate_flags=0; +#endif WORKMAN + i=yy_SpinDown(); + if (i<0) return (-EIO); + DS[d].audio_state=0; + return (0); + + case CDROMVOLCTRL: /* Volume control */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMVOLCTRL entered.\n")); + st=verify_area(VERIFY_READ,(void *) arg,sizeof(volctrl)); + if (st) return (st); + memcpy_fromfs(&volctrl,(char *) arg,sizeof(volctrl)); + DS[d].vol_chan0=0; + DS[d].vol_ctrl0=volctrl.channel0; + DS[d].vol_chan1=1; + DS[d].vol_ctrl1=volctrl.channel1; + i=xx_SetVolume(); + return (0); + + case CDROMSUBCHNL: /* Get subchannel info */ + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMSUBCHNL entered.\n")); + if ((st_spinning)||(!subq_valid)) { i=xx_ReadSubQ(); + if (i<0) return (-EIO); + } + st=verify_area(VERIFY_WRITE, (void *) arg, sizeof(struct cdrom_subchnl)); + if (st) return (st); + memcpy_fromfs(&SC, (void *) arg, sizeof(struct cdrom_subchnl)); +#if 0 + if (DS[d].SubQ_audio==0x80) DS[d].SubQ_audio=CDROM_AUDIO_NO_STATUS; +#endif + switch (DS[d].audio_state) + { + case audio_playing: + SC.cdsc_audiostatus=CDROM_AUDIO_PLAY; + break; + case audio_pausing: + SC.cdsc_audiostatus=CDROM_AUDIO_PAUSED; + break; + default: + SC.cdsc_audiostatus=CDROM_AUDIO_NO_STATUS; + break; + } + SC.cdsc_adr=DS[d].SubQ_ctl_adr; + SC.cdsc_ctrl=DS[d].SubQ_ctl_adr>>4; + SC.cdsc_trk=bcd2bin(DS[d].SubQ_trk); + SC.cdsc_ind=bcd2bin(DS[d].SubQ_pnt_idx); + if (SC.cdsc_format==CDROM_LBA) + { + SC.cdsc_absaddr.lba=msf2blk(DS[d].SubQ_run_tot); + SC.cdsc_reladdr.lba=msf2blk(DS[d].SubQ_run_trk); + } + else /* not only if (SC.cdsc_format==CDROM_MSF) */ + { + SC.cdsc_absaddr.msf.minute=(DS[d].SubQ_run_tot>>16)&0x00FF; + SC.cdsc_absaddr.msf.second=(DS[d].SubQ_run_tot>>8)&0x00FF; + SC.cdsc_absaddr.msf.frame=DS[d].SubQ_run_tot&0x00FF; + SC.cdsc_reladdr.msf.minute=(DS[d].SubQ_run_trk>>16)&0x00FF; + SC.cdsc_reladdr.msf.second=(DS[d].SubQ_run_trk>>8)&0x00FF; + SC.cdsc_reladdr.msf.frame=DS[d].SubQ_run_trk&0x00FF; + } + memcpy_tofs((void *) arg, &SC, sizeof(struct cdrom_subchnl)); + DPRINTF((DBG_IOC,"SBPCD: CDROMSUBCHNL: %1X %02X %08X %08X %02X %02X %06X %06X\n", + SC.cdsc_format,SC.cdsc_audiostatus, + SC.cdsc_adr,SC.cdsc_ctrl, + SC.cdsc_trk,SC.cdsc_ind, + SC.cdsc_absaddr,SC.cdsc_reladdr)); + return (0); + + case CDROMREADMODE2: + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE2 requested.\n")); + return (-EINVAL); + + case CDROMREADMODE1: + DPRINTF((DBG_IOC,"SBPCD: ioctl: CDROMREADMODE1 requested.\n")); + return (-EINVAL); + + default: + DPRINTF((DBG_IOX,"SBPCD: ioctl: unknown function request %04X\n", cmd)); + return (-EINVAL); + } /* end switch(cmd) */ +} +/*==========================================================================*/ +/* + * Take care of the different block sizes between cdrom and Linux. + * When Linux gets variable block sizes this will probably go away. + */ +static void sbp_transfer(void) +{ + long offs; + + while ( (CURRENT->nr_sectors > 0) && + (CURRENT->sector/4 >= DS[d].sbp_first_frame) && + (CURRENT->sector/4 <= DS[d].sbp_last_frame) ) + { + offs = (CURRENT->sector - DS[d].sbp_first_frame * 4) * 512; + memcpy(CURRENT->buffer, DS[d].sbp_buf + offs, 512); + CURRENT->nr_sectors--; + CURRENT->sector++; + CURRENT->buffer += 512; + } +} +/*==========================================================================*/ +/* + * We seem to get never an interrupt. + */ +#if SBPCD_USE_IRQ +static void sbpcd_interrupt(int unused) +{ + int st; + + st = inb(CDi_status) & 0xFF; + DPRINTF((DBG_IRQ,"SBPCD: INTERRUPT received - CDi_status=%02X\n", st)); +} +#endif SBPCD_USE_IRQ +/*==========================================================================*/ +/* + * Called from the timer to check the results of the get-status cmd. + */ +static int sbp_status(void) +{ + int st; + + st=ResponseStatus(); + if (st<0) + { + DPRINTF((DBG_INF,"SBPCD: sbp_status: timeout.\n")); + return (0); + } + + if (!st_spinning) DPRINTF((DBG_SPI,"SBPCD: motor got off - ignoring.\n")); + + if (st_check) + { + DPRINTF((DBG_INF,"SBPCD: st_check detected - retrying.\n")); + return (0); + } + if (!st_door_closed) + { + DPRINTF((DBG_INF,"SBPCD: door is open - retrying.\n")); + return (0); + } + if (!st_caddy_in) + { + DPRINTF((DBG_INF,"SBPCD: disk removed - retrying.\n")); + return (0); + } + if (!st_diskok) + { + DPRINTF((DBG_INF,"SBPCD: !st_diskok detected - retrying.\n")); + return (0); + } + if (st_busy) + { + DPRINTF((DBG_INF,"SBPCD: st_busy detected - retrying.\n")); + return (0); + } + return (1); +} +/*==========================================================================*/ +/* + * I/O request routine, called from Linux kernel. + */ +static void do_sbpcd_request(void) +{ + u_int block; + int dev; + u_int nsect; + int i, status_tries, data_tries; + +request_loop: + + sti(); + + if ((CURRENT==NULL)||(CURRENT->dev<0)) return; + if (CURRENT -> sector == -1) return; + + dev = MINOR(CURRENT->dev); + if ( (dev<0) || (dev>=NR_SBPCD) ) + { + DPRINTF((DBG_INF,"SBPCD: do_request: bad device: %d\n", dev)); + return; + } + switch_drive(dev); + + INIT_REQUEST; + block = CURRENT->sector; + nsect = CURRENT->nr_sectors; + + if (CURRENT->cmd != READ) + { + DPRINTF((DBG_INF,"SBPCD: bad cmd %d\n", CURRENT->cmd)); + end_request(0); + goto request_loop; + } + + DPRINTF((DBG_MUL,"SBPCD: read LBA %d\n", block/4)); + sbp_transfer(); + + /* if we satisfied the request from the buffer, we're done. */ + + if (CURRENT->nr_sectors == 0) + { + end_request(1); + goto request_loop; + } + + i=prepare(0,0); /* at moment not really a hassle check, but ... */ + if (i!=0) DPRINTF((DBG_INF,"SBPCD: \"prepare\" tells error %d -- ignored\n", i)); + + if (!st_spinning) xx_SpinUp(); + + for (data_tries=3; data_tries > 0; data_tries--) + { + for (status_tries=3; status_tries > 0; status_tries--) + { + flags_cmd_out |= f_respo3; + xx_ReadStatus(); + if (sbp_status() != 0) break; + sbp_sleep(1); /* wait a bit, try again */ + } + if (status_tries == 0) + { + DPRINTF((DBG_INF,"SBPCD: sbp_status: failed after 3 tries\n")); + break; + } + + sbp_read_cmd(); + sbp_sleep(0); + if (sbp_data() != 0) + { + end_request(1); + goto request_loop; + } + } + + end_request(0); + sbp_sleep(10); /* wait a bit, try again */ + goto request_loop; +} +/*==========================================================================*/ +/* + * build and send the READ command. + * Maybe it would be better to "set mode1" before ... + */ +static void sbp_read_cmd(void) +{ + int i; + int block; + + DS[d].sbp_first_frame=DS[d].sbp_last_frame=-1; /* purge buffer */ + block=CURRENT->sector/4; + + if (new_drive) + { +#if MANY_SESSION + DPRINTF((DBG_MUL,"SBPCD: read MSF %08X\n", blk2msf(block))); + if ( (DS[d].f_multisession) && (multisession_valid) ) + { + DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n", + blk2msf(DS[d].lba_multi+block), + blk2msf(block))); + block=DS[d].lba_multi+block; + } +#else + if ( (block==166) && (DS[d].f_multisession) && (multisession_valid) ) + { + DPRINTF((DBG_MUL,"SBPCD: MultiSession: use %08X for %08X (msf)\n", + blk2msf(DS[d].lba_multi+16), + blk2msf(block))); + block=DS[d].lba_multi+16; + } +#endif MANY_SESSION + } + + if (block+SBP_BUFFER_FRAMES <= DS[d].CDsize_frm) + DS[d].sbp_read_frames = SBP_BUFFER_FRAMES; + else + { + DS[d].sbp_read_frames=DS[d].CDsize_frm-block; + /* avoid reading past end of data */ + if (DS[d].sbp_read_frames < 1) + { + DPRINTF((DBG_INF,"SBPCD: requested frame %d, CD size %d ???\n", + block, DS[d].CDsize_frm)); + DS[d].sbp_read_frames=1; + } + } + DS[d].sbp_current = 0; + + flags_cmd_out = f_putcmd | + f_respo2 | + f_ResponseStatus | + f_obey_p_check; + + if (!new_drive) + { + if (DS[d].drv_type>=drv_201) + { + lba2msf(block,&drvcmd[1]); /* msf-bcd format required */ + bin2bcdx(&drvcmd[1]); + bin2bcdx(&drvcmd[2]); + bin2bcdx(&drvcmd[3]); + } + else + { + drvcmd[1]=(block>>16)&0x000000ff; + drvcmd[2]=(block>>8)&0x000000ff; + drvcmd[3]=block&0x000000ff; + } + drvcmd[4]=0; + drvcmd[5]=DS[d].sbp_read_frames; + drvcmd[6]=(DS[d].drv_type= 1000) + { + DPRINTF((DBG_INF,"SBPCD: info: %d waits in %d frames.\n", + data_waits, data_tries)); + data_waits = data_tries = 0; + } + } +#if SBPCD_DIS_IRQ + sti(); +#endif SBPCD_DIS_IRQ + + if (error_flag) /* must have been spurious D_RDY or (ATTN&&!D_RDY) */ + { + DPRINTF((DBG_INF,"SBPCD: read aborted by drive\n")); + i=DriveReset(); /* ugly fix to prevent a hang */ + return (0); + } + + if (!new_drive) + { +#if SBPCD_DIS_IRQ + cli(); +#endif SBPCD_DIS_IRQ + i=maxtim_data; + for (timeout=jiffies+100; timeout > jiffies; timeout--) + { + for ( ;i!=0;i--) + { + j=inb(CDi_status); + if (!(j&s_not_data_ready)) break; + if (!(j&s_not_result_ready)) break; + if (j&s_attention) break; + } + if (i != 0 || timeout <= jiffies) break; + sbp_sleep(0); + i = 1; + } + if (i==0) { DPRINTF((DBG_INF,"SBPCD: STATUS TIMEOUT AFTER READ")); } + if (!(j&s_attention)) + { + DPRINTF((DBG_INF,"SBPCD: sbp_data: timeout waiting DRV_ATTN - retrying\n")); + i=DriveReset(); /* ugly fix to prevent a hang */ +#if SBPCD_DIS_IRQ + sti(); +#endif SBPCD_DIS_IRQ + return (0); + } +#if SBPCD_DIS_IRQ + sti(); +#endif SBPCD_DIS_IRQ + } + + do + { + if (!new_drive) xx_ReadStatus(); + i=ResponseStatus(); /* builds status_byte, returns orig. status (old) or faked p_success_old (new) */ + if (i<0) { DPRINTF((DBG_INF,"SBPCD: xx_ReadStatus error after read: %02X\n", + DS[d].status_byte)); + return (0); + } + } + while ((!new_drive)&&(!st_check)&&(!(i&p_success_old))); + if (st_check) + { + i=xx_ReadError(); + DPRINTF((DBG_INF,"SBPCD: xx_ReadError was necessary after read: %02X\n",i)); + return (0); + } + + DS[d].sbp_first_frame = CURRENT -> sector / 4; + DS[d].sbp_last_frame = DS[d].sbp_first_frame + DS[d].sbp_read_frames - 1; + sbp_transfer(); + return (1); +} +/*==========================================================================*/ +/*==========================================================================*/ +/* + * Open the device special file. Check that a disk is in. Read TOC. + */ +int sbpcd_open(struct inode *ip, struct file *fp) +{ + int i; + + if (ndrives==0) return (-ENXIO); /* no hardware */ + + i = MINOR(ip->i_rdev); + if ( (i<0) || (i>=NR_SBPCD) ) + { + DPRINTF((DBG_INF,"SBPCD: open: bad device: %d\n", i)); + return (-ENODEV); /* no such drive */ + } + switch_drive(i); + + if (!st_spinning) xx_SpinUp(); + + flags_cmd_out |= f_respo2; + xx_ReadStatus(); /* command: give 1-byte status */ + i=ResponseStatus(); + if (i<0) + { + DPRINTF((DBG_INF,"SBPCD: sbpcd_open: xx_ReadStatus timed out\n")); + return (-EIO); /* drive doesn't respond */ + } + DPRINTF((DBG_STA,"SBPCD: sbpcd_open: status %02X\n", DS[d].status_byte)); + if (!st_door_closed||!st_caddy_in) + { + DPRINTF((DBG_INF,"SBPCD: sbpcd_open: no disk in drive\n")); + return (-EIO); + } + +/* + * we could try to keep an "open" counter here and lock the door if 0->1. + * not done yet. + */ + + + if (!st_spinning) xx_SpinUp(); + + i=DiskInfo(); + if ((DS[d].ored_ctl_adr&0x40)==0) + DPRINTF((DBG_INF,"SBPCD: CD contains no data tracks.\n")); + return (0); +} +/*==========================================================================*/ +/* + * On close, we flush all sbp blocks from the buffer cache. + */ +static void sbpcd_release(struct inode * ip, struct file * file) +{ + int i; +/* + * we could try to count down an "open" counter here + * and unlock the door if zero. + * not done yet. + */ + + i = MINOR(ip->i_rdev); + if ( (i<0) || (i>=NR_SBPCD) ) + { + DPRINTF((DBG_INF,"SBPCD: release: bad device: %d\n", i)); + return; + } + switch_drive(i); + + DS[d].sbp_first_frame=DS[d].sbp_last_frame=-1; + sync_dev(ip->i_rdev); /* nonsense if read only device? */ + invalidate_buffers(ip->i_rdev); + DS[d].diskstate_flags &= ~cd_size_bit; +} +/*==========================================================================*/ +/* + * + */ +static struct file_operations sbpcd_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + sbpcd_ioctl, /* ioctl */ + NULL, /* mmap */ + sbpcd_open, /* open */ + sbpcd_release /* release */ +}; +/*==========================================================================*/ +/* + * SBP interrupt descriptor + */ +#if SBPCD_USE_IRQ +static struct sigaction sbpcd_sigaction = +{ + sbpcd_interrupt, + 0, + SA_INTERRUPT, + NULL +}; +#endif SBPCD_USE_IRQ +/*==========================================================================*/ +/* + * accept "kernel command line" parameters + * (suggested by Peter MacDonald with SLS 1.03) + * + * use: tell LILO: + * sbpcd=0x230,SoundBlaster + * or + * sbpcd=0x300,LaserMate + * + * (upper/lower case sensitive here!!!). + * + * the address value has to be the TRUE CDROM PORT ADDRESS - + * not the soundcard base address. + * + */ +void sbpcd_setup(char *s, int *p) +{ + DPRINTF((DBG_INI,"SBPCD: sbpcd_setup called with %04X,%s\n",p[1], s)); + if (!strcmp(s,str_sb)) sbpro_type=1; + else sbpro_type=0; + if (p[0]>0) sbpcd_ioaddr=p[1]; + + CDo_command=sbpcd_ioaddr; + CDi_info=sbpcd_ioaddr; + CDi_status=sbpcd_ioaddr+1; + CDo_reset=sbpcd_ioaddr+2; + CDo_enable=sbpcd_ioaddr+3; + if (sbpro_type==1) + { + MIXER_addr=sbpcd_ioaddr-0x10+0x04; + MIXER_data=sbpcd_ioaddr-0x10+0x05; + CDo_sel_d_i=sbpcd_ioaddr+1; + CDi_data=sbpcd_ioaddr; + } + else CDi_data=sbpcd_ioaddr+2; +} +/*==========================================================================*/ +/* + * Test for presence of drive and initialize it. Called at boot time. + */ +u_long sbpcd_init(u_long mem_start, u_long mem_end) +{ + int i=0, j=0; + int addr[2]={1, CDROM_PORT}; + int port_index; + + DPRINTF((DBG_INF,"SBPCD version %s\n", VERSION)); + + DPRINTF((DBG_INF,"SBPCD: Looking for a SoundBlaster/Matsushita CD-ROM drive\n")); + DPRINTF((DBG_WRN,"SBPCD: \n")); + DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = W A R N I N G = = = = = = = = = =\n")); + DPRINTF((DBG_WRN,"SBPCD: Auto-Probing can cause a hang (f.e. touching an ethernet card).\n")); + DPRINTF((DBG_WRN,"SBPCD: If that happens, you have to reboot and use the\n")); + DPRINTF((DBG_WRN,"SBPCD: LILO (kernel) command line feature like:\n")); + DPRINTF((DBG_WRN,"SBPCD: \n")); + DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x230,SoundBlaster\n")); + DPRINTF((DBG_WRN,"SBPCD: or like:\n")); + DPRINTF((DBG_WRN,"SBPCD: LILO boot: linux sbpcd=0x300,LaserMate\n")); + DPRINTF((DBG_WRN,"SBPCD: \n")); + DPRINTF((DBG_WRN,"SBPCD: with your REAL address.\n")); + DPRINTF((DBG_WRN,"SBPCD: = = = = = = = = = = END of WARNING = = = = = = = = = =\n")); + DPRINTF((DBG_WRN,"SBPCD: \n")); + sti(); /* to avoid possible "printk" bug */ + + autoprobe[0]=sbpcd_ioaddr; /* possibly changed by kernel command line */ + autoprobe[1]=sbpro_type; /* possibly changed by kernel command line */ + + for (port_index=0;port_index=0) break; /* drive found */ + printk ("\n"); + sti(); /* to avoid possible "printk" bug */ + } /* end of cycling through the set of possible I/O port addresses */ + + if (ndrives==0) + { + DPRINTF((DBG_INF,"SBPCD: No drive found.\n")); + sti(); + return (mem_start); + } + + DPRINTF((DBG_INF,"SBPCD: %d %s CD-ROM drive(s) at 0x%04X.\n", + ndrives, type, CDo_command)); + sti(); /* to avoid possible "printk" bug */ + check_datarate(); + DPRINTF((DBG_INI,"SBPCD: check_datarate done.\n")); + sti(); /* to avoid possible "printk" bug */ + + for (j=0;j=0) DS[d].CD_changed=1; + } + + if (sbpro_type) + { + OUT(MIXER_addr,MIXER_CD_Volume); + OUT(MIXER_data,0xCC); /* one nibble per channel */ + } + + if (register_blkdev(MATSUSHITA_CDROM_MAJOR, "sbpcd", &sbpcd_fops) != 0) + { + DPRINTF((DBG_INF,"SBPCD: Can't get MAJOR %d for Matsushita CDROM\n", + MATSUSHITA_CDROM_MAJOR)); + sti(); /* to avoid possible "printk" bug */ + return (mem_start); + } + blk_dev[MATSUSHITA_CDROM_MAJOR].request_fn = DEVICE_REQUEST; + read_ahead[MATSUSHITA_CDROM_MAJOR] = 4; /* just one frame */ + + snarf_region(CDo_command,4); + +#if SBPCD_USE_IRQ + if (irqaction(SBPCD_INTR_NR, &sbpcd_sigaction)) + { + DPRINTF((DBG_INF,"SBPCD: Can't get IRQ%d for sbpcd driver\n", + SBPCD_INTR_NR)); + sti(); /* to avoid possible "printk" bug */ + } +#endif SBPCD_USE_IRQ + +/* + * allocate memory for the frame buffers + */ + for (j=0;j +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#define MAJOR_NR XT_DISK_MAJOR +#include "blk.h" + +XD_INFO xd_info[XD_MAXDRIVES]; + +/* If you try this driver and find that your card is not detected by the driver at bootup, you need to add your BIOS + signature and details to the following list of signatures. A BIOS signature is a string embedded into the first + few bytes of your controller's on-board ROM BIOS. To find out what yours is, use something like MS-DOS's DEBUG + command. Run DEBUG, and then you can examine your BIOS signature with: + + d xxxx:0000 + + where xxxx is the segment of your controller (like C800 or D000 or something). On the ASCII dump at the right, you should + be able to see a string mentioning the manufacturer's copyright etc. Add this string into the table below. The parameters + in the table are, in order: + + offset ; this is the offset (in bytes) from the start of your ROM where the signature starts + signature ; this is the actual text of the signature + xd_?_init_controller ; this is the controller init routine used by your controller + xd_?_init_drive ; this is the drive init routine used by your controller + + 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 . + + 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",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 +}; + +static struct hd_struct xd[XD_MAXDRIVES << 6]; +static int xd_sizes[XD_MAXDRIVES << 6],xd_access[XD_MAXDRIVES] = { 0,0 }; +static int xd_blocksizes[XD_MAXDRIVES << 6]; +static struct gendisk xd_gendisk = { MAJOR_NR,"xd",6,1 << 6,XD_MAXDRIVES,xd_geninit,xd,xd_sizes,0,(void *) xd_info,NULL }; +static struct file_operations xd_fops = { NULL,block_read,block_write,NULL,NULL,xd_ioctl,NULL,xd_open,xd_release,block_fsync }; + +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 = 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) +{ + u_char i,controller,*address; + + if (register_blkdev(MAJOR_NR,"xd",&xd_fops)) { + printk("xd_init: unable to get major number %d\n",MAJOR_NR); + return (mem_start); + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + read_ahead[MAJOR_NR] = 8; /* 8 sector (4kB) read ahead */ + xd_gendisk.next = gendisk_head; + gendisk_head = &xd_gendisk; + + if (xd_detect(&controller,&address)) { + + printk("xd_init: detected a%s controller (type %d) at address %p\n",xd_sigs[controller].name,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); + for (i = 0; i < xd_drives; i++) + printk("xd_init: drive %d geometry - heads = %d, cylinders = %d, sectors = %d\n",i,xd_info[i].heads,xd_info[i].cylinders,xd_info[i].sectors); + + if (!request_irq(xd_irq,xd_interrupt_handler)) { + if (request_dma(xd_dma)) { + printk("xd_init: unable to get DMA%d\n",xd_dma); + free_irq(xd_irq); + } + } + else + printk("xd_init: unable to get IRQ%d\n",xd_irq); + } + return mem_start; +} + +/* xd_detect: scan the possible BIOS ROM locations for the signature strings */ +static u_char xd_detect (u_char *controller,u_char **address) +{ + 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))) { + *controller = j; + *address = xd_bases[i]; + found++; + } + return (found); +} + +/* xd_geninit: set up the "raw" device entries in the table */ +static void xd_geninit (void) +{ + u_char i; + + for (i = 0; i < xd_drives; i++) { + xd[i << 6].nr_sects = xd_info[i].heads * xd_info[i].cylinders * xd_info[i].sectors; + xd_valid[i] = 1; + } + + xd_gendisk.nr_real = xd_drives; + + for(i=0;i<(XD_MAXDRIVES << 6);i++) xd_blocksizes[i] = 1024; + blksize_size[MAJOR_NR] = xd_blocksizes; +} + +/* xd_open: open a device */ +static int xd_open (struct inode *inode,struct file *file) +{ + int dev = DEVICE_NR(MINOR(inode->i_rdev)); + + if (dev < xd_drives) { + while (!xd_valid[dev]) + sleep_on(&xd_wait_open); + + xd_access[dev]++; + + return (0); + } + else + return (-ENODEV); +} + +/* do_xd_request: handle an incoming request */ +static void do_xd_request (void) +{ + u_int block,count,retry; + int code; + + sti(); + while (code = 0, CURRENT) { + INIT_REQUEST; /* do some checking on the request structure */ + + if (CURRENT_DEV < xd_drives && CURRENT->sector + CURRENT->nr_sectors <= xd[MINOR(CURRENT->dev)].nr_sects) { + block = CURRENT->sector + xd[MINOR(CURRENT->dev)].start_sect; + count = CURRENT->nr_sectors; + + switch (CURRENT->cmd) { + case READ: + case WRITE: for (retry = 0; (retry < XD_RETRIES) && !code; retry++) + code = xd_readwrite(CURRENT->cmd,CURRENT_DEV,CURRENT->buffer,block,count); + break; + default: printk("do_xd_request: unknown request\n"); break; + } + } + end_request(code); /* wrap up, 0 = fail, 1 = success */ + } +} + +/* xd_ioctl: handle device ioctl's */ +static int xd_ioctl (struct inode *inode,struct file *file,u_int cmd,u_long arg) +{ + XD_GEOMETRY *geometry = (XD_GEOMETRY *) arg; + int dev = DEVICE_NR(MINOR(inode->i_rdev)),err; + + if (inode && (dev < xd_drives)) + switch (cmd) { + case HDIO_GETGEO: if (arg) { + if ((err = verify_area(VERIFY_WRITE,geometry,sizeof(*geometry)))) + return (err); + put_fs_byte(xd_info[dev].heads,(char *) &geometry->heads); + put_fs_byte(xd_info[dev].sectors,(char *) &geometry->sectors); + put_fs_word(xd_info[dev].cylinders,(short *) &geometry->cylinders); + put_fs_long(xd[MINOR(inode->i_rdev)].start_sect,(long *) &geometry->start); + + return (0); + } + break; + case BLKGETSIZE: if (arg) { + if ((err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long)))) + return (err); + put_fs_long(xd[MINOR(inode->i_rdev)].nr_sects,(long *) arg); + + return (0); + } + break; + case BLKFLSBUF: + if(!suser()) return -EACCES; + if(!inode->i_rdev) return -EINVAL; + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + return 0; + + case BLKRRPART: return (xd_reread_partitions(inode->i_rdev)); + RO_IOCTLS(inode->i_rdev,arg); + } + return (-EINVAL); +} + +/* xd_release: release the device */ +static void xd_release (struct inode *inode, struct file *file) +{ + int dev = DEVICE_NR(MINOR(inode->i_rdev)); + + if (dev < xd_drives) { + sync_dev(dev); + xd_access[dev]--; + } +} + +/* xd_reread_partitions: rereads the partition table from a drive */ +static int xd_reread_partitions(int dev) +{ + int target = DEVICE_NR(MINOR(dev)),start = target << xd_gendisk.minor_shift,partition; + + cli(); xd_valid[target] = (xd_access[target] != 1); sti(); + if (xd_valid[target]) + return (-EBUSY); + + for (partition = xd_gendisk.max_p - 1; partition >= 0; partition--) { + sync_dev(MAJOR_NR << 8 | start | partition); + invalidate_inodes(MAJOR_NR << 8 | start | partition); + invalidate_buffers(MAJOR_NR << 8 | start | partition); + xd_gendisk.part[start + partition].start_sect = 0; + xd_gendisk.part[start + partition].nr_sects = 0; + }; + + xd_gendisk.part[start].nr_sects = xd_info[target].heads * xd_info[target].cylinders * xd_info[target].sectors; + resetup_one_dev(&xd_gendisk,target); + + xd_valid[target] = 1; + wake_up(&xd_wait_open); + + return (0); +} + +/* xd_readwrite: handle a read/write request */ +static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count) +{ + u_char cmdblk[6],sense[4]; + u_short track,cylinder; + u_char head,sector,control,mode,temp; + +#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 */ + + control = xd_info[drive].control; + while (count) { + temp = count < xd_maxsectors ? count : xd_maxsectors; + + track = block / xd_info[drive].sectors; + head = track % xd_info[drive].heads; + cylinder = track / xd_info[drive].heads; + sector = block % xd_info[drive].sectors; + +#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 */ + + 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); + + switch (xd_command(cmdblk,mode,(u_char *) buffer,(u_char *) buffer,sense,XD_TIMEOUT)) { + case 1: printk("xd_readwrite: timeout, recalibrating drive\n"); xd_recalibrate(drive); return (0); + case 2: switch ((sense[0] & 0x30) >> 4) { + case 0: printk("xd_readwrite: drive error, code = 0x%X",sense[0] & 0x0F); break; + case 1: printk("xd_readwrite: controller error, code = 0x%X",sense[0] & 0x0F); break; + case 2: printk("xd_readwrite: command error, code = 0x%X",sense[0] & 0x0F); break; + case 3: printk("xd_readwrite: miscellaneous error, code = 0x%X",sense[0] & 0x0F); break; + } + if (sense[0] & 0x80) + printk(" - drive = %d, head = %d, cylinder = %d, sector = %d\n",sense[1] & 0xE0,sense[1] & 0x1F,((sense[2] & 0xC0) << 2) | sense[3],sense[2] & 0x3F); + else + printk(" - no valid disk address\n"); + return (0); + } + count -= temp, buffer += temp * 0x200, block += temp; + } + return (1); +} + +/* xd_recalibrate: recalibrate a given drive and reset controller if necessary */ +static void xd_recalibrate (u_char drive) +{ + u_char cmdblk[6]; + + xd_build(cmdblk,CMD_RECALIBRATE,drive,0,0,0,0,0); + if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 8)) + printk("xd_recalibrate: warning! error recalibrating, controller may be unstable\n"); +} + +/* xd_interrupt_handler: interrupt service routine */ +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 */ + outb(0,XD_CONTROL); /* acknowledge interrupt */ + wake_up(&xd_wait_int); /* and wake up sleeping processes */ + } + else + printk("xd_interrupt_handler: unexpected interrupt\n"); +} + +/* xd_dma: set up the DMA controller for a data transfer */ +static u_char xd_setup_dma (u_char mode,u_char *buffer,u_int count) +{ + if (buffer < ((u_char *) 0x1000000 - count)) { /* transfer to address < 16M? */ + 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 */ + return (PIO_MODE); + } + disable_dma(xd_dma); + clear_dma_ff(xd_dma); + set_dma_mode(xd_dma,mode); + set_dma_addr(xd_dma,(u_int) buffer); + set_dma_count(xd_dma,count); + + return (DMA_MODE); /* use DMA and INT */ + } +#ifdef DEBUG_OTHER + printk("xd_setup_dma: using PIO, cannot DMA above 16 meg\n"); +#endif /* DEBUG_OTHER */ + return (PIO_MODE); +} + +/* xd_build: put stuff into an array in a format suitable for the controller */ +static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control) +{ + cmdblk[0] = command; + cmdblk[1] = ((drive & 0x07) << 5) | (head & 0x1F); + cmdblk[2] = ((cylinder & 0x300) >> 2) | (sector & 0x3F); + cmdblk[3] = cylinder & 0xFF; + cmdblk[4] = count; + cmdblk[5] = control; + + return (cmdblk); +} + +/* xd_waitport: waits until port & mask == flags or a timeout occurs. return 1 for a timeout */ +static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout) +{ + u_long expiry = jiffies + timeout; + + while (((inb(port) & mask) != flags) && (jiffies < expiry)) + ; + + return (jiffies >= expiry); +} + +/* xd_command: handle all data transfers necessary for a single command */ +static u_int xd_command (u_char *command,u_char mode,u_char *indata,u_char *outdata,u_char *sense,u_long timeout) +{ + u_char cmdblk[6],csb,complete = 0; + +#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 */ + + outb(0,XD_SELECT); + outb(mode,XD_CONTROL); + + if (xd_waitport(XD_STATUS,STAT_SELECT,STAT_SELECT,timeout)) + return (1); + + while (!complete) { + if (xd_waitport(XD_STATUS,STAT_READY,STAT_READY,timeout)) + return (1); + switch (inb(XD_STATUS) & (STAT_COMMAND | STAT_INPUT)) { + case 0: if (mode == DMA_MODE) { + enable_dma(xd_dma); + sleep_on(&xd_wait_int); + disable_dma(xd_dma); + } + else + outb(outdata ? *outdata++ : 0,XD_DATA); + break; + case STAT_INPUT: if (mode == DMA_MODE) { + enable_dma(xd_dma); + sleep_on(&xd_wait_int); + disable_dma(xd_dma); + } + else + if (indata) + *indata++ = inb(XD_DATA); + else + inb(XD_DATA); + break; + case STAT_COMMAND: outb(command ? *command++ : 0,XD_DATA); break; + case STAT_COMMAND + | STAT_INPUT: complete = 1; break; + } + } + csb = inb(XD_DATA); + + if (xd_waitport(XD_STATUS,0,STAT_SELECT,timeout)) /* wait until deselected */ + return (1); + + if (csb & CSB_ERROR) { /* read sense data if error */ + xd_build(cmdblk,CMD_SENSE,(csb & CSB_LUN) >> 5,0,0,0,0,0); + if (xd_command(cmdblk,0,sense,0,0,XD_TIMEOUT)) + printk("xd_command: warning! sense command failed!\n"); + } + +#ifdef DEBUG_COMMAND + printk("xd_command: completed with csb = 0x%X\n",csb); +#endif /* DEBUG_COMMAND */ + + return (csb & CSB_ERROR); +} + +static u_char xd_initdrives (void (*init_drive)(u_char drive)) +{ + u_char cmdblk[6],i,count = 0; + + for (i = 0; i < XD_MAXDRIVES; i++) { + xd_build(cmdblk,CMD_TESTREADY,i,0,0,0,0,0); + if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) { + init_drive(count); + count++; + } + } + return (count); +} + +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; + xd_maxsectors = 0x01; /* my card seems to have trouble doing multi-block transfers? */ + + outb(0,XD_RESET); /* reset the controller */ +} + +static void xd_dtc_init_drive (u_char drive) +{ + u_char cmdblk[6],buf[64]; + + xd_build(cmdblk,CMD_DTCGETGEOM,drive,0,0,0,0,0); + if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { + xd_info[drive].heads = buf[0x0A]; /* heads */ + xd_info[drive].cylinders = ((u_short *) (buf))[0x04]; /* cylinders */ + xd_info[drive].sectors = 17; /* sectors */ +#if 0 + 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 */ + 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_dtc_init_drive: error setting step rate for drive %d\n",drive); + } + else + printk("xd_dtc_init_drive: error reading geometry for drive %d\n",drive); +} + +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 */ +} + +static void xd_wd_init_drive (u_char drive) +{ + u_char cmdblk[6],buf[0x200]; + + xd_build(cmdblk,CMD_READ,drive,0,0,0,1,0); + if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { + xd_info[drive].heads = buf[0x1AF]; /* heads */ + xd_info[drive].cylinders = ((u_short *) (buf + 1))[0xD6]; /* cylinders */ + xd_info[drive].sectors = 17; /* sectors */ +#if 0 + 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 */ + 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_wd_init_drive: error reading geometry for drive %d\n",drive); +} + +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; + xd_maxsectors = 0x40; + + outb(0,XD_RESET); /* reset the controller */ +} + +static void xd_seagate_init_drive (u_char drive) +{ + u_char cmdblk[6],buf[0x200]; + + xd_build(cmdblk,CMD_ST11GETGEOM,drive,0,0,0,1,0); + if (!xd_command(cmdblk,PIO_MODE,buf,0,0,XD_TIMEOUT * 2)) { + xd_info[drive].heads = buf[0x04]; /* heads */ + xd_info[drive].cylinders = (buf[0x02] << 8) | buf[0x03]; /* cylinders */ + xd_info[drive].sectors = buf[0x05]; /* sectors */ + xd_info[drive].control = 0; /* control byte */ + } + else + 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 + etc. by trying values until it gets the highest successful value. Idea courtesy Salvador Abreu (spa@fct.unl.pt). */ +static void xd_override_init_drive (u_char drive) +{ + u_short min[] = { 0,0,0 },max[] = { 16,1024,64 },test[] = { 0,0,0 }; + u_char cmdblk[6],i; + + for (i = 0; i < 3; i++) { + while (min[i] != max[i] - 1) { + test[i] = (min[i] + max[i]) / 2; + xd_build(cmdblk,CMD_SEEK,drive,(u_char) test[0],(u_short) test[1],(u_char) test[2],0,0); + if (!xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) + min[i] = test[i]; + else + max[i] = test[i]; + } + test[i] = min[i]; + } + xd_info[drive].heads = (u_char) min[0] + 1; + xd_info[drive].cylinders = (u_short) min[1] + 1; + xd_info[drive].sectors = (u_char) min[2] + 1; + xd_info[drive].control = 0; +} + +/* 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) +{ + u_char cmdblk[14]; + + xd_build(cmdblk,command,drive,0,0,0,0,0); + cmdblk[6] = (u_char) (cylinders >> 8) & 0x03; + cmdblk[7] = (u_char) (cylinders & 0xFF); + cmdblk[8] = heads & 0x1F; + cmdblk[9] = (u_char) (rwrite >> 8) & 0x03; + cmdblk[10] = (u_char) (rwrite & 0xFF); + cmdblk[11] = (u_char) (wprecomp >> 8) & 0x03; + cmdblk[12] = (u_char) (wprecomp & 0xFF); + cmdblk[13] = ecc; + + if (xd_command(cmdblk,PIO_MODE,0,0,0,XD_TIMEOUT * 2)) + printk("xd_setparam: error setting characteristics for drive %d\n",drive); +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/Makefile new file mode 100644 index 000000000..414845967 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/Makefile @@ -0,0 +1,87 @@ +# +# 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_82C710_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 + +dep: + $(CPP) -M $(SRCS) > .depend + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/atixlmouse.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/atixlmouse.c new file mode 100644 index 000000000..c9952fcbe --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/atixlmouse.c @@ -0,0 +1,198 @@ +/* + * ATI XL Bus Mouse Driver for Linux + * by Bob Harris (rth@sparta.com) + * + * Uses VFS interface for linux 0.98 (01OCT92) + * + * Modified by Chris Colohan (colohan@eecg.toronto.edu) + * + * version 0.3 + */ + +#include +#include +#include +#include + +#include +#include +#include +#include + +#define ATIXL_MOUSE_IRQ 5 /* H/W interrupt # set up on ATIXL board */ +#define ATIXL_BUSMOUSE 3 /* Minor device # (mknod c 10 3 /dev/bm) */ + +/* ATI XL Inport Busmouse Definitions */ + +#define ATIXL_MSE_DATA_PORT 0x23d +#define ATIXL_MSE_SIGNATURE_PORT 0x23e +#define ATIXL_MSE_CONTROL_PORT 0x23c + +#define ATIXL_MSE_READ_BUTTONS 0x00 +#define ATIXL_MSE_READ_X 0x01 +#define ATIXL_MSE_READ_Y 0x02 + +/* Some nice ATI XL macros */ + +/* Select IR7, HOLD UPDATES (INT ENABLED), save X,Y */ +#define ATIXL_MSE_DISABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ + outb( (0x20 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } + +/* Select IR7, Enable updates (INT ENABLED) */ +#define ATIXL_MSE_ENABLE_UPDATE() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ + outb( (0xdf & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } + +/* Select IR7 - Mode Register, NO INTERRUPTS */ +#define ATIXL_MSE_INT_OFF() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ + outb( (0xe7 & inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } + +/* Select IR7 - Mode Register, DATA INTERRUPTS ENABLED */ +#define ATIXL_MSE_INT_ON() { outb( 0x07, ATIXL_MSE_CONTROL_PORT ); \ + outb( (0x08 | inb( ATIXL_MSE_DATA_PORT )), ATIXL_MSE_DATA_PORT ); } + +/* Same general mouse structure */ + +static struct mouse_status { + char buttons; + char latch_buttons; + int dx; + int dy; + int present; + int ready; + int active; + struct wait_queue *wait; +} mouse; + +void mouse_interrupt(int unused) +{ + char dx, dy, buttons; + + ATIXL_MSE_DISABLE_UPDATE(); /* Note that interrupts are still enabled */ + outb(ATIXL_MSE_READ_X, ATIXL_MSE_CONTROL_PORT); /* Select IR1 - X movement */ + dx = inb( ATIXL_MSE_DATA_PORT); + outb(ATIXL_MSE_READ_Y, ATIXL_MSE_CONTROL_PORT); /* Select IR2 - Y movement */ + dy = inb( ATIXL_MSE_DATA_PORT); + outb(ATIXL_MSE_READ_BUTTONS, ATIXL_MSE_CONTROL_PORT); /* Select IR0 - Button Status */ + buttons = inb( ATIXL_MSE_DATA_PORT); + if (dx != 0 || dy != 0 || buttons != mouse.latch_buttons) { + mouse.latch_buttons |= buttons; + mouse.dx += dx; + mouse.dy += dy; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + } + ATIXL_MSE_ENABLE_UPDATE(); +} + +static void release_mouse(struct inode * inode, struct file * file) +{ + ATIXL_MSE_INT_OFF(); /* Interrupts are really shut down here */ + mouse.active = 0; + mouse.ready = 0; + free_irq(ATIXL_MOUSE_IRQ); +} + + +static int open_mouse(struct inode * inode, struct file * file) +{ + if (!mouse.present) + return -EINVAL; + if (mouse.active) + return -EBUSY; + mouse.active = 1; + mouse.ready = 0; + mouse.dx = 0; + mouse.dy = 0; + mouse.buttons = mouse.latch_buttons = 0; + if (request_irq(ATIXL_MOUSE_IRQ, mouse_interrupt)) { + mouse.active = 0; + return -EBUSY; + } + ATIXL_MSE_INT_ON(); /* Interrupts are really enabled here */ + return 0; +} + + +static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + return -EINVAL; +} + +static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + int i; + + if (count < 3) + return -EINVAL; + if (!mouse.ready) + return -EAGAIN; + ATIXL_MSE_DISABLE_UPDATE(); + /* Allowed interrupts to occur during data gathering - shouldn't hurt */ + put_fs_byte((char)(~mouse.latch_buttons&7) | 0x80 , buffer); + if (mouse.dx < -127) + mouse.dx = -127; + if (mouse.dx > 127) + mouse.dx = 127; + put_fs_byte((char)mouse.dx, buffer + 1); + if (mouse.dy < -127) + mouse.dy = -127; + if (mouse.dy > 127) + mouse.dy = 127; + put_fs_byte((char)-mouse.dy, buffer + 2); + for(i = 3; i < count; i++) + put_fs_byte(0x00, buffer + i); + mouse.dx = 0; + mouse.dy = 0; + mouse.latch_buttons = mouse.buttons; + mouse.ready = 0; + ATIXL_MSE_ENABLE_UPDATE(); + return i; /* i data bytes returned */ +} + +static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + if (sel_type != SEL_IN) + return 0; + if (mouse.ready) + return 1; + select_wait(&mouse.wait,wait); + return 0; +} + +struct file_operations atixl_busmouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_select, /* mouse_select */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + release_mouse, +}; + +unsigned long atixl_busmouse_init(unsigned long kmem_start) +{ + unsigned char a,b,c; + + a = inb( ATIXL_MSE_SIGNATURE_PORT ); /* Get signature */ + b = inb( ATIXL_MSE_SIGNATURE_PORT ); + c = inb( ATIXL_MSE_SIGNATURE_PORT ); + if (( a != b ) && ( a == c )) + printk("\nATI Inport "); + else{ + mouse.present = 0; + return kmem_start; + } + outb(0x80, ATIXL_MSE_CONTROL_PORT); /* Reset the Inport device */ + outb(0x07, ATIXL_MSE_CONTROL_PORT); /* Select Internal Register 7 */ + outb(0x0a, ATIXL_MSE_DATA_PORT); /* Data Interrupts 8+, 1=30hz, 2=50hz, 3=100hz, 4=200hz rate */ + mouse.present = 1; + mouse.active = 0; + mouse.ready = 0; + mouse.buttons = mouse.latch_buttons = 0; + mouse.dx = mouse.dy = 0; + mouse.wait = NULL; + printk("Bus mouse detected and installed.\n"); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/busmouse.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/busmouse.c new file mode 100644 index 000000000..0d7a3be9e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/busmouse.c @@ -0,0 +1,239 @@ +/* + * Logitech Bus Mouse Driver for Linux + * by James Banks + * + * Mods by Matthew Dillon + * calls verify_area() + * tracks better when X is busy or paging + * + * Heavily modified by David Giller + * changed from queue- to counter- driven + * hacked out a (probably incorrect) mouse_select + * + * Modified again by Nathan Laredo to interface with + * 0.96c-pl1 IRQ handling changes (13JUL92) + * didn't bother touching select code. + * + * Modified the select() code blindly to conform to the VFS + * requirements. 92.07.14 - Linus. Somebody should test it out. + * + * Modified by Johan Myreen to make room for other mice (9AUG92) + * removed assignment chr_fops[10] = &mouse_fops; see mouse.c + * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. + * renamed this file mouse.c => busmouse.c + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct mouse_status mouse; +static int mouse_irq = MOUSE_IRQ; + +void bmouse_setup(char *str, int *ints) +{ + if (ints[0] > 0) + mouse_irq=ints[1]; +} + +static void mouse_interrupt(int unused) +{ + char dx, dy; + unsigned char buttons; + + MSE_INT_OFF(); + outb(MSE_READ_X_LOW, MSE_CONTROL_PORT); + dx = (inb(MSE_DATA_PORT) & 0xf); + outb(MSE_READ_X_HIGH, MSE_CONTROL_PORT); + dx |= (inb(MSE_DATA_PORT) & 0xf) << 4; + outb(MSE_READ_Y_LOW, MSE_CONTROL_PORT ); + dy = (inb(MSE_DATA_PORT) & 0xf); + outb(MSE_READ_Y_HIGH, MSE_CONTROL_PORT); + buttons = inb(MSE_DATA_PORT); + dy |= (buttons & 0xf) << 4; + buttons = ((buttons >> 5) & 0x07); + if (dx != 0 || dy != 0 || buttons != mouse.buttons) { + mouse.buttons = buttons; + mouse.dx += dx; + mouse.dy -= dy; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + + /* + * keep dx/dy reasonable, but still able to track when X (or + * whatever) must page or is busy (i.e. long waits between + * reads) + */ + if (mouse.dx < -2048) + mouse.dx = -2048; + if (mouse.dx > 2048) + mouse.dx = 2048; + + if (mouse.dy < -2048) + mouse.dy = -2048; + if (mouse.dy > 2048) + mouse.dy = 2048; + } + MSE_INT_ON(); +} + +/* + * close access to the mouse (can deal with multiple + * opens if allowed in the future) + */ + +static void close_mouse(struct inode * inode, struct file * file) +{ + if (--mouse.active == 0) { + MSE_INT_OFF(); + free_irq(mouse_irq); + } +} + +/* + * open access to the mouse, currently only one open is + * allowed. + */ + +static int open_mouse(struct inode * inode, struct file * file) +{ + if (!mouse.present) + return -EINVAL; + if (mouse.active) + return -EBUSY; + mouse.ready = 0; + mouse.dx = 0; + mouse.dy = 0; + mouse.buttons = 0x87; + if (request_irq(mouse_irq, mouse_interrupt)) + return -EBUSY; + mouse.active = 1; + MSE_INT_ON(); + return 0; +} + +/* + * writes are disallowed + */ + +static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + return -EINVAL; +} + +/* + * read mouse data. Currently never blocks. + */ + +static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + int r; + int dx; + int dy; + unsigned char buttons; + + if (count < 3) + return -EINVAL; + if ((r = verify_area(VERIFY_WRITE, buffer, count))) + return r; + if (!mouse.ready) + return -EAGAIN; + + /* + * Obtain the current mouse parameters and limit as appropriate for + * the return data format. Interrupts are only disabled while + * obtaining the parameters, NOT during the puts_fs_byte() calls, + * so paging in put_fs_byte() does not effect mouse tracking. + */ + + MSE_INT_OFF(); + dx = mouse.dx; + dy = mouse.dy; + if (dx < -127) + dx = -127; + if (dx > 127) + dx = 127; + if (dy < -127) + dy = -127; + if (dy > 127) + dy = 127; + buttons = mouse.buttons; + mouse.dx -= dx; + mouse.dy -= dy; + mouse.ready = 0; + MSE_INT_ON(); + + put_fs_byte(buttons | 0x80, buffer); + put_fs_byte((char)dx, buffer + 1); + put_fs_byte((char)dy, buffer + 2); + for (r = 3; r < count; r++) + put_fs_byte(0x00, buffer + r); + return r; +} + +/* + * select for mouse input, must disable the mouse interrupt while checking + * mouse.ready/select_wait() to avoid race condition (though in reality + * such a condition is not fatal to the proper operation of the mouse since + * multiple interrupts generally occur). + */ + +static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + int r = 0; + + if (sel_type == SEL_IN) { + MSE_INT_OFF(); + if (mouse.ready) { + r = 1; + } else { + select_wait(&mouse.wait, wait); + } + MSE_INT_ON(); + } + return(r); +} + +struct file_operations bus_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_select, /* mouse_select */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + close_mouse, +}; + +unsigned long bus_mouse_init(unsigned long kmem_start) +{ + int i; + + outb(MSE_CONFIG_BYTE, MSE_CONFIG_PORT); + outb(MSE_SIGNATURE_BYTE, MSE_SIGNATURE_PORT); + for (i = 0; i < 100000; i++) + /* busy loop */; + if (inb(MSE_SIGNATURE_PORT) != MSE_SIGNATURE_BYTE) { + mouse.present = 0; + return kmem_start; + } + outb(MSE_DEFAULT_MODE, MSE_CONFIG_PORT); + MSE_INT_OFF(); + mouse.present = 1; + mouse.active = 0; + mouse.ready = 0; + mouse.buttons = 0x87; + mouse.dx = 0; + mouse.dy = 0; + mouse.wait = NULL; + printk("Logitech Bus mouse detected and installed.\n"); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/console.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/console.c new file mode 100644 index 000000000..a22889856 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/console.c @@ -0,0 +1,1951 @@ +/* + * linux/kernel/console.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * console.c + * + * This module exports the console io functions: + * + * 'long con_init(long)' + * 'int con_open(struct tty_struct *tty, struct file * filp)' + * 'void update_screen(int new_console)' + * 'void blank_screen(void)' + * 'void unblank_screen(void)' + * + * 'int con_get_font(char *)' + * 'int con_set_font(char *)' + * 'int con_get_trans(char *)' + * 'int con_set_trans(char *)' + * + * Hopefully this will be a rather complete VT102 implementation. + * + * Beeping thanks to John T Kohl. + * + * Virtual Consoles, Screen Blanking, Screen Dumping, Color, Graphics + * Chars, and VT100 enhancements by Peter MacDonald. + * + * Copy and paste function by Andrew Haylett. + * + * User definable mapping table and font loading by Eugene G. Crosser, + * + * + * Code to check for different video-cards mostly by Galen Hunt, + * + * + */ + +#define CAN_LOAD_EGA_FONTS /* undefine if the user must not do this */ + +/* + * NOTE!!! We sometimes disable and enable interrupts for a short while + * (to put a word in video IO), but this will work even for keyboard + * interrupts. We know interrupts aren't enabled when getting a keyboard + * interrupt, as we use trap-gates. Hopefully all is well. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kbd_kern.h" +#include "vt_kern.h" + +#ifdef CONFIG_SELECTION +#include + +/* Routines for selection control. */ +int set_selection(const int arg); +int paste_selection(struct tty_struct *tty); +static void clear_selection(void); + +/* Variables for selection control. */ +#define SEL_BUFFER_SIZE TTY_BUF_SIZE +static int sel_cons; +static int sel_start = -1; +static int sel_end; +static char sel_buffer[SEL_BUFFER_SIZE] = { '\0' }; +#endif /* CONFIG_SELECTION */ + +#define NPAR 16 + +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 text lines */ + +static unsigned char video_type; /* Type of display being used */ +static unsigned long video_mem_base; /* Base of video memory */ +static unsigned long video_mem_term; /* End of video memory */ +static unsigned long video_size_row; /* Bytes per row */ +static unsigned char video_page; /* Initial video page */ +static unsigned short video_port_reg; /* Video register select port */ +static unsigned short video_port_val; /* Video register value port */ +static int can_do_color = 0; +static int printable = 0; + +static struct { + unsigned short vc_video_erase_char; /* Background erase character */ + unsigned char vc_attr; /* Current attributes */ + unsigned char vc_def_color; /* Default colors */ + unsigned char vc_color; /* Foreground & background */ + unsigned char vc_s_color; /* Saved foreground & background */ + unsigned char vc_ulcolor; /* Colour for underline mode */ + unsigned char vc_halfcolor; /* Colour for half intensity mode */ + unsigned long vc_origin; /* Used for EGA/VGA fast scroll */ + unsigned long vc_scr_end; /* Used for EGA/VGA fast scroll */ + unsigned long vc_pos; + unsigned long vc_x,vc_y; + unsigned long vc_top,vc_bottom; + unsigned long vc_state; + unsigned long vc_npar,vc_par[NPAR]; + unsigned long vc_video_mem_start; /* Start of video RAM */ + unsigned long vc_video_mem_end; /* End of video RAM (sort of) */ + unsigned long vc_saved_x; + unsigned long vc_saved_y; + /* mode flags */ + unsigned long vc_charset : 1; /* Character set G0 / G1 */ + unsigned long vc_s_charset : 1; /* Saved character set */ + unsigned long vc_decscnm : 1; /* Screen Mode */ + unsigned long vc_decom : 1; /* Origin Mode */ + unsigned long vc_decawm : 1; /* Autowrap Mode */ + unsigned long vc_deccm : 1; /* Cursor Visible */ + unsigned long vc_decim : 1; /* Insert Mode */ + /* attribute flags */ + unsigned long vc_intensity : 2; /* 0=half-bright, 1=normal, 2=bold */ + unsigned long vc_underline : 1; + unsigned long vc_blink : 1; + unsigned long vc_reverse : 1; + unsigned long vc_s_intensity : 2; /* saved rendition */ + unsigned long vc_s_underline : 1; + unsigned long vc_s_blink : 1; + unsigned long vc_s_reverse : 1; + /* misc */ + unsigned long vc_ques : 1; + unsigned long vc_need_wrap : 1; + unsigned long vc_tab_stop[5]; /* Tab stops. 160 columns. */ + unsigned char * vc_translate; + unsigned char * vc_G0_charset; + unsigned char * vc_G1_charset; + unsigned char * vc_saved_G0; + unsigned char * vc_saved_G1; + /* additional information is in vt_kern.h */ +} vc_cons [NR_CONSOLES]; + +unsigned short *vc_scrbuf[NR_CONSOLES]; +static unsigned short * vc_scrmembuf; +static int console_blanked = 0; + +#define origin (vc_cons[currcons].vc_origin) +#define scr_end (vc_cons[currcons].vc_scr_end) +#define pos (vc_cons[currcons].vc_pos) +#define top (vc_cons[currcons].vc_top) +#define bottom (vc_cons[currcons].vc_bottom) +#define x (vc_cons[currcons].vc_x) +#define y (vc_cons[currcons].vc_y) +#define state (vc_cons[currcons].vc_state) +#define npar (vc_cons[currcons].vc_npar) +#define par (vc_cons[currcons].vc_par) +#define ques (vc_cons[currcons].vc_ques) +#define attr (vc_cons[currcons].vc_attr) +#define saved_x (vc_cons[currcons].vc_saved_x) +#define saved_y (vc_cons[currcons].vc_saved_y) +#define translate (vc_cons[currcons].vc_translate) +#define G0_charset (vc_cons[currcons].vc_G0_charset) +#define G1_charset (vc_cons[currcons].vc_G1_charset) +#define saved_G0 (vc_cons[currcons].vc_saved_G0) +#define saved_G1 (vc_cons[currcons].vc_saved_G1) +#define video_mem_start (vc_cons[currcons].vc_video_mem_start) +#define video_mem_end (vc_cons[currcons].vc_video_mem_end) +#define video_erase_char (vc_cons[currcons].vc_video_erase_char) +#define decscnm (vc_cons[currcons].vc_decscnm) +#define decom (vc_cons[currcons].vc_decom) +#define decawm (vc_cons[currcons].vc_decawm) +#define deccm (vc_cons[currcons].vc_deccm) +#define decim (vc_cons[currcons].vc_decim) +#define need_wrap (vc_cons[currcons].vc_need_wrap) +#define color (vc_cons[currcons].vc_color) +#define s_color (vc_cons[currcons].vc_s_color) +#define def_color (vc_cons[currcons].vc_def_color) +#define foreground (color & 0x0f) +#define background (color & 0xf0) +#define charset (vc_cons[currcons].vc_charset) +#define s_charset (vc_cons[currcons].vc_s_charset) +#define intensity (vc_cons[currcons].vc_intensity) +#define underline (vc_cons[currcons].vc_underline) +#define blink (vc_cons[currcons].vc_blink) +#define reverse (vc_cons[currcons].vc_reverse) +#define s_intensity (vc_cons[currcons].vc_s_intensity) +#define s_underline (vc_cons[currcons].vc_s_underline) +#define s_blink (vc_cons[currcons].vc_s_blink) +#define s_reverse (vc_cons[currcons].vc_s_reverse) +#define ulcolor (vc_cons[currcons].vc_ulcolor) +#define halfcolor (vc_cons[currcons].vc_halfcolor) +#define tab_stop (vc_cons[currcons].vc_tab_stop) +#define vcmode (vt_cons[currcons].vc_mode) +#define vtmode (vt_cons[currcons].vt_mode) +#define vtpid (vt_cons[currcons].vt_pid) +#define vtnewvt (vt_cons[currcons].vt_newvt) + +#define set_kbd(x) set_vc_kbd_mode(kbd_table+currcons,x) +#define clr_kbd(x) clr_vc_kbd_mode(kbd_table+currcons,x) +#define is_kbd(x) vc_kbd_mode(kbd_table+currcons,x) + +#define decarm VC_REPEAT +#define decckm VC_CKMODE +#define kbdapplic VC_APPLIC +#define kbdraw VC_RAW +#define lnm VC_CRLF + +int blankinterval = 10*60*HZ; +static int screen_size = 0; + +/* + * this is what the terminal answers to a ESC-Z or csi0c query. + */ +#define VT100ID "\033[?1;2c" +#define VT102ID "\033[?6c" + +static unsigned char * translations[] = { +/* 8-bit Latin-1 mapped to the PC character set: '\0' means non-printable */ +(unsigned char *) + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" + "`abcdefghijklmnopqrstuvwxyz{|}~\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\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\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\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" + "\0\0\0\0\0\0\0\0\0\0\376\0\0\0\0\0" + " !\"#$%&'()*+,-./0123456789:;<=>?" + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^ " + "\004\261\007\007\007\007\370\361\007\007\331\277\332\300\305\304" + "\304\304\137\137\303\264\301\302\263\363\362\343\330\234\007\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" + "\377\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\376\376\376\376\232\376\376\341" + "\205\240\203\376\204\206\221\207\212\202\210\211\215\241\214\213" + "\376\244\225\242\223\376\224\366\376\227\243\226\201\376\376\230", +/* IBM graphics: minimal translations (BS, CR, LF, LL, SO, SI and ESC) */ +(unsigned char *) + "\000\001\002\003\004\005\006\007\000\011\000\013\000\000\000\000" + "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" + "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" + "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" + "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" + "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" + "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" + "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377", + /* USER: customizable mappings, initialized as the previous one (IBM) */ +(unsigned char *) + "\000\001\002\003\004\005\006\007\010\011\000\013\000\000\016\017" + "\020\021\022\023\024\025\026\027\030\031\032\000\034\035\036\037" + "\040\041\042\043\044\045\046\047\050\051\052\053\054\055\056\057" + "\060\061\062\063\064\065\066\067\070\071\072\073\074\075\076\077" + "\100\101\102\103\104\105\106\107\110\111\112\113\114\115\116\117" + "\120\121\122\123\124\125\126\127\130\131\132\133\134\135\136\137" + "\140\141\142\143\144\145\146\147\150\151\152\153\154\155\156\157" + "\160\161\162\163\164\165\166\167\170\171\172\173\174\175\176\177" + "\200\201\202\203\204\205\206\207\210\211\212\213\214\215\216\217" + "\220\221\222\223\224\225\226\227\230\231\232\233\234\235\236\237" + "\240\241\242\243\244\245\246\247\250\251\252\253\254\255\256\257" + "\260\261\262\263\264\265\266\267\270\271\272\273\274\275\276\277" + "\300\301\302\303\304\305\306\307\310\311\312\313\314\315\316\317" + "\320\321\322\323\324\325\326\327\330\331\332\333\334\335\336\337" + "\340\341\342\343\344\345\346\347\350\351\352\353\354\355\356\357" + "\360\361\362\363\364\365\366\367\370\371\372\373\374\375\376\377" +}; + +#define NORM_TRANS (translations[0]) +#define GRAF_TRANS (translations[1]) +#define NULL_TRANS (translations[2]) +#define USER_TRANS (translations[3]) + +static unsigned char color_table[] = { 0, 4, 2, 6, 1, 5, 3, 7, + 8,12,10,14, 9,13,11,15 }; + +/* + * gotoxy() must verify all boundaries, because the arguments + * might also be negative. If the given position is out of + * bounds, the cursor is placed at the nearest margin. + */ +static void gotoxy(int currcons, int new_x, int new_y) +{ + int max_y; + + if (new_x < 0) + x = 0; + else + if (new_x >= video_num_columns) + x = video_num_columns - 1; + else + x = new_x; + if (decom) { + new_y += top; + max_y = bottom; + } else + max_y = video_num_lines; + if (new_y < 0) + y = 0; + else + if (new_y >= max_y) + y = max_y - 1; + else + y = new_y; + pos = origin + y*video_size_row + (x<<1); + need_wrap = 0; +} + +/* + * *Very* limited hardware scrollback support.. + */ +static unsigned short __real_origin; +static unsigned short __origin; + +static inline void __set_origin(unsigned short offset) +{ + unsigned long flags; +#ifdef CONFIG_SELECTION + clear_selection(); +#endif /* CONFIG_SELECTION */ + save_flags(flags); cli(); + __origin = offset; + outb_p(12, video_port_reg); + outb_p(offset >> 8, video_port_val); + outb_p(13, video_port_reg); + outb_p(offset, video_port_val); + restore_flags(flags); +} + +void scrollback(int lines) +{ + if (!lines) + lines = video_num_lines/2; + lines *= video_num_columns; + lines = __origin - lines; + if (lines < 0) + lines = 0; + __set_origin(lines); +} + +void scrollfront(int lines) +{ + if (!lines) + lines = video_num_lines/2; + lines *= video_num_columns; + lines = __origin + lines; + if (lines > __real_origin) + lines = __real_origin; + __set_origin(lines); +} + +static void set_origin(int currcons) +{ + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + return; + if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) + return; + __real_origin = (origin-video_mem_base) >> 1; + __set_origin(__real_origin); +} + +static inline void hide_cursor(int currcons) +{ + outb_p(14, video_port_reg); + outb_p(0xff&((scr_end-video_mem_base)>>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((scr_end-video_mem_base)>>1), video_port_val); +} + +static inline void set_cursor(int currcons) +{ + unsigned long flags; + + if (currcons != fg_console || console_blanked || vcmode == KD_GRAPHICS) + return; + if (__real_origin != __origin) + set_origin(__real_origin); + save_flags(flags); cli(); + if (deccm) { + outb_p(14, video_port_reg); + outb_p(0xff&((pos-video_mem_base)>>9), video_port_val); + outb_p(15, video_port_reg); + outb_p(0xff&((pos-video_mem_base)>>1), video_port_val); + } else + hide_cursor(currcons); + restore_flags(flags); +} + +static void scrup(int currcons, unsigned int t, unsigned int b) +{ + int hardscroll = 1; + + if (b > video_num_lines || t >= b) + return; + if (video_type != VIDEO_TYPE_EGAC && video_type != VIDEO_TYPE_EGAM) + hardscroll = 0; + else if (t || b != video_num_lines) + hardscroll = 0; + if (hardscroll) { + origin += video_size_row; + pos += video_size_row; + scr_end += video_size_row; + if (scr_end > video_mem_end) { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%1\n\t" + "rep\n\t" + "stosw" + : /* no output */ + :"a" (video_erase_char), + "c" ((video_num_lines-1)*video_num_columns>>1), + "D" (video_mem_start), + "S" (origin) + :"cx","di","si"); + scr_end -= origin-video_mem_start; + pos -= origin-video_mem_start; + origin = video_mem_start; + } else { + __asm__("cld\n\t" + "rep\n\t" + "stosw" + : /* no output */ + :"a" (video_erase_char), + "c" (video_num_columns), + "D" (scr_end-video_size_row) + :"cx","di"); + } + set_origin(currcons); + } else { + __asm__("cld\n\t" + "rep\n\t" + "movsl\n\t" + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw" + : /* no output */ + :"a" (video_erase_char), + "c" ((b-t-1)*video_num_columns>>1), + "D" (origin+video_size_row*t), + "S" (origin+video_size_row*(t+1)) + :"cx","di","si"); + } +} + +static void scrdown(int currcons, unsigned int t, unsigned int b) +{ + if (b > video_num_lines || t >= b) + return; + __asm__("std\n\t" + "rep\n\t" + "movsl\n\t" + "addl $2,%%edi\n\t" /* %edi has been decremented by 4 */ + "movl _video_num_columns,%%ecx\n\t" + "rep\n\t" + "stosw\n\t" + "cld" + : /* no output */ + :"a" (video_erase_char), + "c" ((b-t-1)*video_num_columns>>1), + "D" (origin+video_size_row*b-4), + "S" (origin+video_size_row*(b-1)-4) + :"ax","cx","di","si"); +} + +static void lf(int currcons) +{ + if (y+1top) { + y--; + pos -= video_size_row; + return; + } else + scrdown(currcons,top,bottom); + need_wrap = 0; +} + +static inline void cr(int currcons) +{ + pos -= x<<1; + need_wrap = x = 0; +} + +static inline void bs(int currcons) +{ + if (x) { + pos -= 2; + x--; + need_wrap = 0; + } +} + +static inline void del(int currcons) +{ +#if 0 + if (x) { + if (!need_wrap) { /* this is not the right condition */ + pos -= 2; + x--; + } + *(unsigned short *)pos = video_erase_char; + need_wrap = 0; + } +#endif +} + +static void csi_J(int currcons, int vpar) +{ + unsigned long count; + unsigned long start; + + switch (vpar) { + case 0: /* erase from cursor to end of display */ + count = (scr_end-pos)>>1; + start = pos; + break; + case 1: /* erase from start to cursor */ + count = ((pos-origin)>>1)+1; + start = origin; + break; + case 2: /* erase whole display */ + count = video_num_columns * video_num_lines; + start = origin; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + : /* no output */ + :"c" (count), + "D" (start),"a" (video_erase_char) + :"cx","di"); + need_wrap = 0; +} + +static void csi_K(int currcons, int vpar) +{ + long count; + long start; + + switch (vpar) { + case 0: /* erase from cursor to end of line */ + count = video_num_columns-x; + start = pos; + break; + case 1: /* erase from start of line to cursor */ + start = pos - (x<<1); + count = x+1; + break; + case 2: /* erase whole line */ + start = pos - (x<<1); + count = video_num_columns; + break; + default: + return; + } + __asm__("cld\n\t" + "rep\n\t" + "stosw\n\t" + : /* no output */ + :"c" (count), + "D" (start),"a" (video_erase_char) + :"cx","di"); + need_wrap = 0; +} + +/* + * I hope this works. The monochrome part is untested. + */ +static void update_attr(int currcons) +{ + attr = color; + if (can_do_color) { + if (underline) + attr = (attr & 0xf0) | ulcolor; + else if (intensity == 0) + attr = (attr & 0xf0) | halfcolor; + } + if (reverse ^ decscnm) + attr = (attr & 0x88) | (((attr >> 4) | (attr << 4)) & 0x77); + if (blink) + attr ^= 0x80; + if (intensity == 2) + attr ^= 0x08; + if (!can_do_color) { + if (underline) + attr = (attr & 0xf8) | 0x01; + else if (intensity == 0) + attr = (attr & 0xf0) | 0x08; + } + if (decscnm) + video_erase_char = (((color & 0x88) | (((color >> 4) | (color << 4)) & 0x77)) << 8) | ' '; + else + video_erase_char = (color << 8) | ' '; +} + +static void default_attr(int currcons) +{ + intensity = 1; + underline = 0; + reverse = 0; + blink = 0; + color = def_color; +} + +static void csi_m(int currcons) +{ + int i; + + for (i=0;i<=npar;i++) + switch (par[i]) { + case 0: /* all attributes off */ + default_attr(currcons); + break; + case 1: + intensity = 2; + break; + case 2: + intensity = 0; + break; + case 4: + underline = 1; + break; + case 5: + blink = 1; + break; + case 7: + reverse = 1; + break; + case 21: + case 22: + intensity = 1; + break; + case 24: + underline = 0; + break; + case 25: + blink = 0; + break; + case 27: + reverse = 0; + break; + case 39: + color = (def_color & 0x0f) | background; + break; + case 49: + color = (def_color & 0xf0) | foreground; + break; + default: + if (par[i] >= 30 && par[i] <= 37) + color = color_table[par[i]-30] + | background; + else if (par[i] >= 40 && par[i] <= 47) + color = (color_table[par[i]-40]<<4) + | foreground; + break; + } + update_attr(currcons); +} + +static void respond_string(char * p, int currcons, struct tty_struct * tty) +{ + while (*p) { + put_tty_queue(*p, &tty->read_q); + p++; + } + TTY_READ_FLUSH(tty); +} + +static void respond_num(unsigned int n, int currcons, struct tty_struct * tty) +{ + char buff[3]; + int i = 0; + + do { + buff[i++] = (n%10)+'0'; + n /= 10; + } while(n && i < 3); /* We'll take no chances */ + while (i--) { + put_tty_queue(buff[i], &tty->read_q); + } + /* caller must flush */ +} + +static void cursor_report(int currcons, struct tty_struct * tty) +{ + put_tty_queue('\033', &tty->read_q); + put_tty_queue('[', &tty->read_q); + respond_num(y + (decom ? top+1 : 1), currcons, tty); + put_tty_queue(';', &tty->read_q); + respond_num(x+1, currcons, tty); + put_tty_queue('R', &tty->read_q); + TTY_READ_FLUSH(tty); +} + +static inline void status_report(int currcons, struct tty_struct * tty) +{ + respond_string("\033[0n", currcons, tty); /* Terminal ok */ +} + +static inline void respond_ID(int currcons, struct tty_struct * tty) +{ + respond_string(VT102ID, currcons, tty); +} + +static void invert_screen(int currcons) { + unsigned char *p; + + if (can_do_color) + for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2) + *p = (*p & 0x88) | (((*p >> 4) | (*p << 4)) & 0x77); + else + for (p = (unsigned char *)origin+1; p < (unsigned char *)scr_end; p+=2) + *p ^= *p & 0x07 == 1 ? 0x70 : 0x77; +} + +static void set_mode(int currcons, int on_off) +{ + int i; + + for (i=0; i<=npar; i++) + if (ques) switch(par[i]) { /* DEC private modes set/reset */ + case 1: /* Cursor keys send ^[Ox/^[[x */ + if (on_off) + set_kbd(decckm); + else + clr_kbd(decckm); + break; + case 3: /* 80/132 mode switch unimplemented */ + csi_J(currcons,2); + gotoxy(currcons,0,0); + break; + case 5: /* Inverted screen on/off */ + if (decscnm != on_off) { + decscnm = on_off; + invert_screen(currcons); + update_attr(currcons); + } + break; + case 6: /* Origin relative/absolute */ + decom = on_off; + gotoxy(currcons,0,0); + break; + case 7: /* Autowrap on/off */ + decawm = on_off; + break; + case 8: /* Autorepeat on/off */ + if (on_off) + set_kbd(decarm); + else + clr_kbd(decarm); + break; + case 25: /* Cursor on/off */ + deccm = on_off; + set_cursor(currcons); + break; + } else switch(par[i]) { /* ANSI modes set/reset */ + case 4: /* Insert Mode on/off */ + decim = on_off; + break; + case 20: /* Lf, Enter == CrLf/Lf */ + if (on_off) + set_kbd(lnm); + else + clr_kbd(lnm); + break; + } +} + +static void setterm_command(int currcons) +{ + switch(par[0]) { + case 1: /* set color for underline mode */ + if (can_do_color && par[1] < 16) { + ulcolor = color_table[par[1]]; + if (underline) + update_attr(currcons); + } + break; + case 2: /* set color for half intensity mode */ + if (can_do_color && par[1] < 16) { + halfcolor = color_table[par[1]]; + if (intensity == 0) + update_attr(currcons); + } + break; + case 8: /* store colors as defaults */ + def_color = attr; + default_attr(currcons); + update_attr(currcons); + break; + case 9: /* set blanking interval */ + blankinterval = ((par[1] < 60) ? par[1] : 60) * 60 * HZ; + break; + } +} + +static void insert_char(int currcons) +{ + unsigned int i = x; + unsigned short tmp, old = video_erase_char; + unsigned short * p = (unsigned short *) pos; + + while (i++ < video_num_columns) { + tmp = *p; + *p = old; + old = tmp; + p++; + } + need_wrap = 0; +} + +static void insert_line(int currcons) +{ + scrdown(currcons,y,bottom); + need_wrap = 0; +} + +static void delete_char(int currcons) +{ + unsigned int i = x; + unsigned short * p = (unsigned short *) pos; + + while (++i < video_num_columns) { + *p = *(p+1); + p++; + } + *p = video_erase_char; + need_wrap = 0; +} + +static void delete_line(int currcons) +{ + scrup(currcons,y,bottom); + need_wrap = 0; +} + +static void csi_at(int currcons, unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + insert_char(currcons); +} + +static void csi_L(int currcons, unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr = 1; + while (nr--) + insert_line(currcons); +} + +static void csi_P(int currcons, unsigned int nr) +{ + if (nr > video_num_columns) + nr = video_num_columns; + else if (!nr) + nr = 1; + while (nr--) + delete_char(currcons); +} + +static void csi_M(int currcons, unsigned int nr) +{ + if (nr > video_num_lines) + nr = video_num_lines; + else if (!nr) + nr=1; + while (nr--) + delete_line(currcons); +} + +static void save_cur(int currcons) +{ + saved_x = x; + saved_y = y; + s_intensity = intensity; + s_underline = underline; + s_blink = blink; + s_reverse = reverse; + s_charset = charset; + s_color = color; + saved_G0 = G0_charset; + saved_G1 = G1_charset; +} + +static void restore_cur(int currcons) +{ + gotoxy(currcons,saved_x,saved_y); + intensity = s_intensity; + underline = s_underline; + blink = s_blink; + reverse = s_reverse; + charset = s_charset; + color = s_color; + G0_charset = saved_G0; + G1_charset = saved_G1; + translate = charset ? G1_charset : G0_charset; + update_attr(currcons); + need_wrap = 0; +} + +enum { ESnormal, ESesc, ESsquare, ESgetpars, ESgotpars, ESfunckey, + EShash, ESsetG0, ESsetG1, ESignore }; + +static void reset_terminal(int currcons, int do_clear) +{ + top = 0; + bottom = video_num_lines; + state = ESnormal; + ques = 0; + translate = NORM_TRANS; + G0_charset = NORM_TRANS; + G1_charset = GRAF_TRANS; + charset = 0; + need_wrap = 0; + + decscnm = 0; + decom = 0; + decawm = 1; + deccm = 1; + decim = 0; + + set_kbd(decarm); + clr_kbd(decckm); + clr_kbd(kbdapplic); + clr_kbd(lnm); + kbd_table[currcons].lockstate = 0; + kbd_table[currcons].ledstate = kbd_table[currcons].default_ledstate; + set_leds(); + + default_attr(currcons); + update_attr(currcons); + + tab_stop[0] = 0x01010100; + tab_stop[1] = + tab_stop[2] = + tab_stop[3] = + tab_stop[4] = 0x01010101; + + if (do_clear) { + gotoxy(currcons,0,0); + csi_J(currcons,2); + save_cur(currcons); + } +} + +void con_write(struct tty_struct * tty) +{ + int c; + unsigned int currcons; + + currcons = tty->line - 1; + if (currcons >= NR_CONSOLES) { + printk("con_write: illegal tty (%d)\n", currcons); + return; + } +#ifdef CONFIG_SELECTION + /* clear the selection as soon as any characters are to be written + out on the console holding the selection. */ + if (!EMPTY(&tty->write_q) && currcons == sel_cons) + clear_selection(); +#endif /* CONFIG_SELECTION */ + disable_bh(KEYBOARD_BH); + while (!tty->stopped && (c = get_tty_queue(&tty->write_q)) >= 0) { + if (state == ESnormal && translate[c]) { + if (need_wrap) { + cr(currcons); + lf(currcons); + } + if (decim) + insert_char(currcons); + c = translate[c]; + *(unsigned short *) pos = (attr << 8) + c; + if (x == video_num_columns - 1) + need_wrap = decawm; + else { + x++; + pos+=2; + } + continue; + } + + /* + * Control characters can be used in the _middle_ + * of an escape sequence. + */ + switch (c) { + case 7: + kd_mksound(0x637, HZ/8); + continue; + case 8: + bs(currcons); + continue; + case 9: + pos -= (x << 1); + while (x < video_num_columns - 1) { + x++; + if (tab_stop[x >> 5] & (1 << (x & 31))) + break; + } + pos += (x << 1); + continue; + case 10: case 11: case 12: + lf(currcons); + if (!is_kbd(lnm)) + continue; + case 13: + cr(currcons); + continue; + case 14: + charset = 1; + translate = G1_charset; + continue; + case 15: + charset = 0; + translate = G0_charset; + continue; + case 24: case 26: + state = ESnormal; + continue; + case 27: + state = ESesc; + continue; + case 127: + del(currcons); + continue; + case 128+27: + state = ESsquare; + continue; + } + switch(state) { + case ESesc: + state = ESnormal; + switch (c) { + case '[': + state = ESsquare; + continue; + case 'E': + cr(currcons); + lf(currcons); + continue; + case 'M': + ri(currcons); + continue; + case 'D': + lf(currcons); + continue; + case 'H': + tab_stop[x >> 5] |= (1 << (x & 31)); + continue; + case 'Z': + respond_ID(currcons,tty); + continue; + case '7': + save_cur(currcons); + continue; + case '8': + restore_cur(currcons); + continue; + case '(': + state = ESsetG0; + continue; + case ')': + state = ESsetG1; + continue; + case '#': + state = EShash; + continue; + case 'c': + reset_terminal(currcons,1); + continue; + case '>': /* Numeric keypad */ + clr_kbd(kbdapplic); + continue; + case '=': /* Appl. keypad */ + set_kbd(kbdapplic); + continue; + } + continue; + case ESsquare: + for(npar = 0 ; npar < NPAR ; npar++) + par[npar] = 0; + npar = 0; + state = ESgetpars; + if (c == '[') { /* Function key */ + state=ESfunckey; + continue; + } + ques = (c=='?'); + if (ques) + continue; + case ESgetpars: + if (c==';' && npar='0' && c<='9') { + par[npar] *= 10; + par[npar] += c-'0'; + continue; + } else state=ESgotpars; + case ESgotpars: + state = ESnormal; + switch(c) { + case 'h': + set_mode(currcons,1); + continue; + case 'l': + set_mode(currcons,0); + continue; + case 'n': + if (!ques) + if (par[0] == 5) + status_report(currcons,tty); + else if (par[0] == 6) + cursor_report(currcons,tty); + continue; + } + if (ques) { + ques = 0; + continue; + } + switch(c) { + case 'G': case '`': + if (par[0]) par[0]--; + gotoxy(currcons,par[0],y); + continue; + case 'A': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y-par[0]); + continue; + case 'B': case 'e': + if (!par[0]) par[0]++; + gotoxy(currcons,x,y+par[0]); + continue; + case 'C': case 'a': + if (!par[0]) par[0]++; + gotoxy(currcons,x+par[0],y); + continue; + case 'D': + if (!par[0]) par[0]++; + gotoxy(currcons,x-par[0],y); + continue; + case 'E': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y+par[0]); + continue; + case 'F': + if (!par[0]) par[0]++; + gotoxy(currcons,0,y-par[0]); + continue; + case 'd': + if (par[0]) par[0]--; + gotoxy(currcons,x,par[0]); + continue; + case 'H': case 'f': + if (par[0]) par[0]--; + if (par[1]) par[1]--; + gotoxy(currcons,par[1],par[0]); + continue; + case 'J': + csi_J(currcons,par[0]); + continue; + case 'K': + csi_K(currcons,par[0]); + continue; + case 'L': + csi_L(currcons,par[0]); + continue; + case 'M': + csi_M(currcons,par[0]); + continue; + case 'P': + csi_P(currcons,par[0]); + continue; + case 'c': + if (!par[0]) + respond_ID(currcons,tty); + continue; + case 'g': + if (!par[0]) + tab_stop[x >> 5] &= ~(1 << (x & 31)); + else if (par[0] == 3) { + tab_stop[0] = + tab_stop[1] = + tab_stop[2] = + tab_stop[3] = + tab_stop[4] = 0; + } + continue; + case 'm': + csi_m(currcons); + continue; + case 'r': + if (!par[0]) + par[0]++; + if (!par[1]) + par[1] = video_num_lines; + /* Minimum allowed region is 2 lines */ + if (par[0] < par[1] && + par[1] <= video_num_lines) { + top=par[0]-1; + bottom=par[1]; + gotoxy(currcons,0,0); + } + continue; + case 's': + save_cur(currcons); + continue; + case 'u': + restore_cur(currcons); + continue; + case '@': + csi_at(currcons,par[0]); + continue; + case ']': /* setterm functions */ + setterm_command(currcons); + continue; + } + continue; + case ESfunckey: + state = ESnormal; + continue; + case EShash: + state = ESnormal; + if (c == '8') { + /* DEC screen alignment test. kludge :-) */ + video_erase_char = + (video_erase_char & 0xff00) | 'E'; + csi_J(currcons, 2); + video_erase_char = + (video_erase_char & 0xff00) | ' '; + } + continue; + case ESsetG0: + if (c == '0') + G0_charset = GRAF_TRANS; + else if (c == 'B') + G0_charset = NORM_TRANS; + else if (c == 'U') + G0_charset = NULL_TRANS; + else if (c == 'K') + G0_charset = USER_TRANS; + if (charset == 0) + translate = G0_charset; + state = ESnormal; + continue; + case ESsetG1: + if (c == '0') + G1_charset = GRAF_TRANS; + else if (c == 'B') + G1_charset = NORM_TRANS; + else if (c == 'U') + G1_charset = NULL_TRANS; + else if (c == 'K') + G1_charset = USER_TRANS; + if (charset == 1) + translate = G1_charset; + state = ESnormal; + continue; + default: + state = ESnormal; + } + } + if (vcmode != KD_GRAPHICS) + set_cursor(currcons); + enable_bh(KEYBOARD_BH); + if (LEFT(&tty->write_q) > WAKEUP_CHARS) + wake_up_interruptible(&tty->write_q.proc_list); +} + +void do_keyboard_interrupt(void) +{ + TTY_READ_FLUSH(TTY_TABLE(0)); + timer_active &= ~(1<=NR_CONSOLES) + return; + while ((c = *(b++)) != 0) { + if (c == 10 || c == 13 || need_wrap) { + if (c != 13) + lf(currcons); + cr(currcons); + if (c == 10 || c == 13) + continue; + } + *(unsigned short *) pos = (attr << 8) + c; + if (x == video_num_columns - 1) { + need_wrap = 1; + continue; + } + x++; + pos+=2; + } + set_cursor(currcons); + if (vt_cons[fg_console].vc_mode == KD_GRAPHICS) + return; + timer_active &= ~(1<NR_CONSOLES)) + return -EIO; + put_fs_byte((char)(video_num_lines),buf++); + put_fs_byte((char)(video_num_columns),buf++); + currcons = (currcons ? currcons-1 : fg_console); + sptr = (char *) origin; + for (l=video_num_lines*video_num_columns; l>0 ; l--, sptr++) + put_fs_byte(*sptr++,buf++); + return(0); +} + +/* + * All we do is set the write and ioctl subroutines; later on maybe we'll + * dynamically allocate the console screen memory. + */ +int con_open(struct tty_struct *tty, struct file * filp) +{ + tty->write = con_write; + tty->ioctl = vt_ioctl; + if (tty->line > NR_CONSOLES) + return -ENODEV; + return 0; +} + +#ifdef CONFIG_SELECTION +/* correction factor for when screen is hardware-scrolled */ +#define hwscroll_offset (currcons == fg_console ? ((__real_origin - __origin) << 1) : 0) + +/* set reverse video on characters s-e of console with selection. */ +static void highlight(const int currcons, const int s, const int e) +{ + unsigned char *p, *p1, *p2; + + p1 = (unsigned char *)origin - hwscroll_offset + s + 1; + p2 = (unsigned char *)origin - hwscroll_offset + e + 1; + if (p1 > p2) + { + p = p1; + p1 = p2; + p2 = p; + } + for (p = p1; p <= p2; p += 2) + *p = (*p & 0x88) | ((*p << 4) & 0x70) | ((*p >> 4) & 0x07); +} + +/* is c in range [a-zA-Z0-9_]? */ +static inline int inword(const char c) { return (isalnum(c) || c == '_'); } + +/* does screen address p correspond to character at LH/RH edge of screen? */ +static inline int atedge(const int p) +{ + return (!(p % video_size_row) || !((p + 2) % video_size_row)); +} + +/* constrain v such that l <= v <= u */ +static inline short limit(const int v, const int l, const int u) +{ + return (v < l) ? l : ((v > u) ? u : v); +} + +/* set the current selection. Invoked by ioctl(). */ +int set_selection(const int arg) +{ + unsigned short *args, xs, ys, xe, ye; + int currcons = fg_console; + int sel_mode, new_sel_start, new_sel_end, spc; + char *bp, *obp, *spos; + int i, ps, pe; + char *off = (char *)origin - hwscroll_offset; + + unblank_screen(); + args = (unsigned short *)(arg + 1); + xs = get_fs_word(args++) - 1; + ys = get_fs_word(args++) - 1; + xe = get_fs_word(args++) - 1; + ye = get_fs_word(args++) - 1; + sel_mode = get_fs_word(args); + + xs = limit(xs, 0, video_num_columns - 1); + ys = limit(ys, 0, video_num_lines - 1); + xe = limit(xe, 0, video_num_columns - 1); + ye = limit(ye, 0, video_num_lines - 1); + ps = ys * video_size_row + (xs << 1); + pe = ye * video_size_row + (xe << 1); + + if (ps > pe) /* make sel_start <= sel_end */ + { + int tmp = ps; + ps = pe; + pe = tmp; + } + + switch (sel_mode) + { + case 0: /* character-by-character selection */ + default: + new_sel_start = ps; + new_sel_end = pe; + break; + case 1: /* word-by-word selection */ + spc = isspace(*(off + ps)); + for (new_sel_start = ps; ; ps -= 2) + { + if ((spc && !isspace(*(off + ps))) || + (!spc && !inword(*(off + ps)))) + break; + new_sel_start = ps; + if (!(ps % video_size_row)) + break; + } + spc = isspace(*(off + pe)); + for (new_sel_end = pe; ; pe += 2) + { + if ((spc && !isspace(*(off + pe))) || + (!spc && !inword(*(off + pe)))) + break; + new_sel_end = pe; + if (!((pe + 2) % video_size_row)) + break; + } + break; + case 2: /* line-by-line selection */ + new_sel_start = ps - ps % video_size_row; + new_sel_end = pe + video_size_row + - pe % video_size_row - 2; + break; + } + /* select to end of line if on trailing space */ + if (new_sel_end > new_sel_start && + !atedge(new_sel_end) && isspace(*(off + new_sel_end))) + { + for (pe = new_sel_end + 2; ; pe += 2) + { + if (!isspace(*(off + pe)) || atedge(pe)) + break; + } + if (isspace(*(off + pe))) + new_sel_end = pe; + } + if (sel_cons != currcons) + { + clear_selection(); + sel_cons = currcons; + } + if (sel_start == -1) /* no current selection */ + highlight(sel_cons, new_sel_start, new_sel_end); + else if (new_sel_start == sel_start) + { + if (new_sel_end == sel_end) /* no action required */ + return 0; + else if (new_sel_end > sel_end) /* extend to right */ + highlight(sel_cons, sel_end + 2, new_sel_end); + else /* contract from right */ + highlight(sel_cons, new_sel_end + 2, sel_end); + } + else if (new_sel_end == sel_end) + { + if (new_sel_start < sel_start) /* extend to left */ + highlight(sel_cons, new_sel_start, sel_start - 2); + else /* contract from left */ + highlight(sel_cons, sel_start, new_sel_start - 2); + } + else /* some other case; start selection from scratch */ + { + clear_selection(); + highlight(sel_cons, new_sel_start, new_sel_end); + } + sel_start = new_sel_start; + sel_end = new_sel_end; + obp = bp = sel_buffer; + for (i = sel_start; i <= sel_end; i += 2) + { + spos = (char *)off + i; + *bp++ = *spos; + if (!isspace(*spos)) + obp = bp; + if (! ((i + 2) % video_size_row)) + { + /* strip trailing blanks from line and add newline, + unless non-space at end of line. */ + if (obp != bp) + { + bp = obp; + *bp++ = '\r'; + } + obp = bp; + } + /* check for space, leaving room for next character, possible + newline, and null at end. */ + if (bp - sel_buffer > SEL_BUFFER_SIZE - 3) + break; + } + *bp = '\0'; + return 0; +} + +/* insert the contents of the selection buffer into the queue of the + tty associated with the current console. Invoked by ioctl(). */ +int paste_selection(struct tty_struct *tty) +{ + char *bp = sel_buffer; + + if (! *bp) + return 0; + unblank_screen(); + while (*bp) + { + put_tty_queue(*bp, &tty->read_q); + bp++; + } + TTY_READ_FLUSH(tty); + return 0; +} + +/* remove the current selection highlight, if any, from the console holding + the selection. */ +static void clear_selection() +{ + if (sel_start != -1) + { + highlight(sel_cons, sel_start, sel_end); + sel_start = -1; + } +} +#endif /* CONFIG_SELECTION */ + +/* + * PIO_FONT support. + */ + +#define colourmap ((char *)0xa0000) +#define blackwmap ((char *)0xb0000) +#define cmapsz 8192 +#define seq_port_reg (0x3c4) +#define seq_port_val (0x3c5) +#define gr_port_reg (0x3ce) +#define gr_port_val (0x3cf) + +static int set_get_font(char * arg, int set) +{ +#ifdef CAN_LOAD_EGA_FONTS + int i; + char *charmap; + + /* no use to "load" CGA... */ + + if (video_type == VIDEO_TYPE_EGAC) + charmap = colourmap; + else if (video_type == VIDEO_TYPE_EGAM) + charmap = blackwmap; + else + return -EINVAL; + + i = verify_area(set ? VERIFY_READ : VERIFY_WRITE, (void *)arg, cmapsz); + if (i) + return i; + + cli(); + outb_p( 0x00, seq_port_reg ); /* First, the sequencer */ + outb_p( 0x01, seq_port_val ); /* Synchronous reset */ + outb_p( 0x02, seq_port_reg ); + outb_p( 0x04, seq_port_val ); /* CPU writes only to map 2 */ + outb_p( 0x04, seq_port_reg ); + outb_p( 0x07, seq_port_val ); /* Sequential addressing */ + outb_p( 0x00, seq_port_reg ); + outb_p( 0x03, seq_port_val ); /* Clear synchronous reset */ + + outb_p( 0x04, gr_port_reg ); /* Now, the graphics controller */ + outb_p( 0x02, gr_port_val ); /* select map 2 */ + outb_p( 0x05, gr_port_reg ); + outb_p( 0x00, gr_port_val ); /* disable odd-even addressing */ + outb_p( 0x06, gr_port_reg ); + outb_p( 0x00, gr_port_val ); /* map start at A000:0000 */ + sti(); + + if (set) + for (i=0; i +#include +#include + +u_short key_map[NR_KEYMAPS][NR_KEYS] = { + { + 0x0200, 0x001b, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, + 0x0037, 0x0038, 0x0039, 0x0030, 0x002d, 0x003d, 0x007f, 0x0009, + 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69, + 0x0b6f, 0x0b70, 0x005b, 0x005d, 0x0201, 0x0702, 0x0b61, 0x0b73, + 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x003b, + 0x0027, 0x0060, 0x0700, 0x005c, 0x0b7a, 0x0b78, 0x0b63, 0x0b76, + 0x0b62, 0x0b6e, 0x0b6d, 0x002c, 0x002e, 0x002f, 0x0700, 0x030c, + 0x0703, 0x0020, 0x0207, 0x0100, 0x0101, 0x0102, 0x0103, 0x0104, + 0x0105, 0x0106, 0x0107, 0x0108, 0x0109, 0x0208, 0x0209, 0x0307, + 0x0308, 0x0309, 0x030b, 0x0304, 0x0305, 0x0306, 0x030a, 0x0301, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x003c, 0x010a, + 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x001b, 0x0021, 0x0040, 0x0023, 0x0024, 0x0025, 0x005e, + 0x0026, 0x002a, 0x0028, 0x0029, 0x005f, 0x002b, 0x007f, 0x0009, + 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49, + 0x0b4f, 0x0b50, 0x007b, 0x007d, 0x0201, 0x0702, 0x0b41, 0x0b53, + 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x003a, + 0x0022, 0x007e, 0x0700, 0x007c, 0x0b5a, 0x0b58, 0x0b43, 0x0b56, + 0x0b42, 0x0b4e, 0x0b4d, 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, 0x003e, 0x010a, + 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x020b, 0x0601, 0x0602, 0x0117, 0x0600, 0x020a, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0040, 0x0200, 0x0024, 0x0200, 0x0200, + 0x007b, 0x005b, 0x005d, 0x007d, 0x005c, 0x0200, 0x0200, 0x0200, + 0x0b71, 0x0b77, 0x0b65, 0x0b72, 0x0b74, 0x0b79, 0x0b75, 0x0b69, + 0x0b6f, 0x0b70, 0x0200, 0x007e, 0x0201, 0x0702, 0x0b61, 0x0b73, + 0x0b64, 0x0b66, 0x0b67, 0x0b68, 0x0b6a, 0x0b6b, 0x0b6c, 0x0200, + 0x0200, 0x0200, 0x0700, 0x0200, 0x0b7a, 0x0b78, 0x0b63, 0x0b76, + 0x0b62, 0x0b6e, 0x0b6d, 0x0200, 0x0200, 0x0200, 0x0700, 0x030c, + 0x0703, 0x0200, 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, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0b51, 0x0b57, 0x0b45, 0x0b52, 0x0b54, 0x0b59, 0x0b55, 0x0b49, + 0x0b4f, 0x0b50, 0x0200, 0x0200, 0x0201, 0x0702, 0x0b41, 0x0b53, + 0x0b44, 0x0b46, 0x0b47, 0x0b48, 0x0b4a, 0x0b4b, 0x0b4c, 0x0200, + 0x0200, 0x0200, 0x0700, 0x0200, 0x0b5a, 0x0b58, 0x0b43, 0x0b56, + 0x0b42, 0x0b4e, 0x0b4d, 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0000, 0x001b, 0x001c, 0x001d, 0x001e, + 0x001f, 0x007f, 0x0200, 0x0200, 0x001f, 0x0200, 0x0200, 0x0200, + 0x0011, 0x0017, 0x0005, 0x0012, 0x0014, 0x0019, 0x0015, 0x0009, + 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, 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x010a, + 0x010b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 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, + 0x0302, 0x0303, 0x0300, 0x020c, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x081b, 0x0831, 0x0832, 0x0833, 0x0834, 0x0835, 0x0836, + 0x0837, 0x0838, 0x0839, 0x0830, 0x082d, 0x083d, 0x087f, 0x0809, + 0x0871, 0x0877, 0x0865, 0x0872, 0x0874, 0x0879, 0x0875, 0x0869, + 0x086f, 0x0870, 0x085b, 0x085d, 0x080d, 0x0702, 0x0861, 0x0873, + 0x0864, 0x0866, 0x0867, 0x0868, 0x086a, 0x086b, 0x086c, 0x083b, + 0x0827, 0x0860, 0x0700, 0x085c, 0x087a, 0x0878, 0x0863, 0x0876, + 0x0862, 0x086e, 0x086d, 0x082c, 0x082e, 0x082f, 0x0700, 0x030c, + 0x0703, 0x0820, 0x0207, 0x0500, 0x0501, 0x0502, 0x0503, 0x0504, + 0x0505, 0x0506, 0x0507, 0x0508, 0x0509, 0x0208, 0x0209, 0x0907, + 0x0908, 0x0909, 0x030b, 0x0904, 0x0905, 0x0906, 0x030a, 0x0901, + 0x0902, 0x0903, 0x0900, 0x0310, 0x0206, 0x0200, 0x083c, 0x050a, + 0x050b, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x001c, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x020c, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x020c, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, { + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 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, + 0x0302, 0x0303, 0x0300, 0x0310, 0x0206, 0x0200, 0x0200, 0x0200, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + 0x030e, 0x0702, 0x030d, 0x0200, 0x0701, 0x0205, 0x0114, 0x0603, + 0x0118, 0x0601, 0x0602, 0x0117, 0x0600, 0x0119, 0x0115, 0x0116, + 0x011a, 0x010c, 0x010d, 0x011b, 0x011c, 0x0110, 0x0311, 0x011d, + 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, 0x0200, + }, +}; + +char func_buf[FUNC_BUFSIZE] = { + '\033', '[', '[', 'A', 0, + '\033', '[', '[', 'B', 0, + '\033', '[', '[', 'C', 0, + '\033', '[', '[', 'D', 0, + '\033', '[', '[', 'E', 0, + '\033', '[', '1', '7', '~', 0, + '\033', '[', '1', '8', '~', 0, + '\033', '[', '1', '9', '~', 0, + '\033', '[', '2', '0', '~', 0, + '\033', '[', '2', '1', '~', 0, + '\033', '[', '2', '3', '~', 0, + '\033', '[', '2', '4', '~', 0, + '\033', '[', '2', '5', '~', 0, + '\033', '[', '2', '6', '~', 0, + '\033', '[', '2', '8', '~', 0, + '\033', '[', '2', '9', '~', 0, + '\033', '[', '3', '1', '~', 0, + '\033', '[', '3', '2', '~', 0, + '\033', '[', '3', '3', '~', 0, + '\033', '[', '3', '4', '~', 0, + '\033', '[', '1', '~', 0, + '\033', '[', '2', '~', 0, + '\033', '[', '3', '~', 0, + '\033', '[', '4', '~', 0, + '\033', '[', '5', '~', 0, + '\033', '[', '6', '~', 0, + '\033', '[', 'M', 0, + 0, + 0, + '\033', '[', 'P', 0, + 0, + 0, + 0, + 0, + 0, + 0, +}; + +char *func_table[NR_FUNC] = { + func_buf + 0, + func_buf + 5, + func_buf + 10, + func_buf + 15, + func_buf + 20, + func_buf + 25, + func_buf + 31, + func_buf + 37, + func_buf + 43, + func_buf + 49, + func_buf + 55, + func_buf + 61, + func_buf + 67, + func_buf + 73, + func_buf + 79, + func_buf + 85, + func_buf + 91, + func_buf + 97, + func_buf + 103, + func_buf + 109, + func_buf + 115, + func_buf + 120, + func_buf + 125, + func_buf + 130, + func_buf + 135, + func_buf + 140, + func_buf + 145, + func_buf + 149, + func_buf + 150, + func_buf + 151, + func_buf + 155, + func_buf + 156, + func_buf + 157, + func_buf + 158, + func_buf + 159, + func_buf + 160, +}; + +struct kbdiacr accent_table[MAX_DIACR] = { + {'`', 'A', '\300'}, {'`', 'a', '\340'}, + {'\'', 'A', '\301'}, {'\'', 'a', '\341'}, + {'^', 'A', '\302'}, {'^', 'a', '\342'}, + {'~', 'A', '\303'}, {'~', 'a', '\343'}, + {'"', 'A', '\304'}, {'"', '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'}, + {'`', 'E', '\310'}, {'`', 'e', '\350'}, + {'\'', 'E', '\311'}, {'\'', 'e', '\351'}, + {'^', 'E', '\312'}, {'^', 'e', '\352'}, + {'"', 'E', '\313'}, {'"', 'e', '\353'}, + {'`', 'I', '\314'}, {'`', 'i', '\354'}, + {'\'', 'I', '\315'}, {'\'', 'i', '\355'}, + {'^', 'I', '\316'}, {'^', 'i', '\356'}, + {'"', 'I', '\317'}, {'"', 'i', '\357'}, + {'-', 'D', '\320'}, {'-', 'd', '\360'}, + {'~', 'N', '\321'}, {'~', 'n', '\361'}, + {'`', 'O', '\322'}, {'`', 'o', '\362'}, + {'\'', 'O', '\323'}, {'\'', 'o', '\363'}, + {'^', 'O', '\324'}, {'^', 'o', '\364'}, + {'~', 'O', '\325'}, {'~', 'o', '\365'}, + {'"', 'O', '\326'}, {'"', 'o', '\366'}, + {'/', 'O', '\330'}, {'/', 'o', '\370'}, + {'`', 'U', '\331'}, {'`', 'u', '\371'}, + {'\'', 'U', '\332'}, {'\'', 'u', '\372'}, + {'^', 'U', '\333'}, {'^', 'u', '\373'}, + {'"', 'U', '\334'}, {'"', 'u', '\374'}, + {'\'', 'Y', '\335'}, {'\'', 'y', '\375'}, + {'T', 'H', '\336'}, {'t', 'h', '\376'}, + {'s', 's', '\337'}, {'"', 'y', '\377'}, + {'s', 'z', '\337'}, {'i', 'j', '\377'}, +}; + +unsigned int accent_table_size = 68; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/defkeymap.map b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/defkeymap.map new file mode 100644 index 000000000..47d39abbd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/defkeymap.map @@ -0,0 +1,321 @@ +keycode 0 = +keycode 1 = Escape Escape + alt keycode 1 = Meta_Escape +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 + alt keycode 4 = Meta_three +keycode 5 = four dollar dollar + control keycode 5 = Control_backslash + alt keycode 5 = Meta_four +keycode 6 = five percent + control keycode 6 = Control_bracketright + alt keycode 6 = Meta_five +keycode 7 = six asciicircum + control keycode 7 = Control_asciicircum + alt keycode 7 = Meta_six +keycode 8 = seven ampersand braceleft + control keycode 8 = Control_underscore + alt keycode 8 = Meta_seven +keycode 9 = eight asterisk bracketleft + control keycode 9 = Delete + alt keycode 9 = Meta_eight +keycode 10 = nine parenleft bracketright + alt keycode 10 = Meta_nine +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 +keycode 14 = Delete Delete + alt keycode 14 = Meta_Delete +keycode 15 = Tab Tab + alt keycode 15 = Meta_Tab +keycode 16 = q +keycode 17 = w +keycode 18 = e +keycode 19 = r +keycode 20 = t +keycode 21 = y +keycode 22 = u +keycode 23 = i +keycode 24 = o +keycode 25 = p +keycode 26 = bracketleft braceleft + control keycode 26 = Escape + alt keycode 26 = Meta_bracketleft +keycode 27 = bracketright braceright asciitilde + control keycode 27 = Control_bracketright + alt keycode 27 = Meta_bracketright +keycode 28 = Return + alt keycode 28 = Meta_Control_m +keycode 29 = Control +keycode 30 = a +keycode 31 = s +keycode 32 = d +keycode 33 = f +keycode 34 = g +keycode 35 = h +keycode 36 = j +keycode 37 = k +keycode 38 = l +keycode 39 = semicolon colon + alt keycode 39 = Meta_semicolon +keycode 40 = apostrophe quotedbl + control keycode 40 = Control_g + alt keycode 40 = Meta_apostrophe +keycode 41 = grave asciitilde + control keycode 41 = nul + alt keycode 41 = Meta_grave +keycode 42 = Shift +keycode 43 = backslash bar + control keycode 43 = Control_backslash + alt keycode 43 = Meta_backslash +keycode 44 = z +keycode 45 = x +keycode 46 = c +keycode 47 = v +keycode 48 = b +keycode 49 = n +keycode 50 = m +keycode 51 = comma less + alt keycode 51 = Meta_comma +keycode 52 = period greater + control keycode 52 = Compose + alt keycode 52 = Meta_period +keycode 53 = slash question + control keycode 53 = Delete + alt keycode 53 = Meta_slash +keycode 54 = Shift +keycode 55 = KP_Multiply +keycode 56 = Alt +keycode 57 = space space + control keycode 57 = nul + alt keycode 57 = Meta_space +keycode 58 = Caps_Lock +keycode 59 = F1 F11 Console_13 + control keycode 59 = F1 + alt keycode 59 = Console_1 +keycode 60 = F2 F12 Console_14 + control keycode 60 = F2 + alt keycode 60 = Console_2 +keycode 61 = F3 F13 Console_15 + control keycode 61 = F3 + alt keycode 61 = Console_3 +keycode 62 = F4 F14 Console_16 + control keycode 62 = F4 + alt keycode 62 = Console_4 +keycode 63 = F5 F15 Console_17 + control keycode 63 = F5 + alt keycode 63 = Console_5 +keycode 64 = F6 F16 Console_18 + control keycode 64 = F6 + alt keycode 64 = Console_6 +keycode 65 = F7 F17 Console_19 + control keycode 65 = F7 + alt keycode 65 = Console_7 +keycode 66 = F8 F18 Console_20 + control keycode 66 = F8 + alt keycode 66 = Console_8 +keycode 67 = F9 F19 Console_21 + control keycode 67 = F9 + alt keycode 67 = Console_9 +keycode 68 = F10 F20 Console_22 + control keycode 68 = F10 + alt keycode 68 = Console_10 +keycode 69 = Num_Lock +keycode 70 = Scroll_Lock Show_Memory Show_Registers + control keycode 70 = Show_State + alt keycode 70 = Scroll_Lock +keycode 71 = KP_7 + alt keycode 71 = Ascii_7 +keycode 72 = KP_8 + alt keycode 72 = Ascii_8 +keycode 73 = KP_9 + alt keycode 73 = Ascii_9 +keycode 74 = KP_Subtract +keycode 75 = KP_4 + alt keycode 75 = Ascii_4 +keycode 76 = KP_5 + alt keycode 76 = Ascii_5 +keycode 77 = KP_6 + alt keycode 77 = Ascii_6 +keycode 78 = KP_Add +keycode 79 = KP_1 + alt keycode 79 = Ascii_1 +keycode 80 = KP_2 + alt keycode 80 = Ascii_2 +keycode 81 = KP_3 + alt keycode 81 = Ascii_3 +keycode 82 = KP_0 + alt keycode 82 = Ascii_0 +keycode 83 = KP_Period + altgr control keycode 83 = Boot + control alt keycode 83 = Boot +keycode 84 = Last_Console +keycode 85 = +keycode 86 = less greater bar + alt keycode 86 = Meta_less +keycode 87 = F11 F11 Console_23 + control keycode 87 = F11 + alt keycode 87 = Console_11 +keycode 88 = F12 F12 Console_24 + control keycode 88 = F12 + alt keycode 88 = Console_12 +keycode 89 = +keycode 90 = +keycode 91 = +keycode 92 = +keycode 93 = +keycode 94 = +keycode 95 = +keycode 96 = KP_Enter +keycode 97 = Control +keycode 98 = KP_Divide +keycode 99 = Control_backslash + control keycode 99 = Control_backslash + alt keycode 99 = Control_backslash +keycode 100 = AltGr +keycode 101 = Break +keycode 102 = Find +keycode 103 = Up +keycode 104 = Prior + shift keycode 104 = Scroll_Backward +keycode 105 = Left +keycode 106 = Right +keycode 107 = Select +keycode 108 = Down +keycode 109 = Next + shift keycode 109 = Scroll_Forward +keycode 110 = Insert +keycode 111 = Remove + altgr control keycode 111 = Boot + control alt keycode 111 = Boot +keycode 112 = Macro +keycode 113 = F13 +keycode 114 = F14 +keycode 115 = Help +keycode 116 = Do +keycode 117 = F17 +keycode 118 = KP_MinPlus +keycode 119 = Pause +keycode 120 = +keycode 121 = +keycode 122 = +keycode 123 = +keycode 124 = +keycode 125 = +keycode 126 = +keycode 127 = +string F1 = "\033[[A" +string F2 = "\033[[B" +string F3 = "\033[[C" +string F4 = "\033[[D" +string F5 = "\033[[E" +string F6 = "\033[17~" +string F7 = "\033[18~" +string F8 = "\033[19~" +string F9 = "\033[20~" +string F10 = "\033[21~" +string F11 = "\033[23~" +string F12 = "\033[24~" +string F13 = "\033[25~" +string F14 = "\033[26~" +string F15 = "\033[28~" +string F16 = "\033[29~" +string F17 = "\033[31~" +string F18 = "\033[32~" +string F19 = "\033[33~" +string F20 = "\033[34~" +string Find = "\033[1~" +string Insert = "\033[2~" +string Remove = "\033[3~" +string Select = "\033[4~" +string Prior = "\033[5~" +string Next = "\033[6~" +string Help = "" +string Do = "" +string Macro = "\033[M" +string Pause = "\033[P" +string F21 = "" +string F22 = "" +string F23 = "" +string F24 = "" +string F25 = "" +string F26 = "" +compose '`' 'A' to 'À' +compose '`' 'a' to 'à' +compose '\'' 'A' to 'Á' +compose '\'' 'a' to 'á' +compose '^' 'A' to 'Â' +compose '^' 'a' to 'â' +compose '~' 'A' to 'Ã' +compose '~' 'a' to 'ã' +compose '"' 'A' to 'Ä' +compose '"' 'a' to 'ä' +compose 'O' 'A' to 'Å' +compose 'o' 'a' to 'å' +compose '0' 'A' to 'Å' +compose '0' 'a' to 'å' +compose 'A' 'A' to 'Å' +compose 'a' 'a' to 'å' +compose 'A' 'E' to 'Æ' +compose 'a' 'e' to 'æ' +compose ',' 'C' to 'Ç' +compose ',' 'c' to 'ç' +compose '`' 'E' to 'È' +compose '`' 'e' to 'è' +compose '\'' 'E' to 'É' +compose '\'' 'e' to 'é' +compose '^' 'E' to 'Ê' +compose '^' 'e' to 'ê' +compose '"' 'E' to 'Ë' +compose '"' 'e' to 'ë' +compose '`' 'I' to 'Ì' +compose '`' 'i' to 'ì' +compose '\'' 'I' to 'Í' +compose '\'' 'i' to 'í' +compose '^' 'I' to 'Î' +compose '^' 'i' to 'î' +compose '"' 'I' to 'Ï' +compose '"' 'i' to 'ï' +compose '-' 'D' to 'Ð' +compose '-' 'd' to 'ð' +compose '~' 'N' to 'Ñ' +compose '~' 'n' to 'ñ' +compose '`' 'O' to 'Ò' +compose '`' 'o' to 'ò' +compose '\'' 'O' to 'Ó' +compose '\'' 'o' to 'ó' +compose '^' 'O' to 'Ô' +compose '^' 'o' to 'ô' +compose '~' 'O' to 'Õ' +compose '~' 'o' to 'õ' +compose '"' 'O' to 'Ö' +compose '"' 'o' to 'ö' +compose '/' 'O' to 'Ø' +compose '/' 'o' to 'ø' +compose '`' 'U' to 'Ù' +compose '`' 'u' to 'ù' +compose '\'' 'U' to 'Ú' +compose '\'' 'u' to 'ú' +compose '^' 'U' to 'Û' +compose '^' 'u' to 'û' +compose '"' 'U' to 'Ü' +compose '"' 'u' to 'ü' +compose '\'' 'Y' to 'Ý' +compose '\'' 'y' to 'ý' +compose 'T' 'H' to 'Þ' +compose 't' 'h' to 'þ' +compose 's' 's' to 'ß' +compose '"' 'y' to 'ÿ' +compose 's' 'z' to 'ß' +compose 'i' 'j' to 'ÿ' diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/diacr.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/diacr.h new file mode 100644 index 000000000..1c1a3ff05 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/diacr.h @@ -0,0 +1,8 @@ +#ifndef _DIACR_H +#define _DIACR_H +#include + +extern struct kbdiacr accent_table[]; +extern unsigned int accent_table_size; + +#endif /* _DIACR_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/kbd_kern.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/kbd_kern.h new file mode 100644 index 000000000..4f852725c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/kbd_kern.h @@ -0,0 +1,107 @@ +#ifndef _KBD_KERN_H +#define _KBD_KERN_H + +#include +#define set_leds() mark_bh(KEYBOARD_BH) + +#include + +/* + * kbd->xxx contains the VC-local things (flag settings etc..) + * + * Note: externally visible are LED_SCR, LED_NUM, LED_CAP defined in kd.h + * The code in KDGETLED / KDSETLED depends on the internal and + * external order being the same. + * + * Note: lockstate is used as index in the array key_map. + */ +struct kbd_struct { + unsigned char ledstate; /* 3 bits */ + unsigned char default_ledstate; +#define VC_SCROLLOCK 0 /* scroll-lock mode */ +#define VC_NUMLOCK 1 /* numeric lock mode */ +#define VC_CAPSLOCK 2 /* capslock mode */ + + unsigned char lockstate; /* 4 bits - must be in 0..15 */ +#define VC_SHIFTLOCK KG_SHIFT /* shift lock mode */ +#define VC_ALTGRLOCK KG_ALTGR /* altgr lock mode */ +#define VC_CTRLLOCK KG_CTRL /* control lock mode */ +#define VC_ALTLOCK KG_ALT /* alt lock mode */ + + unsigned char modeflags; +#define VC_APPLIC 0 /* application key mode */ +#define VC_CKMODE 1 /* cursor key mode */ +#define VC_REPEAT 2 /* keyboard repeat */ +#define VC_CRLF 3 /* 0 - enter sends CR, 1 - enter sends CRLF */ +#define VC_META 4 /* 0 - meta, 1 - meta=prefix with ESC */ +#define VC_PAUSE 5 /* pause key pressed - unused */ +#define VC_RAW 6 /* raw (scancode) mode */ +#define VC_MEDIUMRAW 7 /* medium raw (keycode) mode */ +}; + +extern struct kbd_struct kbd_table[]; + + +extern unsigned long kbd_init(unsigned long); + +extern inline int vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + return ((kbd->ledstate >> flag) & 1); +} + +extern inline int vc_kbd_lock(struct kbd_struct * kbd, int flag) +{ + return ((kbd->lockstate >> flag) & 1); +} + +extern inline int vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + return ((kbd->modeflags >> flag) & 1); +} + +extern inline void set_vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + kbd->ledstate |= 1 << flag; +} + +extern inline void set_vc_kbd_lock(struct kbd_struct * kbd, int flag) +{ + kbd->lockstate |= 1 << flag; +} + +extern inline void set_vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + kbd->modeflags |= 1 << flag; +} + +extern inline void clr_vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + kbd->ledstate &= ~(1 << flag); +} + +extern inline void clr_vc_kbd_lock(struct kbd_struct * kbd, int flag) +{ + kbd->lockstate &= ~(1 << flag); +} + +extern inline void clr_vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + kbd->modeflags &= ~(1 << flag); +} + +extern inline void chg_vc_kbd_led(struct kbd_struct * kbd, int flag) +{ + kbd->ledstate ^= 1 << flag; +} + +extern inline void chg_vc_kbd_lock(struct kbd_struct * kbd, int flag) +{ + kbd->lockstate ^= 1 << flag; +} + +extern inline void chg_vc_kbd_mode(struct kbd_struct * kbd, int flag) +{ + kbd->modeflags ^= 1 << flag; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/keyboard.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/keyboard.c new file mode 100644 index 000000000..9bad94db4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/keyboard.c @@ -0,0 +1,870 @@ +/* + * linux/kernel/chr_drv/keyboard.c + * + * Keyboard driver for Linux v0.99 using Latin-1. + * + * Written for linux by Johan Myreen as a translation from + * 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 + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include "kbd_kern.h" +#include "diacr.h" + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +#define KBD_DEFLEDS (1 << VC_NUMLOCK) +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +/* + * The default IO slowdown is doing 'inb()'s from 0x61, which should be + * safe. But as that is the keyboard controller chip address, we do our + * slowdowns here by doing short jumps: the keyboard controller should + * be able to keep up + */ +#define REALLY_SLOW_IO +#define SLOW_IO_BY_JUMPING +#include +#include + +extern void do_keyboard_interrupt(void); +extern void ctrl_alt_del(void); +extern void change_console(unsigned int new_console); +extern void scrollback(int); +extern void scrollfront(int); + +#define fake_keyboard_interrupt() \ +__asm__ __volatile__("int $0x21") + +unsigned char kbd_read_mask = 0x01; /* modified by psaux.c */ + +/* + * 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, }; +/* keyboard key bitmap */ +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; +static struct tty_struct * tty = NULL; + +/* used only by send_data - set by keyboard_interrupt */ +static volatile unsigned char acknowledge = 0; +static volatile unsigned char resend = 0; + +typedef void (*k_hand)(unsigned char value, char up_flag); +typedef void (k_handfn)(unsigned char value, char up_flag); + +static k_handfn + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase; + +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_lock, do_lowercase +}; + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, NR_FUNC - 1, 14, 17, 4, 255, 3, NR_SHIFT, + 255, 9, 3, 255 +}; + +const int NR_TYPES = SIZE(max_vals); + +static void put_queue(int); +static unsigned char handle_diacr(unsigned char); + +/* pt_regs - set by keyboard_interrupt(), used by show_ptregs() */ +static struct pt_regs * pt_regs; + +static int got_break = 0; + +static inline void kb_wait(void) +{ + int i; + + for (i=0; i<0x10000; i++) + if ((inb_p(0x64) & 0x02) == 0) + break; +} + +static inline void send_cmd(unsigned char c) +{ + kb_wait(); + outb(c,0x64); +} + +/* + * 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) + +#define E1_PAUSE (E0_BASE+23) + +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 int prev_scancode = 0; /* remember E0, E1 */ + char up_flag; /* 0 or 0200 */ + char raw_mode; + + pt_regs = (struct pt_regs *) int_pt_regs; + send_cmd(0xAD); /* disable keyboard */ + kb_wait(); + if ((inb_p(0x64) & kbd_read_mask) != 0x01) + goto end_kbd_intr; + scancode = inb(0x60); + mark_bh(KEYBOARD_BH); + if (scancode == 0xfa) { + acknowledge = 1; + goto end_kbd_intr; + } else if (scancode == 0xfe) { + resend = 1; + goto end_kbd_intr; + } + tty = TTY_TABLE(0); + kbd = kbd_table + fg_console; + if ((raw_mode = vc_kbd_mode(kbd,VC_RAW))) { + put_queue(scancode); + /* 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 == 0xe0 || scancode == 0xe1) { + prev_scancode = scancode; + goto end_kbd_intr; + } + + /* + * Convert scancode to keysym, using prev_scancode. + */ + up_flag = (scancode & 0200); + scancode &= 0x7f; + + if (prev_scancode) { + /* + * usually it will be 0xe0, but a Pause key generates + * e1 1d 45 e1 9d c5 when pressed, and nothing when released + */ + if (prev_scancode != 0xe0) { + if (prev_scancode == 0xe1 && scancode == 0x1d) { + prev_scancode = 0x100; + goto end_kbd_intr; + } else if (prev_scancode == 0x100 && scancode == 0x45) { + scancode = E1_PAUSE; + prev_scancode = 0; + } else { + printk("keyboard: unknown e1 escape sequence\n"); + prev_scancode = 0; + goto end_kbd_intr; + } + } else { + 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; + } + + /* + * 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: earlier kernels had a bug and did not pass the up/down + * bit to applications.) + */ + + if (up_flag) { + clear_bit(scancode, key_down); + rep = 0; + } else + rep = set_bit(scancode, key_down); + + if (raw_mode) + goto end_kbd_intr; + + if (vc_kbd_mode(kbd, VC_MEDIUMRAW)) { + put_queue(scancode + up_flag); + 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 + * with slow applications and under heavy loads. + */ + if (!rep || + (vc_kbd_mode(kbd,VC_REPEAT) && tty && + (L_ECHO(tty) || (EMPTY(&tty->secondary) && EMPTY(&tty->read_q))))) + { + u_short key_code; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = shift_state ^ kbd->lockstate; + + key_code = key_map[shift_final][scancode]; + type = KTYP(key_code); + + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd,VC_CAPSLOCK)) + key_code = key_map[shift_final ^ (1<read_q; + + if (LEFT(qp)) { + qp->buf[qp->head] = ch; + INC(qp->head); + } +} + +static void puts_queue(char *cp) +{ + struct tty_queue *qp; + char ch; + + /* why interruptible here, plain wake_up above? */ + wake_up_interruptible(&keypress_wait); + if (!tty) + return; + qp = &tty->read_q; + + while ((ch = *(cp++)) != 0) { + if (LEFT(qp)) { + qp->buf[qp->head] = ch; + INC(qp->head); + } + } +} + +static void applkey(int key, char mode) +{ + static char buf[] = { 0x1b, 'O', 0x00, 0x00 }; + + buf[1] = (mode ? 'O' : '['); + buf[2] = key; + puts_queue(buf); +} + +static void enter(void) +{ + put_queue(13); + if (vc_kbd_mode(kbd,VC_CRLF)) + put_queue(10); +} + +static void caps_toggle(void) +{ + if (rep) + return; + chg_vc_kbd_led(kbd,VC_CAPSLOCK); +} + +static void caps_on(void) +{ + if (rep) + return; + set_vc_kbd_led(kbd,VC_CAPSLOCK); +} + +static void show_ptregs(void) +{ + if (!pt_regs) + return; + printk("\n"); + printk("EIP: %04x:%08lx",0xffff & pt_regs->cs,pt_regs->eip); + if (pt_regs->cs & 3) + printk(" ESP: %04x:%08lx",0xffff & pt_regs->ss,pt_regs->esp); + printk(" EFLAGS: %08lx\n",pt_regs->eflags); + printk("EAX: %08lx EBX: %08lx ECX: %08lx EDX: %08lx\n", + pt_regs->orig_eax,pt_regs->ebx,pt_regs->ecx,pt_regs->edx); + printk("ESI: %08lx EDI: %08lx EBP: %08lx", + pt_regs->esi, pt_regs->edi, pt_regs->ebp); + printk(" DS: %04x ES: %04x FS: %04x GS: %04x\n", + 0xffff & pt_regs->ds,0xffff & pt_regs->es, + 0xffff & pt_regs->fs,0xffff & pt_regs->gs); +} + +static void hold(void) +{ + if (rep || !tty) + return; + + /* + * Note: SCROLLOCK wil be set (cleared) by stop_tty (start_tty); + * these routines are also activated by ^S/^Q. + * (And SCROLLOCK can also be set by the ioctl KDSETLED.) + */ + if (tty->stopped) + start_tty(tty); + else + stop_tty(tty); +} + +#if 0 +/* unused at present - and the VC_PAUSE bit is not used anywhere either */ +static void pause(void) +{ + chg_vc_kbd_mode(kbd,VC_PAUSE); +} +#endif + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) { + applkey('P', 1); + return; + } + if (!rep) /* no autorepeat for numlock, ChN */ + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ + /* pressing alt-printscreen switches to the last used console, ChN */ + want_console = last_console; +} + +static void send_intr(void) +{ + got_break = 1; +} + +static void scrll_forw(void) +{ + scrollfront(0); +} + +static void scrll_back(void) +{ + scrollback(0); +} + +static void boot_it(void) +{ + ctrl_alt_del(); +} + +static void compose(void) +{ + dead_key_next = 1; +} + +static void do_spec(unsigned char value, char up_flag) +{ + typedef void (*fnp)(void); + fnp fn_table[] = { + NULL, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scrll_forw, scrll_back, + boot_it, caps_on, compose + }; + + if (up_flag) + return; + if (value >= SIZE(fn_table)) + return; + if (!fn_table[value]) + return; + fn_table[value](); +} + +static void do_lowercase(unsigned char value, char up_flag) +{ + printk("keyboard.c: do_lowercase was called - impossible\n"); +} + +static void do_self(unsigned char value, char up_flag) +{ + if (up_flag) + return; /* no action, if this is a key release */ + + if (diacr) + value = handle_diacr(value); + + if (dead_key_next) { + dead_key_next = 0; + diacr = value; + return; + } + + put_queue(value); +} + +#define A_GRAVE '`' +#define A_ACUTE '\'' +#define A_CFLEX '^' +#define A_TILDE '~' +#define A_DIAER '"' +static unsigned char ret_diacr[] = + {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. */ + +static void do_dead(unsigned char value, char up_flag) +{ + if (up_flag) + return; + + value = ret_diacr[value]; + if (diacr == value) { /* pressed twice */ + diacr = 0; + put_queue(value); + return; + } + diacr = value; +} + + +/* If space is pressed, return the character corresponding the pending */ +/* dead key, otherwise try to combine the two. */ + +unsigned char handle_diacr(unsigned char ch) +{ + int d = diacr; + int i; + + diacr = 0; + if (ch == ' ') + return d; + + for (i = 0; i < accent_table_size; 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) +{ + if (up_flag) + return; + want_console = value; +} + +static void do_fn(unsigned char value, char up_flag) +{ + if (up_flag) + return; + 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?"; + + if (up_flag) + return; /* no action, if this is a key release */ + + /* kludge... shift forces cursor/number keys */ + if (vc_kbd_mode(kbd,VC_APPLIC) && !k_down[KG_SHIFT]) { + applkey(app_map[value], 1); + return; + } + + if (!vc_kbd_led(kbd,VC_NUMLOCK)) + switch (value) { + case KVAL(K_PCOMMA): + case KVAL(K_PDOT): + do_fn(KVAL(K_REMOVE), 0); + return; + case KVAL(K_P0): + do_fn(KVAL(K_INSERT), 0); + return; + case KVAL(K_P1): + do_fn(KVAL(K_SELECT), 0); + return; + case KVAL(K_P2): + do_cur(KVAL(K_DOWN), 0); + return; + case KVAL(K_P3): + do_fn(KVAL(K_PGDN), 0); + return; + case KVAL(K_P4): + do_cur(KVAL(K_LEFT), 0); + return; + case KVAL(K_P6): + do_cur(KVAL(K_RIGHT), 0); + return; + case KVAL(K_P7): + do_fn(KVAL(K_FIND), 0); + return; + case KVAL(K_P8): + do_cur(KVAL(K_UP), 0); + return; + case KVAL(K_P9): + do_fn(KVAL(K_PGUP), 0); + return; + case KVAL(K_P5): + applkey('G', vc_kbd_mode(kbd, VC_APPLIC)); + return; + } + + put_queue(pad_chars[value]); + if (value == KVAL(K_PENTER) && vc_kbd_mode(kbd, VC_CRLF)) + put_queue(10); +} + +static void do_cur(unsigned char value, char up_flag) +{ + static char *cur_chars = "BDCA"; + if (up_flag) + return; + + applkey(cur_chars[value], vc_kbd_mode(kbd,VC_CKMODE)); +} + +static void do_shift(unsigned char value, char up_flag) +{ + int old_state = shift_state; + + if (rep) + return; + + /* kludge... */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + clr_vc_kbd_led(kbd, VC_CAPSLOCK); + } + + if (up_flag) { + /* handle the case that two shift or control + keys are depressed simultaneously */ + if (k_down[value]) + k_down[value]--; + } else + k_down[value]++; + + if (k_down[value]) + shift_state |= (1 << value); + else + shift_state &= ~ (1 << value); + + /* kludge */ + if (up_flag && shift_state != old_state && npadch != -1) { + put_queue(npadch); + 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< 0); + return 0; +} + +/* + * This routine is the bottom half of the keyboard interrupt + * routine, and runs with all interrupts enabled. It does + * console changing, led setting and copy_to_cooked, which can + * take a reasonably long time. + * + * Aside from timing (which isn't really that important for + * keyboard interrupts as they happen often), using the software + * interrupt routines for this thing allows us to easily mask + * this when we don't want any of the above to happen. Not yet + * used, but this allows for easy and efficient race-condition + * prevention later on. + */ +static void kbd_bh(void * unused) +{ + static unsigned char old_leds = 0xff; + unsigned char leds = kbd_table[fg_console].ledstate; + + if (leds != old_leds) { + old_leds = leds; + if (!send_data(0xed) || !send_data(leds)) + send_data(0xf4); /* re-enable kbd if any errors */ + } + if (want_console >= 0) { + if (want_console != fg_console) { + last_console = fg_console; + change_console(want_console); + } + want_console = -1; + } + if (got_break) { + if (tty && !I_IGNBRK(tty)) { + if (I_BRKINT(tty)) { + flush_input(tty); + flush_output(tty); + if (tty->pgrp > 0) + kill_pg(tty->pgrp, SIGINT, 1); + } else { + cli(); + if (LEFT(&tty->read_q) >= 2) { + set_bit(tty->read_q.head, + &tty->readq_flags); + put_queue(TTY_BREAK); + put_queue(0); + } + sti(); + } + } + got_break = 0; + } + do_keyboard_interrupt(); + cli(); + if ((inb_p(0x64) & kbd_read_mask) == 0x01) + fake_keyboard_interrupt(); + sti(); +} + +long no_idt[2] = {0, 0}; + +/* + * This routine reboots the machine by asking the keyboard + * controller to pulse the reset-line low. We try that for a while, + * and if it doesn't work, we do some other stupid things. + */ +void hard_reset_now(void) +{ + int i, j; + extern unsigned long pg0[1024]; + + sti(); +/* rebooting needs to touch the page at absolute addr 0 */ + pg0[0] = 7; + *((unsigned short *)0x472) = 0x1234; + for (;;) { + for (i=0; i<100; i++) { + kb_wait(); + for(j = 0; j < 100000 ; j++) + /* nothing */; + outb(0xfe,0x64); /* pulse reset low */ + } + __asm__("\tlidt _no_idt"); + } +} + +unsigned long kbd_init(unsigned long kmem_start) +{ + int i; + struct kbd_struct * kbd; + + kbd = kbd_table + 0; + for (i = 0 ; i < NR_CONSOLES ; i++,kbd++) { + kbd->ledstate = KBD_DEFLEDS; + kbd->default_ledstate = KBD_DEFLEDS; + kbd->lockstate = KBD_DEFLOCK; + kbd->modeflags = KBD_DEFMODE; + } + + bh_base[KEYBOARD_BH].routine = kbd_bh; + request_irq(KEYBOARD_IRQ,keyboard_interrupt); + mark_bh(KEYBOARD_BH); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/lp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/lp.c new file mode 100644 index 000000000..ec4029758 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/lp.c @@ -0,0 +1,461 @@ +/* + * Copyright (C) 1992 by Jim Weigand and Linus Torvalds + * Copyright (C) 1992,1993 by Michael K. Johnson + * - Thanks much to Gunter Windau for pointing out to me where the error + * checking ought to be. + * Copyright (C) 1993 by Nigel Gamble (added interrupt code) + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * All my debugging code assumes that you debug with only one printer at + * a time. RWWH + */ + +#undef LP_DEBUG + +static int lp_reset(int minor) +{ + int testvalue; + unsigned char command; + + command = LP_PSELECP | LP_PINITP; + + /* reset value */ + outb_p(0, LP_C(minor)); + for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++) + ; + outb_p(command, LP_C(minor)); + return LP_S(minor); +} + +#ifdef LP_DEBUG +static int lp_max_count = 1; +#endif + +static int lp_char_polled(char lpchar, int minor) +{ + int status = 0, wait = 0; + unsigned long count = 0; + + do { + status = LP_S(minor); + count ++; + if(need_resched) + schedule(); + } while(!(status & LP_PBUSY) && count < LP_CHAR(minor)); + + if (count == LP_CHAR(minor)) { + return 0; + /* we timed out, and the character was /not/ printed */ + } +#ifdef LP_DEBUG + if (count > lp_max_count) { + printk("lp success after %d counts.\n",count); + lp_max_count=count; + } +#endif + outb_p(lpchar, LP_B(minor)); + /* must wait before taking strobe high, and after taking strobe + low, according spec. Some printers need it, others don't. */ + while(wait != LP_WAIT(minor)) wait++; + /* control port takes strobe high */ + outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor ))); + while(wait) wait--; + /* take strobe low */ + outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor ))); + + return 1; +} + +static int lp_char_interrupt(char lpchar, int minor) +{ + int wait = 0; + unsigned char status; + + + if (!((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY) + || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY) + || !((status = LP_S(minor)) & LP_PACK) || (status & LP_PBUSY)) { + + outb_p(lpchar, LP_B(minor)); + /* must wait before taking strobe high, and after taking strobe + low, according spec. Some printers need it, others don't. */ + while(wait != LP_WAIT(minor)) wait++; + /* control port takes strobe high */ + outb_p(( LP_PSELECP | LP_PINITP | LP_PSTROBE ), ( LP_C( minor ))); + while(wait) wait--; + /* take strobe low */ + outb_p(( LP_PSELECP | LP_PINITP ), ( LP_C( minor ))); + return 1; + } + + return 0; +} + +#ifdef LP_DEBUG + unsigned int lp_total_chars = 0; + unsigned int lp_last_call = 0; +#endif + +static void lp_interrupt(int irq) +{ + struct lp_struct *lp = &lp_table[0]; + struct lp_struct *lp_end = &lp_table[LP_NO]; + + while (irq != lp->irq) { + if (++lp >= lp_end) + return; + } + + wake_up(&lp->lp_wait_q); +} + +static int lp_write_interrupt(struct inode * inode, struct file * file, char * buf, int count) +{ + unsigned int minor = MINOR(inode->i_rdev); + unsigned long copy_size; + unsigned long total_bytes_written = 0; + unsigned long bytes_written; + struct lp_struct *lp = &lp_table[minor]; + unsigned char status; + + do { + bytes_written = 0; + copy_size = (count <= LP_BUFFER_SIZE ? count : LP_BUFFER_SIZE); + memcpy_fromfs(lp->lp_buffer, buf, copy_size); + + while (copy_size) { + if (lp_char_interrupt(lp->lp_buffer[bytes_written], minor)) { + --copy_size; + ++bytes_written; + } else { + if (!((status = LP_S(minor)) & LP_PERRORP)) { + int rc = total_bytes_written + bytes_written; + + if ((status & LP_POUTPA)) { + printk("lp%d out of paper\n", minor); + if (!rc) + rc = -ENOSPC; + } else if (!(status & LP_PSELECD)) { + printk("lp%d off-line\n", minor); + if (!rc) + rc = -EIO; + } else { + printk("lp%d printer error\n", minor); + if (!rc) + rc = -EIO; + } + if(LP_F(minor) & LP_ABORT) + return rc; + } + cli(); + outb_p((LP_PSELECP|LP_PINITP|LP_PINTEN), (LP_C(minor))); + status = LP_S(minor); + if (!(status & LP_PACK) || (status & LP_PBUSY)) { + outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor))); + sti(); + continue; + } + current->timeout = jiffies + LP_TIMEOUT_INTERRUPT; + interruptible_sleep_on(&lp->lp_wait_q); + outb_p((LP_PSELECP|LP_PINITP), (LP_C(minor))); + if (current->signal & ~current->blocked) { + if (total_bytes_written + bytes_written) + return total_bytes_written + bytes_written; + else + return -EINTR; + } + } + } + + total_bytes_written += bytes_written; + buf += bytes_written; + count -= bytes_written; + + } while (count > 0); + + return total_bytes_written; +} + +static int lp_write_polled(struct inode * inode, struct file * file, + char * buf, int count) +{ + int retval; + unsigned int minor = MINOR(inode->i_rdev); + char c, *temp = buf; + +#ifdef LP_DEBUG + if (jiffies-lp_last_call > LP_TIME(minor)) { + lp_total_chars = 0; + lp_max_count = 1; + } + lp_last_call = jiffies; +#endif + + temp = buf; + while (count > 0) { + c = get_fs_byte(temp); + retval = lp_char_polled(c, minor); + /* only update counting vars if character was printed */ + if (retval) { count--; temp++; +#ifdef LP_DEBUG + lp_total_chars++; +#endif + } + if (!retval) { /* if printer timed out */ + int status = LP_S(minor); + + if (status & LP_POUTPA) { + printk("lp%d out of paper\n", minor); + if(LP_F(minor) & LP_ABORT) + return temp-buf?temp-buf:-ENOSPC; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } else + if (!(status & LP_PSELECD)) { + printk("lp%d off-line\n", minor); + if(LP_F(minor) & LP_ABORT) + return temp-buf?temp-buf:-EIO; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } else + /* not offline or out of paper. on fire? */ + if (!(status & LP_PERRORP)) { + printk("lp%d on fire\n", minor); + if(LP_F(minor) & LP_ABORT) + return temp-buf?temp-buf:-EFAULT; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIMEOUT_POLLED; + schedule(); + } + + /* check for signals before going to sleep */ + if (current->signal & ~current->blocked) { + if (temp != buf) + return temp-buf; + else + return -EINTR; + } +#ifdef LP_DEBUG + printk("lp sleeping at %d characters for %d jiffies\n", + lp_total_chars, LP_TIME(minor)); + lp_total_chars=0; +#endif + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + LP_TIME(minor); + schedule(); + } + } + return temp-buf; +} + +static int lp_write(struct inode * inode, struct file * file, char * buf, int count) +{ + if (LP_IRQ(MINOR(inode->i_rdev))) + return lp_write_interrupt(inode, file, buf, count); + else + return lp_write_polled(inode, file, buf, count); +} + +static int lp_lseek(struct inode * inode, struct file * file, + off_t offset, int origin) +{ + return -ESPIPE; +} + +static int lp_open(struct inode * inode, struct file * file) +{ + unsigned int minor = MINOR(inode->i_rdev); + int ret; + unsigned int irq; + struct sigaction sa; + + if (minor >= LP_NO) + return -ENODEV; + if ((LP_F(minor) & LP_EXIST) == 0) + return -ENODEV; + if (LP_F(minor) & LP_BUSY) + return -EBUSY; + + if ((irq = LP_IRQ(minor))) { + lp_table[minor].lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); + if (!lp_table[minor].lp_buffer) + return -ENOMEM; + + sa.sa_handler = lp_interrupt; + sa.sa_flags = SA_INTERRUPT; + sa.sa_mask = 0; + sa.sa_restorer = NULL; + ret = irqaction(irq, &sa); + if (ret) { + kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); + lp_table[minor].lp_buffer = NULL; + printk("lp%d unable to use interrupt %d, error %d\n", minor, irq, ret); + return ret; + } + } + + LP_F(minor) |= LP_BUSY; + + return 0; +} + +static void lp_release(struct inode * inode, struct file * file) +{ + unsigned int minor = MINOR(inode->i_rdev); + unsigned int irq; + + if ((irq = LP_IRQ(minor))) { + free_irq(irq); + kfree_s(lp_table[minor].lp_buffer, LP_BUFFER_SIZE); + lp_table[minor].lp_buffer = NULL; + } + + LP_F(minor) &= ~LP_BUSY; +} + + +static int lp_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + unsigned int minor = MINOR(inode->i_rdev); + int retval = 0; + +#ifdef LP_DEBUG + printk("lp%d ioctl, cmd: 0x%x, arg: 0x%x\n", minor, cmd, arg); +#endif + if (minor >= LP_NO) + return -ENODEV; + if ((LP_F(minor) & LP_EXIST) == 0) + return -ENODEV; + switch ( cmd ) { + case LPTIME: + LP_TIME(minor) = arg; + break; + case LPCHAR: + LP_CHAR(minor) = arg; + break; + case LPABORT: + if (arg) + LP_F(minor) |= LP_ABORT; + else + LP_F(minor) &= ~LP_ABORT; + break; + case LPWAIT: + LP_WAIT(minor) = arg; + break; + case LPSETIRQ: { + int oldirq; + int newirq = arg; + struct lp_struct *lp = &lp_table[minor]; + struct sigaction sa; + + if (!suser()) + return -EPERM; + + oldirq = LP_IRQ(minor); + + /* Allocate buffer now if we are going to need it */ + if (!oldirq && newirq) { + lp->lp_buffer = (char *) kmalloc(LP_BUFFER_SIZE, GFP_KERNEL); + if (!lp->lp_buffer) + return -ENOMEM; + } + + if (oldirq) { + free_irq(oldirq); + } + if (newirq) { + /* Install new irq */ + sa.sa_handler = lp_interrupt; + sa.sa_flags = SA_INTERRUPT; + sa.sa_mask = 0; + sa.sa_restorer = NULL; + if ((retval = irqaction(newirq, &sa))) { + if (oldirq) { + /* restore old irq */ + irqaction(oldirq, &sa); + } else { + /* We don't need the buffer */ + kfree_s(lp->lp_buffer, LP_BUFFER_SIZE); + lp->lp_buffer = NULL; + } + return retval; + } + } + if (oldirq && !newirq) { + /* We don't need the buffer */ + kfree_s(lp->lp_buffer, LP_BUFFER_SIZE); + lp->lp_buffer = NULL; + } + LP_IRQ(minor) = newirq; + lp_reset(minor); + break; + } + case LPGETIRQ: + retval = LP_IRQ(minor); + break; + default: + retval = -EINVAL; + } + return retval; +} + + +static struct file_operations lp_fops = { + lp_lseek, + NULL, /* lp_read */ + lp_write, + NULL, /* lp_readdir */ + NULL, /* lp_select */ + lp_ioctl, + NULL, /* lp_mmap */ + lp_open, + lp_release +}; + +long lp_init(long kmem_start) +{ + int offset = 0; + unsigned int testvalue = 0; + int count = 0; + + if (register_chrdev(LP_MAJOR,"lp",&lp_fops)) { + printk("unable to get major %d for line printer\n", LP_MAJOR); + return kmem_start; + } + /* take on all known port values */ + for (offset = 0; offset < LP_NO; offset++) { + /* write to port & read back to check */ + outb_p( LP_DUMMY, LP_B(offset)); + for (testvalue = 0 ; testvalue < LP_DELAY ; testvalue++) + ; + testvalue = inb_p(LP_B(offset)); + if (testvalue != 255) { + LP_F(offset) |= LP_EXIST; + lp_reset(offset); + printk("lp_init: lp%d exists (%d), ", offset, testvalue); + if (LP_IRQ(offset)) + printk("using IRQ%d\n", LP_IRQ(offset)); + else + printk("using polling driver\n"); + count++; + } + } + if (count == 0) + printk("lp_init: no lp devices found\n"); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mem.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mem.c new file mode 100644 index 000000000..9d461363d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mem.c @@ -0,0 +1,426 @@ +/* + * linux/kernel/chr_drv/mem.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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) +{ + return -EIO; +} + +static int write_ram(struct inode * inode, struct file * file,char * buf, int count) +{ + return -EIO; +} + +static int read_mem(struct inode * inode, struct file * file,char * buf, int count) +{ + unsigned long p = file->f_pos; + int read; + + if (count < 0) + return -EINVAL; + if (p >= high_memory) + return 0; + if (count > high_memory - p) + count = high_memory - p; + read = 0; + while (p < PAGE_SIZE && count > 0) { + put_fs_byte(0,buf); + buf++; + p++; + count--; + read++; + } + memcpy_tofs(buf,(void *) p,count); + read += count; + file->f_pos += read; + return read; +} + +static int write_mem(struct inode * inode, struct file * file,char * buf, int count) +{ + unsigned long p = file->f_pos; + int written; + + if (count < 0) + return -EINVAL; + if (p >= high_memory) + return 0; + if (count > high_memory - p) + count = high_memory - p; + written = 0; + while (p < PAGE_SIZE && count > 0) { + /* Hmm. Do something? */ + buf++; + p++; + count--; + written++; + } + memcpy_fromfs((void *) p,buf,count); + written += count; + file->f_pos += written; + return count; +} + +static int mmap_mem(struct inode * inode, struct file * file, + unsigned long addr, size_t len, int prot, unsigned long off) +{ + struct vm_area_struct * mpnt; + + if (off & 0xfff || off + len < off) + return -ENXIO; + if (x86 > 3 && off >= high_memory) + prot |= PAGE_PCD; + if (remap_page_range(addr, off, 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(struct vm_area_struct), 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, NULL, NULL); + return 0; +} + +static int read_kmem(struct inode *inode, struct file *file, char *buf, int count) +{ + int read1, read2; + + read1 = read_mem(inode, file, buf, count); + if (read1 < 0) + return read1; + read2 = vread(buf + read1, (char *) file->f_pos, count - read1); + if (read2 < 0) + return read2; + file->f_pos += read2; + return read1 + read2; +} + +static int read_port(struct inode * inode,struct file * file,char * buf, int count) +{ + unsigned int i = file->f_pos; + char * tmp = buf; + + while (count-- > 0 && i < 65536) { + put_fs_byte(inb(i),tmp); + i++; + tmp++; + } + file->f_pos = i; + return tmp-buf; +} + +static int write_port(struct inode * inode,struct file * file,char * buf, int count) +{ + unsigned int i = file->f_pos; + char * tmp = buf; + + while (count-- > 0 && i < 65536) { + outb(get_fs_byte(tmp),i); + i++; + tmp++; + } + file->f_pos = i; + return tmp-buf; +} + +static int read_null(struct inode * node,struct file * file,char * buf,int count) +{ + return 0; +} + +static int write_null(struct inode * inode,struct file * file,char * buf, int count) +{ + return count; +} + +static int read_zero(struct inode * node,struct file * file,char * buf,int count) +{ + int left; + + for (left = count; left > 0; left--) { + put_fs_byte(0,buf); + buf++; + } + return count; +} + +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 = NULL; + mpnt->vm_offset = off; + mpnt->vm_ops = NULL; + insert_vm_struct(current, mpnt); + merge_segments(current->mmap, ignoff_mergep, inode); + return 0; +} + +static int read_full(struct inode * node,struct file * file,char * buf,int count) +{ + return count; +} + +static int write_full(struct inode * inode,struct file * file,char * buf, int count) +{ + return -ENOSPC; +} + +/* + * Special lseek() function for /dev/null and /dev/zero. Most notably, you can fopen() + * both devices with "a" now. This was previously impossible. SRB. + */ + +static int null_lseek(struct inode * inode, struct file * file, off_t offset, int orig) +{ + return file->f_pos=0; +} +/* + * The memory devices use the full 32 bits of the offset, and so we cannot + * check against negative addresses: they are ok. The return value is weird, + * though, in that case (0). + * + * also note that seeking relative to the "end of file" isn't supported: + * it has no meaning, so it returns -EINVAL. + */ +static int memory_lseek(struct inode * inode, struct file * file, off_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } + if (file->f_pos < 0) + return 0; + return file->f_pos; +} + +#define write_kmem write_mem +#define mmap_kmem mmap_mem +#define zero_lseek null_lseek +#define write_zero write_null + +static struct file_operations ram_fops = { + memory_lseek, + read_ram, + write_ram, + NULL, /* ram_readdir */ + NULL, /* ram_select */ + NULL, /* ram_ioctl */ + NULL, /* ram_mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +static struct file_operations mem_fops = { + memory_lseek, + read_mem, + write_mem, + NULL, /* mem_readdir */ + NULL, /* mem_select */ + NULL, /* mem_ioctl */ + mmap_mem, + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +static struct file_operations kmem_fops = { + memory_lseek, + read_kmem, + write_kmem, + NULL, /* kmem_readdir */ + NULL, /* kmem_select */ + NULL, /* kmem_ioctl */ + mmap_kmem, + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +static struct file_operations null_fops = { + null_lseek, + read_null, + write_null, + NULL, /* null_readdir */ + NULL, /* null_select */ + NULL, /* null_ioctl */ + NULL, /* null_mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +static struct file_operations port_fops = { + memory_lseek, + read_port, + write_port, + NULL, /* port_readdir */ + NULL, /* port_select */ + NULL, /* port_ioctl */ + NULL, /* port_mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +static struct file_operations zero_fops = { + zero_lseek, + read_zero, + write_zero, + NULL, /* zero_readdir */ + NULL, /* zero_select */ + NULL, /* zero_ioctl */ + mmap_zero, + NULL, /* no special open code */ + NULL /* no special release code */ +}; + +static struct file_operations full_fops = { + memory_lseek, + read_full, + write_full, + NULL, /* full_readdir */ + NULL, /* full_select */ + NULL, /* full_ioctl */ + NULL, /* full_mmap */ + NULL, /* no special open code */ + NULL /* no special release code */ +}; + +static int memory_open(struct inode * inode, struct file * filp) +{ + switch (MINOR(inode->i_rdev)) { + case 0: + filp->f_op = &ram_fops; + break; + case 1: + filp->f_op = &mem_fops; + break; + case 2: + filp->f_op = &kmem_fops; + break; + case 3: + filp->f_op = &null_fops; + break; + case 4: + filp->f_op = &port_fops; + break; + case 5: + filp->f_op = &zero_fops; + break; + case 7: + filp->f_op = &full_fops; + break; + default: + return -ENODEV; + } + if (filp->f_op && filp->f_op->open) + return filp->f_op->open(inode,filp); + return 0; +} + +static struct file_operations memory_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + memory_open, /* just a selector for the real open */ + NULL, /* release */ + NULL /* fsync */ +}; + +#ifdef CONFIG_FTAPE +char* ftape_big_buffer; +#endif + +long chr_dev_init(long mem_start, long mem_end) +{ + if (register_chrdev(MEM_MAJOR,"mem",&memory_fops)) + printk("unable to get major %d for memory devs\n", MEM_MAJOR); + mem_start = tty_init(mem_start); +#ifdef CONFIG_PRINTER + mem_start = lp_init(mem_start); +#endif +#if defined (CONFIG_BUSMOUSE) || defined (CONFIG_82C710_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 +/* + * Rude way to allocate kernel memory buffer for tape device + */ +#ifdef CONFIG_FTAPE + /* allocate NR_FTAPE_BUFFERS 32Kb buffers at aligned address */ + ftape_big_buffer= (char*) ((mem_start + 0x7fff) & ~0x7fff); + printk( "ftape: allocated %d buffers alligned at: %p\n", + NR_FTAPE_BUFFERS, ftape_big_buffer); + mem_start = (long) ftape_big_buffer + NR_FTAPE_BUFFERS * 0x8000; +#endif + return mem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mouse.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mouse.c new file mode 100644 index 000000000..107405f82 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/mouse.c @@ -0,0 +1,99 @@ +/* + * linux/kernel/chr_drv/mouse.c + * + * Generic mouse open routine by Johan Myreen + * + * Based on code from Linus + * + * Teemu Rantanen's Microsoft Busmouse support and Derrick Cole's + * changes incorporated into 0.97pl4 + * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) + * See busmouse.c for particulars. + * + * Made things a lot mode modular - easy to compile in just one or two + * of the mouse drivers, as they are now completely independent. Linus. + */ + +#include +#include +#include +#include +#include +#include + +/* + * note that you can remove any or all of the drivers by undefining + * the minor values in + */ +extern struct file_operations bus_mouse_fops; +extern struct file_operations psaux_fops; +extern struct file_operations ms_bus_mouse_fops; +extern struct file_operations atixl_busmouse_fops; + +extern unsigned long bus_mouse_init(unsigned long); +extern unsigned long psaux_init(unsigned long); +extern unsigned long ms_bus_mouse_init(unsigned long); +extern unsigned long atixl_busmouse_init(unsigned long); + +static int mouse_open(struct inode * inode, struct file * file) +{ + int minor = MINOR(inode->i_rdev); + + switch (minor) { +#ifdef CONFIG_BUSMOUSE + case BUSMOUSE_MINOR: + file->f_op = &bus_mouse_fops; + break; +#endif +#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE + case PSMOUSE_MINOR: + file->f_op = &psaux_fops; + break; +#endif +#ifdef CONFIG_MS_BUSMOUSE + case MS_BUSMOUSE_MINOR: + file->f_op = &ms_bus_mouse_fops; + break; +#endif +#ifdef CONFIG_ATIXL_BUSMOUSE + case ATIXL_BUSMOUSE_MINOR: + file->f_op = &atixl_busmouse_fops; + break; +#endif + default: + return -ENODEV; + } + return file->f_op->open(inode,file); +} + +static struct file_operations mouse_fops = { + NULL, /* seek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + mouse_open, + NULL /* release */ +}; + +unsigned long mouse_init(unsigned long kmem_start) +{ +#ifdef CONFIG_BUSMOUSE + kmem_start = bus_mouse_init(kmem_start); +#endif +#if defined CONFIG_PSMOUSE || defined CONFIG_82C710_MOUSE + kmem_start = psaux_init(kmem_start); +#endif +#ifdef CONFIG_MS_BUSMOUSE + kmem_start = ms_bus_mouse_init(kmem_start); +#endif +#ifdef CONFIG_ATIXL_BUSMOUSE + kmem_start = atixl_busmouse_init(kmem_start); +#endif + if (register_chrdev(MOUSE_MAJOR,"mouse",&mouse_fops)) + printk("unable to get major %d for mouse devices\n", + MOUSE_MAJOR); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/msbusmouse.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/msbusmouse.c new file mode 100644 index 000000000..6db02c089 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/msbusmouse.c @@ -0,0 +1,175 @@ +/* + * Microsoft busmouse driver based on Logitech driver (see busmouse.c) + * + * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92) + * + * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net) + * 8/28/92 + * + * Microsoft Bus Mouse support folded into 0.97pl4 code + * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) + * Changes: Logitech and Microsoft support in the same kernel. + * Defined new constants in busmouse.h for MS mice. + * Added int mse_busmouse_type to distinguish busmouse types + * Added a couple of new functions to handle differences in using + * MS vs. Logitech (where the int variable wasn't appropriate). + * + * Modified by Peter Cervasio (address above) (26SEP92) + * Changes: Included code to (properly?) detect when a Microsoft mouse is + * really attached to the machine. Don't know what this does to + * Logitech bus mice, but all it does is read ports. + * + * Modified by Christoph Niemann (niemann@rubdv15.etdv.ruhr-uni-bochum.de) + * Changes: Better interrupt-handler (like in busmouse.c). + * Some changes to reduce code-size. + * Changed dectection code to use inb_p() instead of doing empty + * loops to delay i/o. + * + * version 0.3a + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +static struct mouse_status mouse; + +static void ms_mouse_interrupt(int unused) +{ + char dx, dy; + unsigned char buttons; + + outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); + outb((inb(MS_MSE_DATA_PORT) | 0x20), MS_MSE_DATA_PORT); + + outb(MS_MSE_READ_X, MS_MSE_CONTROL_PORT); + dx = inb(MS_MSE_DATA_PORT); + + outb(MS_MSE_READ_Y, MS_MSE_CONTROL_PORT); + dy = inb(MS_MSE_DATA_PORT); + + outb(MS_MSE_READ_BUTTONS, MS_MSE_CONTROL_PORT); + buttons = ~(inb(MS_MSE_DATA_PORT)) & 0x07; + + outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); + outb((inb(MS_MSE_DATA_PORT) & 0xdf), MS_MSE_DATA_PORT); + + if (dx != 0 || dy != 0 || buttons != mouse.buttons || ((~buttons) & 0x07)) { + mouse.buttons = buttons; + mouse.dx += dx; + mouse.dy += dy; + mouse.ready = 1; + wake_up_interruptible(&mouse.wait); + } +} + +static void release_mouse(struct inode * inode, struct file * file) +{ + MS_MSE_INT_OFF(); + mouse.active = mouse.ready = 0; + free_irq(MOUSE_IRQ); +} + +static int open_mouse(struct inode * inode, struct file * file) +{ + if (!mouse.present) + return -EINVAL; + if (mouse.active) + return -EBUSY; + mouse.active = 1; + mouse.ready = mouse.dx = mouse.dy = 0; + mouse.buttons = 0x80; + if (request_irq(MOUSE_IRQ, ms_mouse_interrupt)) { + mouse.active = 0; + return -EBUSY; + } + outb(MS_MSE_START, MS_MSE_CONTROL_PORT); + MS_MSE_INT_ON(); + return 0; +} + + +static int write_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + return -EINVAL; +} + +static int read_mouse(struct inode * inode, struct file * file, char * buffer, int count) +{ + int i, dx, dy; + + if (count < 3) + return -EINVAL; + if (!mouse.ready) + return -EAGAIN; + put_fs_byte(mouse.buttons | 0x80, buffer); + dx = mouse.dx < -127 ? -127 : mouse.dx > 127 ? 127 : mouse.dx; + dy = mouse.dy < -127 ? 127 : mouse.dy > 127 ? -127 : -mouse.dy; + put_fs_byte((char)dx, buffer + 1); + put_fs_byte((char)dy, buffer + 2); + for (i = 3; i < count; i++) + put_fs_byte(0x00, buffer + i); + mouse.dx -= dx; + mouse.dy += dy; + mouse.ready = 0; + return i; +} + +static int mouse_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + if (sel_type != SEL_IN) + return 0; + if (mouse.ready) + return 1; + select_wait(&mouse.wait,wait); + return 0; +} + +struct file_operations ms_bus_mouse_fops = { + NULL, /* mouse_seek */ + read_mouse, + write_mouse, + NULL, /* mouse_readdir */ + mouse_select, /* mouse_select */ + NULL, /* mouse_ioctl */ + NULL, /* mouse_mmap */ + open_mouse, + release_mouse, +}; + +unsigned long ms_bus_mouse_init(unsigned long kmem_start) +{ + int mse_byte, i; + + mouse.present = mouse.active = mouse.ready = 0; + mouse.buttons = 0x80; + mouse.dx = mouse.dy = 0; + mouse.wait = NULL; + if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { + + mse_byte = inb_p(MS_MSE_SIGNATURE_PORT); + + for (i = 0; i < 4; i++) { + if (inb_p(MS_MSE_SIGNATURE_PORT) == 0xde) { + if (inb_p(MS_MSE_SIGNATURE_PORT) == mse_byte) + mouse.present = 1; + else + mouse.present = 0; + } else + mouse.present = 0; + } + } + if (mouse.present == 0) { + return kmem_start; + } + MS_MSE_INT_OFF(); + printk("Microsoft BusMouse detected and installed.\n"); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/psaux.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/psaux.c new file mode 100644 index 000000000..da133b353 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/psaux.c @@ -0,0 +1,552 @@ +/* + * linux/kernel/chr_drv/psaux.c + * + * Driver for PS/2 type mouse by Johan Myreen. + * + * Supports pointing devices attached to a PS/2 type + * Keyboard and Auxiliary Device Controller. + * + * Corrections in device setup for some laptop mice & trackballs. + * 02Feb93 (troyer@saifr00.cfsat.Honeywell.COM,mch@wimsey.bc.ca) + * + * Changed to prevent keyboard lockups on AST Power Exec. + * 28Jul93 Brad Bosch - brad@lachman.com + * + * Modified by Johan Myreen (jem@cs.hut.fi) 04Aug93 + * to include support for QuickPort mouse. + * + * Changed references to "QuickPort" with "82C710" since "QuickPort" + * is not what this driver is all about -- QuickPort is just a + * connector type, and this driver is for the mouse port on the Chips + * & Technologies 82C710 interface chip. 15Nov93 jem@cs.hut.fi + */ + +/* Uncomment the following line if your mouse needs initialization. */ + +/* #define INITIALIZE_DEVICE */ + +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +/* aux controller ports */ +#define AUX_INPUT_PORT 0x60 /* Aux device output buffer */ +#define AUX_OUTPUT_PORT 0x60 /* Aux device input buffer */ +#define AUX_COMMAND 0x64 /* Aux device command buffer */ +#define AUX_STATUS 0x64 /* Aux device status reg */ + +/* aux controller status bits */ +#define AUX_OBUF_FULL 0x21 /* output buffer (from device) full */ +#define AUX_IBUF_FULL 0x02 /* input buffer (to device) full */ + +/* aux controller commands */ +#define AUX_CMD_WRITE 0x60 /* value to write to controller */ +#define AUX_MAGIC_WRITE 0xd4 /* value to send aux device data */ + +#define AUX_INTS_ON 0x47 /* enable controller interrupts */ +#define AUX_INTS_OFF 0x65 /* disable controller interrupts */ + +#define AUX_DISABLE 0xa7 /* disable aux */ +#define AUX_ENABLE 0xa8 /* enable aux */ + +/* aux device commands */ +#define AUX_SET_RES 0xe8 /* set resolution */ +#define AUX_SET_SCALE11 0xe6 /* set 1:1 scaling */ +#define AUX_SET_SCALE21 0xe7 /* set 2:1 scaling */ +#define AUX_GET_SCALE 0xe9 /* get scaling factor */ +#define AUX_SET_STREAM 0xea /* set stream mode */ +#define AUX_SET_SAMPLE 0xf3 /* set sample rate */ +#define AUX_ENABLE_DEV 0xf4 /* enable aux device */ +#define AUX_DISABLE_DEV 0xf5 /* disable aux device */ +#define AUX_RESET 0xff /* reset aux device */ + +#define MAX_RETRIES 60 /* some aux operations take long time*/ +#define AUX_IRQ 12 +#define AUX_BUF_SIZE 2048 + +/* 82C710 definitions */ + +#define QP_DATA 0x310 /* Data Port I/O Address */ +#define QP_STATUS 0x311 /* Status Port I/O Address */ + +#define QP_DEV_IDLE 0x01 /* Device Idle */ +#define QP_RX_FULL 0x02 /* Device Char received */ +#define QP_TX_IDLE 0x04 /* Device XMIT Idle */ +#define QP_RESET 0x08 /* Device Reset */ +#define QP_INTS_ON 0x10 /* Device Interrupt On */ +#define QP_ERROR_FLAG 0x20 /* Device Error */ +#define QP_CLEAR 0x40 /* Device Clear */ +#define QP_ENABLE 0x80 /* Device Enable */ + +#define QP_IRQ 12 + +extern unsigned char aux_device_present; +extern unsigned char kbd_read_mask; /* from keyboard.c */ + +struct aux_queue { + unsigned long head; + unsigned long tail; + struct wait_queue *proc_list; + unsigned char buf[AUX_BUF_SIZE]; +}; + +static struct aux_queue *queue; +static int aux_ready = 0; +static int aux_busy = 0; +static int aux_present = 0; +static int poll_aux_status(void); + +#ifdef CONFIG_82C710_MOUSE +static int qp_present = 0; +static int qp_busy = 0; +static int qp_data = QP_DATA; +static int qp_status = QP_STATUS; + +static int poll_qp_status(void); +static int probe_qp(void); +#endif + + +/* + * Write to aux device + */ + +static void aux_write_dev(int val) +{ + poll_aux_status(); + outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); /* write magic cookie */ + poll_aux_status(); + outb_p(val,AUX_OUTPUT_PORT); /* write data */ +} + +/* + * Write to device & handle returned ack + */ + +#if defined INITIALIZE_DEVICE +static int aux_write_ack(int val) +{ + int retries = 0; + + aux_write_dev(val); /* write the value to the device */ + while ((inb(AUX_STATUS) & AUX_OBUF_FULL) != AUX_OBUF_FULL + && retries < MAX_RETRIES) { /* wait for ack */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 5; + schedule(); + retries++; + } + + if ((inb(AUX_STATUS) & AUX_OBUF_FULL) == AUX_OBUF_FULL) + { + return (inb(AUX_INPUT_PORT)); + } + return 0; +} +#endif /* INITIALIZE_DEVICE */ + +/* + * Write aux device command + */ + +static void aux_write_cmd(int val) +{ + poll_aux_status(); + outb_p(AUX_CMD_WRITE,AUX_COMMAND); + poll_aux_status(); + outb_p(val,AUX_OUTPUT_PORT); +} + + +static unsigned int get_from_queue(void) +{ + unsigned int result; + unsigned long flags; + + save_flags(flags); + cli(); + result = queue->buf[queue->tail]; + queue->tail = (queue->tail + 1) & (AUX_BUF_SIZE-1); + restore_flags(flags); + return result; +} + + +static inline int queue_empty(void) +{ + return queue->head == queue->tail; +} + + + +/* + * Interrupt from the auxiliary device: a character + * is waiting in the keyboard/aux controller. + */ + +static void aux_interrupt(int cpl) +{ + int head = queue->head; + int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); + + queue->buf[head] = inb(AUX_INPUT_PORT); + if (head != maxhead) { + head++; + head &= AUX_BUF_SIZE-1; + } + queue->head = head; + aux_ready = 1; + wake_up_interruptible(&queue->proc_list); +} + +/* + * Interrupt handler for the 82C710 mouse port. A character + * is waiting in the 82C710. + */ + +#ifdef CONFIG_82C710_MOUSE +static void qp_interrupt(int cpl) +{ + int head = queue->head; + int maxhead = (queue->tail-1) & (AUX_BUF_SIZE-1); + + queue->buf[head] = inb(qp_data); + if (head != maxhead) { + head++; + head &= AUX_BUF_SIZE-1; + } + queue->head = head; + aux_ready = 1; + wake_up_interruptible(&queue->proc_list); +} +#endif + + +static void release_aux(struct inode * inode, struct file * file) +{ + aux_write_dev(AUX_DISABLE_DEV); /* disable aux device */ + aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ + poll_aux_status(); + outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ + poll_aux_status(); + free_irq(AUX_IRQ); + aux_busy = 0; +} + +#ifdef CONFIG_82C710_MOUSE +static void release_qp(struct inode * inode, struct file * file) +{ + unsigned char status; + + if (!poll_qp_status()) + printk("Warning: Mouse device busy in release_qp()\n"); + status = inb_p(qp_status); + outb_p(status & ~(QP_ENABLE|QP_INTS_ON), qp_status); + if (!poll_qp_status()) + printk("Warning: Mouse device busy in release_qp()\n"); + free_irq(QP_IRQ); + qp_busy = 0; +} +#endif + +/* + * Install interrupt handler. + * Enable auxiliary device. + */ + +static int open_aux(struct inode * inode, struct file * file) +{ + if (!aux_present) + return -EINVAL; + if (aux_busy) + return -EBUSY; + if (!poll_aux_status()) + return -EBUSY; + aux_busy = 1; + queue->head = queue->tail = 0; /* Flush input queue */ + if (request_irq(AUX_IRQ, aux_interrupt)) { + aux_busy = 0; + return -EBUSY; + } + poll_aux_status(); + outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */ + aux_write_dev(AUX_ENABLE_DEV); /* enable aux device */ + aux_write_cmd(AUX_INTS_ON); /* enable controller ints */ + poll_aux_status(); + aux_ready = 0; + return 0; +} + +#ifdef CONFIG_82C710_MOUSE +/* + * Install interrupt handler. + * Enable the device, enable interrupts. Set qp_busy + * (allow only one opener at a time.) + */ + +static int open_qp(struct inode * inode, struct file * file) +{ + unsigned char status; + + if (!qp_present) + return -EINVAL; + + if (qp_busy) + return -EBUSY; + + if (request_irq(QP_IRQ, qp_interrupt)) + return -EBUSY; + + qp_busy = 1; + + status = inb_p(qp_status); + status |= (QP_ENABLE|QP_RESET); + outb_p(status, qp_status); + status &= ~(QP_RESET); + outb_p(status, qp_status); + + queue->head = queue->tail = 0; /* Flush input queue */ + status |= QP_INTS_ON; + outb_p(status, qp_status); /* Enable interrupts */ + + while (!poll_qp_status()) { + printk("Error: Mouse device busy in open_qp()\n"); + return -EBUSY; + } + + outb_p(AUX_ENABLE_DEV, qp_data); /* Wake up mouse */ + + return 0; +} +#endif + +/* + * Write to the aux device. + */ + +static int write_aux(struct inode * inode, struct file * file, char * buffer, int count) +{ + int i = count; + + while (i--) { + if (!poll_aux_status()) + return -EIO; + outb_p(AUX_MAGIC_WRITE,AUX_COMMAND); + if (!poll_aux_status()) + return -EIO; + outb_p(get_fs_byte(buffer++),AUX_OUTPUT_PORT); + } + inode->i_mtime = CURRENT_TIME; + return count; +} + + +#ifdef CONFIG_82C710_MOUSE +/* + * Write to the 82C710 mouse device. + */ + +static int write_qp(struct inode * inode, struct file * file, char * buffer, int count) +{ + int i = count; + + while (i--) { + if (!poll_qp_status()) + return -EIO; + outb_p(get_fs_byte(buffer++), qp_data); + } + inode->i_mtime = CURRENT_TIME; + return count; +} +#endif + + +/* + * Put bytes from input queue to buffer. + */ + +static int read_aux(struct inode * inode, struct file * file, char * buffer, int count) +{ + struct wait_queue wait = { current, NULL }; + int i = count; + unsigned char c; + + if (queue_empty()) { + if (file->f_flags & O_NONBLOCK) + return -EAGAIN; + add_wait_queue(&queue->proc_list, &wait); +repeat: + current->state = TASK_INTERRUPTIBLE; + if (queue_empty() && !(current->signal & ~current->blocked)) { + schedule(); + goto repeat; + } + current->state = TASK_RUNNING; + remove_wait_queue(&queue->proc_list, &wait); + } + while (i > 0 && !queue_empty()) { + c = get_from_queue(); + put_fs_byte(c, buffer++); + i--; + } + aux_ready = !queue_empty(); + if (count-i) { + inode->i_atime = CURRENT_TIME; + return count-i; + } + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; +} + + +static int aux_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + if (sel_type != SEL_IN) + return 0; + if (aux_ready) + return 1; + select_wait(&queue->proc_list, wait); + return 0; +} + + +struct file_operations psaux_fops = { + NULL, /* seek */ + read_aux, + write_aux, + NULL, /* readdir */ + aux_select, + NULL, /* ioctl */ + NULL, /* mmap */ + open_aux, + release_aux, +}; + + +/* + * Initialize driver. First check for a 82C710 chip; if found + * forget about the Aux port and use the *_qp functions. + */ + +unsigned long psaux_init(unsigned long kmem_start) +{ + int qp_found = 0; + +#ifdef CONFIG_82C710_MOUSE + printk("Probing 82C710 mouse port device.\n"); + if ((qp_found = probe_qp())) { + printk("82C710 type pointing device detected -- driver installed.\n"); +/* printk("82C710 address = %x (should be 0x310)\n", qp_data); */ + qp_present = 1; + psaux_fops.write = write_qp; + psaux_fops.open = open_qp; + psaux_fops.release = release_qp; + poll_qp_status(); + } else +#endif + if (aux_device_present == 0xaa) { + printk("PS/2 auxiliary pointing device detected -- driver installed.\n"); + aux_present = 1; + kbd_read_mask = AUX_OBUF_FULL; + poll_aux_status(); + } else { + return kmem_start; /* No mouse at all */ + } + queue = (struct aux_queue *) kmem_start; + kmem_start += sizeof (struct aux_queue); + queue->head = queue->tail = 0; + queue->proc_list = NULL; + if (!qp_found) { +#if defined INITIALIZE_DEVICE + outb_p(AUX_ENABLE,AUX_COMMAND); /* Enable Aux */ + aux_write_ack(AUX_SET_SAMPLE); + aux_write_ack(100); /* 100 samples/sec */ + aux_write_ack(AUX_SET_RES); + aux_write_ack(3); /* 8 counts per mm */ + aux_write_ack(AUX_SET_SCALE21); /* 2:1 scaling */ + poll_aux_status(); +#endif /* INITIALIZE_DEVICE */ + outb_p(AUX_DISABLE,AUX_COMMAND); /* Disable Aux device */ + aux_write_cmd(AUX_INTS_OFF); /* disable controller ints */ + poll_aux_status(); + } + return kmem_start; +} + +static int poll_aux_status(void) +{ + int retries=0; + + while ((inb(AUX_STATUS)&0x03) && retries < MAX_RETRIES) { + if (inb_p(AUX_STATUS) & AUX_OBUF_FULL == AUX_OBUF_FULL) + inb_p(AUX_INPUT_PORT); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 5; + schedule(); + retries++; + } + return !(retries==MAX_RETRIES); +} + +#ifdef CONFIG_82C710_MOUSE +/* + * Wait for device to send output char and flush any input char. + */ + +static int poll_qp_status(void) +{ + int retries=0; + + while ((inb(qp_status)&(QP_RX_FULL|QP_TX_IDLE|QP_DEV_IDLE)) + != (QP_DEV_IDLE|QP_TX_IDLE) + && retries < MAX_RETRIES) { + + if (inb_p(qp_status)&(QP_RX_FULL)) + inb_p(qp_data); + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + 5; + schedule(); + retries++; + } + return !(retries==MAX_RETRIES); +} + +/* + * Function to read register in 82C710. + */ + +static inline unsigned char read_710(unsigned char index) +{ + outb_p(index, 0x390); /* Write index */ + return inb_p(0x391); /* Read the data */ +} + +/* + * See if we can find a 82C710 device. Read mouse address. + */ + +static int probe_qp(void) +{ + outb_p(0x55, 0x2fa); /* Any value except 9, ff or 36 */ + outb_p(0xaa, 0x3fa); /* Inverse of 55 */ + outb_p(0x36, 0x3fa); /* Address the chip */ + outb_p(0xe4, 0x3fa); /* 390/4; 390 = config address */ + outb_p(0x1b, 0x2fa); /* Inverse of e4 */ + if (read_710(0x0f) != 0xe4) /* Config address found? */ + return 0; /* No: no 82C710 here */ + qp_data = read_710(0x0d)*4; /* Get mouse I/O address */ + qp_status = qp_data+1; + outb_p(0x0f, 0x390); + outb_p(0x0f, 0x391); /* Close config mode */ + return 1; +} +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/pty.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/pty.c new file mode 100644 index 000000000..482afe6b2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/pty.c @@ -0,0 +1,114 @@ +/* + * linux/kernel/chr_drv/pty.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * pty.c + * + * This module exports the following pty function: + * + * int pty_open(struct tty_struct * tty, struct file * filp); + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#define MIN(a,b) ((a) < (b) ? (a) : (b)) + +static void pty_close(struct tty_struct * tty, struct file * filp) +{ + if (!tty) + return; + if (IS_A_PTY_MASTER(tty->line)) { + if (tty->count > 1) + printk("master pty_close: count = %d!!\n", tty->count); + } else { + if (tty->count > 2) + return; + } + wake_up_interruptible(&tty->secondary.proc_list); + wake_up_interruptible(&tty->read_q.proc_list); + wake_up_interruptible(&tty->write_q.proc_list); + if (!tty->link) + return; + wake_up_interruptible(&tty->link->secondary.proc_list); + wake_up_interruptible(&tty->link->read_q.proc_list); + wake_up_interruptible(&tty->link->write_q.proc_list); + if (IS_A_PTY_MASTER(tty->line)) + tty_hangup(tty->link); + else { + start_tty(tty); + set_bit(TTY_SLAVE_CLOSED, &tty->link->flags); + } +} + +static inline void pty_copy(struct tty_struct * from, struct tty_struct * to) +{ + unsigned long count, n; + struct tty_queue *fq, *tq; + int skip_readq; + + if (from->stopped || EMPTY(&from->write_q)) + return; + fq = &from->write_q; + /* Bypass the read_q if this is a pty master. */ + skip_readq = IS_A_PTY_MASTER(to->line) && to->disc == N_TTY; + tq = skip_readq ? &to->secondary : &to->read_q; + count = MIN(CHARS(fq), LEFT(tq)); + while (count) { + n = MIN(MIN(TTY_BUF_SIZE - fq->tail, TTY_BUF_SIZE - tq->head), + count); + memcpy(&tq->buf[tq->head], &fq->buf[fq->tail], n); + count -= n; + fq->tail = (fq->tail + n) & (TTY_BUF_SIZE - 1); + tq->head = (tq->head + n) & (TTY_BUF_SIZE - 1); + } + if (skip_readq) + wake_up_interruptible(&to->secondary.proc_list); + else + TTY_READ_FLUSH(to); + if (LEFT(fq) > WAKEUP_CHARS) + wake_up_interruptible(&fq->proc_list); + if (from->write_data_cnt) { + set_bit(from->line, &tty_check_write); + mark_bh(TTY_BH); + } +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. It copies the input to the output-queue of its + * slave. + */ +static void pty_write(struct tty_struct * tty) +{ + if (tty->link) + pty_copy(tty,tty->link); +} + +int pty_open(struct tty_struct *tty, struct file * filp) +{ + if (!tty || !tty->link) + return -ENODEV; + if (IS_A_PTY_SLAVE(tty->line)) + clear_bit(TTY_SLAVE_CLOSED, &tty->link->flags); + tty->write = tty->link->write = pty_write; + tty->close = tty->link->close = pty_close; + wake_up_interruptible(&tty->read_q.proc_list); + if (filp->f_flags & O_NDELAY) + return 0; + while (!tty->link->count && !(current->signal & ~current->blocked)) + interruptible_sleep_on(&tty->link->read_q.proc_list); + if (!tty->link->count) + return -ERESTARTSYS; + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/serial.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/serial.c new file mode 100644 index 000000000..2b6aa0cc5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/serial.c @@ -0,0 +1,2071 @@ +/* + * linux/kernel/serial.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Extensively rewritten by Theodore Ts'o, 8/16/92 -- 9/14/92. Now + * much more extensible to support other serial cards based on the + * 16450/16550A UART's. Added support for the AST FourPort and the + * Accent Async board. + * + * set_serial_info fixed to set the flags, custom divisor, and uart + * type fields. Fix suggested by Michael K. Johnson 12/12/92. + * + * This module exports the following rs232 io functions: + * + * long rs_init(long); + * int rs_open(struct tty_struct * tty, struct file * filp) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* + * Serial driver configuration section. Here are the various options: + * + * CONFIG_AUTO_IRQ + * Enables automatic IRQ detection. I've put in some + * fixes to this which should make this work much more + * cleanly than it used to in 0.98pl2-6. It should be + * much less vulnerable to false IRQs now. + * + * CONFIG_AST_FOURPORT + * Enables support for the AST Fourport serial port. + * + * CONFIG_ACCENT_ASYNC + * Enables support for the Accent Async 4 port serial + * port. + * + * CONFIG_HUB6 + * Enables support for the venerable Bell Technologies + * HUB6 card. + */ + +#undef ISR_HACK + +/* + * rs_event - Bitfield of serial lines that events pending + * to be processed at the next clock tick. + * IRQ_timeout - How long the timeout should be for each IRQ + * should be after the IRQ has been active. + * IRQ_timer - Array of timeout values for each interrupt IRQ. + * This is based on jiffies; not offsets. + * + * We assume here that int's are 32 bits, so an array of two gives us + * 64 lines, which is the maximum we can support. + */ +static int rs_event[2]; + +static struct async_struct *IRQ_ports[16]; +static int IRQ_active; +static unsigned long IRQ_timer[16]; +static int IRQ_timeout[16]; +static volatile int rs_irq_triggered; +static volatile int rs_triggered; +static int rs_wild_int_mask; + +static void autoconfig(struct async_struct * info); +static void change_speed(unsigned int line); + +/* + * This assumes you have a 1.8432 MHz clock for your UART. + * + * It'd be nice if someone built a serial card with a 24.576 MHz + * clock, since the 16550A is capable of handling a top speed of 1.5 + * megabits/second; but this requires the faster clock. + */ +#define BASE_BAUD ( 1843200 / 16 ) + +#ifdef CONFIG_AUTO_IRQ +#define AUTO_IRQ_FLAG ASYNC_AUTO_IRQ +#else +#define AUTO_IRQ_FLAG 0 +#endif + +/* Standard COM flags (except for COM4, because of the 8514 problem) */ +#define STD_COM_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_SKIP_TEST | AUTO_IRQ_FLAG) +#define STD_COM4_FLAGS (ASYNC_BOOT_AUTOCONF | AUTO_IRQ_FLAG) + +#ifdef CONFIG_AST_FOURPORT +#define FOURPORT_FLAGS (ASYNC_BOOT_AUTOCONF | ASYNC_FOURPORT | AUTO_IRQ_FLAG) +#else +#define FOURPORT_FLAGS (ASYNC_FOURPORT | AUTO_IRQ_FLAG) +#endif + +#ifdef CONFIG_ACCENT_ASYNC +#define ACCENT_FLAGS (ASYNC_BOOT_AUTOCONF | AUTO_IRQ_FLAG) +#else +#define ACCENT_FLAGS AUTO_IRQ_FLAG +#endif + +#ifdef CONFIG_BOCA +#define BOCA_FLAGS (ASYNC_BOOT_AUTOCONF | AUTO_IRQ_FLAG) +#else +#define BOCA_FLAGS AUTO_IRQ_FLAG +#endif + +#ifdef CONFIG_HUB6 +#define HUB6_FLAGS (ASYNC_BOOT_AUTOCONF) +#else +#define HUB6_FLAGS 0 +#endif + +/* + * The following define the access methods for the HUB6 card. All + * access is through two ports for all 24 possible chips. The card is + * selected through the high 2 bits, the port on that card with the + * "middle" 3 bits, and the register on that port with the bottom + * 3 bits. + * + * While the access port and interrupt is configurable, the default + * port locations are 0x302 for the port control register, and 0x303 + * for the data read/write register. Normally, the interrupt is at irq3 + * but can be anything from 3 to 7 inclusive. Note tht using 3 will + * require disabling com2. + */ + +#define C_P(card,port) (((card)<<6|(port)<<3) + 1) + +struct async_struct rs_table[] = { + /* UART CLK PORT IRQ FLAGS */ + { BASE_BAUD, 0x3F8, 4, STD_COM_FLAGS }, /* ttyS0 */ + { BASE_BAUD, 0x2F8, 3, STD_COM_FLAGS }, /* ttyS1 */ + { BASE_BAUD, 0x3E8, 4, STD_COM_FLAGS }, /* ttyS2 */ + { BASE_BAUD, 0x2E8, 3, STD_COM4_FLAGS }, /* ttyS3 */ + + { BASE_BAUD, 0x1A0, 9, FOURPORT_FLAGS }, /* ttyS4 */ + { BASE_BAUD, 0x1A8, 9, FOURPORT_FLAGS }, /* ttyS5 */ + { BASE_BAUD, 0x1B0, 9, FOURPORT_FLAGS }, /* ttyS6 */ + { BASE_BAUD, 0x1B8, 9, FOURPORT_FLAGS }, /* ttyS7 */ + + { BASE_BAUD, 0x2A0, 5, FOURPORT_FLAGS }, /* ttyS8 */ + { BASE_BAUD, 0x2A8, 5, FOURPORT_FLAGS }, /* ttyS9 */ + { BASE_BAUD, 0x2B0, 5, FOURPORT_FLAGS }, /* ttyS10 */ + { BASE_BAUD, 0x2B8, 5, FOURPORT_FLAGS }, /* ttyS11 */ + + { BASE_BAUD, 0x330, 4, ACCENT_FLAGS }, /* ttyS12 */ + { BASE_BAUD, 0x338, 4, ACCENT_FLAGS }, /* ttyS13 */ + { BASE_BAUD, 0x000, 0, 0 }, /* ttyS14 (spare; user configurable) */ + { BASE_BAUD, 0x000, 0, 0 }, /* ttyS15 (spare; user configurable) */ + + { BASE_BAUD, 0x100, 12, BOCA_FLAGS }, /* ttyS16 */ + { BASE_BAUD, 0x108, 12, BOCA_FLAGS }, /* ttyS17 */ + { BASE_BAUD, 0x110, 12, BOCA_FLAGS }, /* ttyS18 */ + { BASE_BAUD, 0x118, 12, BOCA_FLAGS }, /* ttyS19 */ + { BASE_BAUD, 0x120, 12, BOCA_FLAGS }, /* ttyS20 */ + { BASE_BAUD, 0x128, 12, BOCA_FLAGS }, /* ttyS21 */ + { BASE_BAUD, 0x130, 12, BOCA_FLAGS }, /* ttyS22 */ + { BASE_BAUD, 0x138, 12, BOCA_FLAGS }, /* ttyS23 */ + { BASE_BAUD, 0x140, 12, BOCA_FLAGS }, /* ttyS24 */ + { BASE_BAUD, 0x148, 12, BOCA_FLAGS }, /* ttyS25 */ + { BASE_BAUD, 0x150, 12, BOCA_FLAGS }, /* ttyS26 */ + { BASE_BAUD, 0x158, 12, BOCA_FLAGS }, /* ttyS27 */ + { BASE_BAUD, 0x160, 12, BOCA_FLAGS }, /* ttyS28 */ + { BASE_BAUD, 0x168, 12, BOCA_FLAGS }, /* ttyS29 */ + { BASE_BAUD, 0x170, 12, BOCA_FLAGS }, /* ttyS30 */ + { BASE_BAUD, 0x178, 12, BOCA_FLAGS }, /* ttyS31 */ + +/* You can have up to four HUB6's in the system, but I've only + * included two cards here for a total of twelve ports. + */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,0) }, /* ttyS32 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,1) }, /* ttyS33 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,2) }, /* ttyS34 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,3) }, /* ttyS35 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,4) }, /* ttyS36 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(0,5) }, /* ttyS37 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,0) }, /* ttyS32 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,1) }, /* ttyS33 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,2) }, /* ttyS34 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,3) }, /* ttyS35 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,4) }, /* ttyS36 */ + { BASE_BAUD, 0x302, 3, HUB6_FLAGS, C_P(1,5) }, /* ttyS37 */ +}; + +#define NR_PORTS (sizeof(rs_table)/sizeof(struct async_struct)) + +/* + * This is used to figure out the divsor speeds and the timeouts + */ +static int baud_table[] = { + 0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, + 9600, 19200, 38400, 57600, 115200, 0 }; + +static void rs_throttle(struct tty_struct * tty, int status); + +static inline unsigned int serial_in(struct async_struct *info, int offset) +{ + if (info->hub6) { + outb(info->hub6 - 1 + offset, info->port); + return inb(info->port+1); + } else + return inb(info->port + offset); +} + +static inline unsigned int serial_inp(struct async_struct *info, int offset) +{ + if (info->hub6) { + outb(info->hub6 - 1 + offset, info->port); + return inb_p(info->port+1); + } else + return inb_p(info->port + offset); +} + +static inline void serial_out(struct async_struct *info, int offset, int value) +{ + if (info->hub6) { + outb(info->hub6 - 1 + offset, info->port); + outb(value, info->port+1); + } else + outb(value, info->port+offset); +} + +static inline void serial_outp(struct async_struct *info, int offset, + int value) +{ + if (info->hub6) { + outb(info->hub6 - 1 + offset, info->port); + outb_p(value, info->port+1); + } else + outb_p(value, info->port+offset); +} + +/* + * ------------------------------------------------------------ + * rs_stop() and rs_start() + * + * This routines are called before setting or resetting tty->stopped. + * They enable or disable transmitter interrupts, as necessary. + * ------------------------------------------------------------ + */ +static void rs_stop(struct tty_struct *tty) +{ + struct async_struct *info; + + info = rs_table + DEV_TO_SL(tty->line); + + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; +#ifdef ISR_HACK + serial_out(info, UART_IER, info->IER); +#endif +} + +static void rs_start(struct tty_struct *tty) +{ + struct async_struct *info; + + info = rs_table + DEV_TO_SL(tty->line); + + info->IER = (UART_IER_MSI | UART_IER_RLSI | + UART_IER_THRI | UART_IER_RDI); +#ifdef ISR_HACK + serial_out(info, UART_IER, info->IER); +#endif +} + +/* + * ---------------------------------------------------------------------- + * + * Here starts the interrupt handling routines. All of the following + * subroutines are declared as inline and are folded into + * rs_interrupt(). They were separated out for readability's sake. + * + * Note: rs_interrupt() is a "fast" interrupt, which means that it + * runs with interrupts turned off. People who may want to modify + * rs_interrupt() should try to keep the interrupt handler as fast as + * possible. After you are done making modifications, it is not a bad + * idea to do: + * + * gcc -S -DKERNEL -Wall -Wstrict-prototypes -O6 -fomit-frame-pointer serial.c + * + * and look at the resulting assemble code in serial.s. + * + * - Ted Ts'o (tytso@mit.edu), 7-Mar-93 + * ----------------------------------------------------------------------- + */ + +/* + * This is the serial driver's interrupt routine while we are probing + * for submarines. + */ +static void rs_probe(int irq) +{ + rs_irq_triggered = irq; + rs_triggered |= 1 << irq; + return; +} + +/* + * This routine is used by the interrupt handler to schedule + * processing in the software interrupt portion of the driver. + */ +static inline void rs_sched_event(struct async_struct *info, + int event) +{ + info->event |= 1 << event; + set_bit(info->line, rs_event); + mark_bh(SERIAL_BH); +} + +static inline void receive_chars(struct async_struct *info, + int *status) +{ + struct tty_queue * queue; + int head, tail, ch; + +/* + * Just like the LEFT(x) macro, except it uses the loal tail + * and head variables. + */ +#define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1)) + + queue = &info->tty->read_q; + head = queue->head; + tail = queue->tail; + do { + ch = serial_inp(info, UART_RX); + /* + * There must be at least 2 characters + * free in the queue; otherwise we punt. + */ + if (VLEFT < 2) + break; + if (*status & info->read_status_mask) { + set_bit(head, &info->tty->readq_flags); + if (*status & (UART_LSR_BI)) { + queue->buf[head++]= TTY_BREAK; + rs_sched_event(info, RS_EVENT_BREAK); + } else if (*status & UART_LSR_PE) + queue->buf[head++]= TTY_PARITY; + else if (*status & UART_LSR_FE) + queue->buf[head++]= TTY_FRAME; + else if (*status & UART_LSR_OE) + queue->buf[head++]= TTY_OVERRUN; + head &= TTY_BUF_SIZE-1; + } + queue->buf[head++] = ch; + head &= TTY_BUF_SIZE-1; + } while ((*status = serial_inp(info, UART_LSR)) & UART_LSR_DR); + queue->head = head; + if ((VLEFT < RQ_THRESHOLD_LW) && !set_bit(TTY_RQ_THROTTLED, + &info->tty->flags)) + rs_throttle(info->tty, TTY_THROTTLE_RQ_FULL); + rs_sched_event(info, RS_EVENT_READ_PROCESS); +#ifdef SERIAL_DEBUG_INTR + printk("DR..."); +#endif +} + +static inline void transmit_chars(struct async_struct *info, int *done_work) +{ + struct tty_queue * queue; + int head, tail, count; + + queue = &info->tty->write_q; + head = queue->head; + tail = queue->tail; + if (head==tail && !info->x_char) { + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; +#ifdef ISR_HACK + serial_out(info, UART_IER, info->IER); +#endif + return; + } + count = info->xmit_fifo_size; + if (info->x_char) { + serial_outp(info, UART_TX, info->x_char); + info->x_char = 0; + count--; + } + while (count-- && (tail != head)) { + serial_outp(info, UART_TX, queue->buf[tail++]); + tail &= TTY_BUF_SIZE-1; + } + queue->tail = tail; + if (VLEFT > WAKEUP_CHARS) { + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + if (info->tty->write_data_cnt) { + set_bit(info->tty->line, &tty_check_write); + mark_bh(TTY_BH); + } + } +#ifdef SERIAL_DEBUG_INTR + printk("THRE..."); +#endif + (*done_work)++; +} + +static inline int check_modem_status(struct async_struct *info) +{ + int status; + + status = serial_in(info, UART_MSR); + + if ((status & UART_MSR_DDCD) && !C_CLOCAL(info->tty)) { +#if (defined(SERIAL_DEBUG_OPEN) || defined(SERIAL_DEBUG_INTR)) + printk("ttys%d CD now %s...", info->line, + (status & UART_MSR_DCD) ? "on" : "off"); +#endif + if (status & UART_MSR_DCD) + rs_sched_event(info, RS_EVENT_OPEN_WAKEUP); + else if (!((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_CALLOUT_NOHUP))) { +#ifdef SERIAL_DEBUG_OPEN + printk("scheduling hangup..."); +#endif + rs_sched_event(info, RS_EVENT_HANGUP); + } + } + if (C_CRTSCTS(info->tty)) { + if (info->tty->hw_stopped) { + if (status & UART_MSR_CTS) { +#ifdef SERIAL_DEBUG_INTR + printk("CTS tx start..."); +#endif + info->tty->hw_stopped = 0; + rs_start(info->tty); + return 1; + } + } else { + if (!(status & UART_MSR_CTS)) { +#ifdef SERIAL_DEBUG_INTR + printk("CTS tx stop..."); +#endif + info->tty->hw_stopped = 1; + rs_stop(info->tty); + } + } + } + return 0; +} + +static inline void figure_RS_timer(void) +{ + int timeout = 6000; /* 60 seconds; really big :-) */ + int i, mask; + + if (!IRQ_active) + return; + for (i=0, mask = 1; mask <= IRQ_active; i++, mask <<= 1) { + if (!(mask & IRQ_active)) + continue; + if (IRQ_timer[i] < timeout) + timeout = IRQ_timer[i]; + } + timer_table[RS_TIMER].expires = jiffies + timeout; + timer_active |= 1 << RS_TIMER; +} + + +/* + * This is the serial driver's generic interrupt routine + */ +static void rs_interrupt(int irq) +{ + int status; + struct async_struct * info; + int done, done_work, pass_number, recheck_count; + + rs_irq_triggered = irq; + rs_triggered |= 1 << irq; + + info = IRQ_ports[irq]; + done = 1; + done_work = 0; + pass_number = 0; + while (info) { + if (info->tty && + info->tty->termios && + (!pass_number || + !(serial_inp(info, UART_IIR) & UART_IIR_NO_INT))) { + done = 0; + status = serial_inp(info, UART_LSR); + if (status & UART_LSR_DR) { + receive_chars(info, &status); + done_work++; + } + recheck_count = 0; + recheck_write: + if (status & UART_LSR_THRE) { + wake_up_interruptible(&info->xmit_wait); + if (!info->tty->stopped && + !info->tty->hw_stopped) + transmit_chars(info, &done_work); + } + if (check_modem_status(info) && + (recheck_count++ <= 64)) + goto recheck_write; +#ifdef SERIAL_DEBUG_INTR + if (recheck_count > 16) + printk("recheck_count = %d\n", recheck_count); +#endif + } +#ifdef ISR_HACK + serial_outp(info, UART_IER, 0); + serial_out(info, UART_IER, info->IER); +#endif + + info = info->next_port; + if (!info && !done) { + info = IRQ_ports[irq]; + done = 1; + if (pass_number++ > 64) + break; /* Prevent infinite loops */ + } + } + if ((info = IRQ_ports[irq]) != NULL) { +#ifdef 0 + do { + serial_outp(info, UART_IER, 0); + serial_out(info, UART_IER, info->IER); + info = info->next_port; + } while (info); +#endif + if (irq && !done_work) + IRQ_timer[irq] = jiffies + 1500; + else + IRQ_timer[irq] = jiffies + IRQ_timeout[irq]; + IRQ_active |= 1 << irq; + } + figure_RS_timer(); +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * This routine is called when we receive a break on a serial line. + * It is executed out of the software interrupt routine. + */ +static inline void handle_rs_break(struct async_struct *info) +{ + if (info->flags & ASYNC_SAK) + do_SAK(info->tty); + + if (!I_IGNBRK(info->tty) && I_BRKINT(info->tty)) { + flush_input(info->tty); + flush_output(info->tty); + if (info->tty->pgrp > 0) + kill_pg(info->tty->pgrp, SIGINT,1); + } +} + +/* + * This routine is used to handle the "bottom half" processing for the + * serial driver, known also the "software interrupt" processing. + * This processing is done at the kernel interrupt level, after the + * rs_interrupt() has returned, BUT WITH INTERRUPTS TURNED ON. This + * is where time-consuming activities which can not be done in the + * interrupt driver proper are done; the interrupt driver schedules + * them using rs_sched_event(), and they get done here. + */ +static void do_softint(void *unused) +{ + int i; + struct async_struct *info; + + for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { + if (clear_bit(i, rs_event)) { + if (!info->tty) + continue; + if (clear_bit(RS_EVENT_READ_PROCESS, &info->event)) { + TTY_READ_FLUSH(info->tty); + } + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + wake_up_interruptible(&info->tty->write_q.proc_list); + } + if (clear_bit(RS_EVENT_HANGUP, &info->event)) { + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~(ASYNC_NORMAL_ACTIVE| + ASYNC_CALLOUT_ACTIVE); + } + if (clear_bit(RS_EVENT_BREAK, &info->event)) + handle_rs_break(info); + if (clear_bit(RS_EVENT_OPEN_WAKEUP, &info->event)) { + wake_up_interruptible(&info->open_wait); + } + } + } +} + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to run the rs_interrupt routine at certain + * intervals, either because a serial interrupt might have been lost, + * or because (in the case of IRQ=0) the serial port does not have an + * interrupt, and is being checked only via the timer interrupts. + */ +static void rs_timer(void) +{ + int i, mask; + int timeout = 0; + + for (i = 0, mask = 1; mask <= IRQ_active; i++, mask <<= 1) { + if ((mask & IRQ_active) && (IRQ_timer[i] <= jiffies)) { + IRQ_active &= ~mask; + cli(); +#ifdef SERIAL_DEBUG_TIMER + printk("rs_timer: rs_interrupt(%d)...", i); +#endif + rs_interrupt(i); + sti(); + } + if (mask & IRQ_active) { + if (!timeout || (IRQ_timer[i] < timeout)) + timeout = IRQ_timer[i]; + } + } + if (timeout) { + timer_table[RS_TIMER].expires = timeout; + timer_active |= 1 << RS_TIMER; + } +} + +/* + * --------------------------------------------------------------- + * Low level utility subroutines for the serial driver: routines to + * figure out the appropriate timeout for an interrupt chain, routines + * to initialize and startup a serial port, and routines to shutdown a + * serial port. Useful stuff like that. + * --------------------------------------------------------------- + */ + +/* + * Grab all interrupts in preparation for doing an automatic irq + * detection. dontgrab is a mask of irq's _not_ to grab. Returns a + * mask of irq's which were grabbed and should therefore be freed + * using free_all_interrupts(). + */ +static int grab_all_interrupts(int dontgrab) +{ + int irq_lines = 0; + int i, mask; + struct sigaction sa; + + sa.sa_handler = rs_probe; + sa.sa_flags = (SA_INTERRUPT); + sa.sa_mask = 0; + sa.sa_restorer = NULL; + + for (i = 0, mask = 1; i < 16; i++, mask <<= 1) { + if (!(mask & dontgrab) && !irqaction(i, &sa)) { + irq_lines |= mask; + } + } + return irq_lines; +} + +/* + * Release all interrupts grabbed by grab_all_interrupts + */ +static void free_all_interrupts(int irq_lines) +{ + int i; + + for (i = 0; i < 16; i++) { + if (irq_lines & (1 << i)) + free_irq(i); + } +} + +/* + * This routine figures out the correct timeout for a particular IRQ. + * It uses the smallest timeout of all of the serial ports in a + * particular interrupt chain. + */ +static void figure_IRQ_timeout(int irq) +{ + struct async_struct *info; + int timeout = 6000; /* 60 seconds === a long time :-) */ + + info = IRQ_ports[irq]; + if (!info) { + IRQ_timeout[irq] = 6000; + return; + } + while (info) { + if (info->timeout < timeout) + timeout = info->timeout; + info = info->next_port; + } + if (!irq) + timeout = timeout / 2; + IRQ_timeout[irq] = timeout ? timeout : 1; +} + +static int startup(struct async_struct * info, int get_irq) +{ + unsigned short ICP; + unsigned long flags; + struct sigaction sa; + int retval; + + if (info->flags & ASYNC_INITIALIZED) + return 0; + + if (!info->port || !info->type) { + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + return 0; + } + + save_flags(flags); cli(); + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, info->irq); +#endif + + /* + * Allocate the IRQ if necessary + */ + if (get_irq && info->irq && !IRQ_ports[info->irq]) { + sa.sa_handler = rs_interrupt; + sa.sa_flags = (SA_INTERRUPT); + sa.sa_mask = 0; + sa.sa_restorer = NULL; + retval = irqaction(info->irq,&sa); + if (retval) { + restore_flags(flags); + return retval; + } + } + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + if (info->type == PORT_16550A) { + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + info->xmit_fifo_size = 16; + } else + info->xmit_fifo_size = 1; + + /* + * Clear the interrupt registers. + */ + (void)serial_inp(info, UART_LSR); + (void)serial_inp(info, UART_RX); + (void)serial_inp(info, UART_IIR); + (void)serial_inp(info, UART_MSR); + + /* + * Now, initialize the UART + */ + serial_outp(info, UART_LCR, UART_LCR_WLEN8); /* reset DLAB */ + if (info->flags & ASYNC_FOURPORT) + serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + else + serial_outp(info, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + + /* + * Finally, enable interrupts + */ +#ifdef ISR_HACK + info->IER = UART_IER_MSI | UART_IER_RLSI | UART_IER_RDI; + serial_outp(info, UART_IER, info->IER); /* enable interrupts */ +#else + info->IER = (UART_IER_MSI | UART_IER_RLSI | + UART_IER_THRI | UART_IER_RDI); + serial_outp(info, UART_IER, info->IER); /* enable all intrs */ +#endif + if (info->flags & ASYNC_FOURPORT) { + /* Enable interrupts on the AST Fourport board */ + ICP = (info->port & 0xFE0) | 0x01F; + outb_p(0x80, ICP); + (void) inb_p(ICP); + } + + /* + * And clear the interrupt registers again for luck. + */ + (void)serial_inp(info, UART_LSR); + (void)serial_inp(info, UART_RX); + (void)serial_inp(info, UART_IIR); + (void)serial_inp(info, UART_MSR); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + /* + * Set up parity check flag + */ + if (info->tty && info->tty->termios && I_INPCK(info->tty)) + info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | + UART_LSR_FE | UART_LSR_PE); + else + info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | + UART_LSR_FE); + + /* + * Insert serial port into IRQ chain. + */ + info->prev_port = 0; + info->next_port = IRQ_ports[info->irq]; + if (info->next_port) + info->next_port->prev_port = info; + IRQ_ports[info->irq] = info; + figure_IRQ_timeout(info->irq); + + /* + * Set up serial timers... + */ + IRQ_active |= 1 << info->irq; + figure_RS_timer(); + + /* + * and set the speed of the serial port + */ + change_speed(info->line); + + info->flags |= ASYNC_INITIALIZED; + restore_flags(flags); + return 0; +} + +/* + * This routine will shutdown a serial port; interrupts are disabled, and + * DTR is dropped if the hangup on close termio flag is on. + */ +static void shutdown(struct async_struct * info, int do_free_irq) +{ + unsigned long flags; + + if (!(info->flags & ASYNC_INITIALIZED)) + return; + +#ifdef SERIAL_DEBUG_OPEN + printk("Shutting down serial port %d (irq %d)....", info->line, + info->irq); +#endif + + save_flags(flags); cli(); /* Disable interrupts */ + + /* + * First unlink the serial port from the IRQ chain... + */ + if (info->next_port) + info->next_port->prev_port = info->prev_port; + if (info->prev_port) + info->prev_port->next_port = info->next_port; + else + IRQ_ports[info->irq] = info->next_port; + figure_IRQ_timeout(info->irq); + + /* + * Free the IRQ, if necessary + */ + if (do_free_irq && info->irq && !IRQ_ports[info->irq]) + free_irq(info->irq); + + info->IER = 0; + serial_outp(info, UART_IER, 0x00); /* disable all intrs */ + if (info->flags & ASYNC_FOURPORT) { + /* reset interrupts on the AST Fourport board */ + (void) inb((info->port & 0xFE0) | 0x01F); + } + if (info->tty && !(info->tty->termios->c_cflag & HUPCL)) + serial_outp(info, UART_MCR, UART_MCR_DTR); + else + /* reset DTR,RTS,OUT_2 */ + serial_outp(info, UART_MCR, 0x00); + + /* disable FIFO's */ + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + (void)serial_in(info, UART_RX); /* read data port to reset things */ + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ASYNC_INITIALIZED; + restore_flags(flags); +} + +/* + * This routine is called to set the UART divisor registers to match + * the specified baud rate for a serial port. + */ +static void change_speed(unsigned int line) +{ + struct async_struct * info; + unsigned short port; + int quot = 0; + unsigned cflag,cval,mcr,fcr; + int i; + + if (line >= NR_PORTS) + return; + info = rs_table + line; + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!(port = info->port)) + return; + i = cflag & CBAUD; + if (i == 15) { + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_HI) + i += 1; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_VHI) + i += 2; + if ((info->flags & ASYNC_SPD_MASK) == ASYNC_SPD_CUST) + quot = info->custom_divisor; + } + if (quot) { + info->timeout = ((info->xmit_fifo_size*HZ*15*quot) / + info->baud_base) + 2; + } else if (baud_table[i] == 134) { + quot = (2*info->baud_base / 269); + info->timeout = (info->xmit_fifo_size*HZ*30/269) + 2; + } else if (baud_table[i]) { + quot = info->baud_base / baud_table[i]; + info->timeout = (info->xmit_fifo_size*HZ*15/baud_table[i]) + 2; + } else { + quot = 0; + info->timeout = 0; + } + cli(); + mcr = serial_in(info, UART_MCR); + if (quot) { + serial_out(info, UART_MCR, mcr | UART_MCR_DTR); + } else { + serial_out(info, UART_MCR, mcr & ~UART_MCR_DTR); + sti(); + return; + } + sti(); + /* byte size and parity */ + cval = cflag & (CSIZE | CSTOPB); + cval >>= 4; + if (cflag & PARENB) + cval |= UART_LCR_PARITY; + if (!(cflag & PARODD)) + cval |= UART_LCR_EPAR; + if (info->type == PORT_16550A) { + if ((info->baud_base / quot) < 2400) + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_1; + else + fcr = UART_FCR_ENABLE_FIFO | UART_FCR_TRIGGER_8; + } else + fcr = 0; + + cli(); + serial_outp(info, UART_LCR, cval | UART_LCR_DLAB); /* set DLAB */ + serial_outp(info, UART_DLL, quot & 0xff); /* LS of divisor */ + serial_outp(info, UART_DLM, quot >> 8); /* MS of divisor */ + serial_outp(info, UART_LCR, cval); /* reset DLAB */ + serial_outp(info, UART_FCR, fcr); /* set fcr */ + sti(); +} + +/* + * ------------------------------------------------------------ + * rs_write() and friends + * ------------------------------------------------------------ + */ + +/* + * This routine is used by rs_write to restart transmitter interrupts, + * which are disabled after we have a transmitter interrupt which went + * unacknowledged because we had run out of data to transmit. + * + * Note: this subroutine must be called with the interrupts *off* + */ +static inline void restart_port(struct async_struct *info) +{ + struct tty_queue * queue; + int head, tail, count; + + if (!info) + return; + + if (serial_inp(info, UART_LSR) & UART_LSR_THRE) { + if (info->x_char) { + serial_outp(info, UART_TX, info->x_char); + info->x_char = 0; + } else { + queue = &info->tty->write_q; + head = queue->head; + tail = queue->tail; + count = info->xmit_fifo_size; + while (count--) { + if (tail == head) + break; + serial_outp(info, UART_TX, queue->buf[tail++]); + tail &= TTY_BUF_SIZE-1; + } + queue->tail = tail; + } + } +} + +/* + * This routine gets called when tty_write has put something into + * the write_queue. + */ +void rs_write(struct tty_struct * tty) +{ + struct async_struct *info; + + if (!tty || tty->stopped || tty->hw_stopped) + return; + info = rs_table + DEV_TO_SL(tty->line); + if (!info || !info->tty || !(info->flags & ASYNC_INITIALIZED)) + return; + cli(); + restart_port(info); + info->IER = (UART_IER_MSI | UART_IER_RLSI | + UART_IER_THRI | UART_IER_RDI); +#ifdef ISR_HACK + serial_out(info, UART_IER, info->IER); +#endif + sti(); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled (and that the throttle + * should be released). + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty, int status) +{ + struct async_struct *info; + unsigned char mcr; + unsigned long flags; + + save_flags(flags); cli(); +#if SERIAL_DEBUG_THROTTLE + printk("throttle tty%d: %d (%d, %d)....\n", DEV_TO_SL(tty->line), + status, LEFT(&tty->read_q), LEFT(&tty->secondary)); +#endif + switch (status) { + case TTY_THROTTLE_RQ_FULL: + info = rs_table + DEV_TO_SL(tty->line); + if (I_IXOFF(tty)) { + info->x_char = STOP_CHAR(tty); + } else { + mcr = serial_inp(info, UART_MCR); + mcr &= ~UART_MCR_RTS; + serial_out(info, UART_MCR, mcr); + } + break; + case TTY_THROTTLE_RQ_AVAIL: + info = rs_table + DEV_TO_SL(tty->line); + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } else { + mcr = serial_in(info, UART_MCR); + mcr |= UART_MCR_RTS; + serial_out(info, UART_MCR, mcr); + } + break; + } + restore_flags(flags); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct async_struct * info, + struct serial_struct * retinfo) +{ + struct serial_struct tmp; + + if (!retinfo) + return -EFAULT; + memset(&tmp, 0, sizeof(tmp)); + tmp.type = info->type; + tmp.line = info->line; + tmp.port = info->port; + tmp.irq = info->irq; + tmp.flags = info->flags; + tmp.baud_base = info->baud_base; + tmp.close_delay = info->close_delay; + tmp.custom_divisor = info->custom_divisor; + tmp.hub6 = info->hub6; + memcpy_tofs(retinfo,&tmp,sizeof(*retinfo)); + return 0; +} + +static int set_serial_info(struct async_struct * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct async_struct old_info; + unsigned int i,change_irq,change_port; + int retval; + struct sigaction sa; + + if (!new_info) + return -EFAULT; + memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); + old_info = *info; + + change_irq = new_serial.irq != info->irq; + change_port = (new_serial.port != info->port) || (new_serial.hub6 != info->hub6); + + if (!suser()) { + if (change_irq || change_port || + (new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ASYNC_USR_MASK) != + (info->flags & ~ASYNC_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ASYNC_USR_MASK) | + (new_serial.flags & ASYNC_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (new_serial.irq == 2) + new_serial.irq = 9; + + if ((new_serial.irq > 15) || (new_serial.port > 0xffff) || + (new_serial.type < PORT_UNKNOWN) || (new_serial.type > PORT_MAX)) { + return -EINVAL; + } + + /* Make sure address is not already in use */ + for (i = 0 ; i < NR_PORTS; i++) + if ((info != &rs_table[i]) && + (rs_table[i].port == new_serial.port) && rs_table[i].type) + return -EADDRINUSE; + + /* + * If necessary, first we try to grab the new IRQ for serial + * interrupts. (We have to do this early, since we may get an + * error trying to do this.) + */ + if (new_serial.port && new_serial.type && new_serial.irq && + (change_irq || !(info->flags & ASYNC_INITIALIZED))) { + if (!IRQ_ports[new_serial.irq]) { + sa.sa_handler = rs_interrupt; + sa.sa_flags = (SA_INTERRUPT); + sa.sa_mask = 0; + sa.sa_restorer = NULL; + retval = irqaction(new_serial.irq,&sa); + if (retval) + return retval; + } + } + + if ((change_port || change_irq) && (info->count > 1)) + return -EBUSY; + + /* + * OK, past this point, all the error checking has been done. + * At this point, we start making changes..... + */ + + info->baud_base = new_serial.baud_base; + info->flags = ((info->flags & ~ASYNC_FLAGS) | + (new_serial.flags & ASYNC_FLAGS)); + info->custom_divisor = new_serial.custom_divisor; + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + + if (change_port || change_irq) { + /* + * We need to shutdown the serial port at the old + * port/irq combination. + */ + shutdown(info, change_irq); + info->irq = new_serial.irq; + info->port = new_serial.port; + info->hub6 = new_serial.hub6; + } + +check_and_exit: + if (!info->port || !info->type) + return 0; + if (info->flags & ASYNC_INITIALIZED) { + if (((old_info.flags & ASYNC_SPD_MASK) != + (info->flags & ASYNC_SPD_MASK)) || + (old_info.custom_divisor != info->custom_divisor)) + change_speed(info->line); + } else + (void) startup(info, 0); + return 0; +} + +static int get_modem_info(struct async_struct * info, unsigned int *value) +{ + unsigned char control, status; + unsigned int result; + + cli(); + control = serial_in(info, UART_MCR); + status = serial_in(info, UART_MSR); + sti(); + result = ((control & UART_MCR_RTS) ? TIOCM_RTS : 0) + | ((control & UART_MCR_DTR) ? TIOCM_DTR : 0) + | ((status & UART_MSR_DCD) ? TIOCM_CAR : 0) + | ((status & UART_MSR_RI) ? TIOCM_RNG : 0) + | ((status & UART_MSR_DSR) ? TIOCM_DSR : 0) + | ((status & UART_MSR_CTS) ? TIOCM_CTS : 0); + put_fs_long(result,(unsigned long *) value); + return 0; +} + +static int set_modem_info(struct async_struct * info, unsigned int cmd, + unsigned int *value) +{ + unsigned char control; + unsigned int arg = get_fs_long((unsigned long *) value); + + cli(); + control = serial_in(info, UART_MCR); + sti(); + + switch (cmd) { + case TIOCMBIS: + if (arg & TIOCM_RTS) + control |= UART_MCR_RTS; + if (arg & TIOCM_DTR) + control |= UART_MCR_DTR; + break; + case TIOCMBIC: + if (arg & TIOCM_RTS) + control &= ~UART_MCR_RTS; + if (arg & TIOCM_DTR) + control &= ~UART_MCR_DTR; + break; + case TIOCMSET: + control = (control & ~(UART_MCR_RTS | UART_MCR_DTR)) + | ((arg & TIOCM_RTS) ? UART_MCR_RTS : 0) + | ((arg & TIOCM_DTR) ? UART_MCR_DTR : 0); + break; + default: + return -EINVAL; + } + cli(); + serial_out(info, UART_MCR, control); + sti(); + return 0; +} + +static int do_autoconfig(struct async_struct * info) +{ + int retval; + + if (!suser()) + return -EPERM; + + if (info->count > 1) + return -EBUSY; + + shutdown(info, 1); + + cli(); + autoconfig(info); + sti(); + + retval = startup(info, 1); + if (retval) + return retval; + return 0; +} + + +/* + * This routine sends a break character out the serial port. + */ +static void send_break( struct async_struct * info, int duration) +{ + if (!info->port) + return; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + cli(); + serial_out(info, UART_LCR, serial_inp(info, UART_LCR) | UART_LCR_SBC); + schedule(); + serial_out(info, UART_LCR, serial_inp(info, UART_LCR) & ~UART_LCR_SBC); + sti(); +} + +/* + * This routine returns a bitfield of "wild interrupts". Basically, + * any unclaimed interrupts which is flapping around. + */ +static int check_wild_interrupts(int doprint) +{ + int i, mask; + int wild_interrupts = 0; + int irq_lines; + unsigned long timeout; + unsigned long flags; + + /* Turn on interrupts (they may be off) */ + save_flags(flags); sti(); + + irq_lines = grab_all_interrupts(0); + + /* + * Delay for 0.1 seconds -- we use a busy loop since this may + * occur during the bootup sequence + */ + timeout = jiffies+10; + while (timeout >= jiffies) + ; + + rs_triggered = 0; /* Reset after letting things settle */ + + timeout = jiffies+10; + while (timeout >= jiffies) + ; + + for (i = 0, mask = 1; i < 16; i++, mask <<= 1) { + if ((rs_triggered & (1 << i)) && + (irq_lines & (1 << i))) { + wild_interrupts |= mask; + if (doprint) + printk("Wild interrupt? (IRQ %d)\n", i); + } + } + free_all_interrupts(irq_lines); + restore_flags(flags); + return wild_interrupts; +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error, line; + struct async_struct * info; + + line = DEV_TO_SL(tty->line); + if (line < 0 || line >= NR_PORTS) + return -ENODEV; + info = rs_table + line; + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + send_break(info, arg ? arg*(HZ/10) : HZ/4); + return 0; + case TIOCGSOFTCAR: + error = verify_area(VERIFY_WRITE, (void *) arg,sizeof(long)); + if (error) + return error; + put_fs_long(C_CLOCAL(tty) ? 1 : 0, + (unsigned long *) arg); + return 0; + case TIOCSSOFTCAR: + arg = get_fs_long((unsigned long *) arg); + tty->termios->c_cflag = + ((tty->termios->c_cflag & ~CLOCAL) | + (arg ? CLOCAL : 0)); + return 0; + case TIOCMGET: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + return get_modem_info(info, (unsigned int *) arg); + case TIOCMBIS: + case TIOCMBIC: + case TIOCMSET: + return set_modem_info(info, cmd, (unsigned int *) arg); + case TIOCGSERIAL: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; + return get_serial_info(info, + (struct serial_struct *) arg); + case TIOCSSERIAL: + return set_serial_info(info, + (struct serial_struct *) arg); + case TIOCSERCONFIG: + return do_autoconfig(info); + + case TIOCSERGWILD: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(int)); + if (error) + return error; + put_fs_long(rs_wild_int_mask, (unsigned long *) arg); + return 0; + + case TIOCSERSWILD: + if (!suser()) + return -EPERM; + rs_wild_int_mask = get_fs_long((unsigned long *) arg); + if (rs_wild_int_mask < 0) + rs_wild_int_mask = check_wild_interrupts(0); + return 0; + + default: + return -EINVAL; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct async_struct *info; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + info = &rs_table[DEV_TO_SL(tty->line)]; + + change_speed(DEV_TO_SL(tty->line)); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_write(tty); + } + + if (!(old_termios->c_cflag & CLOCAL) && + (tty->termios->c_cflag & CLOCAL)) + wake_up_interruptible(&info->open_wait); + + if (I_INPCK(tty)) + info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | + UART_LSR_FE | UART_LSR_PE); + else + info->read_status_mask = (UART_LSR_OE | UART_LSR_BI | + UART_LSR_FE); +} + +/* + * ------------------------------------------------------------ + * rs_close() + * + * This routine is called when the serial port gets closed. First, we + * wait for the last remaining data to be sent. Then, we unlink its + * async structure from the interrupt chain if necessary, and we free + * that IRQ if nothing is left in the chain. + * ------------------------------------------------------------ + */ +static void rs_close(struct tty_struct *tty, struct file * filp) +{ + struct async_struct * info; + int line; + + if (tty_hung_up_p(filp)) + return; + + line = DEV_TO_SL(tty->line); + if ((line < 0) || (line >= NR_PORTS)) + return; + info = rs_table + line; +#ifdef SERIAL_DEBUG_OPEN + printk("rs_close ttys%d, count = %d\n", info->line, info->count); +#endif + if ((tty->count == 1) && (info->count != 1)) { + /* + * Uh, oh. tty->count is 1, which means that the tty + * structure will be freed. Info->count should always + * be one in these conditions. If it's greater than + * one, we've got real problems, since it means the + * serial port won't be shutdown. + */ + printk("rs_close: bad serial port count; tty->count is 1, " + "info->count is %d\n", info->count); + info->count = 1; + } + if (--info->count < 0) { + printk("rs_close: bad serial port count for ttys%d: %d\n", + info->line, info->count); + info->count = 0; + } + if (info->count) + return; + info->flags |= ASYNC_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ASYNC_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ASYNC_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + tty->stopped = 0; /* Force flush to succeed */ + tty->hw_stopped = 0; + if (info->flags & ASYNC_INITIALIZED) { + rs_start(tty); + /* + * XXX There should be a timeout added to + * wait_until_sent, eventually. TYT 1/19/94 + */ + wait_until_sent(tty); + } else + flush_output(tty); + flush_input(tty); + cli(); + /* + * Make sure the UART transmitter has completely drained; this + * is especially important if there is a transmit FIFO! + */ + if (!(serial_inp(info, UART_LSR) & UART_LSR_THRE)) { + rs_start(tty); /* Make sure THRI interrupt enabled */ + interruptible_sleep_on(&info->xmit_wait); + } + sti(); + shutdown(info, 1); + clear_bit(line, rs_event); + info->event = 0; + info->tty = 0; + if (info->blocked_open) { + if (info->close_delay) { + tty->count++; /* avoid race condition */ + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + info->close_delay; + schedule(); + tty->count--; + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE| + ASYNC_CLOSING); + wake_up_interruptible(&info->close_wait); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void rs_hangup(struct tty_struct *tty) +{ + struct async_struct * info; + int line; + + line = DEV_TO_SL(tty->line); + if ((line < 0) || (line >= NR_PORTS)) + return; + info = rs_table + line; + + shutdown(info, 1); + clear_bit(line, rs_event); + info->event = 0; + info->count = 0; + info->flags &= ~(ASYNC_NORMAL_ACTIVE|ASYNC_CALLOUT_ACTIVE); + info->tty = 0; + wake_up_interruptible(&info->open_wait); +} + +/* + * ------------------------------------------------------------ + * rs_open() and friends + * ------------------------------------------------------------ + */ +static int block_til_ready(struct tty_struct *tty, struct file * filp, + struct async_struct *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = C_CLOCAL(tty); + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & ASYNC_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + return -EAGAIN; + else + return -ERESTARTSYS; +#else + return -EAGAIN; +#endif + } + + /* + * If this is a callout device, then just make sure the normal + * device isn't being used. + */ + if (MAJOR(filp->f_rdev) == TTYAUX_MAJOR) { + if (info->flags & ASYNC_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ASYNC_CALLOUT_ACTIVE) && + (info->flags & ASYNC_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ASYNC_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, then make the check up front + * and then exit. + */ + if (filp->f_flags & O_NONBLOCK) { + if (info->flags & ASYNC_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; + } + + /* + * Block waiting for the carrier detect and the line to become + * free (i.e., not in use by the callout). While we are in + * this loop, info->count is dropped by one, so that + * rs_close() knows when to free things. We restore it upon + * exit, either normal or abnormal. + */ + retval = 0; + add_wait_queue(&info->open_wait, &wait); +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready before block: ttys%d, count = %d\n", + info->line, info->count); +#endif + info->count--; + info->blocked_open++; + while (1) { + cli(); + if (!(info->flags & ASYNC_CALLOUT_ACTIVE)) + serial_out(info, UART_MCR, + serial_inp(info, UART_MCR) | + (UART_MCR_DTR | UART_MCR_RTS)); + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ASYNC_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ASYNC_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ASYNC_CALLOUT_ACTIVE) && + !(info->flags & ASYNC_CLOSING) && + (do_clocal || (serial_in(info, UART_MSR) & + UART_MSR_DCD))) + break; + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&info->open_wait, &wait); + if (!tty_hung_up_p(filp)) + info->count++; + info->blocked_open--; +#ifdef SERIAL_DEBUG_OPEN + printk("block_til_ready after blocking: ttys%d, count = %d\n", + info->line, info->count); +#endif + if (retval) + return retval; + info->flags |= ASYNC_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its async structure into + * the IRQ chain. It also performs the serial-speicific + * initalization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct async_struct *info; + int retval, line; + + line = DEV_TO_SL(tty->line); + if ((line < 0) || (line >= NR_PORTS)) + return -ENODEV; + info = rs_table + line; +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d, count = %d\n", info->line, info->count); +#endif + info->count++; + info->tty = tty; + + tty->write = rs_write; + tty->close = rs_close; + tty->ioctl = rs_ioctl; + tty->throttle = rs_throttle; + tty->set_termios = rs_set_termios; + tty->stop = rs_stop; + tty->start = rs_start; + tty->hangup = rs_hangup; + if ((info->count == 1) && (info->flags & ASYNC_SPLIT_TERMIOS)) { + if (MAJOR(filp->f_rdev) == TTY_MAJOR) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + } + /* + * Start up serial port + */ + retval = startup(info, 1); + if (retval) + return retval; + + retval = block_til_ready(tty, filp, info); + if (retval) { +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open returning after block_til_ready with %d\n", + retval); +#endif + return retval; + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* + * --------------------------------------------------------------------- + * rs_init() and friends + * + * rs_init() is called at boot-time to initialize the serial driver. + * --------------------------------------------------------------------- + */ + +/* + * This routine prints out the appropriate serial driver version + * number, and identifies which options were configured into this + * driver. + */ +static void show_serial_version(void) +{ + printk("Serial driver version 3.99a with"); +#ifdef CONFIG_AST_FOURPORT + printk(" AST_FOURPORT"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_ACCENT_ASYNC + printk(" ACCENT_ASYNC"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_HUB6 + printk(" HUB-6"); +#define SERIAL_OPT +#endif +#ifdef CONFIG_AUTO_IRQ + printk (" AUTO_IRQ"); +#define SERIAL_OPT +#endif +#ifdef SERIAL_OPT + printk(" enabled\n"); +#else + printk(" no serial options enabled\n"); +#endif +#undef SERIAL_OPT +} + +/* + * This routine is called by do_auto_irq(); it attempts to determine + * which interrupt a serial port is configured to use. It is not + * fool-proof, but it works a large part of the time. + */ +static int get_auto_irq(struct async_struct *info) +{ + unsigned char save_MCR, save_IER, save_ICP=0; + unsigned short ICP=0, port = info->port; + unsigned long timeout; + + /* + * Enable interrupts and see who answers + */ + rs_irq_triggered = 0; + cli(); + save_IER = serial_inp(info, UART_IER); + save_MCR = serial_inp(info, UART_MCR); + if (info->flags & ASYNC_FOURPORT) { + serial_outp(info, UART_MCR, UART_MCR_DTR | UART_MCR_RTS); + serial_outp(info, UART_IER, 0x0f); /* enable all intrs */ + ICP = (port & 0xFE0) | 0x01F; + save_ICP = inb_p(ICP); + outb_p(0x80, ICP); + (void) inb_p(ICP); + } else { + serial_outp(info, UART_MCR, + UART_MCR_DTR | UART_MCR_RTS | UART_MCR_OUT2); + serial_outp(info, UART_IER, 0x0f); /* enable all intrs */ + } + sti(); + /* + * Next, clear the interrupt registers. + */ + (void)serial_inp(info, UART_LSR); + (void)serial_inp(info, UART_RX); + (void)serial_inp(info, UART_IIR); + (void)serial_inp(info, UART_MSR); + + timeout = jiffies+2; + while (timeout >= jiffies) { + if (rs_irq_triggered) + break; + } + /* + * Now check to see if we got any business, and clean up. + */ + cli(); + serial_outp(info, UART_IER, save_IER); + serial_outp(info, UART_MCR, save_MCR); + if (info->flags & ASYNC_FOURPORT) + outb_p(save_ICP, ICP); + sti(); + return(rs_irq_triggered); +} + +/* + * Calls get_auto_irq() multiple times, to make sure we don't get + * faked out by random interrupts + */ +static int do_auto_irq(struct async_struct * info) +{ + unsigned port = info->port; + int irq_lines = 0; + int irq_try_1 = 0, irq_try_2 = 0; + int retries; + unsigned long flags; + + if (!port) + return 0; + + /* Turn on interrupts (they may be off) */ + save_flags(flags); sti(); + + irq_lines = grab_all_interrupts(rs_wild_int_mask); + + for (retries = 0; retries < 5; retries++) { + if (!irq_try_1) + irq_try_1 = get_auto_irq(info); + if (!irq_try_2) + irq_try_2 = get_auto_irq(info); + if (irq_try_1 && irq_try_2) { + if (irq_try_1 == irq_try_2) + break; + irq_try_1 = irq_try_2 = 0; + } + } + restore_flags(flags); + free_all_interrupts(irq_lines); + return (irq_try_1 == irq_try_2) ? irq_try_1 : 0; +} + +/* + * This routine is called by rs_init() to initialize a specific serial + * port. It determines what type of UART ship this serial port is + * using: 8250, 16450, 16550, 16550A. The important question is + * whether or not this UART is a 16550A or not, since this will + * determine whether or not we can use its FIFO features or not. + */ +static void autoconfig(struct async_struct * info) +{ + unsigned char status1, status2, scratch, scratch2; + unsigned port = info->port; + unsigned long flags; + + info->type = PORT_UNKNOWN; + + if (!port) + return; + + save_flags(flags); cli(); + + /* + * Do a simple existence test first; if we fail this, there's + * no point trying anything else. + */ + scratch = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, 0); + scratch2 = serial_inp(info, UART_IER); + serial_outp(info, UART_IER, scratch); + if (scratch2) { + restore_flags(flags); + return; /* We failed; there's nothing here */ + } + + /* + * Check to see if a UART is really there. Certain broken + * internal modems based on the Rockwell chipset fail this + * test, because they apparently don't implement the loopback + * test mode. So this test is skipped on the COM 1 through + * COM 4 ports. This *should* be safe, since no board + * manufactucturer would be stupid enough to design a board + * that conflicts with COM 1-4 --- we hope! + */ + if (!(info->flags & ASYNC_SKIP_TEST)) { + scratch = serial_inp(info, UART_MCR); + serial_outp(info, UART_MCR, UART_MCR_LOOP | scratch); + scratch2 = serial_inp(info, UART_MSR); + serial_outp(info, UART_MCR, UART_MCR_LOOP | 0x0A); + status1 = serial_inp(info, UART_MSR) & 0xF0; + serial_outp(info, UART_MCR, scratch); + serial_outp(info, UART_MSR, scratch2); + if (status1 != 0x90) { + restore_flags(flags); + return; + } + } + + /* + * If the AUTO_IRQ flag is set, try to do the automatic IRQ + * detection. + */ + if (info->flags & ASYNC_AUTO_IRQ) + info->irq = do_auto_irq(info); + + serial_outp(info, UART_FCR, UART_FCR_ENABLE_FIFO); + scratch = serial_in(info, UART_IIR) >> 6; + info->xmit_fifo_size = 1; + switch (scratch) { + case 0: + info->type = PORT_16450; + break; + case 1: + info->type = PORT_UNKNOWN; + break; + case 2: + info->type = PORT_16550; + break; + case 3: + info->type = PORT_16550A; + info->xmit_fifo_size = 16; + break; + } + if (info->type == PORT_16450) { + scratch = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0xa5); + status1 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, 0x5a); + status2 = serial_in(info, UART_SCR); + serial_outp(info, UART_SCR, scratch); + + if ((status1 != 0xa5) || (status2 != 0x5a)) + info->type = PORT_8250; + } + + /* + * Reset the UART. + */ + serial_outp(info, UART_MCR, 0x00); + serial_outp(info, UART_FCR, (UART_FCR_CLEAR_RCVR | + UART_FCR_CLEAR_XMIT)); + (void)serial_in(info, UART_RX); + + restore_flags(flags); +} + +/* + * The serial driver boot-time initialization code! + */ +long rs_init(long kmem_start) +{ + int i; + struct async_struct * info; + + memset(&rs_event, 0, sizeof(rs_event)); + bh_base[SERIAL_BH].routine = do_softint; + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + IRQ_active = 0; +#ifdef CONFIG_AUTO_IRQ + rs_wild_int_mask = check_wild_interrupts(1); +#endif + + for (i = 0; i < 16; i++) { + IRQ_ports[i] = 0; + IRQ_timeout[i] = 0; + } + + show_serial_version(); + for (i = 0, info = rs_table; i < NR_PORTS; i++,info++) { + info->line = i; + info->tty = 0; + info->type = PORT_UNKNOWN; + info->custom_divisor = 0; + info->close_delay = 50; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + memset(&info->callout_termios, 0, sizeof(struct termios)); + memset(&info->normal_termios, 0, sizeof(struct termios)); + info->open_wait = 0; + info->xmit_wait = 0; + info->close_wait = 0; + info->next_port = 0; + info->prev_port = 0; + if (info->irq == 2) + info->irq = 9; + if (!(info->flags & ASYNC_BOOT_AUTOCONF)) + continue; + autoconfig(info); + if (info->type == PORT_UNKNOWN) + continue; + printk("tty%02d%s at 0x%04x (irq = %d)", info->line, + (info->flags & ASYNC_FOURPORT) ? " FourPort" : "", + info->port, info->irq); + switch (info->type) { + case PORT_8250: + printk(" is a 8250\n"); + break; + case PORT_16450: + printk(" is a 16450\n"); + break; + case PORT_16550: + printk(" is a 16550\n"); + break; + case PORT_16550A: + printk(" is a 16550A\n"); + break; + default: + printk("\n"); + break; + } + } + return kmem_start; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tpqic02.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tpqic02.c new file mode 100644 index 000000000..45e695854 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tpqic02.c @@ -0,0 +1,2622 @@ +/* $Id: tpqic02.c,v 0.2.1.21 1993/06/18 19:04:33 root Exp root $ + * + * Driver for tape drive support for Linux-i386 0.99.12. + * + * Copyright (c) 1993 by H. H. Bergman. All rights reserved. + * Current e-mail address: csg279@wing.rug.nl + * [If you are unable to reach me directly, try the TAPE mailing list + * channel on linux-activists@niksula.hut.fi using "X-Mn-Key: TAPE" as + * the first line in your message.] + * + * Distribution of this program in executable form is only allowed if + * all of the corresponding source files are made available through the same + * medium at no extra cost. + * + * I will not accept any responsibility for damage caused directly or + * indirectly by this program, or code derived from this program. + * + * Use this code at your own risk. Don't blame me if it destroys your data! + * Make sure you have a backup before you try this code. + * + * This driver was partially inspired by the 'wt' driver in the 386BSD + * source distribution, which carries the following copyright notice: + * + * Copyright (c) 1991 The Regents of the University of California. + * All rights reserved. + * + * You are not allowed to change this line nor the text above. + * + * $Log: tpqic02.c,v $ + * Revision 0.2.1.21 1993/06/18 19:04:33 root + * minor fixes for 0.99.10. + * + * Revision 0.2.1.20 1993/06/11 21:38:51 root + * Added exception code for status 0x8000 (Cypher weirdness). + * + * Revision 0.2.1.19 1993/04/19 23:13:59 root + * Cleanups. Changed to 0.99.8. + * + * Revision 0.2.1.18 1993/03/22 17:39:47 root + * Moved to 0.99.7. Added Archive MTSEEK and MTTELL support. + * + * Revision 0.2.1.17 1993/03/08 18:51:59 root + * Tried to `fix' write-once bug in previous release. + * + * Revision 0.2.1.16 1993/03/01 00:06:16 root + * Use register_chrdev() for 0.99.6. + * + * Revision 0.2.1.15 1993/02/25 00:14:25 root + * minor cleanups. + * + * Revision 0.2.1.14 1993/01/25 00:06:14 root + * Kernel udelay. Eof fixups. + * Removed report_ read/write dummies; have strace(1) now. + * + * Revision 0.2.1.13 1993/01/10 02:24:43 root + * Rewrote wait_for_ready() to use newer schedule() features. + * This improves performance for rewinds etc. + * + * Revision 0.2.1.12 1993/01/05 18:44:09 root + * Changes for 0.99.1. Fixed `restartable reads'. + * + * Revision 0.2.1.11 1992/11/28 01:19:10 root + * Changes to exception handling (significant). + * Changed returned error codes. Hopefully they're correct now. + * Changed declarations to please gcc-2.3.1. + * Patch to deal with bogus interrupts for Archive cards. + * + * Revision 0.2.1.10 1992/10/28 00:50:44 root + * underrun/error counter needed byte swapping. + * + * Revision 0.2.1.9 1992/10/15 17:06:01 root + * Removed online() stuff. Changed EOF handling. + * + * Revision 0.2.1.8 1992/10/02 22:25:48 root + * Removed `no_sleep' parameters (got usleep() now), + * cleaned up some comments. + * + * Revision 0.2.1.7 1992/09/27 01:41:55 root + * Changed write() to do entire user buffer in one go, rather than just + * a kernel-buffer sized portion each time. + * + * Revision 0.2.1.6 1992/09/21 02:15:30 root + * Introduced udelay() function for microsecond-delays. + * Trying to use get_dma_residue rather than TC flags. + * Patch to fill entire user buffer on reads before + * returning. + * + * Revision 0.2.1.5 1992/09/19 02:31:28 root + * Some changes based on patches by Eddy Olk to + * support Archive SC402/SC499R controller cards. + * + * Revision 0.2.1.4 1992/09/07 01:37:37 root + * Minor changes + * + * Revision 0.2.1.3 1992/08/13 00:11:02 root + * Added some support for Archive SC402 and SC499 cards. + * (Untested.) + * + * Revision 0.2.1.2 1992/08/10 02:02:36 root + * Changed from linux/system.h macros to asm/dma.h inline functions. + * + * Revision 0.2.1.1 1992/08/08 01:12:39 root + * cleaned up a bit. added stuff for selftesting. + * preparing for asm/dma.h instead of linux/system.h + * + * Revision 0.2 1992/08/03 20:11:30 root + * Changed to use new IRQ allocation. Padding now done at runtime, pads to + * 512 bytes. Because of this the page regs must be re-programmed every + * block! Added hooks for selftest commands. + * Moved to linux-0.97. + * + * Revision 0.1.0.5 1992/06/22 22:20:30 root + * moved to Linux 0.96b + * + * Revision 0.1.0.4 1992/06/18 02:00:04 root + * Use minor bit-7 to enable/disable printing of extra debugging info + * when do tape access. + * Added semop stuff for DMA/IRQ allocation checking. Don't think this + * is the right way to do it though. + * + * Revision 0.1.0.3 1992/06/01 01:57:34 root + * changed DRQ to DMA. added TDEBUG ifdefs to reduce output. + * + * Revision 0.1.0.2 1992/05/31 14:02:38 root + * changed SET_DMA_PAGE handling slightly. + * + * Revision 0.1.0.1 1992/05/27 12:12:03 root + * Can now use multiple files on tape (sort of). + * First release. + * + * Revision 0.1 1992/05/26 01:16:31 root + * Initial version. Copyright H. H. Bergman 1992 + * + */ + +/* After the legalese, now the important bits: + * + * This is a driver for the Wangtek 5150 tape drive with + * a QIC-02 controller for ISA-PC type computers. + * Hopefully it will work with other QIC-02 tape drives as well. + * + * Make sure your setup matches the configuration parameters. + * Also, be careful to avoid IO conflicts with other devices! + */ + +#include + +/* skip this driver if not required for this configuration */ +#if CONFIG_TAPE_QIC02 + +/* +#define TDEBUG +*/ + +#define REALLY_SLOW_IO /* it sure is ... */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +/* check existence of required configuration parameters */ +#if !defined(TAPE_QIC02_PORT) || \ + !defined(TAPE_QIC02_IRQ) || \ + !defined(TAPE_QIC02_DMA) +#error tape_qic02 configuration error +#endif + + +#define TPQIC_NAME "tpqic02" + +/* Linux outb() commands have (value,port) as parameters. + * One might expect (port,value) instead, so beware! + */ + +static volatile int ctlbits = 0; /* control reg bits for tape interface */ + +static struct wait_queue *tape_qic02_transfer = NULL; /* sync rw with interrupts */ + +static volatile struct mtget ioctl_status; /* current generic status */ + +static volatile struct tpstatus tperror; /* last drive status */ + +static char rcs_revision[] = "$Revision: 0.2.1.21 $"; +static char rcs_date[] = "$Date: 1993/06/18 19:04:33 $"; + +/* Flag bits for status and outstanding requests. + * (Could all be put in one bit-field-struct.) + * Some variables need `volatile' because they may be modified + * by an interrupt. + */ +static volatile flag status_dead = YES; /* device is legally dead until proven alive */ +static flag status_open = NO; /* in use or not */ + +static volatile flag status_bytes_wr = NO; /* write FM at close or not */ +static volatile flag status_bytes_rd = NO; /* (rd|wr) used for rewinding */ + +static volatile unsigned long status_cmd_pending = 0; /* cmd in progress */ +static volatile flag status_expect_int = NO; /* ready for interrupts */ +static volatile flag status_timer_on = NO; /* using time-out */ +static volatile int status_error = 0; /* int handler may detect error */ +static volatile flag status_eof_detected = NO; /* end of file */ +static volatile flag status_eom_detected = NO; /* end of recorded media */ +static volatile flag status_eot_detected = NO; /* end of tape */ +static volatile flag doing_read = NO; +static volatile flag doing_write = NO; + +static volatile unsigned long dma_bytes_todo; +static volatile unsigned long dma_bytes_done; +static volatile unsigned dma_mode = 0; /* !=0 also means DMA in use */ +static flag need_rewind = YES; + +static dev_t current_tape_dev = QIC02_TAPE_MAJOR << 8; +static int extra_blocks_left = BLOCKS_BEYOND_EW; + + +/* return_*_eof: + * NO: not at EOF, + * YES: tell app EOF was reached (return 0). + * + * return_*_eof==YES && reported_*_eof==NO ==> + * return current buffer, next time(s) return EOF. + * + * return_*_eof==YES && reported_*_eof==YES ==> + * at EOF and application knows it, so we can + * move on to the next file. + * + */ +static flag return_read_eof = NO; /* set to signal app EOF was reached */ +static flag return_write_eof = NO; +static flag reported_read_eof = NO; /* set when we've done that */ +static flag reported_write_eof = NO; + + +#ifdef TP_HAVE_SEEK +/* This is for doing `mt seek ' */ +static char seek_addr_buf[SEEK_BUF_SIZE]; +#endif + + +/* In write mode, we have to write a File Mark after the last block written, + * when the tape device is closed. Tape repositioning and reading in write + * mode is allowed as long as no actual writing has been done. After writing + * the File Mark, repositioning and reading are allowed again. + */ +static int mode_access; /* access mode: READ or WRITE */ + + +/* This is the actual kernel buffer where the interrupt routines read + * from/write to. It is needed because the DMA channels 1 and 3 cannot + * access the user buffers. [The kernel buffer must reside in the lower + * 1MBytes of system memory because of the DMA controller.] + * The user must ensure that a large enough buffer is passed to the + * kernel, in order to reduce tape repositioning. + * + * The buffer is 512 bytes larger than expected, because I want to align it + * at 512 bytes, to prevent problems with 64k boundaries. + */ + +static volatile char tape_qic02_buf[TPQBUF_SIZE+TAPE_BLKSIZE]; +/* A really good compiler would be able to align this at 512 bytes... :-( */ + +static unsigned long buffaddr; /* aligned physical address of buffer */ + + +/* This translates minor numbers to the corresponding recording format: */ +static char *format_names[] = { + "not set", /* for dumb drives unable to handle format selection */ + "11", /* extinct */ + "24", + "120", + "150", + "300", /* untested. */ + "600" /* untested. */ +}; + + +/* `exception_list' is needed for exception status reporting. + * Exceptions 1..14 are defined by QIC-02 rev F. + * The drive status is matched sequentially to each entry, + * ignoring irrelevant bits, until a match is found. If no + * match is found, exception number 0 is used. (That should of + * course never happen...) The original table was based on the + * "Exception Status Summary" in QIC-02 rev F, but some changes + * were required to make it work with real-world drives. + * + * Exception 1 (CNI) is changed to also cover status 0x00e0 (mask USL), + * Exception 4 (EOM) is changed to also cover status 0x8288 (mask EOR), + * Exception 11 (FIL) is changed to also cover status 0x0089 (mask EOM). + * Exception 15 (EOR) is added for seek-to-end-of-data (catch EOR), + * Exception 16 (BOM) is added for beginning-of-media (catch BOM). + */ +static struct exception_list_type { + short mask, code; + char *msg; +} exception_list[] = { + {0, 0, + "Unknown exception status code", /* extra: 0 */}, + {~(TP_WRP|TP_USL), TP_ST0|TP_CNI, + /* My Wangtek 5150EQ sometimes reports a status code + * of 0x00e0, which is not a valid exception code, but + * I think it should be recognized as "NO CARTRIDGE". + */ + "Cartridge not in place" /* 1 */}, + {-1, TP_ST0|TP_CNI|TP_USL|TP_WRP, + "Drive not online" /* 2 */}, + {~(TP_ST1|TP_BOM), TP_ST0|TP_WRP, + "Write protected cartridge" /* 3 */}, + {~(TP_ST1|TP_EOR), TP_ST0|TP_EOM, + "End of media" /* 4 */}, + {~TP_WRP, TP_ST0|TP_UDA| TP_ST1|TP_BOM, + "Read or Write abort. Rewind tape." /* 5 */}, + {~TP_WRP, TP_ST0|TP_UDA, + "Read error. Bad block transferred." /* 6 */}, + {~TP_WRP, TP_ST0|TP_UDA|TP_BNL, + "Read error. Filler block transferred." /* 7 */}, + {~TP_WRP, TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT, + "Read error. No data detected." /* 8 */}, + {~TP_WRP, TP_ST0|TP_EOM|TP_UDA|TP_BNL |TP_ST1|TP_NDT, + "Read error. No data detected. EOM." /* 9 */}, + {~(TP_WRP|TP_MBD|TP_PAR|TP_EOR), TP_ST0|TP_UDA|TP_BNL |TP_ST1|TP_NDT|TP_BOM, + "Read error. No data detected. BOM." /* 10 */}, + {~(TP_WRP|TP_EOM), TP_ST0|TP_FIL, + /* Status 0x0089 (EOM & FM) is viewed as an FM, + * because it can only happen during a read. + * EOM is checked separately for an FM condition. + */ + "File mark detected" /* 11 */}, + {~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_ILL, + "Illegal command" /* 12 */}, + {~(TP_ST0|TP_CNI|TP_USL|TP_WRP|TP_BOM), TP_ST1|TP_POR, + "Reset occurred" /* 13 */}, + {~TP_WRP, TP_ST0|TP_FIL|TP_MBD, /* NOTE: ST1 not set! */ + "Marginal block detected" /* 14 */}, + {~(TP_ST0|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL |TP_NDT), TP_ST1|TP_EOR, + /********** Is the extra TP_NDT really needed Eddy? **********/ + "End of recorded media" /* extra: 15 */}, + /* 15 is returned when SEEKEOD completes successfully */ + {~(TP_WRP|TP_ST0), TP_ST1|TP_BOM, + "Beginning of media" /* extra: 16 */} +#ifdef CYPHER_BUG + /* Perhaps the Cypher driver clears the TP_BOM bit after the + * status has been read? The QIC-02 specs explicitly state that + * the BOM bit should remain set as long as the tape is logically + * at the beginning of the tape. + */ + ,{-1, TP_ST1, + "Hmm, this must be Cypher drive... Aaargh" /* extra */} +#endif +}; +#define NR_OF_EXC (sizeof(exception_list)/sizeof(struct exception_list_type)) + + + +static void tpqputs(char *s) +{ + printk(TPQIC_NAME ": %s\n", s); +} /* tpqputs */ + + +/* Perform byte order swapping for a 16-bit word. + * + * [FIXME] This should probably be in include/asm/ + * ([FIXME] i486 can do this faster) + */ +static inline void byte_swap_w(volatile unsigned short * w) +{ + int t = *w; + + *w = (t>>8) | ((t & 0xff)<<8); +} + + + +/* Init control register bits on interface card. + * For Archive, interrupts must be enabled explicitly. + * Wangtek interface card requires ONLINE to be set, Archive SC402/SC499R + * cards keep it active all the time. + */ +static void ifc_init(void) +{ +#if TAPE_QIC02_IFC == WANGTEK + ctlbits = WT_CTL_ONLINE; /* online */ + outb_p(ctlbits, QIC_CTL_PORT); + +#elif TAPE_QIC02_IFC == ARCHIVE + ctlbits = 0; /* no interrupts yet */ + outb_p(ctlbits, QIC_CTL_PORT); + outb_p(0, AR_RESET_DMA_PORT); /* dummy write to reset DMA */ +#else +# error No valid interface card specified +#endif +} /* ifc_init */ + + +static void report_exception(unsigned n) +{ + if (n >= NR_OF_EXC) { tpqputs("Oops -- report_exception"); n = 0; } + printk(TPQIC_NAME ": sense: %s\n", exception_list[n].msg); +} /* report_exception */ + + +/* Try to map the drive-exception bits `s' to a predefined "exception number", + * by comparing the significant exception bits for each entry in the + * exception table (`exception_list[]'). + * It is assumed that s!=0. + */ +static int decode_exception_nr(short s) /* s must be short, because of sign-extension */ +{ + int i; + + for (i=1; i= 0) + sensemsg(n); +} /* report_error */ +#endif + + +/* perform appropriate action for certain exceptions */ +static void handle_exception(int exnr, int exbits) +{ + if (exnr==EXC_NCART) { + /* Cartridge was changed. Redo sense(). + * EXC_NCART should be handled in open(). + * It is not permitted to remove the tape while + * the tape driver has open files. + */ + need_rewind = YES; + status_eof_detected = NO; + status_eom_detected = NO; + } + else if (exnr==EXC_XFILLER) + tpqputs("[Bad block -- filler data transferred.]"); + else if (exnr==EXC_XBAD) + tpqputs("[CRC failed!]"); + else if (exnr==EXC_MARGINAL) { + /* A marginal block behaves much like a FM. + * User may continue reading, if desired. + */ + tpqputs("[Marginal block]"); + doing_read = NO; + } else if (exnr==EXC_FM) + doing_read = NO; +} /* handle_exception */ + + +static inline int is_exception(void) +{ + return (inb(QIC_STAT_PORT) & QIC_STAT_EXCEPTION) == 0; +} /* is_exception */ + + +/* Reset the tape drive and controller. + * When reset fails, it marks the drive as dead and all + * requests (except reset) are to be ignored (ENXIO). + */ +static int tape_reset(int verbose) +{ + ifc_init(); /* reset interface card */ + + outb_p(ctlbits | QIC_CTL_RESET, QIC_CTL_PORT); /* assert reset */ + + /* Next, we need to wait >=25 usec. */ + udelay(30); + + /* after reset, we will be at BOT (modulo an automatic rewind) */ + status_eof_detected = NO; + status_eom_detected = NO; + status_cmd_pending = 0; + need_rewind = YES; + doing_read = doing_write = NO; + ioctl_status.mt_fileno = ioctl_status.mt_blkno = 0; + + outb_p(ctlbits & ~QIC_CTL_RESET, QIC_CTL_PORT); /* de-assert reset */ + /* KLUDGE FOR G++ BUG */ + { int stat = inb_p(QIC_STAT_PORT); + status_dead = ((stat & QIC_STAT_RESETMASK) != QIC_STAT_RESETVAL); } + /* if successful, inb(STAT) returned RESETVAL */ + if (status_dead) + printk(TPQIC_NAME ": reset failed!\n"); + else if (verbose) + printk(TPQIC_NAME ": reset successful\n"); + + return (status_dead)? TE_DEAD : TE_OK; +} /* tape_reset */ + + + +/* Notify tape drive of a new command. It only waits for the + * command to be accepted, not for the actual command to complete. + * + * Before calling this routine, QIC_CMD_PORT must have been loaded + * with the command to be executed. + * After this routine, the exception bit must be checked. + * This routine is also used by rdstatus(), so in that case, any exception + * must be ignored (`ignore_ex' flag). + */ +static int notify_cmd(char cmd, short ignore_ex) +{ + int i; + + outb_p(cmd, QIC_CMD_PORT); /* output the command */ + + /* wait 1 usec before asserting /REQUEST */ + udelay(1); + + if ((!ignore_ex) && is_exception()) { + tpqputs("*** exception detected in notify_cmd"); + /** force a reset here **/ + if (tape_reset(1)==TE_DEAD) + return TE_DEAD; + if (is_exception()) { + tpqputs("exception persists after reset."); + tpqputs(" ^ exception ignored."); + } + } + + outb_p(ctlbits | QIC_CTL_REQUEST, QIC_CTL_PORT); /* set request bit */ + i = TAPE_NOTIFY_TIMEOUT; + /* The specs say this takes about 500 usec, but there is no upper limit! + * If the drive were busy retensioning or something like that, + * it could be *much* longer! + */ + while ((inb_p(QIC_STAT_PORT) & QIC_STAT_READY) && (--i>0)) + /*skip*/; /* wait for ready */ + if (i==0) { + tpqputs("timed out waiting for ready in notify_cmd"); + status_dead = YES; + return TE_TIM; + } + + outb_p(ctlbits & ~QIC_CTL_REQUEST, QIC_CTL_PORT); /* reset request bit */ + i = TAPE_NOTIFY_TIMEOUT; + /* according to the specs this one should never time-out */ + while (((inb_p(QIC_STAT_PORT) & QIC_STAT_READY) == 0) && (--i>0)) + /*skip*/; /* wait for not ready */ + if (i==0) { + tpqputs("timed out waiting for !ready in notify_cmd"); + status_dead = YES; + return TE_TIM; + } + /* command accepted */ + return TE_OK; +} /* notify_cmd */ + + + +/* Wait for a command to complete, with timeout */ +static int wait_for_ready(time_t timeout) +{ + int stat; + time_t spin_t; + + /* Wait for ready or exception, without driving the loadavg up too much. + * In most cases, the tape drive already has READY asserted, + * so optimize for that case. + * + * First, busy wait a few usec: + */ + spin_t = 50; + while (((stat = inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK) && (--spin_t>0)) + /*SKIP*/; + if ((stat & QIC_STAT_READY) == 0) + return TE_OK; /* covers 99.99% of all calls */ + + /* Then use schedule() a few times */ + spin_t = 3; /* max 0.03 sec busy waiting */ + if (spin_t > timeout) + spin_t = timeout; + timeout -= spin_t; + spin_t += jiffies; + + while (((stat = inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK) && (jiffiestimeout = jiffies + 30; /* nap 0.30 sec between checks, */ + current->state = TASK_INTERRUPTIBLE; + schedule(); /* but could be woken up earlier by signals... */ + } + + /* don't use jiffies for this test because it may have changed by now */ + if ((stat & QIC_STAT_MASK) == QIC_STAT_MASK) { + tpqputs("wait_for_ready() timed out"); + return TE_TIM; + } + + if ((stat & QIC_STAT_EXCEPTION) == 0) { + tpqputs("exception detected after waiting_for_ready"); + return TE_EX; + } else { + return TE_OK; + } +} /* wait_for_ready */ + + +/* Send some data to the drive */ +static int send_qic02_data(char sb[], unsigned size, int ignore_ex) +{ + int i, stat; + + for (i=0; i0) && ((inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK)) + n--; /* wait for ready or exception or timeout */ + if (n==0) { + /* n (above) should be chosen such that on your machine + * you rarely ever see the message below, and it should + * be small enough to give reasonable response time.] + */ + tpqputs("waiting looong in rdstatus() -- drive dead?"); + while ((inb_p(QIC_STAT_PORT) & QIC_STAT_MASK) == QIC_STAT_MASK) + schedule(); + tpqputs("finished waiting in rdstatus()"); + } + + (void) notify_cmd(qcmd, 1); /* send read status command */ + /* ignore return code -- should always be ok, STAT may contain + * exception flag from previous exception which we are trying to clear. + */ + + if (TP_DIAGS(current_tape_dev)) + printk(TPQIC_NAME ": reading status bytes: "); + + for (q=stp; q20 usec */ + + outb_p(ctlbits & ~QIC_CTL_REQUEST, QIC_CTL_PORT); /* un-set request */ + + } + + /* Specs say we should wait for READY here. + * My drive doesn't seem to need it here yet, but others do? + */ + while (inb_p(QIC_STAT_PORT) & QIC_STAT_READY) + /*skip*/; /* wait for ready */ + + if (TP_DIAGS(current_tape_dev)) + printk("\n"); + + return TE_OK; +} /* rdstatus */ + + + +/* Get standard status (6 bytes). + * The `.dec' and `.urc' fields are in MSB-first byte-order, + * so they have to be swapped first. + */ +static int get_status(char *stp) +{ + int stat = rdstatus(stp, TPSTATSIZE, QCMD_RD_STAT); +#if defined(i386) || defined(i486) + byte_swap_w(&tperror.dec); + byte_swap_w(&tperror.urc); +#else + /* should probably swap status bytes #definition */ +#endif + return stat; +} /* get_status */ + + +#if 0 +/* This fails for my Wangtek drive */ +/* get "Extended Status Register 3" (64 bytes) + * + * If the meaning of the returned bytes were known, the MT_TYPE + * identifier could be used to decode them, since they are + * "vendor unique". :-( + */ +static int get_ext_status3(void) +{ + char vus[64]; /* vendor unique status */ + int stat, i; + + tpqputs("Attempting to read Extended Status 3..."); + stat = rdstatus(vus, sizeof(vus), QCMD_RD_STAT_X3); + if (stat != TE_OK) + return stat; + + tpqputs("Returned status bytes:"); + for (i=0; i0 */ +{ + int stat; + + TPQPUTS("start_dma() enter"); + TPQDEB({printk(TPQIC_NAME ": doing_read==%d, doing_write==%d\n", doing_read, doing_write);}) + + dma_bytes_done = 0; + dma_bytes_todo = bytes_todo; + status_error = NO; + /* dma_mode!=0 indicates that the dma controller is in use */ + dma_mode = (mode == WRITE)? DMA_MODE_WRITE : DMA_MODE_READ; + + /* Only give READ/WRITE DATA command to tape drive if we haven't + * done that already. Otherwise the drive will rewind to the beginning + * of the current file on tape. Any QIC command given other than + * R/W FM will break the read/write transfer cycle. + * do_qic_cmd() will terminate doing_{read,write} + */ + if ((doing_read == NO) && (doing_write == NO)) { + /* First, we have to clear the status -- maybe remove TP_FIL??? + */ + +#if 0 + /* Next dummy get status is to make sure CNI is valid, + since we're only just starting a read/write it doesn't + matter some exceptions are cleared by reading the status; + we're only interested in CNI and WRP. -Eddy */ + get_status((char *) &tperror); +#else + /* TP_CNI should now be handled in open(). -Hennus */ +#endif + + stat = tp_sense(((mode == WRITE)? 0 : TP_WRP) | TP_BOM | TP_FIL); + if (stat != TE_OK) + return stat; + +#if OBSOLETE + /************* not needed iff rd_status() would wait for ready!!!!!! **********/ + if (wait_for_ready(TIM_S) != TE_OK) { /*** not sure this is needed ***/ + tpqputs("wait_for_ready failed in start_dma"); + return -EIO; + } +#endif + + /* Tell the controller the data direction */ + + /* r/w, timeout medium, check exceptions, sets status_cmd_pending. */ + stat = send_qic02_cmd((mode == WRITE)? QCMD_WRT_DATA : QCMD_RD_DATA, TIM_M, 0); + if (stat!=TE_OK) { + printk(TPQIC_NAME ": start_dma: init %s failed\n", + (mode == WRITE)? "write" : "read"); + (void) tp_sense(0); + return stat; + } + + /* Do this last, because sense() will clear the doing_{read,write} + * flags, causing trouble next time around. + */ + if (wait_for_ready(TIM_M) != TE_OK) + return -EIO; + switch (mode) { + case READ: + doing_read = YES; + break; + case WRITE: + doing_write = YES; + break; + default: + printk(TPQIC_NAME ": requested unknown mode %d\n", mode); + panic(TPQIC_NAME ": invalid mode in start_dma()"); + } + + } else if (is_exception()) { + /* This is for Archive drives, to handle reads with 0 bytes + * left for the last read request. + * + * ******** this also affects EOF/EOT handling! ************ + */ + tpqputs("detected exception in start_dma() while transfer in progress"); + status_error = YES; + return TE_END; + } + + + status_expect_int = YES; + + /* This assumes tape is already positioned, but these + * semi-'intelligent' drives are unpredictable... + */ + TIMERON(TIM_M*2); + + /* initiate first data block read from/write to the tape controller */ + + cli(); + dma_transfer(); + sti(); + + TPQPUTS("start_dma() end"); + return TE_OK; +} /* start_dma */ + + +/* This cleans up after the dma transfer has completed + * (or failed). If an exception occurred, a sense() + * must be done. If the exception was caused by a FM, + * sense() will set `status_eof_detected' and + * `status_eom_detected', as required. + */ +static void end_dma(unsigned long * bytes_done) +{ + int stat = TE_OK; + + TIMEROFF; + + TPQPUTS("end_dma() enter"); + + disable_dma(TAPE_QIC02_DMA); + clear_dma_ff(TAPE_QIC02_DMA); + +#if TAPE_QIC02_IFC == WANGTEK + outb_p(WT_CTL_ONLINE, QIC_CTL_PORT); /* back to normal */ +#elif TAPE_QIC02_IFC == ARCHIVE + outb_p(0, AR_RESET_DMA_PORT); +#endif + + stat = wait_for_ready(TIM_M); + if (status_error || (stat!=TE_OK)) { + tpqputs("DMA transfer exception"); + stat = tp_sense((dma_mode==READ)? TP_WRP : 0); + /* no return here -- got to clean up first! */ + } + /* take the tape controller offline */ + + /* finish off DMA stuff */ + + + dma_mode = 0; + /* Note: The drive is left on-line, ready for the next + * data transfer. + * If the next command to the drive does not continue + * the pending cycle, it must do 2 sense()s first. + */ + + *bytes_done = dma_bytes_done; + status_expect_int = NO; + ioctl_status.mt_blkno += (dma_bytes_done / TAPE_BLKSIZE); + + TPQPUTS("end_dma() exit"); + /*** could return stat here ***/ +} /* end_dma */ + +/*********** Below are the (public) OS-interface procedures ***********/ + + +/* tape_qic02_times_out() is called when a DMA transfer doesn't complete + * quickly enough. Usually this means there is something seriously wrong + * with the hardware/software, but it could just be that the controller + * has decided to do a long rewind, just when I didn't expect it. + * Just try again. + */ +static void tape_qic02_times_out(void) +{ + printk("time-out in %s driver\n", TPQIC_NAME); + if ((status_cmd_pending>0) || dma_mode) { + /* takes tooo long, shut it down */ + status_dead = YES; + status_cmd_pending = 0; + status_timer_on = NO; + status_expect_int = NO; + status_error = YES; + if (dma_mode) { + dma_mode = 0; /* signal end to read/write routine */ + wake_up(&tape_qic02_transfer); + } + } +} /* tape_qic02_times_out */ + +/* + * Interrupt handling: + * + * 1) Interrupt is generated iff at the end of + * a 512-DMA-block transfer. + * 2) EXCEPTION is not raised unless something + * is wrong or EOT/FM is detected. + * 3) FM EXCEPTION is set *after* the last byte has + * been transferred by DMA. By the time the interrupt + * is handled, the EXCEPTION may already be set. + * + * So, + * 1) On EXCEPTION, assume data has been transferred, so + * continue as usual, but set a flag to indicate the + * exception was detected. + * Do a sense status when the flag is found set. + * 2) Do not attempt to continue a transfer after an exception. + * [??? What about marginal blocks???????] + */ + + +/* tape_qic02_interrupt() is called when the tape controller completes + * a DMA transfer. + * We are not allowed to sleep here! + * + * Check if the transfer was successful, check if we need to transfer + * more. If the buffer contains enough data/is empty enough, signal the + * read/write() thread to copy to/from user space. + * When we are finished, set flags to indicate end, disable timer. + * NOTE: This *must* be fast! + */ +static void tape_qic02_interrupt(int unused) +{ + int stat, r, i; + + TIMEROFF; + + if (status_expect_int) { + if (TP_DIAGS(current_tape_dev)) + printk("@"); + + stat = inb(QIC_STAT_PORT); /* Knock, knock */ +#if TAPE_QIC02_IFC == ARCHIVE /* "Who's there?" */ + if (((stat & (AR_STAT_DMADONE)) == 0) && + ((stat & (QIC_STAT_EXCEPTION)) != 0)) { + TIMERCONT; + return; /* "Linux with IRQ sharing" */ + } +#endif + if ((stat & QIC_STAT_EXCEPTION) == 0) { /* exception occurred */ + /* Possible causes for an exception during a transfer: + * - during a write-cycle: end of tape (EW) hole detected. + * - during a read-cycle: filemark or EOD detected. + * - something went wrong + * So don't continue with the next block. + */ + tpqputs("isr: exception on tape controller"); + printk(" status %02x\n", stat); + status_error = TE_EX; + + dma_bytes_done += TAPE_BLKSIZE; + + dma_mode = 0; /* wake up rw() */ + status_expect_int = NO; + wake_up(&tape_qic02_transfer); + return; + } + /* return if tape controller not ready, or + * if dma channel hasn't finished last byte yet. + */ + r = 0; +/* Skip next ready check for Archive controller because + * it may be busy reading ahead. Weird. --hhb + */ +#if TAPE_QIC02_IFC != ARCHIVE /* I think this is a drive-dependency, not IFC -- hhb */ + if (stat & QIC_STAT_READY) { /* not ready */ + tpqputs("isr: ? Tape controller not ready"); + r = 1; + } +#endif + + if ( (i = get_dma_residue(TAPE_QIC02_DMA)) != 0 ) { + printk(TPQIC_NAME ": dma_residue == %x !!!\n", i); + r = 1; /* big trouble, but can't do much about it... */ + } + + if (r) + return; + + /* finish DMA cycle */ + + /* no errors detected, continue */ + dma_bytes_done += TAPE_BLKSIZE; + if (dma_bytes_done >= dma_bytes_todo) { + /* finished! Wakeup rw() */ + dma_mode = 0; + status_expect_int = NO; + TPQPUTS("isr: dma_bytes_done"); + wake_up(&tape_qic02_transfer); + } else { + /* start next transfer, account for track-switching time */ + timer_table[TAPE_QIC02_TIMER].expires = jiffies + 6*HZ; + dma_transfer(); + } + } else { + printk(TPQIC_NAME ": Unexpected interrupt, stat == %x\n", + inb(QIC_STAT_PORT)); + } +} /* tape_qic02_interrupt */ + + +static int tape_qic02_lseek(struct inode * inode, struct file * file, off_t offset, int origin) +{ + return -EINVAL; /* not supported */ +} /* tape_qic02_lseek */ + + +/* read/write routines: + * This code copies between a kernel buffer and a user buffer. The + * actual data transfer is done using DMA and interrupts. Time-outs + * are also used. + * + * When a filemark is read, we return '0 bytes read' and continue with the + * next file after that. + * When EOM is read, we return '0 bytes read' twice. + * When the EOT marker is detected on writes, '0 bytes read' should be + * returned twice. If user program does a MTNOP after that, 2 additional + * blocks may be written. ------- FIXME: Implement this correctly ************************************************* + * + * Only read/writes in multiples of 512 bytes are accepted. + * When no bytes are available, we sleep() until they are. The controller will + * generate an interrupt, and we (should) get a wake_up() call. + * + * Simple buffering is used. User program should ensure that a large enough + * buffer is used. Usually the drive does some buffering as well (something + * like 4k or so). + * + * Scott S. Bertilson suggested to continue filling the user buffer, rather + * than waste time on a context switch, when the kernel buffer fills up. + */ + +/* + * Problem: tar(1) doesn't always read the entire file. Sometimes the entire file + * has been read, but the EOF token is never returned to tar(1), simply because + * tar(1) knows it has already read all of the data it needs. So we must use + * open/release to reset the `reported_read_eof' flag. If we don't, the next read + * request would return the EOF flag for the previous file. + */ + +static int tape_qic02_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int error; + dev_t dev = inode->i_rdev; + unsigned short flags = filp->f_flags; + unsigned long bytes_todo, bytes_done, total_bytes_done = 0; + int stat; + + if (TP_DIAGS(current_tape_dev)) + printk(TPQIC_NAME ": request READ, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n", + MINOR(dev), buf, count, filp->f_pos, flags); + + if (count % TAPE_BLKSIZE) { /* Only allow mod 512 bytes at a time. */ + tpqputs("Wrong block size"); + return -EINVAL; + } + + /* Just assume everything is ok. Controller will scream if not. */ + + if (status_bytes_wr) /* Once written, no more reads, 'till after WFM. */ + return -EACCES; + + + /* Make sure buffer is safe to write into. */ + error = verify_area(VERIFY_WRITE, buf, count); + if (error) { + printk(TPQIC_NAME ": read: verify_area(WRITE, %lx, %x) failed\n", buf, count); + return error; + } + + /* This is rather ugly because it has to implement a finite state + * machine in order to handle the EOF situations properly. + */ + while (count>=0) { + bytes_done = 0; + /* see how much fits in the kernel buffer */ + bytes_todo = TPQBUF_SIZE; + if (bytes_todo>count) + bytes_todo = count; + + /* Must ensure that user program sees exactly one EOF token (==0) */ + if (return_read_eof==YES) { + printk("read: return_read_eof==%d, reported_read_eof==%d, total_bytes_done==%d\n", return_read_eof, reported_read_eof, total_bytes_done); + + if (reported_read_eof==NO) { + /* have not yet returned EOF to user program */ + if (total_bytes_done>0) { + return total_bytes_done; /* next time return EOF */ + } else { + reported_read_eof = YES; /* move on next time */ + return 0; /* return EOF */ + } + } else { + /* Application program has already received EOF + * (above), now continue with next file on tape, + * if possible. + * When the FM is reached, EXCEPTION is set, + * causing a sense(). Subsequent read/writes will + * continue after the FM. + */ +/*********** ?????????? this should check for (EOD|NDT), not EOM, 'cause we can read past EW: ************/ + if (status_eom_detected) + /* If EOM, nothing left to read, so keep returning EOFs. + *** should probably set some flag to avoid clearing + *** status_eom_detected through ioctls or something + */ + return 0; + else { + /* just eof, there may be more files ahead... */ + return_read_eof = NO; + reported_read_eof = NO; + status_eof_detected = NO; /* reset this too */ + /*fall through*/ + } + } + } + +/*****************************/ + if (bytes_todo==0) + return total_bytes_done; + + if (bytes_todo>0) { + /* start reading data */ + if (is_exception()) /****************************************/ + tpqputs("is_exception() before start_dma()!"); +/****************************************************************** + ***** if start_dma() fails because the head is positioned 0 bytes + ***** before the FM, (causing EXCEPTION to be set) return_read_eof should + ***** be set to YES, and we should return total_bytes_done, rather than -ENXIO. + ***** The app should recognize this as an EOF condition. + ***************************************************************************/ + stat = start_dma(READ, bytes_todo); + if (stat == TE_OK) { + /* Wait for transfer to complete, interrupt should wake us */ + while (dma_mode != 0) { + sleep_on(&tape_qic02_transfer); + } + if (status_error) + return_read_eof = YES; + } else if (stat != TE_END) { + /* should do sense() on error here */ +#if 0 + return -ENXIO; +#else + printk("Trouble: stat==%02x\n", stat); + return_read_eof = YES; + /*************** check EOF/EOT handling!!!!!! **/ +#endif + } + end_dma(&bytes_done); + if (bytes_done>bytes_todo) { + tpqputs("read: Oops, read more bytes than requested"); + return -EIO; + } + /* copy buffer to user-space in one go */ + if (bytes_done>0) + memcpy_tofs( (void *) buf, (void *) buffaddr, bytes_done); +#if 1 + /* Checks Ton's patch below */ + if ((return_read_eof == NO) && (status_eof_detected == YES)) { + printk(TPQIC_NAME ": read(): return_read_eof=%d, status_eof_detected=YES. return_read_eof:=YES\n", return_read_eof); + } +#endif + if ((bytes_todo != bytes_done) || (status_eof_detected == YES)) + /* EOF or EOM detected. return EOF next time. */ + return_read_eof = YES; + } /* else: ignore read request for 0 bytes */ + + if (bytes_done>0) { + status_bytes_rd = YES; + buf += bytes_done; + filp->f_pos += bytes_done; + total_bytes_done += bytes_done; + count -= bytes_done; + } + } + tpqputs("read request for <0 bytes"); + return -EINVAL; +} /* tape_qic02_read */ + + + +/* The drive detects near-EOT by means of the holes in the tape. + * When the holes are detected, there is some space left. The drive + * reports this as a TP_EOM exception. After clearing the exception, + * the drive should accept two extra blocks. + * + * It seems there are some archiver programs that would like to use the + * extra space for writing a continuation marker. The driver should return + * end-of-file to the user program on writes, when the holes are detected. + * If the user-program wants to use the extra space, it should use the + * MTNOP ioctl() to get the generic status register and may then continue + * writing (max 1kB). ----------- doesn't work yet............... + * + * EOF behaviour on writes: + * If there is enough room, write all of the data. + * If there is insufficient room, write as much as will fit and + * return the amount written. If the requested amount differs from the + * written amount, the application program should recognize that as the + * end of file. Subsequent writes will return -ENOSPC. + * Unless the minor bits specify a rewind-on-close, the tape will not + * be rewound when it is full. The user-program should do that, if desired. + * If the driver were to do that automatically, a user-program could be + * confused about the EOT/BOT condition after re-opening the tape device. + * + * Multiple volume support: Tar closes the tape device before prompting for + * the next tape. The user may then insert a new tape and tar will open the + * tape device again. The driver will detect an exception status in (No Cartridge) + * and force a rewind. After that tar may continue writing. + */ +static int tape_qic02_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + int error; + dev_t dev = inode->i_rdev; + unsigned short flags = filp->f_flags; + unsigned long bytes_todo, bytes_done, total_bytes_done = 0; + + if (TP_DIAGS(current_tape_dev)) + printk(TPQIC_NAME ": request WRITE, minor=%x, buf=%lx, count=%x, pos=%x, flags=%x\n", + MINOR(dev), buf, count, filp->f_pos, flags); + + if (count % TAPE_BLKSIZE) { /* only allow mod 512 bytes at a time */ + tpqputs("Wrong block size"); + return -EINVAL; + } + + if (mode_access==READ) { + tpqputs("Not in write mode"); + return -EACCES; + } + + /* open() does a sense() and we can assume the tape isn't changed + * between open() and release(), so the tperror.exs bits will still + * be valid. + */ + if ((tperror.exs & TP_ST0) && (tperror.exs & TP_WRP)) { + tpqputs("Cartridge is write-protected."); + return -EACCES; /* don't even try when write protected */ + } + + /* Make sure buffer is safe to read from. */ + error = verify_area(VERIFY_READ, buf, count); + if (error) { + printk(TPQIC_NAME ": write: verify_area(READ, %lx, %x) failed\n", buf, count); + return error; + } + + if (doing_read == YES) + terminate_read(0); + + while (count>=0) { + /* see how much fits in the kernel buffer */ + bytes_done = 0; + bytes_todo = TPQBUF_SIZE; + if (bytes_todo>count) + bytes_todo = count; + + if (return_write_eof == YES) { + /* return_write_eof should be reset on reverse tape movements. */ + + if (reported_write_eof==NO) { + if (bytes_todo>0) { + tpqputs("partial write"); + /* partial write signals EOF to user program */ + } + reported_write_eof = YES; + return total_bytes_done; + } else { + return -ENOSPC; /* return error */ + } + } + + /* Quit when done. */ + if (bytes_todo==0) + return total_bytes_done; + + + /* copy from user to DMA buffer and initiate transfer. */ + if (bytes_todo>0) { + memcpy_fromfs( (void *) buffaddr, (void *) buf, bytes_todo); + +/****************** similar problem with read() at FM could happen here at EOT. + ******************/ + +/***** if at EOT, 0 bytes can be written. start_dma() will + ***** fail and write() will return ENXIO error + *****/ + if (start_dma(WRITE, bytes_todo) != TE_OK) { + tpqputs("write: start_dma() failed"); + /* should do sense() on error here */ + return -ENXIO; /*********** FIXTHIS **************/ + } + + /* Wait for write to complete, interrupt should wake us. */ + while ((status_error == 0) && (dma_mode != 0)) { + sleep_on(&tape_qic02_transfer); + } + + end_dma(&bytes_done); + if (bytes_done>bytes_todo) { + tpqputs("write: Oops, wrote more bytes than requested"); + return -EIO; + } + /* If the dma-transfer was aborted because of an exception, + * status_error will have been set in the interrupt handler. + * Then end_dma() will do a sense(). + * If the exception was EXC_EOM, the EW-hole was encountered + * and two more blocks could be written. For the time being we'll + * just consider this to be the EOT. + * Otherwise, something Bad happened, such as the maximum number + * of block-rewrites was exceeded. [e.g. A very bad spot on tape was + * encountered. Normally short dropouts are compensated for by + * rewriting the block in error, up to 16 times. I'm not sure + * QIC-24 drives can do this.] + */ + if (status_error) { + if (status_eom_detected == YES) { + tpqputs("write: EW detected"); + return_write_eof = YES; + } else { + /* probably EXC_RWA */ + tpqputs("write: dma: error in writing"); + return -EIO; + } + } + if (bytes_todo != bytes_done) + /* EOF or EOM detected. return EOT next time. */ + return_write_eof = YES; + } + /* else: ignore write request for 0 bytes. */ + + if (bytes_done>0) { + status_bytes_wr = YES; + buf += bytes_done; + filp->f_pos += bytes_done; + total_bytes_done += bytes_done; + count -= bytes_done; + } + } + tpqputs("write request for <0 bytes"); + printk(TPQIC_NAME ": status_bytes_wr %x, buf %x, total_bytes_done %x, count %x\n", status_bytes_wr, buf, total_bytes_done, count); + return -EINVAL; +} /* tape_qic02_write */ + + + +/* tape_qic02_open() + * We allow the device to be opened, even if it is marked 'dead' because + * we want to be able to reset the tape device without rebooting. + * Only one open tape file at a time, except when minor=255. + * Minor 255 is only allowed for resetting and always returns <0. + * + * The density command is only allowed when TP_BOM is set. Thus, remember + * the most recently used minor bits. When they are different from the + * remembered values, rewind the tape and set the required density. + * Don't rewind if the minor bits specify density 0. + */ +static int tape_qic02_open(struct inode * inode, struct file * filp) +{ + dev_t dev = inode->i_rdev; + unsigned short flags = filp->f_flags; + unsigned short dens; + int s; + + status_open = NO; + + if (TP_DIAGS(dev)) { + printk("tape_qic02_open: dev=%x, flags=%x ", dev, flags); + } + + if (MINOR(dev)==255) /* special case for resetting */ + if (suser()) + return (tape_reset(1)==TE_OK) ? -EAGAIN : -ENXIO; + else + return -EPERM; + + if (status_open==YES) { + return -EBUSY; /* only one at a time... */ + } + status_open = YES; + + status_bytes_rd = NO; + status_bytes_wr = NO; + + return_read_eof = NO; /********????????????????*****/ + return_write_eof = (status_eot_detected)? YES : NO; + + /* Clear this in case user app close()d before reading EOF token */ + status_eof_detected = NO; + + reported_read_eof = NO; + reported_write_eof = NO; + + + switch (flags & O_ACCMODE) { + case O_RDONLY: + mode_access = READ; + break; + case O_WRONLY: /* Fallthru... Strictly speaking this is not correct... */ + case O_RDWR: /* reads are allowed as long as nothing is written */ + mode_access = WRITE; + break; + } + + + /* This is to avoid tape-changed problems (TP_CNI exception). */ + if (is_exception()) { + s = tp_sense(TP_WRP|TP_EOM|TP_BOM|TP_CNI|TP_EOR); + if (s != TE_OK) { + status_open = NO; + tpqputs("open: sense() failed after exception was detected"); + return -EIO; + } + } + + + /* not allowed to do QCMD_DENS_* unless tape is rewound */ + if ((TP_DENS(dev)!=0) && (TP_DENS(current_tape_dev) != TP_DENS(dev))) { + /* force rewind if minor bits have changed, + * i.e. user wants to use tape in different format. + * [assuming single drive operation] + */ + tpqputs("Density minor bits have changed. Forcing rewind."); + need_rewind = YES; + } else { + /* density bits still the same, but TP_DIAGS bit + * may have changed. + */ + current_tape_dev = dev; + } + + if (need_rewind == YES) { + s = do_qic_cmd(QCMD_REWIND, TIM_R); + if (s != 0) { + tpqputs("open: rewind failed"); + status_open = NO; + return -EIO; + } + } + + +/* Note: After a reset command, the controller will rewind the tape + * just before performing any tape movement operation! + */ + if (status_dead) { + tpqputs("open: tape dead, attempting reset"); + if (tape_reset(1)!=TE_OK) { + status_open = NO; + return -ENXIO; + } else { + status_dead = NO; + if (tp_sense(~(TP_ST1|TP_ILL)) != TE_OK) { + tpqputs("open: tp_sense() failed\n"); + status_dead = YES; /* try reset next time */ + status_open = NO; + return -EIO; + } + } + } + + /* things should be ok, once we get here */ + + + /* set density: only allowed when TP_BOM status bit is set, + * so we must have done a rewind by now. If not, just skip over. + * Only give set density command when minor bits have changed. + */ + if (TP_DENS(current_tape_dev) == TP_DENS(dev) ) + return 0; + + current_tape_dev = dev; + need_rewind = NO; + dens = TP_DENS(dev); + if (dens < sizeof(format_names)/sizeof(char *)) + printk(TPQIC_NAME ": format: %s%s\n", (dens!=0)? "QIC-" : "", format_names[dens]); + else + tpqputs("Wait for retensioning..."); + + switch (TP_DENS(dev)) { + case 0: /* This one's for Eddy ;-) */ + s = 0; + break; + case 1: + s = do_qic_cmd(QCMD_DENS_11, TIM_S); + break; + case 2: + s = do_qic_cmd(QCMD_DENS_24, TIM_S); + break; + case 3: + s = do_qic_cmd(QCMD_DENS_120, TIM_S); + break; + case 4: + s = do_qic_cmd(QCMD_DENS_150, TIM_S); + break; + case 5: + s = do_qic_cmd(QCMD_DENS_300, TIM_S); + break; + case 6: + s = do_qic_cmd(QCMD_DENS_600, TIM_S); + break; + default: /* otherwise do a retension before anything else */ + s = do_qic_cmd(QCMD_RETEN, TIM_R); + } + if (s != 0) { + status_open = NO; /* fail if fault occurred */ + status_dead = YES; /* force reset */ + current_tape_dev = 0xff80; + return -EIO; + } + + return 0; +} /* tape_qic02_open */ + + +static int tape_qic02_readdir(struct inode * inode, struct file * filp, struct dirent * dp, int count) +{ + return -ENOTDIR; /* not supported */ +} /* tape_qic02_readdir */ + + +static void tape_qic02_release(struct inode * inode, struct file * filp) +{ + dev_t dev = inode->i_rdev; + + if (TP_DIAGS(dev)) + printk("tape_qic02_release: dev=%x\n", dev); + + /* Terminate any pending write cycle. Terminating the read-cycle + * is delayed until it is required to do so for a new command. + */ + terminate_write(-1); + + if (status_dead==YES) + tpqputs("release: device dead!?"); + + if (status_open==NO) { + tpqputs("release: device not open"); + return; + } + /* Rewind only if minor number requires it AND + * read/writes have been done. + */ + if ((TP_REWCLOSE(dev)) && (status_bytes_rd | status_bytes_wr)) { + tpqputs("release: Doing rewind..."); + (void) do_qic_cmd(QCMD_REWIND, TIM_R); + } + + status_open = NO; + return; +} /* tape_qic02_release */ + + + +/* ioctl allows user programs to rewind the tape and stuff like that */ +static int tape_qic02_ioctl(struct inode * inode, struct file * filp, + unsigned int iocmd, unsigned long ioarg) +{ + int error; + short i; + int dev_maj = MAJOR(inode->i_rdev); + int c; + struct mtop operation; + char *stp, *argp; + +#ifdef TP_HAVE_TELL + unsigned char blk_addr[6]; + struct mtpos ioctl_tell; +#endif + + if (TP_DIAGS(current_tape_dev)) + printk(TPQIC_NAME ": ioctl(%4x, %4x, %4x)\n", dev_maj, iocmd, ioarg); + + if (!inode || !ioarg) + return -EINVAL; + + /* check iocmd first */ + + if (dev_maj != QIC02_TAPE_MAJOR) { + printk(TPQIC_NAME ": Oops! Wrong device?\n"); + /* A panic() would be appropriate here */ + return -ENODEV; + } + + c = iocmd & IOCCMD_MASK; + if (c == (MTIOCTOP & IOCCMD_MASK)) { + + /* Compare expected struct size and actual struct size. This + * is useful to catch programs compiled with old #includes. + */ + if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtop)) { + tpqputs("sizeof(struct mtop) does not match!"); + return -EFAULT; + } + error = verify_area(VERIFY_READ, (char *) ioarg, sizeof(operation)); + if (error) + return error; + + /* copy mtop struct from user space to kernel space */ + stp = (char *) &operation; + argp = (char *) ioarg; + for (i=0; i>16)&0xff; + seek_addr_buf[1] = (operation.mt_count>>8)&0xff; + seek_addr_buf[2] = (operation.mt_count)&0xff; + if (operation.mt_count>>24) + return -EINVAL; + + if ((error = do_ioctl_cmd(operation.mt_op)) != 0) + return error; + ioctl_status.mt_resid = 0; + } else { + while (operation.mt_count > 0) { + operation.mt_count--; + if ((error = do_ioctl_cmd(operation.mt_op)) != 0) + return error; + ioctl_status.mt_resid = operation.mt_count; + } + } + return 0; + + } else if (c == (MTIOCGET & IOCCMD_MASK)) { + if (TP_DIAGS(current_tape_dev)) + printk("GET "); + + /* compare expected struct size and actual struct size */ + if (((iocmd & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtget)) { + tpqputs("sizeof(struct mtget) does not match!"); + return -EFAULT; + } + + /* check for valid user address */ + error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_status)); + if (error) + return error; + + /* It appears (gmt(1)) that it is normal behaviour to + * first set the status with MTNOP, and then to read + * it out with MTIOCGET + */ + + /* copy results to user space */ + stp = (char *) &ioctl_status; + argp = (char *) ioarg; + for (i=0; i> IOCSIZE_SHIFT) != sizeof(struct mtpos)) { + tpqputs("sizeof(struct mtpos) does not match!"); + return -EFAULT; + } + + /* check for valid user address */ + error = verify_area(VERIFY_WRITE, (void *) ioarg, sizeof(ioctl_tell)); + if (error) + return error; + + tpqputs("MTTELL reading block address"); + if ((doing_read==YES) || (doing_write==YES)) + finish_rw(QCMDV_TELL_BLK); + + c = rdstatus((char *) blk_addr, sizeof(blk_addr), QCMDV_TELL_BLK); + if (c!=TE_OK) + return -EIO; + + ioctl_tell.mt_blkno = (blk_addr[3] << 16) | (blk_addr[4] << 8) | blk_addr[5]; + + /* copy results to user space */ + stp = (char *) &ioctl_tell; + argp = (char *) ioarg; + for (i=0; i + */ + + /* get IRQ */ + if (irqaction(TAPE_QIC02_IRQ, &tape_qic02_sigaction)) { + printk(TPQIC_NAME ": can't allocate IRQ%d for QIC-02 tape\n", + TAPE_QIC02_IRQ); + return kmem_start; + } + + /* After IRQ, allocate DMA channel */ + if (request_dma(TAPE_QIC02_DMA)) { + printk(TPQIC_NAME ": can't allocate DMA%d for QIC-02 tape\n", + TAPE_QIC02_DMA); + free_irq(TAPE_QIC02_IRQ); + return kmem_start; + } + + if (TPSTATSIZE != 6) { + printk(TPQIC_NAME ": internal error: tpstatus struct incorrect!\n"); + return kmem_start; + } + if ((TPQBUF_SIZE<512) || (TPQBUF_SIZE>=0x10000)) { + printk(TPQIC_NAME ": internal error: DMA buffer size out of range\n"); + return kmem_start; + } + + printk(TPQIC_NAME ": DMA buffers: %u blocks", NR_BLK_BUF); + + /* Setup the page-address for the dma transfer. + * This assumes a one-to-one identity mapping between + * kernel addresses and physical memory. + */ + buffaddr = align_buffer((unsigned long) &tape_qic02_buf, TAPE_BLKSIZE); + printk(", at address 0x%lx (0x%lx)\n", buffaddr, (unsigned long) &tape_qic02_buf); + +#ifndef CONFIG_MAX_16M + if (buffaddr+TPQBUF_SIZE>=0x1000000) { + printk(TPQIC_NAME ": DMA buffer *must* be in lower 16MB\n"); + return kmem_start; + } +#endif + + /* If we got this far, install driver functions */ + if (register_chrdev(QIC02_TAPE_MAJOR, TPQIC_NAME, &tape_qic02_fops)) { + printk(TPQIC_NAME ": Unable to get chrdev major %d\n", + QIC02_TAPE_MAJOR); + return kmem_start; + } + + /* prepare timer */ + TIMEROFF; + timer_table[TAPE_QIC02_TIMER].expires = 0; + timer_table[TAPE_QIC02_TIMER].fn = tape_qic02_times_out; + + if (tape_reset(0)!=TE_OK || tp_sense(TP_WRP|TP_POR|TP_CNI)!=TE_OK) { + status_dead = YES; + } else { + if (is_exception()) { + tpqputs("exception detected\n"); + (void) tp_sense(TP_WRP|TP_POR|TP_CNI); + } + } + + /* initialize generic status for ioctl requests */ + + ioctl_status.mt_type = TAPE_QIC02_DRIVE; /* MT_IS* id nr */ + + ioctl_status.mt_resid = 0; /* ---residual count */ + ioctl_status.mt_gstat = 0; /* ---generic status */ + ioctl_status.mt_erreg = 0; /* not used */ + ioctl_status.mt_fileno = 0; /* number of current file on tape */ + ioctl_status.mt_blkno = 0; /* number of current (logical) block */ + + return kmem_start; +} /* tape_qic02_init */ + + +#endif /* CONFIG_TAPE_QIC02 */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_io.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_io.c new file mode 100644 index 000000000..29976010b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_io.c @@ -0,0 +1,1826 @@ +/* + * linux/kernel/tty_io.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles + * or rs-channels. It also implements echoing, cooked mode etc. + * + * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0. + * + * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the + * tty_struct and tty_queue structures. Previously there was a array + * of 256 tty_struct's which was statically allocated, and the + * tty_queue structures were allocated at boot time. Both are now + * dynamically allocated only when the tty is open. + * + * Also restructured routines so that there is more of a separation + * between the high-level tty routines (tty_io.c and tty_ioctl.c) and + * the low-level tty routines (serial.c, pty.c, console.c). This + * makes for cleaner and more compact code. -TYT, 9/17/92 + * + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines + * which can be dynamically activated and de-activated by the line + * discipline handling modules (like SLIP). + * + * NOTE: pay no attention to the line discpline code (yet); its + * interface is still subject to change in this version... + * -- TYT, 1/31/92 + * + * Added functionality to the OPOST tty handling. No delays, but all + * other bits should be there. + * -- Nick Holloway , 27th May 1993. + * + * Rewrote canonical mode and added more termios flags. + * -- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include "kbd_kern.h" +#include "vt_kern.h" + +#define CONSOLE_DEV MKDEV(TTY_MAJOR,0) + +#define MAX_TTYS 256 + +struct tty_struct *tty_table[MAX_TTYS]; +struct termios *tty_termios[MAX_TTYS]; /* We need to keep the termios state */ + /* around, even when a tty is closed */ +struct termios *termios_locked[MAX_TTYS]; /* Bitfield of locked termios flags*/ +struct tty_ldisc ldiscs[NR_LDISCS]; /* line disc dispatch table */ +int tty_check_write[MAX_TTYS/32]; /* bitfield for the bh handler */ + +/* + * fg_console is the current virtual console, + * redirect is the pseudo-tty that console output + * is redirected to if asked by TIOCCONS. + */ +int fg_console = 0; +struct tty_struct * redirect = NULL; +struct wait_queue * keypress_wait = NULL; + +static void initialize_tty_struct(int line, struct tty_struct *tty); +static void initialize_termios(int line, struct termios *tp); + +static int tty_read(struct inode *, struct file *, char *, int); +static int tty_write(struct inode *, struct file *, char *, int); +static int tty_select(struct inode *, struct file *, int, select_table *); +static int tty_open(struct inode *, struct file *); +static void tty_release(struct inode *, struct file *); + +int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc) +{ + if (disc < N_TTY || disc >= NR_LDISCS) + return -EINVAL; + + if (new_ldisc) { + ldiscs[disc] = *new_ldisc; + ldiscs[disc].flags |= LDISC_FLAG_DEFINED; + } else + memset(&ldiscs[disc], 0, sizeof(struct tty_ldisc)); + + return 0; +} + +void put_tty_queue(unsigned char c, struct tty_queue * queue) +{ + int head; + unsigned long flags; + + save_flags(flags); + cli(); + head = (queue->head + 1) & (TTY_BUF_SIZE-1); + if (head != queue->tail) { + queue->buf[queue->head] = c; + queue->head = head; + } + restore_flags(flags); +} + +int get_tty_queue(struct tty_queue * queue) +{ + int result = -1; + unsigned long flags; + + save_flags(flags); + cli(); + if (queue->tail != queue->head) { + result = queue->buf[queue->tail]; + INC(queue->tail); + } + restore_flags(flags); + return result; +} + +/* + * This routine copies out a maximum of buflen characters from the + * read_q; it is a convenience for line disciplines so they can grab a + * large block of data without calling get_tty_char directly. It + * returns the number of characters actually read. Return terminates + * if an error character is read from the queue and the return value + * is negated. + */ +int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, int buflen) +{ + int result = 0; + unsigned char *p = bufp; + unsigned long flags; + int head, tail; + int ok = 1; + + save_flags(flags); + cli(); + tail = tty->read_q.tail; + head = tty->read_q.head; + while ((result < buflen) && (tail!=head) && ok) { + ok = !clear_bit (tail, &tty->readq_flags); + *p++ = tty->read_q.buf[tail++]; + tail &= TTY_BUF_SIZE-1; + result++; + } + tty->read_q.tail = tail; + restore_flags(flags); + return (ok) ? result : -result; +} + + +void tty_write_flush(struct tty_struct * tty) +{ + if (!tty->write || EMPTY(&tty->write_q)) + return; + if (set_bit(TTY_WRITE_BUSY,&tty->flags)) + return; + tty->write(tty); + if (!clear_bit(TTY_WRITE_BUSY,&tty->flags)) + printk("tty_write_flush: bit already cleared\n"); +} + +void tty_read_flush(struct tty_struct * tty) +{ + if (!tty || EMPTY(&tty->read_q)) + return; + if (set_bit(TTY_READ_BUSY, &tty->flags)) + return; + ldiscs[tty->disc].handler(tty); + if (!clear_bit(TTY_READ_BUSY, &tty->flags)) + printk("tty_read_flush: bit already cleared\n"); +} + +static int hung_up_tty_read(struct inode * inode, struct file * file, char * buf, int count) +{ + return 0; +} + +static int hung_up_tty_write(struct inode * inode, struct file * file, char * buf, int count) +{ + return -EIO; +} + +static int hung_up_tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) +{ + return 1; +} + +static int hung_up_tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + return -EIO; +} + +static int tty_lseek(struct inode * inode, struct file * file, off_t offset, int orig) +{ + return -ESPIPE; +} + +static struct file_operations tty_fops = { + tty_lseek, + tty_read, + tty_write, + NULL, /* tty_readdir */ + tty_select, + tty_ioctl, + NULL, /* tty_mmap */ + tty_open, + tty_release +}; + +static struct file_operations hung_up_tty_fops = { + tty_lseek, + hung_up_tty_read, + hung_up_tty_write, + NULL, /* hung_up_tty_readdir */ + hung_up_tty_select, + hung_up_tty_ioctl, + NULL, /* hung_up_tty_mmap */ + NULL, /* hung_up_tty_open */ + tty_release /* hung_up_tty_release */ +}; + +void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) +{ + int i; + struct file * filp; + struct task_struct *p; + int dev; + + if (!tty) + return; + dev = MKDEV(TTY_MAJOR,tty->line); + for (filp = first_file, i=0; if_next) { + if (!filp->f_count) + continue; + if (filp->f_rdev != dev) + continue; + if (filp->f_inode && filp->f_inode->i_rdev == CONSOLE_DEV) + continue; + if (filp->f_op != &tty_fops) + continue; + filp->f_op = fops; + } + flush_input(tty); + flush_output(tty); + wake_up_interruptible(&tty->secondary.proc_list); + if (tty->session > 0) + kill_sl(tty->session,SIGHUP,1); + tty->session = 0; + tty->pgrp = -1; + for_each_task(p) { + if (p->tty == tty->line) + p->tty = -1; + } + if (tty->hangup) + (tty->hangup)(tty); +} + +void tty_hangup(struct tty_struct * tty) +{ +#ifdef TTY_DEBUG_HANGUP + printk("tty%d hangup...\n", tty->line); +#endif + do_tty_hangup(tty, &hung_up_tty_fops); +} + +void tty_vhangup(struct tty_struct * tty) +{ +#ifdef TTY_DEBUG_HANGUP + printk("tty%d vhangup...\n", tty->line); +#endif + do_tty_hangup(tty, &hung_up_tty_fops); +} + +int tty_hung_up_p(struct file * filp) +{ + return (filp->f_op == &hung_up_tty_fops); +} + +/* + * This function is typically called only by the session leader, when + * it wants to dissassociate itself from its controlling tty. + * + * It performs the following functions: + * (1) Sends a SIGHUP to the foreground process group + * (2) Clears the tty from being controlling the session + * (3) Clears the controlling tty for all processes in the + * session group. + */ +void disassociate_ctty(int priv) +{ + struct tty_struct *tty; + struct task_struct *p; + + if (current->tty >= 0) { + tty = tty_table[current->tty]; + if (tty) { + if (tty->pgrp > 0) + kill_pg(tty->pgrp, SIGHUP, priv); + tty->session = 0; + tty->pgrp = -1; + } else + printk("disassociate_ctty: ctty is NULL?!?"); + } + + for_each_task(p) + if (p->session == current->session) + p->tty = -1; +} + +/* + * Sometimes we want to wait until a particular VT has been activated. We + * do it in a very simple manner. Everybody waits on a single queue and + * get woken up at once. Those that are satisfied go on with their business, + * while those not ready go back to sleep. Seems overkill to add a wait + * to each vt just for this - usually this does nothing! + */ +static struct wait_queue *vt_activate_queue = NULL; + +/* + * Sleeps until a vt is activated, or the task is interrupted. Returns + * 0 if activation, -1 if interrupted. + */ +int vt_waitactive(void) +{ + interruptible_sleep_on(&vt_activate_queue); + return (current->signal & ~current->blocked) ? -1 : 0; +} + +#define vt_wake_waitactive() wake_up(&vt_activate_queue) + +extern int kill_proc(int pid, int sig, int priv); + +/* + * Performs the back end of a vt switch + */ +void complete_change_console(unsigned int new_console) +{ + unsigned char old_vc_mode; + + if (new_console == fg_console || new_console >= NR_CONSOLES) + return; + + /* + * If we're switching, we could be going from KD_GRAPHICS to + * KD_TEXT mode or vice versa, which means we need to blank or + * unblank the screen later. + */ + old_vc_mode = vt_cons[fg_console].vc_mode; + update_screen(new_console); + + /* + * If this new console is under process control, send it a signal + * telling it that it has acquired. Also check if it has died and + * clean up (similar to logic employed in change_console()) + */ + if (vt_cons[new_console].vt_mode.mode == VT_PROCESS) + { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(vt_cons[new_console].vt_pid, + vt_cons[new_console].vt_mode.acqsig, + 1) != 0) + { + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + vt_cons[new_console].vc_mode = KD_TEXT; + clr_vc_kbd_mode(kbd_table + new_console, VC_RAW); + clr_vc_kbd_mode(kbd_table + new_console, VC_MEDIUMRAW); + vt_cons[new_console].vt_mode.mode = VT_AUTO; + vt_cons[new_console].vt_mode.waitv = 0; + vt_cons[new_console].vt_mode.relsig = 0; + vt_cons[new_console].vt_mode.acqsig = 0; + vt_cons[new_console].vt_mode.frsig = 0; + vt_cons[new_console].vt_pid = -1; + vt_cons[new_console].vt_newvt = -1; + } + } + + /* + * We do this here because the controlling process above may have + * gone, and so there is now a new vc_mode + */ + if (old_vc_mode != vt_cons[new_console].vc_mode) + { + if (vt_cons[new_console].vc_mode == KD_TEXT) + unblank_screen(); + else { + timer_active &= ~(1<= NR_CONSOLES) + return; + + /* + * If this vt is in process mode, then we need to handshake with + * that process before switching. Essentially, we store where that + * vt wants to switch to and wait for it to tell us when it's done + * (via VT_RELDISP ioctl). + * + * We also check to see if the controlling process still exists. + * If it doesn't, we reset this vt to auto mode and continue. + * This is a cheap way to track process control. The worst thing + * that can happen is: we send a signal to a process, it dies, and + * the switch gets "lost" waiting for a response; hopefully, the + * user will try again, we'll detect the process is gone (unless + * the user waits just the right amount of time :-) and revert the + * vt to auto control. + */ + if (vt_cons[fg_console].vt_mode.mode == VT_PROCESS) + { + /* + * Send the signal as privileged - kill_proc() will + * tell us if the process has gone or something else + * is awry + */ + if (kill_proc(vt_cons[fg_console].vt_pid, + vt_cons[fg_console].vt_mode.relsig, + 1) == 0) + { + /* + * It worked. Mark the vt to switch to and + * return. The process needs to send us a + * VT_RELDISP ioctl to complete the switch. + */ + vt_cons[fg_console].vt_newvt = new_console; + return; + } + + /* + * The controlling process has died, so we revert back to + * normal operation. In this case, we'll also change back + * to KD_TEXT mode. I'm not sure if this is strictly correct + * but it saves the agony when the X server dies and the screen + * remains blanked due to KD_GRAPHICS! It would be nice to do + * this outside of VT_PROCESS but there is no single process + * to account for and tracking tty count may be undesirable. + */ + vt_cons[fg_console].vc_mode = KD_TEXT; + clr_vc_kbd_mode(kbd_table + fg_console, VC_RAW); + clr_vc_kbd_mode(kbd_table + fg_console, VC_MEDIUMRAW); + vt_cons[fg_console].vt_mode.mode = VT_AUTO; + vt_cons[fg_console].vt_mode.waitv = 0; + vt_cons[fg_console].vt_mode.relsig = 0; + vt_cons[fg_console].vt_mode.acqsig = 0; + vt_cons[fg_console].vt_mode.frsig = 0; + vt_cons[fg_console].vt_pid = -1; + vt_cons[fg_console].vt_newvt = -1; + /* + * Fall through to normal (VT_AUTO) handling of the switch... + */ + } + + /* + * Ignore all switches in KD_GRAPHICS+VT_AUTO mode + */ + if (vt_cons[fg_console].vc_mode == KD_GRAPHICS) + return; + + complete_change_console(new_console); +} + +void wait_for_keypress(void) +{ + sleep_on(&keypress_wait); +} + +void stop_tty(struct tty_struct *tty) +{ + if (tty->stopped) + return; + tty->stopped = 1; + if (tty->link && tty->link->packet) { + tty->ctrl_status &= ~TIOCPKT_START; + tty->ctrl_status |= TIOCPKT_STOP; + wake_up_interruptible(&tty->link->secondary.proc_list); + } + if (tty->stop) + (tty->stop)(tty); + if (IS_A_CONSOLE(tty->line)) { + set_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); + set_leds(); + } +} + +void start_tty(struct tty_struct *tty) +{ + if (!tty->stopped) + return; + tty->stopped = 0; + if (tty->link && tty->link->packet) { + tty->ctrl_status &= ~TIOCPKT_STOP; + tty->ctrl_status |= TIOCPKT_START; + wake_up_interruptible(&tty->link->secondary.proc_list); + } + if (tty->start) + (tty->start)(tty); + TTY_WRITE_FLUSH(tty); + if (IS_A_CONSOLE(tty->line)) { + clr_vc_kbd_led(kbd_table + fg_console, VC_SCROLLOCK); + set_leds(); + } +} + +/* Perform OPOST processing. Returns -1 when the write_q becomes full + and the character must be retried. */ + +static int opost(unsigned char c, struct tty_struct *tty) +{ + if (FULL(&tty->write_q)) + return -1; + if (O_OPOST(tty)) { + switch (c) { + case '\n': + if (O_ONLRET(tty)) + tty->column = 0; + if (O_ONLCR(tty)) { + if (LEFT(&tty->write_q) < 2) + return -1; + put_tty_queue('\r', &tty->write_q); + tty->column = 0; + } + tty->canon_column = tty->column; + break; + case '\r': + if (O_ONOCR(tty) && tty->column == 0) + return 0; + if (O_OCRNL(tty)) { + c = '\n'; + if (O_ONLRET(tty)) + tty->canon_column = tty->column = 0; + break; + } + tty->canon_column = tty->column = 0; + break; + case '\t': + if (O_TABDLY(tty) == XTABS) { + if (LEFT(&tty->write_q) < 8) + return -1; + do + put_tty_queue(' ', &tty->write_q); + while (++tty->column % 8); + return 0; + } + tty->column = (tty->column | 7) + 1; + break; + case '\b': + if (tty->column > 0) + tty->column--; + break; + default: + if (O_OLCUC(tty)) + c = toupper(c); + if (!iscntrl(c)) + tty->column++; + break; + } + } + put_tty_queue(c, &tty->write_q); + return 0; +} + +/* Must be called only when L_ECHO(tty) is true. */ + +static void echo_char(unsigned char c, struct tty_struct *tty) +{ + if (L_ECHOCTL(tty) && iscntrl(c) && c != '\t') { + opost('^', tty); + opost(c ^ 0100, tty); + } else + opost(c, tty); +} + +static void eraser(unsigned char c, struct tty_struct *tty) +{ + enum { ERASE, WERASE, KILL } kill_type; + int seen_alnums; + + if (tty->secondary.head == tty->canon_head) { + /* opost('\a', tty); */ /* what do you think? */ + return; + } + if (c == ERASE_CHAR(tty)) + kill_type = ERASE; + else if (c == WERASE_CHAR(tty)) + kill_type = WERASE; + else { + if (!L_ECHO(tty)) { + tty->secondary.head = tty->canon_head; + return; + } + if (!L_ECHOK(tty) || !L_ECHOKE(tty)) { + tty->secondary.head = tty->canon_head; + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + echo_char(KILL_CHAR(tty), tty); + /* Add a newline if ECHOK is on and ECHOKE is off. */ + if (L_ECHOK(tty)) + opost('\n', tty); + return; + } + kill_type = KILL; + } + + seen_alnums = 0; + while (tty->secondary.head != tty->canon_head) { + c = LAST(&tty->secondary); + if (kill_type == WERASE) { + /* Equivalent to BSD's ALTWERASE. */ + if (isalnum(c) || c == '_') + seen_alnums++; + else if (seen_alnums) + break; + } + DEC(tty->secondary.head); + if (L_ECHO(tty)) { + if (L_ECHOPRT(tty)) { + if (!tty->erasing) { + opost('\\', tty); + tty->erasing = 1; + } + echo_char(c, tty); + } else if (!L_ECHOE(tty)) { + echo_char(ERASE_CHAR(tty), tty); + } else if (c == '\t') { + unsigned int col = tty->canon_column; + unsigned long tail = tty->canon_head; + + /* Find the column of the last char. */ + while (tail != tty->secondary.head) { + c = tty->secondary.buf[tail]; + if (c == '\t') + col = (col | 7) + 1; + else if (iscntrl(c)) { + if (L_ECHOCTL(tty)) + col += 2; + } else + col++; + INC(tail); + } + + /* Now backup to that column. */ + while (tty->column > col) { + /* Can't use opost here. */ + put_tty_queue('\b', &tty->write_q); + tty->column--; + } + } else { + if (iscntrl(c) && L_ECHOCTL(tty)) { + opost('\b', tty); + opost(' ', tty); + opost('\b', tty); + } + if (!iscntrl(c) || L_ECHOCTL(tty)) { + opost('\b', tty); + opost(' ', tty); + opost('\b', tty); + } + } + } + if (kill_type == ERASE) + break; + } + if (tty->erasing && tty->secondary.head == tty->canon_head) { + opost('/', tty); + tty->erasing = 0; + } +} + +static void isig(int sig, struct tty_struct *tty) +{ + kill_pg(tty->pgrp, sig, 1); + if (!L_NOFLSH(tty)) { + flush_input(tty); + flush_output(tty); + } +} + +static void copy_to_cooked(struct tty_struct * tty) +{ + int c, special_flag; + unsigned long flags; + + if (!tty) { + printk("copy_to_cooked: called with NULL tty\n"); + return; + } + if (!tty->write) { + printk("copy_to_cooked: tty %d has null write routine\n", + tty->line); + } + while (1) { + /* + * Check to see how much room we have left in the + * secondary queue. Send a throttle command or abort + * if necessary. + */ + c = LEFT(&tty->secondary); + if (tty->throttle && (c < SQ_THRESHOLD_LW) + && !set_bit(TTY_SQ_THROTTLED, &tty->flags)) + tty->throttle(tty, TTY_THROTTLE_SQ_FULL); + if (c == 0) + break; + save_flags(flags); cli(); + if (!EMPTY(&tty->read_q)) { + c = tty->read_q.buf[tty->read_q.tail]; + special_flag = clear_bit(tty->read_q.tail, + &tty->readq_flags); + INC(tty->read_q.tail); + restore_flags(flags); + } else { + restore_flags(flags); + break; + } + if (special_flag) { + tty->char_error = c; + continue; + } + if (tty->char_error) { + if (tty->char_error == TTY_BREAK) { + tty->char_error = 0; + if (I_IGNBRK(tty)) + continue; + /* A break is handled by the lower levels. */ + if (I_BRKINT(tty)) + continue; + if (I_PARMRK(tty)) { + put_tty_queue('\377', &tty->secondary); + put_tty_queue('\0', &tty->secondary); + } + put_tty_queue('\0', &tty->secondary); + continue; + } + if (tty->char_error == TTY_OVERRUN) { + tty->char_error = 0; + printk("tty%d: input overrun\n", tty->line); + continue; + } + /* Must be a parity or frame error */ + tty->char_error = 0; + if (I_IGNPAR(tty)) { + continue; + } + if (I_PARMRK(tty)) { + put_tty_queue('\377', &tty->secondary); + put_tty_queue('\0', &tty->secondary); + put_tty_queue(c, &tty->secondary); + } else + put_tty_queue('\0', &tty->secondary); + continue; + } + if (I_ISTRIP(tty)) + c &= 0x7f; + if (!tty->lnext) { + if (c == '\r') { + if (I_IGNCR(tty)) + continue; + if (I_ICRNL(tty)) + c = '\n'; + } else if (c == '\n' && I_INLCR(tty)) + c = '\r'; + } + if (I_IUCLC(tty) && L_IEXTEN(tty)) + c=tolower(c); + if (c == __DISABLED_CHAR) + tty->lnext = 1; + if (L_ICANON(tty) && !tty->lnext) { + if (c == ERASE_CHAR(tty) || c == KILL_CHAR(tty) || + (c == WERASE_CHAR(tty) && L_IEXTEN(tty))) { + eraser(c, tty); + continue; + } + if (c == LNEXT_CHAR(tty) && L_IEXTEN(tty)) { + tty->lnext = 1; + if (L_ECHO(tty)) { + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + if (L_ECHOCTL(tty)) { + opost('^', tty); + opost('\b', tty); + } + } + continue; + } + if (c == REPRINT_CHAR(tty) && L_ECHO(tty) && + L_IEXTEN(tty)) { + unsigned long tail = tty->canon_head; + + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + echo_char(c, tty); + opost('\n', tty); + while (tail != tty->secondary.head) { + echo_char(tty->secondary.buf[tail], + tty); + INC(tail); + } + continue; + } + } + if (I_IXON(tty) && !tty->lnext) { + if ((tty->stopped && I_IXANY(tty) && L_IEXTEN(tty)) || + c == START_CHAR(tty)) { + start_tty(tty); + continue; + } + if (c == STOP_CHAR(tty)) { + stop_tty(tty); + continue; + } + } + if (L_ISIG(tty) && !tty->lnext) { + if (c == INTR_CHAR(tty)) { + isig(SIGINT, tty); + continue; + } + if (c == QUIT_CHAR(tty)) { + isig(SIGQUIT, tty); + continue; + } + if (c == SUSP_CHAR(tty)) { + if (!is_orphaned_pgrp(tty->pgrp)) + isig(SIGTSTP, tty); + continue; + } + } + + if (tty->erasing) { + opost('/', tty); + tty->erasing = 0; + } + if (c == '\n' && !tty->lnext) { + if (L_ECHO(tty) || (L_ICANON(tty) && L_ECHONL(tty))) + opost('\n', tty); + } else if (L_ECHO(tty)) { + /* Don't echo the EOF char in canonical mode. Sun + handles this differently by echoing the char and + then backspacing, but that's a hack. */ + if (c != EOF_CHAR(tty) || !L_ICANON(tty) || + tty->lnext) { + /* Record the column of first canon char. */ + if (tty->canon_head == tty->secondary.head) + tty->canon_column = tty->column; + echo_char(c, tty); + } + } + + if (I_PARMRK(tty) && c == (unsigned char) '\377' && + (c != EOF_CHAR(tty) || !L_ICANON(tty) || tty->lnext)) + put_tty_queue(c, &tty->secondary); + + if (L_ICANON(tty) && !tty->lnext && + (c == '\n' || c == EOF_CHAR(tty) || c == EOL_CHAR(tty) || + (c == EOL2_CHAR(tty) && L_IEXTEN(tty)))) { + if (c == EOF_CHAR(tty)) + c = __DISABLED_CHAR; + set_bit(tty->secondary.head, &tty->secondary_flags); + put_tty_queue(c, &tty->secondary); + tty->canon_head = tty->secondary.head; + tty->canon_data++; + } else + put_tty_queue(c, &tty->secondary); + tty->lnext = 0; + } + if (!EMPTY(&tty->write_q)) + TTY_WRITE_FLUSH(tty); + if (L_ICANON(tty) ? tty->canon_data : !EMPTY(&tty->secondary)) + wake_up_interruptible(&tty->secondary.proc_list); + + if (tty->throttle && (LEFT(&tty->read_q) >= RQ_THRESHOLD_HW) + && clear_bit(TTY_RQ_THROTTLED, &tty->flags)) + tty->throttle(tty, TTY_THROTTLE_RQ_AVAIL); +} + +int is_ignored(int sig) +{ + return ((current->blocked & (1<<(sig-1))) || + (current->sigaction[sig-1].sa_handler == SIG_IGN)); +} + +static inline int input_available_p(struct tty_struct *tty) +{ + /* Avoid calling TTY_READ_FLUSH unnecessarily. */ + if (L_ICANON(tty)) { + if (tty->canon_data || FULL(&tty->read_q)) + return 1; + } else if (!EMPTY(&tty->secondary)) + return 1; + + /* Shuffle any pending data down the queues. */ + TTY_READ_FLUSH(tty); + if (tty->link) + TTY_WRITE_FLUSH(tty->link); + + if (L_ICANON(tty)) { + if (tty->canon_data || FULL(&tty->read_q)) + return 1; + } else if (!EMPTY(&tty->secondary)) + return 1; + return 0; +} + +static int read_chan(struct tty_struct *tty, struct file *file, + unsigned char *buf, unsigned int nr) +{ + struct wait_queue wait = { current, NULL }; + int c; + unsigned char *b = buf; + int minimum, time; + int retval = 0; + + if (L_ICANON(tty)) { + minimum = time = 0; + current->timeout = (unsigned long) -1; + } else { + time = (HZ / 10) * TIME_CHAR(tty); + minimum = MIN_CHAR(tty); + if (minimum) + current->timeout = (unsigned long) -1; + else { + if (time) { + current->timeout = time + jiffies; + time = 0; + } else + current->timeout = 0; + minimum = 1; + } + } + + add_wait_queue(&tty->secondary.proc_list, &wait); + while (1) { + /* Job control check -- must be done at start and after + every sleep (POSIX.1 7.1.1.4). */ + /* don't stop on /dev/console */ + if (file->f_inode->i_rdev != CONSOLE_DEV && + current->tty == tty->line) { + if (tty->pgrp <= 0) + printk("read_chan: tty->pgrp <= 0!\n"); + else if (current->pgrp != tty->pgrp) { + if (is_ignored(SIGTTIN) || + is_orphaned_pgrp(current->pgrp)) { + retval = -EIO; + break; + } + kill_pg(current->pgrp, SIGTTIN, 1); + retval = -ERESTARTSYS; + break; + } + } + /* First test for status change. */ + if (tty->packet && tty->link->ctrl_status) { + if (b != buf) + break; + put_fs_byte(tty->link->ctrl_status, b++); + tty->link->ctrl_status = 0; + break; + } + /* This statement must be first before checking for input + so that any interrupt will set the state back to + TASK_RUNNING. */ + current->state = TASK_INTERRUPTIBLE; + if (!input_available_p(tty)) { + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) { + retval = -EIO; + break; + } + if (tty_hung_up_p(file)) + break; + if (!current->timeout) + break; + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + break; + } + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + schedule(); + continue; + } + current->state = TASK_RUNNING; + + /* Deal with packet mode. */ + if (tty->packet && b == buf) { + put_fs_byte(TIOCPKT_DATA, b++); + nr--; + } + + while (nr > 0) { + int eol; + + cli(); + if (EMPTY(&tty->secondary)) { + sti(); + break; + } + eol = clear_bit(tty->secondary.tail, + &tty->secondary_flags); + c = tty->secondary.buf[tty->secondary.tail]; + INC(tty->secondary.tail); + sti(); + if (eol) { + if (--tty->canon_data < 0) { + printk("read_chan: canon_data < 0!\n"); + tty->canon_data = 0; + } + if (c == __DISABLED_CHAR) + break; + put_fs_byte(c, b++); + nr--; + break; + } + put_fs_byte(c, b++); + nr--; + } + + /* If there is enough space in the secondary queue now, let the + low-level driver know. */ + if (tty->throttle && (LEFT(&tty->secondary) >= SQ_THRESHOLD_HW) + && !clear_bit(TTY_SQ_THROTTLED, &tty->flags)) + tty->throttle(tty, TTY_THROTTLE_SQ_AVAIL); + + /* XXX packet mode's status byte is mistakenly counted */ + if (b - buf >= minimum || !nr) + break; + if (time) + current->timeout = time + jiffies; + } + remove_wait_queue(&tty->secondary.proc_list, &wait); + current->state = TASK_RUNNING; + current->timeout = 0; + return (b - buf) ? b - buf : retval; +} + +static int write_chan(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr) +{ + struct wait_queue wait = { current, NULL }; + int c; + unsigned char *b = buf; + int retval = 0; + + /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ + if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) { + retval = check_change(tty, tty->line); + if (retval) + return retval; + } + + add_wait_queue(&tty->write_q.proc_list, &wait); + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + if (tty_hung_up_p(file) || (tty->link && !tty->link->count)) { + retval = -EIO; + break; + } + while (nr > 0) { + c = get_fs_byte(b); + /* Care is needed here: opost() can abort even + if the write_q is not full. */ + if (opost(c, tty) < 0) + break; + b++; nr--; + } + TTY_WRITE_FLUSH(tty); + if (!nr) + break; + if (EMPTY(&tty->write_q) && !need_resched) + continue; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&tty->write_q.proc_list, &wait); + return (b - buf) ? b - buf : retval; +} + +static int tty_read(struct inode * inode, struct file * file, char * buf, int count) +{ + int i, dev; + struct tty_struct * tty; + + dev = file->f_rdev; + if (MAJOR(dev) != TTY_MAJOR) { + printk("tty_read: bad pseudo-major nr #%d\n", MAJOR(dev)); + return -EINVAL; + } + dev = MINOR(dev); + tty = TTY_TABLE(dev); + if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) + return -EIO; + + /* This check not only needs to be done before reading, but also + whenever read_chan() gets woken up after sleeping, so I've + moved it to there. This should only be done for the N_TTY + line discipline, anyway. Same goes for write_chan(). -- jlc. */ +#if 0 + if ((inode->i_rdev != CONSOLE_DEV) && /* don't stop on /dev/console */ + (tty->pgrp > 0) && + (current->tty == dev) && + (tty->pgrp != current->pgrp)) + if (is_ignored(SIGTTIN) || is_orphaned_pgrp(current->pgrp)) + return -EIO; + else { + (void) kill_pg(current->pgrp, SIGTTIN, 1); + return -ERESTARTSYS; + } +#endif + if (ldiscs[tty->disc].read) + /* XXX casts are for what kernel-wide prototypes should be. */ + i = (ldiscs[tty->disc].read)(tty,file,(unsigned char *)buf,(unsigned int)count); + else + i = -EIO; + if (i > 0) + inode->i_atime = CURRENT_TIME; + return i; +} + +static int tty_write(struct inode * inode, struct file * file, char * buf, int count) +{ + int dev, i, is_console; + struct tty_struct * tty; + + dev = file->f_rdev; + is_console = (inode->i_rdev == CONSOLE_DEV); + if (MAJOR(dev) != TTY_MAJOR) { + printk("tty_write: pseudo-major != TTY_MAJOR\n"); + return -EINVAL; + } + dev = MINOR(dev); + if (is_console && redirect) + tty = redirect; + else + tty = TTY_TABLE(dev); + if (!tty || !tty->write || (tty->flags & (1 << TTY_IO_ERROR))) + return -EIO; +#if 0 + if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && + (current->tty == dev) && (tty->pgrp != current->pgrp)) { + if (is_orphaned_pgrp(current->pgrp)) + return -EIO; + if (!is_ignored(SIGTTOU)) { + (void) kill_pg(current->pgrp, SIGTTOU, 1); + return -ERESTARTSYS; + } + } +#endif + if (ldiscs[tty->disc].write) + /* XXX casts are for what kernel-wide prototypes should be. */ + i = (ldiscs[tty->disc].write)(tty,file,(unsigned char *)buf,(unsigned int)count); + else + i = -EIO; + if (i > 0) + inode->i_mtime = CURRENT_TIME; + return i; +} + +/* + * This is so ripe with races that you should *really* not touch this + * unless you know exactly what you are doing. All the changes have to be + * made atomically, or there may be incorrect pointers all over the place. + */ +static int init_dev(int dev) +{ + struct tty_struct *tty, *o_tty; + struct termios *tp, *o_tp, *ltp, *o_ltp; + int retval; + int o_dev; + + o_dev = PTY_OTHER(dev); + tty = o_tty = NULL; + tp = o_tp = NULL; + ltp = o_ltp = NULL; +repeat: + retval = -EAGAIN; + if (IS_A_PTY_MASTER(dev) && tty_table[dev] && tty_table[dev]->count) + goto end_init; + retval = -ENOMEM; + if (!tty_table[dev] && !tty) { + if (!(tty = (struct tty_struct*) get_free_page(GFP_KERNEL))) + goto end_init; + initialize_tty_struct(dev, tty); + goto repeat; + } + if (!tty_termios[dev] && !tp) { + tp = (struct termios *) kmalloc(sizeof(struct termios), + GFP_KERNEL); + if (!tp) + goto end_init; + initialize_termios(dev, tp); + goto repeat; + } + if (!termios_locked[dev] && !ltp) { + ltp = (struct termios *) kmalloc(sizeof(struct termios), + GFP_KERNEL); + if (!ltp) + goto end_init; + memset(ltp, 0, sizeof(struct termios)); + goto repeat; + } + if (IS_A_PTY(dev)) { + if (!tty_table[o_dev] && !o_tty) { + o_tty = (struct tty_struct *) + get_free_page(GFP_KERNEL); + if (!o_tty) + goto end_init; + initialize_tty_struct(o_dev, o_tty); + goto repeat; + } + if (!tty_termios[o_dev] && !o_tp) { + o_tp = (struct termios *) + kmalloc(sizeof(struct termios), GFP_KERNEL); + if (!o_tp) + goto end_init; + initialize_termios(o_dev, o_tp); + goto repeat; + } + if (!termios_locked[o_dev] && !o_ltp) { + o_ltp = (struct termios *) + kmalloc(sizeof(struct termios), GFP_KERNEL); + if (!o_ltp) + goto end_init; + memset(o_ltp, 0, sizeof(struct termios)); + goto repeat; + } + + } + /* Now we have allocated all the structures: update all the pointers.. */ + if (!tty_termios[dev]) { + tty_termios[dev] = tp; + tp = NULL; + } + if (!tty_table[dev]) { + tty->termios = tty_termios[dev]; + tty_table[dev] = tty; + tty = NULL; + } + if (!termios_locked[dev]) { + termios_locked[dev] = ltp; + ltp = NULL; + } + if (IS_A_PTY(dev)) { + if (!tty_termios[o_dev]) { + tty_termios[o_dev] = o_tp; + o_tp = NULL; + } + if (!termios_locked[o_dev]) { + termios_locked[o_dev] = o_ltp; + o_ltp = NULL; + } + if (!tty_table[o_dev]) { + o_tty->termios = tty_termios[o_dev]; + tty_table[o_dev] = o_tty; + o_tty = NULL; + } + tty_table[dev]->link = tty_table[o_dev]; + tty_table[o_dev]->link = tty_table[dev]; + } + tty_table[dev]->count++; + if (IS_A_PTY_MASTER(dev)) + tty_table[o_dev]->count++; + retval = 0; +end_init: + if (tty) + free_page((unsigned long) tty); + if (o_tty) + free_page((unsigned long) o_tty); + if (tp) + kfree_s(tp, sizeof(struct termios)); + if (o_tp) + kfree_s(o_tp, sizeof(struct termios)); + if (ltp) + kfree_s(ltp, sizeof(struct termios)); + if (o_ltp) + kfree_s(o_ltp, sizeof(struct termios)); + return retval; +} + +/* + * Even releasing the tty structures is a tricky business.. We have + * to be very careful that the structures are all released at the + * same time, as interrupts might otherwise get the wrong pointers. + */ +static void release_dev(int dev, struct file * filp) +{ + struct tty_struct *tty, *o_tty; + struct termios *tp, *o_tp; + struct task_struct **p; + + tty = tty_table[dev]; + tp = tty_termios[dev]; + o_tty = NULL; + o_tp = NULL; + if (!tty) { + printk("release_dev: tty_table[%d] was NULL\n", dev); + return; + } + if (!tp) { + printk("release_dev: tty_termios[%d] was NULL\n", dev); + return; + } +#ifdef TTY_DEBUG_HANGUP + printk("release_dev of tty%d (tty count=%d)...", dev, tty->count); +#endif + if (IS_A_PTY(dev)) { + o_tty = tty_table[PTY_OTHER(dev)]; + o_tp = tty_termios[PTY_OTHER(dev)]; + if (!o_tty) { + printk("release_dev: pty pair(%d) was NULL\n", dev); + return; + } + if (!o_tp) { + printk("release_dev: pty pair(%d) termios was NULL\n", dev); + return; + } + if (tty->link != o_tty || o_tty->link != tty) { + printk("release_dev: bad pty pointers\n"); + return; + } + } + tty->write_data_cnt = 0; /* Clear out pending trash */ + if (tty->close) + tty->close(tty, filp); + if (IS_A_PTY_MASTER(dev)) { + if (--tty->link->count < 0) { + printk("release_dev: bad tty slave count (dev = %d): %d\n", + dev, tty->count); + tty->link->count = 0; + } + } + if (--tty->count < 0) { + printk("release_dev: bad tty_table[%d]->count: %d\n", + dev, tty->count); + tty->count = 0; + } + if (tty->count) + return; + +#ifdef TTY_DEBUG_HANGUP + printk("freeing tty structure..."); +#endif + + /* + * Make sure there aren't any processes that still think this + * tty is their controlling tty. + */ + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if ((*p) && (*p)->tty == tty->line) + (*p)->tty = -1; + } + + /* + * Shutdown the current line discipline, and reset it to + * N_TTY. + */ + if (ldiscs[tty->disc].close != NULL) + ldiscs[tty->disc].close(tty); + tty->disc = N_TTY; + tty->termios->c_line = N_TTY; + + if (o_tty) { + if (o_tty->count) + return; + else { + tty_table[PTY_OTHER(dev)] = NULL; + tty_termios[PTY_OTHER(dev)] = NULL; + } + } + tty_table[dev] = NULL; + if (IS_A_PTY(dev)) { + tty_termios[dev] = NULL; + kfree_s(tp, sizeof(struct termios)); + } + if (tty == redirect || o_tty == redirect) + redirect = NULL; + free_page((unsigned long) tty); + if (o_tty) + free_page((unsigned long) o_tty); + if (o_tp) + kfree_s(o_tp, sizeof(struct termios)); +} + +/* + * tty_open and tty_release keep up the tty count that contains the + * number of opens done on a tty. We cannot use the inode-count, as + * different inodes might point to the same tty. + * + * Open-counting is needed for pty masters, as well as for keeping + * track of serial lines: DTR is dropped when the last close happens. + * (This is not done solely through tty->count, now. - Ted 1/27/92) + * + * The termios state of a pty is reset on first open so that + * settings don't persist across reuse. + */ +static int tty_open(struct inode * inode, struct file * filp) +{ + struct tty_struct *tty; + int major, minor; + int noctty, retval; + +retry_open: + minor = MINOR(inode->i_rdev); + major = MAJOR(inode->i_rdev); + noctty = filp->f_flags & O_NOCTTY; + if (major == TTYAUX_MAJOR) { + if (!minor) { + major = TTY_MAJOR; + minor = current->tty; + } + /* noctty = 1; */ + } else if (major == TTY_MAJOR) { + if (!minor) { + minor = fg_console + 1; + noctty = 1; + } + } else { + printk("Bad major #%d in tty_open\n", MAJOR(inode->i_rdev)); + return -ENODEV; + } + if (minor <= 0) + return -ENXIO; + if (IS_A_PTY_MASTER(minor)) + noctty = 1; + filp->f_rdev = (major << 8) | minor; + retval = init_dev(minor); + if (retval) + return retval; + tty = tty_table[minor]; +#ifdef TTY_DEBUG_HANGUP + printk("opening tty%d...", tty->line); +#endif + if (test_bit(TTY_EXCLUSIVE, &tty->flags) && !suser()) + return -EBUSY; + +#if 0 + /* clean up the packet stuff. */ + /* + * Why is this not done in init_dev? Right here, if another + * 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 + * + * Not needed. These are cleared in initialize_tty_struct. -- jlc + */ + tty->ctrl_status = 0; + tty->packet = 0; +#endif + + if (tty->open) { + retval = tty->open(tty, filp); + } else { + retval = -ENODEV; + } + if (retval) { +#ifdef TTY_DEBUG_HANGUP + printk("error %d in opening tty%d...", retval, tty->line); +#endif + + release_dev(minor, filp); + if (retval != -ERESTARTSYS) + return retval; + if (current->signal & ~current->blocked) + return retval; + schedule(); + goto retry_open; + } + if (!noctty && + current->leader && + current->tty<0 && + tty->session==0) { + current->tty = minor; + tty->session = current->session; + tty->pgrp = current->pgrp; + } + filp->f_rdev = MKDEV(TTY_MAJOR,minor); /* Set it to something normal */ + return 0; +} + +/* + * Note that releasing a pty master also releases the child, so + * we have to make the redirection checks after that and on both + * sides of a pty. + */ +static void tty_release(struct inode * inode, struct file * filp) +{ + int dev; + + dev = filp->f_rdev; + if (MAJOR(dev) != TTY_MAJOR) { + printk("tty_release: tty pseudo-major != TTY_MAJOR\n"); + return; + } + dev = MINOR(filp->f_rdev); + if (!dev) { + printk("tty_release: bad f_rdev\n"); + return; + } + release_dev(dev, filp); +} + +static int tty_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) +{ + int dev; + struct tty_struct * tty; + + dev = filp->f_rdev; + if (MAJOR(dev) != TTY_MAJOR) { + printk("tty_select: tty pseudo-major != TTY_MAJOR\n"); + return 0; + } + dev = MINOR(filp->f_rdev); + tty = TTY_TABLE(dev); + if (!tty) { + printk("tty_select: tty struct for dev %d was NULL\n", dev); + return 0; + } + if (ldiscs[tty->disc].select) + return (ldiscs[tty->disc].select)(tty, inode, filp, + sel_type, wait); + return 0; +} + +static int normal_select(struct tty_struct * tty, struct inode * inode, + struct file * file, int sel_type, select_table *wait) +{ + switch (sel_type) { + case SEL_IN: + if (input_available_p(tty)) + return 1; + /* fall through */ + case SEL_EX: + if (tty->packet && tty->link->ctrl_status) + return 1; + if (tty->flags & (1 << TTY_SLAVE_CLOSED)) + return 1; + if (tty_hung_up_p(file)) + return 1; + select_wait(&tty->secondary.proc_list, wait); + return 0; + case SEL_OUT: + if (!FULL(&tty->write_q)) + return 1; + select_wait(&tty->write_q.proc_list, wait); + return 0; + } + return 0; +} + +/* + * This implements the "Secure Attention Key" --- the idea is to + * prevent trojan horses by killing all processes associated with this + * tty when the user hits the "Secure Attention Key". Required for + * super-paranoid applications --- see the Orange Book for more details. + * + * This code could be nicer; ideally it should send a HUP, wait a few + * seconds, then send a INT, and then a KILL signal. But you then + * have to coordinate with the init process, since all processes associated + * with the current tty must be dead before the new getty is allowed + * to spawn. + */ +void do_SAK( struct tty_struct *tty) +{ +#ifdef TTY_SOFT_SAK + tty_hangup(tty); +#else + struct task_struct **p; + int line = tty->line; + int session = tty->session; + int i; + struct file *filp; + + flush_input(tty); + flush_output(tty); + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!(*p)) + continue; + if (((*p)->tty == line) || + ((session > 0) && ((*p)->session == session))) + send_sig(SIGKILL, *p, 1); + else { + for (i=0; i < NR_OPEN; i++) { + filp = (*p)->filp[i]; + if (filp && (filp->f_op == &tty_fops) && + (MINOR(filp->f_rdev) == line)) { + send_sig(SIGKILL, *p, 1); + break; + } + } + } + } +#endif +} + +/* + * This routine allows a kernel routine to send a large chunk of data + * to a particular tty; if all of the data can be queued up for ouput + * immediately, tty_write_data() will return 0. If, however, not all + * of the data can be immediately queued for delivery, the number of + * bytes left to be queued up will be returned, and the rest of the + * data will be queued up when there is room. The callback function + * will be called (with the argument callarg) when the last of the + * data is finally in the queue. + * + * Note that the callback routine will _not_ be called if all of the + * data could be queued immediately. This is to avoid a problem with + * the kernel stack getting too deep, which might happen if the + * callback routine calls tty_write_data with itself as an argument. + */ +int tty_write_data(struct tty_struct *tty, char *bufp, int buflen, + void (*callback)(void * data), void * callarg) +{ + int head, tail, count; + unsigned long flags; + char *p; + +#define VLEFT ((tail-head-1)&(TTY_BUF_SIZE-1)) + + save_flags(flags); + cli(); + if (tty->write_data_cnt) { + restore_flags(flags); + return -EBUSY; + } + + head = tty->write_q.head; + tail = tty->write_q.tail; + count = buflen; + p = bufp; + + while (count && VLEFT > 0) { + tty->write_q.buf[head++] = *p++; + head &= TTY_BUF_SIZE-1; + count--; + } + tty->write_q.head = head; + if (count) { + tty->write_data_cnt = count; + tty->write_data_ptr = (unsigned char *) p; + tty->write_data_callback = callback; + tty->write_data_arg = callarg; + } + restore_flags(flags); + tty->write(tty); + return count; +} + +/* + * This routine routine is called after an interrupt has drained a + * tty's write queue, so that there is more space for data waiting to + * be sent in tty->write_data_ptr. + * + * tty_check_write[8] is a bitstring which indicates which ttys + * needs to be processed. + */ +void tty_bh_routine(void * unused) +{ + int i, j, line, mask; + int head, tail, count; + unsigned char * p; + struct tty_struct * tty; + + for (i = 0, line = 0; i < MAX_TTYS / 32; i++) { + if (!tty_check_write[i]) { + line += 32; + continue; + } + for (j=0, mask=0; j < 32; j++, line++, mask <<= 1) { + if (clear_bit(j, &tty_check_write[i])) { + tty = tty_table[line]; + if (!tty || !tty->write_data_cnt) + continue; + cli(); + head = tty->write_q.head; + tail = tty->write_q.tail; + count = tty->write_data_cnt; + p = tty->write_data_ptr; + + while (count && VLEFT > 0) { + tty->write_q.buf[head++] = *p++; + head &= TTY_BUF_SIZE-1; + count--; + } + tty->write_q.head = head; + tty->write_data_ptr = p; + tty->write_data_cnt = count; + sti(); + if (!count) + (tty->write_data_callback) + (tty->write_data_arg); + } + } + } + +} + +/* + * This subroutine initializes a tty structure. We have to set up + * things correctly for each different type of tty. + */ +static void initialize_tty_struct(int line, struct tty_struct *tty) +{ + memset(tty, 0, sizeof(struct tty_struct)); + tty->line = line; + tty->disc = N_TTY; + tty->pgrp = -1; + if (IS_A_CONSOLE(line)) { + tty->open = con_open; + tty->winsize.ws_row = video_num_lines; + tty->winsize.ws_col = video_num_columns; + } else if IS_A_SERIAL(line) { + tty->open = rs_open; + } else if IS_A_PTY(line) { + tty->open = pty_open; + } +} + +static void initialize_termios(int line, struct termios * tp) +{ + memset(tp, 0, sizeof(struct termios)); + memcpy(tp->c_cc, INIT_C_CC, NCCS); + if (IS_A_CONSOLE(line) || IS_A_PTY_SLAVE(line)) { + tp->c_iflag = ICRNL | IXON; + tp->c_oflag = OPOST | ONLCR; + tp->c_cflag = B38400 | CS8 | CREAD; + tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | + ECHOCTL | ECHOKE | IEXTEN; + } else if (IS_A_SERIAL(line)) { + tp->c_iflag = ICRNL | IXON; + tp->c_oflag = OPOST | ONLCR | XTABS; + tp->c_cflag = B9600 | CS8 | CREAD | HUPCL | CLOCAL; + tp->c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK | + ECHOCTL | ECHOKE | IEXTEN; + } else if (IS_A_PTY_MASTER(line)) + tp->c_cflag = B9600 | CS8 | CREAD; +} + +static struct tty_ldisc tty_ldisc_N_TTY = { + 0, /* flags */ + NULL, /* open */ + NULL, /* close */ + read_chan, /* read */ + write_chan, /* write */ + NULL, /* ioctl */ + normal_select, /* select */ + copy_to_cooked /* handler */ +}; + + +long tty_init(long kmem_start) +{ + int i; + + if (sizeof(struct tty_struct) > PAGE_SIZE) + panic("size of tty structure > PAGE_SIZE!"); + if (register_chrdev(TTY_MAJOR,"tty",&tty_fops)) + panic("unable to get major %d for tty device", TTY_MAJOR); + if (register_chrdev(TTYAUX_MAJOR,"tty",&tty_fops)) + panic("unable to get major %d for tty device", TTYAUX_MAJOR); + for (i=0 ; i< MAX_TTYS ; i++) { + tty_table[i] = 0; + tty_termios[i] = 0; + } + memset(tty_check_write, 0, sizeof(tty_check_write)); + bh_base[TTY_BH].routine = tty_bh_routine; + + /* Setup the default TTY line discipline. */ + memset(ldiscs, 0, sizeof(ldiscs)); + (void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY); + + kmem_start = kbd_init(kmem_start); + kmem_start = con_init(kmem_start); + kmem_start = rs_init(kmem_start); + return kmem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_ioctl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_ioctl.c new file mode 100644 index 000000000..1f4b50e44 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/tty_ioctl.c @@ -0,0 +1,657 @@ +/* + * linux/kernel/drivers/char/tty_ioctl.c + * + * Copyright (C) 1991, 1992, 1993, 1994 Linus Torvalds + * + * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines + * which can be dynamically activated and de-activated by the line + * discipline handling modules (like SLIP). + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#undef DEBUG +#ifdef DEBUG +# define PRINTK(x) printk (x) +#else +# define PRINTK(x) /**/ +#endif + +extern int session_of_pgrp(int pgrp); +extern int do_screendump(int arg); +extern int kill_pg(int pgrp, int sig, int priv); + +#ifdef CONFIG_SELECTION +extern int set_selection(const int arg); +extern int paste_selection(struct tty_struct *tty); +#endif /* CONFIG_SELECTION */ + +static int tty_set_ldisc(struct tty_struct *tty, int ldisc); + +void flush_input(struct tty_struct * tty) +{ + cli(); + tty->read_q.head = tty->read_q.tail = 0; + tty->secondary.head = tty->secondary.tail = 0; + tty->canon_head = tty->canon_data = tty->erasing = 0; + memset(&tty->readq_flags, 0, sizeof tty->readq_flags); + memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags); + sti(); + if (!tty->link) + return; + /* No cli() since ptys don't use interrupts. */ + tty->link->write_q.head = tty->link->write_q.tail = 0; + wake_up_interruptible(&tty->link->write_q.proc_list); + if (tty->link->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHREAD; + wake_up_interruptible(&tty->link->secondary.proc_list); + } +} + +void flush_output(struct tty_struct * tty) +{ + cli(); + tty->write_q.head = tty->write_q.tail = 0; + sti(); + wake_up_interruptible(&tty->write_q.proc_list); + if (!tty->link) + return; + /* No cli() since ptys don't use interrupts. */ + tty->link->read_q.head = tty->link->read_q.tail = 0; + tty->link->secondary.head = tty->link->secondary.tail = 0; + tty->link->canon_head = tty->link->canon_data = tty->link->erasing = 0; + memset(&tty->link->readq_flags, 0, sizeof tty->readq_flags); + memset(&tty->link->secondary_flags, 0, sizeof tty->secondary_flags); + if (tty->link->packet) { + tty->ctrl_status |= TIOCPKT_FLUSHWRITE; + wake_up_interruptible(&tty->link->secondary.proc_list); + } +} + +void wait_until_sent(struct tty_struct * tty) +{ + struct wait_queue wait = { current, NULL }; + + TTY_WRITE_FLUSH(tty); + if (EMPTY(&tty->write_q)) + return; + add_wait_queue(&tty->write_q.proc_list, &wait); + current->counter = 0; /* make us low-priority */ + while (1) { + current->state = TASK_INTERRUPTIBLE; + if (current->signal & ~current->blocked) + break; + TTY_WRITE_FLUSH(tty); + if (EMPTY(&tty->write_q)) + break; + schedule(); + } + current->state = TASK_RUNNING; + remove_wait_queue(&tty->write_q.proc_list, &wait); +} + +static int do_get_ps_info(int arg) +{ + struct tstruct { + int flag; + int present[NR_TASKS]; + struct task_struct tasks[NR_TASKS]; + }; + struct tstruct *ts = (struct tstruct *)arg; + struct task_struct **p; + char *c, *d; + int i, n = 0; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct tstruct)); + if (i) + return i; + for (p = &FIRST_TASK ; p <= &LAST_TASK ; p++, n++) + if (*p) + { + c = (char *)(*p); + d = (char *)(ts->tasks+n); + for (i=0 ; ipresent+n)); + } + else + put_fs_long(0, (unsigned long *)(ts->present+n)); + return(0); +} + +static void unset_locked_termios(struct termios *termios, + struct termios *old, + struct termios *locked) +{ + int i; + +#define NOSET_MASK(x,y,z) (x = ((x) & ~(z)) | ((y) & (z))) + + if (!locked) { + printk("Warning?!? termios_locked is NULL.\n"); + return; + } + + NOSET_MASK(termios->c_iflag, old->c_iflag, locked->c_iflag); + NOSET_MASK(termios->c_oflag, old->c_oflag, locked->c_oflag); + NOSET_MASK(termios->c_cflag, old->c_cflag, locked->c_cflag); + NOSET_MASK(termios->c_lflag, old->c_lflag, locked->c_lflag); + termios->c_line = locked->c_line ? old->c_line : termios->c_line; + for (i=0; i < NCCS; i++) + termios->c_cc[i] = locked->c_cc[i] ? + old->c_cc[i] : termios->c_cc[i]; +} + +int check_change(struct tty_struct * tty, int channel) +{ + /* If we try to set the state of terminal and we're not in the + foreground, send a SIGTTOU. If the signal is blocked or + ignored, go ahead and perform the operation. POSIX 7.2) */ + if (current->tty != channel) + return 0; + if (tty->pgrp <= 0) { + printk("check_change: tty->pgrp <= 0!\n"); + return 0; + } + if (current->pgrp == tty->pgrp) + return 0; + if (is_ignored(SIGTTOU)) + return 0; + if (is_orphaned_pgrp(current->pgrp)) + return -EIO; + (void) kill_pg(current->pgrp,SIGTTOU,1); + return -ERESTARTSYS; +} + +static int set_termios_2(struct tty_struct * tty, struct termios * termios) +{ + struct termios old_termios = *tty->termios; + int canon_change; + + canon_change = (old_termios.c_lflag ^ termios->c_lflag) & ICANON; + cli(); + *tty->termios = *termios; + if (canon_change) { + memset(&tty->secondary_flags, 0, sizeof tty->secondary_flags); + tty->canon_head = tty->secondary.tail; + tty->canon_data = 0; + tty->erasing = 0; + } + sti(); + if (canon_change && !L_ICANON(tty) && !EMPTY(&tty->secondary)) + /* Get characters left over from canonical mode. */ + wake_up_interruptible(&tty->secondary.proc_list); + + /* see if packet mode change of state */ + + if (tty->link && tty->link->packet) { + int old_flow = ((old_termios.c_iflag & IXON) && + (old_termios.c_cc[VSTOP] == '\023') && + (old_termios.c_cc[VSTART] == '\021')); + int new_flow = (I_IXON(tty) && + STOP_CHAR(tty) == '\023' && + START_CHAR(tty) == '\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; + wake_up_interruptible(&tty->link->secondary.proc_list); + } + } + + unset_locked_termios(tty->termios, &old_termios, + termios_locked[tty->line]); + + if (tty->set_termios) + (*tty->set_termios)(tty, &old_termios); + + return 0; +} + +static int set_termios(struct tty_struct * tty, struct termios * termios, + int channel) +{ + struct termios tmp_termios; + + memcpy_fromfs(&tmp_termios, termios, sizeof (struct termios)); + return set_termios_2(tty, &tmp_termios); +} + +static int get_termio(struct tty_struct * tty, struct termio * termio) +{ + int i; + struct termio tmp_termio; + + i = verify_area(VERIFY_WRITE, termio, sizeof (struct termio)); + if (i) + return i; + tmp_termio.c_iflag = tty->termios->c_iflag; + tmp_termio.c_oflag = tty->termios->c_oflag; + tmp_termio.c_cflag = tty->termios->c_cflag; + tmp_termio.c_lflag = tty->termios->c_lflag; + tmp_termio.c_line = tty->termios->c_line; + for(i=0 ; i < NCC ; i++) + tmp_termio.c_cc[i] = tty->termios->c_cc[i]; + memcpy_tofs(termio, &tmp_termio, sizeof (struct termio)); + return 0; +} + +static int set_termio(struct tty_struct * tty, struct termio * termio, + int channel) +{ + struct termio tmp_termio; + struct termios tmp_termios; + + tmp_termios = *tty->termios; + memcpy_fromfs(&tmp_termio, termio, sizeof (struct termio)); + +#define SET_LOW_BITS(x,y) ((x) = (0xffff0000 & (x)) | (y)) + + SET_LOW_BITS(tmp_termios.c_iflag, tmp_termio.c_iflag); + SET_LOW_BITS(tmp_termios.c_oflag, tmp_termio.c_oflag); + SET_LOW_BITS(tmp_termios.c_cflag, tmp_termio.c_cflag); + SET_LOW_BITS(tmp_termios.c_lflag, tmp_termio.c_lflag); + memcpy(&tmp_termios.c_cc, &tmp_termio.c_cc, NCC); + +#undef SET_LOW_BITS + + return set_termios_2(tty, &tmp_termios); +} + +static int set_window_size(struct tty_struct * tty, struct winsize * ws) +{ + struct winsize tmp_ws; + + memcpy_fromfs(&tmp_ws, ws, sizeof (struct winsize)); + if (memcmp(&tmp_ws, &tty->winsize, sizeof (struct winsize)) && + tty->pgrp > 0) + kill_pg(tty->pgrp, SIGWINCH, 1); + tty->winsize = tmp_ws; + return 0; +} + +/* Set the discipline of a tty line. */ +static int tty_set_ldisc(struct tty_struct *tty, int ldisc) +{ + if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS) || + !(ldiscs[ldisc].flags & LDISC_FLAG_DEFINED)) + return -EINVAL; + + if (tty->disc == ldisc) + return 0; /* We are already in the desired discipline */ + + /* Shutdown the current discipline. */ + wait_until_sent(tty); + flush_input(tty); + if (ldiscs[tty->disc].close) + ldiscs[tty->disc].close(tty); + + /* Now set up the new line discipline. */ + tty->disc = ldisc; + tty->termios->c_line = ldisc; + if (ldiscs[tty->disc].open) + return(ldiscs[tty->disc].open(tty)); + else + return 0; +} + +static unsigned long inq_canon(struct tty_struct * tty) +{ + int nr, head, tail; + + if (!tty->canon_data) + return 0; + head = tty->canon_head; + tail = tty->secondary.tail; + nr = (head - tail) & (TTY_BUF_SIZE-1); + /* Skip EOF-chars.. */ + while (head != tail) { + if (test_bit(tail, &tty->secondary_flags) && + tty->secondary.buf[tail] == __DISABLED_CHAR) + nr--; + INC(tail); + } + return nr; +} + +int tty_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct tty_struct * tty; + struct tty_struct * other_tty; + struct tty_struct * termios_tty; + pid_t pgrp; + int dev; + int termios_dev; + int retval; + + if (MAJOR(file->f_rdev) != TTY_MAJOR) { + printk("tty_ioctl: tty pseudo-major != TTY_MAJOR\n"); + return -EINVAL; + } + dev = MINOR(file->f_rdev); + tty = TTY_TABLE(dev); + if (!tty) + return -EINVAL; + if (IS_A_PTY(dev)) + other_tty = tty_table[PTY_OTHER(dev)]; + else + other_tty = NULL; + if (IS_A_PTY_MASTER(dev)) { + termios_tty = other_tty; + termios_dev = PTY_OTHER(dev); + } else { + termios_tty = tty; + termios_dev = dev; + } + switch (cmd) { + case TCGETS: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct termios)); + if (retval) + return retval; + memcpy_tofs((struct termios *) arg, + termios_tty->termios, + sizeof (struct termios)); + return 0; + case TCSETSF: + case TCSETSW: + case TCSETS: + retval = check_change(termios_tty, termios_dev); + if (retval) + return retval; + if (cmd == TCSETSF || cmd == TCSETSW) { + if (cmd == TCSETSF) + flush_input(termios_tty); + wait_until_sent(termios_tty); + } + return set_termios(termios_tty, (struct termios *) arg, + termios_dev); + case TCGETA: + return get_termio(termios_tty,(struct termio *) arg); + case TCSETAF: + case TCSETAW: + case TCSETA: + retval = check_change(termios_tty, termios_dev); + if (retval) + return retval; + if (cmd == TCSETAF || cmd == TCSETAW) { + if (cmd == TCSETAF) + flush_input(termios_tty); + wait_until_sent(termios_tty); + } + return set_termio(termios_tty, (struct termio *) arg, + termios_dev); + case TCXONC: + retval = check_change(tty, dev); + if (retval) + return retval; + switch (arg) { + case TCOOFF: + stop_tty(tty); + break; + case TCOON: + start_tty(tty); + break; + case TCIOFF: + if (STOP_CHAR(tty) != __DISABLED_CHAR) + put_tty_queue(STOP_CHAR(tty), + &tty->write_q); + break; + case TCION: + if (START_CHAR(tty) != __DISABLED_CHAR) + put_tty_queue(START_CHAR(tty), + &tty->write_q); + break; + default: + return -EINVAL; + } + return 0; + case TCFLSH: + retval = check_change(tty, dev); + if (retval) + return retval; + switch (arg) { + case TCIFLUSH: + flush_input(tty); + break; + case TCIOFLUSH: + flush_input(tty); + /* fall through */ + case TCOFLUSH: + flush_output(tty); + break; + default: + return -EINVAL; + } + return 0; + case TIOCEXCL: + set_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCNXCL: + clear_bit(TTY_EXCLUSIVE, &tty->flags); + return 0; + case TIOCSCTTY: + if (current->leader && + (current->session == tty->session)) + return 0; + /* + * The process must be a session leader and + * not have a controlling tty already. + */ + if (!current->leader || (current->tty >= 0)) + return -EPERM; + if (tty->session > 0) { + /* + * This tty is already the controlling + * tty for another session group! + */ + if ((arg == 1) && suser()) { + /* + * Steal it away + */ + struct task_struct *p; + + for_each_task(p) + if (p->tty == dev) + p->tty = -1; + } else + return -EPERM; + } + current->tty = dev; + tty->session = current->session; + tty->pgrp = current->pgrp; + return 0; + case TIOCGPGRP: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (pid_t)); + if (retval) + return retval; + put_fs_long(termios_tty->pgrp, (pid_t *) arg); + return 0; + case TIOCSPGRP: + retval = check_change(termios_tty, termios_dev); + if (retval) + return retval; + if ((current->tty < 0) || + (current->tty != termios_dev) || + (termios_tty->session != current->session)) + return -ENOTTY; + pgrp = get_fs_long((pid_t *) arg); + if (pgrp < 0) + return -EINVAL; + if (session_of_pgrp(pgrp) != current->session) + return -EPERM; + termios_tty->pgrp = pgrp; + return 0; + case TIOCOUTQ: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + put_fs_long(CHARS(&tty->write_q), + (unsigned long *) arg); + return 0; + case TIOCINQ: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + if (L_ICANON(tty)) + put_fs_long(inq_canon(tty), + (unsigned long *) arg); + else + put_fs_long(CHARS(&tty->secondary), + (unsigned long *) arg); + return 0; + case TIOCSTI: + if ((current->tty != dev) && !suser()) + return -EACCES; + put_tty_queue(get_fs_byte((char *) arg), &tty->read_q); + TTY_READ_FLUSH(tty); + return 0; + case TIOCGWINSZ: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct winsize)); + if (retval) + return retval; + memcpy_tofs((struct winsize *) arg, &tty->winsize, + sizeof (struct winsize)); + return 0; + case TIOCSWINSZ: + if (IS_A_PTY_MASTER(dev)) + set_window_size(other_tty,(struct winsize *) arg); + return set_window_size(tty,(struct winsize *) arg); + case TIOCLINUX: + switch (get_fs_byte((char *)arg)) + { + case 0: + return do_screendump(arg); + case 1: + return do_get_ps_info(arg); +#ifdef CONFIG_SELECTION + case 2: + return set_selection(arg); + case 3: + return paste_selection(tty); +#endif /* CONFIG_SELECTION */ + default: + return -EINVAL; + } + case TIOCCONS: + if (IS_A_CONSOLE(dev)) { + if (!suser()) + return -EPERM; + redirect = NULL; + return 0; + } + if (redirect) + return -EBUSY; + if (!suser()) + return -EPERM; + if (IS_A_PTY_MASTER(dev)) + redirect = other_tty; + else if (IS_A_PTY_SLAVE(dev)) + redirect = tty; + else + return -EINVAL; + return 0; + case FIONBIO: + arg = get_fs_long((unsigned long *) arg); + if (arg) + file->f_flags |= O_NONBLOCK; + else + file->f_flags &= ~O_NONBLOCK; + return 0; + case TIOCNOTTY: + if (MINOR(file->f_rdev) != current->tty) + return -EINVAL; + if (current->leader) + disassociate_ctty(0); + current->tty = -1; + return 0; + case TIOCGETD: + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + put_fs_long(tty->disc, (unsigned long *) arg); + return 0; + case TIOCSETD: + retval = check_change(tty, dev); + if (retval) + return retval; + arg = get_fs_long((unsigned long *) arg); + return tty_set_ldisc(tty, arg); + case TIOCGLCKTRMIOS: + arg = get_fs_long((unsigned long *) arg); + retval = verify_area(VERIFY_WRITE, (void *) arg, + sizeof (struct termios)); + if (retval) + return retval; + memcpy_tofs((struct termios *) arg, + &termios_locked[termios_dev], + sizeof (struct termios)); + return 0; + case TIOCSLCKTRMIOS: + if (!suser()) + return -EPERM; + arg = get_fs_long((unsigned long *) arg); + memcpy_fromfs(&termios_locked[termios_dev], + (struct termios *) arg, + sizeof (struct termios)); + return 0; + case TIOCPKT: + if (!IS_A_PTY_MASTER(dev)) + return -EINVAL; + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (unsigned long)); + if (retval) + return retval; + if (get_fs_long(arg)) { + if (!tty->packet) { + tty->packet = 1; + tty->ctrl_status = 0; + } + } else + tty->packet = 0; + return 0; + case TCSBRK: case TCSBRKP: + retval = check_change(tty, dev); + if (retval) + return retval; + wait_until_sent(tty); + if (!tty->ioctl) + return 0; + tty->ioctl(tty, file, cmd, arg); + return 0; + default: + if (tty->ioctl) { + retval = (tty->ioctl)(tty, file, cmd, arg); + if (retval != -EINVAL) + return retval; + } + if (ldiscs[tty->disc].ioctl) { + retval = (ldiscs[tty->disc].ioctl) + (tty, file, cmd, arg); + return retval; + } + return -EINVAL; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt.c new file mode 100644 index 000000000..2fb3731da --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt.c @@ -0,0 +1,591 @@ +/* + * kernel/chr_drv/vt.c + * + * Copyright (C) 1992 obz under the linux copyright + * Dynamic diacritical handling - aeb@cwi.nl - Dec 1993 + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "kbd_kern.h" +#include "vt_kern.h" +#include "diacr.h" + +/* + * Console (vt and kd) routines, as defined by USL SVR4 manual, and by + * experimentation and study of X386 SYSV handling. + * + * One point of difference: SYSV vt's are /dev/vtX, which X >= 0, and + * /dev/console is a separate ttyp. Under Linux, /dev/tty0 is /dev/console, + * and the vc start at /dev/ttyX, X >= 1. We maintain that here, so we will + * always treat our set of vt as numbered 1..NR_CONSOLES (corresponding to + * ttys 0..NR_CONSOLES-1). Explicitly naming VT 0 is illegal, but using + * /dev/tty0 (fg_console) as a target is legal, since an implicit aliasing + * to the current console is done by the main ioctl code. + */ + +struct vt_struct 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); + +/* + * routines to load custom translation table and EGA/VGA font from console.c + */ +extern int con_set_trans(char * table); +extern int con_get_trans(char * table); +extern int con_set_font(char * fontmap); +extern int con_get_font(char * fontmap); + +/* + * these are the valid i/o ports we're allowed to change. they map all the + * video ports + */ +#define GPFIRST 0x3b4 +#define GPLAST 0x3df +#define GPNUM (GPLAST - GPFIRST + 1) + +/* + * Generates sound of some count for some number of clock ticks + * [count = 1193180 / frequency] + * + * If freq is 0, will turn off sound, else will turn it on for that time. + * If msec is 0, will return immediately, else will sleep for msec time, then + * turn sound off. + * + * We use the BEEP_TIMER vector since we're using the same method to + * generate sound, and we'll overwrite any beep in progress. That may + * be something to fix later, if we like. + * + * We also return immediately, which is what was implied within the X + * comments - KDMKTONE doesn't put the process to sleep. + */ +static void +kd_nosound(unsigned long ignored) +{ + /* disable counter 2 */ + outb(inb_p(0x61)&0xFC, 0x61); + return; +} + +void +kd_mksound(unsigned int count, unsigned int ticks) +{ + static struct timer_list sound_timer = { NULL, 0, 0, kd_nosound }; + + cli(); + del_timer(&sound_timer); + if (count) { + /* enable counter 2 */ + outb_p(inb_p(0x61)|3, 0x61); + /* set command for counter 2, 2 byte write */ + outb_p(0xB6, 0x43); + /* select desired HZ */ + outb_p(count & 0xff, 0x42); + outb((count >> 8) & 0xff, 0x42); + + if (ticks) { + sound_timer.expires = ticks; + add_timer(&sound_timer); + } + } else + kd_nosound(0); + sti(); + return; +} + +/* + * We handle the console-specific ioctl's here. We allow the + * capability to modify any console, not just the fg_console. + */ +int vt_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int console, i; + unsigned char ucval; + struct kbd_struct * kbd; + + console = tty->line - 1; + + if (console < 0 || console >= NR_CONSOLES) + return -EINVAL; + + kbd = kbd_table + console; + switch (cmd) { + case KIOCSOUND: + kd_mksound((unsigned int)arg, 0); + return 0; + + case KDMKTONE: + { + unsigned int ticks = HZ * ((arg >> 16) & 0xffff) / 1000; + + /* + * Generate the tone for the appropriate number of ticks. + * If the time is zero, turn off sound ourselves. + */ + kd_mksound(arg & 0xffff, ticks); + if (ticks == 0) + kd_nosound(0); + return 0; + } + + case KDGKBTYPE: + /* + * this is naive. + */ + i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char)); + if (!i) + put_fs_byte(KB_101, (char *) arg); + return i; + + case KDADDIO: + case KDDELIO: + /* + * KDADDIO and KDDELIO may be able to add ports beyond what + * we reject here, but to be safe... + */ + if (arg < GPFIRST || arg > GPLAST) + return -EINVAL; + return sys_ioperm(arg, 1, (cmd == KDADDIO)) ? -ENXIO : 0; + + case KDENABIO: + case KDDISABIO: + return sys_ioperm(GPFIRST, GPNUM, + (cmd == KDENABIO)) ? -ENXIO : 0; + + case KDSETMODE: + /* + * currently, setting the mode from KD_TEXT to KD_GRAPHICS + * doesn't do a whole lot. i'm not sure if it should do any + * restoration of modes or what... + */ + switch (arg) { + case KD_GRAPHICS: + break; + case KD_TEXT0: + case KD_TEXT1: + arg = KD_TEXT; + case KD_TEXT: + break; + default: + return -EINVAL; + } + if (vt_cons[console].vc_mode == (unsigned char) arg) + return 0; + vt_cons[console].vc_mode = (unsigned char) arg; + if (console != fg_console) + return 0; + /* + * explicitly blank/unblank the screen if switching modes + */ + if (arg == KD_TEXT) + unblank_screen(); + else { + timer_active &= ~(1<kb_index)) >= NR_KEYS) + return -EINVAL; + if ((s = get_fs_byte((char *) &a->kb_table)) >= NR_KEYMAPS) + return -EINVAL; + put_fs_word(key_map[s][i], (short *) &a->kb_value); + return 0; + } + + case KDSKBENT: + { + const struct kbentry * a = (struct kbentry *)arg; + u_char s; + u_short v; + + i = verify_area(VERIFY_READ, (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) + return -EINVAL; + if (KTYP(v = get_fs_word(&a->kb_value)) >= NR_TYPES) + return -EINVAL; + if (KVAL(v) > max_vals[KTYP(v)]) + return -EINVAL; + key_map[s][i] = v; + return 0; + } + + case KDGKBSENT: + { + struct kbsentry *a = (struct kbsentry *)arg; + char *p; + u_char *q; + + i = verify_area(VERIFY_WRITE, (void *)a, sizeof(struct kbsentry)); + if (i) + return i; + if ((i = get_fs_byte(&a->kb_func)) >= NR_FUNC || i < 0) + return -EINVAL; + q = a->kb_string; + p = func_table[i]; + if(!p) { + /* beware of tables generated for a smaller NR_FUNC */ + printk("KDGKBSENT error: func_table[%d] is nil.\n", + i); + return -EINVAL; + } + for ( ; *p; p++) + put_fs_byte(*p, q++); + put_fs_byte(0, q); + return 0; + } + + case KDSKBSENT: + { + struct kbsentry * const a = (struct kbsentry *)arg; + int delta; + char *first_free; + int k; + u_char *p; + char *q; + + 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; + q = func_table[i]; + if (!q) { + /* beware of tables generated for a smaller NR_FUNC */ + printk("KDSKBSENT error: func_table[%d] is nil.\n", + i); + return -EINVAL; + } + delta = -strlen(q); + for (p = a->kb_string; get_fs_byte(p); p++) + delta++; + first_free = func_table[NR_FUNC - 1] + + strlen(func_table[NR_FUNC - 1]) + 1; + if ( + delta > 0 && + first_free + delta > func_buf + FUNC_BUFSIZE + ) + return -EINVAL; + if (i < NR_FUNC - 1) { + memmove( + func_table[i + 1] + delta, + func_table[i + 1], + first_free - func_table[i + 1]); + for (k = i + 1; k < NR_FUNC; k++) + if (func_table[k]) /* just to be sure */ + func_table[k] += delta; + } + for (p = a->kb_string, q = func_table[i]; ; p++, q++) + if (!(*q = get_fs_byte(p))) + break; + return 0; + } + + case KDGKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + + i = verify_area(VERIFY_WRITE, (void *) a, sizeof(struct kbdiacrs)); + if (i) + return i; + put_fs_long(accent_table_size, &a->kb_cnt); + memcpy_tofs(a->kbdiacr, accent_table, + accent_table_size*sizeof(struct kbdiacr)); + return 0; + } + + case KDSKBDIACR: + { + struct kbdiacrs *a = (struct kbdiacrs *)arg; + unsigned int ct; + + i = verify_area(VERIFY_READ, (void *) a, sizeof(struct kbdiacrs)); + if (i) + return i; + ct = get_fs_long(&a->kb_cnt); + if (ct >= MAX_DIACR) + return -EINVAL; + accent_table_size = ct; + memcpy_fromfs(accent_table, a->kbdiacr, ct*sizeof(struct kbdiacr)); + return 0; + } + + case KDGETLED: + i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(unsigned char)); + if (i) + return i; + put_fs_byte(kbd->ledstate, (char *) arg); + return 0; + + case KDSETLED: + if (arg & ~7) + return -EINVAL; + kbd->ledstate = arg; + set_leds(); + return 0; + + case VT_SETMODE: + { + struct vt_mode *vtmode = (struct vt_mode *)arg; + char mode; + + i = verify_area(VERIFY_WRITE, (void *)vtmode, sizeof(struct vt_mode)); + if (i) + return i; + mode = get_fs_byte(&vtmode->mode); + if (mode != VT_AUTO && mode != VT_PROCESS) + return -EINVAL; + vt_cons[console].vt_mode.mode = mode; + vt_cons[console].vt_mode.waitv = get_fs_byte(&vtmode->waitv); + vt_cons[console].vt_mode.relsig = get_fs_word(&vtmode->relsig); + vt_cons[console].vt_mode.acqsig = get_fs_word(&vtmode->acqsig); + /* the frsig is ignored, so we set it to 0 */ + vt_cons[console].vt_mode.frsig = 0; + vt_cons[console].vt_pid = current->pid; + vt_cons[console].vt_newvt = 0; + return 0; + } + + case VT_GETMODE: + { + struct vt_mode *vtmode = (struct vt_mode *)arg; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct vt_mode)); + if (i) + return i; + put_fs_byte(vt_cons[console].vt_mode.mode, &vtmode->mode); + put_fs_byte(vt_cons[console].vt_mode.waitv, &vtmode->waitv); + put_fs_word(vt_cons[console].vt_mode.relsig, &vtmode->relsig); + put_fs_word(vt_cons[console].vt_mode.acqsig, &vtmode->acqsig); + put_fs_word(vt_cons[console].vt_mode.frsig, &vtmode->frsig); + return 0; + } + + /* + * Returns global vt state. Note that VT 0 is always open, since + * it's an alias for the current VT, and people can't use it here. + */ + case VT_GETSTATE: + { + struct vt_stat *vtstat = (struct vt_stat *)arg; + unsigned short state, mask; + + i = verify_area(VERIFY_WRITE,(void *)vtstat, sizeof(struct vt_stat)); + if (i) + return i; + put_fs_word(fg_console + 1, &vtstat->v_active); + state = 1; /* /dev/tty0 is always open */ + for (i = 1, mask = 2; i <= NR_CONSOLES; ++i, mask <<= 1) + if (tty_table[i] && tty_table[i]->count > 0) + state |= mask; + put_fs_word(state, &vtstat->v_state); + return 0; + } + + /* + * Returns the first available (non-opened) console. + */ + case VT_OPENQRY: + i = verify_area(VERIFY_WRITE, (void *) arg, sizeof(long)); + if (i) + return i; + for (i = 1; i <= NR_CONSOLES; ++i) + if (!tty_table[i] || tty_table[i]->count == 0) + break; + put_fs_long(i <= NR_CONSOLES ? i : -1, (unsigned long *)arg); + return 0; + + /* + * ioctl(fd, VT_ACTIVATE, num) will cause us to switch to vt # num, + * with num >= 1 (switches to vt 0, our console) are not allowed, just + * to preserve sanity. + */ + case VT_ACTIVATE: + if (arg == 0 || arg > NR_CONSOLES) + return -ENXIO; + change_console(arg - 1); + return 0; + + /* + * wait until the specified VT has been activated + */ + case VT_WAITACTIVE: + if (arg == 0 || arg > NR_CONSOLES) + return -ENXIO; + while (fg_console != arg - 1) + { + if (vt_waitactive() < 0) + return -EINTR; + } + return 0; + + /* + * If a vt is under process control, the kernel will not switch to it + * immediately, but postpone the operation until the process calls this + * ioctl, allowing the switch to complete. + * + * According to the X sources this is the behavior: + * 0: pending switch-from not OK + * 1: pending switch-from OK + * 2: completed switch-to OK + */ + case VT_RELDISP: + if (vt_cons[console].vt_mode.mode != VT_PROCESS) + return -EINVAL; + + /* + * Switching-from response + */ + if (vt_cons[console].vt_newvt >= 0) + { + if (arg == 0) + /* + * Switch disallowed, so forget we were trying + * to do it. + */ + vt_cons[console].vt_newvt = -1; + + else + { + /* + * The current vt has been released, so + * complete the switch. + */ + int newvt = vt_cons[console].vt_newvt; + vt_cons[console].vt_newvt = -1; + complete_change_console(newvt); + } + } + + /* + * Switched-to response + */ + else + { + /* + * If it's just an ACK, ignore it + */ + if (arg != VT_ACKACQ) + return -EINVAL; + } + + return 0; + + case PIO_FONT: + return con_set_font((char *)arg); + /* con_set_font() defined in console.c */ + + case GIO_FONT: + return con_get_font((char *)arg); + /* con_get_font() defined in console.c */ + + case PIO_SCRNMAP: + return con_set_trans((char *)arg); + /* con_set_trans() defined in console.c */ + + case GIO_SCRNMAP: + return con_get_trans((char *)arg); + /* con_get_trans() defined in console.c */ + + default: + return -EINVAL; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt_kern.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt_kern.h new file mode 100644 index 000000000..978119a38 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/char/vt_kern.h @@ -0,0 +1,23 @@ +#ifndef _VT_KERN_H +#define _VT_KERN_H + +/* + * this really is an extension of the vc_cons structure in console.c, but + * with information needed by the vt package + */ + +#include + +extern struct vt_struct { + unsigned char vc_mode; /* KD_TEXT, ... */ + unsigned char vc_kbdraw; + unsigned char vc_kbde0; + unsigned char vc_kbdleds; + struct vt_mode vt_mode; + int vt_pid; + int vt_newvt; +} vt_cons[NR_CONSOLES]; + +void kd_mksound(unsigned int count, unsigned int ticks); + +#endif /* _VT_KERN_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c501.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c501.c new file mode 100644 index 000000000..d0141b0e5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c501.c @@ -0,0 +1,560 @@ +/* 3c501.c: A 3Com 3c501 ethernet driver for linux. */ +/* + Copyright (C) 1992,1993 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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]; +#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->data, 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 = skb->data; + + 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); + outsb(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; + + insb(DATAPORT, skb->data, 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.c new file mode 100644 index 000000000..bf86c6fa8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.c @@ -0,0 +1,442 @@ +/* 3c503.c: A shared-memory NS8390 ethernet driver 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 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 = + "3c503.c:v0.99.13 8/30/93 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include + +#include "dev.h" + +#include "8390.h" +#include "3c503.h" + +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, + const unsigned char *buf, const start_page); +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 +el2_probe(struct device *dev) +{ + int *addr, addrs[] = { 0xddffe, 0xd9ffe, 0xcdffe, 0xc9ffe, 0}; + short ioaddr = dev->base_addr; + + if (ioaddr < 0) + return ENXIO; /* Don't probe at all. */ + if (ioaddr > 0) + return ! el2probe1(ioaddr, dev); + + for (addr = addrs; *addr; addr++) { + int i; + unsigned int base_bits = *(unsigned char *)*addr; + /* Find first set bit. */ + for(i = 7; i >= 0; i--, base_bits >>= 1) + if (base_bits & 0x1) + break; + if (base_bits != 1) + continue; +#ifdef HAVE_PORTRESERVE + if (check_region(ports[i], 16)) + continue; +#endif + if (el2probe1(ports[i], dev)) + return 0; + } +#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; + } + 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 +el2probe1(int ioaddr, struct device *dev) +{ + int i, iobase_reg, membase_reg, saved_406; + unsigned char *station_addr = dev->dev_addr; + + /* We verify that it's a 3C503 board by checking the first three octets + of its ethernet address. */ + printk("3c503 probe at %#3x:", ioaddr); + iobase_reg = inb(ioaddr+0x403); + membase_reg = inb(ioaddr+0x404); + /* Verify ASIC register that should be 0 or have a single bit set. */ + if ( (iobase_reg & (iobase_reg - 1)) + || (membase_reg & (membase_reg - 1))) { + printk(" not found.\n"); + return 0; + } + saved_406 = inb_p(ioaddr + 0x406); + outb_p(ECNTRL_RESET|ECNTRL_THIN, ioaddr + 0x406); /* Reset it... */ + outb_p(ECNTRL_THIN, ioaddr + 0x406); + /* Map the station addr PROM into the lower I/O ports. */ + outb(ECNTRL_SAPROM|ECNTRL_THIN, ioaddr + 0x406); + for (i = 0; i < ETHER_ADDR_LEN; i++) { + printk(" %2.2X", (station_addr[i] = inb(ioaddr + i))); + } + if ( station_addr[0] != 0x02 + || station_addr[1] != 0x60 + || station_addr[2] != 0x8c) { + printk(" 3C503 not found.\n"); + /* Restore the register we frobbed. */ + 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 { + dev->mem_start = ((membase_reg & 0xc0) ? 0xD8000 : 0xC8000) + + ((membase_reg & 0xA0) ? 0x4000 : 0); + +#define EL2_MEMSIZE (EL2SM_STOP_PG - EL2SM_START_PG)*256 +#ifdef EL2MEMTEST + /* This has never found an error, but someone might care. */ + { /* Check the card's memory. */ + int *mem_base = (int *)dev->mem_start; + int memtest_value = 0xbbadf00d; + mem_base[0] = 0xba5eba5e; + for (i = 1; i < EL2_MEMSIZE/sizeof(mem_base[0]); i++) { + mem_base[i] = memtest_value; + if (mem_base[0] != 0xba5eba5e + || mem_base[i] != memtest_value) { + printk(" memory failure or memory address conflict.\n"); + dev->mem_start = 0; + break; + } + memtest_value += 0x55555555; + mem_base[i] = 0; + } + } +#endif /* EL2MEMTEST */ + /* Divide the on-board memory into a single maximum-sized transmit + (double-sized for ping-pong transmit) buffer at the base, and + use the rest as a receive ring. */ + dev->mem_end = dev->rmem_end = dev->mem_start + EL2_MEMSIZE; + dev->rmem_start = TX_PAGES*256 + dev->mem_start; + } + if (ei_debug > 2) + printk("\n3c503: memory params start=%#5x rstart=%#5x end=%#5x rend=%#5x.\n", + dev->mem_start, dev->rmem_start, dev->mem_end, dev->rmem_end); + + /* Finish setting the board's parameters. */ + ei_status.name = "3C503"; + ei_status.tx_start_page = EL2SM_START_PG; + ei_status.rx_start_page = EL2SM_START_PG + TX_PAGES; + ei_status.stop_page = EL2SM_STOP_PG; + ei_status.reset_8390 = &el2_reset_8390; + ei_status.block_input = &el2_block_input; + ei_status.block_output = &el2_block_output; + + 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 (*irqp, NULL) != -EBUSY) { + /* Twinkle the interrupt, and check if it's seen. */ + autoirq_setup(0); + outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); + outb_p(0x00, E33G_IDCFR); + if (*irqp == autoirq_report(0) /* It's a good IRQ line! */ + && request_irq (dev->irq = *irqp, &ei_interrupt) == 0) + break; + } + } while (*++irqp); + if (*irqp == 0) { + outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */ + return -EAGAIN; + } + } else { + if (request_irq(dev->irq, &ei_interrupt)) { + return -EAGAIN; + } + } + el2_init_card(dev); + return ei_open(dev); +} + +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. */ + + NS8390_init(dev, 0); + + return 0; +} + +/* This is called whenever we have a unrecoverable failure: + transmit timeout + Bad ring buffer packet header + */ +static void +el2_reset_8390(struct device *dev) +{ + if (ei_debug > 1) { + printk("%s: Resetting the 3c503 board...", dev->name); + printk("%#x=%#02x %#x=%#02x %#x=%#02x...", E33G_IDCFR, inb(E33G_IDCFR), + E33G_CNTRL, inb(E33G_CNTRL), E33G_GACFR, inb(E33G_GACFR)); + } + outb_p(ECNTRL_RESET|ECNTRL_THIN, E33G_CNTRL); + ei_status.txing = 0; + outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); + el2_init_card(dev); + if (ei_debug > 1) printk("done\n"); +} + +/* Initialize the 3c503 GA registers after a reset. */ +static void +el2_init_card(struct device *dev) +{ + /* Unmap the station PROM and select the DIX or BNC connector. */ + outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); + + /* Set ASIC copy of rx's first and last+1 buffer pages */ + /* These must be the same as in the 8390. */ + outb(ei_status.rx_start_page, E33G_STARTPG); + outb(ei_status.stop_page, E33G_STOPPG); + + /* Point the vector pointer registers somewhere ?harmless?. */ + outb(0xff, E33G_VP2); /* Point at the ROM restart location 0xffff0 */ + outb(0xff, E33G_VP1); + outb(0x00, E33G_VP0); + /* Turn off all interrupts until we're opened. */ + outb_p(0x00, dev->base_addr + EN0_IMR); + /* Enable IRQs iff started. */ + outb(EGACFR_NORM, E33G_GACFR); + + /* Set the interrupt line. */ + outb_p((0x04 << (dev->irq == 9 ? 2 : dev->irq)), E33G_IDCFR); + outb_p(8, E33G_DRQCNT); /* Set burst size to 8 */ + outb_p(0x20, E33G_DMAAH); /* Put a valid addr in the GA DMA */ + outb_p(0x00, E33G_DMAAL); + return; /* We always succeed */ +} + +/* Either use the shared memory (if enabled on the board) or put the packet + out through the ASIC FIFO. The latter is probably much slower. */ +static void +el2_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page) +{ + int i; /* Buffer index */ + int boguscount = 0; /* timeout counter */ + + /* This should really be set with during an open(). */ + outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */ + + if (dev->mem_start) { /* Shared memory transfer */ + void *dest_addr = (void *)(dev->mem_start + + ((start_page - ei_status.tx_start_page) << 8)); + 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, (int) dest_addr); + else if (ei_debug > 4) + printk("%s: 3c503 send_packet() good memory copy @ %#5x.\n", + dev->name, (int) dest_addr); + return; + } + /* No shared memory, put the packet out the slow way. */ + /* Set up then start the internal memory transfer to Tx Start Page */ + outb(0x00, E33G_DMAAL); + outb_p(start_page, E33G_DMAAH); + outb_p((ei_status.interface_num ? ECNTRL_AUI : ECNTRL_THIN ) | ECNTRL_OUTPUT + | ECNTRL_START, E33G_CNTRL); + + /* This is the byte copy loop: it should probably be tuned for + for speed once everything is working. I think it is possible + to output 8 bytes between each check of the status bit. */ + for(i = 0; i < count; i++) { + if (i % 8 == 0) + while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0) + if (++boguscount > (i<<3) + 32) { + printk("%s: FIFO blocked in el2_block_output (at %d of %d, bc=%d).\n", + dev->name, i, count, boguscount); + return; + } + outb(buf[i], E33G_FIFOH); + } + outb_p(ei_status.interface_num==0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); + return; +} + +/* Returns the new ring pointer. */ +static int +el2_block_input(struct device *dev, int count, char *buf, int ring_offset) +{ + int boguscount = 0; + int end_of_ring = dev->rmem_end; + unsigned int i; + + /* Maybe enable shared memory just be to be safe... nahh.*/ + if (dev->mem_start) { /* Use the shared memory. */ + ring_offset -= (EL2SM_START_PG<<8); + if (dev->mem_start + ring_offset + count > end_of_ring) { + /* We must wrap the input move. */ + int semi_count = end_of_ring - (dev->mem_start + ring_offset); + if (ei_debug > 4) + printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n", + dev->name, 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); + return dev->rmem_start + count; + } + if (ei_debug > 4) + printk("%s: 3c503 block_input() @ %#5x+%x=%5x.\n", + dev->name, dev->mem_start, ring_offset, + dev->mem_start + ring_offset); + memcpy(buf, (char *)dev->mem_start + ring_offset, count); + return ring_offset + count; + } + /* No shared memory, use programmed I/O. */ + outb(ring_offset & 0xff, E33G_DMAAL); + outb_p((ring_offset >> 8) & 0xff, E33G_DMAAH); + outb_p((ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI) | ECNTRL_INPUT + | ECNTRL_START, E33G_CNTRL); + + /* This is the byte copy loop: it should probably be tuned for + for speed once everything is working. */ + for(i = 0; i < count; i++) { + if (i % 8 == 0) + while ((inb(E33G_STATUS) & ESTAT_DPRDY) == 0) + if (++boguscount > (i<<3) + 32) { + printk("%s: FIFO blocked in el2_block_input() (at %d of %d, bc=%d).\n", + dev->name, i, count, boguscount); + boguscount = 0; + break; + } + buf[i] = inb_p(E33G_FIFOH); + } + outb_p(ei_status.interface_num == 0 ? ECNTRL_THIN : ECNTRL_AUI, E33G_CNTRL); + return 0; +} + +/* + * Local variables: + * version-control: t + * kept-new-versions: 5 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.h new file mode 100644 index 000000000..f469a92c3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c503.h @@ -0,0 +1,60 @@ +/* Definitions for the 3Com 3c503 Etherlink 2. */ +/* This file is distributed under the GPL. + 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) + +/* Shared memory management parameters */ + +#define EL2SM_START_PG (0x20) /* First page of TX buffer */ +#define EL2SM_STOP_PG (0x40) /* Last page +1 of RX ring */ + +/* 3Com 3c503 ASIC registers */ +#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) */ +#define E33G_ROMBASE (EL2H+4) /* Read of memory base jumpers. */ +#define E33G_GACFR (EL2H+5) /* Config/setup bits for the ASIC GA */ +#define E33G_CNTRL (EL2H+6) /* Board's main control register */ +#define E33G_STATUS (EL2H+7) /* Status on completions. */ +#define E33G_IDCFR (EL2H+8) /* Interrupt/DMA config register */ + /* (Which IRQ to assert, DMA chan to use) */ +#define E33G_DMAAH (EL2H+9) /* High byte of DMA address reg */ +#define E33G_DMAAL (EL2H+10) /* Low byte of DMA address reg */ +/* "Vector pointer" - if this address matches a read, the EPROM (rather than + shared RAM) is mapped into memory space. */ +#define E33G_VP2 (EL2H+11) +#define E33G_VP1 (EL2H+12) +#define E33G_VP0 (EL2H+13) +#define E33G_FIFOH (EL2H+14) /* FIFO for programmed I/O moves */ +#define E33G_FIFOL (EL2H+15) /* ... low byte of above. */ + +/* Bits in E33G_CNTRL register: */ + +#define ECNTRL_RESET (0x01) /* Software reset of the ASIC and 8390 */ +#define ECNTRL_THIN (0x02) /* Onboard xcvr enable, AUI disable */ +#define ECNTRL_AUI (0x00) /* Onboard xcvr disable, AUI enable */ +#define ECNTRL_SAPROM (0x04) /* Map the station address prom */ +#define ECNTRL_DBLBFR (0x20) /* FIFO configuration bit */ +#define ECNTRL_OUTPUT (0x40) /* PC-to-3C503 direction if 1 */ +#define ECNTRL_INPUT (0x00) /* 3C503-to-PC direction if 0 */ +#define ECNTRL_START (0x80) /* Start the DMA logic */ + +/* Bits in E33G_STATUS register: */ + +#define ESTAT_DPRDY (0x80) /* Data port (of FIFO) ready */ +#define ESTAT_UFLW (0x40) /* Tried to read FIFO when it was empty */ +#define ESTAT_OFLW (0x20) /* Tried to write FIFO when it was full */ +#define ESTAT_DTC (0x10) /* Terminal Count from PC bus DMA logic */ +#define ESTAT_DIP (0x08) /* DMA In Progress */ + +/* Bits in E33G_GACFR register: */ + +#define EGACFR_NORM (0x49) /* Enable 8K shared mem, no DMA TC int */ +#define EGACFR_IRQOFF (0xc9) /* Above, and disable 8390 IRQ line */ + +/* End of 3C503 parameter definitions */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c507.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c507.c new file mode 100644 index 000000000..ba53e06cc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c507.c @@ -0,0 +1,898 @@ +/* 3c507.c: An EtherLink16 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 + + Thanks go to jennings@Montrouge.SMR.slb.com ( Patrick Jennings) + and jrs@world.std.com (Rick Sladkey) for testing and bugfixes. + + Things remaining to do: + Verify that the tx and rx buffers don't have fencepost errors. + Move the theory of operation and memory map documentation. + The statistics need to be updated correctly. +*/ + +static char *version = + "3c507.c:v0.03 10/27/93 Donald Becker (becker@super.org)\n"; + +#include + +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.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(addr, size) kfree_s(addr,size); +#else +#include +#endif + +/* use 0 for production, 1 for verification, 2..7 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 1 +#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. + Both are started from a list of three configuration tables, of which only + the last, the System Control Block (SCB), is used after reset-time. The SCB + has the following fileds: + Status word + Command word + Tx/Command block addr. + Rx block addr. + The command word accepts the following controls for the Tx and Rx units: + */ + +#define CUC_START 0x0100 +#define CUC_RESUME 0x0200 +#define CUC_SUSPEND 0x0300 +#define RX_START 0x0010 +#define RX_RESUME 0x0020 +#define RX_SUSPEND 0x0030 + +/* 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; + ushort rx_head; + ushort rx_tail; + ushort tx_head; + ushort tx_cmd_link; + ushort tx_reap; +}; + +/* + Details of the EtherLink16 Implementation + The 3c507 is a generic shared-memory i82586 implementation. + The host can map 16K, 32K, 48K, or 64K of the 64K memory into + 0x0[CD][08]0000, or all 64K into 0xF[02468]0000. + */ + +/* Offsets from the base I/O address. */ +#define SA_DATA 0 /* Station address data, or 3Com signature. */ +#define MISC_CTRL 6 /* Switch the SA_DATA banks, and bus config bits. */ +#define RESET_IRQ 10 /* Reset the latched IRQ line. */ +#define SIGNAL_CA 11 /* Frob the 82586 Channel Attention line. */ +#define ROM_CONFIG 13 +#define MEM_CONFIG 14 +#define IRQ_CONFIG 15 + +/* The ID port is used at boot-time to locate the ethercard. */ +#define ID_PORT 0x100 + +/* Offsets to registers in the mailbox (SCB). */ +#define iSCB_STATUS 0x8 +#define iSCB_CMD 0xA +#define iSCB_CBL 0xC /* Command BLock offset. */ +#define iSCB_RFA 0xE /* 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. This is designed to be similar to the EtherExpress, + thus the unusual location of the SCB at 0x0008. + + 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 (1518+14+18) /* packet+header+RBD */ +#define RX_BUF_END (dev->mem_end - dev->mem_start) + +/* + 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. */ + 0, CmdMulticastList, IDLELOOP, 0, +}; + +/* Index to functions, as function prototypes. */ + +extern int el16_probe(struct device *dev); /* Called from Space.c */ + +static int el16_probe1(struct device *dev, short ioaddr); +static int el16_open(struct device *dev); +static int el16_send_packet(struct sk_buff *skb, struct device *dev); +static void el16_interrupt(int reg_ptr); +static void el16_rx(struct device *dev); +static int el16_close(struct device *dev); +static struct enet_statistics *el16_get_stats(struct device *dev); + +static void hardware_send_packet(struct device *dev, void *buf, short length); +void init_82586_mem(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 +el16_probe(struct device *dev) +{ + /* Don't probe all settable addresses, 0x[23][0-F]0, just common ones. */ + int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0}; + int base_addr = dev->base_addr; + ushort lrs_state = 0xff, i; + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return el16_probe1(dev, base_addr); + else if (base_addr > 0) + return ENXIO; /* Don't probe at all. */ + + /* Send the ID sequence to the ID_PORT to enable the board. */ + outb(0x00, ID_PORT); + for(i = 0; i < 255; i++) { + outb(lrs_state, ID_PORT); + lrs_state <<= 1; + if (lrs_state & 0x100) + lrs_state ^= 0xe7; + } + outb(0x00, ID_PORT); + + for (port = &ports[0]; *port; port++) { + short ioaddr = *port; +#if 0 + /* This is my original code. */ + if (inb(ioaddr) == '*' && inb(ioaddr+1) == '3' + && inb(ioaddr+2) == 'C' && inb(ioaddr+3) == 'O' + && el16_probe1(dev, *port) == 0) + return 0; +#else + /* This is code from jennings@Montrouge.SMR.slb.com, done so that + the string can be printed out. */ + char res[5]; + res[0] = inb(ioaddr); res[1] = inb(ioaddr+1); + res[2] = inb(ioaddr+2); res[3] = inb(ioaddr+3); + res[4] = 0; + if (res[0] == '*' && res[1] == '3' + && res[2] == 'C' && res[3] == 'O' + && el16_probe1(dev, *port) == 0) + return 0; +#endif + } + + return ENODEV; /* ENODEV would be more accurate. */ +} + +int el16_probe1(struct device *dev, short ioaddr) +{ + int i, irq, irqval; + + printk("%s: 3c507 at %#x,", dev->name, ioaddr); + + /* We should make a few more checks here, like the first three octets of + the S.A. for the manufactor's code. */ + + irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; + + irqval = request_irq(irq, &el16_interrupt); + if (irqval) { + printk ("unable to get IRQ %d (irqval=%d).\n", irq, irqval); + return EAGAIN; + } + + /* We've committed to using the board, and can start filling in *dev. */ + snarf_region(ioaddr, 16); + dev->base_addr = ioaddr; + + outb(0x01, ioaddr + MISC_CTRL); + for (i = 0; i < 6; i++) { + dev->dev_addr[i] = inb(ioaddr + i); + printk(" %02x", dev->dev_addr[i]); + } + + if ((dev->mem_start & 0xf) > 0) + net_debug = dev->mem_start & 7; + +#ifdef MEM_BASE + dev->mem_start = MEM_BASE; + dev->mem_end = dev->mem_start + 0x10000; +#else + { + int base; + int size; + char mem_config = inb(ioaddr + MEM_CONFIG); + if (mem_config & 0x20) { + size = 64*1024; + base = 0xf00000 + (mem_config & 0x08 ? 0x080000 + : ((mem_config & 3) << 17)); + } else { + size = ((mem_config & 3) + 1) << 14; + base = 0x0c0000 + ( (mem_config & 0x18) << 12); + } + if (size != 0x10000) + printk("%s: Warning, this version probably only works with 64K of" + "shared memory.\n", dev->name); + dev->mem_start = base; + dev->mem_end = base + size; + } +#endif + + dev->if_port = (inb(ioaddr + ROM_CONFIG) & 0x80) ? 1 : 0; + dev->irq = inb(ioaddr + IRQ_CONFIG) & 0x0f; + + printk(", IRQ %d, %sternal xcvr, memory %#x-%#x.\n", dev->irq, + dev->if_port ? "ex" : "in", dev->mem_start, dev->mem_end-1); + + 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 = el16_open; + dev->stop = el16_close; + dev->hard_start_xmit = el16_send_packet; + dev->get_stats = el16_get_stats; + + /* 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; +} + + + +static int +el16_open(struct device *dev) +{ + irq2dev_map[dev->irq] = dev; + + /* Initialize the 82586 memory and start it. */ + init_82586_mem(dev); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + return 0; +} + +static int +el16_send_packet(struct sk_buff *skb, struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + short *shmem = (short*)dev->mem_start; + + 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, + shmem[iSCB_STATUS>>1] & 0x8000 ? "IRQ conflict" : + "network cable problem"); + /* 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"); + shmem[iSCB_CMD>>1] = 0xf000|CUC_START|RX_START; + outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ + 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->data, 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 = skb->data; + + /* Disable the 82586's input to the interrupt line. */ + outb(0x80, ioaddr + MISC_CTRL); + hardware_send_packet(dev, buf, length); + dev->trans_start = jiffies; + /* Enable the 82586 interrupt input. */ + outb(0x84, ioaddr + MISC_CTRL); + } + + if (skb->free) + kfree_skb (skb, FREE_WRITE); + + /* You might need to clean up and record Tx statistics here. */ + + return 0; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static void +el16_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; + ushort ack_cmd = 0; + ushort *shmem; + + 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; + shmem = ((ushort*)dev->mem_start); + + status = shmem[iSCB_STATUS>>1]; + + if (net_debug > 4) { + printk("%s: 3c507 interrupt, status %4.4x.\n", dev->name, status); + } + + /* Disable the 82586's input to the interrupt line. */ + outb(0x80, ioaddr + MISC_CTRL); + + /* Reap the Tx packet buffers. */ + while (lp->tx_reap != lp->tx_head) { + unsigned short tx_status = shmem[lp->tx_reap>>1]; + + 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); + el16_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) { + static void init_rx_bufs(struct device *); + /* 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); + shmem[iSCB_RFA >> 1] = RX_BUF_START; + ack_cmd |= RX_START; + } + + shmem[iSCB_CMD>>1] = ack_cmd; + outb(0, ioaddr + SIGNAL_CA); /* Issue channel-attn. */ + + /* Clear the latched interrupt. */ + outb(0, ioaddr + RESET_IRQ); + + /* Enable the 82586's interrupt input. */ + outb(0x84, ioaddr + MISC_CTRL); + + return; +} + +static int +el16_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + ushort *shmem = (short*)dev->mem_start; + + dev->tbusy = 1; + dev->start = 0; + + /* Flush the Tx and disable Rx. */ + shmem[iSCB_CMD >> 1] = RX_SUSPEND | CUC_SUSPEND; + outb(0, ioaddr + SIGNAL_CA); + + /* Disable the 82586's input to the interrupt line. */ + outb(0x80, ioaddr + MISC_CTRL); + + /* We always physically use the IRQ line, so we don't do free_irq(). + We do remove ourselves from the map. */ + + 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 * +el16_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; +} + +/* Initialize the Rx-block list. */ +static void +init_rx_bufs(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + unsigned short *write_ptr; + + int cur_rxbuf = lp->rx_head = RX_BUF_START; + + /* Initialize each Rx frame + data buffer. */ + do { /* While there is room for one more. */ + + write_ptr = (unsigned short *)(dev->mem_start + cur_rxbuf); + + *write_ptr++ = 0x0000; /* Status */ + *write_ptr++ = 0x0000; /* Command */ + *write_ptr++ = cur_rxbuf + RX_BUF_SIZE; /* Link */ + *write_ptr++ = cur_rxbuf + 22; /* Buffer offset */ + *write_ptr++ = 0x0000; /* Pad for dest addr. */ + *write_ptr++ = 0x0000; + *write_ptr++ = 0x0000; + *write_ptr++ = 0x0000; /* Pad for source addr. */ + *write_ptr++ = 0x0000; + *write_ptr++ = 0x0000; + *write_ptr++ = 0x0000; /* Pad for protocol. */ + + *write_ptr++ = 0x0000; /* Buffer: Actual count */ + *write_ptr++ = -1; /* Buffer: Next (none). */ + *write_ptr++ = cur_rxbuf + 0x20; /* Buffer: Address low */ + *write_ptr++ = 0x0000; + /* Finally, the number of bytes in the buffer. */ + *write_ptr++ = 0x8000 + RX_BUF_SIZE-0x20; + + 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. */ + write_ptr = (unsigned short *) + (dev->mem_start + lp->rx_tail + 2); + *write_ptr++ = 0xC000; /* Command, mark as last. */ + *write_ptr++ = lp->rx_head; /* Link */ + +} + +void +init_82586_mem(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + short ioaddr = dev->base_addr; + ushort *shmem = (short*)dev->mem_start; + + /* Enable loopback to protect the wire while starting up, + and hold the 586 in reset during the memory initialization. */ + outb(0x20, ioaddr + MISC_CTRL); + + /* Write the words at 0xfff6 (address-aliased to 0xfffff6). */ +#ifdef old + memcpy((void*)dev->mem_start+0xfff6, init_words, 10); +#else + memcpy((void*)dev->mem_end-10, init_words, 10); +#endif + /* Write the words at 0x0000. */ + memcpy((char*)dev->mem_start, init_words + 5, sizeof(init_words) - 10); + + /* Fill in the station address. */ + memcpy((char*)dev->mem_start+SA_OFFSET, dev->dev_addr, + sizeof(dev->dev_addr)); + + /* The Tx-block list is written as needed. We just set up the values. */ + lp->tx_cmd_link = IDLELOOP + 4; + lp->tx_head = lp->tx_reap = TX_BUF_START; + + init_rx_bufs(dev); + + /* Start the 586 by releasing the reset line, but leave loopback. */ + outb(0xA0, ioaddr + MISC_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 (shmem[iSCB_STATUS>>1] == 0) + if (--boguscnt == 0) { + printk("%s: i82586 initialization timed out with status %04x," + "cmd %04x.\n", dev->name, + shmem[iSCB_STATUS>>1], shmem[iSCB_CMD>>1]); + break; + } + /* Issue channel-attn -- the 82586 won't start. */ + outb(0, ioaddr + SIGNAL_CA); + } + + /* Disable loopback and enable interrupts. */ + outb(0x84, ioaddr + MISC_CTRL); + if (net_debug > 4) + printk("%s: Initialized 82586, status %04x.\n", dev->name, + shmem[iSCB_STATUS>>1]); + return; +} + +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; + ushort tx_block = lp->tx_head; + ushort *write_ptr = (ushort *)(dev->mem_start + tx_block); + + /* Set the write pointer to the Tx block, and put out the header. */ + *write_ptr++ = 0x0000; /* Tx status */ + *write_ptr++ = CMD_INTR|CmdTx; /* Tx command */ + *write_ptr++ = tx_block+16; /* Next command is a NoOp. */ + *write_ptr++ = tx_block+8; /* Data Buffer offset. */ + + /* Output the data buffer descriptor. */ + *write_ptr++ = length | 0x8000; /* Byte count parameter. */ + *write_ptr++ = -1; /* No next data buffer. */ + *write_ptr++ = tx_block+22; /* Buffer follows the NoOp command. */ + *write_ptr++ = 0x0000; /* Buffer address high bits (always zero). */ + + /* Output the Loop-back NoOp command. */ + *write_ptr++ = 0x0000; /* Tx status */ + *write_ptr++ = CmdNOp; /* Tx command */ + *write_ptr++ = tx_block+16; /* Next is myself. */ + + /* Output the packet at the write pointer. */ + memcpy(write_ptr, buf, length); + + /* Set the old command link pointing to this send packet. */ + *(ushort*)(dev->mem_start + lp->tx_cmd_link) = tx_block; + 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: 3c507 @%x send length = %d, tx_block %3x, next %3x.\n", + dev->name, ioaddr, length, tx_block, lp->tx_head); + } + + if (lp->tx_head != lp->tx_reap) + dev->tbusy = 0; +} + +static void +el16_rx(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + short *shmem = (short*)dev->mem_start; + ushort rx_head = lp->rx_head; + ushort rx_tail = lp->rx_tail; + ushort boguscount = 10; + short frame_status; + + while ((frame_status = shmem[rx_head>>1]) < 0) { /* Command complete */ + ushort *read_frame = (short *)(dev->mem_start + rx_head); + ushort rfd_cmd = read_frame[1]; + ushort next_rx_frame = read_frame[2]; + ushort data_buffer_addr = read_frame[3]; + ushort *data_frame = (short *)(dev->mem_start + data_buffer_addr); + ushort pkt_len = data_frame[0]; + + 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; + + /* 'skb->data' points to the start of sk_buff data area. */ + memcpy(skb->data, data_frame + 5, 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 + lp->stats.rx_packets++; + } + + /* Clear the status word and set End-of-List on the rx frame. */ + read_frame[0] = 0; + read_frame[1] = 0xC000; + /* Clear the end-of-list on the prev. RFD. */ + *(short*)(dev->mem_start + rx_tail + 2) = 0x0000; + + rx_tail = rx_head; + rx_head = next_rx_frame; + if (--boguscount == 0) + break; + } + + lp->rx_head = rx_head; + lp->rx_tail = rx_tail; +} + +/* + * 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 3c507.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c509.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c509.c new file mode 100644 index 000000000..7e18ce779 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/3c509.c @@ -0,0 +1,692 @@ +/* 3c509.c: A 3c509 EtherLink3 ethernet driver for linux. */ +/* + Written 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 is for the 3Com EtherLinkIII series. + + The author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 +*/ + +static char *version = "3c509.c:pl13t 11/24/93 becker@super.org\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.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) +#endif + + +#ifdef EL3_DEBUG +int el3_debug = EL3_DEBUG; +#else +int el3_debug = 2; +#endif + +/* To minimize the size of the driver source I only define operating + constants if they are used several times. You'll need the manual + if you want to understand driver details. */ +/* Offsets from base I/O address. */ +#define EL3_DATA 0x00 +#define EL3_CMD 0x0e +#define EL3_STATUS 0x0e +#define ID_PORT 0x100 +#define EEPROM_READ 0x80 + +#define EL3WINDOW(win_num) outw(0x0800+(win_num), ioaddr + EL3_CMD) + +/* Register window 1 offsets, the window used in normal operation. */ +#define TX_FIFO 0x00 +#define RX_FIFO 0x00 +#define RX_STATUS 0x08 +#define TX_STATUS 0x0B +#define TX_FREE 0x0C /* Remaining free bytes in Tx buffer. */ + +#define WN4_MEDIA 0x0A /* Window 4: Various transceiver/media bits. */ +#define MEDIA_TP 0x00C0 /* Enable link beat and jabber for 10baseT. */ + +struct el3_private { + struct enet_statistics stats; +}; + +static ushort id_read_eeprom(int index); +static ushort read_eeprom(short ioaddr, int index); +static int el3_open(struct device *dev); +static int el3_start_xmit(struct sk_buff *skb, struct device *dev); +static void el3_interrupt(int reg_ptr); +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 + + + +int el3_probe(struct device *dev) +{ + short lrs_state = 0xff, i; + ushort ioaddr, irq, if_port; + short *phys_addr = (short *)dev->dev_addr; + static int current_tag = 0; + + /* First check for a board on the EISA bus. */ + if (EISA_bus) { + for (ioaddr = 0x1000; ioaddr < 0x9000; ioaddr += 0x1000) { + if (inw(ioaddr) != 0x6d50) + continue; + + irq = inw(ioaddr + 8) >> 12; + if_port = inw(ioaddr + 6)>>14; + for (i = 0; i < 3; i++) + phys_addr[i] = htons(read_eeprom(ioaddr, i)); + + /* Restore the "Manufacturer ID" to the EEPROM read register. */ + /* The manual says to restore "Product ID" (reg. 3). !???! */ + read_eeprom(ioaddr, 7); + + /* Was the EISA code an add-on hack? Nahhhhh... */ + goto found; + } + } + +#ifdef CONFIG_MCA + if (MCA_bus) { + mca_adaptor_select_mode(1); + for (i = 0; i < 8; i++) + if ((mca_adaptor_id(i) | 1) == 0x627c) { + ioaddr = mca_pos_base_addr(i); + irq = inw(ioaddr + 8) >> 12; + if_port = inw(ioaddr + 6)>>14; + for (i = 0; i < 3; i++) + phys_addr[i] = htons(read_eeprom(ioaddr, i)); + + mca_adaptor_select_mode(0); + goto found; + } + mca_adaptor_select_mode(0); + + } +#endif + + /* Send the ID sequence to the ID_PORT. */ + outb(0x00, ID_PORT); + outb(0x00, ID_PORT); + for(i = 0; i < 255; i++) { + outb(lrs_state, ID_PORT); + lrs_state <<= 1; + lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; + } + + /* For the first probe, clear all board's tag registers. */ + if (current_tag == 0) + outb(0xd0, ID_PORT); + else /* Otherwise kill off already-found boards. */ + outb(0xd8, ID_PORT); + + if (id_read_eeprom(7) != 0x6d50) { + return -ENODEV; + } + + /* Read in EEPROM data, which does contention-select. + Only the lowest address board will stay "on-line". + 3Com got the byte order backwards. */ + for (i = 0; i < 3; i++) { + phys_addr[i] = htons(id_read_eeprom(i)); + } + + { + unsigned short iobase = id_read_eeprom(8); + if_port = iobase >> 14; + ioaddr = 0x200 + ((iobase & 0x1f) << 4); + } + irq = id_read_eeprom(9) >> 12; + + /* The current Space.c structure makes it difficult to have more + than one adaptor initialized. Send me email if you have a need for + multiple adaptors, and we'll work out something. -becker@super.org */ + if (dev->base_addr != 0 + && dev->base_addr != (unsigned short)ioaddr) { + return -ENODEV; + } + + /* Set the adaptor tag so that the next card can be found. */ + outb(0xd0 + ++current_tag, ID_PORT); + + /* Activate the adaptor at the EEPROM location. */ + outb(0xff, ID_PORT); + + EL3WINDOW(0); + if (inw(ioaddr) != 0x6d50) + return -ENODEV; + + found: + dev->base_addr = ioaddr; + dev->irq = irq; + dev->if_port = if_port; + snarf_region(dev->base_addr, 16); + + { + char *if_names[] = {"10baseT", "AUI", "undefined", "BNC"}; + printk("%s: 3c509 at %#3.3x tag %d, %s port, address ", + dev->name, dev->base_addr, current_tag, if_names[dev->if_port]); + } + + /* Read in the station address. */ + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i]); + printk(", IRQ %d.\n", dev->irq); + + /* Make up a EL3-specific-data structure. */ + dev->priv = kmalloc(sizeof(struct el3_private), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct el3_private)); + + if (el3_debug > 0) + printk(version); + + /* The EL3-specific entries in the device structure. */ + dev->open = &el3_open; + 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 fields 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; +} + +/* Read a word from the EEPROM using the regular EEPROM access register. + Assume that we are in register window zero. + */ +static ushort read_eeprom(short ioaddr, int index) +{ + int timer; + + outw(EEPROM_READ + index, ioaddr + 10); + /* Pause for at least 162 us. for the read to take place. */ + for (timer = 0; timer < 162*4 + 400; timer++) + SLOW_DOWN_IO; + return inw(ioaddr + 12); +} + +/* Read a word from the EEPROM when in the ISA ID probe state. */ +static ushort id_read_eeprom(int index) +{ + int timer, bit, word = 0; + + /* Issue read command, and pause for at least 162 us. for it to complete. + Assume extra-fast 16Mhz bus. */ + outb(EEPROM_READ + index, ID_PORT); + + /* This should really be done by looking at one of the timer channels. */ + for (timer = 0; timer < 162*4 + 400; timer++) + SLOW_DOWN_IO; + + for (bit = 15; bit >= 0; bit--) + word = (word << 1) + (inb(ID_PORT) & 0x01); + + if (el3_debug > 3) + printk(" 3c509 EEPROM word %d %#4.4x.\n", index, word); + + return word; +} + + + +static int +el3_open(struct device *dev) +{ + int ioaddr = dev->base_addr; + int i; + + if (request_irq(dev->irq, &el3_interrupt)) { + return -EAGAIN; + } + + EL3WINDOW(0); + if (el3_debug > 3) + printk("%s: Opening, IRQ %d status@%x %4.4x.\n", dev->name, + dev->irq, ioaddr + EL3_STATUS, inw(ioaddr + EL3_STATUS)); + + /* Activate board: this is probably unnecessary. */ + outw(0x0001, ioaddr + 4); + + irq2dev_map[dev->irq] = dev; + + /* Set the IRQ line. */ + outw((dev->irq << 12) | 0x0f00, ioaddr + 8); + + /* Set the station address in window 2 each time opened. */ + EL3WINDOW(2); + + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + i); + + if (dev->if_port == 3) + /* Start the thinnet transceiver. We should really wait 50ms...*/ + outw(0x1000, ioaddr + EL3_CMD); + else if (dev->if_port == 0) { + /* 10baseT interface, enabled link beat and jabber check. */ + EL3WINDOW(4); + outw(inw(ioaddr + WN4_MEDIA) | MEDIA_TP, ioaddr + WN4_MEDIA); + } + + /* Switch to register set 1 for normal use. */ + EL3WINDOW(1); + + outw(0x8005, ioaddr + EL3_CMD); /* Accept b-case and phys addr only. */ + outw(0xA800, ioaddr + EL3_CMD); /* Turn on statistics. */ + outw(0x2000, ioaddr + EL3_CMD); /* Enable the receiver. */ + outw(0x4800, ioaddr + EL3_CMD); /* Enable transmitter. */ + outw(0x78ff, ioaddr + EL3_CMD); /* Allow all status bits to be seen. */ + dev->interrupt = 0; + dev->tbusy = 0; + dev->start = 1; + outw(0x7098, ioaddr + EL3_CMD); /* Set interrupt mask. */ + + if (el3_debug > 3) + printk("%s: Opened 3c509 IRQ %d status %4.4x.\n", + dev->name, dev->irq, inw(ioaddr + EL3_STATUS)); + + return 0; /* Always succeed */ +} + +static int +el3_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + int ioaddr = dev->base_addr; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 10) + return 1; + printk("%s: transmit timed out, tx_status %2.2x status %4.4x.\n", + dev->name, inb(ioaddr + TX_STATUS), inw(ioaddr + EL3_STATUS)); + dev->trans_start = jiffies; + /* Issue TX_RESET and TX_START commands. */ + outw(0x5800, ioaddr + EL3_CMD); /* TX_RESET */ + outw(0x4800, ioaddr + EL3_CMD); /* TX_START */ + dev->tbusy = 0; + } + + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* Fill in the ethernet header. */ + if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + skb->arp=1; + + if (skb->len <= 0) + return 0; + + if (el3_debug > 4) { + printk("%s: el3_start_xmit(lenght = %d) called, status %4.4x.\n", + dev->name, skb->len, inw(ioaddr + EL3_STATUS)); + } +#ifndef final_version + { /* Error-checking code, delete for 1.00. */ + ushort status = inw(ioaddr + EL3_STATUS); + if (status & 0x0001 /* IRQ line active, missed one. */ + && inw(ioaddr + EL3_STATUS) & 1) { /* Make sure. */ + printk("%s: Missed interrupt, status then %04x now %04x" + " Tx %2.2x Rx %4.4x.\n", dev->name, status, + inw(ioaddr + EL3_STATUS), inb(ioaddr + TX_STATUS), + inw(ioaddr + RX_STATUS)); + outw(0x7800, ioaddr + EL3_CMD); /* Fake interrupt trigger. */ + outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */ + outw(0x78ff, ioaddr + EL3_CMD); /* Set all status bits visible. */ + } + } +#endif + + /* Avoid timer-based retransmission conflicts. */ + 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. */ + outsl(ioaddr + TX_FIFO, skb->data, (skb->len + 3) >> 2); + + 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); + + /* Clear the Tx status stack. */ + { + short tx_status; + int i = 4; + + while (--i > 0 && (tx_status = inb(ioaddr + TX_STATUS)) > 0) { + if (el3_debug > 5) + printk(" Tx status %4.4x.\n", tx_status); + if (tx_status & 0x38) lp->stats.tx_aborted_errors++; + if (tx_status & 0x30) outw(0x5800, ioaddr + EL3_CMD); + if (tx_status & 0x3C) outw(0x4800, ioaddr + EL3_CMD); + outb(0x00, ioaddr + TX_STATUS); /* Pop the status stack. */ + } + } + return 0; +} + +/* The EL3 interrupt handler. */ +static void +el3_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = (struct device *)(irq2dev_map[irq]); + int ioaddr, status; + int i = 0; + + if (dev == NULL) { + printk ("el3_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + dev->interrupt = 1; + + ioaddr = dev->base_addr; + status = inw(ioaddr + EL3_STATUS); + + if (el3_debug > 4) + printk("%s: interrupt, status %4.4x.\n", dev->name, status); + + while ((status = inw(ioaddr + EL3_STATUS)) & 0x01) { + + if (status & 0x10) + el3_rx(dev); + + if (status & 0x08) { + if (el3_debug > 5) + printk(" TX room bit was handled.\n"); + /* There's room in the FIFO for a full-sized packet. */ + outw(0x6808, ioaddr + EL3_CMD); /* Ack IRQ */ + dev->tbusy = 0; + mark_bh(INET_BH); + } + if (status & 0x80) /* Statistics full. */ + update_stats(ioaddr, dev); + + if (++i > 10) { + printk("%s: Infinite loop in interrupt, status %4.4x.\n", + dev->name, status); + break; + } + /* Clear the other interrupts we have handled. */ + outw(0x6899, ioaddr + EL3_CMD); /* Ack IRQ */ + } + + if (el3_debug > 4) { + printk("%s: exiting interrupt, status %4.4x.\n", dev->name, + inw(ioaddr + EL3_STATUS)); + } + + dev->interrupt = 0; + return; +} + + +static struct enet_statistics * +el3_get_stats(struct device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + + sti(); + update_stats(dev->base_addr, dev); + cli(); + return &lp->stats; +} + +/* Update statistics. We change to register window 6, so this should be run + single-threaded if the device is active. This is expected to be a rare + operation, and it's simpler for the rest of the driver to assume that + window 1 is always valid rather than use a special window-state variable. + */ +static void update_stats(int ioaddr, struct device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + + if (el3_debug > 5) + printk(" Updating the statistics.\n"); + /* Turn off statistics updates while reading. */ + outw(0xB000, ioaddr + EL3_CMD); + /* Switch to the stats window, and read everything. */ + EL3WINDOW(6); + lp->stats.tx_carrier_errors += inb(ioaddr + 0); + lp->stats.tx_heartbeat_errors += inb(ioaddr + 1); + /* Multiple collisions. */ inb(ioaddr + 2); + lp->stats.collisions += inb(ioaddr + 3); + lp->stats.tx_window_errors += inb(ioaddr + 4); + lp->stats.rx_fifo_errors += inb(ioaddr + 5); + lp->stats.tx_packets += inb(ioaddr + 6); + lp->stats.rx_packets += inb(ioaddr + 7); + /* Tx deferrals */ inb(ioaddr + 8); + inw(ioaddr + 10); /* Total Rx and Tx octets. */ + inw(ioaddr + 12); + + /* Back to window 1, and turn statistics back on. */ + EL3WINDOW(1); + outw(0xA800, ioaddr + EL3_CMD); + return; +} + +static int +el3_rx(struct device *dev) +{ + struct el3_private *lp = (struct el3_private *)dev->priv; + int ioaddr = dev->base_addr; + short rx_status; + + if (el3_debug > 5) + printk(" In rx_packet(), status %4.4x, rx_status %4.4x.\n", + inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS)); + while ((rx_status = inw(ioaddr + RX_STATUS)) > 0) { + if (rx_status & 0x4000) { /* Error, update stats. */ + short error = rx_status & 0x3C00; + lp->stats.rx_errors++; + switch (error) { + case 0x2000: lp->stats.rx_over_errors++; break; + case 0x2C00: lp->stats.rx_length_errors++; break; + case 0x3400: lp->stats.rx_crc_errors++; break; + case 0x2400: lp->stats.rx_length_errors++; break; + case 0x3000: lp->stats.rx_frame_errors++; break; + case 0x0800: lp->stats.rx_frame_errors++; break; + } + } + if ( (! (rx_status & 0x4000)) + || ! (rx_status & 0x2000)) { /* Dribble bits are OK. */ + short pkt_len = rx_status & 0x7ff; + int sksize = sizeof(struct sk_buff) + pkt_len + 3; + struct sk_buff *skb; + + skb = alloc_skb(sksize, GFP_ATOMIC); + if (el3_debug > 4) + printk(" Receiving packet size %d status %4.4x.\n", + pkt_len, rx_status); + if (skb != NULL) { + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + + /* 'skb->data' points to the start of sk_buff data area. */ + insl(ioaddr+RX_FIFO, skb->data, + (pkt_len + 3) >> 2); + +#ifdef HAVE_NETIF_RX + netif_rx(skb); + outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */ + continue; +#else + skb->lock = 0; + if (dev_rint((unsigned char *)skb, pkt_len, + IN_SKBUFF,dev)== 0){ + if (el3_debug > 6) + printk(" dev_rint() happy, status %4.4x.\n", + inb(ioaddr + EL3_STATUS)); + outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */ + while (inw(ioaddr + EL3_STATUS) & 0x1000) + printk(" Waiting for 3c509 to discard packet, status %x.\n", + inw(ioaddr + EL3_STATUS) ); + if (el3_debug > 6) + printk(" discarded packet, status %4.4x.\n", + inb(ioaddr + EL3_STATUS)); + continue; + } else { + printk("%s: receive buffers full.\n", dev->name); + kfree_s(skb, sksize); + } +#endif + } else if (el3_debug) + printk("%s: Couldn't allocate a sk_buff of size %d.\n", + dev->name, sksize); + } + lp->stats.rx_dropped++; + outw(0x4000, ioaddr + EL3_CMD); /* Rx discard */ + while (inw(ioaddr + EL3_STATUS) & 0x1000) + printk(" Waiting for 3c509 to discard packet, status %x.\n", + inw(ioaddr + EL3_STATUS) ); + } + + if (el3_debug > 5) + printk(" Exiting rx_packet(), status %4.4x, rx_status %4.4x.\n", + inw(ioaddr+EL3_STATUS), inw(ioaddr+8)); + + 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) +{ + int ioaddr = dev->base_addr; + + if (el3_debug > 2) + printk("%s: Shutting down ethercard.\n", dev->name); + + dev->tbusy = 1; + dev->start = 0; + + /* Turn off statistics. We update lp->stats below. */ + outw(0xB000, ioaddr + EL3_CMD); + + /* Disable the receiver and transmitter. */ + outw(0x1800, ioaddr + EL3_CMD); + outw(0x5000, ioaddr + EL3_CMD); + + if (dev->if_port == 3) + /* Turn off thinnet power. */ + outw(0xb800, ioaddr + EL3_CMD); + else if (dev->if_port == 0) { + /* Disable link beat and jabber, if_port may change ere next open(). */ + EL3WINDOW(4); + outw(inw(ioaddr + WN4_MEDIA) & ~MEDIA_TP, ioaddr + WN4_MEDIA); + } + + free_irq(dev->irq); + /* Switching back to window 0 disables the IRQ. */ + EL3WINDOW(0); + /* But we explicitly zero the IRQ line select anyway. */ + outw(0x0f00, ioaddr + 8); + + + irq2dev_map[dev->irq] = 0; + + update_stats(ioaddr, dev); + return 0; +} + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c 3c509.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.c new file mode 100644 index 000000000..9c896cc59 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.c @@ -0,0 +1,756 @@ +/* 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 + +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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->data, 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, skb->data, 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, skb->data, + 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->data' points to the start of sk_buff data area. */ + ei_block_input(dev, pkt_len, (char *) skb->data, + 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.h new file mode 100644 index 000000000..08e763eb6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/8390.h @@ -0,0 +1,159 @@ +/* Generic NS8390 register definitions. */ +/* This file is part of Donald Becker's 8390 drivers, and is distributed + under the same license. + Some of these names and comments originated from the Crynwr + packet drivers, which are distributed under the GPL. */ + +#ifndef _8390_h +#define _8390_h + +#include +#include + +#define TX_2X_PAGES 12 +#define TX_1X_PAGES 6 +#define TX_PAGES (ei_status.pingpong ? TX_2X_PAGES : TX_1X_PAGES) + +#define ETHER_ADDR_LEN 6 + +/* From 8390.c */ +extern int ei_debug; +extern struct sigaction ei_sigaction; + +extern int ethif_init(struct device *dev); +extern int ethdev_init(struct device *dev); +extern void NS8390_init(struct device *dev, int startp); +extern int ei_open(struct device *dev); +extern void ei_interrupt(int reg_ptr); + +#ifndef HAVE_AUTOIRQ +/* From auto_irq.c */ +extern struct device *irq2dev_map[16]; +extern void autoirq_setup(int waittime); +extern int autoirq_report(int waittime); +#endif + +/* Most of these entries should be in 'struct device' (or most of the + things in there should be here!) */ +/* You have one of these per-board */ +struct ei_device { + char *name; + void (*reset_8390)(struct device *); + void (*block_output)(struct device *, int, const unsigned char *, int); + int (*block_input)(struct device *, int, char *, int); + int open:1; + int word16:1; /* We have the 16-bit (vs 8-bit) version of the card. */ + int txing:1; /* Transmit Active */ + int dmaing:2; /* Remote DMA Active */ + int irqlock:1; /* 8390's intrs disabled when '1'. */ + int pingpong:1; /* Using the ping-pong driver */ + unsigned char tx_start_page, rx_start_page, stop_page; + unsigned char current_page; /* Read pointer in buffer */ + unsigned char interface_num; /* Net port (AUI, 10bT.) to use. */ + unsigned char txqueue; /* Tx Packet buffer queue length. */ + unsigned char in_interrupt; + short tx1, tx2; /* Packet lengths for ping-pong tx. */ + short lasttx; /* Alpha version consistency check. */ + unsigned char reg0; /* Register '0' in a WD8013 */ + unsigned char reg5; /* Register '5' in a WD8013 */ + unsigned char saved_irq; /* Original dev->irq value. */ + /* The new statistics table. */ + struct enet_statistics stat; +}; + +#define ei_status (*(struct ei_device *)(dev->priv)) + +/* Some generic ethernet register configurations. */ +#define E8390_TX_IRQ_MASK 0xa /* For register EN0_ISR */ +#define E8390_RX_IRQ_MASK 0x5 +#define E8390_RXCONFIG 0x4 /* EN0_RXCR: broadcasts, no multicast,errors */ +#define E8390_RXOFF 0x20 /* EN0_RXCR: Accept no packets */ +#define E8390_TXCONFIG 0x00 /* EN0_TXCR: Normal transmit mode */ +#define E8390_TXOFF 0x02 /* EN0_TXCR: Transmitter off */ + +/* Register accessed at EN_CMD, the 8390 base addr. */ +#define E8390_STOP 0x01 /* Stop and reset the chip */ +#define E8390_START 0x02 /* Start the chip, clear reset */ +#define E8390_TRANS 0x04 /* Transmit a frame */ +#define E8390_RREAD 0x08 /* Remote read */ +#define E8390_RWRITE 0x10 /* Remote write */ +#define E8390_NODMA 0x20 /* Remote DMA */ +#define E8390_PAGE0 0x00 /* Select page chip registers */ +#define E8390_PAGE1 0x40 /* using the two high-order bits */ +#define E8390_PAGE2 0x80 /* Page 3 is invalid. */ + +#define E8390_CMD 0x00 /* The command register (for all pages) */ +/* Page 0 register offsets. */ +#define EN0_CLDALO 0x01 /* Low byte of current local dma addr RD */ +#define EN0_STARTPG 0x01 /* Starting page of ring bfr WR */ +#define EN0_CLDAHI 0x02 /* High byte of current local dma addr RD */ +#define EN0_STOPPG 0x02 /* Ending page +1 of ring bfr WR */ +#define EN0_BOUNDARY 0x03 /* Boundary page of ring bfr RD WR */ +#define EN0_TSR 0x04 /* Transmit status reg RD */ +#define EN0_TPSR 0x04 /* Transmit starting page WR */ +#define EN0_NCR 0x05 /* Number of collision reg RD */ +#define EN0_TCNTLO 0x05 /* Low byte of tx byte count WR */ +#define EN0_FIFO 0x06 /* FIFO RD */ +#define EN0_TCNTHI 0x06 /* High byte of tx byte count WR */ +#define EN0_ISR 0x07 /* Interrupt status reg RD WR */ +#define EN0_CRDALO 0x08 /* low byte of current remote dma address RD */ +#define EN0_RSARLO 0x08 /* Remote start address reg 0 */ +#define EN0_CRDAHI 0x09 /* high byte, current remote dma address RD */ +#define EN0_RSARHI 0x09 /* Remote start address reg 1 */ +#define EN0_RCNTLO 0x0a /* Remote byte count reg WR */ +#define EN0_RCNTHI 0x0b /* Remote byte count reg WR */ +#define EN0_RSR 0x0c /* rx status reg RD */ +#define EN0_RXCR 0x0c /* RX configuration reg WR */ +#define EN0_TXCR 0x0d /* TX configuration reg WR */ +#define EN0_COUNTER0 0x0d /* Rcv alignment error counter RD */ +#define EN0_DCFG 0x0e /* Data configuration reg WR */ +#define EN0_COUNTER1 0x0e /* Rcv CRC error counter RD */ +#define EN0_IMR 0x0f /* Interrupt mask reg WR */ +#define EN0_COUNTER2 0x0f /* Rcv missed frame error counter RD */ + +/* Bits in EN0_ISR - Interrupt status register */ +#define ENISR_RX 0x01 /* Receiver, no error */ +#define ENISR_TX 0x02 /* Transmitter, no error */ +#define ENISR_RX_ERR 0x04 /* Receiver, with error */ +#define ENISR_TX_ERR 0x08 /* Transmitter, with error */ +#define ENISR_OVER 0x10 /* Receiver overwrote the ring */ +#define ENISR_COUNTERS 0x20 /* Counters need emptying */ +#define ENISR_RDC 0x40 /* remote dma complete */ +#define ENISR_RESET 0x80 /* Reset completed */ +#define ENISR_ALL 0x3f /* Interrupts we will enable */ + +/* Bits in EN0_DCFG - Data config register */ +#define ENDCFG_WTS 0x01 /* word transfer mode selection */ + +/* Page 1 register offsets. */ +#define EN1_PHYS 0x01 /* This board's physical enet addr RD WR */ +#define EN1_CURPAG 0x07 /* Current memory page RD WR */ +#define EN1_MULT 0x08 /* Multicast filter mask array (8 bytes) RD WR */ + +/* Bits in received packet status byte and EN0_RSR*/ +#define ENRSR_RXOK 0x01 /* Received a good packet */ +#define ENRSR_CRC 0x02 /* CRC error */ +#define ENRSR_FAE 0x04 /* frame alignment error */ +#define ENRSR_FO 0x08 /* FIFO overrun */ +#define ENRSR_MPA 0x10 /* missed pkt */ +#define ENRSR_PHY 0x20 /* physical/multicase address */ +#define ENRSR_DIS 0x40 /* receiver disable. set in monitor mode */ +#define ENRSR_DEF 0x80 /* deferring */ + +/* Transmitted packet status, EN0_TSR. */ +#define ENTSR_PTX 0x01 /* Packet transmitted without error */ +#define ENTSR_ND 0x02 /* The transmit wasn't deferred. */ +#define ENTSR_COL 0x04 /* The transmit collided at least once. */ +#define ENTSR_ABT 0x08 /* The transmit collided 16 times, and was deferred. */ +#define ENTSR_CRS 0x10 /* The carrier sense was lost. */ +#define ENTSR_FU 0x20 /* A "FIFO underrun" occured during transmit. */ +#define ENTSR_CDH 0x40 /* The collision detect "heartbeat" signal was lost. */ +#define ENTSR_OWC 0x80 /* There was an out-of-window collision. */ + +/* The per-packet-header format. */ +struct e8390_pkt_hdr { + unsigned char status; /* status */ + unsigned char next; /* pointer to next packet. */ + unsigned short count; /* header + packet lenght in bytes */ +}; +#endif /* _8390_h */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/CONFIG b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/CONFIG new file mode 100644 index 000000000..cb9bbed35 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/CONFIG @@ -0,0 +1,55 @@ +# +# This file is used for selecting non-standard netcard options, and +# need not be modified for typical use. +# +# Drivers are *not* selected in this file, but rather with files +# automatically generated during the top-level kernel configuration. +# +# Special options supported, indexed by their 'config' name: +# +# CONFIG_WD80x3 The Western Digital (SMC) WD80x3 driver +# WD_SHMEM=xxx Forces the address of the shared memory +# WD_no_mapout Don't map out the shared memory (faster, but +# your machine may not warm-boot). +# CONFIG_NE2000 The NE-[12]000 clone driver. +# PACKETBUF_MEMSIZE Allows an extra-large packet buffer to be +# used. Usually pointless under Linux. +# show_all_SAPROM Show the entire address PROM, not just the +# ethernet address, during boot. +# rw_bugfix Patch an obscure bug with a version of the 8390. +# CONFIG_HPLAN The HP-LAN driver (for 8390-based boards only). +# rw_bugfix Fix the same obscure bug. +# CONFIG_EL2 The 3c503 EtherLink II driver +# EL2_AUI Default to the AUI port instead of the BNC port +# no_probe_nonshared_memory Don't probe for programmed-I/O boards. +# EL2MEMTEST Test shared memory at boot-time. +# CONFIG_PLIP The Crynwr-protocol PL/IP driver +# INITIALTIMEOUTFACTOR Timing parameters. +# MAXTIMEOUTFACTOR +# D_LINK The D-Link DE-600 Portable Ethernet Adaptor. +# D_LINK_IO The D-Link I/O address (0x378 == typical) +# D_LINK_IRQ The D-Link IRQ number to use (IRQ7 == typical) +# D_LINK_DEBUG Enable or disable D-Link debugging +# + +# The following options exist, but cannot be set in this file. +# lance.c +# LANCE_DMA Change the default DMA to other than DMA5. +# 8390.c +# NO_PINGPONG Disable ping-pong transmit buffers. + + +# Most drivers also have a *_DEBUG setting that may be adjusted. +# The 8390 drivers share the EI_DEBUG settting. + +# General options for Space.c +OPTS = # -DETH0_ADDR=0x300 -DETH0_IRQ=11 + +WD_OPTS = #-DWD_SHMEM=0xDD000 +EL2_OPTS = #-DEL2_AUI +NE_OPTS = +HP_OPTS = +PLIP_OPTS = + +# The following are the only parameters that must be set in this file. +DL_OPTS = -DD_LINK_IO=0x378 -DD_LINK_IRQ=7 -UD_LINK_DEBUG diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/LICENSE.SRC b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/LICENSE.SRC new file mode 100644 index 000000000..500940a6a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/LICENSE.SRC @@ -0,0 +1,15 @@ +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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Makefile new file mode 100644 index 000000000..51c1c8d9e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Makefile @@ -0,0 +1,150 @@ +# File: drivers/net/Makefile +# +# Makefile for the Linux network (ethercard) device drivers. +# + +# This will go away in some future future: hidden configuration files +# are difficult for users to deal with. +include CONFIG + +NETDRV_OBJS := net.a(Space.o) net.a(auto_irq.o) net.a(net_init.o) +CFLAGS := $(CFLAGS) -I../../net/inet +CPP := $(CPP) -I../../net/inet + +# The point of the makefile... +all: net.a + +Space.o: Space.c ../../include/linux/autoconf.h + $(CC) $(CFLAGS) $(OPTS) $(DL_OPTS) -c $< -o $@ + +net_init.o: ../../include/linux/autoconf.h + +ifdef CONFIG_WD80x3 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(wd.o) +CONFIG_8390 = CONFIG_8390 +wd.o: wd.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(WD_OPTS) -c $< +endif + +ifdef CONFIG_EL2 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c503.o) +CONFIG_8390 = CONFIG_8390 +3c503.o: 3c503.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(EL2_OPTS) -c $< +endif + +ifdef CONFIG_NE2000 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(ne.o) +CONFIG_8390 = CONFIG_8390 +ne.o: ne.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(NE_OPTS) -c $< +endif + +ifdef CONFIG_HPLAN +NETDRV_OBJS := $(NETDRV_OBJS) net.a(hp.o) +CONFIG_8390 = CONFIG_8390 +hp.o: hp.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(HP_OPTS) -c $< +endif + +ifdef CONFIG_ULTRA +NETDRV_OBJS := $(NETDRV_OBJS) net.a(smc-ultra.o) +CONFIG_8390 = CONFIG_8390 +endif + +ifdef CONFIG_E2100 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(e2100.o) +CONFIG_8390 = CONFIG_8390 +endif + +ifdef CONFIG_PLIP +NETDRV_OBJS := $(NETDRV_OBJS) net.a(plip.o) +plip.o: plip.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(PLIP_OPTS) -c $< +endif + +ifdef CONFIG_PPP +NETDRV_OBJS := $(NETDRV_OBJS) net.a(ppp.o) net.a(slhc.o) +endif + +ifdef CONFIG_SLIP +NETDRV_OBJS := $(NETDRV_OBJS) net.a(slip.o) net.a(slhc.o) +slip.o: slip.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) -c $< +endif + +ifdef CONFIG_DE600 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(d_link.o) +d_link.o: d_link.c CONFIG + $(CC) $(CPPFLAGS) $(CFLAGS) $(DL_OPTS) -c $< +endif + +ifdef CONFIG_AT1500 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(lance.o) +endif +ifdef CONFIG_LANCE +NETDRV_OBJS := $(NETDRV_OBJS) net.a(lance.o) +endif +ifdef CONFIG_AT1700 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(at1700.o) +endif +ifdef CONFIG_EL1 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c501.o) +endif +ifdef CONFIG_EL16 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c507.o) +endif +ifdef CONFIG_EL3 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c509.o) +endif +ifdef CONFIG_EEXPRESS +NETDRV_OBJS := $(NETDRV_OBJS) net.a(eexpress.o) +endif +ifdef CONFIG_ZNET +NETDRV_OBJS := $(NETDRV_OBJS) net.a(znet.o) +endif +ifdef CONFIG_DEPCA +NETDRV_OBJS := $(NETDRV_OBJS) net.a(depca.o) +endif +ifdef CONFIG_ATP +NETDRV_OBJS := $(NETDRV_OBJS) net.a(atp.o) +endif +ifdef CONFIG_NI52 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(ni52.o) +endif +ifdef CONFIG_NI65 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(ni65.o) +endif +ifdef CONFIG_ELPLUS +NETDRV_OBJS := $(NETDRV_OBJS) net.a(3c505.o) +endif +ifdef CONFIG_AC3200 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(ac3200.o) +CONFIG_8390 = CONFIG_8390 +endif + +ifdef CONFIG_8390 +NETDRV_OBJS := $(NETDRV_OBJS) net.a(8390.o) +endif + +ifdef CONFIG_IP_DEFRAG +NETDRV_OBJS := $(NETDRV_OBJS) net.a(ip-frag.o) +endif + +net.a: $(NETDRV_OBJS) + ranlib net.a + +clean: + rm -f core *.o *.a *.s + +dep: + $(CPP) -M *.c > .depend + +tar: + + +# include a dependency file if one exists + +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README.DLINK b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README.DLINK new file mode 100644 index 000000000..192d4bd6d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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 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 + . + 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README1.PLIP b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README1.PLIP new file mode 100644 index 000000000..d68745b4a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README1.PLIP @@ -0,0 +1,113 @@ +\title{PLIP: The Parallel Line Internet Protocol Device} + +\author{ Donald Becker (becker@super.org)} +\affiliation{I.D.A. Supercomputing Research Center, Bowie MD 20715} + +%% At some point T. Thorn will probably contribute text, +%% \author{ Tommy Thorn (tthorn@daimi.aau.dk)} + +\section{PLIP Introduction} +This document describes the parallel port packet pusher for Net/LGX. +This device interface allows a point-to-point connection between two +parallel ports to appear as a IP network interface. + +\chapter{PLIP hardware interconnection} +PLIP uses several different data transfer methods. The first (and the +only one implemented in the early version of the code) uses a standard +printer "null" cable to transfers data four bits at a time using +data bit outputs connected to status bit inputs. + +The second data transfer method relies on both machines having +bi-directional parallel ports, rather than output-only ``printer'' +ports. This allows byte-wide transfers and avoids reconstructing +nibbles into bytes, leading to much faster transfers. + +\section{Parallel Transfer Mode 0 Cable} +The cable for the first transfer mode is a standard +printer "null" cable which transfers data four bits at a time using +data bit outputs of the first port (machine T) connected to the +status bit inputs of the second port (machine R). There are five +status inputs, and they are used as four data inputs and a clock (data +strobe) input, arranged so that the data input bits appear as contiguous +bits with standard status register implementation. + +A cable that implements this protocol is available commercially as a +"Null Printer" or "Turbo Laplink" cable. It can be constructed with +two DB-25 male connectors symmetrically connected as follows: + + STROBE output 1* + D0->ERROR 2 - 15 15 - 2 + D1->SLCT 3 - 13 13 - 3 + D2->PAPOUT 4 - 12 12 - 4 + D3->ACK 5 - 10 10 - 5 + D4->BUSY 6 - 11 11 - 6 + D5,D6,D7 are 7*, 8*, 9* + AUTOFD output 14* + INIT output 16* + SLCTIN 17 - 17 + extra grounds are 18*,19*,20*,21*,22*,23*,24* + GROUND 25 - 25 +* Do not connect these pins on either end + +If the cable you are using has a metallic shield it should be +connected to the metallic DB-25 shell at one end only. + +\section{Parallel Transfer Mode 1} +The second data transfer method relies on both machines having +bi-directional parallel ports, rather than output-only ``printer'' +ports. This allows byte-wide transfers, and avoids reconstructing +nibbles into bytes. This cable should not be used on unidirectional +``printer'' (as opposed to ``parallel'') ports or when the machine +isn't configured for PLIP, as it will result in output driver +conflicts and the (unlikely) possibility of damage. + +The cable for this tranfer mode should be constructed as follows: + + STROBE->BUSY 1 - 11 + D0->D0 2 - 2 + D1->D1 3 - 3 + D2->D2 4 - 4 + D3->D3 5 - 5 + D4->D4 6 - 6 + D5->D5 7 - 7 + D6->D6 8 - 8 + D7->D7 9 - 9 + INIT -> ACK 16 - 10 + AUTOFD->PAPOUT 14 - 12 + SLCT->SLCTIN 13 - 17 + GND->ERROR 18 - 15 + extra grounds are 19*,20*,21*,22*,23*,24* + GROUND 25 - 25 +* Do not connect these pins on either end + +Once again, if the cable you are using has a metallic shield it should +be connected to the metallic DB-25 shell at one end only. + +\section{PLIP Mode 0 tranfer protocol} +The PLIP driver is compatible with the "Crynwr" parallel port transfer +standard in Mode 0. That standard specifies the following protocol: + + send header nibble '8' + count-low octet + count-high octet + ... data octets + checksum octet + +Each octet is sent as + + >4)&0x0F)> + +To start a transfer the transmitting machine outputs a nibble 0x08. +The raises the ACK line, triggering an interrupt in the receiving +machine. The receiving machine disables + +Restated: + +(OUT is bit 0-4, OUT.j is bit j from OUT. IN likewise) +Send_Byte: + OUT := low nibble, OUT.4 := 1 + WAIT FOR IN.4 = 1 + OUT := high nibble, OUT.4 := 0 + WAIT FOR IN.4 = 0 + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README2.PLIP b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README2.PLIP new file mode 100644 index 000000000..63b4754bf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/README2.PLIP @@ -0,0 +1,78 @@ + +(2nd attempt. 1st bounced.) +Hi again + +About my previous mail: I've looked into parallel.asm, and I'm +rather confused. Looks like the code agrees with you, but not +the protocol description preceeding it?? I got to look more +careful, but it wont be for a while (approx a week). + +>From plip.c (v0.04): + +>make one yourself. The wiring is: +> INIT 16 - 16 SLCTIN 17 - 17 +> GROUND 25 - 25 +> D0->ERROR 2 - 15 15 - 2 + +I saw you removed 1 and 14 from the cable description, but not +16 and 17. Why is that? + +Have been succesful in getting parallel.com working (the Messy-Loss +software). Using the pksend on the sender and pkall/pkwatch/whatnot +gives me a hung receiver. (The cable works, I've tried unet11, a DOS +cheap-net prog.) + +Using PLIP v0.03 and trying to ping the other end gives + 88 timeout 88 timeout....(more) 2386 bogous packet size, dropped +on the receiver, and on the sender lots of timeout, but of +course I don't know how much is supposed to work. + +The following to something I wrote when I should have gone to bed a +long time ago. Use it for whatever you like, or dump it in the bin. ;^) + +/Tommy +----- +Becker [& Co] provdly presents PLIP + +What is PLIP? +============= + +PLIP is Parallel Line IP, that is, the transportation of IP packages +over a parallel port. In the case of a PC, the obvious choice is the +printer port. PLIP is a non-standard, but [can use] uses the standard +LapLink null-printer cable [can also work in turbo mode, with a PLIP +cable]. [The protocol used to pack IP packages, is a simple one +initiated by Crynwr.] + +Advantages of PLIP +================== + +It's cheap, it's availble everywhere, and it's easy. + +The PLIP cable is all that's needed to connect two Linux boxes, and it +can be build for very bucks. + +Connecting two Linux boxes takes only a seconds decision and a few +minutes work, no need to search for a [supported] netcard. This might +even be especially important in the case of notebooks, where netcard +are not easily availble. + +Not requiring a netcard also means that apart from connecting the +cables, everything else is software configuration [which in principle +could be made very easy.] + +Disadvantages of PLIP +===================== + +Doesn't work over a modem, like SLIP and PPP. Limited range, 15 m. +Can only be used to connect three (?) Linux boxes. Doesn't connect to +an exiting ethernet. Isn't standard (not even de facto standard, like +SLIP). + +Performens +========== + +PLIP easily outperforms ethernet cards....(ups, I was dreaming, but +it *is* getting late. EOB) + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Space.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Space.c new file mode 100644 index 000000000..6cc4cf6b1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/Space.c @@ -0,0 +1,267 @@ +/* + * 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. + * + * Holds initial configuration information for devices. + * + * NOTE: This file is a nice idea, but its current format does not work + * well for drivers that support multiple units, like the SLIP + * driver. We should actually have only one pointer to a driver + * here, with the driver knowing how many units it supports. + * Currently, the SLIP driver abuses the "base_addr" integer + * field of the 'device' structure to store the unit number... + * -FvK + * + * Version: @(#)Space.c 1.0.7 08/12/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Donald J. Becker, + * + * 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 +#include +#include "dev.h" + +#define LOOPBACK /* always present, right? */ + +#define NEXT_DEV NULL + + +/* A unifed ethernet device probe. This is the easiest way to have every + 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); +extern int hp_probe(struct device *dev); +extern int znet_probe(struct device *); +extern int express_probe(struct device *); +extern int el3_probe(struct device *); +extern int at1500_probe(struct device *); +extern int at1700_probe(struct device *); +extern int depca_probe(struct device *); +extern int el1_probe(struct device *); +extern int el16_probe(struct device *); +extern int elplus_probe(struct device *); +extern int ac3200_probe(struct device *); +extern int e2100_probe(struct device *); + +/* Detachable devices ("pocket adaptors" and special PCMCIA drivers). */ +extern int atp_init(struct device *); +extern int d_link_init(struct device *); + +static int +ethif_probe(struct device *dev) +{ + short base_addr = dev->base_addr; + + if (base_addr < 0 || base_addr == 1) + return 1; /* ENXIO */ + + if (1 +#if defined(CONFIG_ULTRA) + && ultra_probe(dev) +#endif +#if defined(CONFIG_WD80x3) || defined(WD80x3) + && wd_probe(dev) +#endif +#if defined(CONFIG_EL2) || defined(EL2) /* 3c503 */ + && el2_probe(dev) +#endif +#if defined(CONFIG_NE2000) || defined(NE2000) + && ne_probe(dev) +#endif +#if defined(CONFIG_HPLAN) || defined(HPLAN) + && hp_probe(dev) +#endif +#ifdef CONFIG_AT1500 + && at1500_probe(dev) +#endif +#ifdef CONFIG_AT1700 + && at1700_probe(dev) +#endif +#ifdef CONFIG_EL3 /* 3c509 */ + && el3_probe(dev) +#endif +#ifdef CONFIG_ZNET /* Zenith Z-Note and some IBM Thinkpads. */ + && znet_probe(dev) +#endif +#ifdef CONFIG_EEXPRESS /* Intel EtherExpress */ + && express_probe(dev) +#endif +#ifdef CONFIG_DEPCA /* DEC DEPCA */ + && depca_probe(dev) +#endif +#ifdef CONFIG_EL1 /* 3c501 */ + && el1_probe(dev) +#endif +#ifdef CONFIG_EL16 /* 3c507 */ + && el16_probe(dev) +#endif +#ifdef CONFIG_ELPLUS /* 3c505 */ + && elplus_probe(dev) +#endif +#ifdef CONFIG_AC3200 /* Ansel Communications EISA 3200. */ + && ac3200_probe(dev) +#endif +#ifdef CONFIG_E2100 /* Cabletron E21xx series. */ + && e2100_probe(dev) +#endif + && 1 ) { + return 1; /* -ENODEV or -EAGAIN would be more accurate. */ + } + return 0; +} + + +/* This remains seperate because it requires the addr and IRQ to be set. */ +#if defined(D_LINK) || defined(CONFIG_DE600) +static struct device d_link_dev = { + "dl0", 0, 0, 0, 0, D_LINK_IO, D_LINK_IRQ, 0, 0, 0, NEXT_DEV, d_link_init }; +# undef NEXT_DEV +# define NEXT_DEV (&d_link_dev) +#endif + +/* Run-time ATtachable (Pocket) devices have a different (not "eth#") name. */ +#ifdef CONFIG_ATP /* AT-LAN-TEC (RealTek) pocket adaptor. */ +static struct device atp_dev = { + "atp0", 0, 0, 0, 0, 0, 0, 0, 0, 0, NEXT_DEV, atp_init, /* ... */ }; +# undef NEXT_DEV +# define NEXT_DEV (&atp_dev) +#endif + +/* The first device defaults to I/O base '0', which means autoprobe. */ +#ifdef EI8390 +# define ETH0_ADDR EI8390 +#else +# define ETH0_ADDR 0 +#endif +#ifdef EI8390_IRQ +# define ETH0_IRQ EI8390_IRQ +#else +# define ETH0_IRQ 0 +#endif +/* "eth0" defaults to autoprobe, other use a base of "-0x20", "don't probe". + Enable these with boot-time setup. 0.99pl13+ can optionally autoprobe. */ + +static struct device eth3_dev = { + "eth3", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, NEXT_DEV, ethif_probe }; +static struct device eth2_dev = { + "eth2", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð3_dev, ethif_probe }; +static struct device eth1_dev = { + "eth1", 0,0,0,0,0xffe0 /* I/O base*/, 0,0,0,0, ð2_dev, ethif_probe }; + +static struct device eth0_dev = { + "eth0", 0, 0, 0, 0, ETH0_ADDR, ETH0_IRQ, 0, 0, 0, ð1_dev, ethif_probe }; + +# undef NEXT_DEV +# define NEXT_DEV (ð0_dev) + +#if defined(PLIP) || defined(CONFIG_PLIP) + extern int plip_init(struct device *); + static struct device plip2_dev = { + "plip2", 0, 0, 0, 0, 0x278, 2, 0, 0, 0, NEXT_DEV, plip_init, }; + static struct device plip1_dev = { + "plip1", 0, 0, 0, 0, 0x378, 7, 0, 0, 0, &plip2_dev, plip_init, }; + static struct device plip0_dev = { + "plip0", 0, 0, 0, 0, 0x3BC, 5, 0, 0, 0, &plip1_dev, plip_init, }; +# undef NEXT_DEV +# define NEXT_DEV (&plip0_dev) +#endif /* PLIP */ + +#if defined(SLIP) || defined(CONFIG_SLIP) + extern int slip_init(struct device *); + static struct device slip3_dev = { + "sl3", /* Internal SLIP driver, channel 3 */ + 0x0, /* recv memory end */ + 0x0, /* recv memory start */ + 0x0, /* memory end */ + 0x0, /* memory start */ + 0x3, /* base I/O address */ + 0, /* IRQ */ + 0, 0, 0, /* flags */ + NEXT_DEV, /* next device */ + slip_init /* slip_init should set up the rest */ + }; + static struct device slip2_dev = { + "sl2", /* Internal SLIP driver, channel 2 */ + 0x0, /* recv memory end */ + 0x0, /* recv memory start */ + 0x0, /* memory end */ + 0x0, /* memory start */ + 0x2, /* base I/O address */ + 0, /* IRQ */ + 0, 0, 0, /* flags */ + &slip3_dev, /* next device */ + slip_init /* slip_init should set up the rest */ + }; + static struct device slip1_dev = { + "sl1", /* Internal SLIP driver, channel 1 */ + 0x0, /* recv memory end */ + 0x0, /* recv memory start */ + 0x0, /* memory end */ + 0x0, /* memory start */ + 0x1, /* base I/O address */ + 0, /* IRQ */ + 0, 0, 0, /* flags */ + &slip2_dev, /* next device */ + slip_init /* slip_init should set up the rest */ + }; + static struct device slip0_dev = { + "sl0", /* Internal SLIP driver, channel 0 */ + 0x0, /* recv memory end */ + 0x0, /* recv memory start */ + 0x0, /* memory end */ + 0x0, /* memory start */ + 0x0, /* base I/O address */ + 0, /* IRQ */ + 0, 0, 0, /* flags */ + &slip1_dev, /* next device */ + slip_init /* slip_init should set up the rest */ + }; +# undef NEXT_DEV +# define NEXT_DEV (&slip0_dev) +#endif /* SLIP */ + +#if defined(CONFIG_PPP) +extern int ppp_init(struct device *); +static struct device ppp3_dev = { + "ppp3", 0x0, 0x0, 0x0, 0x0, 3, 0, 0, 0, 0, NEXT_DEV, ppp_init, }; +static struct device ppp2_dev = { + "ppp2", 0x0, 0x0, 0x0, 0x0, 2, 0, 0, 0, 0, &ppp3_dev, ppp_init, }; +static struct device ppp1_dev = { + "ppp1", 0x0, 0x0, 0x0, 0x0, 1, 0, 0, 0, 0, &ppp2_dev, ppp_init, }; +static struct device ppp0_dev = { + "ppp0", 0x0, 0x0, 0x0, 0x0, 0, 0, 0, 0, 0, &ppp1_dev, ppp_init, }; +#undef NEXT_DEV +#define NEXT_DEV (&ppp0_dev) +#endif /* PPP */ + +#ifdef LOOPBACK + extern int loopback_init(struct device *dev); + static struct device loopback_dev = { + "lo", /* Software Loopback interface */ + 0x0, /* recv memory end */ + 0x0, /* recv memory start */ + 0x0, /* memory end */ + 0x0, /* memory start */ + 0, /* base I/O address */ + 0, /* IRQ */ + 0, 0, 0, /* flags */ + NEXT_DEV, /* next device */ + loopback_init /* loopback_init should set up the rest */ + }; +# undef NEXT_DEV +# define NEXT_DEV (&loopback_dev) +#endif + + +struct device *dev_base = NEXT_DEV; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/at1700.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/at1700.c new file mode 100644 index 000000000..cfc5922d7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/at1700.c @@ -0,0 +1,660 @@ +/* at1700.c: A network device driver for the Allied Telesis AT1700. + + Written 1993 by Donald Becker. This is a alpha test limited release. + This version may only be used and distributed according to the terms of the + GNU Public License, incorporated 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 is a device driver for the Allied Telesis AT1700, which is a + straight-foward Fujitsu MB86965 implementation. +*/ + +static char *version = + "at1700.c:v0.03 11/16/93 Donald Becker (becker@super.org)\n"; + +#include + +/* + Sources: + The Fujitsu MB86695 datasheet. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.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(addr, size) kfree_s(addr,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; + +typedef unsigned char uchar; + +/* Information that need to be kept for each board. */ +struct net_local { + struct enet_statistics stats; + long open_time; /* Useless example local info. */ + uint tx_started:1; /* Number of packet on the Tx queue. */ + uchar tx_queue; /* Number of packet on the Tx queue. */ + ushort tx_queue_len; /* Current length of the Tx queue. */ +}; + + +/* Offsets from the base address. */ +#define STATUS 0 +#define TX_STATUS 0 +#define RX_STATUS 1 +#define TX_INTR 2 /* Bit-mapped interrupt enable registers. */ +#define RX_INTR 3 +#define TX_MODE 4 +#define RX_MODE 5 +#define CONFIG_0 6 /* Misc. configuration settings. */ +#define CONFIG_1 7 +/* Run-time register bank 2 definitions. */ +#define DATAPORT 8 /* Word-wide DMA or programmed-I/O dataport. */ +#define TX_START 10 +#define MODE13 13 +#define EEPROM_Ctrl 16 +#define EEPROM_Data 17 + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x40 /* EEPROM shift clock, in reg. 16. */ +#define EE_CS 0x20 /* EEPROM chip select, in reg. 16. */ +#define EE_DATA_WRITE 0x80 /* EEPROM chip data in, in reg. 17. */ +#define EE_DATA_READ 0x80 /* EEPROM chip data out, in reg. 17. */ + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay() do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD (5 << 6) +#define EE_READ_CMD (6 << 6) +#define EE_ERASE_CMD (7 << 6) + + +/* Index to functions, as function prototypes. */ + +extern int at1700_probe(struct device *dev); + +static int at1700_probe1(struct device *dev, short ioaddr); +static int read_eeprom(int ioaddr, int location); +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 + + +/* 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 +at1700_probe(struct device *dev) +{ + short ports[] = {0x300, 0x280, 0x380, 0x320, 0x340, 0x260, 0x2a0, 0x240, 0}; + short *port, base_addr = dev->base_addr; + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return at1700_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, 32)) + continue; +#endif + if (inw(ioaddr) != 0x0000) + continue; + if (at1700_probe1(dev, ioaddr) == 0) + return 0; + } + + return ENODEV; /* ENODEV would be more accurate. */ +} + +int at1700_probe1(struct device *dev, short ioaddr) +{ + unsigned short signature[4] = {0x0000, 0xffff, 0x41f6, 0xefb6}; + unsigned short signature_invalid[4] = {0x0000, 0xffff, 0x00f0, 0x2f00}; + char irqmap[4] = {3, 4, 5, 9}; + unsigned short *station_address = (unsigned short *)dev->dev_addr; + unsigned int i, irq; + + /* Resetting the chip doesn't reset the ISA interface, so don't bother. + That means we have to be careful with the register values we probe for. + */ + for (i = 0; i < 4; i++) + if ((inw(ioaddr + 2*i) | signature_invalid[i]) != signature[i]) { + if (net_debug > 1) + printk("AT1700 signature match failed at %d (%04x vs. %04x)\n", + i, inw(ioaddr + 2*i), signature[i]); + return -ENODEV; + } +#ifdef HAVE_PORTRESERVE + /* Grab the region so that we can find another board if the IRQ request + fails. */ + snarf_region(ioaddr, 32); +#endif + + irq = irqmap[ read_eeprom(ioaddr, 0) >> 14 ]; + + /* Snarf the interrupt vector now. */ + if (request_irq(irq, &net_interrupt)) { + printk ("AT1700 found at %#3x, but it's unusable due to a conflict on" + "IRQ %d.\n", ioaddr, irq); + return EAGAIN; + } + + printk("%s: AT1700 found at %#3x, IRQ %d, address ", dev->name, + ioaddr, irq); + + dev->base_addr = ioaddr; + dev->irq = irq; + irq2dev_map[irq] = dev; + + for(i = 0; i < 3; i++) { + unsigned short eeprom_val = read_eeprom(ioaddr, 4+i); + printk("%04x", eeprom_val); + station_address[i] = ntohs(eeprom_val); + } + + /* The EEPROM word 12 bit 0x0400 means use regular 100 ohm 10baseT signals, + rather than 150 ohm shielded twisted pair compansation. + 0x0000 == auto-sense the interface + 0x0800 == use TP interface + 0x1800 == use coax interface + */ + { + char *porttype[] = {"auto-sense", "10baseT", "auto-sense", "10base2"}; + ushort setup_value = read_eeprom(ioaddr, 12); + + dev->if_port = setup_value >> 8; + printk(" %s interface (%04x).\n", porttype[(dev->if_port>>3) & 3], + setup_value); + } + + /* Set the station address in bank zero. */ + outb(0xe0, ioaddr + 7); + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + 8 + i); + + /* Switch to bank 1 and set the multicast table to accept none. */ + outb(0xe4, ioaddr + 7); + for (i = 0; i < 8; i++) + outb(0x00, ioaddr + 8 + i); + + /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit + bus access, two 4K Tx queues, and disabled Tx and Rx. */ + outb(0xda, ioaddr + CONFIG_0); + + /* Switch to bank 2 and lock our I/O address. */ + outb(0xe8, ioaddr + 7); + outb(dev->if_port, MODE13); + + /* Power-down the chip. Aren't we green! */ + outb(0x00, ioaddr + CONFIG_1); + + 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; +} + +static int read_eeprom(int ioaddr, int location) +{ + int i; + unsigned short retval = 0; + short ee_addr = ioaddr + EEPROM_Ctrl; + short ee_daddr = ioaddr + EEPROM_Data; + int read_cmd = location | EE_READ_CMD; + short ctrl_val = EE_CS; + + outb(ctrl_val, ee_addr); + + /* Shift the read command bits out. */ + for (i = 9; i >= 0; i--) { + short dataval = (read_cmd & (1 << i)) ? EE_DATA_WRITE : 0; + outb(dataval, ee_daddr); + outb(EE_CS | EE_SHIFT_CLK, ee_addr); /* EEPROM clock tick. */ + eeprom_delay(); + outb(EE_CS, ee_addr); /* Finish EEPROM a clock tick. */ + eeprom_delay(); + } + outb(EE_CS, ee_addr); + + for (i = 16; i > 0; i--) { + outb(EE_CS | EE_SHIFT_CLK, ee_addr); + eeprom_delay(); + retval = (retval << 1) | ((inb(ee_daddr) & EE_DATA_READ) ? 1 : 0); + outb(EE_CS, 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 int net_open(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int i; + + /* Powerup the chip, initialize config register 1, and select bank 0. */ + outb(0xe0, ioaddr + CONFIG_1); + + /* Set the station address in bank zero. */ + for (i = 0; i < 6; i++) + outb(dev->dev_addr[i], ioaddr + 8 + i); + + /* Switch to bank 1 and set the multicast table to accept none. */ + outb(0xe4, ioaddr + 7); + for (i = 0; i < 8; i++) + outb(0x00, ioaddr + 8 + i); + + /* Set the configuration register 0 to 32K 100ns. byte-wide memory, 16 bit + bus access, and two 4K Tx queues. */ + outb(0xda, ioaddr + CONFIG_0); + + /* Same config 0, except enable the Rx and Tx. */ + outb(0x5a, ioaddr + CONFIG_0); + /* Switch to register bank 2 for the run-time registers. */ + outb(0xe8, ioaddr + CONFIG_1); + + /* Turn on Rx interrupts, leave Tx interrupts off until packet Tx. */ + outb(0x00, ioaddr + TX_INTR); + outb(0x81, ioaddr + RX_INTR); + + 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 < 10) + return 1; + printk("%s: transmit timed out with status %04x, %s?\n", dev->name, + inw(ioaddr + STATUS), inb(ioaddr + TX_STATUS) & 0x80 + ? "IRQ conflict" : "network cable problem"); + printk("%s: timeout registers: %04x %04x %04x %04x %04x %04x %04x %04x.\n", + dev->name, inw(ioaddr + 0), inw(ioaddr + 2), inw(ioaddr + 4), + inw(ioaddr + 6), inw(ioaddr + 8), inw(ioaddr + 10), + inw(ioaddr + 12), inw(ioaddr + 14)); + lp->stats.tx_errors++; + /* ToDo: We should try to restart the adaptor... */ + outw(0xffff, ioaddr + 24); + outw(0xffff, ioaddr + TX_STATUS); + outw(0xe85a, ioaddr + CONFIG_0); + outw(0x8100, ioaddr + TX_INTR); + 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->data, 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 = skb->data; + + if (net_debug > 4) + printk("%s: Transmitting a packet of length %d.\n", dev->name, + skb->len); + + /* Turn off the possible Tx interrupts. */ + outb(0x00, ioaddr + TX_INTR); + + outw(length, ioaddr + DATAPORT); + outsw(ioaddr + DATAPORT, buf, (length + 1) >> 1); + + lp->tx_queue++; + lp->tx_queue_len += length + 2; + + if (lp->tx_started == 0) { + /* If the Tx is idle, always trigger a transmit. */ + outb(0x80 | lp->tx_queue, ioaddr + TX_START); + lp->tx_queue = 0; + lp->tx_queue_len = 0; + dev->trans_start = jiffies; + lp->tx_started = 1; + } else if (lp->tx_queue_len < 4096 - 1502) /* Room for one more packet? */ + dev->tbusy = 0; + + /* Turn on Tx interrupts back on. */ + outb(0x82, ioaddr + TX_INTR); + } + 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 = (struct device *)(irq2dev_map[irq]); + struct net_local *lp; + int ioaddr, status; + + if (dev == NULL) { + printk ("at1700_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 + TX_STATUS); + outw(status, ioaddr + TX_STATUS); + + if (net_debug > 4) + printk("%s: Interrupt with status %04x.\n", dev->name, status); + if (status & 0xff00 + || (inb(ioaddr + RX_MODE) & 0x40) == 0) { /* Got a packet(s). */ + net_rx(dev); + } + if (status & 0x00ff) { + if (status & 0x80) { + lp->stats.tx_packets++; + if (lp->tx_queue) { + outb(0x80 | lp->tx_queue, ioaddr + TX_START); + lp->tx_queue = 0; + lp->tx_queue_len = 0; + dev->trans_start = jiffies; + dev->tbusy = 0; + mark_bh(INET_BH); /* Inform upper layers. */ + } else { + lp->tx_started = 0; + /* Turn on Tx interrupts off. */ + outb(0x00, ioaddr + TX_INTR); + dev->tbusy = 0; + } + } + } + + 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 = 5; + + while ((inb(ioaddr + RX_MODE) & 0x40) == 0) { + ushort status = inw(ioaddr + DATAPORT); + + if (net_debug > 4) + printk("%s: Rxing packet mode %02x status %04x.\n", + dev->name, inb(ioaddr + RX_MODE), status); +#ifndef final_version + if (status == 0) { + outb(0x05, ioaddr + 14); + break; + } +#endif + + if ((status & 0xF0) != 0x20) { /* There was an error. */ + lp->stats.rx_errors++; + if (status & 0x08) lp->stats.rx_length_errors++; + if (status & 0x04) lp->stats.rx_frame_errors++; + if (status & 0x02) lp->stats.rx_crc_errors++; + if (status & 0x01) lp->stats.rx_over_errors++; + } else { + ushort pkt_len = inw(ioaddr + DATAPORT); + /* Malloc up new buffer. */ + int sksize = sizeof(struct sk_buff) + pkt_len; + struct sk_buff *skb; + + if (pkt_len > 1550) { + printk("%s: The AT1700 claimed a very large packet, size %d.\n", + dev->name, pkt_len); + outb(0x05, ioaddr + 14); + lp->stats.rx_errors++; + break; + } + skb = alloc_skb(sksize, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet (len %d).\n", + dev->name, pkt_len); + outb(0x05, ioaddr + 14); + lp->stats.rx_dropped++; + break; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + + /* 'skb->data' points to the start of sk_buff data area. */ + insw(ioaddr + DATAPORT, skb->data, (pkt_len + 1) >> 1); + + if (net_debug > 5) { + int i; + printk("%s: Rxed packet of length %d: ", dev->name, pkt_len); + for (i = 0; i < 14; i++) + printk(" %02x", skb->data[i]); + printk(".\n"); + } + +#ifdef HAVE_NETIF_RX + netif_rx(skb); +#else + skb->lock = 0; + if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { + kfree_s(skb, sksize); + lp->stats.rx_dropped++; + break; + } +#endif + lp->stats.rx_packets++; + } + if (--boguscount <= 0) + break; + } + + /* 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. */ + { + int i; + for (i = 0; i < 20; i++) { + if ((inb(ioaddr + RX_MODE) & 0x40) == 0x40) + break; + outb(0x05, ioaddr + 14); + } + + if (net_debug > 5) + printk("%s: Exint Rx packet with mode %02x after %d ticks.\n", + dev->name, inb(ioaddr + RX_MODE), i); + } + 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; + + /* Set configuration register 0 to disable Tx and Rx. */ + outb(0xda, ioaddr + CONFIG_0); + + /* Update the statistics -- ToDo. */ + + /* Power-down the chip. Green, green, green! */ + outb(0x00, ioaddr + CONFIG_1); + + 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; + + cli(); + /* ToDo: Update the statistics from the device registers. */ + 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(3, ioaddr + RX_MODE); /* Enable promiscuous mode */ + } else + outw(2, ioaddr + RX_MODE); /* Disable promiscuous, use normal mode */ +} +#endif + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c at1700.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.c new file mode 100644 index 000000000..d86dc8223 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.c @@ -0,0 +1,795 @@ +/* atp.c: Attached (pocket) ethernet adaptor 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 + +*/ + +static char *version = + "atp.c:v0.03 1/19/94 Donald Becker (becker@super.org)\n"; + +/* + This file is a device driver for the RealTek (aka AT-Lan-Tec) pocket + ethernet adaptor. This is a common low-cost OEM pocket ethernet + adaptor, sold under many names. + + Sources: + This driver was written from the packet driver assembly code provided by + Vincent Bono of AT-Lan-Tec. Ever try to figure out how a complicated + device works just from the assembly code? It ain't pretty. The following + description is written based on guesses and writing lots of special-purpose + code to test my theorized operation. + + Theory of Operation + + The RTL8002 adaptor seems to be built around a custom spin of the SEEQ + controller core. It probably has a 16K or 64K internal packet buffer, of + which the first 4K is devoted to transmit and the rest to receive. + The controller maintains the queue of received packet and the packet buffer + access pointer internally, with only 'reset to beginning' and 'skip to next + packet' commands visible. The transmit packet queue holds two (or more?) + packets: both 'retransmit this packet' (due to collision) and 'transmit next + packet' commands must be started by hand. + + The station address is stored in a standard bit-serial EEPROM which must be + read (ughh) by the device driver. (Provisions have been made for + substituting a 74S288 PROM, but I haven't gotten reports of any models + using it.) Unlike built-in devices, a pocket adaptor can temporarily lose + power without indication to the device driver. The major effect is that + the station address, receive filter (promiscuous, etc.) and transceiver + must be reset. + + The controller itself has 16 registers, some of which use only the lower + bits. The registers are read and written 4 bits at a time. The four bit + register address is presented on the data lines along with a few additional + timing and control bits. The data is then read from status port or written + to the data port. + + Since the bulk data transfer of the actual packets through the slow + parallel port dominates the driver's running time, four distinct data + (non-register) transfer modes are provided by the adaptor, two in each + direction. In the first mode timing for the nibble transfers is + provided through the data port. In the second mode the same timing is + provided through the control port. In either case the data is read from + the status port and written to the data port, just as it is accessing + registers. + + In addition to the basic data transfer methods, several more are modes are + created by adding some delay by doing multiple reads of the data to allow + it to stabilize. This delay seems to be needed on most machines. + + The data transfer mode is stored in the 'dev->if_port' field. Its default + value is '4'. It may be overriden at boot-time using the third parameter + to the "ether=..." initialization. + + The header file provides inline functions that encapsulate the + register and data access methods. These functions are hand-tuned to + generate reasonable object code. This header file also documents my + interpretations of the device registers. +*/ + +#include /* Used only to override default values. */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "eth.h" +#include "skbuff.h" +#include "arp.h" + +#include "atp.h" + +/* Compatibility definitions for earlier kernel versions. */ +#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(addr, size) kfree_s(addr,size); +#endif + +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#endif + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 4 +#endif +static unsigned int net_debug = NET_DEBUG; + +/* The number of low I/O ports used by the ethercard. */ +#define ETHERCARD_TOTAL_SIZE 3 + +/* Index to functions, as function prototypes. */ + +extern int atp_probe(struct device *dev); + +static int atp_probe1(struct device *dev, short ioaddr); +static void init_dev(struct device *dev); +static void get_node_ID(struct device *dev); +static unsigned short eeprom_op(short ioaddr, unsigned int cmd); +static int net_open(struct device *dev); +static void hardware_init(struct device *dev); +static void write_packet(short ioaddr, int length, unsigned char *packet, int mode); +static void trigger_send(short ioaddr, int length); +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 void read_block(short ioaddr, int length, unsigned char *buffer, int data_mode); +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 + + +/* 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 +atp_init(struct device *dev) +{ + int *port, ports[] = {0x378, 0x278, 0x3bc, 0}; + int base_addr = dev->base_addr; + + if (base_addr > 0x1ff) /* Check a single specified location. */ + return atp_probe1(dev, base_addr); + else if (base_addr == 1) /* Don't probe at all. */ + return ENXIO; + + for (port = ports; *port; port++) { + int ioaddr = *port; + outb(0x57, ioaddr + PAR_DATA); + if (inb(ioaddr + PAR_DATA) != 0x57) + continue; + if (atp_probe1(dev, ioaddr) == 0) + return 0; + } + + return ENODEV; +} + +static int atp_probe1(struct device *dev, short ioaddr) +{ + int saved_ctrl_reg, status; + + outb(0xff, ioaddr + PAR_DATA); + /* Save the original value of the Control register, in case we guessed + wrong. */ + saved_ctrl_reg = inb(ioaddr + PAR_CONTROL); + /* IRQEN=0, SLCTB=high INITB=high, AUTOFDB=high, STBB=high. */ + outb(0x04, ioaddr + PAR_CONTROL); + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + eeprom_delay(2048); + status = read_nibble(ioaddr, CMR1); + + if ((status & 0x78) != 0x08) { + /* The pocket adaptor probe failed, restore the control register. */ + outb(saved_ctrl_reg, ioaddr + PAR_CONTROL); + return 1; + } + status = read_nibble(ioaddr, CMR2_h); + if ((status & 0x78) != 0x10) { + outb(saved_ctrl_reg, ioaddr + PAR_CONTROL); + return 1; + } + /* Find the IRQ used by triggering an interrupt. */ + write_reg_byte(ioaddr, CMR2, 0x01); /* No accept mode, IRQ out. */ + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); /* Enable Tx and Rx. */ + + /* Omit autoIRQ routine for now. Use "table lookup" instead. Uhgggh. */ + if (ioaddr == 0x378) + dev->irq = 7; + else + dev->irq = 5; + write_reg_high(ioaddr, CMR1, CMR1h_TxRxOFF); /* Diable Tx and Rx units. */ + write_reg(ioaddr, CMR2, CMR2_NULL); + + dev->base_addr = ioaddr; + + /* Read the station address PROM. */ + get_node_ID(dev); + + printk("%s: Pocket adaptor found at %#3x, IRQ %d, SAPROM " + "%02X:%02X:%02X:%02X:%02X:%02X.\n", dev->name, dev->base_addr, + dev->irq, dev->dev_addr[0], dev->dev_addr[1], dev->dev_addr[2], + dev->dev_addr[3], dev->dev_addr[4], dev->dev_addr[5]); + + /* Leave the hardware in a reset state. */ + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + + if (net_debug) + printk(version); + + /* Initialize the device structure. */ + init_dev(dev); + dev->priv = kmalloc(sizeof(struct net_local), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct net_local)); + + + { + struct net_local *lp = (struct net_local *)dev->priv; + lp->addr_mode = CMR2h_Normal; + } + + /* For the ATP adaptor the "if_port" is really the data transfer mode. */ + dev->if_port = (dev->mem_start & 0xf) ? dev->mem_start & 0x7 : 4; + if (dev->mem_end & 0xf) + net_debug = dev->mem_end & 7; + + 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 + + return 0; +} + +/* Fill in the fields of the device structure with ethernet-generic values. + This should be in a common file instead of per-driver. */ +static void init_dev(struct device *dev) +{ + int i; + + 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); +} + +/* Read the station address PROM, usually a word-wide EEPROM. */ +static void get_node_ID(struct device *dev) +{ + short ioaddr = dev->base_addr; + int sa_offset = 0; + int i; + + write_reg(ioaddr, CMR2, CMR2_EEPROM); /* Point to the EEPROM control registers. */ + + /* Some adaptors have the station address at offset 15 instead of offset + zero. Check for it, and fix it if needed. */ + if (eeprom_op(ioaddr, EE_READ(0)) == 0xffff) + sa_offset = 15; + + for (i = 0; i < 3; i++) + ((unsigned short *)dev->dev_addr)[i] = + ntohs(eeprom_op(ioaddr, EE_READ(sa_offset + i))); + + write_reg(ioaddr, CMR2, CMR2_NULL); +} + +/* + An EEPROM read command starts by shifting out 0x60+address, and then + shifting in the serial data. See the NatSemi databook for details. + * ________________ + * CS : __| + * ___ ___ + * CLK: ______| |___| | + * __ _______ _______ + * DI : __X_______X_______X + * DO : _________X_______X + */ + +static unsigned short eeprom_op(short ioaddr, unsigned int cmd) +{ + unsigned eedata_out = 0; + int num_bits = EE_CMD_SIZE; + + while (--num_bits >= 0) { + char outval = test_bit(num_bits, &cmd) ? EE_DATA_WRITE : 0; + write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_LOW); + eeprom_delay(5); + write_reg_high(ioaddr, PROM_CMD, outval | EE_CLK_HIGH); + eedata_out <<= 1; + if (read_nibble(ioaddr, PROM_DATA) & EE_DATA_READ) + eedata_out++; + eeprom_delay(5); + } + write_reg_high(ioaddr, PROM_CMD, EE_CLK_LOW & ~EE_CS); + return eedata_out; +} + + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine sets 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. + + This is an attachable device: if there is no dev->priv entry then it wasn't + probed for at boot-time, and we need to probe for it again. + */ +static int net_open(struct device *dev) +{ + + /* The interrupt line is turned off (tri-stated) when the device isn't in + use. That's especially important for "attached" interfaces where the + port or interrupt may be shared. */ + if (irq2dev_map[dev->irq] != 0 + || (irq2dev_map[dev->irq] = dev) == 0 + || request_irq(dev->irq, &net_interrupt)) { + return -EAGAIN; + } + + hardware_init(dev); + dev->start = 1; + return 0; +} + +/* This routine resets the hardware. We initialize everything, assuming that + the hardware may have been temporarily detacted. */ +static void hardware_init(struct device *dev) +{ + struct net_local *lp = (struct net_local *)dev->priv; + int ioaddr = dev->base_addr; + int i; + + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + + for (i = 0; i < 6; i++) + write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); + + write_reg_high(ioaddr, CMR2, lp->addr_mode); + + if (net_debug > 2) { + printk("%s: Reset: current Rx mode %d.\n", dev->name, + (read_nibble(ioaddr, CMR2_h) >> 3) & 0x0f); + } + + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + write_reg_high(ioaddr, CMR1, CMR1h_RxENABLE | CMR1h_TxENABLE); + + /* Enable the interrupt line from the serial port. */ + outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + + /* Unmask the interesting interrupts. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); + + lp->tx_unit_busy = 0; + lp->pac_cnt_in_tx_buf = 0; + lp->saved_tx_size = 0; + + dev->tbusy = 0; + dev->interrupt = 0; +} + +static void trigger_send(short ioaddr, int length) +{ + write_reg_byte(ioaddr, TxCNT0, length & 0xff); + write_reg(ioaddr, TxCNT1, length >> 8); + write_reg(ioaddr, CMR1, CMR1_Xmit); +} + +static void write_packet(short ioaddr, int length, unsigned char *packet, int data_mode) +{ + length = (length + 1) & ~1; /* Round up to word length. */ + outb(EOC+MAR, ioaddr + PAR_DATA); + if ((data_mode & 1) == 0) { + /* Write the packet out, starting with the write addr. */ + outb(WrAddr+MAR, ioaddr + PAR_DATA); + do { + write_byte_mode0(ioaddr, *packet++); + } while (--length > 0) ; + } else { + /* Write the packet out in slow mode. */ + unsigned char outbyte = *packet++; + + outb(Ctrl_LNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + outb(WrAddr+MAR, ioaddr + PAR_DATA); + + outb((outbyte & 0x0f)|0x40, ioaddr + PAR_DATA); + outb(outbyte & 0x0f, ioaddr + PAR_DATA); + outbyte >>= 4; + outb(outbyte & 0x0f, ioaddr + PAR_DATA); + outb(Ctrl_HNibWrite + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + while (--length > 0) + write_byte_mode1(ioaddr, *packet++); + } + /* Terminate the Tx frame. End of write: ECB. */ + outb(0xff, ioaddr + PAR_DATA); + outb(Ctrl_HNibWrite | Ctrl_SelData | Ctrl_IRQEN, ioaddr + PAR_CONTROL); +} + +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, + inb(ioaddr + PAR_CONTROL) & 0x10 ? "network cable problem" + : "IRQ conflict"); + lp->stats.tx_errors++; + /* Try to restart the adaptor. */ + hardware_init(dev); + 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->data, 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 = skb->data; + int flags; + + /* Disable interrupts by writing 0x00 to the Interrupt Mask Register. + This sequence must not be interrupted by an incoming packet. */ + save_flags(flags); + cli(); + write_reg(ioaddr, IMR, 0); + write_reg_high(ioaddr, IMR, 0); + restore_flags(flags); + + write_packet(ioaddr, length, buf, dev->if_port); + + lp->pac_cnt_in_tx_buf++; + if (lp->tx_unit_busy == 0) { + trigger_send(ioaddr, length); + lp->saved_tx_size = 0; /* Redundent */ + lp->re_tx = 0; + lp->tx_unit_busy = 1; + } else + lp->saved_tx_size = length; + + dev->trans_start = jiffies; + /* Re-enable the LPT interrupts. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); + } + + 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 = (struct device *)(irq2dev_map[irq]); + struct net_local *lp; + int ioaddr, status, boguscount = 20; + static int num_tx_since_rx = 0; + + if (dev == NULL) { + printk ("ATP_interrupt(): irq %d for unknown device.\n", irq); + return; + } + dev->interrupt = 1; + + ioaddr = dev->base_addr; + lp = (struct net_local *)dev->priv; + + /* Disable additional spurious interrupts. */ + outb(Ctrl_SelData, ioaddr + PAR_CONTROL); + + /* The adaptor's output is currently the IRQ line, switch it to data. */ + write_reg(ioaddr, CMR2, CMR2_NULL); + write_reg(ioaddr, IMR, 0); + + if (net_debug > 5) printk("%s: In interrupt ", dev->name); + while (--boguscount > 0) { + status = read_nibble(ioaddr, ISR); + if (net_debug > 5) printk("loop status %02x..", status); + + if (status & (ISR_RxOK<<3)) { + write_reg(ioaddr, ISR, ISR_RxOK); /* Clear the Rx interrupt. */ + do { + int read_status = read_nibble(ioaddr, CMR1); + if (net_debug > 6) + printk("handling Rx packet %02x..", read_status); + /* We acknowledged the normal Rx interrupt, so if the interrupt + is still outstanding we must have a Rx error. */ + if (read_status & (CMR1_IRQ << 3)) { /* Overrun. */ + lp->stats.rx_over_errors++; + /* Set to no-accept mode long enough to remove a packet. */ + write_reg_high(ioaddr, CMR2, CMR2h_OFF); + net_rx(dev); + /* Clear the interrupt and return to normal Rx mode. */ + write_reg_high(ioaddr, ISR, ISRh_RxErr); + write_reg_high(ioaddr, CMR2, lp->addr_mode); + } else if ((read_status & (CMR1_BufEnb << 3)) == 0) { + net_rx(dev); + dev->last_rx = jiffies; + num_tx_since_rx = 0; + } else + break; + } while (--boguscount > 0); + } else if (status & ((ISR_TxErr + ISR_TxOK)<<3)) { + if (net_debug > 6) printk("handling Tx done.."); + /* Clear the Tx interrupt. We should check for too many failures + and reinitialize the adaptor. */ + write_reg(ioaddr, ISR, ISR_TxErr + ISR_TxOK); + if (status & (ISR_TxErr<<3)) { + lp->stats.collisions++; + if (++lp->re_tx > 15) { + lp->stats.tx_aborted_errors++; + hardware_init(dev); + break; + } + /* Attempt to retransmit. */ + if (net_debug > 6) printk("attempting to ReTx"); + write_reg(ioaddr, CMR1, CMR1_ReXmit + CMR1_Xmit); + } else { + /* Finish up the transmit. */ + lp->stats.tx_packets++; + lp->pac_cnt_in_tx_buf--; + if ( lp->saved_tx_size) { + trigger_send(ioaddr, lp->saved_tx_size); + lp->saved_tx_size = 0; + lp->re_tx = 0; + } else + lp->tx_unit_busy = 0; + dev->tbusy = 0; + mark_bh(INET_BH); /* Inform upper layers. */ + } + num_tx_since_rx++; + } else if (num_tx_since_rx > 8 + && jiffies > dev->last_rx + 100) { + if (net_debug > 2) + printk("%s: Missed packet? No Rx after %d Tx and %d jiffies" + " status %02x CMR1 %02x.\n", dev->name, + num_tx_since_rx, jiffies - dev->last_rx, status, + (read_nibble(ioaddr, CMR1) >> 3) & 15); + lp->stats.rx_missed_errors++; + hardware_init(dev); + num_tx_since_rx = 0; + break; + } else + break; + } + + { + int i; + for (i = 0; i < 6; i++) + write_reg_byte(ioaddr, PAR0 + i, dev->dev_addr[i]); + } + + /* Tell the adaptor that it can go back to using the output line as IRQ. */ + write_reg(ioaddr, CMR2, CMR2_IRQOUT); + /* Enable the physical interrupt line, which is sure to be low until.. */ + outb(Ctrl_SelData + Ctrl_IRQEN, ioaddr + PAR_CONTROL); + /* .. we enable the interrupt sources. */ + write_reg(ioaddr, IMR, ISR_RxOK | ISR_TxErr | ISR_TxOK); + write_reg_high(ioaddr, IMR, ISRh_RxErr); /* Hmmm, really needed? */ + + if (net_debug > 5) printk("exiting interrupt.\n"); + + dev->interrupt = 0; + + 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; +#ifdef notdef + ushort header[4]; +#else + struct rx_header rx_head; +#endif + + /* Process the received packet. */ + outb(EOC+MAR, ioaddr + PAR_DATA); + read_block(ioaddr, 8, (unsigned char*)&rx_head, dev->if_port); + if (net_debug > 5) + printk(" rx_count %04x %04x %04x %04x..", rx_head.pad, + rx_head.rx_count, rx_head.rx_status, rx_head.cur_addr); + if ((rx_head.rx_status & 0x77) != 0x01) { + lp->stats.rx_errors++; + /* Ackkk! I don't have any documentation on what the error bits mean! + The best I can do is slap the device around a bit. */ + if (net_debug > 3) printk("%s: Unknown ATP Rx error %04x.\n", + dev->name, rx_head.rx_status); + hardware_init(dev); + return; + } else { + /* Malloc up new buffer. */ + int pkt_len = (rx_head.rx_count & 0x7ff) - 4; /* The "-4" is omits the FCS (CRC). */ + 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++; + goto done; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + + /* 'skb->data' points to the start of sk_buff data area. */ + read_block(ioaddr, pkt_len, skb->data, dev->if_port); + + if (net_debug > 6) { + unsigned char *data = skb->data; + printk(" data %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x%02x %02x%02x..", + data[0], data[1], data[2], data[3], data[4], data[5], + data[6], data[7], data[8], data[9], data[10], data[11], + data[12], data[13]); + } + +#ifdef HAVE_NETIF_RX + netif_rx(skb); +#else + skb->lock = 0; + if (dev_rint((unsigned char*)skb, pkt_len, IN_SKBUFF, dev) != 0) { + kfree_s(skb, sksize); + lp->stats.rx_dropped++; + break; + } +#endif + lp->stats.rx_packets++; + } + done: + write_reg(ioaddr, CMR1, CMR1_NextPkt); + return; +} + +static void read_block(short ioaddr, int length, unsigned char *p, int data_mode) +{ + + if (data_mode <= 3) { /* Mode 0 or 1 */ + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + outb(length == 8 ? RdAddr | HNib | MAR : RdAddr | MAR, + ioaddr + PAR_DATA); + if (data_mode <= 1) { /* Mode 0 or 1 */ + do *p++ = read_byte_mode0(ioaddr); while (--length > 0); + } else /* Mode 2 or 3 */ + do *p++ = read_byte_mode2(ioaddr); while (--length > 0); + } else if (data_mode <= 5) + do *p++ = read_byte_mode4(ioaddr); while (--length > 0); + else + do *p++ = read_byte_mode6(ioaddr); while (--length > 0); + + outb(EOC+HNib+MAR, ioaddr + PAR_DATA); + outb(Ctrl_SelData, ioaddr + PAR_CONTROL); +} + +/* 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; + + dev->tbusy = 1; + dev->start = 0; + + /* Flush the Tx and disable Rx here. */ + lp->addr_mode = CMR2h_OFF; + write_reg_high(ioaddr, CMR2, CMR2h_OFF); + + /* Free the IRQ line. */ + outb(0x00, ioaddr + PAR_CONTROL); + free_irq(dev->irq); + irq2dev_map[dev->irq] = 0; + + /* Leave the hardware in a reset state. */ + write_reg_high(ioaddr, CMR1, CMR1h_RESET); + + 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; + 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) +{ + struct net_local *lp = (struct net_local *)dev->priv; + short ioaddr = dev->base_addr; + lp->addr_mode = num_addrs ? CMR2h_PROMISC : CMR2h_Normal; + write_reg_high(ioaddr, CMR2, lp->addr_mode); +} +#endif + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c atp.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.h new file mode 100644 index 000000000..6988eae9d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/atp.h @@ -0,0 +1,264 @@ +#include +#include +#include + +struct net_local { +#ifdef __KERNEL__ + struct enet_statistics stats; +#endif + ushort saved_tx_size; + unsigned char + re_tx, /* Number of packet retransmissions. */ + tx_unit_busy, + addr_mode, /* Current Rx filter e.g. promiscuous, etc. */ + pac_cnt_in_tx_buf; +}; + +struct rx_header { + ushort pad; /* The first read is always corrupted. */ + ushort rx_count; + ushort rx_status; /* Unknown bit assignments :-<. */ + ushort cur_addr; /* Apparently the current buffer address(?) */ +}; + +#define PAR_DATA 0 +#define PAR_STATUS 1 +#define PAR_CONTROL 2 + +#define Ctrl_LNibRead 0x08 /* LP_PSELECP */ +#define Ctrl_HNibRead 0 +#define Ctrl_LNibWrite 0x08 /* LP_PSELECP */ +#define Ctrl_HNibWrite 0 +#define Ctrl_SelData 0x04 /* LP_PINITP */ +#define Ctrl_IRQEN 0x10 /* LP_PINTEN */ + +#define EOW 0xE0 +#define EOC 0xE0 +#define WrAddr 0x40 /* Set address of EPLC read, write register. */ +#define RdAddr 0xC0 +#define HNib 0x10 + +enum page0_regs +{ + /* The first six registers hold the ethernet physical station address. */ + PAR0 = 0, PAR1 = 1, PAR2 = 2, PAR3 = 3, PAR4 = 4, PAR5 = 5, + TxCNT0 = 6, TxCNT1 = 7, /* The transmit byte count. */ + TxSTAT = 8, RxSTAT = 9, /* Tx and Rx status. */ + ISR = 10, IMR = 11, /* Interrupt status and mask. */ + CMR1 = 12, /* Command register 1. */ + CMR2 = 13, /* Command register 2. */ + MAR = 14, /* Memory address register. */ + CMR2_h = 0x1d, }; + +enum eepage_regs +{ PROM_CMD = 6, PROM_DATA = 7 }; /* Note that PROM_CMD is in the "high" bits. */ + + +#define ISR_TxOK 0x01 +#define ISR_RxOK 0x04 +#define ISR_TxErr 0x02 +#define ISRh_RxErr 0x11 /* ISR, high nibble */ + +#define CMR1h_RESET 0x04 /* Reset. */ +#define CMR1h_RxENABLE 0x02 /* Rx unit enable. */ +#define CMR1h_TxENABLE 0x01 /* Tx unit enable. */ +#define CMR1h_TxRxOFF 0x00 +#define CMR1_ReXmit 0x08 /* Trigger a retransmit. */ +#define CMR1_Xmit 0x04 /* Trigger a transmit. */ +#define CMR1_IRQ 0x02 /* Interrupt active. */ +#define CMR1_BufEnb 0x01 /* Enable the buffer(?). */ +#define CMR1_NextPkt 0x01 /* Enable the buffer(?). */ + +#define CMR2_NULL 8 +#define CMR2_IRQOUT 9 +#define CMR2_RAMTEST 10 +#define CMR2_EEPROM 12 /* Set to page 1, for reading the EEPROM. */ + +#define CMR2h_OFF 0 /* No accept mode. */ +#define CMR2h_Physical 1 /* Accept a physical address match only. */ +#define CMR2h_Normal 2 /* Accept physical and broadcast address. */ +#define CMR2h_PROMISC 3 /* Promiscuous mode. */ + +/* An inline function used below: it differs from inb() by explicitly return an unsigned + char, saving a truncation. */ +extern inline unsigned char inbyte(unsigned short port) +{ + unsigned char _v; + __asm__ __volatile__ ("inb %w1,%b0" :"=a" (_v):"d" (port)); + return _v; +} + +/* Read register OFFSET. + This command should aways be terminated with read_end(). */ +extern inline unsigned char read_nibble(short port, unsigned char offset) +{ + unsigned char retval; + outb(EOC+offset, port + PAR_DATA); + outb(RdAddr+offset, port + PAR_DATA); + inbyte(port + PAR_STATUS); /* Settling time delay */ + retval = inbyte(port + PAR_STATUS); + outb(EOC+offset, port + PAR_DATA); + + return retval; +} + +/* Functions for bulk data read. The interrupt line is always disabled. */ +/* Get a byte using read mode 0, reading data from the control lines. */ +extern inline unsigned char read_byte_mode0(short ioaddr) +{ + unsigned char low_nib; + + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +/* The same as read_byte_mode0(), but does multiple inb()s for stability. */ +extern inline unsigned char read_byte_mode2(short ioaddr) +{ + unsigned char low_nib; + + outb(Ctrl_LNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(Ctrl_HNibRead, ioaddr + PAR_CONTROL); + inbyte(ioaddr + PAR_STATUS); /* Settling time delay -- needed! */ + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +/* Read a byte through the data register. */ +extern inline unsigned char read_byte_mode4(short ioaddr) +{ + unsigned char low_nib; + + outb(RdAddr | MAR, ioaddr + PAR_DATA); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +/* Read a byte through the data register, double reading to allow settling. */ +extern inline unsigned char read_byte_mode6(short ioaddr) +{ + unsigned char low_nib; + + outb(RdAddr | MAR, ioaddr + PAR_DATA); + inbyte(ioaddr + PAR_STATUS); + low_nib = (inbyte(ioaddr + PAR_STATUS) >> 3) & 0x0f; + outb(RdAddr | HNib | MAR, ioaddr + PAR_DATA); + inbyte(ioaddr + PAR_STATUS); + return low_nib | ((inbyte(ioaddr + PAR_STATUS) << 1) & 0xf0); +} + +extern inline void +write_reg(short port, unsigned char reg, unsigned char value) +{ + unsigned char outval; + outb(EOC | reg, port + PAR_DATA); + outval = WrAddr | reg; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outval &= 0xf0; + outval |= value; + outb(outval, port + PAR_DATA); + outval &= 0x1f; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); + + outb(EOC | outval, port + PAR_DATA); +} + +extern inline void +write_reg_high(short port, unsigned char reg, unsigned char value) +{ + unsigned char outval = EOC | HNib | reg; + + outb(outval, port + PAR_DATA); + outval &= WrAddr | HNib | 0x0f; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outval = WrAddr | HNib | value; + outb(outval, port + PAR_DATA); + outval &= HNib | 0x0f; /* HNib | value */ + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); + + outb(EOC | HNib | outval, port + PAR_DATA); +} + +/* Write a byte out using nibble mode. The low nibble is written first. */ +extern inline void +write_reg_byte(short port, unsigned char reg, unsigned char value) +{ + unsigned char outval; + outb(EOC | reg, port + PAR_DATA); /* Reset the address register. */ + outval = WrAddr | reg; + outb(outval, port + PAR_DATA); + outb(outval, port + PAR_DATA); /* Double write for PS/2. */ + + outb((outval & 0xf0) | (value & 0x0f), port + PAR_DATA); + outb(value & 0x0f, port + PAR_DATA); + value >>= 4; + outb(value, port + PAR_DATA); + outb(0x10 | value, port + PAR_DATA); + outb(0x10 | value, port + PAR_DATA); + + outb(EOC | value, port + PAR_DATA); /* Reset the address register. */ +} + +/* + * Bulk data writes to the packet buffer. The interrupt line remains enabled. + * The first, faster method uses only the dataport (data modes 0, 2 & 4). + * The second (backup) method uses data and control regs (modes 1, 3 & 5). + * It should only be needed when there is skew between the individual data + * lines. + */ +extern inline void write_byte_mode0(short ioaddr, unsigned char value) +{ + outb(value & 0x0f, ioaddr + PAR_DATA); + outb((value>>4) | 0x10, ioaddr + PAR_DATA); +} + +extern inline void write_byte_mode1(short ioaddr, unsigned char value) +{ + outb(value & 0x0f, ioaddr + PAR_DATA); + outb(Ctrl_IRQEN | Ctrl_LNibWrite, ioaddr + PAR_CONTROL); + outb((value>>4) | 0x10, ioaddr + PAR_DATA); + outb(Ctrl_IRQEN | Ctrl_HNibWrite, ioaddr + PAR_CONTROL); +} + +/* Write 16bit VALUE to the packet buffer: the same as above just doubled. */ +extern inline void write_word_mode0(short ioaddr, unsigned short value) +{ + outb(value & 0x0f, ioaddr + PAR_DATA); + value >>= 4; + outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); + value >>= 4; + outb(value & 0x0f, ioaddr + PAR_DATA); + value >>= 4; + outb((value & 0x0f) | 0x10, ioaddr + PAR_DATA); +} + +/* EEPROM_Ctrl bits. */ +#define EE_SHIFT_CLK 0x04 /* EEPROM shift clock. */ +#define EE_CS 0x02 /* EEPROM chip select. */ +#define EE_CLK_HIGH 0x12 +#define EE_CLK_LOW 0x16 +#define EE_DATA_WRITE 0x01 /* EEPROM chip data in. */ +#define EE_DATA_READ 0x08 /* EEPROM chip data out. */ + +/* Delay between EEPROM clock transitions. */ +#define eeprom_delay(ticks) \ +do { int _i = 40; while (--_i > 0) { __SLOW_DOWN_IO; }} while (0) + +/* The EEPROM commands include the alway-set leading bit. */ +#define EE_WRITE_CMD(offset) (((5 << 6) + (offset)) << 17) +#define EE_READ(offset) (((6 << 6) + (offset)) << 17) +#define EE_ERASE(offset) (((7 << 6) + (offset)) << 17) +#define EE_CMD_SIZE 27 /* The command+address+data size. */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/auto_irq.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/auto_irq.c new file mode 100644 index 000000000..6fa11e191 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/auto_irq.c @@ -0,0 +1,115 @@ +/* auto_irq.c: Auto-configure IRQ lines for linux. */ +/* + Written 1993 by Donald Becker. + + The Author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + + This code is a general-purpose IRQ line detector for devices with + jumpered IRQ lines. If you can make the device raise an IRQ (and + that IRQ line isn't already being used), these routines will tell + you what IRQ line it's using -- perfect for those oh-so-cool boot-time + device probes! + + To use this, first call autoirq_setup(timeout). TIMEOUT is how many + 'jiffies' (1/18 sec.) to detect other devices that have active IRQ lines, + and can usually be zero at boot. 'autoirq_setup()' returns the bit + vector of nominally-available IRQ lines (lines may be physically in-use, + but not yet registered to a device). + Next, set up your device to trigger an interrupt. + Finally call autoirq_report(TIMEOUT) to find out which IRQ line was + most recently active. The TIMEOUT should usually be zero, but may + be set to the number of jiffies to wait for a slow device to raise an IRQ. + + The idea of using the setup timeout to filter out bogus IRQs came from + the serial driver. +*/ + + +#ifdef version +static char *version="auto_irq.c:v0.02 1993 Donald Becker (becker@super.org)"; +#endif + +/*#include */ +/*#include */ +#include +#include +#include +#include "dev.h" +/*#include */ + +struct device *irq2dev_map[16] = {0, 0, /* ... zeroed */}; + +int irqs_busy = 0x01; /* The set of fixed IRQs always enabled */ +int irqs_used = 0x01; /* The set of fixed IRQs sometimes enabled. */ +int irqs_reserved = 0x00; /* An advisory "reserved" table. */ +int irqs_shared = 0x00; /* IRQ lines "shared" among conforming cards.*/ + +static volatile int irq_number; /* The latest irq number we actually found. */ +static volatile int irq_bitmap; /* The irqs we actually found. */ +static int irq_handled; /* The irq lines we have a handler on. */ + +static void autoirq_probe(int irq) +{ + irq_number = irq; + set_bit(irq, (void *)&irq_bitmap); /* irq_bitmap |= 1 << irq; */ + return; +} +struct sigaction autoirq_sigaction = { autoirq_probe, 0, SA_INTERRUPT, NULL}; + +int autoirq_setup(int waittime) +{ + int i, mask; + int timeout = jiffies+waittime; + + irq_number = 0; + irq_bitmap = 0; + irq_handled = 0; + for (i = 0; i < 16; i++) { + if (!irqaction(i, &autoirq_sigaction)) + set_bit(i, (void *)&irq_handled); /* irq_handled |= 1 << i;*/ + } + /* Update our USED lists. */ + irqs_used |= ~irq_handled; + + /* Hang out at least jiffies waiting for bogus IRQ hits. */ + while (timeout > jiffies) + ; + + for (i = 0, mask = 0x01; i < 16; i++, mask <<= 1) { + if (irq_bitmap & irq_handled & mask) { + irq_handled &= ~mask; +#ifdef notdef + printk(" Spurious interrupt on IRQ %d\n", i); +#endif + free_irq(i); + } + } + return irq_handled; +} + +int autoirq_report(int waittime) +{ + int i; + int timeout = jiffies+waittime; + + /* Hang out at least jiffies waiting for the IRQ. */ + while (timeout > jiffies) + if (irq_number) + break; + + /* Retract the irq handlers that we installed. */ + for (i = 0; i < 16; i++) { + if (test_bit(i, (void *)&irq_handled)) + free_irq(i); + } + return irq_number; +} + +/* + * Local variables: + * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c auto_irq.c" + * version-control: t + * kept-new-versions: 5 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/d_link.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/d_link.c new file mode 100644 index 000000000..2ff8a1b1e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/d_link.c @@ -0,0 +1,766 @@ +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 + * + * 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 + * 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) + * 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. + * + **************************************************************/ +/* 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 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#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" + +#define netstats enet_statistics + +#ifndef HAVE_ALLOC_SKB +#define alloc_skb(size,pri) (struct sk_buff *)kmalloc(size,pri) +#endif + +/************************************************** + * * + * Definition of D-Link Ethernet Pocket adapter * + * * + **************************************************/ +/* + * 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 + */ +#define SELECT_NIC 0x04 /* select Network Interface Card */ +#define SELECT_PRN 0x1c /* select Printer */ +#define NML_PRN 0xec /* normal Printer situation */ +#define IRQEN 0x10 /* enable IRQ line */ + +/* + * D-Link STATUS_PORT + */ +#define RX_BUSY 0x80 +#define RX_GOOD 0x40 +#define TX_FAILED16 0x10 +#define TX_BUSY 0x08 + +/* + * D-Link DATA_PORT commands + * command in low 4 bits + * data in high 4 bits + * select current data nibble with HI_NIBBLE bit + */ +#define WRITE_DATA 0x00 /* write memory */ +#define READ_DATA 0x01 /* read memory */ +#define STATUS 0x02 /* read status register */ +#define COMMAND 0x03 /* write command register (see COMMAND below) */ +#define NULL_COMMAND 0x04 /* null command */ +#define RX_LEN 0x05 /* read received packet length */ +#define TX_ADDR 0x06 /* set adapter transmit memory address */ +#define RW_ADDR 0x07 /* set adapter read/write memory address */ +#define HI_NIBBLE 0x08 /* read/write the high nibble of data, + or-ed with rest of command */ + +/* + * command register, accessed through DATA_PORT with low bits = COMMAND + */ +#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 */ + +#define RESET 0x80 /* set bit 7 high */ +#define STOP_RESET 0x00 /* set bit 7 low */ + +/* + * data to command register + * (high 4 bits in write to DATA_PORT) + */ +#define RX_PAGE2_SELECT 0x10 /* bit 4, only 2 pages to select */ +#define RX_BASE_PAGE 0x20 /* bit 5, always set when specifying RX_ADDR */ +#define FLIP_IRQ 0x40 /* bit 6 */ + +/* + * D-Link adapter internal memory: + * + * 0-2K 1:st transmit page (send from pointer up to 2K) + * 2-4K 2:nd transmit page (send from pointer up to 4K) + * + * 4-6K 1:st receive page (data from 4K upwards) + * 6-8K 2:nd receive page (data from 6K upwards) + * + * 8K+ Adapter ROM (contains magic code and last 3 bytes of Ethernet address) + */ +#define MEM_2K 0x0800 /* 2048 */ +#define MEM_4K 0x1000 /* 4096 */ +#define MEM_6K 0x1800 /* 6144 */ +#define NODE_ADDRESS 0x2000 /* 8192 */ + +#define RUNT 60 /* Too small Ethernet packet */ + +/************************************************** + * * + * End of definition * + * * + **************************************************/ + +/* + * Index to functions, as function prototypes. + */ + +/* 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(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 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); + +/* + * D-Link driver variables: + */ +extern struct device *irq2dev_map[16]; +static volatile int rx_page = 0; + +#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 + */ + +#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 + +/* Thanks for hints from Mark Burton */ +#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 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; + + outb_p(STATUS, DATA_PORT); + status = inb(STATUS_PORT); + outb_p(NULL_COMMAND | HI_NIBBLE, DATA_PORT); + + return status; +} + +static inline unsigned char +d_link_read_byte(unsigned char type, struct device *dev) { /* dev used by macros */ + unsigned char lo; + + (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; +} + +/* + * Open/initialize the board. This is called (in the current kernel) + * after booting when 'ifconfig 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 + * there is a non-reboot way to recover if something goes wrong. + */ +static int +d_link_open(struct device *dev) +{ + 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; +} + +/* + * The inverse routine to d_link_open(). + */ +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! */ + + return 0; +} + +static struct netstats * +get_stats(struct device *dev) +{ + return (struct netstats *)(dev->priv); +} + +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); +} + +/* + * Copy a buffer to the adapter transmit page memory. + * Start sending. + */ +static int +d_link_start_xmit(struct sk_buff *skb, struct device *dev) +{ + int transmit_from; + int len; + int tickssofar; + unsigned char *buffer = skb->data; + + /* + * If some higher layer thinks we've missed a + * 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 (hardware addresses) with an arp. */ + if (!skb->arp) + if(dev->rebuild_header(skb->data, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + skb->arp = 1; + + if (free_tx_pages <= 0) { /* Do timeouts, to avoid hangs. */ + tickssofar = jiffies - dev->trans_start; + + if (tickssofar < 5) + return 1; + + /* else */ + printk("%s: transmit timed out (%d), %s?\n", + dev->name, + tickssofar, + "network cable problem" + ); + /* Restart the adapter. */ + adapter_init(dev); + } + + /* Start real output */ + PRINTK(("d_link_start_xmit:len=%d, page %d/%d\n", skb->len, tx_fifo_in, free_tx_pages)); + + if ((len = skb->len) < RUNT) + len = RUNT; + + 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); + + 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); + } + else { + dev->tbusy = !free_tx_pages; + select_prn(); + } + + sti(); /* interrupts back on */ + + if (skb->free) + kfree_skb (skb, FREE_WRITE); + + return 0; +} + +/* + * The typical workload of the driver: + * Handle the network interface interrupts. + */ +static void +d_link_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + 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; + } + + dev->interrupt = 1; + select_nic(); + irq_status = d_link_read_status(dev); + + do { + PRINTK(("d_link_interrupt (%2.2X)\n", irq_status)); + + if (irq_status & RX_GOOD) + d_link_rx_intr(dev); + else if (!(irq_status & RX_BUSY)) + d_link_put_command(RX_ENABLE); + + /* 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) ); + /* + * 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!) + */ + + /* Enable adapter interrupts */ + dev->interrupt = 0; + select_prn(); + + if (retrig) + trigger_interrupt(dev); + + sti(); + return; +} + +static int +d_link_tx_intr(struct device *dev, int irq_status) +{ + /* + * Returns 1 if tx still not done + */ + + mark_bh(INET_BH); + /* Check if current transmission is done yet */ + if (irq_status & TX_BUSY) + return 1; /* tx not done, try again */ + + /* 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; + } + + /* 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; + } + /* else */ + + return 0; +} + +/* + * 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; + register unsigned char *buffer; + + cli(); + /* Get size of received packet */ + 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 */ + read_from = rx_page_adr(); + next_rx_page(); + d_link_put_command(RX_ENABLE); + sti(); + + if ((size < 32) || (size > 1535)) + printk("%s: Bogus packet size %d.\n", dev->name, size); + + sksize = sizeof(struct sk_buff) + size; + 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 */ + + skb->lock = 0; + skb->mem_len = sksize; + skb->mem_addr = skb; + /* 'skb->data' points to the start of sk_buff data area. */ + buffer = skb->data; + + /* copy the packet into the buffer */ + d_link_setup_address(read_from, RW_ADDR); + for (i = size; i > 0; --i, ++buffer) + *buffer = d_link_read_byte(READ_DATA, dev); + + ((struct netstats *)(dev->priv))->rx_packets++; /* count all receives */ + + if (dev_rint((unsigned char *)skb, size, IN_SKBUFF, dev)) + printk("%s: receive buffers full.\n", dev->name); + /* + * 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. + */ +} + +int +d_link_init(struct device *dev) +{ + int i; + + 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(": not at I/O %#3x.\n", DATA_PORT); + return ENODEV; + } + + /* + * Maybe we found one, + * have to check if it is a D-Link DE-600 adapter... + */ + + /* Get the adapter ethernet address from the ROM */ + d_link_setup_address(NODE_ADDRESS, RW_ADDR); + for (i = 0; i < ETH_ALEN; i++) { + dev->dev_addr[i] = d_link_read_byte(READ_DATA, dev); + dev->broadcast[i] = 0xff; + } + + /* Check magic code */ + if ((dev->dev_addr[1] == 0xde) && (dev->dev_addr[2] == 0x15)) { + /* OK, install real address */ + dev->dev_addr[0] = 0x00; + dev->dev_addr[1] = 0x80; + dev->dev_addr[2] = 0xc8; + dev->dev_addr[3] &= 0x0f; + dev->dev_addr[3] |= 0x70; + } else { + 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)); + + 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->hard_start_xmit = &d_link_start_xmit; + + /* These are ethernet specific. */ + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = 1500; /* eth_mtu */ + dev->addr_len = ETH_ALEN; + + /* 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); + + select_prn(); + return 0; +} + +static void +adapter_init(struct device *dev) +{ + int i; + + cli(); + dev->tbusy = 0; /* Transmit busy... */ + dev->interrupt = 0; + dev->start = 1; + + select_nic(); + rx_page = 0; /* used by RESET */ + d_link_put_command(RESET); + d_link_put_command(STOP_RESET); + + tx_fifo_in = 0; + tx_fifo_out = 0; + free_tx_pages = TX_PAGES; + + /* 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/eexpress.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/eexpress.c new file mode 100644 index 000000000..dff42384b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/eexpress.c @@ -0,0 +1,1026 @@ +/* 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.06 10/27/93 Donald Becker (becker@super.org)\n"; + +#include + +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.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) +#else +/* This isn't quite right, but it's the best version define I can find right now. */ +#include +#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. + + */ + +static 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, 0x270, 0x320, 0x340, 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; + + 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); + } + + /* It's now OK to leave the board in reset, pending the open(). */ + outb(ASIC_RESET, ioaddr + EEPROM_Ctrl); + + 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. */ +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 (irq2dev_map[dev->irq] != 0 + /* This is always true, but avoid the false IRQ. */ + || (irq2dev_map[dev->irq] = dev) == 0 + || request_irq(dev->irq, &eexp_interrupt)) { + return -EAGAIN; + } + + /* 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->data, 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 = skb->data; + + /* 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); + outsw(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); + outsw(ioaddr, init_words, sizeof(init_words)>>1); + + /* Fill in the station address. */ + outw(SA_OFFSET, ioaddr + WRITE_PTR); + outsw(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! */ + outsw(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); + + insw(ioaddr, skb->data, (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_s(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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/hp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/hp.c new file mode 100644 index 000000000..eda01d12d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/hp.c @@ -0,0 +1,328 @@ +/* hp.c: A HP LAN ethernet driver for linux. */ +/* + Written 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 a driver for the HP LAN 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 = + "hp.c:v0.99.14a 12/2/93 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "8390.h" + +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#endif + +#define HP_IO_EXTENT 32 + +#define HP_DATAPORT 0x0c /* "Remote DMA" data port. */ +#define HP_ID 0x07 +#define HP_CONFIGURE 0x08 /* Configuration register. */ +#define HP_RUN 0x01 /* 1 == Run, 0 == reset. */ +#define HP_IRQ 0x0E /* Mask for software-configured IRQ line. */ +#define HP_DATAON 0x10 /* Turn on dataport */ +#define NIC_OFFSET 0x10 /* Offset the 8390 registers. */ + +#define HP_START_PG 0x00 /* First page of TX buffer */ +#define HP_8BSTOP_PG 0x80 /* Last page +1 of RX ring */ +#define HP_16BSTOP_PG 0xFF /* Same, for 16 bit cards. */ + +int hp_probe(struct device *dev); +int hpprobe1(struct device *dev, int ioaddr); + +static void hp_reset_8390(struct device *dev); +static int hp_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void hp_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); +static void hp_init_card(struct device *dev); + +/* The map from IRQ number to HP_CONFIGURE register setting. */ +/* My default is IRQ5 0 1 2 3 4 5 6 7 8 9 10 11 */ +static char irqmap[16] = { 0, 0, 4, 6, 8,10, 0,14, 0, 4, 2,12,0,0,0,0}; + + +/* Probe for an HP LAN adaptor. + Also initialize the card and fill in STATION_ADDR with the station + address. */ + +int hp_probe(struct device *dev) +{ + int *port, ports[] = {0x300, 0x320, 0x340, 0x280, 0x2C0, 0x200, 0x240, 0}; + short ioaddr = dev->base_addr; + + if (ioaddr > 0x1ff) /* Check a single specified location. */ + return hpprobe1(dev, ioaddr); + else if (ioaddr > 0) /* Don't probe at all. */ + return ENXIO; + + for (port = &ports[0]; *port; port++) { + if (check_region(*port, HP_IO_EXTENT)) + continue; + if (hpprobe1(dev, *port) == 0) { + return 0; + } + } + return ENODEV; +} + +int hpprobe1(struct device *dev, int ioaddr) +{ + int status, i, board_id, wordmode; + char *name; + unsigned char *station_addr = dev->dev_addr; + + /* Check for the HP physical address, 08 00 09 xx xx xx. */ + if (inb(ioaddr) != 0x08 + || inb(ioaddr+1) != 0x00 + || inb(ioaddr+2) != 0x09) + return ENODEV; + + /* This really isn't good enough, we may pick up HP LANCE boards also! */ + /* Verify that there is a 8390 at the expected location. */ + outb(E8390_NODMA + E8390_STOP, ioaddr); + SLOW_DOWN_IO; + status = inb(ioaddr); + if (status != 0x21 && status != 0x23) + return ENODEV; + + /* Set up the parameters based on the board ID. + If you have additional mappings, please mail them to becker@super.org. */ + if ((board_id = inb(ioaddr + HP_ID)) & 0x80) { + name = "HP27247"; + wordmode = 1; + } else { + name = "HP27250"; + wordmode = 0; + } + + /* Grab the region so we can find another board if something fails. */ + snarf_region(ioaddr, HP_IO_EXTENT); + + printk("%s: %s (ID %02x) at %#3x,", dev->name, name, board_id, ioaddr); + + for(i = 0; i < ETHER_ADDR_LEN; i++) + printk(" %2.2x", station_addr[i] = inb(ioaddr + i)); + + /* Snarf the interrupt now. Someday this could be moved to open(). */ + if (dev->irq < 2) { + int irq_16list[] = { 11, 10, 5, 3, 4, 7, 9, 0}; + int irq_8list[] = { 7, 5, 3, 4, 9, 0}; + int *irqp = wordmode ? irq_16list : irq_8list; + do { + int irq = *irqp; + if (request_irq (irq, NULL) != -EBUSY) { + autoirq_setup(0); + /* Twinkle the interrupt, and check if it's seen. */ + outb_p(irqmap[irq] | HP_RUN, ioaddr + HP_CONFIGURE); + outb_p( 0x00 | HP_RUN, ioaddr + HP_CONFIGURE); + if (irq == autoirq_report(0) /* It's a good IRQ line! */ + && request_irq (irq, &ei_interrupt) == 0) { + printk(" selecting IRQ %d.\n", irq); + dev->irq = *irqp; + break; + } + } + } while (*++irqp); + if (*irqp == 0) { + printk(" no free IRQ lines.\n"); + return EBUSY; + } + } else { + if (dev->irq == 2) + dev->irq = 9; + if (irqaction(dev->irq, &ei_sigaction)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return EBUSY; + } + } + + if (ei_debug > 1) + printk(version); + + /* Set the base address to point to the NIC, not the "real" base! */ + dev->base_addr = ioaddr + NIC_OFFSET; + + ethdev_init(dev); + + ei_status.name = name; + ei_status.word16 = wordmode; + ei_status.tx_start_page = HP_START_PG; + ei_status.rx_start_page = HP_START_PG + TX_PAGES; + ei_status.stop_page = wordmode ? HP_16BSTOP_PG : HP_8BSTOP_PG; + + ei_status.reset_8390 = &hp_reset_8390; + ei_status.block_input = &hp_block_input; + ei_status.block_output = &hp_block_output; + hp_init_card(dev); + + return 0; +} + +static void +hp_reset_8390(struct device *dev) +{ + int hp_base = dev->base_addr - NIC_OFFSET; + int saved_config = inb_p(hp_base + HP_CONFIGURE); + int reset_start_time = jiffies; + + if (ei_debug > 1) printk("resetting the 8390 time=%d...", jiffies); + outb_p(0x00, hp_base + HP_CONFIGURE); + 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; + } + } + + outb_p(saved_config, hp_base + HP_CONFIGURE); + while ((inb_p(hp_base+NIC_OFFSET+EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2) { + printk("%s: hp_reset_8390() did not complete.\n", dev->name); + return; + } + if (ei_debug > 1) printk("8390 reset done (%d).", jiffies); +} + +/* Block input and output, similar to the Crynwr packet driver. If you + porting to a new ethercard look at the packet driver source for hints. + The HP LAN doesn't use shared memory -- we put the packet + out through the "remote DMA" dataport. */ + +static int +hp_block_input(struct device *dev, int count, char *buf, int ring_offset) +{ + int nic_base = dev->base_addr; + int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); + int xfer_count = count; + + outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE); + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base); + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base); + if (ei_status.word16) { + insw(nic_base - NIC_OFFSET + HP_DATAPORT,buf,count>>1); + if (count & 0x01) + buf[count-1] = inb(nic_base - NIC_OFFSET + HP_DATAPORT), xfer_count++; + } else { + insb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count); + } + /* This is for the ALPHA version only, remove for later releases. */ + if (ei_debug > 0) { /* DMA termination address check... */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + int addr = (high << 8) + low; + /* Check only the lower 8 bits so we can ignore ring wrap. */ + if (((ring_offset + xfer_count) & 0xff) != (addr & 0xff)) + printk("%s: RX transfer address mismatch, %#4.4x vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } + outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE); + return ring_offset + count; +} + +static void +hp_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page) +{ + int nic_base = dev->base_addr; + int saved_config = inb_p(nic_base - NIC_OFFSET + HP_CONFIGURE); + + outb_p(saved_config | HP_DATAON, nic_base - NIC_OFFSET + HP_CONFIGURE); + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + if (ei_status.word16 && (count & 0x01)) + count++; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base); + +#ifdef ei8390_bug + /* Handle the read-before-write bug the same way as the + Crynwr packet driver -- the NatSemi method doesn't work. */ + outb_p(0x42, nic_base + EN0_RCNTLO); + outb_p(0, nic_base + EN0_RCNTHI); + outb_p(0xff, nic_base + EN0_RSARLO); + outb_p(0x00, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, EN_CMD); + /* Make certain that the dummy read has occured. */ + inb_p(0x61); + inb_p(0x61); +#endif + + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); + + outb_p(E8390_RWRITE+E8390_START, nic_base); + if (ei_status.word16) { + /* Use the 'rep' sequence for 16 bit boards. */ + outsw(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count>>1); + } else { + outsb(nic_base - NIC_OFFSET + HP_DATAPORT, buf, count); + } + + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here -- it's broken! */ + + /* This is for the ALPHA version only, remove for later releases. */ + if (ei_debug > 0) { /* DMA termination address check... */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + int addr = (high << 8) + low; + if ((start_page << 8) + count != addr) + printk("%s: TX Transfer address mismatch, %#4.4x vs. %#4.4x.\n", + dev->name, (start_page << 8) + count, addr); + } + outb_p(saved_config & (~HP_DATAON), nic_base - NIC_OFFSET + HP_CONFIGURE); + return; +} + +/* This function resets the ethercard if something screws up. */ +static void +hp_init_card(struct device *dev) +{ + int irq = dev->irq; + NS8390_init(dev, 0); + outb_p(irqmap[irq&0x0f] | HP_RUN, + dev->base_addr - NIC_OFFSET + HP_CONFIGURE); + return; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c hp.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/iow.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/iow.h new file mode 100644 index 000000000..6e15688fb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/iow.h @@ -0,0 +1,6 @@ +#ifndef _ASM_IOW_H +#define _ASM_IOW_H + +/* no longer used */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/lance.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/lance.c new file mode 100644 index 000000000..1d610e88a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/lance.c @@ -0,0 +1,844 @@ +/* lance.c: An AMD LANCE ethernet driver for linux. */ +/* + Written 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 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.14g 12/21/93 becker@super.org\n"; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "eth.h" +#include "skbuff.h" +#include "arp.h" + +#ifndef HAVE_PORTRESERVE +#define check_region(addr, size) 0 +#define snarf_region(addr, size) do ; while(0) +#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 + +struct device *init_etherdev(struct device *dev, int sizeof_private, + unsigned long *mem_startp); + +#ifdef LANCE_DEBUG +int lance_debug = LANCE_DEBUG; +#else +int lance_debug = 1; +#endif + +#ifndef LANCE_DMA +#define LANCE_DMA 5 +#endif + +/* + Theory of Operation + +I. Board Compatibility + +This device driver is designed for the AMD 79C960, the "PCnet-ISA +single-chip ethernet controller for ISA". This chip is used in a wide +variety of boards from vendors such as Allied Telesis, HP, Kingston, +and Boca. This driver is also intended to work with older AMD 7990 +designs, such as the NE1500 and NE2100. For convenience, I use the name +LANCE to refer to either AMD chip. + +II. Board-specific settings + +The driver is designed to work the boards that use the faster +bus-master mode, rather than in shared memory mode. (Only older designs +have on-board buffer memory needed to support the slower shared memory mode.) + +Most boards have jumpered settings for the I/O base, IRQ line, and DMA channel. +This driver probes the likely base addresses, {0x300, 0x320, 0x340, 0x360}. +After the board is found it generates an DMA-timeout interrupt and uses +autoIRQ to find the IRQ line. The DMA channel defaults to LANCE_DMA, or it +can be set with the low bits of the otherwise-unused dev->mem_start value. + +The HP-J2405A board is an exception: with this board it's easy to read the +EEPROM-set values for the base, IRQ, and DMA. Of course you must already +_know_ the base address, but that entry is for changing the EEPROM. + +III. Driver operation + +IIIa. Ring buffers +The LANCE uses ring buffers of Tx and Rx descriptors. Each entry describes +the base and length of the data buffer, along with status bits. The length +of these buffers is set by LANCE_LOG_{RX,TX}_BUFFERS, which is log_2() of +the buffer length (rather than being directly the buffer length) for +implementation ease. The current values are 2 (Tx) and 4 (Rx), which leads to +ring sizes of 4 (Tx) and 16 (Rx). Increasing the number of ring entries +needlessly uses extra space and reduces the chance that an upper layer will +be able to reorder queued Tx packets based on priority. Decreasing the number +of entries makes it more difficult to achieve back-to-back packet transmission +and increases the chance that Rx ring will overflow. (Consider the worst case +of receiving back-to-back minimum-sized packets.) + +The LANCE has the capability to "chain" both Rx and Tx buffers, but this driver +statically allocates full-sized (slightly oversized -- PKT_BUF_SZ) buffers to +avoid the administrative overhead. For the Rx side this avoids dynamically +allocating full-sized buffers "just in case", at the expense of a +memory-to-memory data copy for each packet received. For most systems this +is an good tradeoff: the Rx buffer will always be in low memory, the copy +is inexpensive, and it primes the cache for later packet processing. For Tx +the buffers are only used when needed as low-memory bounce buffers. + +IIIB. 16M memory limitations. +For the ISA bus master mode all structures used directly by the LANCE, +the initialization block, Rx and Tx rings, and data buffers, must be +accessable from the ISA bus, i.e. in the lower 16M of real memory. +This is a problem for current Linux kernels on >16M machines. The network +devices are initialized after memory initialization, and the kernel doles out +memory from the top of memory downward. The current solution is to have a +special network initialization routine that's called before memory +initialization; this will eventually be generalized for all network devices. +As mentioned before, low-memory "bounce-buffers" are used when needed. + +IIIC. Synchronization +The driver runs as two independent, single-threaded flows of control. One +is the send-packet routine, which enforces single-threaded use by the +dev->tbusy flag. The other thread is the interrupt handler, which is single +threaded by the hardware and other software. + +The send packet thread has partial control over the Tx ring and 'dev->tbusy' +flag. It sets the tbusy flag whenever it's queuing a Tx packet. If the next +queue slot is empty, it clears the tbusy flag when finished otherwise it sets +the 'lp->tx_full' flag. + +The interrupt handler has exclusive control over the Rx ring and records stats +from the Tx ring. (The Tx-done interrupt can't be selectively turned off, so +we can't avoid the interrupt overhead by having the Tx routine reap the Tx +stats.) After reaping the stats, it marks the queue entry as empty by setting +the 'base' to zero. Iff the 'lp->tx_full' flag is set, it clears both the +tx_full and tbusy flags. + +*/ + +/* Set the number of Tx and Rx buffers, using Log_2(# buffers). + Reasonable default values are 4 Tx buffers, and 16 Rx buffers. + That translates to 2 (4 == 2^^2) and 4 (16 == 2^^4). */ +#ifndef LANCE_LOG_TX_BUFFERS +#define LANCE_LOG_TX_BUFFERS 4 +#define LANCE_LOG_RX_BUFFERS 4 +#endif + +#define TX_RING_SIZE (1 << (LANCE_LOG_TX_BUFFERS)) +#define TX_RING_MOD_MASK (TX_RING_SIZE - 1) +#define TX_RING_LEN_BITS ((LANCE_LOG_TX_BUFFERS) << 29) + +#define RX_RING_SIZE (1 << (LANCE_LOG_RX_BUFFERS)) +#define RX_RING_MOD_MASK (RX_RING_SIZE - 1) +#define RX_RING_LEN_BITS ((LANCE_LOG_RX_BUFFERS) << 29) + +#define PKT_BUF_SZ 1544 + +/* Offsets from base I/O address. */ +#define LANCE_DATA 0x10 +#define LANCE_ADDR 0x12 +#define LANCE_RESET 0x14 +#define LANCE_BUS_IF 0x16 +#define LANCE_TOTAL_SIZE 0x18 + +/* The LANCE Rx and Tx ring descriptors. */ +struct lance_rx_head { + int base; + short buf_length; /* This length is 2's complement (negative)! */ + short msg_length; /* This length is "normal". */ +}; + +struct lance_tx_head { + int base; + short length; /* Length is 2's complement (negative)! */ + short misc; +}; + +/* The LANCE initialization block, described in databook. */ +struct lance_init_block { + unsigned short mode; /* Pre-set mode (reg. 15) */ + unsigned char phys_addr[6]; /* Physical ethernet address */ + unsigned filter[2]; /* Multicast filter (unused). */ + /* Receive and transmit ring base, along with extra bits. */ + unsigned rx_ring; /* Tx and Rx ring base pointers */ + unsigned tx_ring; +}; + +struct lance_private { + char devname[8]; + /* These must aligned on 8-byte boundaries. */ + struct lance_rx_head rx_ring[RX_RING_SIZE]; + struct lance_tx_head tx_ring[TX_RING_SIZE]; + struct lance_init_block init_block; + long rx_buffs; /* Address of Rx and Tx buffers. */ + /* Tx low-memory "bounce buffer" address. */ + char (*tx_bounce_buffs)[PKT_BUF_SZ]; + 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 */ +}; + +static unsigned long lance_probe1(short ioaddr, unsigned long mem_start); +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); +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 HAVE_MULTICAST +static void set_multicast_list(struct device *dev, int num_addrs, void *addrs); +#endif + + + +unsigned long lance_init(unsigned long mem_start, unsigned long mem_end) +{ + int *port, ports[] = {0x300, 0x320, 0x340, 0x360, 0}; + + for (port = &ports[0]; *port; port++) { + int ioaddr = *port; + + if ( check_region(ioaddr, LANCE_TOTAL_SIZE) == 0 + && inb(ioaddr + 14) == 0x57 + && inb(ioaddr + 15) == 0x57) { + mem_start = lance_probe1(ioaddr, mem_start); + } + } + + return mem_start; +} + +static unsigned long lance_probe1(short ioaddr, unsigned long mem_start) +{ + struct device *dev; + struct lance_private *lp; + int hpJ2405A = 0; + int i, reset_val; + + 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 mem_start; + + dev = init_etherdev(0, sizeof(struct lance_private) + + PKT_BUF_SZ*(RX_RING_SIZE + TX_RING_SIZE), + &mem_start); + + 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)); + + dev->base_addr = ioaddr; + snarf_region(ioaddr, LANCE_TOTAL_SIZE); + + /* Make certain the data structures used by the LANCE are aligned. */ + dev->priv = (void *)(((int)dev->priv + 7) & ~7); + lp = (struct lance_private *)dev->priv; + lp->rx_buffs = (long)dev->priv + sizeof(struct lance_private); + lp->tx_bounce_buffs = (char (*)[PKT_BUF_SZ]) + (lp->rx_buffs + PKT_BUF_SZ*RX_RING_SIZE); + +#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 mem_start; + } +#endif + + outw(88, ioaddr+LANCE_ADDR); + lp->old_lance = (inw(ioaddr+LANCE_DATA) != 0x3003); + +#if defined(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++) + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; + lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS; + lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS; + + outw(0x0001, ioaddr+LANCE_ADDR); + outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA); + outw(0x0002, ioaddr+LANCE_ADDR); + outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA); + outw(0x0000, ioaddr+LANCE_ADDR); + + 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. */ + if (dev->mem_start & 0x07) + dev->dma = dev->mem_start & 0x07; + else if (dev->dma == 0) + dev->dma = LANCE_DMA; + + /* 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 mem_start; + } + } else + printk(" assigned IRQ %d DMA %d.\n", dev->irq, dev->dma); + } + + 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); + + /* The LANCE-specific entries in the device structure. */ + dev->open = &lance_open; + 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 + + return mem_start; +} + + +static int +lance_open(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int ioaddr = dev->base_addr; + int i; + + if (request_irq(dev->irq, &lance_interrupt)) { + return -EAGAIN; + } + + if (request_dma(dev->dma)) { + free_irq(dev->irq); + return -EAGAIN; + } + irq2dev_map[dev->irq] = dev; + + /* Reset the LANCE */ + inw(ioaddr+LANCE_RESET); + + /* The DMA controller is used as a no-operation slave, "cascade mode". */ + enable_dma(dev->dma); + set_dma_mode(dev->dma, DMA_MODE_CASCADE); + + /* Un-Reset the LANCE, needed only for the NE2100. */ + if (lp->old_lance) + outw(0, ioaddr+LANCE_RESET); + + 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", + dev->name, dev->irq, dev->dma, (int) lp->tx_ring, (int) lp->rx_ring, + (int) &lp->init_block); + + lance_init_ring(dev); + /* Re-initialize the LANCE, and start it when done. */ + outw(0x0001, ioaddr+LANCE_ADDR); + outw((short) (int) &lp->init_block, ioaddr+LANCE_DATA); + outw(0x0002, ioaddr+LANCE_ADDR); + outw(((int)&lp->init_block) >> 16, ioaddr+LANCE_DATA); + + outw(0x0004, ioaddr+LANCE_ADDR); + outw(0x0d15, ioaddr+LANCE_DATA); + + outw(0x0000, ioaddr+LANCE_ADDR); + outw(0x0001, ioaddr+LANCE_DATA); + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + i = 0; + while (i++ < 100) + if (inw(ioaddr+LANCE_DATA) & 0x0100) + break; + outw(0x0142, ioaddr+LANCE_DATA); + + if (lance_debug > 2) + printk("%s: LANCE open after %d ticks, init block %#x csr0 %4.4x.\n", + dev->name, i, (int) &lp->init_block, inw(ioaddr+LANCE_DATA)); + + return 0; /* Always succeed */ +} + +/* Initialize the LANCE Rx and Tx rings. */ +static void +lance_init_ring(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int i; + + lp->cur_rx = lp->cur_tx = 0; + lp->dirty_rx = lp->dirty_tx = 0; + + for (i = 0; i < RX_RING_SIZE; i++) { + lp->rx_ring[i].base = (lp->rx_buffs + i*PKT_BUF_SZ) | 0x80000000; + lp->rx_ring[i].buf_length = -PKT_BUF_SZ; + } + /* The Tx buffer address is filled in as needed, but we do need to clear + the upper ownership bit. */ + for (i = 0; i < TX_RING_SIZE; i++) { + lp->tx_ring[i].base = 0; + } + + lp->init_block.mode = 0x0000; + for (i = 0; i < 6; i++) + lp->init_block.phys_addr[i] = dev->dev_addr[i]; + lp->init_block.filter[0] = 0x00000000; + lp->init_block.filter[1] = 0x00000000; + lp->init_block.rx_ring = (int)lp->rx_ring | RX_RING_LEN_BITS; + lp->init_block.tx_ring = (int)lp->tx_ring | TX_RING_LEN_BITS; +} + +static int +lance_start_xmit(struct sk_buff *skb, struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int ioaddr = dev->base_addr; + int entry; + + /* Transmitter timeout, serious problems. */ + if (dev->tbusy) { + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 10) + return 1; + outw(0, ioaddr+LANCE_ADDR); + printk("%s: transmit timed out, status %4.4x, resetting.\n", + dev->name, inw(ioaddr+LANCE_DATA)); + outw(0x0001, ioaddr+LANCE_DATA); + lp->stats.tx_errors++; +#ifndef final_version + { + int i; + printk(" Ring data dump: dirty_tx %d cur_tx %d cur_rx %d.", + lp->dirty_tx, lp->cur_tx, lp->cur_rx); + for (i = 0 ; i < RX_RING_SIZE; i++) + printk("%s %08x %04x %04x", i & 0x3 ? "" : "\n ", + lp->rx_ring[i].base, -lp->rx_ring[i].buf_length, + lp->rx_ring[i].msg_length); + for (i = 0 ; i < TX_RING_SIZE; i++) + printk(" %s%08x %04x %04x", i & 0x3 ? "" : "\n ", + lp->tx_ring[i].base, -lp->tx_ring[i].length, + lp->tx_ring[i].misc); + printk("\n"); + } +#endif + lance_init_ring(dev); + outw(0x0043, ioaddr+LANCE_DATA); + + dev->tbusy=0; + dev->trans_start = jiffies; + + return 0; + } + + if (skb == NULL) { + dev_tint(dev); + return 0; + } + + /* Fill in the ethernet header. */ + if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + skb->arp=1; + + if (skb->len <= 0) + return 0; + + if (lance_debug > 3) { + outw(0x0000, ioaddr+LANCE_ADDR); + printk("%s: lance_start_xmit() called, csr0 %4.4x.\n", dev->name, + inw(ioaddr+LANCE_DATA)); + outw(0x0000, ioaddr+LANCE_DATA); + } + + /* 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); + + /* Fill in a Tx ring entry */ + + /* Mask to ring buffer boundary. */ + entry = lp->cur_tx & TX_RING_MOD_MASK; + + /* Caution: the write order is important here, set the base address + with the "ownership" bits last. */ + + /* The old LANCE chips doesn't automatically pad buffers to min. size. */ + if (lp->old_lance) { + lp->tx_ring[entry].length = + -(ETH_ZLEN < skb->len ? skb->len : ETH_ZLEN); + } else + lp->tx_ring[entry].length = -skb->len; + + lp->tx_ring[entry].misc = 0x0000; + + /* If any part of this buffer is >16M we must copy it to a low-memory + buffer. */ + if ((int)(skb->data) + skb->len > 0x01000000) { + if (lance_debug > 5) + printk("%s: bouncing a high-memory packet (%#x).\n", + dev->name, (int)skb->data); + memcpy(&lp->tx_bounce_buffs[entry], skb->data, skb->len); + lp->tx_ring[entry].base = + (int)(lp->tx_bounce_buffs + entry) | 0x83000000; + if (skb->free) + kfree_skb (skb, FREE_WRITE); + } else + { + /* Gimme!!! */ + if(skb->free==0) + skb_kept_by_device(skb); + lp->tx_ring[entry].base = (int)skb->data | 0x83000000; + } + lp->cur_tx++; + + /* Trigger an immediate send poll. */ + outw(0x0000, ioaddr+LANCE_ADDR); + outw(0x0048, ioaddr+LANCE_DATA); + + dev->trans_start = jiffies; + + if (lp->tx_ring[(entry+1) & TX_RING_MOD_MASK].base == 0) + dev->tbusy=0; + + return 0; +} + +/* The LANCE interrupt handler. */ +static void +lance_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = (struct device *)(irq2dev_map[irq]); + struct lance_private *lp; + int csr0, ioaddr; + + if (dev == NULL) { + printk ("lance_interrupt(): irq %d for unknown device.\n", irq); + return; + } + + ioaddr = dev->base_addr; + lp = (struct lance_private *)dev->priv; + if (dev->interrupt) + printk("%s: Re-entering the interrupt handler.\n", dev->name); + + dev->interrupt = 1; + + outw(0x00, dev->base_addr + LANCE_ADDR); + csr0 = inw(dev->base_addr + LANCE_DATA); + + /* Acknowledge all of the current interrupt sources ASAP. */ + outw(csr0 & ~0x004f, dev->base_addr + LANCE_DATA); + + if (lance_debug > 5) + printk("%s: interrupt csr0=%#2.2x new csr=%#2.2x.\n", + dev->name, csr0, inw(dev->base_addr + LANCE_DATA)); + + if (csr0 & 0x0400) /* Rx interrupt */ + lance_rx(dev); + + if (csr0 & 0x0200) { /* Tx-done interrupt */ + int dirty_tx = lp->dirty_tx; + + while (dirty_tx < lp->cur_tx) { + int entry = dirty_tx & TX_RING_MOD_MASK; + int status = lp->tx_ring[entry].base; + void *databuff; + + if (status < 0) + break; /* It still hasn't been Txed */ + + lp->tx_ring[entry].base = 0; + databuff = (void*)(status & 0x00ffffff); + + if (status & 0x40000000) { /* There was an major error, log it. */ + int err_status = lp->tx_ring[entry].misc; + lp->stats.tx_errors++; + if (err_status & 0x0400) lp->stats.tx_aborted_errors++; + if (err_status & 0x0800) lp->stats.tx_carrier_errors++; + if (err_status & 0x1000) lp->stats.tx_window_errors++; + if (err_status & 0x4000) lp->stats.tx_fifo_errors++; + /* We should re-init() after the FIFO error. */ + } else if (status & 0x18000000) + lp->stats.collisions++; + else + lp->stats.tx_packets++; + + /* We don't free the skb if it's a data-only copy in the bounce + buffer. The address checks here are sorted -- the first test + should always work. */ + if (databuff >= (void*)(&lp->tx_bounce_buffs[TX_RING_SIZE]) + || databuff < (void*)(lp->tx_bounce_buffs)) { + struct sk_buff *skb = ((struct sk_buff *)databuff) - 1; + if (skb->free) + kfree_skb(skb, FREE_WRITE); + else + skb_device_release(skb,FREE_WRITE); + /* Warning: skb may well vanish at the point you call device_release! */ + } + dirty_tx++; + } + +#ifndef final_version + if (lp->cur_tx - dirty_tx >= TX_RING_SIZE) { + printk("out-of-sync dirty pointer, %d vs. %d.\n", + dirty_tx, lp->cur_tx); + dirty_tx += TX_RING_SIZE; + } +#endif + + if (dev->tbusy && dirty_tx > lp->cur_tx - TX_RING_SIZE + 2) { + /* The ring is no longer full, clear tbusy. */ + dev->tbusy = 0; + mark_bh(INET_BH); + } + + lp->dirty_tx = dirty_tx; + } + + if (csr0 & 0x8000) { + if (csr0 & 0x4000) lp->stats.tx_errors++; + if (csr0 & 0x1000) lp->stats.rx_errors++; + } + + /* Clear the interrupts we've handled. */ + outw(0x0000, dev->base_addr + LANCE_ADDR); + outw(0x7f40, dev->base_addr + LANCE_DATA); + + if (lance_debug > 4) + printk("%s: exiting interrupt, csr%d=%#4.4x.\n", + dev->name, inw(ioaddr + LANCE_ADDR), + inw(dev->base_addr + LANCE_DATA)); + + dev->interrupt = 0; + return; +} + +static int +lance_rx(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + int entry = lp->cur_rx & RX_RING_MOD_MASK; + + /* If we own the next entry, it's a new packet. Send it up. */ + while (lp->rx_ring[entry].base >= 0) { + int status = lp->rx_ring[entry].base >> 24; + + 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, compatible with net-2e. */ + short pkt_len = lp->rx_ring[entry].msg_length; + 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, deferring packet.\n", dev->name); + lp->stats.rx_dropped++; /* Really, deferred. */ + break; + } + skb->mem_len = sksize; + skb->mem_addr = skb; + skb->len = pkt_len; + skb->dev = dev; + memcpy(skb->data, + (unsigned char *)(lp->rx_ring[entry].base & 0x00ffffff), + 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 + lp->stats.rx_packets++; + } + + lp->rx_ring[entry].base |= 0x80000000; + entry = (++lp->cur_rx) & RX_RING_MOD_MASK; + } + + /* We should check that at least two ring entries are free. If not, + we should free one and mark stats->rx_dropped++. */ + + return 0; +} + +static int +lance_close(struct device *dev) +{ + int ioaddr = dev->base_addr; + struct lance_private *lp = (struct lance_private *)dev->priv; + + dev->start = 0; + dev->tbusy = 1; + + outw(112, ioaddr+LANCE_ADDR); + lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA); + + outw(0, ioaddr+LANCE_ADDR); + + if (lance_debug > 1) + printk("%s: Shutting down ethercard, status was %2.2x.\n", + dev->name, inw(ioaddr+LANCE_DATA)); + + /* We stop the LANCE here -- it occasionally polls + memory if we don't. */ + outw(0x0004, ioaddr+LANCE_DATA); + + disable_dma(dev->dma); + + free_irq(dev->irq); + free_dma(dev->dma); + + irq2dev_map[dev->irq] = 0; + + return 0; +} + +static struct enet_statistics * +lance_get_stats(struct device *dev) +{ + struct lance_private *lp = (struct lance_private *)dev->priv; + short ioaddr = dev->base_addr; + short saved_addr; + + cli(); + saved_addr = inw(ioaddr+LANCE_ADDR); + outw(112, ioaddr+LANCE_ADDR); + lp->stats.rx_missed_errors = inw(ioaddr+LANCE_DATA); + outw(saved_addr, ioaddr+LANCE_ADDR); + 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; + + /* 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__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c lance.c" + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/ne.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/ne.c new file mode 100644 index 000000000..e198d5575 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/ne.c @@ -0,0 +1,422 @@ +/* ne.c: A general non-shared-memory NS8390 ethernet driver 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 driver should work with many 8390-based ethernet boards. Currently + it support the NE1000, NE2000, clones, and some Cabletron products. + + The Author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 +*/ + +/* Routines for the NatSemi-based designs (NE[12]000). */ + +static char *version = + "ne.c:v0.99-14a 12/3/93 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "8390.h" + +#define NE_BASE (dev->base_addr) +#define NE_CMD 0x00 +#define NE_DATAPORT 0x10 /* NatSemi-defined port window offset. */ +#define NE_RESET 0x1f /* Issue a read to reset, a write to clear. */ + +#define NE1SM_START_PG 0x20 /* First page of TX buffer */ +#define NE1SM_STOP_PG 0x40 /* Last page +1 of RX ring */ +#define NESM_START_PG 0x40 /* First page of TX buffer */ +#define NESM_STOP_PG 0x80 /* Last page +1 of RX ring */ + +int ne_probe(struct device *dev); +static int neprobe1(int ioaddr, struct device *dev, int verbose); + +static void ne_reset_8390(struct device *dev); +static int ne_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void ne_block_output(struct device *dev, const int count, + const unsigned char *buf, const int start_page); + + +/* Probe for various non-shared-memory ethercards. + + NEx000-clone boards have a Station Address PROM (SAPROM) in the packet + buffer memory space. NE2000 clones have 0x57,0x57 in bytes 0x0e,0x0f of + the SAPROM, while other supposed NE2000 clones must be detected by their + SA prefix. + + Reading the SAPROM from a word-wide card with the 8390 set in byte-wide + mode results in doubled values, which can be detected and compansated for. + + The probe is also responsible for initializing the card and filling + in the 'dev' and 'ei_status' structures. + + We use the minimum memory size for some ethercard product lines, iff we can't + distinguish models. You can increase the packet buffer size by setting + PACKETBUF_MEMSIZE. Reported Cabletron packet buffer locations are: + E1010 starts at 0x100 and ends at 0x2000. + E1010-x starts at 0x100 and ends at 0x8000. ("-x" means "more memory") + E2010 starts at 0x100 and ends at 0x4000. + E2010-x starts at 0x100 and ends at 0xffff. */ + +int ne_probe(struct device *dev) +{ + int *port, ports[] = {0x300, 0x280, 0x320, 0x340, 0x360, 0}; + short ioaddr = dev->base_addr; + + if (ioaddr < 0) + return ENXIO; /* Don't probe at all. */ + if (ioaddr > 0x100) + return ! neprobe1(ioaddr, dev, 1); + + for (port = &ports[0]; *port; port++) { +#ifdef HAVE_PORTRESERVE + if (check_region(*port, 32)) + continue; +#endif + if (inb_p(*port) != 0xff && neprobe1(*port, dev, 0)) { + dev->base_addr = *port; + return 0; + } + } + dev->base_addr = ioaddr; + return ENODEV; +} + +static int neprobe1(int ioaddr, struct device *dev, int verbose) +{ + int i; + unsigned char SA_prom[32]; + int wordlength = 2; + char *name; + int start_page, stop_page; + int neX000, ctron, dlink, dfi; + int reg0 = inb(ioaddr); + + if ( reg0 == 0xFF) + return 0; + + /* Do a quick preliminary check that we have a 8390. */ + { int regd; + outb_p(E8390_NODMA+E8390_PAGE1+E8390_STOP, ioaddr + E8390_CMD); + regd = inb_p(ioaddr + 0x0d); + outb_p(0xff, ioaddr + 0x0d); + outb_p(E8390_NODMA+E8390_PAGE0, ioaddr + E8390_CMD); + inb_p(ioaddr + EN0_COUNTER0); /* Clear the counter by reading. */ + if (inb_p(ioaddr + EN0_COUNTER0) != 0) { + outb_p(reg0, ioaddr); + outb(regd, ioaddr + 0x0d); /* Restore the old values. */ + return 0; + } + } + + printk("NE*000 ethercard probe at %#3x:", ioaddr); + + /* Read the 16 bytes of station address prom, returning 1 for + an eight-bit interface and 2 for a 16-bit interface. + We must first initialize registers, similar to NS8390_init(eifdev, 0). + We can't reliably read the SAPROM address without this. + (I learned the hard way!). */ + { + struct {unsigned char value, offset; } program_seq[] = { + {E8390_NODMA+E8390_PAGE0+E8390_STOP, E8390_CMD}, /* Select page 0*/ + {0x48, EN0_DCFG}, /* Set byte-wide (0x48) access. */ + {0x00, EN0_RCNTLO}, /* Clear the count regs. */ + {0x00, EN0_RCNTHI}, + {0x00, EN0_IMR}, /* Mask completion irq. */ + {0xFF, EN0_ISR}, + {E8390_RXOFF, EN0_RXCR}, /* 0x20 Set to monitor */ + {E8390_TXOFF, EN0_TXCR}, /* 0x02 and loopback mode. */ + {32, EN0_RCNTLO}, + {0x00, EN0_RCNTHI}, + {0x00, EN0_RSARLO}, /* DMA starting at 0x0000. */ + {0x00, EN0_RSARHI}, + {E8390_RREAD+E8390_START, E8390_CMD}, + }; + for (i = 0; i < sizeof(program_seq)/sizeof(program_seq[0]); i++) + outb_p(program_seq[i].value, ioaddr + program_seq[i].offset); + } + for(i = 0; i < 32 /*sizeof(SA_prom)*/; i+=2) { + SA_prom[i] = inb(ioaddr + NE_DATAPORT); + SA_prom[i+1] = inb(ioaddr + NE_DATAPORT); + if (SA_prom[i] != SA_prom[i+1]) + wordlength = 1; + } + + if (wordlength == 2) { + /* We must set the 8390 for word mode, AND RESET IT. */ + int tmp; + outb_p(0x49, ioaddr + EN0_DCFG); + tmp = inb_p(NE_BASE + NE_RESET); + outb(tmp, NE_BASE + NE_RESET); + /* Un-double the SA_prom values. */ + for (i = 0; i < 16; i++) + SA_prom[i] = SA_prom[i+i]; + } + +#if defined(show_all_SAPROM) + /* If your ethercard isn't detected define this to see the SA_PROM. */ + for(i = 0; i < sizeof(SA_prom); i++) + printk(" %2.2x", SA_prom[i]); +#else + for(i = 0; i < ETHER_ADDR_LEN; i++) { + dev->dev_addr[i] = SA_prom[i]; + printk(" %2.2x", SA_prom[i]); + } +#endif + + neX000 = (SA_prom[14] == 0x57 && SA_prom[15] == 0x57); + ctron = (SA_prom[0] == 0x00 && SA_prom[1] == 0x00 && SA_prom[2] == 0x1d); + dlink = (SA_prom[0] == 0x00 && SA_prom[1] == 0xDE && SA_prom[2] == 0x01); + dfi = (SA_prom[0] == 'D' && SA_prom[1] == 'F' && SA_prom[2] == 'I'); + + /* Set up the rest of the parameters. */ + if (neX000 || dlink || dfi) { + if (wordlength == 2) { + name = dlink ? "DE200" : "NE2000"; + start_page = NESM_START_PG; + stop_page = NESM_STOP_PG; + } else { + name = dlink ? "DE100" : "NE1000"; + start_page = NE1SM_START_PG; + stop_page = NE1SM_STOP_PG; + } + } else if (ctron) { + name = "Cabletron"; + start_page = 0x01; + stop_page = (wordlength == 2) ? 0x40 : 0x20; + } else { + printk(" not found.\n"); + return 0; + } + + if (dev->irq < 2) { + autoirq_setup(0); + outb_p(0x50, ioaddr + EN0_IMR); /* Enable one interrupt. */ + outb_p(0x00, ioaddr + EN0_RCNTLO); + outb_p(0x00, ioaddr + EN0_RCNTHI); + outb_p(E8390_RREAD+E8390_START, ioaddr); /* Trigger it... */ + outb_p(0x00, ioaddr + EN0_IMR); /* Mask it again. */ + dev->irq = autoirq_report(0); + if (ei_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; + + /* Snarf the interrupt now. There's no point in waiting since we cannot + share and the board will usually be enabled. */ + { + int irqval = irqaction (dev->irq, &ei_sigaction); + if (irqval) { + printk (" unable to get IRQ %d (irqval=%d).\n", dev->irq, irqval); + return 0; + } + } + + dev->base_addr = ioaddr; + +#ifdef HAVE_PORTRESERVE + snarf_region(ioaddr, 32); +#endif + + ethdev_init(dev); + printk("\n%s: %s found at %#x, using IRQ %d.\n", + dev->name, name, ioaddr, dev->irq); + + if (ei_debug > 0) + printk(version); + + ei_status.name = name; + ei_status.tx_start_page = start_page; + ei_status.stop_page = stop_page; + ei_status.word16 = (wordlength == 2); + + ei_status.rx_start_page = start_page + TX_PAGES; +#ifdef PACKETBUF_MEMSIZE + /* Allow the packet buffer size to be overridden by know-it-alls. */ + ei_status.stop_page = ei_status.tx_start_page + PACKETBUF_MEMSIZE; +#endif + + ei_status.reset_8390 = &ne_reset_8390; + ei_status.block_input = &ne_block_input; + ei_status.block_output = &ne_block_output; + NS8390_init(dev, 0); + return dev->base_addr; +} + +/* Hard reset the card. This used to pause for the same period that a + 8390 reset command required, but that shouldn't be necessary. */ +static void +ne_reset_8390(struct device *dev) +{ + int tmp = inb_p(NE_BASE + NE_RESET); + int reset_start_time = jiffies; + + if (ei_debug > 1) printk("resetting the 8390 t=%d...", jiffies); + ei_status.txing = 0; + + outb_p(tmp, NE_BASE + NE_RESET); + /* This check _should_not_ be necessary, omit eventually. */ + while ((inb_p(NE_BASE+EN0_ISR) & ENISR_RESET) == 0) + if (jiffies - reset_start_time > 2) { + printk("%s: ne_reset_8390() did not complete.\n", dev->name); + break; + } +} + +/* Block input and output, similar to the Crynwr packet driver. If you + porting to a new ethercard look at the packet driver source for hints. + The NEx000 doesn't share it on-board packet memory -- you have to put + the packet out through the "remote DMA" dataport using outb. */ + +static int +ne_block_input(struct device *dev, int count, char *buf, int ring_offset) +{ + int xfer_count = count; + int nic_base = dev->base_addr; + + if (ei_status.dmaing) { + if (ei_debug > 0) + printk("%s: DMAing conflict in ne_block_input." + "[DMAstat:%1x][irqlock:%1x]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return 0; + } + ei_status.dmaing |= 0x01; + outb_p(E8390_NODMA+E8390_PAGE0+E8390_START, nic_base+ NE_CMD); + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(ring_offset & 0xff, nic_base + EN0_RSARLO); + outb_p(ring_offset >> 8, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + if (ei_status.word16) { + insw(NE_BASE + NE_DATAPORT,buf,count>>1); + if (count & 0x01) + buf[count-1] = inb(NE_BASE + NE_DATAPORT), xfer_count++; + } else { + insb(NE_BASE + NE_DATAPORT, buf, count); + } + + /* This was for the ALPHA version only, but enough people have + encountering problems that it is still here. If you see + this message you either 1) have an slightly imcompatible clone + or 2) have noise/speed problems with your bus. */ + if (ei_debug > 1) { /* DMA termination address check... */ + int addr, tries = 20; + do { + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here + -- it's broken! Check the "DMA" address instead. */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if (((ring_offset + xfer_count) & 0xff) == low) + break; + } while (--tries > 0); + if (tries <= 0) + printk("%s: RX transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, ring_offset + xfer_count, addr); + } + ei_status.dmaing &= ~0x01; + return ring_offset + count; +} + +static void +ne_block_output(struct device *dev, int count, + const unsigned char *buf, const int start_page) +{ + int retries = 0; + int nic_base = NE_BASE; + + /* Round the count up for word writes. Do we need to do this? + What effect will an odd byte count have on the 8390? + I should check someday. */ + if (ei_status.word16 && (count & 0x01)) + count++; + if (ei_status.dmaing) { + if (ei_debug > 0) + printk("%s: DMAing conflict in ne_block_output." + "[DMAstat:%1x][irqlock:%1x]\n", + dev->name, ei_status.dmaing, ei_status.irqlock); + return; + } + ei_status.dmaing |= 0x02; + /* We should already be in page 0, but to be safe... */ + outb_p(E8390_PAGE0+E8390_START+E8390_NODMA, nic_base + NE_CMD); + + retry: +#if defined(rw_bugfix) + /* Handle the read-before-write bug the same way as the + Crynwr packet driver -- the NatSemi method doesn't work. + Actually this doesn't aways work either, but if you have + problems with your NEx000 this is better than nothing! */ + outb_p(0x42, nic_base + EN0_RCNTLO); + outb_p(0x00, nic_base + EN0_RCNTHI); + outb_p(0x42, nic_base + EN0_RSARLO); + outb_p(0x00, nic_base + EN0_RSARHI); + outb_p(E8390_RREAD+E8390_START, nic_base + NE_CMD); + /* Make certain that the dummy read has occured. */ + SLOW_DOWN_IO; + SLOW_DOWN_IO; + SLOW_DOWN_IO; +#endif /* rw_bugfix */ + + /* Now the normal output. */ + outb_p(count & 0xff, nic_base + EN0_RCNTLO); + outb_p(count >> 8, nic_base + EN0_RCNTHI); + outb_p(0x00, nic_base + EN0_RSARLO); + outb_p(start_page, nic_base + EN0_RSARHI); + + outb_p(E8390_RWRITE+E8390_START, nic_base + NE_CMD); + if (ei_status.word16) { + outsw(NE_BASE + NE_DATAPORT, buf, count>>1); + } else { + outsb(NE_BASE + NE_DATAPORT, buf, count); + } + + /* This was for the ALPHA version only, but enough people have + encountering problems that it is still here. */ + if (ei_debug > 1) { /* DMA termination address check... */ + int addr, tries = 20; + do { + /* DON'T check for 'inb_p(EN0_ISR) & ENISR_RDC' here + -- it's broken! Check the "DMA" address instead. */ + int high = inb_p(nic_base + EN0_RSARHI); + int low = inb_p(nic_base + EN0_RSARLO); + addr = (high << 8) + low; + if ((start_page << 8) + count == addr) + break; + } while (--tries > 0); + if (tries <= 0) { + printk("%s: Tx packet transfer address mismatch," + "%#4.4x (expected) vs. %#4.4x (actual).\n", + dev->name, (start_page << 8) + count, addr); + if (retries++ == 0) + goto retry; + } + } + ei_status.dmaing &= ~0x02; + return; +} + + +/* + * Local variables: + * compile-command: "gcc -DKERNEL -Wall -O6 -fomit-frame-pointer -I/usr/src/linux/net/tcp -c ne.c" + * version-control: t + * kept-new-versions: 5 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/net_init.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/net_init.c new file mode 100644 index 000000000..4c15147a0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/net_init.c @@ -0,0 +1,163 @@ +/* netdrv_init.c: Initialization for network devices. */ +/* + 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 contains the initialization for the "pl14+" style ethernet + drivers. It should eventually replace most of drivers/net/Space.c. + It's primary advantage is that it's able to allocate low-memory buffers. + A secondary advantage is that the dangerous NE*000 netcards can reserve + their I/O port region before the SCSI probes start. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include "dev.h" +#include "eth.h" + +/* The network devices currently exist only in the socket namespace, so these + entries are unused. The only ones that make sense are + open start the ethercard + close stop the ethercard + ioctl To get statistics, perhaps set the interface port (AUI, BNC, etc.) + One can also imagine getting raw packets using + read & write + but this is probably better handled by a raw packet socket. + + Given that almost all of these functions are handled in the current + socket-based scheme, putting ethercard devices in /dev/ seems pointless. +*/ + +/* The next device number/name to assign: "eth0", "eth1", etc. */ +static int next_ethdev_number = 0; + +#ifdef NET_MAJOR_NUM +static struct file_operations netcard_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + NULL, /* open */ + NULL, /* release */ + NULL /* fsync */ +}; +#endif + +unsigned long lance_init(unsigned long mem_start, unsigned long mem_end); + +/* + net_dev_init() is our network device initialization routine. + It's called from init/main.c with the start and end of free memory, + and returns the new start of free memory. + */ + +unsigned long net_dev_init (unsigned long mem_start, unsigned long mem_end) +{ + +#ifdef NET_MAJOR_NUM + if (register_chrdev(NET_MAJOR_NUM, "network",&netcard_fops)) + printk("WARNING: Unable to get major %d for the network devices.\n", + NET_MAJOR_NUM); +#endif + +#if defined(CONFIG_LANCE) /* Note this is _not_ CONFIG_AT1500. */ + mem_start = lance_init(mem_start, mem_end); +#endif + + return mem_start; +} + +/* Fill in the fields of the device structure with ethernet-generic values. + + If no device structure is passed, a new one is constructed, complete with + a SIZEOF_PRIVATE private data area. + + If an empty string area is passed as dev->name, or a new structure is made, + a new name string is constructed. The passed string area should be 8 bytes + long. + */ + +struct device *init_etherdev(struct device *dev, int sizeof_private, + unsigned long *mem_startp) +{ + int i; + int new_device = 0; + + if (dev == NULL) { + int alloc_size = sizeof(struct device) + sizeof("eth%d ") + + sizeof_private; + if (mem_startp && *mem_startp ) { + dev = (struct device *)*mem_startp; + *mem_startp += alloc_size; + } else + dev = (struct device *)kmalloc(alloc_size, GFP_KERNEL); + memset(dev, 0, sizeof(alloc_size)); + dev->name = (char *)(dev + 1); + if (sizeof_private) + dev->priv = dev->name + sizeof("eth%d "); + new_device = 1; + } + + if (dev->name && dev->name[0] == '\0') + sprintf(dev->name, "eth%d", next_ethdev_number++); + + 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); + + if (new_device) { + /* Append the device to the device queue. */ + struct device **old_devp = &dev_base; + while ((*old_devp)->next) + old_devp = & (*old_devp)->next; + (*old_devp)->next = dev; + dev->next = 0; + } + return dev; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c net_init.c" + * version-control: t + * kept-new-versions: 5 + * tab-width: 4 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/plip.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/plip.c new file mode 100644 index 000000000..39530dd58 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/plip.c @@ -0,0 +1,835 @@ +/* Plip.c: A parallel port "network" driver for linux. */ +/* + Written 1993 by Donald Becker and TANABE Hiroyasu. + This code is distributed under the GPL. + + The current author is reached as hiro@sanpo.t.u-tokyo.ac.jp . + For more information do 'whois -h whois.nic.ad.jp HT043JP' + + The original author may be reached as becker@super.org or + C/O Supercomputing Research Ctr., 17100 Science Dr., Bowie MD 20715 + + This is parallel port packet pusher. It's actually more general + than the "IP" in its name suggests -- but 'plip' is just such a + great name! + + This driver was first developed by D. Becker, when he was inspired by + Russ Nelson's parallel port packet driver. He also did the update + to 0.99.10. + + It was further developed by Tommy Thorn (tthorn@daimi.aau.dk). + + Recent versions were debugged and maintained by TANABE Hiroyasu. + + Updated for 0.99pl12 by Donald Becker. + + Changes even more Alan Cox + 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 = + "Net2Debugged PLIP 1.01 (from plip.c:v0.15 for 0.99pl12+, 8/11/93)\n"; + +#include + +/* + Sources: + Ideas and protocols came from Russ Nelson's (nelson@crynwr.com) + "parallel.asm" parallel port packet driver. + TANABE Hiroyasu changes the protocol. + The "Crynwr" parallel port standard specifies the following protocol: + send header nibble '8' + type octet '0xfd' or '0xfc' + count-low octet + count-high octet + ... data octets + checksum octet +Each octet is sent as + >4)&0x0F)> + +The cable used is a de facto standard parallel null cable -- sold as +a "LapLink" cable by various places. You'll need a 10-conductor cable to +make one yourself. The wiring is: + INIT 16 - 16 SLCTIN 17 - 17 + GROUND 25 - 25 + D0->ERROR 2 - 15 15 - 2 + D1->SLCT 3 - 13 13 - 3 + D2->PAPOUT 4 - 12 12 - 4 + D3->ACK 5 - 10 10 - 5 + D4->BUSY 6 - 11 11 - 6 + Do not connect the other pins. They are + D5,D6,D7 are 7,8,9 + STROBE is 1, FEED is 14 + extra grounds are 18,19,20,21,22,23,24 +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "eth.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" + +#ifdef PRINTK +#undef PRINTK +#endif +#ifdef PRINTK2 +#undef PRINTK2 +#endif + +#define PLIP_DEBUG /* debugging */ +#undef PLIP_DEBUG2 /* debugging with more varbose report */ + +#ifdef PLIP_DEBUG +#define PRINTK(x) printk x +#else +#define PRINTK(x) /**/ +#endif +#ifdef PLIP_DEBUG2 +#define PRINTK2(x) printk x +#else +#define PRINTK2(x) /**/ +#endif + +/* The map from IRQ number (as passed to the interrupt handler) to + 'struct device'. */ +extern struct device *irq2dev_map[16]; + +/* Network statistics, with the same names as 'struct enet_statistics'. */ +#define netstats enet_statistics + +/* constants */ +#define PAR_DATA 0 +#define PAR_STATUS 1 +#define PAR_CONTROL 2 +#define PLIP_MTU 1600 +#define PLIP_HEADER_TYPE1 0xfd +#define PLIP_HEADER_TYPE2 0xfc + +/* Index to functions, as function prototypes. */ +extern int plip_probe(int ioaddr, struct device *dev); +static int plip_open(struct device *dev); +static int plip_close(struct device *dev); +static int plip_tx_packet(struct sk_buff *skb, struct device *dev); +static int plip_header (unsigned char *buff, struct device *dev, + unsigned short type, unsigned long h_dest, + unsigned long h_source, unsigned len); + +/* variables used internally. */ +#define INITIALTIMEOUTFACTOR 4 +#define MAXTIMEOUTFACTOR 20 +static int timeoutfactor = INITIALTIMEOUTFACTOR; + +/* Routines used internally. */ +static void plip_device_clear(struct device *dev); +static void plip_receiver_error(struct device *dev); +static void plip_set_physicaladdr(struct device *dev, unsigned long ipaddr); +static int plip_addrcmp(struct ethhdr *eth); +static int plip_send_enethdr(struct device *dev, struct ethhdr *eth); +static int plip_rebuild_enethdr(struct device *dev, struct ethhdr *eth, + unsigned char h_dest, unsigned char h_source, + unsigned short type); +static void cold_sleep(int tics); +static void plip_interrupt(int reg_ptr); /* Dispatch from interrupts. */ +static int plip_receive_packet(struct device *dev); +static int plip_send_packet(struct device *dev, unsigned char *buf, int length); +static int plip_send_start(struct device *dev, struct ethhdr *eth); +static void double_timeoutfactor(void); +static struct enet_statistics *plip_get_stats(struct device *dev); + +int +plip_init(struct device *dev) +{ + int port_base = dev->base_addr; + int i; + + /* Check that there is something at base_addr. */ + outb(0x00, port_base + PAR_CONTROL); + outb(0x55, port_base + PAR_DATA); + if (inb(port_base + PAR_DATA) != 0x55) + return -ENODEV; + + /* Alpha testers must have the version number to report bugs. */ +#ifdef PLIP_DEBUG + { + static int version_shown = 0; + if (! version_shown) + printk(version), version_shown++; + } +#endif + + /* Initialize the device structure. */ + dev->priv = kmalloc(sizeof(struct netstats), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct netstats)); + + for (i = 0; i < DEV_NUMBUFFS; i++) + dev->buffs[i] = NULL; + dev->hard_header = &plip_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 = &plip_open; + dev->stop = &plip_close; + dev->hard_start_xmit = &plip_tx_packet; + dev->get_stats = &plip_get_stats; + + /* These are ethernet specific. */ + dev->type = ARPHRD_ETHER; + dev->hard_header_len = ETH_HLEN; + dev->mtu = PLIP_MTU; /* PLIP may later negotiate max pkt size */ + dev->addr_len = ETH_ALEN; + for (i = 0; i < dev->addr_len; i++) { + dev->broadcast[i]=0xff; + dev->dev_addr[i] = 0; + } + printk("%s: configured for parallel port at %#3x, IRQ %d.\n", + dev->name, dev->base_addr, dev->irq); + + /* initialize internal value */ + timeoutfactor = INITIALTIMEOUTFACTOR; + return 0; +} + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'config name>' program is + run. + + This routine gets exclusive access to the parallel port by allocating + its IRQ line. + */ +static int +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; + dev->start = 1; + return 0; +} + +/* The inverse routine to plip_open(). */ +static int +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; +} + +static int +plip_tx_packet(struct sk_buff *skb, struct device *dev) +{ + int ret_val; + + if (dev->tbusy || dev->interrupt) { /* Do timeouts, to avoid hangs. */ + int tickssofar = jiffies - dev->trans_start; + if (tickssofar < 50) + return 1; + printk("%s: transmit timed out\n", dev->name); + /* Try to restart the adaptor. */ + plip_device_clear(dev); + return 0; + } + + /* 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; + } + + /* Pretend we are an ethernet and fill in the header. This could use + a simplified routine someday. */ + if (!skb->arp && dev->rebuild_header(skb->data, dev)) { + skb->dev = dev; + arp_queue (skb); + return 0; + } + skb->arp=1; + + dev->trans_start = jiffies; + ret_val = plip_send_packet(dev, skb->data, skb->len); + if (skb->free) + kfree_skb (skb, FREE_WRITE); + dev->tbusy = 0; + mark_bh (INET_BH); + return 0/*ret_val*/; +} + +static int +plip_header (unsigned char *buff, struct device *dev, + unsigned short type, unsigned long h_dest, + unsigned long h_source, unsigned len) +{ + if (dev->dev_addr[0] == 0) { + /* set physical address */ + plip_set_physicaladdr(dev, h_source); + } + return eth_header(buff, dev, type, h_dest, h_source, len); +} + +static void + plip_device_clear(struct device *dev) +{ + dev->interrupt = 0; + dev->tbusy = 0; + outb(0x00, dev->base_addr + PAR_DATA); + outb(0x10, dev->base_addr + PAR_CONTROL); /* Enable the rx interrupt. */ +} + +static void + plip_receiver_error(struct device *dev) +{ + dev->interrupt = 0; + dev->tbusy = 0; + outb(0x02, dev->base_addr + PAR_DATA); + outb(0x10, dev->base_addr + PAR_CONTROL); /* Enable the rx interrupt. */ +} + +static int + get_byte(struct device *dev) +{ + unsigned char val, oldval; + unsigned char low_nibble; + int timeout; + int error = 0; + val = inb(dev->base_addr + PAR_STATUS); + timeout = jiffies + timeoutfactor * 2; + do { + oldval = val; + val = inb(dev->base_addr + PAR_STATUS); + if ( oldval != val ) continue; /* it's unstable */ + if ( timeout < jiffies ) { + error++; + break; + } + } while ( (val & 0x80) ); + val = inb(dev->base_addr + PAR_STATUS); + low_nibble = (val >> 3) & 0x0f; + outb(0x11, dev->base_addr + PAR_DATA); + timeout = jiffies + timeoutfactor * 2; + do { + oldval = val; + val = inb(dev->base_addr + PAR_STATUS); + if (oldval != val) continue; /* it's unstable */ + if ( timeout < jiffies ) { + error++; + break; + } + } while ( !(val & 0x80) ); + val = inb(dev->base_addr + PAR_STATUS); + PRINTK2(("%02x %s ", low_nibble | ((val << 1) & 0xf0), + error ? "t":"")); + outb(0x01, dev->base_addr + PAR_DATA); + if (error) { + /* timeout error */ + double_timeoutfactor(); + return -1; + } + return low_nibble | ((val << 1) & 0xf0); +} + +/* The typical workload of the driver: + Handle the parallel port interrupts. */ +static void + plip_interrupt(int reg_ptr) +{ + int irq = -(((struct pt_regs *)reg_ptr)->orig_eax+2); + struct device *dev = irq2dev_map[irq]; + struct netstats *localstats; + + if (dev == NULL) { + PRINTK(("plip_interrupt(): irq %d for unknown device.\n", irq)); + return; + } + localstats = (struct netstats*) dev->priv; + if (dev->tbusy || dev->interrupt) return; + dev->interrupt = 1; + outb(0x00, dev->base_addr + PAR_CONTROL); /* Disable the rx interrupt. */ + sti(); /* Allow other interrupts. */ + PRINTK2(("%s: interrupt. ", dev->name)); + + { + /* check whether the interrupt is valid or not.*/ + int timeout = jiffies + timeoutfactor; + while ((inb(dev->base_addr + PAR_STATUS) & 0xf8) != 0xc0) { + if ( timeout < jiffies ) { + PRINTK2(("%s: No interrupt (status=%#02x)!\n", + dev->name, inb(dev->base_addr + PAR_STATUS))); + plip_device_clear(dev); + return; + } + } + } + if (plip_receive_packet(dev)) { + /* get some error while receiving data */ + localstats->rx_errors++; + plip_receiver_error(dev); + } else { + plip_device_clear(dev); + } +} + +static int +plip_receive_packet(struct device *dev) +{ + int plip_type; + unsigned length; + int checksum = 0; + struct sk_buff *skb; + struct netstats *localstats; + struct ethhdr eth; + + localstats = (struct netstats*) dev->priv; + + outb(1, dev->base_addr + PAR_DATA); /* Ack: 'Ready' */ + + { + /* get header octet and length of packet */ + plip_type = get_byte(dev); + if (plip_type < 0) return 1; /* probably wrong interrupt */ + length = get_byte(dev) << 8; + length |= get_byte(dev); + switch ( plip_type ) { + case PLIP_HEADER_TYPE1: + { + int i; + unsigned char *eth_p = (unsigned char*)ð + for ( i = 0; i < sizeof(eth); i++, eth_p++) { + *eth_p = get_byte(dev); + } + } + break; + case PLIP_HEADER_TYPE2: + { + unsigned char h_dest, h_source; + unsigned short type; + h_dest = get_byte(dev); + h_source = get_byte(dev); + type = get_byte(dev) << 8; + type |= get_byte(dev); + plip_rebuild_enethdr(dev, ð, h_dest, h_source, type); + } + break; + default: + PRINTK(("%s: wrong header octet\n", dev->name)); + } + PRINTK2(("length = %d\n", length)); + if (length > dev->mtu || length < 8) { + PRINTK2(("%s: bogus packet size %d.\n", dev->name, length)); + return 1; + } + } + { + /* get skb area from kernel and + * set appropriate values to skb + */ + int sksize; + sksize = sizeof(struct sk_buff) + length; + skb = alloc_skb(sksize, GFP_ATOMIC); + if (skb == NULL) { + PRINTK(("%s: Couldn't allocate a sk_buff of size %d.\n", + dev->name, sksize)); + return 1; + } + skb->lock = 0; + skb->mem_len = sksize; + skb->mem_addr = skb; + } + { + /* phase of receiving the data */ + /* 'skb->data' points to the start of sk_buff data area. */ + unsigned char *buf = skb->data; + unsigned char *eth_p = (unsigned char *)ð + int i; + for ( i = 0; i < sizeof(eth); i++) { + checksum += *eth_p; + *buf++ = *eth_p++; + } + for ( i = 0; i < length - sizeof(eth); i++) { + unsigned char new_byte = get_byte(dev); + checksum += new_byte; + *buf++ = new_byte; + } + checksum &= 0xff; + if (checksum != get_byte(dev)) { + localstats->rx_crc_errors++; + PRINTK(("checksum error\n")); + return 1; + } else if(dev_rint((unsigned char *)skb, length, IN_SKBUFF, dev)) { + printk("%s: rcv buff full.\n", dev->name); + localstats->rx_dropped++; + return 1; + } + } + { + /* phase of terminating this connection */ + int timeout; + + timeout = jiffies + length * timeoutfactor / 16; + outb(0x00, dev->base_addr + PAR_DATA); + /* Wait for the remote end to reset. */ + while ( (inb(dev->base_addr + PAR_STATUS) & 0xf8) != 0x80 ) { + if (timeout < jiffies ) { + double_timeoutfactor(); + PRINTK(("Remote has not reset.\n")); + break; + } + } + } + localstats->rx_packets++; + return 0; +} + + +static int send_byte(struct device *dev, unsigned char val) +{ + int timeout; + int error = 0; + if (!(inb(dev->base_addr+PAR_STATUS) & 0x08)) { + PRINTK(("remote end become unready while sending\n")); + return -1; + } + PRINTK2((" S%02x", val)); + outb(val, dev->base_addr); /* this makes data bits more stable */ + outb(0x10 | val, dev->base_addr); + timeout = jiffies + timeoutfactor; + while( inb(dev->base_addr+PAR_STATUS) & 0x80 ) + if ( timeout < jiffies ) { + error++; + break; + } + outb(0x10 | (val >> 4), dev->base_addr); + outb(val >> 4, dev->base_addr); + timeout = jiffies + timeoutfactor; + while( (inb(dev->base_addr+PAR_STATUS) & 0x80) == 0 ) + if ( timeout < jiffies ) { + error++; + break; + } + if (error) { + /* timeout error */ + double_timeoutfactor(); + PRINTK2(("t")); + return -1; + } + return 0; +} +/* + * plip_send_start + * trigger remoto rx interrupt and establish a connection. + * + * return value + * 0 : establish the connection + * -1 : connection failed. + */ +static int +plip_send_start(struct device *dev, struct ethhdr *eth) +{ + int timeout; + int status; + int lasttrigger; + struct netstats *localstats = (struct netstats*) dev->priv; + + /* This starts the packet protocol by triggering a remote IRQ. */ + timeout = jiffies + timeoutfactor * 16; + lasttrigger = jiffies; + while ( ((status = inb(dev->base_addr+PAR_STATUS)) & 0x08) == 0 ) { + dev->tbusy = 1; + outb(0x00, dev->base_addr + PAR_CONTROL); /* Disable my rx intr. */ + outb(0x08, dev->base_addr + PAR_DATA); /* Trigger remote rx intr. */ + if (status & 0x40) { + /* The remote end is also trying to send a packet. + * Only one end may go to the receiving phase, + * so we use the "ethernet" address (set from the IP address) + * to determine which end dominates. + */ + if ( plip_addrcmp(eth) > 0 ) { + localstats->collisions++; + PRINTK2(("both ends are trying to send a packet.\n")); + if (plip_receive_packet(dev)) { + /* get some error while receiving data */ + localstats->rx_errors++; + outb(0x02, dev->base_addr + PAR_DATA); + } else { + outb(0x00, dev->base_addr + PAR_DATA); + } + cold_sleep(2); /* make sure that remote end is ready */ + } + continue; /* restart send sequence */ + } + if (lasttrigger != jiffies) { + /* trigger again */ + outb(0x00, dev->base_addr + PAR_DATA); + cold_sleep(1); + lasttrigger = jiffies; + } + if (timeout < jiffies) { + double_timeoutfactor(); + plip_device_clear(dev); + localstats->tx_errors++; + PRINTK(("%s: Connect failed in send_packet().\n", + dev->name)); + /* We failed to send the packet. To emulate the ethernet we + should pretent the send worked fine */ + return -1; + } + } + return 0; +} +static int +plip_send_packet(struct device *dev, unsigned char *buf, int length) +{ + int error = 0; + int plip_type; + struct netstats *localstats; + + PRINTK2(("%s: plip_send_packet(%d) %02x %02x %02x %02x %02x...", + dev->name, length, buf[0], buf[1], buf[2], buf[3], buf[4])); + if (length > dev->mtu) { + printk("%s: packet too big, %d.\n", dev->name, length); + return 0; + } + localstats = (struct netstats*) dev->priv; + + { + /* phase of checking remote status */ + int i; + int timeout = jiffies + timeoutfactor * 8; + while ( (i = (inb(dev->base_addr+PAR_STATUS) & 0xe8)) != 0x80 ) { + if (i == 0x78) { + /* probably cable is not connected */ + /* Implementation Note: + * This status should result in 'Network unreachable'. + * but I don't know the way. + */ + return 0; + } + if (timeout < jiffies) { + /* remote end is not ready */ + double_timeoutfactor(); + localstats->tx_errors++; + PRINTK(("remote end is not ready.\n")); + return 1; /* Failed to send the packet */ + } + } + } + /* phase of making a connection */ + if (plip_send_start(dev, (struct ethhdr *)buf) < 0) + return 1; + + /* select plip type */ + { + /* Use stripped ethernet header if each first 5 octet of eth + * address is same. + */ + int i; + struct ethhdr *eth = (struct ethhdr *)buf; + + plip_type = PLIP_HEADER_TYPE2; + for ( i = 0; i < ETH_ALEN - 1; i++) + if (eth->h_dest[i] != eth->h_source[i]) + plip_type = PLIP_HEADER_TYPE1; + } + + send_byte(dev, plip_type); /* send header octet */ + + { + /* send packet's length */ + /* + * in original plip (before v0.1), it was sent with little endian. + * but in internet, network byteorder is big endian, + * so changed to use big endian. + * maybe using 'ntos()' is better. + */ + send_byte(dev, length >> 8); send_byte(dev, length); + } + { + /* phase of sending data */ + int i; + int checksum = 0; + + if (plip_type == PLIP_HEADER_TYPE2) { + plip_send_enethdr(dev, (struct ethhdr*)buf); + } + for ( i = 0; i < sizeof(struct ethhdr); i++ ) { + if (plip_type == PLIP_HEADER_TYPE1) { + send_byte(dev, *buf); + } + checksum += *buf++; + } + + for (i = 0; i < length - sizeof(struct ethhdr); i++) { + checksum += buf[i]; + if (send_byte(dev, buf[i]) < 0) { + error++; + break; + } + } + send_byte(dev, checksum & 0xff); + } + { + /* phase of terminating this connection */ + int timeout; + + outb(0x00, dev->base_addr + PAR_DATA); + /* Wait for the remote end to reset. */ + timeout = jiffies + ((length * timeoutfactor) >> 4); + while ((inb(dev->base_addr + PAR_STATUS) & 0xe8) != 0x80) { + if (timeout < jiffies ) { + double_timeoutfactor(); + PRINTK(("Remote end has not reset.\n")); + error++; + break; + } + } + if (inb(dev->base_addr + PAR_STATUS) & 0x10) { + /* receiver reports error */ + error++; + } + } + plip_device_clear(dev); + localstats->tx_packets++; + PRINTK2(("plip_send_packet(%d) done.\n", length)); + return error?1:0; +} + +/* + * some trivial functions + */ +static void +plip_set_physicaladdr(struct device *dev, unsigned long ipaddr) +{ + /* + * set physical address to + * 0xfd.0xfd.ipaddr + */ + + unsigned char *addr = dev->dev_addr; + int i; + + if ((ipaddr >> 24) == 0 || (ipaddr >> 24) == 0xff) return; + PRINTK2(("%s: set physical address to %08x\n", dev->name, ipaddr)); + for (i=0; i < ETH_ALEN - sizeof(unsigned long); i++) { + addr[i] = 0xfd; + } + memcpy(&(addr[i]), &ipaddr, sizeof(unsigned long)); +} + +static int +plip_addrcmp(struct ethhdr *eth) +{ + int i; + for ( i = ETH_ALEN - 1; i >= 0; i-- ) { + if (eth->h_dest[i] > eth->h_source[i]) return -1; + if (eth->h_dest[i] < eth->h_source[i]) return 1; + } + PRINTK2(("h_dest = %08x%04x h_source = %08x%04x\n", + *(long*)ð->h_dest[2],*(short*)ð->h_dest[0], + *(long*)ð->h_source[2],*(short*)ð->h_source[0])); + return 0; +} + +static int +plip_send_enethdr(struct device *dev, struct ethhdr *eth) +{ + send_byte(dev, eth->h_dest[ETH_ALEN-1]); + send_byte(dev, eth->h_source[ETH_ALEN-1]); + send_byte(dev, eth->h_proto >> 8); + send_byte(dev, eth->h_proto); + return 0; +} + +static int +plip_rebuild_enethdr(struct device *dev, struct ethhdr *eth, + unsigned char dest, unsigned char source, + unsigned short type) +{ + eth->h_proto = type; + memcpy(eth->h_dest, dev->dev_addr, ETH_ALEN-1); + eth->h_dest[ETH_ALEN-1] = dest; + memcpy(eth->h_source, dev->dev_addr, ETH_ALEN-1); + eth->h_source[ETH_ALEN-1] = source; + return 0; +} + +/* This function is evil, evil, evil. This should be a + _kernel_, rescheduling sleep!. */ +static void +cold_sleep(int tics) +{ + int start = jiffies; + while(jiffies < start + tics) + ; /* do nothing */ + return; +} + +static void + double_timeoutfactor() +{ + timeoutfactor *= 2; + if (timeoutfactor >= MAXTIMEOUTFACTOR) { + timeoutfactor = MAXTIMEOUTFACTOR; + } + return; +} + +static struct enet_statistics * +plip_get_stats(struct device *dev) +{ + struct netstats *localstats = (struct netstats*) dev->priv; + return localstats; +} + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -Wall -O6 -fomit-frame-pointer -x c++ -c plip.c" + * version-control: t + * kept-new-versions: 5 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/skeleton.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/skeleton.c new file mode 100644 index 000000000..b6d047bd5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/skeleton.c @@ -0,0 +1,520 @@ +/* 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, + incorporated 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.05 11/16/93 Donald Becker (becker@super.org)\n"; + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#include + +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "dev.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(addr, size) kfree_s(addr,size); +#endif + +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#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. */ +}; + +/* The number of low I/O ports used by the ethercard. */ +#define ETHERCARD_TOTAL_SIZE 16 + +/* The station (ethernet) address prefix, used for IDing the board. */ +#define SA_ADDR0 0x00 +#define SA_ADDR1 0x42 +#define SA_ADDR2 0x65 + +/* 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; + if (check_region(ioaddr, ETHERCARD_TOTAL_SIZE)) + continue; + if (inb(ioaddr) != 0x57) + continue; + dev->base_addr = ioaddr; + if (netcard_probe1(dev, ioaddr) == 0) + return 0; + } + + dev->base_addr = base_addr; + return ENODEV; +} + +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] != SA_ADDR0 + || station_addr[1] != SA_ADDR1 || station_addr[2] != SA_ADDR2) { + 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 */ + + /* Grab the region so we can find another board if autoIRQ fails. */ + snarf_region(ioaddr, ETHERCARD_TOTAL_SIZE); + + 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->data, 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 = skb->data; + + 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->data' points to the start of sk_buff data area. */ + memcpy(skb->data, (void*)dev->rmem_start, + pkt_len); + /* or */ + insw(ioaddr, skb->data, (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_s(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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.c new file mode 100644 index 000000000..9ba15d019 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.c @@ -0,0 +1,725 @@ +/* + * Routines to compress and uncompress tcp packets (for transmission + * over low speed serial lines). + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation (from 1.19) + * PPP.05 02-15-90 [ks] + * PPP.08 05-02-90 [ks] use PPP protocol field to signal compression + * PPP.15 09-90 [ks] improve mbuf handling + * PPP.16 11-02 [karn] substantially rewritten to use NOS facilities + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "icmp.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" +#include +#include +#include +#include +#include +#include "slhc.h" + +#define DPRINT(x) + +int last_retran; + +static unsigned char *encode(unsigned char *cp,int n); +static long decode(unsigned char **cpp); +static unsigned char * put16(unsigned char *cp, unsigned short x); +static unsigned short pull16(unsigned char **cpp); + +extern int ip_csum(struct iphdr *iph); + + +/* Initialize compression data structure + * slots must be in range 0 to 255 (zero meaning no compression) + */ +struct slcompress * +slhc_init(int rslots, int tslots) +{ + register short i; + register struct cstate *ts; + struct slcompress *comp; + + comp = (struct slcompress *)kmalloc(sizeof(struct slcompress), + GFP_KERNEL); + if (! comp) + return NULL; + + memset(comp, 0, sizeof(struct slcompress)); + + if ( rslots > 0 && rslots < 256 ) { + comp->rstate = + (struct cstate *)kmalloc(rslots * sizeof(struct cstate), + GFP_KERNEL); + if (! comp->rstate) + return NULL; + memset(comp->rstate, 0, rslots * sizeof(struct cstate)); + comp->rslot_limit = rslots - 1; + } + + if ( tslots > 0 && tslots < 256 ) { + comp->tstate = + (struct cstate *)kmalloc(tslots * sizeof(struct cstate), + GFP_KERNEL); + if (! comp->tstate) + return NULL; + memset(comp->tstate, 0, rslots * sizeof(struct cstate)); + comp->tslot_limit = tslots - 1; + } + + comp->xmit_oldest = 0; + comp->xmit_current = 255; + comp->recv_current = 255; + /* + * don't accept any packets with implicit index until we get + * one with an explicit index. Otherwise the uncompress code + * will try to use connection 255, which is almost certainly + * out of range + */ + comp->flags |= SLF_TOSS; + + if ( tslots > 0 ) { + ts = comp->tstate; + for(i = comp->tslot_limit; i > 0; --i){ + ts[i].cs_this = i; + ts[i].next = &(ts[i - 1]); + } + ts[0].next = &(ts[comp->tslot_limit]); + ts[0].cs_this = 0; + } + return comp; +} + + +/* Free a compression data structure */ +void +slhc_free(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return; + + if ( comp->rstate != NULLSLSTATE ) + kfree( comp->rstate ); + + if ( comp->tstate != NULLSLSTATE ) + kfree( comp->tstate ); + + kfree( comp ); +} + + +/* Put a short in host order into a char array in network order */ +static unsigned char * +put16(unsigned char *cp, unsigned short x) +{ + *cp++ = x >> 8; + *cp++ = x; + + return cp; +} + + +/* Encode a number */ +unsigned char * +encode(unsigned char *cp, int n) +{ + if(n >= 256 || n == 0){ + *cp++ = 0; + cp = put16(cp,n); + } else { + *cp++ = n; + } + return cp; +} + +/* Pull a 16-bit integer in host order from buffer in network byte order */ +static unsigned short +pull16(unsigned char **cpp) +{ + short rval; + + rval = *(*cpp)++; + rval <<= 8; + rval |= *(*cpp)++; + return rval; +} + +/* Decode a number */ +long +decode(unsigned char **cpp) +{ + register int x; + + x = *(*cpp)++; + if(x == 0){ + return pull16(cpp) & 0xffff; /* pull16 returns -1 on error */ + } else { + return x & 0xff; /* -1 if PULLCHAR returned error */ + } +} + +/* + * icp and isize are the original packet. + * ocp is a place to put a copy if necessary. + * cpp is initially a pointer to icp. If the copy is used, + * change it to ocp. + */ + +int +slhc_compress(struct slcompress *comp, unsigned char *icp, int isize, + unsigned char *ocp, unsigned char **cpp, int compress_cid) +{ + register struct cstate *ocs = &(comp->tstate[comp->xmit_oldest]); + register struct cstate *lcs = ocs; + register struct cstate *cs = lcs->next; + register unsigned long deltaS, deltaA; + register short changes = 0; + int hlen; + unsigned char new_seq[16]; + register unsigned char *cp = new_seq; + struct iphdr *ip; + struct tcphdr *th, *oth; + + ip = (struct iphdr *) icp; + + /* Bail if this packet isn't TCP, or is an IP fragment */ + if(ip->protocol != IPPROTO_TCP || (ntohs(ip->frag_off) & 0x1fff) || + (ip->frag_off & 32)){ + DPRINT(("comp: noncomp 1 %d %d %d\n", ip->protocol, + ntohs(ip->frag_off), ip->frag_off)); + /* Send as regular IP */ + if(ip->protocol != IPPROTO_TCP) + comp->sls_o_nontcp++; + else + comp->sls_o_tcp++; + return isize; + } + /* Extract TCP header */ + + th = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + hlen = ip->ihl*4 + th->doff*4; + + /* Bail if the TCP packet isn't `compressible' (i.e., ACK isn't set or + * some other control bit is set). + */ + if(th->syn || th->fin || th->rst || + ! (th->ack)){ + DPRINT(("comp: noncomp 2 %x %x %d %d %d %d\n", ip, th, + th->syn, th->fin, th->rst, th->ack)); + /* TCP connection stuff; send as regular IP */ + comp->sls_o_tcp++; + return isize; + } + /* + * Packet is compressible -- we're going to send either a + * COMPRESSED_TCP or UNCOMPRESSED_TCP packet. Either way, + * we need to locate (or create) the connection state. + * + * States are kept in a circularly linked list with + * xmit_oldest pointing to the end of the list. The + * list is kept in lru order by moving a state to the + * head of the list whenever it is referenced. Since + * the list is short and, empirically, the connection + * we want is almost always near the front, we locate + * states via linear search. If we don't find a state + * for the datagram, the oldest state is (re-)used. + */ + for ( ; ; ) { + if( ip->saddr == cs->cs_ip.saddr + && ip->daddr == cs->cs_ip.daddr + && th->source == cs->cs_tcp.source + && th->dest == cs->cs_tcp.dest) + goto found; + + /* if current equal oldest, at end of list */ + if ( cs == ocs ) + break; + lcs = cs; + cs = cs->next; + comp->sls_o_searches++; + }; + /* + * Didn't find it -- re-use oldest cstate. Send an + * uncompressed packet that tells the other side what + * connection number we're using for this conversation. + * + * Note that since the state list is circular, the oldest + * state points to the newest and we only need to set + * xmit_oldest to update the lru linkage. + */ + comp->sls_o_misses++; + comp->xmit_oldest = lcs->cs_this; + DPRINT(("comp: not found\n")); + goto uncompressed; + +found: + /* + * Found it -- move to the front on the connection list. + */ + if(lcs == ocs) { + /* found at most recently used */ + } else if (cs == ocs) { + /* found at least recently used */ + comp->xmit_oldest = lcs->cs_this; + } else { + /* more than 2 elements */ + lcs->next = cs->next; + cs->next = ocs->next; + ocs->next = cs; + } + + /* + * Make sure that only what we expect to change changed. + * Check the following: + * IP protocol version, header length & type of service. + * The "Don't fragment" bit. + * The time-to-live field. + * The TCP header length. + * IP options, if any. + * TCP options, if any. + * If any of these things are different between the previous & + * current datagram, we send the current datagram `uncompressed'. + */ + oth = &cs->cs_tcp; + + if(last_retran + || ip->version != cs->cs_ip.version || ip->ihl != cs->cs_ip.ihl + || ip->tos != cs->cs_ip.tos + || (ip->frag_off & 64) != (cs->cs_ip.frag_off & 64) + || ip->ttl != cs->cs_ip.ttl + || th->doff != cs->cs_tcp.doff + || (ip->ihl > 5 && memcmp(ip+1,cs->cs_ipopt,((ip->ihl)-5)*4) != 0) + || (th->doff > 5 && memcmp(th+1,cs->cs_tcpopt,((th->doff)-5)*4 != 0))){ + DPRINT(("comp: incompat\n")); + goto uncompressed; + } + + /* + * Figure out which of the changing fields changed. The + * receiver expects changes in the order: urgent, window, + * ack, seq (the order minimizes the number of temporaries + * needed in this section of code). + */ + if(th->urg){ + deltaS = ntohs(th->urg_ptr); + cp = encode(cp,deltaS); + changes |= NEW_U; + } else if(th->urg_ptr != oth->urg_ptr){ + /* argh! URG not set but urp changed -- a sensible + * implementation should never do this but RFC793 + * doesn't prohibit the change so we have to deal + * with it. */ + DPRINT(("comp: urg incompat\n")); + goto uncompressed; + } + if((deltaS = ntohs(th->window) - ntohs(oth->window)) != 0){ + cp = encode(cp,deltaS); + changes |= NEW_W; + } + if((deltaA = ntohl(th->ack_seq) - ntohl(oth->ack_seq)) != 0L){ + if(deltaA > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaA); + changes |= NEW_A; + } + if((deltaS = ntohl(th->seq) - ntohl(oth->seq)) != 0L){ + if(deltaS > 0x0000ffff) + goto uncompressed; + cp = encode(cp,deltaS); + changes |= NEW_S; + } + + switch(changes){ + case 0: /* Nothing changed. If this packet contains data and the + * last one didn't, this is probably a data packet following + * an ack (normal on an interactive connection) and we send + * it compressed. Otherwise it's probably a retransmit, + * retransmitted ack or window probe. Send it uncompressed + * in case the other side missed the compressed version. + */ + if(ip->tot_len != cs->cs_ip.tot_len && + ntohs(cs->cs_ip.tot_len) == hlen) + break; + DPRINT(("comp: retrans\n")); + goto uncompressed; + break; + case SPECIAL_I: + case SPECIAL_D: + /* actual changes match one of our special case encodings -- + * send packet uncompressed. + */ + DPRINT(("comp: special\n")); + goto uncompressed; + case NEW_S|NEW_A: + if(deltaS == deltaA && + deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for echoed terminal traffic */ + changes = SPECIAL_I; + cp = new_seq; + } + break; + case NEW_S: + if(deltaS == ntohs(cs->cs_ip.tot_len) - hlen){ + /* special case for data xfer */ + changes = SPECIAL_D; + cp = new_seq; + } + break; + } + deltaS = ntohs(ip->id) - ntohs(cs->cs_ip.id); + if(deltaS != 1){ + cp = encode(cp,deltaS); + changes |= NEW_I; + } + if(th->psh) + changes |= TCP_PUSH_BIT; + /* Grab the cksum before we overwrite it below. Then update our + * state with this packet's header. + */ + deltaA = ntohs(th->check); + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + /* We want to use the original packet as our compressed packet. + * (cp - new_seq) is the number of bytes we need for compressed + * sequence numbers. In addition we need one byte for the change + * mask, one for the connection id and two for the tcp checksum. + * So, (cp - new_seq) + 4 bytes of header are needed. + */ + deltaS = cp - new_seq; + if(compress_cid == 0 || comp->xmit_current != cs->cs_this){ + cp = ocp; + *cpp = ocp; + *cp++ = changes | NEW_C; + *cp++ = cs->cs_this; + comp->xmit_current = cs->cs_this; + } else { + cp = ocp; + *cpp = ocp; + *cp++ = changes; + } + cp = put16(cp,(short)deltaA); /* Write TCP checksum */ +/* deltaS is now the size of the change section of the compressed header */ + DPRINT(("comp: %x %x %x %d %d\n", icp, cp, new_seq, hlen, deltaS)); + memcpy(cp,new_seq,deltaS); /* Write list of deltas */ + memcpy(cp+deltaS,icp+hlen,isize-hlen); + comp->sls_o_compressed++; + ocp[0] |= SL_TYPE_COMPRESSED_TCP; + return isize - hlen + deltaS + (cp - ocp); + + /* Update connection state cs & send uncompressed packet (i.e., + * a regular ip/tcp packet but with the 'conversation id' we hope + * to use on future compressed packets in the protocol field). + */ +uncompressed: + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,th,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (th->doff > 5) + memcpy(cs->cs_tcpopt, th+1, ((th->doff) - 5) * 4); + comp->xmit_current = cs->cs_this; + comp->sls_o_uncompressed++; + memcpy(ocp, icp, isize); + *cpp = ocp; + ocp[9] = cs->cs_this; + ocp[0] |= SL_TYPE_UNCOMPRESSED_TCP; + return isize; +} + + +int +slhc_uncompress(struct slcompress *comp, unsigned char *icp, int isize) +{ + register int changes; + long x; + register struct tcphdr *thp; + register struct iphdr *ip; + register struct cstate *cs; + int len, hdrlen; + unsigned char *cp = icp; + + /* We've got a compressed packet; read the change byte */ + comp->sls_i_compressed++; + if(isize < 3){ + comp->sls_i_error++; + DPRINT(("uncomp: runt\n")); + return 0; + } + changes = *cp++; + if(changes & NEW_C){ + /* Make sure the state index is in range, then grab the state. + * If we have a good state index, clear the 'discard' flag. + */ + x = *cp++; /* Read conn index */ + if(x < 0 || x > comp->rslot_limit) + goto bad; + + comp->flags &=~ SLF_TOSS; + comp->recv_current = x; + } else { + /* this packet has an implicit state index. If we've + * had a line error since the last time we got an + * explicit state index, we have to toss the packet. */ + if(comp->flags & SLF_TOSS){ + comp->sls_i_tossed++; + DPRINT(("uncomp: toss\n")); + return 0; + } + } + cs = &comp->rstate[comp->recv_current]; + thp = &cs->cs_tcp; + ip = &cs->cs_ip; + + if((x = pull16(&cp)) == -1) { /* Read the TCP checksum */ + DPRINT(("uncomp: bad tcp chk\n")); + goto bad; + } + thp->check = htons(x); + + thp->psh = (changes & TCP_PUSH_BIT) ? 1 : 0; +/* + * we can use the same number for the length of the saved header and + * the current one, because the packet wouldn't have been sent + * as compressed unless the options were the same as the previous one + */ + + hdrlen = ip->ihl * 4 + thp->doff * 4; + + switch(changes & SPECIALS_MASK){ + case SPECIAL_I: /* Echoed terminal traffic */ + { + register short i; + i = ntohs(ip->tot_len) - hdrlen; + thp->ack_seq = htonl( ntohl(thp->ack_seq) + i); + thp->seq = htonl( ntohl(thp->seq) + i); + } + break; + + case SPECIAL_D: /* Unidirectional data */ + thp->seq = htonl( ntohl(thp->seq) + + ntohs(ip->tot_len) - hdrlen); + break; + + default: + if(changes & NEW_U){ + thp->urg = 1; + if((x = decode(&cp)) == -1) { + DPRINT(("uncomp: bad U\n")); + goto bad; + } + thp->urg_ptr = htons(x); + } else + thp->urg = 0; + if(changes & NEW_W){ + if((x = decode(&cp)) == -1) { + DPRINT(("uncomp: bad W\n")); + goto bad; + } + thp->window = htons( ntohs(thp->window) + x); + } + if(changes & NEW_A){ + if((x = decode(&cp)) == -1) { + DPRINT(("uncomp: bad A\n")); + goto bad; + } + thp->ack_seq = htonl( ntohl(thp->ack_seq) + x); + } + if(changes & NEW_S){ + if((x = decode(&cp)) == -1) { + DPRINT(("uncomp: bad S\n")); + goto bad; + } + thp->seq = htonl( ntohl(thp->seq) + x); + } + break; + } + if(changes & NEW_I){ + if((x = decode(&cp)) == -1) { + DPRINT(("uncomp: bad I\n")); + goto bad; + } + ip->id = htons (ntohs (ip->id) + x); + } else + ip->id = htons (ntohs (ip->id) + 1); + + /* + * At this point, cp points to the first byte of data in the + * packet. Put the reconstructed TCP and IP headers back on the + * packet. Recalculate IP checksum (but not TCP checksum). + */ + + len = isize - (cp - icp); + if (len < 0) + goto bad; + len += hdrlen; + ip->tot_len = htons(len); + ip->check = 0; + + DPRINT(("uncomp: %d %d %d %d\n", cp - icp, hdrlen, isize, len)); + + memmove(icp + hdrlen, cp, len - hdrlen); + + cp = icp; + memcpy(cp, ip, 20); + cp += 20; + + if (ip->ihl > 5) { + memcpy(cp, cs->cs_ipopt, ((ip->ihl) - 5) * 4); + cp += ((ip->ihl) - 5) * 4; + } + + ((struct iphdr *)icp)->check = ip_csum((struct iphdr*)icp); + + memcpy(cp, thp, 20); + cp += 20; + + if (thp->doff > 5) { + memcpy(cp, cs->cs_tcpopt, ((thp->doff) - 5) * 4); + cp += ((thp->doff) - 5) * 4; + } + +if (inet_debug == DBG_SLIP) printk("\runcomp: change %x len %d\n", changes, len); + return len; +bad: + comp->sls_i_error++; + return slhc_toss( comp ); +} + + +int +slhc_remember(struct slcompress *comp, unsigned char *icp, int isize) +{ + register struct cstate *cs; + short ip_len; + struct iphdr *ip; + struct tcphdr *thp; + + unsigned char index; + + if(isize < 20) { + /* The packet is shorter than a legal IP header */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + /* Sneak a peek at the IP header's IHL field to find its length */ + ip_len = (icp[0] & 0xf) << 2; + if(ip_len < 20){ + /* The IP header length field is too small */ + comp->sls_i_runt++; + return slhc_toss( comp ); + } + index = icp[9]; + icp[9] = IPPROTO_TCP; + ip = (struct iphdr *) icp; + + if (ip_csum(ip)) { + /* Bad IP header checksum; discard */ + comp->sls_i_badcheck++; + return slhc_toss( comp ); + } + thp = (struct tcphdr *)(((unsigned char *)ip) + ip->ihl*4); + if(index > comp->rslot_limit) { + comp->sls_i_error++; + return slhc_toss(comp); + } + + /* Update local state */ + cs = &comp->rstate[comp->recv_current = index]; + comp->flags &=~ SLF_TOSS; + memcpy(&cs->cs_ip,ip,20); + memcpy(&cs->cs_tcp,thp,20); + if (ip->ihl > 5) + memcpy(cs->cs_ipopt, ip+1, ((ip->ihl) - 5) * 4); + if (thp->doff > 5) + memcpy(cs->cs_tcpopt, thp+1, ((thp->doff) - 5) * 4); + cs->cs_hsize = ip->ihl*2 + thp->doff*2; + /* Put headers back on packet + * Neither header checksum is recalculated + */ + comp->sls_i_uncompressed++; + return isize; +} + + +int +slhc_toss(struct slcompress *comp) +{ + if ( comp == NULLSLCOMPR ) + return 0; + + comp->flags |= SLF_TOSS; + return 0; +} + + +void slhc_i_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%ld Cmp, %ld Uncmp, %ld Bad, %ld Tossed\n", + comp->sls_i_compressed, + comp->sls_i_uncompressed, + comp->sls_i_error, + comp->sls_i_tossed); + } +} + + +void slhc_o_status(struct slcompress *comp) +{ + if (comp != NULLSLCOMPR) { + printk("\t%ld Cmp, %ld Uncmp, %ld AsIs, %ld NotTCP\n", + comp->sls_o_compressed, + comp->sls_o_uncompressed, + comp->sls_o_tcp, + comp->sls_o_nontcp); + printk("\t%10ld Searches, %10ld Misses\n", + comp->sls_o_searches, + comp->sls_o_misses); + } +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.h new file mode 100644 index 000000000..0044b0283 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slhc.h @@ -0,0 +1,187 @@ +#ifndef _SLHC_H +#define _SLHC_H +/* + * Definitions for tcp compression routines. + * + * $Header: slcompress.h,v 1.10 89/12/31 08:53:02 van Exp $ + * + * Copyright (c) 1989 Regents of the University of California. + * All rights reserved. + * + * Redistribution and use in source and binary forms are permitted + * provided that the above copyright notice and this paragraph are + * duplicated in all such forms and that any documentation, + * advertising materials, and other materials related to such + * distribution and use acknowledge that the software was developed + * by the University of California, Berkeley. The name of the + * University may not be used to endorse or promote products derived + * from this software without specific prior written permission. + * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED + * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. + * + * Van Jacobson (van@helios.ee.lbl.gov), Dec 31, 1989: + * - Initial distribution. + * + * + * modified for KA9Q Internet Software Package by + * Katie Stevens (dkstevens@ucdavis.edu) + * University of California, Davis + * Computing Services + * - 01-31-90 initial adaptation + * + * - Feb 1991 Bill_Simpson@um.cc.umich.edu + * variable number of conversation slots + * allow zero or one slots + * separate routines + * status display + */ + +/* + * Compressed packet format: + * + * The first octet contains the packet type (top 3 bits), TCP + * 'push' bit, and flags that indicate which of the 4 TCP sequence + * numbers have changed (bottom 5 bits). The next octet is a + * conversation number that associates a saved IP/TCP header with + * the compressed packet. The next two octets are the TCP checksum + * from the original datagram. The next 0 to 15 octets are + * sequence number changes, one change per bit set in the header + * (there may be no changes and there are two special cases where + * the receiver implicitly knows what changed -- see below). + * + * There are 5 numbers which can change (they are always inserted + * in the following order): TCP urgent pointer, window, + * acknowlegement, sequence number and IP ID. (The urgent pointer + * is different from the others in that its value is sent, not the + * change in value.) Since typical use of SLIP links is biased + * toward small packets (see comments on MTU/MSS below), changes + * use a variable length coding with one octet for numbers in the + * range 1 - 255 and 3 octets (0, MSB, LSB) for numbers in the + * range 256 - 65535 or 0. (If the change in sequence number or + * ack is more than 65535, an uncompressed packet is sent.) + */ + +/* + * Packet types (must not conflict with IP protocol version) + * + * The top nibble of the first octet is the packet type. There are + * three possible types: IP (not proto TCP or tcp with one of the + * control flags set); uncompressed TCP (a normal IP/TCP packet but + * with the 8-bit protocol field replaced by an 8-bit connection id -- + * this type of packet syncs the sender & receiver); and compressed + * TCP (described above). + * + * LSB of 4-bit field is TCP "PUSH" bit (a worthless anachronism) and + * is logically part of the 4-bit "changes" field that follows. Top + * three bits are actual packet type. For backward compatibility + * and in the interest of conserving bits, numbers are chosen so the + * IP protocol version number (4) which normally appears in this nibble + * means "IP packet". + */ + +/* SLIP compression masks for len/vers byte */ +#define SL_TYPE_IP 0x40 +#define SL_TYPE_UNCOMPRESSED_TCP 0x70 +#define SL_TYPE_COMPRESSED_TCP 0x80 +#define SL_TYPE_ERROR 0x00 + +/* Bits in first octet of compressed packet */ +#define NEW_C 0x40 /* flag bits for what changed in a packet */ +#define NEW_I 0x20 +#define NEW_S 0x08 +#define NEW_A 0x04 +#define NEW_W 0x02 +#define NEW_U 0x01 + +/* reserved, special-case values of above */ +#define SPECIAL_I (NEW_S|NEW_W|NEW_U) /* echoed interactive traffic */ +#define SPECIAL_D (NEW_S|NEW_A|NEW_W|NEW_U) /* unidirectional data */ +#define SPECIALS_MASK (NEW_S|NEW_A|NEW_W|NEW_U) + +#define TCP_PUSH_BIT 0x10 + +/* + * data type and sizes conversion assumptions: + * + * VJ code KA9Q style generic + * u_char byte_t unsigned char 8 bits + * u_short int16 unsigned short 16 bits + * u_int int16 unsigned short 16 bits + * u_long unsigned long unsigned long 32 bits + * int int32 long 32 bits + */ + +typedef unsigned char byte_t; +typedef unsigned long int32; + +/* + * "state" data for each active tcp conversation on the wire. This is + * basically a copy of the entire IP/TCP header from the last packet + * we saw from the conversation together with a small identifier + * the transmit & receive ends of the line use to locate saved header. + */ +struct cstate { + byte_t cs_this; /* connection id number (xmit) */ + struct cstate *next; /* next in ring (xmit) */ + struct iphdr cs_ip; /* ip/tcp hdr from most recent packet */ + struct tcphdr cs_tcp; + unsigned char cs_ipopt[64]; + unsigned char cs_tcpopt[64]; + int cs_hsize; +}; +#define NULLSLSTATE (struct cstate *)0 + +/* + * all the state data for one serial line (we need one of these per line). + */ +struct slcompress { + struct cstate *tstate; /* transmit connection states (array)*/ + struct cstate *rstate; /* receive connection states (array)*/ + + byte_t tslot_limit; /* highest transmit slot id (0-l)*/ + byte_t rslot_limit; /* highest receive slot id (0-l)*/ + + byte_t xmit_oldest; /* oldest xmit in ring */ + byte_t xmit_current; /* most recent xmit id */ + byte_t recv_current; /* most recent rcvd id */ + + byte_t flags; +#define SLF_TOSS 0x01 /* tossing rcvd frames until id received */ + + int32 sls_o_nontcp; /* outbound non-TCP packets */ + int32 sls_o_tcp; /* outbound TCP packets */ + int32 sls_o_uncompressed; /* outbound uncompressed packets */ + int32 sls_o_compressed; /* outbound compressed packets */ + int32 sls_o_searches; /* searches for connection state */ + int32 sls_o_misses; /* times couldn't find conn. state */ + + int32 sls_i_uncompressed; /* inbound uncompressed packets */ + int32 sls_i_compressed; /* inbound compressed packets */ + int32 sls_i_error; /* inbound error packets */ + int32 sls_i_tossed; /* inbound packets tossed because of error */ + + int32 sls_i_runt; + int32 sls_i_badcheck; +}; +#define NULLSLCOMPR (struct slcompress *)0 + +#define __ARGS(x) x + +/* In slhc.c: */ +struct slcompress *slhc_init __ARGS((int rslots, int tslots)); +void slhc_free __ARGS((struct slcompress *comp)); + +int slhc_compress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize, unsigned char *ocp, unsigned char **cpp, + int compress_cid)); +int slhc_uncompress __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_remember __ARGS((struct slcompress *comp, unsigned char *icp, + int isize)); +int slhc_toss __ARGS((struct slcompress *comp)); + +void slhc_i_status __ARGS((struct slcompress *comp)); +void slhc_o_status __ARGS((struct slcompress *comp)); + +#endif /* _SLHC_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.c new file mode 100644 index 000000000..514fa8ceb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.c @@ -0,0 +1,1196 @@ +/* + * slip.c This module implements the SLIP protocol for kernel-based + * devices like TTY. It interfaces between a raw TTY, and the + * kernel's INET protocol layers (via DDI). + * + * Version: @(#)slip.c 0.7.6 05/25/93 + * + * Authors: Laurence Culhane, + * Fred N. van Kempen, + * + * 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. + * Matt Dillon : Printable slip (borrowed from NET2E) + * Pauline Middelink : Slip driver fixes. + * Alan Cox : Honours the old SL_COMPRESSED flag + * Alan Cox : KISS AX.25 and AXUI IP support + * Michael Riepe : Automatic CSLIP recognition added + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#ifdef CONFIG_AX25 +#include "ax25.h" +#endif +#include "eth.h" +#include "ip.h" +#include "route.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" +#include "slip.h" +#include "slhc.h" + +#define SLIP_VERSION "0.7.5" + +/* 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 */ +# define IP_OF_COPIED 0x80 /* Copied-on-fragmentation flag */ +# define IP_OF_CLASS 0x60 /* Option class */ +# define IP_OF_NUMBER 0x1f /* Option number */ +#endif + + +static struct slip sl_ctrl[SL_NRUNIT]; +static struct tty_ldisc sl_ldisc; +static int already = 0; + + +/* Dump the contents of an IP datagram. */ +static void +ip_dump(unsigned char *ptr, int len) +{ +#ifdef SL_DUMP + struct iphdr *ip; + struct tcphdr *th; + int dlen, doff; + + if (inet_debug != DBG_SLIP) return; + + ip = (struct iphdr *) ptr; + th = (struct tcphdr *) (ptr + ip->ihl * 4); + printk("\r%s -> %s seq %lx ack %lx len %d\n", + in_ntoa(ip->saddr), in_ntoa(ip->daddr), + ntohl(th->seq), ntohl(th->ack_seq), ntohs(ip->tot_len)); + return; + + printk("\r*****\n"); + printk("%p %d\n", ptr, len); + ip = (struct iphdr *) ptr; + dlen = ntohs(ip->tot_len); + doff = ((ntohs(ip->frag_off) & IPF_F_OFFSET) << 3); + + + printk("SLIP: %s->", in_ntoa(ip->saddr)); + printk("%s\n", in_ntoa(ip->daddr)); + printk(" len %u ihl %u ver %u ttl %u prot %u", + dlen, ip->ihl, ip->version, ip->ttl, ip->protocol); + + if (ip->tos != 0) printk(" tos %u", ip->tos); + if (doff != 0 || (ntohs(ip->frag_off) & IPF_MF)) + printk(" id %u offs %u", ntohs(ip->id), doff); + + if (ntohs(ip->frag_off) & IPF_DF) printk(" DF"); + if (ntohs(ip->frag_off) & IPF_MF) printk(" MF"); + printk("\n*****\n"); +#endif +} + +#if 0 +void clh_dump(unsigned char *cp, int len) +{ + if (len > 60) + len = 60; + printk("%d:", len); + while (len > 0) { + printk(" %x", *cp++); + len--; + } + printk("\n\n"); +} +#endif + +/* Initialize a SLIP control block for use. */ +static void +sl_initialize(struct slip *sl, struct device *dev) +{ + sl->inuse = 0; + sl->sending = 0; + sl->escape = 0; + sl->flags = 0; +#ifdef SL_ADAPTIVE + sl->mode = SL_MODE_ADAPTIVE; /* automatic CSLIP recognition */ +#else +#ifdef SL_COMPRESSED + sl->mode = SL_MODE_CSLIP | SL_MODE_ADAPTIVE; /* Default */ +#else + sl->mode = SL_MODE_SLIP; /* Default for non compressors */ +#endif +#endif + + sl->line = dev->base_addr; + sl->tty = NULL; + sl->dev = dev; + sl->slcomp = NULL; + + /* Clear all pointers. */ + sl->rbuff = NULL; + sl->xbuff = NULL; + sl->cbuff = NULL; + + sl->rhead = NULL; + sl->rend = NULL; + dev->rmem_end = (unsigned long) NULL; + dev->rmem_start = (unsigned long) NULL; + dev->mem_end = (unsigned long) NULL; + dev->mem_start = (unsigned long) NULL; +} + + +/* Find a SLIP channel from its `tty' link. */ +static struct slip * +sl_find(struct tty_struct *tty) +{ + struct slip *sl; + int i; + + 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) +{ + unsigned long flags; + struct slip *sl; + int i; + + save_flags (flags); + cli(); + for (i = 0; i < SL_NRUNIT; i++) { + sl = &sl_ctrl[i]; + if (sl->inuse == 0) { + sl->inuse = 1; + sl->tty = NULL; + restore_flags(flags); + return(sl); + } + } + restore_flags(flags); + return(NULL); +} + + +/* Free a SLIP channel. */ +static inline void +sl_free(struct slip *sl) +{ + unsigned long flags; + + if (sl->inuse) { + save_flags(flags); + cli(); + sl->inuse = 0; + sl->tty = NULL; + restore_flags(flags); + } +} + +/* 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 +sl_enqueue(struct slip *sl, unsigned char c) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (sl->rhead < sl->rend) { + *sl->rhead = c; + sl->rhead++; + sl->rcount++; + } else sl->roverrun++; + restore_flags(flags); +} + +/* Release 'i' bytes from a SLIP receiver buffer. */ +static inline void +sl_dequeue(struct slip *sl, int i) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (sl->rhead > sl->rbuff) { + sl->rhead -= i; + sl->rcount -= i; + } + restore_flags(flags); +} + + +/* Set the "sending" flag. This must be atomic, hence the ASM. */ +static inline void +sl_lock(struct slip *sl) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sl->sending = 1; + sl->dev->tbusy = 1; + restore_flags(flags); +} + + +/* Clear the "sending" flag. This must be atomic, hence the ASM. */ +static inline void +sl_unlock(struct slip *sl) +{ + unsigned long flags; + + save_flags(flags); + cli(); + sl->sending = 0; + sl->dev->tbusy = 0; + restore_flags(flags); +} + + +/* Send one completely decapsulated IP datagram to the IP layer. */ +static void +sl_bump(struct slip *sl) +{ + int done; + unsigned char c; + unsigned long flags; + int count; + + count = sl->rcount; + if (sl->mode & (SL_MODE_ADAPTIVE | SL_MODE_CSLIP)) { + if ((c = sl->rbuff[0]) & SL_TYPE_COMPRESSED_TCP) { +#if 1 + /* ignore compressed packets when CSLIP is off */ + if (!(sl->mode & SL_MODE_CSLIP)) { + printk("SLIP: compressed packet ignored\n"); + return; + } +#endif + /* make sure we've reserved enough space for uncompress to use */ + save_flags(flags); + cli(); + if ((sl->rhead + 80) < sl->rend) { + sl->rhead += 80; + sl->rcount += 80; + done = 1; + } else { + sl->roverrun++; + done = 0; + } + restore_flags(flags); + if (! done) /* not enough space available */ + return; + + count = slhc_uncompress(sl->slcomp, sl->rbuff, count); + if (count <= 0) { + sl->errors++; + return; + } + } else if (c >= SL_TYPE_UNCOMPRESSED_TCP) { + if (!(sl->mode & SL_MODE_CSLIP)) { + /* turn on header compression */ + sl->mode |= SL_MODE_CSLIP; + printk("SLIP: header compression turned on\n"); + } + sl->rbuff[0] &= 0x4f; + if (slhc_remember(sl->slcomp, sl->rbuff, count) <= 0) { + sl->errors++; + return; + } + } + } + + DPRINTF((DBG_SLIP, "<< \"%s\" recv:\r\n", sl->dev->name)); + ip_dump(sl->rbuff, sl->rcount); + + /* Bump the datagram to the upper layers... */ + do { + DPRINTF((DBG_SLIP, "SLIP: packet is %d at 0x%X\n", + sl->rcount, sl->rbuff)); + /* clh_dump(sl->rbuff, count); */ + done = dev_rint(sl->rbuff, count, 0, sl->dev); + if (done == 0 || done == 1) break; + } while(1); + + sl->rpacket++; +} + + +/* TTY finished sending a datagram, so clean up. */ +static void +sl_next(struct slip *sl) +{ + DPRINTF((DBG_SLIP, "SLIP: sl_next(0x%X) called!\n", sl)); + sl_unlock(sl); + dev_tint(sl->dev); +} + + +/* Encapsulate one IP datagram and stuff into a TTY queue. */ +static void +sl_encaps(struct slip *sl, unsigned char *icp, int len) +{ + unsigned char *bp, *p; + int count; + + 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; + printk("slip: truncating oversized transmit packet!\n"); + } + + p = icp; + if(sl->mode & SL_MODE_CSLIP) + len = slhc_compress(sl->slcomp, p, len, sl->cbuff, &p, 1); + +#ifdef OLD + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + bp = sl->xbuff; + *bp++ = END; + count = 1; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + while(len-- > 0) { + c = *p++; + switch(c) { + case END: + *bp++ = ESC; + *bp++ = ESC_END; + count += 2; + break; + case ESC: + *bp++ = ESC; + *bp++ = ESC_ESC; + count += 2; + break; + default: + *bp++ = c; + count++; + } + } + *bp++ = END; + count++; +#else + if(sl->mode & SL_MODE_SLIP6) + count=slip_esc6(p, (unsigned char *)sl->xbuff,len); + else + count=slip_esc(p, (unsigned char *)sl->xbuff,len); +#endif + sl->spacket++; + bp = sl->xbuff; + + /* Tell TTY to send it on its way. */ + DPRINTF((DBG_SLIP, "SLIP: kicking TTY for %d bytes at 0x%X\n", count, bp)); + if (tty_write_data(sl->tty, (char *) bp, count, + (void (*)(void *))sl_next, (void *) sl) == 0) { + DPRINTF((DBG_SLIP, "SLIP: TTY already done with %d bytes!\n", count)); + sl_next(sl); + } +} + +/*static void sl_hex_dump(unsigned char *x,int l) +{ + int n=0; + printk("sl_xmit: (%d bytes)\n",l); + while(l) + { + printk("%2X ",(int)*x++); + l--; + n++; + if(n%32==0) + printk("\n"); + } + if(n%32) + printk("\n"); +}*/ + +/* Encapsulate an IP datagram and kick it into a TTY queue. */ +static int +sl_xmit(struct sk_buff *skb, struct device *dev) +{ + struct tty_struct *tty; + struct slip *sl; + + /* Find the correct SLIP channel to use. */ + sl = &sl_ctrl[dev->base_addr]; + tty = sl->tty; + DPRINTF((DBG_SLIP, "SLIP: sl_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) { + DPRINTF((DBG_SLIP, "SLIP: sl_xmit: BUSY\r\n")); + sl->sbusy++; + return(1); + } + + /* We were not, so we are now... :-) */ + if (skb != NULL) { +#ifdef CONFIG_AX25 + if(sl->mode & SL_MODE_AX25) + { + if(!skb->arp && dev->rebuild_header(skb->data,dev)) + { + skb->dev=dev; + arp_queue(skb); + return 0; + } + skb->arp=1; + } +#endif + sl_lock(sl); +/* sl_hex_dump(skb->data,skb->len);*/ + sl_encaps(sl, skb->data, skb->len); + if (skb->free) kfree_skb(skb, FREE_WRITE); + } + return(0); +} + + +/* Return the frame type ID. This is normally IP but maybe be AX.25. */ +static unsigned short +sl_type_trans (struct sk_buff *skb, struct device *dev) +{ +#ifdef CONFIG_AX25 + struct slip *sl=&sl_ctrl[dev->base_addr]; + if(sl->mode&SL_MODE_AX25) + return(NET16(ETH_P_AX25)); +#endif + return(NET16(ETH_P_IP)); +} + + +/* Fill in the MAC-level header. Not used by SLIP. */ +static int +sl_header(unsigned char *buff, struct device *dev, unsigned short type, + unsigned long daddr, unsigned long saddr, unsigned len) +{ +#ifdef CONFIG_AX25 + struct slip *sl=&sl_ctrl[dev->base_addr]; + if((sl->mode&SL_MODE_AX25) && type!=NET16(ETH_P_AX25)) + return ax25_encapsulate_ip(buff,dev,type,daddr,saddr,len); +#endif + + return(0); +} + + +/* Add an ARP-entry for this device's broadcast address. Not used. */ +static void +sl_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev) +{ +#ifdef CONFIG_AX25 + struct slip *sl=&sl_ctrl[dev->base_addr]; + + if(sl->mode&SL_MODE_AX25) + arp_add(addr,((char *) skb->data)+8,dev); +#endif +} + + +/* Rebuild the MAC-level header. Not used by SLIP. */ +static int +sl_rebuild_header(void *buff, struct device *dev) +{ +#ifdef CONFIG_AX25 + struct slip *sl=&sl_ctrl[dev->base_addr]; + + if(sl->mode&SL_MODE_AX25) + return ax25_rebuild_header(buff,dev); +#endif + return(0); +} + + +/* Open the low-level part of the SLIP channel. Easy! */ +static int +sl_open(struct device *dev) +{ + struct slip *sl; + unsigned char *p; + unsigned long l; + + sl = &sl_ctrl[dev->base_addr]; + if (sl->tty == NULL) { + DPRINTF((DBG_SLIP, "SLIP: channel %d not connected!\n", sl->line)); + return(-ENXIO); + } + sl->dev = dev; + + /* + * Allocate the SLIP frame buffers: + * + * mem_end Top of frame buffers + * mem_start Start of frame buffers + * rmem_end Top of RECV frame buffer + * rmem_start Start of RECV frame buffer + */ + l = (dev->mtu * 2); + p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); + if (p == NULL) { + 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); + + p = (unsigned char *) kmalloc(l + 4, GFP_KERNEL); + if (p == NULL) { + DPRINTF((DBG_SLIP, "SLIP: no memory for SLIP RECV buffer!\n")); + return(-ENOMEM); + } + sl->dev->rmem_start = (unsigned long) p; + 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; + + sl->escape = 0; + sl->sending = 0; + sl->rcount = 0; + + 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); + } + sl->cbuff = p; + + 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); + } + + dev->flags|=IFF_UP; + /* Needed because address '0' is special */ + if(dev->pa_addr==0) + dev->pa_addr=ntohl(0xC0000001); + DPRINTF((DBG_SLIP, "SLIP: channel %d opened.\n", sl->line)); + return(0); +} + + +/* Close the low-level part of the SLIP channel. Easy! */ +static int +sl_close(struct device *dev) +{ + struct slip *sl; + + sl = &sl_ctrl[dev->base_addr]; + if (sl->tty == NULL) { + DPRINTF((DBG_SLIP, "SLIP: channel %d not connected!\n", sl->line)); + return(-EBUSY); + } + sl_free(sl); + + /* Free all SLIP frame buffers. */ + kfree(sl->rbuff); + kfree(sl->xbuff); + kfree(sl->cbuff); + slhc_free(sl->slcomp); + + sl_initialize(sl, dev); + + DPRINTF((DBG_SLIP, "SLIP: channel %d closed.\n", sl->line)); + 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[128]; + unsigned char *p; + struct slip *sl; + int count, error=0; + + 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); + if (count <= 0) + { + count= - count; + if(count) + error=1; + break; + } + p = buff; +#ifdef OLD + while (count--) { + c = *p++; + if (sl->escape) { + if (c == ESC_ESC) + sl_enqueue(sl, ESC); + else if (c == ESC_END) + sl_enqueue(sl, END); + else + printk ("SLIP: received wrong character\n"); + sl->escape = 0; + } else { + if (c == ESC) + sl->escape = 1; + else if (c == END) { + if (sl->rcount > 2) sl_bump(sl); + sl_dequeue(sl, sl->rcount); + sl->rcount = 0; + } else sl_enqueue(sl, c); + } + } +#else + if(sl->mode & SL_MODE_SLIP6) + slip_unesc6(sl,buff,count,error); + else + slip_unesc(sl,buff,count,error); +#endif + } while(1); + +} + + +/* + * 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) { + DPRINTF((DBG_SLIP, "SLIP: TTY %d already connected to %s !\n", + tty->line, sl->dev->name)); + return(-EEXIST); + } + + /* OK. Find a free SLIP channel to use. */ + if ((sl = sl_alloc()) == NULL) { + DPRINTF((DBG_SLIP, "SLIP: TTY %d not connected: all channels in use!\n", + tty->line)); + return(-ENFILE); + } + sl->tty = tty; + tty_read_flush(tty); + tty_write_flush(tty); + + /* Perform the low-level SLIP initialization. */ + (void) sl_open(sl->dev); + DPRINTF((DBG_SLIP, "SLIP: TTY %d connected to %s.\n", + tty->line, sl->dev->name)); + + /* Done. We have linked the TTY line to a channel. */ + return(sl->line); +} + + +static struct enet_statistics * +sl_get_stats(struct device *dev) +{ + static struct enet_statistics stats; + struct slip *sl; + struct slcompress *comp; + + /* Find the correct SLIP channel to use. */ + sl = &sl_ctrl[dev->base_addr]; + if (! sl) + return NULL; + + memset(&stats, 0, sizeof(struct enet_statistics)); + + stats.rx_packets = sl->rpacket; + stats.rx_over_errors = sl->roverrun; + stats.tx_packets = sl->spacket; + stats.tx_dropped = sl->sbusy; + stats.rx_errors = sl->errors; + + comp = sl->slcomp; + if (comp) { + stats.rx_fifo_errors = comp->sls_i_compressed; + stats.rx_dropped = comp->sls_i_tossed; + stats.tx_fifo_errors = comp->sls_o_compressed; + stats.collisions = comp->sls_o_misses; + } + + return (&stats); +} + +/* + * 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) { + DPRINTF((DBG_SLIP, "SLIP: TTY %d not connected !\n", tty->line)); + return; + } + + (void) dev_close(sl->dev); + DPRINTF((DBG_SLIP, "SLIP: TTY %d disconnected from %s.\n", + tty->line, sl->dev->name)); +} + + + /************************************************************************ + * STANDARD SLIP ENCAPSULATION * + ************************************************************************ + * + */ + + int + slip_esc(unsigned char *s, unsigned char *d, int len) + { + int count = 0; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + d[count++] = END; + + /* + * For each byte in the packet, send the appropriate + * character sequence, according to the SLIP protocol. + */ + + while(len-- > 0) { + switch(*s) { + case END: + d[count++] = ESC; + d[count++] = ESC_END; + break; + case ESC: + d[count++] = ESC; + d[count++] = ESC_ESC; + break; + default: + d[count++] = *s; + } + ++s; + } + d[count++] = END; + return(count); + } + + void + slip_unesc(struct slip *sl, unsigned char *s, int count, int error) + { + int i; + + for (i = 0; i < count; ++i, ++s) { + switch(*s) { + case ESC: + sl->flags |= SLF_ESCAPE; + break; + case ESC_ESC: + if (sl->flags & SLF_ESCAPE) + sl_enqueue(sl, ESC); + else + sl_enqueue(sl, *s); + sl->flags &= ~SLF_ESCAPE; + break; + case ESC_END: + if (sl->flags & SLF_ESCAPE) + sl_enqueue(sl, END); + else + sl_enqueue(sl, *s); + sl->flags &= ~SLF_ESCAPE; + break; + case END: + if (sl->rcount > 2) + sl_bump(sl); + sl_dequeue(sl, sl->rcount); + sl->rcount = 0; + sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); + break; + default: + sl_enqueue(sl, *s); + sl->flags &= ~SLF_ESCAPE; + } + } + if (error) + sl->flags |= SLF_ERROR; + } + + /************************************************************************ + * 6 BIT SLIP ENCAPSULATION * + ************************************************************************ + * + */ + + int + slip_esc6(unsigned char *s, unsigned char *d, int len) + { + int count = 0; + int i; + unsigned short v = 0; + short bits = 0; + + /* + * Send an initial END character to flush out any + * data that may have accumulated in the receiver + * due to line noise. + */ + + d[count++] = 0x70; + + /* + * Encode the packet into printable ascii characters + */ + + for (i = 0; i < len; ++i) { + v = (v << 8) | s[i]; + bits += 8; + while (bits >= 6) { + unsigned char c; + + bits -= 6; + c = 0x30 + ((v >> bits) & 0x3F); + d[count++] = c; + } + } + if (bits) { + unsigned char c; + + c = 0x30 + ((v << (6 - bits)) & 0x3F); + d[count++] = c; + } + d[count++] = 0x70; + return(count); + } + + void + slip_unesc6(struct slip *sl, unsigned char *s, int count, int error) + { + int i; + unsigned char c; + + for (i = 0; i < count; ++i, ++s) { + if (*s == 0x70) { + if (sl->rcount > 8) { /* XXX must be 2 for compressed slip */ + #ifdef NOTDEF + printk("rbuff %02x %02x %02x %02x\n", + sl->rbuff[0], + sl->rbuff[1], + sl->rbuff[2], + sl->rbuff[3] + ); + #endif + sl_bump(sl); + } + sl_dequeue(sl, sl->rcount); + sl->rcount = 0; + sl->flags &= ~(SLF_ESCAPE | SLF_ERROR); /* SLF_ESCAPE not used */ + sl->xbits = 0; + } else if (*s >= 0x30 && *s < 0x70) { + sl->xdata = (sl->xdata << 6) | ((*s - 0x30) & 0x3F); + sl->xbits += 6; + if (sl->xbits >= 8) { + sl->xbits -= 8; + c = (unsigned char)(sl->xdata >> sl->xbits); + sl_enqueue(sl, c); + } + + } + } + if (error) + sl->flags |= SLF_ERROR; + } + + +#ifdef CONFIG_AX25 + +int sl_set_mac_address(struct device *dev, void *addr) +{ + int err=verify_area(VERIFY_READ,addr,7); + if(err) + return err; + memcpy_fromfs(dev->dev_addr,addr,7); /* addr is an AX.25 shifted ASCII mac address */ + return 0; +} +#endif + + +/* Perform I/O control on an active SLIP channel. */ +static int +slip_ioctl(struct tty_struct *tty, void *file, int cmd, void *arg) +{ + struct slip *sl; + int err; + + /* First make sure we're connected. */ + if ((sl = sl_find(tty)) == NULL) { + DPRINTF((DBG_SLIP, "SLIP: ioctl: TTY %d not connected !\n", tty->line)); + return(-EINVAL); + } + + DPRINTF((DBG_SLIP, "SLIP: ioctl(%d, 0x%X, 0x%X)\n", tty->line, cmd, arg)); + switch(cmd) { + case SIOCGIFNAME: + err=verify_area(VERIFY_WRITE, arg, 16); + if(err) + return -err; + memcpy_tofs(arg, sl->dev->name, strlen(sl->dev->name) + 1); + return(0); + case SIOCGIFENCAP: + err=verify_area(VERIFY_WRITE,arg,sizeof(long)); + put_fs_long(sl->mode,(long *)arg); + return(0); + case SIOCSIFENCAP: + err=verify_area(VERIFY_READ,arg,sizeof(long)); + sl->mode=get_fs_long((long *)arg); +#ifdef CONFIG_AX25 + if(sl->mode & SL_MODE_AX25) + { + sl->dev->addr_len=7; /* sizeof an AX.25 addr */ + sl->dev->hard_header_len=17; /* We don't do digipeaters */ + sl->dev->type=3; /* AF_AX25 not an AF_INET device */ + } + else + { + sl->dev->addr_len=0; /* No mac addr in slip mode */ + sl->dev->hard_header_len=0; + sl->dev->type=0; + } +#endif + return(0); + case SIOCSIFHWADDR: +#ifdef CONFIG_AX25 + return sl_set_mac_address(sl->dev,arg); +#endif + default: + return(-EINVAL); + } + return(-EINVAL); +} + + +/* Initialize the SLIP driver. Called by DDI. */ +int +slip_init(struct device *dev) +{ + struct slip *sl; + int i; +#ifdef CONFIG_AX25 + static char ax25_bcast[7]={'Q'<<1,'S'<<1,'T'<<1,' '<<1,' '<<1,' '<<1,'0'<<1}; + static char ax25_test[7]={'L'<<1,'I'<<1,'N'<<1,'U'<<1,'X'<<1,' '<<1,'1'<<1}; +#endif + + sl = &sl_ctrl[dev->base_addr]; + + if (already++ == 0) { + printk("SLIP: version %s (%d channels)\n", + SLIP_VERSION, SL_NRUNIT); + printk("CSLIP: code copyright 1989 Regents of the University of California\n"); +#ifdef CONFIG_AX25 + printk("AX25: KISS encapsulation enabled\n"); +#endif + /* Fill in our LDISC request block. */ + sl_ldisc.flags = 0; + sl_ldisc.open = slip_open; + sl_ldisc.close = slip_close; + sl_ldisc.read = NULL; + sl_ldisc.write = NULL; + sl_ldisc.ioctl = (int (*)(struct tty_struct *, struct file *, + unsigned int, unsigned long)) slip_ioctl; + sl_ldisc.select = NULL; + sl_ldisc.handler = slip_recv; + if ((i = tty_register_ldisc(N_SLIP, &sl_ldisc)) != 0) + printk("ERROR: %d\n", i); + } + + /* Set up the "SLIP Control Block". */ + sl_initialize(sl, dev); + + /* Clear all statistics. */ + sl->rcount = 0; /* SLIP receiver count */ + sl->rpacket = 0; /* #frames received */ + sl->roverrun = 0; /* "overrun" counter */ + sl->spacket = 0; /* #frames sent out */ + sl->sbusy = 0; /* "xmit busy" counter */ + sl->errors = 0; /* not used at present */ + + /* Finish setting up the DEVICE info. */ + dev->mtu = SL_MTU; + dev->hard_start_xmit = sl_xmit; + dev->open = sl_open; + dev->stop = sl_close; + dev->hard_header = sl_header; + dev->add_arp = sl_add_arp; + dev->type_trans = sl_type_trans; + dev->get_stats = sl_get_stats; +#ifdef HAVE_SET_MAC_ADDR +#ifdef CONFIG_AX25 + dev->set_mac_address = sl_set_mac_address; +#endif +#endif + dev->hard_header_len = 0; + dev->addr_len = 0; + dev->type = 0; +#ifdef CONFIG_AX25 + memcpy(dev->broadcast,ax25_bcast,7); /* Only activated in AX.25 mode */ + memcpy(dev->dev_addr,ax25_test,7); /* "" "" "" "" */ +#endif + dev->queue_xmit = dev_queue_xmit; + dev->rebuild_header = sl_rebuild_header; + for (i = 0; i < DEV_NUMBUFFS; i++) + dev->buffs[i] = NULL; + + /* 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); + + return(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.h new file mode 100644 index 000000000..b0be29285 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/slip.h @@ -0,0 +1,83 @@ +/* + * 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 03/28/93 + * + * Fixes: + * Alan Cox : Added slip mtu field. + * Matt Dillon : Printable slip (borrowed from net2e) + * + * Author: Fred N. van Kempen, + */ +#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 */ + +/* 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 slip { + /* Bitmapped flag fields. */ + char inuse; /* are we allocated? */ + char sending; /* "channel busy" indicator */ + char escape; /* SLIP state machine */ + char unused; /* fillers */ + + /* Various fields. */ + int line; /* SLIP channel number */ + struct tty_struct *tty; /* ptr to TTY structure */ + struct device *dev; /* easy for intr handling */ + struct slcompress *slcomp; /* for header compression */ + + /* These are pointers to the malloc()ed frame buffers. */ + unsigned char *rbuff; /* receiver buffer */ + unsigned char *xbuff; /* transmitter buffer */ + unsigned char *cbuff; /* compression buffer */ + + /* These are the various pointers into the buffers. */ + unsigned char *rhead; /* RECV buffer pointer (head) */ + unsigned char *rend; /* RECV buffer pointer (end) */ + int rcount; /* SLIP receive counter */ + + /* SLIP interface statistics. */ + unsigned long rpacket; /* inbound frame counter */ + unsigned long roverrun; /* "buffer overrun" counter */ + unsigned long spacket; /* outbound frames counter */ + unsigned long sbusy; /* "transmitter busy" counter */ + unsigned long errors; /* error count */ + + int mtu; /* Our mtu (to spot changes!) */ + unsigned char flags; /* Flag values/ mode etc */ +#define SLF_ESCAPE 2 +#define SLF_ERROR 4 +#define SLF_COMP 16 +#define SLF_EXPN 32 + unsigned char mode; /* SLIP mode */ +#define SL_MODE_SLIP 0 +#define SL_MODE_CSLIP 1 +#define SL_MODE_SLIP6 2 /* Matt Dillon's printable slip */ +#define SL_MODE_CSLIP6 (SL_MODE_SLIP6|SL_MODE_CSLIP) +#define SL_MODE_AX25 4 +#define SL_MODE_ADAPTIVE 8 + int xdata,xbits; /* 6 bit slip controls */ +}; + + +extern int slip_init(struct device *dev); +extern int slip_esc(unsigned char *s, unsigned char *d, int len); +extern int slip_esc6(unsigned char *s, unsigned char *d, int len); +extern void slip_unesc(struct slip *sl, unsigned char *s, int count, int error); +extern void slip_unesc6(struct slip *sl, unsigned char *s, int count, int error); + + +#endif /* _LINUX_SLIP.H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/smc-ultra.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/smc-ultra.c new file mode 100644 index 000000000..5816b83e4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/smc-ultra.c @@ -0,0 +1,268 @@ +/* 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.05 12/21/93 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "8390.h" + +/* Compatibility definitions for earlier kernel versions. */ +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size); do ; while (0) +#endif + +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 +8 to +13, with a checksum + following. +*/ + +int ultra_probe(struct device *dev) +{ + int *port, ports[] = {0x200, 0x220, 0x240, 0x280, 0x300, 0x340, 0x380, 0}; + unsigned short ioaddr = dev->base_addr; + + if (ioaddr > 0x1ff) + return ! ultraprobe1(ioaddr, dev); + else if (ioaddr > 0) + return ENXIO; /* Don't probe at all. */ + + for (port = &ports[0]; *port; port++) { + if (check_region(*port, 32)) + continue; + if ((inb(*port + 7) & 0xF0) == 0x20 /* Check chip ID nibble. */ + && 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; + unsigned char eeprom_irq = 0; + /* Values from various config regs. */ + unsigned char num_pages, irqreg, addr, reg4 = inb(ioaddr + 4) & 0x7f; + + + /* Select the station address register set. */ + outb(reg4, 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)); + + /* Switch from the station address to the alternate register set and + read the useful registers there. */ + outb(0x80 | reg4, ioaddr + 4); + + /* Enabled FINE16 mode to avoid BIOS ROM width mismatches during reboot. */ + outb(0x80 | inb(ioaddr + 0x0c), ioaddr + 0x0c); + irqreg = inb(ioaddr + 0xd); + addr = inb(ioaddr + 0xb); + + /* Switch back to the station address register set so that the MS-DOS driver + can find the card after a warm boot. */ + outb(reg4, ioaddr + 4); + + model_name = "SMC Ultra"; + + if (dev->irq < 2) { + unsigned char irqmap[] = {0, 9, 3, 5, 7, 10, 11, 15}; + int irq; + + /* The IRQ bits are split. */ + irq = irqmap[((irqreg & 0x40) >> 4) + ((irqreg & 0x0c) >> 2)]; + + if (irq == 0) { + printk(", failed to detect IRQ line.\n"); + return -EAGAIN; + } + dev->irq = irq; + eeprom_irq = 1; + } + + + /* OK, were are certain this is going to work. Setup the device. */ + snarf_region(ioaddr, 32); + + /* The 8390 isn't at the base address, so fake the offset */ + dev->base_addr = ioaddr+ULTRA_NIC_OFFSET; + + { + 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(",%s IRQ %d memory %#x-%#x.\n", eeprom_irq ? "" : "assigned ", + dev->irq, 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; + + 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/wd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/wd.c new file mode 100644 index 000000000..c94068fa3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/net/wd.c @@ -0,0 +1,369 @@ +/* wd.c: A WD80x3 ethernet driver for linux. */ +/* + Written 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 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 + + Thanks to Russ Nelson (nelson@crnwyr.com) for loaning me a WD8013. +*/ + +static char *version = + "wd.c:v0.99-14 11/21/93 Donald Becker (becker@super.org)\n"; + +#include +#include +#include +#include +#include +#include +#include + +#include "dev.h" +#include "8390.h" + +/* Compatibility definitions for earlier kernel versions. */ +#ifndef HAVE_PORTRESERVE +#define check_region(ioaddr, size) 0 +#define snarf_region(ioaddr, size) do ; while (0) +#endif + +int wd_probe(struct device *dev); +int wdprobe1(int ioaddr, struct device *dev); + +static int wd_open(struct device *dev); +static void wd_reset_8390(struct device *dev); +static int wd_block_input(struct device *dev, int count, + char *buf, int ring_offset); +static void wd_block_output(struct device *dev, int count, + const unsigned char *buf, const start_page); +static int wd_close_card(struct device *dev); + + +#define WD_START_PG 0x00 /* First page of TX buffer */ +#define WD03_STOP_PG 0x20 /* Last page +1 of RX ring */ +#define WD13_STOP_PG 0x40 /* Last page +1 of RX ring */ + +#define WD_CMDREG 0 /* Offset to ASIC command register. */ +#define WD_RESET 0x80 /* Board reset, in WD_CMDREG. */ +#define WD_MEMENB 0x40 /* Enable the shared memory. */ +#define WD_CMDREG5 5 /* Offset to 16-bit-only ASIC register 5. */ +#define ISA16 0x80 /* Enable 16 bit access from the ISA bus. */ +#define NIC16 0x40 /* Enable 16 bit access from the 8390. */ +#define WD_NIC_OFFSET 16 /* Offset to the 8390 NIC from the base_addr. */ + +/* Probe for the WD8003 and WD8013. These cards have the station + address PROM at I/O ports +8 to +13, with a checksum + following. A Soundblaster can have the same checksum as an WDethercard, + so we have an extra exclusionary check for it. + + The wdprobe1() routine initializes the card and fills the + station address field. */ + +int wd_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 ! wdprobe1(ioaddr, dev); + + for (port = &ports[0]; *port; port++) { + if (check_region(*port, 32)) + continue; + if (inb(*port + 8) != 0xff + && inb(*port + 9) != 0xff /* Extra check to avoid soundcard. */ + && wdprobe1(*port, dev)) + return 0; + } + dev->base_addr = ioaddr; + return ENODEV; +} + +int wdprobe1(int ioaddr, struct device *dev) +{ + int i; + unsigned char *station_addr = dev->dev_addr; + int checksum = 0; + int ancient = 0; /* An old card without config registers. */ + int word16 = 0; /* 0 = 8 bit, 1 = 16 bit */ + char *model_name; + + for (i = 0; i < 8; i++) + checksum += inb(ioaddr + 8 + i); + if ((checksum & 0xff) != 0xFF) + return 0; + + printk("%s: WD80x3 at %#3x, ", dev->name, ioaddr); + for (i = 0; i < 6; i++) + printk(" %2.2X", station_addr[i] = inb(ioaddr + 8 + i)); + + /* The following PureData probe code was contributed by + Mike Jagdis . Puredata does software + configuration differently from others so we have to check for them. + This detects an 8 bit, 16 bit or dumb (Toshiba, jumpered) card. + */ + if (inb(ioaddr+0) == 'P' && inb(ioaddr+1) == 'D') { + unsigned char reg5 = inb(ioaddr+5); + + switch (inb(ioaddr+2)) { + case 0x03: word16 = 0; model_name = "PDI8023-8"; break; + case 0x05: word16 = 0; model_name = "PDUC8023"; break; + case 0x0a: word16 = 1; model_name = "PDI8023-16"; break; + /* Either 0x01 (dumb) or they've released a new version. */ + default: word16 = 0; model_name = "PDI8023"; break; + } + dev->mem_start = ((reg5 & 0x1c) + 0xc0) << 12; + dev->irq = (reg5 & 0xe0) == 0xe0 ? 10 : (reg5 >> 5) + 1; + } else { /* End of PureData probe */ + /* This method of checking for a 16-bit board is borrowed from the + we.c driver. A simpler method is just to look in ASIC reg. 0x03. + I'm comparing the two method in alpha test to make certain they + return the same result. */ + /* Check for the old 8 bit board - it has register 0/8 aliasing. + Do NOT check i>=6 here -- it hangs the old 8003 boards! */ + for (i = 0; i < 6; i++) + if (inb(ioaddr+i) != inb(ioaddr+8+i)) + break; + if (i >= 6) { + ancient = 1; + model_name = "WD8003-old"; + word16 = 0; + } else { + int tmp = inb(ioaddr+1); /* fiddle with 16bit bit */ + outb( tmp ^ 0x01, ioaddr+1 ); /* attempt to clear 16bit bit */ + if (((inb( ioaddr+1) & 0x01) == 0x01) /* A 16 bit card */ + && (tmp & 0x01) == 0x01 ) { /* In a 16 slot. */ + int asic_reg5 = inb(ioaddr+WD_CMDREG5); + /* Magic to set ASIC to word-wide mode. */ + outb( NIC16 | (asic_reg5&0x1f), ioaddr+WD_CMDREG5); + outb(tmp, ioaddr+1); + model_name = "WD8013"; + word16 = 1; /* We have a 16bit board here! */ + } else { + model_name = "WD8003"; + word16 = 0; + } + outb(tmp, ioaddr+1); /* Restore original reg1 value. */ + } +#ifndef final_version + if ( !ancient && (inb(ioaddr+1) & 0x01) != (word16 & 0x01)) + printk("\nWD80?3: Bus width conflict, %d (probe) != %d (reg report).", + word16 ? 16 : 8, (inb(ioaddr+1) & 0x01) ? 16 : 8); +#endif + } + +#if defined(WD_SHMEM) && WD_SHMEM > 0x80000 + /* Allow a compile-time override. */ + dev->mem_start = WD_SHMEM; +#else + if (dev->mem_start == 0) { + /* Sanity and old 8003 check */ + int reg0 = inb(ioaddr); + if (reg0 == 0xff || reg0 == 0) { + /* Future plan: this could check a few likely locations first. */ + dev->mem_start = 0xd0000; + printk(" assigning address %#lx", dev->mem_start); + } else { + int high_addr_bits = inb(ioaddr+WD_CMDREG5) & 0x1f; + /* Some boards don't have the register 5 -- it returns 0xff. */ + if (high_addr_bits == 0x1f || word16 == 0) + high_addr_bits = 0x01; + dev->mem_start = ((reg0&0x3f) << 13) + (high_addr_bits << 19); + } + } +#endif + + /* The 8390 isn't at the base address -- the ASIC regs are there! */ + dev->base_addr = ioaddr+WD_NIC_OFFSET; + + if (dev->irq < 2) { + int irqmap[] = {9,3,5,7,10,11,15,4}; + int reg1 = inb(ioaddr+1); + int reg4 = inb(ioaddr+4); + if (ancient || reg1 == 0xff) { /* Ack!! No way to read the IRQ! */ + short nic_addr = ioaddr+WD_NIC_OFFSET; + + /* We have an old-style ethercard that doesn't report its IRQ + line. Do autoirq to find the IRQ line. Note that this IS NOT + a reliable way to trigger an interrupt. */ + outb_p(E8390_NODMA + E8390_STOP, nic_addr); + outb(0x00, nic_addr+EN0_IMR); /* Disable all intrs. */ + autoirq_setup(0); + outb_p(0xff, nic_addr + EN0_IMR); /* Enable all interrupts. */ + outb_p(0x00, nic_addr + EN0_RCNTLO); + outb_p(0x00, nic_addr + EN0_RCNTHI); + outb(E8390_RREAD+E8390_START, nic_addr); /* Trigger it... */ + dev->irq = autoirq_report(2); + outb_p(0x00, nic_addr+EN0_IMR); /* Mask all intrs. again. */ + + if (ei_debug > 2) + printk(" autoirq is %d", dev->irq); + if (dev->irq < 2) + dev->irq = word16 ? 10 : 5; + } else + dev->irq = irqmap[((reg4 >> 5) & 0x03) + (reg1 & 0x04)]; + } else if (dev->irq == 2) /* Fixup bogosity: IRQ2 is really IRQ9 */ + dev->irq = 9; + + /* Snarf the interrupt now. There's no point in waiting since we cannot + share and the board will usually be enabled. */ + if (irqaction (dev->irq, &ei_sigaction)) { + printk (" unable to get IRQ %d.\n", dev->irq); + return 0; + } + + /* OK, were are certain this is going to work. Setup the device. */ + snarf_region(ioaddr, 32); + ethdev_init(dev); + + ei_status.name = model_name; + ei_status.word16 = word16; + ei_status.tx_start_page = WD_START_PG; + ei_status.rx_start_page = WD_START_PG + TX_PAGES; + ei_status.stop_page = word16 ? WD13_STOP_PG : WD03_STOP_PG; + + /* Don't map in the shared memory until the board is actually opened. */ + dev->rmem_start = dev->mem_start + TX_PAGES*256; + dev->mem_end = dev->rmem_end + = dev->mem_start + (ei_status.stop_page - WD_START_PG)*256; + + printk(" %s, IRQ %d, shared memory at %#lx-%#lx.\n", + model_name, dev->irq, dev->mem_start, dev->mem_end-1); + if (ei_debug > 0) + printk(version); + + ei_status.reset_8390 = &wd_reset_8390; + ei_status.block_input = &wd_block_input; + ei_status.block_output = &wd_block_output; + dev->open = &wd_open; + dev->stop = &wd_close_card; + NS8390_init(dev, 0); + + return dev->base_addr; +} + +static int +wd_open(struct device *dev) +{ + int ioaddr = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ + + /* Map in the shared memory. Always set register 0 last to remain + compatible with very old boards. */ + ei_status.reg0 = ((dev->mem_start>>13) & 0x3f) | WD_MEMENB; + ei_status.reg5 = ((dev->mem_start>>19) & 0x1f) | NIC16; + + if (ei_status.word16) + outb(ei_status.reg5, ioaddr+WD_CMDREG5); + outb(ei_status.reg0, ioaddr); /* WD_CMDREG */ + + return ei_open(dev); +} + +static void +wd_reset_8390(struct device *dev) +{ + int wd_cmd_port = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ + + outb(WD_RESET, wd_cmd_port); + if (ei_debug > 1) printk("resetting the WD80x3 t=%lu...", jiffies); + ei_status.txing = 0; + + /* Set up the ASIC registers, just in case something changed them. */ + 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); + + 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 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 */ + long xfer_start = dev->mem_start + ring_offset - (WD_START_PG<<8); + + /* We'll always get a 4 byte header read followed by a packet read, so + we enable 16 bit mode before the header, and disable after the body. */ + 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 > dev->rmem_end) { + /* We must wrap the input move. */ + int semi_count = dev->rmem_end - xfer_start; + memcpy(buf, (char *)xfer_start, semi_count); + count -= semi_count; + memcpy(buf + semi_count, (char *)dev->rmem_start, count); + } else + memcpy(buf, (char *)xfer_start, count); + + /* Turn off 16 bit access so that reboot works. ISA brain-damage */ + if (ei_status.word16) + outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5); + + 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 */ + long shmem = dev->mem_start + ((start_page - WD_START_PG)<<8); + + + if (ei_status.word16) { + /* Turn on and off 16 bit access so that reboot works. */ + outb(ISA16 | ei_status.reg5, wd_cmdreg+WD_CMDREG5); + memcpy((char *)shmem, buf, count); + outb(ei_status.reg5, wd_cmdreg+WD_CMDREG5); + } else + memcpy((char *)shmem, buf, count); +} + + +static int +wd_close_card(struct device *dev) +{ + int wd_cmdreg = dev->base_addr - WD_NIC_OFFSET; /* WD_CMDREG */ + + if (ei_debug > 1) + printk("%s: Shutting down ethercard.\n", dev->name); + NS8390_init(dev, 0); + + /* Change from 16-bit to 8-bit shared memory so reboot works. */ + outb(ei_status.reg5, wd_cmdreg + WD_CMDREG5 ); + + /* And disable the shared memory. */ + outb(ei_status.reg0 & ~WD_MEMENB, wd_cmdreg); + + return 0; +} + + +/* + * Local variables: + * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c wd.c" + * version-control: t + * tab-width: 4 + * kept-new-versions: 5 + * End: + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/Makefile new file mode 100644 index 000000000..76e3dc218 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/Makefile @@ -0,0 +1,136 @@ +# +# Makefile for kernel/blk_drv/scsi +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DONT put your own dependencies here +# unless its something special (ie not a .c file). +# + +#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_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_GENERIC_NCR5380 +SCSI_OBJS := $(SCSI_OBJS) g_NCR5380.o +SCSI_SRCS := $(SCSI_SRCS) g_NCR5380.c +endif + +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_8xx +SCSI_OBJS := $(SCSI_OBJS) seagate.o +SCSI_SRCS := $(SCSI_SRCS) seagate.c +endif +endif + +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: + rm -f scsi.a + @echo No SCSI drivers configured + $(AR) rcs scsi.a + +dep: + +endif + + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.c new file mode 100644 index 000000000..c90873c39 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.c @@ -0,0 +1,2447 @@ +/* + * NCR 5380 generic driver routines. These should make it *trivial* + * to implement 5380 SCSI drivers under Linux with a non-trantor + * architecture. + * + * Note that these routines also work with NR53c400 family chips. + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix and Linux consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 + * + * DISTRIBUTION REALEASE 4. + * + * 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 $ + * Revision 1.5 1994/01/19 09:14:57 drew + * Fixed udelay() hack that was being used on DATAOUT phases + * instead of a propper wait for the final handshake. + * + * Revision 1.4 1994/01/19 06:44:25 drew + * *** empty log message *** + * + * Revision 1.3 1994/01/19 05:24:40 drew + * Added support for TCR LAST_BYTE_SENT bit. + * + * Revision 1.2 1994/01/15 06:14:11 drew + * REAL DMA support, bug fixes. + * + * Revision 1.1 1994/01/15 06:00:54 drew + * Initial revision + * + */ + +/* + * Furthur development / testing that should be done : + * 1. Cleanup the NCR5380_transfer_dma function and DMA operation complete + * code so that everything does the same thing that's done at the + * end of a pseudo-DMA read operation. + * + * 2. Fix REAL_DMA (interrupt driven, polled works fine) - + * basically, transfer size needs to be reduced by one + * and the last byte read as is done with PSEUDO_DMA. + * + * 3. Test USLEEP code + * + * 4. Test SCSI-II tagged queueing (I have no devices which support + * tagged queueing) + * + * 5. Test linked command handling code after Eric is ready with + * the high level code. + */ + +#ifndef notyet +#undef LINKED +#undef USLEEP +#undef REAL_DMA +#endif + +#ifdef REAL_DMA_POLL +#undef READ_OVERRUNS +#define READ_OVERRUNS +#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. + * + * REAL_DMA_POLL - if defined, REAL DMA is used but the driver doesn't + * rely on phase mismatch and EOP interrupts to determine end + * of phase. + * + * 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. + * Note that the DMA setup functions should return the number of bytes + * that they were able to program the controller for. + * + * Also note that generic i386/PC versions of these macros are + * available as NCR5380_i386_dma_write_setup, + * NCR5380_i386_dma_read_setup, and NCR5380_i386_dma_residual. + * + * NCR5380_dma_write_setup(instance, src, count) - initialize + * NCR5380_dma_read_setup(instance, dst, count) - initialize + * NCR5380_dma_residual(instance); - 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 + +#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 REAL_DMA + " REAL DMA" +#endif +#ifdef REAL_DMA_POLL + " REAL DMA POLL" +#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; + hostdata->flags = FLAG_CHECK_LAST_BYTE_SENT; + + 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; + unsigned char basr; +#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); + basr = NCR5380_read(BUS_AND_STATUS_REG); + /* XXX dispatch to appropriate routine if found and done=0 */ + if (basr & 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 (basr & + 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) + /* + * We should only get PHASE MISMATCH and EOP interrupts + * if we have DMA enabled, so do a sanity check based on + * the current setting of the MODE register. + */ + + if ((NCR5380_read(MODE_REG) & MR_DMA) && ((basr & + BASR_END_DMA_TRANSFER) || + !(basr & BASR_PHASE_MATCH))) { + int transfered; + + if (!hostdata->connected) + panic("scsi%d : recieved end of DMA interrupt with no connected cmd\n", + instance->hostno); + + transfered = (hostdata->dmalen - NCR5380_dma_residual(instance)); + hostdata->connected->SCp.this_residual -= transferred; + hostdata->connected->SCp.ptr += transferred; + hostdata->dmalen = 0; + + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); + + while (NCR5380_read(BUS_AND_STATUS_REG) & + BASR_ACK)); + + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + } +#else +#if (NDEBUG & NDEBUG_INTR) + printk("scsi : unknown interrupt, BASR 0x%X, MR 0x%X, SR 0x%x\n", basr, NCR5380_read(MODE_REG), NCR5380_read(STATUS_REG)); +#endif + (void) NCR5380_read(RESET_PARITY_INTERRUPT_REG); +#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) || defined (REAL_DMA_POLL) +/* + * 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; +#if defined(REAL_DMA_POLL) + int cnt, toPIO; + unsigned char saved_data = 0, overrun = 0, residue; +#endif + + struct NCR5380_hostdata *hostdata = (struct NCR5380_hostdata *) + instance->hostdata; + + NCR5380_setup(instance); + + if ((tmp = (NCR5380_read(STATUS_REG) & PHASE_MASK)) != p) { + *phase = tmp; + return -1; + } +#if defined(REAL_DMA) || defined(REAL_DMA_POLL) +#ifdef READ_OVERRUNS + if (p & SR_IO) { + c -= 2; + } +#endif +#if (NDEBUG & NDEBUG_DMA) + printk("scsi%d : initializing DMA channel %d for %s, %d bytes %s %0x\n", + instance->host_no, instance->dma_channel, (p & SR_IO) ? "reading" : + "writing", c, (p & SR_IO) ? "to" : "from", (unsigned) d); +#endif + hostdata->dma_len = (p & SR_IO) ? + NCR5380_dma_read_setup(instance, d, c) : + NCR5380_dma_write_setup(instance, d, c); +#endif + + 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); +#elif defined(REAL_DMA_POLL) + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); +#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. + */ + +#if defined(PSEUDO_DMA) && !defined(UNSAFE) + cli(); +#endif + NCR5380_write(MODE_REG, MR_BASE | MR_DMA_MODE); +#endif /* def REAL_DMA */ + +#if (NDEBUG & NDEBUG_DMA) & 0 + printk("scsi%d : mode reg = 0x%X\n", instance->host_no, NCR5380_read(MODE_REG)); +#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); + } + +#if defined(REAL_DMA_POLL) + do { + tmp = NCR5380_read(BUS_AND_STATUS_REG); + } while ((tmp & BASR_PHASE_MATCH) && !(tmp & (BASR_BUSY_ERROR | + BASR_END_DMA_TRANSFER))); + +/* + At this point, either we've completed DMA, or we have a phase mismatch, + or we've unexpectedly lost BUSY (which is a real error). + + For write DMAs, we want to wait until the last byte has been + transferred out over the bus before we turn off DMA mode. Alas, there + seems to be no terribly good way of doing this on a 5380 under all + conditions. For non-scatter-gather operations, we can wait until REQ + and ACK both go false, or until a phase mismatch occurs. Gather-writes + are nastier, since the device will be expecting more data than we + are prepared to send it, and REQ will remain asserted. On a 53C8[01] we + could test LAST BIT SENT to assure transfer (I imagine this is precisely + why this signal was added to the newer chips) but on the older 538[01] + this signal does not exist. The workaround for this lack is a watchdog; + we bail out of the wait-loop after a modest amount of wait-time if + the usual exit conditions are not met. Not a terribly clean or + correct solution :-% + + Reads are equally tricky due to a nasty characteristic of the NCR5380. + If the chip is in DMA mode for an READ, it will respond to a target's + REQ by latching the SCSI data into the INPUT DATA register and asserting + ACK, even if it has _already_ been notified by the DMA controller that + the current DMA transfer has completed! If the NCR5380 is then taken + out of DMA mode, this already-acknowledged byte is lost. + + This is not a problem for "one DMA transfer per command" reads, because + the situation will never arise... either all of the data is DMA'ed + properly, or the target switches to MESSAGE IN phase to signal a + disconnection (either operation bringing the DMA to a clean halt). + However, in order to handle scatter-reads, we must work around the + problem. The chosen fix is to DMA N-2 bytes, then check for the + condition before taking the NCR5380 out of DMA mode. One or two extra + bytes are tranferred via PIO as necessary to fill out the original + request. +*/ + + if (p & SR_IO) { +#ifdef READ_OVERRUNS + udelay(10); + if (((NCR5380_read(BUS_AND_STATUS_REG) & (BASR_PHASE_MATCH|BASR_ACK)) == + (BASR_PHASE_MATCH | BASR_ACK))) { + saved_data = NCR5380_read(INPUT_DATA_REGISTER); + overrun = 1; + } +#endif + } else { + int limit = 100; + while (((tmp = NCR5380_read(BUS_AND_STATUS_REG)) & BASR_ACK) || + (NCR5380_read(STATUS_REG) & SR_REQ)) { + if (!(tmp & BASR_PHASE_MATCH)) break; + if (--limit < 0) break; + } + } + + +#if (NDEBUG & NDEBUG_DMA) + printk("scsi%d : polled DMA transfer complete, basr 0x%X, sr 0x%X\n", + instance->host_no, tmp, NCR5380_read(STATUS_REG)); +#endif + + NCR5380_write(MODE_REG, MR_BASE); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + + residue = NCR5380_dma_residual(instance); + c -= residue; + *count -= c; + *data += c; + *phase = NCR5380_read(STATUS_REG) & PHASE_MASK; + +#ifdef READ_OVERRUNS + if (*phase == p && (p & SR_IO) && residue == 0) { + if (overrun) { +#if (NDEBUG & NDEBUG_DMA) + printk("Got an input overrun, using saved byte\n"); +#endif + **data = saved_data; + *data += 1; + *count -= 1; + cnt = toPIO = 1; + } else { + printk("No overrun??\n"); + cnt = toPIO = 2; + } +#if (NDEBUG & NDEBUG_DMA) + printk("Doing %d-byte PIO to 0x%X\n", cnt, *data); +#endif + NCR5380_transfer_pio(instance, phase, &cnt, data); + *count -= toPIO - cnt; + } +#endif + +#if (NDEBUG & NDEBUG_DMA) + printk("Return with data ptr = 0x%X, count %d, last 0x%X, next 0x%X\n", + *data, *count, *(*data+*count-1), *(*data+*count)); +#endif + return 0; + +#elif defined(REAL_DMA) + return 0; +#else /* defined(REAL_DMA_POLL) */ + if (p & SR_IO) { + if (!(foo = NCR5380_pread(instance, d, c - 1))) { + /* + * We can't disable DMA mode after successfully transfering + * what we plan to be the last byte, since that would open up + * a race condition where if the target asserted REQ before + * we got the DMA mode reset, the NCR5380 would have latched + * an additional byte into the INPUT DATA register and we'd + * have dropped it. + * + * The workarround was to transfer one fewer bytes than we + * intended to with the pseudo-DMA read function, wait for + * the chip to latch the last byte, read it, and then disable + * pseudo-DMA mode. + * + * After REQ is asserted, the NCR5380 asserts DRQ and ACK. + * REQ is deasserted when ACK is asserted, and not reasserted + * until ACK goes false. Since the NCR5380 won't lower ACK + * until DACK is asserted, which won't happen unless we twiddle + * the DMA port or we take the NCR5380 out of DMA mode, we + * can gurantee that we won't handshake another extra + * byte. + */ + + while (!(NCR5380_read(BUS_AND_STATUS_REG) & BASR_DRQ)); + /* Wait for clean handshake */ + while (NCR5380_read(STATUS_REG) & SR_REQ); + d[c - 1] = NCR5380_read(INPUT_DATA_REG); + } + } else { + int timeout; + if (!(foo = NCR5380_pwrite(instance, d, c))) { + /* + * Wait for the last byte to be sent. If REQ is being asserted for + * the byte we're interested, we'll ACK it and it will go false. + */ + if (!(hostdata->flags & FLAG_HAS_LAST_BYTE_SENT)) { + timeout = 20000; +#if 1 +#if 1 + while (!(NCR5380_read(BUS_AND_STATUS_REG) & + BASR_DRQ) && (NCR5380_read(BUS_AND_STATUS_REG) & + BASR_PHASE_MATCH)); +#else + if (NCR5380_read(STATUS_REG) & SR_REQ) { + for (; timeout && + !(NCR5380_read(BUS_AND_STATUS_REG) & BASR_ACK); + --timeout); + for (; timeout && (NCR5380_read(STATUS_REG) & SR_REQ); + --timeout); + } +#endif + + +#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) + if (!timeout) + printk("scsi%d : timed out on last byte\n", + instance->host_no); +#endif + + + if (hostdata->flags & FLAG_CHECK_LAST_BYTE_SENT) { + hostdata->flags &= ~FLAG_CHECK_LAST_BYTE_SENT; + if (NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT) { + hostdata->flags |= FLAG_HAS_LAST_BYTE_SENT; +#if (NDEBUG & NDEBUG_LAST_BYTE_SENT) + printk("scsi%d : last bit sent works\n", + instance->host_no); +#endif + } + } + } else + while (!(NCR5380_read(TARGET_COMMAND_REG) & TCR_LAST_BYTE_SENT)); +#else + udelay (5); +#endif + } + } + + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + NCR5380_write(MODE_REG, MR_BASE); + + *data = d + c; + *count = 0; + *phase = (NCR5380_read(STATUS_REG & PHASE_MASK)); +#if defined(PSEUDO_DMA) && !defined(UNSAFE) + sti(); +#endif /* defined(REAL_DMA_POLL) */ + 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, transfersize; + 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) || defined(REAL_DMA_POLL) +#ifdef NCR5380_dma_xfer_len + if (!scsi_devices[cmd->index].borken && + (transfersize = NCR5380_dma_xfer_len(instance, cmd)) != 0) { +#else + if (!scsi_devices[cmd->index].borken && + (transfersize = cmd->transfersize) && + cmd->SCp.this_residual && !(cmd->SCp.this_residual % + transfersize)) { +#endif + len = 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 -= transfersize - len; + } else +#endif /* defined(REAL_DMA) || defined(REAL_DMA_POLL) */ + 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); + + /* + * I'm not sure what the correct thing to do here is : + * + * If the command that just executed is NOT a request + * sense, the obvious thing to do is to set the result + * code to the values of the stored parameters. + * + * If it was a REQUEST SENSE command, we need some way + * to differentiate between the failure code of the original + * and the failure code of the REQUEST sense - the obvious + * case is success, where we fall through and leave the result + * code unchanged. + * + * The non-obvious place is where the REQUEST SENSE failed + */ + + 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); + + while ((NCR5380_read(STATUS_REG) & SR_BSY) && + !hostdata->connected); + 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); + /* Wait for bus free to avoid nasty timeouts */ + while ((NCR5380_read(STATUS_REG) & SR_BSY) && + !hostdata->connected); + 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 + */ + + printk("Unknown message!\n"); + +#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(BUS_AND_STATUS_REG) & BASR_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->dmalen - 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); + printk(" basr 0x%X, sr 0x%X\n", + NCR5380_read(BUS_AND_STATUS_REG), NCR5380_read(STATUS_REG)); +#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 (Scsi_Cmnd *cmd) + * + * Purpose : reset the SCSI bus. + * + * Returns : 0 + * + */ + +#ifndef NCR5380_reset +static +#endif +int NCR5380_reset (Scsi_Cmnd *cmd) { + NCR5380_local_declare(); + NCR5380_setup(cmd->host); + + cli(); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE | ICR_ASSERT_RST); + udelay(1); + NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); + sti(); + + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.h new file mode 100644 index 000000000..359f1509b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/NCR5380.h @@ -0,0 +1,323 @@ +/* + * NCR 5380 defines + * + * Copyright 1993, Drew Eckhardt + * Visionary Computing + * (Unix consulting and custom programming) + * drew@colorado.edu + * +1 (303) 666-5836 + * + * DISTRIBUTION RELEASE 4 + * + * 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 $ + * Revision 1.3 1994/01/19 05:24:40 drew + * Added support for TCR LAST_BYTE_SENT bit. + * + * Revision 1.3 1994/01/19 05:24:40 drew + * Added support for TCR LAST_BYTE_SENT bit. + * + * Revision 1.2 1994/01/15 06:14:11 drew + * REAL DMA support, bug fixes. + * + * Revision 1.1 1994/01/15 06:00:54 drew + * Initial revision + */ + +#ifndef NCR5380_H +#define NCR5380_H + +#define NCR5380_PUBLIC_RELEASE 4 + +#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 +#define NDEBUG_LAST_BYTE_SENT 0x20000 + +/* + * 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_REG 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 and dma_channel fields of the + * Scsi_Host structure + */ + +#define IRQ_NONE 255 +#define DMA_NONE 255 +#define IRQ_AUTO 254 +#define DMA_AUTO 254 + +#define FLAG_HAS_LAST_BYTE_SENT 1 /* NCR53c81 or better */ +#define FLAG_CHECK_LAST_BYTE_SENT 2 /* Only test once */ + +#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 */ +#if defined(REAL_DMA) || defined(REAL_DMA_POLL) + 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 */ + int flags; +#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 (Scsi_Cmnd *cmd); +#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) || defined(REAL_DMA_POLL) +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); + +#if (defined(REAL_DMA) || defined(REAL_DMA_POLL)) && defined(i386) +static __inline__ int NCR5380_i386_dma_setup (struct Scsi_Host *instance, + unsigned char *ptr, unsigned int count, unsigned char mode) { + unsigned limit; + + if (instance->dma_channel <=3) { + if (count > 65536) + count = 65536; + limit = 65536 - (((unsigned) ptr) & 0xFFFF); + } else { + if (count > 65536 * 2) + count = 65536 * 2; + limit = 65536* 2 - (((unsigned) ptr) & 0x1FFFF); + } + + if (count > limit) count = limit; + + if ((count & 1) || (((unsigned) ptr) & 1)) + panic ("scsi%d : attmpted unaligned DMA transfer\n", instance->host_no); + cli(); + disable_dma(instance->dma_channel); + clear_dma_ff(instance->dma_channel); + set_dma_addr(instance->dma_channel, (unsigned int) ptr); + set_dma_count(instance->dma_channel, count); + set_dma_mode(instance->dma_channel, mode); + enable_dma(instance->dma_channel); + sti(); + return count; +} + +static __inline__ int NCR5380_i386_dma_write_setup (struct Scsi_Host *instance, + unsigned char *src, unsigned int count) { + return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_WRITE); +} + +static __inline__ int NCR5380_i386_dma_read_setup (struct Scsi_Host *instance, + unsigned char *src, unsigned int count) { + return NCR5380_i386_dma_setup (instance, src, count, DMA_MODE_READ); +} + +static __inline__ int NCR5380_i386_dma_residual (struct Scsi_Host *instance) { + register int tmp; + cli(); + clear_dma_ff(instance->dma_channel); + tmp = get_dma_residue(instance->dma_channel); + sti(); + return tmp; +} +#endif /* defined(REAL_DMA) && defined(i386) */ +#endif __KERNEL_ +#endif /* ndef ASM */ +#endif /* NCR5380_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.c new file mode 100644 index 000000000..4939e6f0a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.c @@ -0,0 +1,2377 @@ +/* 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.101 1993/12/13 01:16:27 root Exp $ + * + + * $Log: aha152x.c,v $ + * Revision 0.101 1993/12/13 01:16:27 root + * - fixed STATUS phase (non-GOOD stati were dropped sometimes; + * fixes problems with CD-ROM sector size detection & media change) + * + * Revision 0.100 1993/12/10 16:58:47 root + * - fix for unsuccessful selections in case of non-continuous id assignments + * on the scsi bus. + * + * Revision 0.99 1993/10/24 16:19:59 root + * - fixed DATA IN (rare read errors gone) + * + * Revision 0.98 1993/10/17 12:54:44 root + * - fixed some recent fixes (shame on me) + * - moved initialization of scratch area to aha152x_queue + * + * 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=,,, + + 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 +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "constants.h" +#include +#include +#include +#include +#include + +/* 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_RESET /* resets should be rare */ +#define DEBUG_ABORT /* aborts too */ + +/* END OF DEFINES */ + +/* some additional "phases" for getphase() */ +#define P_BUSFREE 1 +#define P_PARITY 2 + +char *aha152x_id = "Adaptec 152x SCSI driver; $Revision: 0.101 $\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 )) + + +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: + * P_BUSFREE BUS FREE phase detected + * P_PARITY 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 P_BUSFREE; + 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 P_PARITY; + + make_acklow(); + } + else + 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=,,,\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 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; itarget, + SCpnt->lun, + *(unsigned char *)SCpnt->cmnd, + SCpnt->use_sg, + SCpnt->request_bufflen ); + disp_ports(); +#endif + + SCpnt->scsi_done = done; + + /* setup scratch area + SCp.ptr : buffer pointer + SCp.this_residual : buffer length + SCp.buffer : next buffer + SCp.buffers_residual : left buffers in list + SCp.phase : current state of the command */ + SCpnt->SCp.phase = not_issued; + if (SCpnt->use_sg) + { + SCpnt->SCp.buffer = (struct scatterlist *)SCpnt->request_buffer; + SCpnt->SCp.ptr = SCpnt->SCp.buffer->address; + SCpnt->SCp.this_residual = SCpnt->SCp.buffer->length; + SCpnt->SCp.buffers_residual = SCpnt->use_sg - 1; + } + else + { + SCpnt->SCp.ptr = (char *)SCpnt->request_buffer; + SCpnt->SCp.this_residual = SCpnt->request_bufflen; + SCpnt->SCp.buffer = NULL; + SCpnt->SCp.buffers_residual = 0; + } + + SCpnt->SCp.Status = CHECK_CONDITION; + SCpnt->SCp.Message = 0; + SCpnt->SCp.have_data_in = 0; + SCpnt->SCp.sent_command = 0; + + /* Turn led on, when this is the first command. */ + cli(); + commands++; + if(commands==1) + SETPORT( PORTA, 1 ); + +#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 SCSI fifo 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(Scsi_Cmnd * __unused) +{ + 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); + do_pause(10); + + 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(); + +#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("issueing command, "); +#endif + 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 + /* end selection attempt */ + CLRBITS(SCSISEQ, ENSELO|ENAUTOATNO ); + + /* 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(); + if(!(phase & ~P_MASK)) /* "real" phase */ + SETPORT(SCSISIG, phase); + 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 (probably we got an message before, that we have to + reject (SDTR, WDTR, etc.) */ + 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 + } + + CLRBITS( SXFRCTL0, ENDMA); + + SETPORT( SIMODE0, 0 ); + SETPORT( SIMODE1, ENPHASEMIS|ENREQINIT ); + + /* wait for data latch to become ready or a phase change */ + while( TESTLO( DMASTAT, INTSTAT ) ) + ; + + if( TESTHI( SSTAT1, PHASEMIS ) ) + aha152x_panic("unable to send message"); + + /* Leave MESSAGE OUT after transfer */ + SETPORT( SSTAT1, CLRATNO); + + SETPORT( SCSIDAT, message ); + + make_acklow(); + getphase(); + + 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) || GETPORT(SSTAT2) & (SFULL|SFCNT)) + printk("aha152x: P_CMD: %d(%d) bytes left in FIFO, resetting\n", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); + + /* reset fifo and enable writes */ + SETPORT(DMACNTRL0, WRITE_READ|RSTFIFO); + SETPORT(DMACNTRL0, ENDMA|WRITE_READ); + + /* clear transfer count and scsi fifo */ + SETPORT(SXFRCTL0, CH1|CLRSTCNT|CLRCH1 ); + SETPORT(SXFRCTL0, SCSIEN|DMAEN|CH1); + + /* missing phase raises INTSTAT */ + 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( DATAPORT, + ¤t_SC->cmnd, + COMMAND_SIZE(current_SC->cmnd[0])>>1 ); + +#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) || defined(DEBUG_TIMING) + printk("inbound message ( MESSAGE REJECT ), "); +#endif + break; + + case SAVE_POINTERS: +#if defined(DEBUG_MSGI) + printk("inbound message ( SAVE DATA POINTERS ), "); +#endif + break; + + 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(SCSIBUS); + +#if defined(DEBUG_MSGI) + printk("length (%d), ", i); +#endif + +#if defined(DEBUG_MSGI) + printk("code ( "); +#endif + + make_acklow(); + if(getphase()!=P_MSGI) + break; + + code = GETPORT(SCSIBUS); + + switch( code ) + { + case 0x00: +#if defined(DEBUG_MSGI) + printk("MODIFY DATA POINTER "); +#endif + SETPORT(SCSISIG, P_MSGI|ATNO); + break; + case 0x01: +#if defined(DEBUG_MSGI) + printk("SYNCHRONOUS DATA TRANSFER REQUEST "); +#endif + SETPORT(SCSISIG, P_MSGI|ATNO); + break; + case 0x02: +#if defined(DEBUG_MSGI) + printk("EXTENDED IDENTIFY "); +#endif + break; + case 0x03: +#if defined(DEBUG_MSGI) + printk("WIDE DATA TRANSFER REQUEST "); +#endif + SETPORT(SCSISIG, P_MSGI|ATNO); + break; + default: +#if defined(DEBUG_MSGI) + if( code & 0x80 ) + printk("reserved (%d) ", code ); + else + printk("vendor specific (%d) ", code); +#endif + SETPORT(SCSISIG, P_MSGI|ATNO); + break; + } +#if defined(DEBUG_MSGI) + printk(" ), data ( "); +#endif + while( --i && (make_acklow(), getphase()==P_MSGI)) + { +#if defined(DEBUG_MSGI) + printk("%x ", GETPORT(SCSIBUS) ); +#else + GETPORT(SCSIBUS); +#endif + } +#if defined(DEBUG_MSGI) + printk(" ), "); +#endif + /* We reject all extended messages. To do this + we just enter MSGO by asserting ATN. Since + we have already identified a REJECT message + will be sent. */ + SETPORT(SCSISIG, P_MSGI|ATNO); + } + break; + + default: + printk("unsupported inbound message %x, ", current_SC->SCp.Message); + break; + + } + + make_acklow(); + phase=getphase(); + } + + /* clear SCSI fifo on BUSFREE */ + if(phase==P_BUSFREE) + SETPORT(SXFRCTL0, CH1|CLRCH1); + + 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); + + SETPORT( SIMODE0, 0 ); + SETPORT( SIMODE1, ENREQINIT ); + + if( TESTHI( SSTAT1, PHASEMIS ) ) + printk("aha152x: passing STATUS phase"); + + current_SC->SCp.Status = GETPORT( SCSIBUS ); + make_acklow(); + getphase(); + +#if defined(DEBUG_STATUS) + printk("inbound status "); + print_status( current_SC->SCp.Status ); + printk(", "); +#endif + 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 + + if(GETPORT(FIFOSTAT) || GETPORT(SSTAT2) & (SFULL|SFCNT)) + printk("aha152x: P_DATAI: %d(%d) bytes left in FIFO, resetting\n", + GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT)); + + /* reset host fifo */ + SETPORT(DMACNTRL0, RSTFIFO); + SETPORT(DMACNTRL0, RSTFIFO|ENDMA); + + SETPORT(SXFRCTL0, CH1|SCSIEN|DMAEN ); + + SETPORT( SIMODE0, 0 ); + SETPORT( SIMODE1, ENPHASEMIS|ENBUSFREE ); + + /* 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 + + 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( DATAPORT, current_SC->SCp.ptr, data_count ); +#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) || GETPORT(SSTAT2) & (SFULL|SFCNT) ) + { + printk("%d(%d) left in FIFO, ", GETPORT(FIFOSTAT), GETPORT(SSTAT2) & (SFULL|SFCNT) ); + 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( DATAPORT, current_SC->SCp.ptr, data_count ); + 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) & (SFULL|SFCNT); + + 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 P_BUSFREE: /* 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 P_PARITY: /* 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: + printk("aha152x: unexpected phase\n"); + 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("); SFCNT ( %d ); ", s & (SFULL|SFCNT) ); + +#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; icmnd[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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha152x.h new file mode 100644 index 000000000..7996f812b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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 + +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(Scsi_Cmnd *); +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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.c new file mode 100644 index 000000000..47904377e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.c @@ -0,0 +1,924 @@ +/* $Id: aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $ + * linux/kernel/aha1542.c + * + * Copyright (C) 1992 Tommy Thorn + * + * Modified by Eric Youngdale + * Use request_irq and request_dma to help prevent unexpected conflicts + * Set up on-board DMA controller, such that we do not have to + * have the bios enabled to use the aha1542. + * Modified by David Gentzel + * Don't call request_dma if dma mask is 0 (for BusLogic BT-445S VL-Bus controller). + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" + +#include "aha1542.h" + +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif +/* +static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1542.c,v 1.1 1992/07/24 06:27:38 root Exp root $"; +*/ + +/* The adaptec can be configured for quite a number of addresses, but +I generally do not want the card poking around at random. We allow +two addresses - this allows people to use the Adaptec with a Midi +card, which also used 0x330 */ + +static unsigned int bases[]={0x330, 0x334}; + +/* 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 + +#define BIOS_TRANSLATION_1632 0 /* Used by some old 1542A boards */ +#define BIOS_TRANSLATION_6432 1 /* Default case these days */ +#define BIOS_TRANSLATION_25563 2 /* Big disk case */ + +struct aha1542_hostdata{ + /* This will effectively start both of them at the first mailbox */ + int bios_translation; /* Mapping bios uses - for compatibility */ + 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 struct Scsi_Host * aha_host[7] = {NULL,}; /* One for each IRQ level (9-15) */ + + + + +#define WAITnexttimeout 3000000 + +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; \ + register WAITtimeout = WAITnexttimeout; \ + while (1) { \ + WAITbits = inb(port) & (mask); \ + if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ + break; \ + if (--WAITtimeout == 0) goto fail; \ + } \ + } + +static void aha1542_stat(void) +{ +/* int s = inb(STATUS), i = inb(INTRFLAGS); + printk("status=%x intrflags=%x\n", s, i, WAITnexttimeout-WAITtimeout); */ +} + +static int aha1542_out(unsigned int base, unchar *cmdp, int len) +{ + while (len--) + { + WAIT(STATUS(base), CDF, 0, CDF); + outb(*cmdp++, DATA(base)); + } + return 0; + fail: + printk("aha1542_out failed(%d): ", len+1); aha1542_stat(); + return 1; +} + +static int aha1542_in(unsigned int base, unchar *cmdp, int len) +{ + while (len--) + { + WAIT(STATUS(base), DF, DF, 0); + *cmdp++ = inb(DATA(base)); + } + return 0; + fail: + printk("aha1542_in failed(%d): ", len+1); aha1542_stat(); + return 1; +} + +static int makecode(unsigned hosterr, unsigned scsierr) +{ + switch (hosterr) { + case 0x0: + case 0xa: /* Linked command complete without error and linked normally */ + case 0xb: /* Linked command complete without error, interrupt generated */ + hosterr = 0; + break; + + case 0x11: /* Selection time out-The initiator selection or target + reselection was not complete within the SCSI Time out period */ + hosterr = DID_TIME_OUT; + break; + + case 0x12: /* Data overrun/underrun-The target attempted to transfer more data + thean was allocated by the Data Length field or the sum of the + Scatter / Gather Data Length fields. */ + + case 0x13: /* Unexpected bus free-The target dropped the SCSI BSY at an unexpected time. */ + + case 0x15: /* MBO command was not 00, 01 or 02-The first byte of the CB was + invalid. This usually indicates a software failure. */ + + case 0x16: /* Invalid CCB Operation Code-The first byte of the CCB was invalid. + This usually indicates a software failure. */ + + case 0x17: /* Linked CCB does not have the same LUN-A subsequent CCB of a set + of linked CCB's does not specify the same logical unit number as + the first. */ + case 0x18: /* Invalid Target Direction received from Host-The direction of a + Target Mode CCB was invalid. */ + + case 0x19: /* Duplicate CCB Received in Target Mode-More than once CCB was + received to service data transfer between the same target LUN + and initiator SCSI ID in the same direction. */ + + case 0x1a: /* Invalid CCB or Segment List Parameter-A segment list with a zero + length segment or invalid segment list boundaries was received. + A CCB parameter was invalid. */ + DEB(printk("Aha1542: %x %x\n", hosterr, scsierr)); + hosterr = DID_ERROR; /* Couldn't find any better */ + break; + + case 0x14: /* Target bus phase sequence failure-An invalid bus phase or bus + phase sequence was requested by the target. The host adapter + will generate a SCSI Reset Condition, notifying the host with + a SCRD interrupt */ + hosterr = DID_RESET; + break; + default: + printk("makecode: unknown hoststatus %x\n", hosterr); + break; + } + return scsierr|(hosterr << 16); +} + +static int aha1542_test_port(int bse, struct Scsi_Host * shpnt) +{ + int i; + unchar inquiry_cmd[] = {CMD_INQUIRY }; + unchar inquiry_result[4]; + unchar *cmdp; + int len; + volatile int debug = 0; + + /* 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(SRST|IRST/*|SCRST*/, CONTROL(bse)); + + i = jiffies + 2; + while (i>jiffies); /* Wait a little bit for things to settle down. */ + + debug = 1; + /* Expect INIT and IDLE, any of the others are bad */ + WAIT(STATUS(bse), STATMASK, INIT|IDLE, STST|DIAGF|INVDCMD|DF|CDF); + + debug = 2; + /* Shouldn't have generated any interrupts during reset */ + if (inb(INTRFLAGS(bse))&INTRMASK) goto fail; + + + /* Perform a host adapter inquiry instead so we do not need to set + up the mailboxes ahead of time */ + + aha1542_out(bse, inquiry_cmd, 1); + + debug = 3; + len = 4; + cmdp = &inquiry_result[0]; + + while (len--) + { + WAIT(STATUS(bse), DF, DF, 0); + *cmdp++ = inb(DATA(bse)); + } + + debug = 8; + /* Reading port should reset DF */ + if (inb(STATUS(bse)) & DF) goto fail; + + debug = 9; + /* When HACC, command is completed, and we're though testing */ + WAIT(INTRFLAGS(bse), HACC, HACC, 0); + /* now initialize adapter */ + + debug = 10; + /* Clear interrupts */ + outb(IRST, CONTROL(bse)); + + debug = 11; + + return debug; /* 1 = ok */ + fail: + return 0; /* 0 = not ok */ +} + +static const char aha_ident[] = "Adaptec 1542"; + +/* What's this little function for? */ +const char *aha1542_info(void) +{ + return aha_ident; +} + +/* A "high" level interrupt handler */ +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(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(shost->io_port))); + }; +#endif + number_serviced = 0; + + while(1==1){ + aha1542_intr_reset(shost->io_port); + + cli(); + 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 != HOSTDATA(shost)->aha1542_last_mbi_used); + + if(mb[mbi].status == 0){ + sti(); + /* Hmm, no mail. Must have read it the last time around */ + if (number_serviced) return; + printk("aha1542.c: interrupt received, but no mail.\n"); + return; + }; + + mbo = (scsi2int(mb[mbi].ccbptr) - ((unsigned int) &ccb[0])) / sizeof(struct ccb); + mbistatus = mb[mbi].status; + mb[mbi].status = 0; + HOSTDATA(shost)->aha1542_last_mbi_used = mbi; + sti(); + +#ifdef DEBUG + { + if (ccb[mbo].tarstat|ccb[mbo].hastat) + printk("aha1542_command: returning %x (status %d)\n", + ccb[mbo].tarstat + ((int) ccb[mbo].hastat << 16), mb[mbi].status); + }; +#endif + + if(mbistatus == 3) continue; /* Aborted command not found */ + +#ifdef DEBUG + printk("...done %d %d\n",mbo, mbi); +#endif + + SCtmp = HOSTDATA(shost)->SCint[mbo]; + + if (!SCtmp || !SCtmp->scsi_done) { + printk("aha1542_intr_handle: Unexpected interrupt\n"); + return; + } + + my_done = SCtmp->scsi_done; + if (SCtmp->host_scribble) scsi_free(SCtmp->host_scribble, 512); + + /* Fetch the sense data, and tuck it away, in the required slot. The + Adaptec automatically fetches it, and there is no guarantee that + we will still have it in the cdb when we come back */ + if (ccb[mbo].tarstat == 2) + memcpy(SCtmp->sense_buffer, &ccb[mbo].cdb[ccb[mbo].cdblen], + sizeof(SCtmp->sense_buffer)); + + + /* is there mail :-) */ + + /* more error checking left out here */ + if (mbistatus != 1) + /* This is surely wrong, but I don't know what's right */ + errstatus = makecode(ccb[mbo].hastat, ccb[mbo].tarstat); + else + errstatus = 0; + +#ifdef DEBUG + if(errstatus) printk("(aha1542 error:%x %x %x) ",errstatus, + ccb[mbo].hastat, ccb[mbo].tarstat); +#endif + + if (ccb[mbo].tarstat == 2) { +#ifdef DEBUG + int i; +#endif + DEB(printk("aha1542_intr_handle: sense:")); +#ifdef DEBUG + for (i = 0; i < 12; i++) + printk("%02x ", ccb[mbo].cdb[ccb[mbo].cdblen+i]); + printk("\n"); +#endif + /* + DEB(printk("aha1542_intr_handle: buf:")); + for (i = 0; i < bufflen; i++) + printk("%02x ", ((unchar *)buff)[i]); + printk("\n"); + */ + } + DEB(if (errstatus) printk("aha1542_intr_handle: returning %6x\n", errstatus)); + SCtmp->result = errstatus; + HOSTDATA(shost)->SCint[mbo] = NULL; /* This effectively frees up the mailbox slot, as + far as queuecommand is concerned */ + my_done(SCtmp); + number_serviced++; + }; +} + +int aha1542_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + unchar ahacmd = CMD_START_SCSI; + unchar direction; + unchar *cmd = (unchar *) SCpnt->cmnd; + unchar target = SCpnt->target; + unchar lun = SCpnt->lun; + 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;}); + + if(*cmd == REQUEST_SENSE){ +#ifndef DEBUG + if (bufflen != sizeof(SCpnt->sense_buffer)) { + printk("Wrong buffer length supplied for request sense (%d)\n",bufflen); + panic("aha1542.c"); + }; +#endif + SCpnt->result = 0; + done(SCpnt); + return 0; + }; + +#ifdef DEBUG + if (*cmd == READ_10 || *cmd == WRITE_10) + i = xscsi2int(cmd+2); + else if (*cmd == READ_6 || *cmd == WRITE_6) + i = scsi2int(cmd+2); + else + i = -1; + if (done) + printk("aha1542_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); + else + printk("aha1542_command: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); + aha1542_stat(); + printk("aha1542_queuecommand: dumping scsi cmd:"); + for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]); + printk("\n"); + if (*cmd == WRITE_10 || *cmd == WRITE_6) + return 0; /* we are still testing, so *don't* write */ +#endif +/* Use the outgoing mailboxes in a round-robin fashion, because this + is how the host adapter will scan for them */ + + cli(); + mbo = HOSTDATA(SCpnt->host)->aha1542_last_mbo_used + 1; + if (mbo >= AHA1542_MAILBOXES) mbo = 0; + + do{ + if(mb[mbo].status == 0 && HOSTDATA(SCpnt->host)->SCint[mbo] == NULL) + break; + mbo++; + if (mbo >= AHA1542_MAILBOXES) mbo = 0; + } while (mbo != HOSTDATA(SCpnt->host)->aha1542_last_mbo_used); + + if(mb[mbo].status || HOSTDATA(SCpnt->host)->SCint[mbo]) + panic("Unable to find empty mailbox for aha1542.\n"); + + HOSTDATA(SCpnt->host)->SCint[mbo] = SCpnt; /* This will effectively prevent someone else from + screwing with this cdb. */ + + HOSTDATA(SCpnt->host)->aha1542_last_mbo_used = mbo; + sti(); + +#ifdef DEBUG + printk("Sending command (%d %x)...",mbo, done); +#endif + + any2scsi(mb[mbo].ccbptr, &ccb[mbo]); /* This gets trashed for some reason*/ + + memset(&ccb[mbo], 0, sizeof(struct ccb)); + + ccb[mbo].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */ + + direction = 0; + if (*cmd == READ_10 || *cmd == READ_6) + direction = 8; + else if (*cmd == WRITE_10 || *cmd == WRITE_6) + direction = 16; + + memcpy(ccb[mbo].cdb, cmd, ccb[mbo].cdblen); + + if (SCpnt->use_sg) { + struct scatterlist * sgpnt; + struct chain * cptr; +#ifdef DEBUG + unsigned char * ptr; +#endif + int i; + ccb[mbo].op = 2; /* SCSI Initiator Command w/scatter-gather*/ + SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); + sgpnt = (struct scatterlist *) SCpnt->request_buffer; + cptr = (struct chain *) SCpnt->host_scribble; + if (cptr == NULL) panic("aha1542.c: unable to allocate DMA memory\n"); + for(i=0; iuse_sg; i++) { + if(sgpnt[i].length == 0 || SCpnt->use_sg > 16 || + (((int)sgpnt[i].address) & 1) || (sgpnt[i].length & 1)){ + unsigned char * ptr; + printk("Bad segment list supplied to aha1542.c (%d, %d)\n",SCpnt->use_sg,i); + for(i=0;iuse_sg;i++){ + printk("%d: %x %x %d\n",i,(unsigned int) sgpnt[i].address, (unsigned int) sgpnt[i].alt_address, + sgpnt[i].length); + }; + printk("cptr %x: ",(unsigned int) cptr); + ptr = (unsigned char *) &cptr[i]; + for(i=0;i<18;i++) printk("%02x ", ptr[i]); + panic("Foooooooood fight!"); + }; + any2scsi(cptr[i].dataptr, sgpnt[i].address); + if(((unsigned int) sgpnt[i].address) & 0xff000000) goto baddma; + any2scsi(cptr[i].datalen, sgpnt[i].length); + }; + any2scsi(ccb[mbo].datalen, SCpnt->use_sg * sizeof(struct chain)); + if(((unsigned int) buff & 0xff000000)) goto baddma; + any2scsi(ccb[mbo].dataptr, cptr); +#ifdef DEBUG + printk("cptr %x: ",cptr); + ptr = (unsigned char *) cptr; + for(i=0;i<18;i++) printk("%02x ", ptr[i]); +#endif + } else { + ccb[mbo].op = 0; /* SCSI Initiator Command */ + SCpnt->host_scribble = NULL; + any2scsi(ccb[mbo].datalen, bufflen); + any2scsi(ccb[mbo].dataptr, buff); + }; + ccb[mbo].idlun = (target&7)<<5 | direction | (lun & 7); /*SCSI Target Id*/ + ccb[mbo].rsalen = 12; + ccb[mbo].linkptr[0] = ccb[mbo].linkptr[1] = ccb[mbo].linkptr[2] = 0; + ccb[mbo].commlinkid = 0; + +#ifdef DEBUGd + { int i; + printk("aha1542_command: sending.. "); + for (i = 0; i < sizeof(ccb[mbo])-10; i++) + printk("%02x ", ((unchar *)&ccb[mbo])[i]); + }; +#endif + + if (done) { + DEB(printk("aha1542_queuecommand: now waiting for interrupt "); aha1542_stat()); + SCpnt->scsi_done = done; + mb[mbo].status = 1; + aha1542_out(SCpnt->host->io_port, &ahacmd, 1); /* start scsi command */ + DEB(aha1542_stat()); + } + else + printk("aha1542_queuecommand: done can't be NULL\n"); + + return 0; + baddma: + panic("Buffer at address > 16Mb used for 1542B"); +} + +static void internal_done(Scsi_Cmnd * SCpnt) +{ + SCpnt->SCp.Status++; +} + +int aha1542_command(Scsi_Cmnd * SCpnt) +{ + DEB(printk("aha1542_command: ..calling aha1542_queuecommand\n")); + + aha1542_queuecommand(SCpnt, internal_done); + + SCpnt->SCp.Status = 0; + while (!SCpnt->SCp.Status); + return SCpnt->result; +} + +/* Initialize mailboxes */ +static void setup_mailboxes(int bse, struct Scsi_Host * shpnt) +{ + int i; + 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= 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)->bios_translation = trans; + if(trans == 2) + printk("aha1542.c: Using extended bios translation\n"); + 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)); + sti(); +#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 */ + 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 + it is available to be used again. Until this gets worked out, we will + leave it commented out. */ + +int aha1542_abort(Scsi_Cmnd * SCpnt, int i) +{ +#if 0 + unchar ahacmd = CMD_START_SCSI; + int mbo; +#endif + DEB(printk("aha1542_abort\n")); +#if 0 + cli(); + for(mbo = 0; mbo < AHA1542_MAILBOXES; mbo++) + if (SCpnt == HOSTDATA(SCpnt->host)->SCint[mbo]){ + mb[mbo].status = 2; /* Abort command */ + aha1542_out(&ahacmd, 1); /* start scsi command */ + sti(); + break; + }; +#endif + return 0; +} + +/* We do not implement a reset function here, but the upper level code assumes + that it will get some kind of response for the command in SCpnt. We must + oblige, or the command will hang the scsi system */ + +int aha1542_reset(Scsi_Cmnd * SCpnt) +{ + DEB(printk("aha1542_reset called\n")); + if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + return 0; +} + +#ifdef CONFIG_BLK_DEV_SD +#include "sd.h" +#endif + +int aha1542_biosparam(int size, int dev, int * ip) +{ + int translation_algorithm; +#ifdef CONFIG_BLK_DEV_SD + Scsi_Device *disk; + + disk = rscsi_disks[MINOR(dev) >> 4].device; + translation_algorithm = HOSTDATA(disk->host)->bios_translation; + /* Should this be > 1024, or >= 1024? Enquiring minds want to know. */ + if((size>>11) > 1024 && translation_algorithm == 2) { + /* Please verify that this is the same as what DOS returns */ + ip[0] = 255; + ip[1] = 63; + ip[2] = size /255/63; + } else { + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; + }; +/* if (ip[2] >= 1024) ip[2] = 1024; */ +#endif + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.h new file mode 100644 index 000000000..e6c547ebc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1542.h @@ -0,0 +1,157 @@ +#ifndef _AHA1542_H + +/* $Id: aha1542.h,v 1.1 1992/07/24 06:27:38 root Exp root $ + * + * Header file for the adaptec 1542 driver for Linux + * + * $Log: aha1542.h,v $ + * Revision 1.1 1992/07/24 06:27:38 root + * Initial revision + * + * Revision 1.2 1992/07/04 18:41:49 root + * Replaced distribution with current drivers + * + * Revision 1.3 1992/06/23 23:58:20 root + * Fixes. + * + * Revision 1.2 1992/05/26 22:13:23 root + * Changed bug that prevented DMA above first 2 mbytes. + * + * Revision 1.1 1992/05/22 21:00:29 root + * Initial revision + * + * Revision 1.1 1992/04/24 18:01:50 root + * Initial revision + * + * Revision 1.1 1992/04/02 03:23:13 drew + * Initial revision + * + * Revision 1.3 1992/01/27 14:46:29 tthorn + * *** empty log message *** + * + */ + +#include + +/* I/O Port interface 4.2 */ +/* READ */ +#define STATUS(base) base +#define STST 0x80 /* Self Test in Progress */ +#define DIAGF 0x40 /* Internal Diagonostic Failure */ +#define INIT 0x20 /* Mailbox Initialization Required */ +#define IDLE 0x10 /* SCSI Host Adapter Idle */ +#define CDF 0x08 /* Command/Data Out Port Full */ +#define DF 0x04 /* Data In Port Full */ +#define INVDCMD 0x01 /* Invalid H A Command */ +#define STATMASK 0xfd /* 0x02 is reserved */ + +#define INTRFLAGS(base) (STATUS(base)+2) +#define ANYINTR 0x80 /* Any Interrupt */ +#define SCRD 0x08 /* SCSI Reset Detected */ +#define HACC 0x04 /* HA Command Complete */ +#define MBOA 0x02 /* MBO Empty */ +#define MBIF 0x01 /* MBI Full */ +#define INTRMASK 0x8f + +/* WRITE */ +#define CONTROL(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(base) (STATUS(base)+1) +#define CMD_NOP 0x00 /* No Operation */ +#define CMD_MBINIT 0x01 /* Mailbox Initialization */ +#define CMD_START_SCSI 0x02 /* Start SCSI Command */ +#define CMD_INQUIRY 0x04 /* Adapter Inquiry */ +#define CMD_EMBOI 0x05 /* Enable MailBox Out Interrupt */ +#define CMD_BUSON_TIME 0x07 /* Set Bus-On Time */ +#define CMD_BUSOFF_TIME 0x08 /* Set Bus-Off Time */ +#define CMD_RETDEVS 0x0a /* Return Installed Devices */ +#define CMD_RETCONF 0x0b /* Return Configuration Data */ +#define CMD_RETSETUP 0x0d /* Return Setup Data */ +#define CMD_ECHO 0x1f /* ECHO Command Data */ + +#define CMD_EXTBIOS 0x28 /* Return extend bios information only 1542C */ +#define CMD_MBENABLE 0x29 /* Set Mailbox Interface enable only 1542C */ + +/* Mailbox Definition 5.2.1 and 5.2.2 */ +struct mailbox { + unchar status; /* Command/Status */ + unchar ccbptr[3]; /* msb, .., lsb */ +}; + +/* This is used with scatter-gather */ +struct chain { + unchar datalen[3]; /* Size of this part of chain */ + unchar dataptr[3]; /* Location of data */ +}; + +/* These belong in scsi.h also */ +#define any2scsi(up, p) \ +(up)[0] = (((unsigned long)(p)) >> 16) ; \ +(up)[1] = (((unsigned long)(p)) >> 8); \ +(up)[2] = ((unsigned long)(p)); + +#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) + +#define xany2scsi(up, p) \ +(up)[0] = ((long)(p)) >> 24; \ +(up)[1] = ((long)(p)) >> 16; \ +(up)[2] = ((long)(p)) >> 8; \ +(up)[3] = ((long)(p)); + +#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ + + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) + +#define MAX_CDB 12 +#define MAX_SENSE 14 + +struct ccb { /* Command Control Block 5.3 */ + unchar op; /* Command Control Block Operation Code */ + unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */ + /* Outbound data transfer, length is checked*/ + /* Inbound data transfer, length is checked */ + /* Logical Unit Number */ + unchar cdblen; /* SCSI Command Length */ + unchar rsalen; /* Request Sense Allocation Length/Disable */ + unchar datalen[3]; /* Data Length (msb, .., lsb) */ + unchar dataptr[3]; /* Data Pointer */ + unchar linkptr[3]; /* Link Pointer */ + unchar commlinkid; /* Command Linking Identifier */ + unchar hastat; /* Host Adapter Status (HASTAT) */ + unchar tarstat; /* Target Device Status */ + unchar reserved[2]; + unchar cdb[MAX_CDB+MAX_SENSE];/* SCSI Command Descriptor Block */ + /* REQUEST SENSE */ +}; + +int aha1542_detect(int); +int aha1542_command(Scsi_Cmnd *); +int aha1542_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int aha1542_abort(Scsi_Cmnd *, int); +const char *aha1542_info(void); +int aha1542_reset(Scsi_Cmnd *); +int aha1542_biosparam(int, int, int*); + +#define AHA1542_MAILBOXES 8 +#define AHA1542_SCATTER 16 +#define AHA1542_CMDLUN 1 + +#ifndef NULL + #define NULL 0 +#endif + +#define AHA1542 {"Adaptec 1542", aha1542_detect, \ + aha1542_info, aha1542_command, \ + aha1542_queuecommand, \ + aha1542_abort, \ + aha1542_reset, \ + NULL, \ + aha1542_biosparam, \ + AHA1542_MAILBOXES, 7, AHA1542_SCATTER, AHA1542_CMDLUN \ + , 0, 1} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.c new file mode 100644 index 000000000..2cd1a3188 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.c @@ -0,0 +1,506 @@ +/* $Id$ + * 1993/03/31 + * linux/kernel/aha1740.c + * + * Based loosely on aha1542.c which is + * Copyright (C) 1992 Tommy Thorn and + * Modified by Eric Youngdale + * + * This file is aha1740.c, written and + * Copyright (C) 1992,1993 Brad McLean + * + * Modifications to makecode and queuecommand + * for proper handling of multiple devices courteously + * provided by Michael Weller, March, 1993 + * + * aha1740_makecode may still need even more work + * if it doesn't work for your devices, take a look. + */ + +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" + +#include "aha1740.h" + +/* IF YOU ARE HAVING PROBLEMS WITH THIS DRIVER, AND WANT TO WATCH + IT WORK, THEN: +#define DEBUG +*/ +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +/* +static const char RCSid[] = "$Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/aha1740.c,v 1.1 1992/07/24 06:27:38 root Exp root $"; +*/ + +static unsigned int slot, base; +static unsigned char irq_level; + +static struct ecb ecb[AHA1740_ECBS]; /* One for each queued operation */ + +static int aha1740_last_ecb_used = 0; /* optimization */ + +int aha1740_makecode(unchar *sense, unchar *status) +{ + struct statusword + { + ushort don:1, /* Command Done - No Error */ + du:1, /* Data underrun */ + :1, qf:1, /* Queue full */ + sc:1, /* Specification Check */ + dor:1, /* Data overrun */ + ch:1, /* Chaining Halted */ + intr:1, /* Interrupt issued */ + asa:1, /* Additional Status Available */ + sns:1, /* Sense information Stored */ + :1, ini:1, /* Initialization Required */ + me:1, /* Major error or exception */ + :1, eca:1, /* Extended Contingent alliance */ + :1; + } status_word; + int retval = DID_OK; + + status_word = * (struct statusword *) status; +#ifdef DEBUG +printk("makecode from %x,%x,%x,%x %x,%x,%x,%x",status[0],status[1],status[2],status[3], +sense[0],sense[1],sense[2],sense[3]); +#endif + if (!status_word.don) /* Anything abnormal was detected */ + { + if ( (status[1]&0x18) || status_word.sc ) /*Additional info available*/ + { + /* Use the supplied info for futher diagnostics */ + switch ( status[2] ) + { + case 0x12: + if ( status_word.dor ) + retval=DID_ERROR; /* It's an Overrun */ + /* If not overrun, assume underrun and ignore it! */ + case 0x00: /* No info, assume no error, should not occur */ + break; + case 0x11: + case 0x21: + retval=DID_TIME_OUT; + break; + case 0x0a: + retval=DID_BAD_TARGET; + break; + case 0x04: + case 0x05: + retval=DID_ABORT; /* Either by this driver or the AHA1740 + itself */ + break; + default: + retval=DID_ERROR; /* No further diagnostics possible */ + } + } + else + { /* Michael suggests, and Brad concurs: */ + if ( status_word.qf ) + { + retval = DID_TIME_OUT; /* forces a redo */ + /* I think this specific one should not happen -Brad */ + printk("aha1740.c: WARNING: AHA1740 queue overflow!\n"); + } + else if ( status[0]&0x60 ) + { + retval = DID_ERROR; /* Didn't found a better error */ + } + /* In any other case return DID_OK so for example + CONDITION_CHECKS make it through to the appropriate + device driver */ + } + } + /* Under all circumstances supply the target status -Michael */ + return status[3] | retval << 16; +} + +int aha1740_test_port(void) +{ + char name[4],tmp; + + /* Okay, look for the EISA ID's */ + name[0]= 'A' -1 + ((tmp = inb(HID0)) >> 2); /* First character */ + name[1]= 'A' -1 + ((tmp & 3) << 3); + name[1]+= ((tmp = inb(HID1)) >> 5)&0x7; /* Second Character */ + name[2]= 'A' -1 + (tmp & 0x1f); /* Third Character */ + name[3]=0; + tmp = inb(HID2); + if ( strcmp ( name, HID_MFG ) || inb(HID2) != HID_PRD ) + return 0; /* Not an Adaptec 174x */ + +/* if ( inb(HID3) != HID_REV ) + printk("aha1740: Warning; board revision of %d; expected %d\n", + inb(HID3),HID_REV); */ + + if ( inb(EBCNTRL) != EBCNTRL_VALUE ) + { + printk("aha1740: Board detected, but EBCNTRL = %x, so disabled it.\n", + inb(EBCNTRL)); + return 0; + } + + if ( inb(PORTADR) & PORTADDR_ENH ) + return 1; /* Okay, we're all set */ + + printk("aha1740: Board detected, but not in enhanced mode, so disabled it.\n"); + return 0; +} + +const char *aha1740_info(void) +{ + static char buffer[] = "Adaptec 174x (EISA)"; + return buffer; +} + +/* A "high" level interrupt handler */ +void aha1740_intr_handle(int foo) +{ + void (*my_done)(Scsi_Cmnd *); + int errstatus, adapstat; + int number_serviced; + struct ecb *ecbptr; + Scsi_Cmnd *SCtmp; + + number_serviced = 0; + + while(inb(G2STAT) & G2STAT_INTPEND) + { + DEB(printk("aha1740_intr top of loop.\n")); + adapstat = inb(G2INTST); + outb(G2CNTRL_IRST,G2CNTRL); /* interrupt reset */ + + switch ( adapstat & G2INTST_MASK ) + { + case G2INTST_CCBRETRY: + case G2INTST_CCBERROR: + case G2INTST_CCBGOOD: + ecbptr = (struct ecb *) ( ((ulong) inb(MBOXIN0)) + + ((ulong) inb(MBOXIN1) <<8) + + ((ulong) inb(MBOXIN2) <<16) + + ((ulong) inb(MBOXIN3) <<24) ); + outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */ + SCtmp = ecbptr->SCpnt; + if (SCtmp->host_scribble) + scsi_free(SCtmp->host_scribble, 512); + /* Fetch the sense data, and tuck it away, in the required slot. The + Adaptec automatically fetches it, and there is no guarantee that + we will still have it in the cdb when we come back */ + if ( (adapstat & G2INTST_MASK) == G2INTST_CCBERROR ) + { + memcpy(SCtmp->sense_buffer, ecbptr->sense, + sizeof(SCtmp->sense_buffer)); + errstatus = aha1740_makecode(ecbptr->sense,ecbptr->status); + } + else + errstatus = 0; + DEB(if (errstatus) printk("aha1740_intr_handle: returning %6x\n", errstatus)); + SCtmp->result = errstatus; + my_done = ecbptr->done; + memset(ecbptr,0,sizeof(struct ecb)); + if ( my_done ) + my_done(SCtmp); + break; + case G2INTST_HARDFAIL: + printk("aha1740 hardware failure!\n"); + panic("aha1740.c"); /* Goodbye */ + case G2INTST_ASNEVENT: + printk("aha1740 asynchronous event: %02x %02x %02x %02x %02x\n",adapstat, + inb(MBOXIN0),inb(MBOXIN1),inb(MBOXIN2),inb(MBOXIN3)); /* Say What? */ + outb(G2CNTRL_HRDY,G2CNTRL); /* Host Ready -> Mailbox in complete */ + break; + case G2INTST_CMDGOOD: + /* set immediate command success flag here: */ + break; + case G2INTST_CMDERROR: + /* Set immediate command failure flag here: */ + break; + } + number_serviced++; + }; +} + +int aha1740_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + unchar direction; + unchar *cmd = (unchar *) SCpnt->cmnd; + unchar target = SCpnt->target; + void *buff = SCpnt->request_buffer; + int bufflen = SCpnt->request_bufflen; + int ecbno; + DEB(int i); + + + if(*cmd == REQUEST_SENSE) + { + if (bufflen != sizeof(SCpnt->sense_buffer)) + { + printk("Wrong buffer length supplied for request sense (%d)\n",bufflen); + panic("aha1740.c"); + } + SCpnt->result = 0; + done(SCpnt); + return 0; + } + +#ifdef DEBUG + if (*cmd == READ_10 || *cmd == WRITE_10) + i = xscsi2int(cmd+2); + else if (*cmd == READ_6 || *cmd == WRITE_6) + i = scsi2int(cmd+2); + else + i = -1; + printk("aha1740_queuecommand: dev %d cmd %02x pos %d len %d ", target, *cmd, i, bufflen); + printk("scsi cmd:"); + for (i = 0; i < (COMMAND_SIZE(*cmd)); i++) printk("%02x ", cmd[i]); + printk("\n"); +#endif + + /* locate an available ecb */ + + cli(); + ecbno = aha1740_last_ecb_used + 1; /* An optimization */ + if (ecbno >= AHA1740_ECBS) ecbno = 0; + + do{ + if( ! ecb[ecbno].cmdw ) + break; + ecbno++; + if (ecbno >= AHA1740_ECBS ) ecbno = 0; + } while (ecbno != aha1740_last_ecb_used); + + if( ecb[ecbno].cmdw ) + panic("Unable to find empty ecb for aha1740.\n"); + + ecb[ecbno].cmdw = AHA1740CMD_INIT; /* SCSI Initiator Command doubles as reserved flag */ + + aha1740_last_ecb_used = ecbno; + sti(); + +#ifdef DEBUG + printk("Sending command (%d %x)...",ecbno, done); +#endif + + ecb[ecbno].cdblen = COMMAND_SIZE(*cmd); /* SCSI Command Descriptor Block Length */ + + direction = 0; + if (*cmd == READ_10 || *cmd == READ_6) + direction = 1; + else if (*cmd == WRITE_10 || *cmd == WRITE_6) + direction = 0; + + memcpy(ecb[ecbno].cdb, cmd, ecb[ecbno].cdblen); + + if (SCpnt->use_sg) + { + struct scatterlist * sgpnt; + struct aha1740_chain * cptr; + int i; +#ifdef DEBUG + unsigned char * ptr; +#endif + ecb[ecbno].sg = 1; /* SCSI Initiator Command w/scatter-gather*/ + SCpnt->host_scribble = (unsigned char *) scsi_malloc(512); + sgpnt = (struct scatterlist *) SCpnt->request_buffer; + cptr = (struct aha1740_chain *) SCpnt->host_scribble; + if (cptr == NULL) panic("aha1740.c: unable to allocate DMA memory\n"); + for(i=0; iuse_sg; i++) + { + cptr[i].dataptr = (long) sgpnt[i].address; + cptr[i].datalen = sgpnt[i].length; + } + ecb[ecbno].datalen = SCpnt->use_sg * sizeof(struct aha1740_chain); + ecb[ecbno].dataptr = (long) cptr; +#ifdef DEBUG + printk("cptr %x: ",cptr); + ptr = (unsigned char *) cptr; + for(i=0;i<24;i++) printk("%02x ", ptr[i]); +#endif + } + else + { + SCpnt->host_scribble = NULL; + ecb[ecbno].datalen = bufflen; + ecb[ecbno].dataptr = (long) buff; + } + ecb[ecbno].lun = SCpnt->lun; + ecb[ecbno].ses = 1; /* Suppress underrun errors */ + ecb[ecbno].dir= direction; + ecb[ecbno].ars=1; /* Yes, get the sense on an error */ + ecb[ecbno].senselen = 12; + ecb[ecbno].senseptr = (long) ecb[ecbno].sense; + ecb[ecbno].statusptr = (long) ecb[ecbno].status; + ecb[ecbno].done = done; + ecb[ecbno].SCpnt = SCpnt; +#ifdef DEBUG + { + int i; + printk("aha1740_command: sending.. "); + for (i = 0; i < sizeof(ecb[ecbno])-10; i++) + printk("%02x ", ((unchar *)&ecb[ecbno])[i]); + } + printk("\n"); +#endif + if (done) + { /* You may question the code below, which contains potentially + non-terminating while loops with interrupts disabled. So did + I when I wrote it, but the Adaptec Spec says the card is so fast, + that this problem virtually never occurs so I've kept it. We + do printk a warning first, so that you'll know if it happens. + In practive the only time we've seen this message is when some- + thing else is in the driver was broken, like _makecode(), or + when a scsi device hung the scsi bus. Even under these conditions, + The loop actually only cycled < 3 times (we instrumented it). */ + ulong adrs; + + DEB(printk("aha1740[%d] critical section\n",ecbno)); + cli(); + if ( ! (inb(G2STAT) & G2STAT_MBXOUT) ) + { + printk("aha1740[%d]_mbxout wait!\n",ecbno); + cli(); /* printk may have done a sti()! */ + } + while ( ! (inb(G2STAT) & G2STAT_MBXOUT) ); /* Oh Well. */ + adrs = (ulong) &(ecb[ecbno]); /* Spit the command */ + outb((char) (adrs&0xff), MBOXOUT0); /* out, note this set */ + outb((char) ((adrs>>8)&0xff), MBOXOUT1); /* of outb's must be */ + outb((char) ((adrs>>16)&0xff), MBOXOUT2); /* atomic */ + outb((char) ((adrs>>24)&0xff), MBOXOUT3); + if ( inb(G2STAT) & G2STAT_BUSY ) + { + printk("aha1740[%d]_attn wait!\n",ecbno); + cli(); + } + while ( inb(G2STAT) & G2STAT_BUSY ); /* And Again! */ + outb(ATTN_START | (target & 7), ATTN); /* Start it up */ + sti(); + DEB(printk("aha1740[%d] request queued.\n",ecbno)); + } + else + printk("aha1740_queuecommand: done can't be NULL\n"); + + return 0; +} + +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; +} + +int aha1740_command(Scsi_Cmnd * SCpnt) +{ + aha1740_queuecommand(SCpnt, internal_done); + + while (!internal_done_flag); + internal_done_flag = 0; + return internal_done_errcode; +} + +/* Query the board for its irq_level. Nothing else matters + in enhanced mode on an EISA bus. */ + +void aha1740_getconfig(void) +{ + static int intab[] = { 9,10,11,12,0,14,15,0 }; + + irq_level = intab [ inb(INTDEF)&0x7 ]; +} + +int aha1740_detect(int hostnum) +{ + memset(&ecb, 0, sizeof(struct ecb)); + DEB(printk("aha1740_detect: \n")); + + for ( slot=MINEISA; slot <= MAXEISA; slot++ ) + { + base = SLOTBASE(slot); + + /* The ioports for eisa boards are generally beyond that used in the + check,snarf_region code, but this may change at some point, so we + go through the motions. */ + + if(check_region(base, 0x5c)) continue; /* See if in use */ + if ( aha1740_test_port()) break; + } + if ( slot > MAXEISA ) + return 0; + + aha1740_getconfig(); + + if ( (inb(G2STAT) & (G2STAT_MBXOUT | G2STAT_BUSY) ) != G2STAT_MBXOUT ) + { /* If the card isn't ready, hard reset it */ + outb(G2CNTRL_HRST,G2CNTRL); + outb(0,G2CNTRL); + } + + printk("Configuring Adaptec at IO:%x, IRQ %d\n",base, + irq_level); + + DEB(printk("aha1740_detect: enable interrupt channel %d\n", irq_level)); + + if (request_irq(irq_level,aha1740_intr_handle)) + { + printk("Unable to allocate IRQ for adaptec controller.\n"); + return 0; + } + snarf_region(base, 0x5c); /* Reserve the space that we need to use */ + return 1; +} + +/* Note: They following two functions do not apply very well to the Adaptec, +which basically manages its own affairs quite well without our interference, +so I haven't put anything into them. I can faintly imagine someone with a +*very* badly behaved SCSI target (perhaps an old tape?) wanting the abort(), +but it hasn't happened yet, and doing aborts brings the Adaptec to its +knees. I cannot (at this moment in time) think of any reason to reset the +card once it's running. So there. */ + +int aha1740_abort(Scsi_Cmnd * SCpnt, int i) +{ + DEB(printk("aha1740_abort called\n")); + return 0; +} + +/* We do not implement a reset function here, but the upper level code assumes + that it will get some kind of response for the command in SCpnt. We must + oblige, or the command will hang the scsi system */ + +int aha1740_reset(Scsi_Cmnd * SCpnt) +{ + DEB(printk("aha1740_reset called\n")); + if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + return 0; +} + +int aha1740_biosparam(int size, int dev, int* ip) +{ +DEB(printk("aha1740_biosparam\n")); + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; +/* if (ip[2] >= 1024) ip[2] = 1024; */ + return 0; +} + +/* Okay, you made it all the way through. As of this writing, 3/31/93, I'm +brad@saturn.gaylord.com or brad@bradpc.gaylord.com. I'll try to help as time +permits if you have any trouble with this driver. Happy Linuxing! */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.h new file mode 100644 index 000000000..a4bb8882a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/aha1740.h @@ -0,0 +1,180 @@ +#ifndef _AHA1740_H + +/* $Id$ + * + * Header file for the adaptec 1740 driver for Linux + * + * With minor revisions 3/31/93 + * Written and (C) 1992,1993 Brad McLean. See aha1740.c + * for more info + * + */ + +#include + +/* Eisa Enhanced mode operation - slot locating and addressing */ +#define MINEISA 1 /* I don't have an EISA Spec to know these ranges, so I */ +#define MAXEISA 8 /* Just took my machine's specifications. Adjust to fit.*/ + /* I just saw an ad, and bumped this from 6 to 8 */ +#define SLOTBASE(x) ((x << 12)+ 0xc80 ) +#define BASE (base) + +/* EISA configuration registers & values */ +#define HID0 (base + 0x0) +#define HID1 (base + 0x1) +#define HID2 (base + 0x2) +#define HID3 (base + 0x3) +#define EBCNTRL (base + 0x4) +#define PORTADR (base + 0x40) +#define BIOSADR (base + 0x41) +#define INTDEF (base + 0x42) +#define SCSIDEF (base + 0x43) +#define BUSDEF (base + 0x44) +#define RESV0 (base + 0x45) +#define RESV1 (base + 0x46) +#define RESV2 (base + 0x47) + +#define HID_MFG "ADP" +#define HID_PRD 0 +#define HID_REV 2 +#define EBCNTRL_VALUE 1 +#define PORTADDR_ENH 0x80 +/* READ */ +#define G2INTST (BASE + 0x56) +#define G2STAT (BASE + 0x57) +#define MBOXIN0 (BASE + 0x58) +#define MBOXIN1 (BASE + 0x59) +#define MBOXIN2 (BASE + 0x5a) +#define MBOXIN3 (BASE + 0x5b) +#define G2STAT2 (BASE + 0x5c) + +#define G2INTST_MASK 0xf0 /* isolate the status */ +#define G2INTST_CCBGOOD 0x10 /* CCB Completed */ +#define G2INTST_CCBRETRY 0x50 /* CCB Completed with a retry */ +#define G2INTST_HARDFAIL 0x70 /* Adapter Hardware Failure */ +#define G2INTST_CMDGOOD 0xa0 /* Immediate command success */ +#define G2INTST_CCBERROR 0xc0 /* CCB Completed with error */ +#define G2INTST_ASNEVENT 0xd0 /* Asynchronous Event Notification */ +#define G2INTST_CMDERROR 0xe0 /* Immediate command error */ + +#define G2STAT_MBXOUT 4 /* Mailbox Out Empty Bit */ +#define G2STAT_INTPEND 2 /* Interrupt Pending Bit */ +#define G2STAT_BUSY 1 /* Busy Bit (attention pending) */ + +#define G2STAT2_READY 0 /* Host Ready Bit */ + +/* WRITE (and ReadBack) */ +#define MBOXOUT0 (BASE + 0x50) +#define MBOXOUT1 (BASE + 0x51) +#define MBOXOUT2 (BASE + 0x52) +#define MBOXOUT3 (BASE + 0x53) +#define ATTN (BASE + 0x54) +#define G2CNTRL (BASE + 0x55) + +#define ATTN_IMMED 0x10 /* Immediate Command */ +#define ATTN_START 0x40 /* Start CCB */ +#define ATTN_ABORT 0x50 /* Abort CCB */ + +#define G2CNTRL_HRST 0x80 /* Hard Reset */ +#define G2CNTRL_IRST 0x40 /* Clear EISA Interrupt */ +#define G2CNTRL_HRDY 0x20 /* Sets HOST ready */ + +/* This is used with scatter-gather */ +struct aha1740_chain { + ulong dataptr; /* Location of data */ + ulong datalen; /* Size of this part of chain */ +}; + +/* These belong in scsi.h */ +#define any2scsi(up, p) \ +(up)[0] = (((unsigned long)(p)) >> 16) ; \ +(up)[1] = (((unsigned long)(p)) >> 8); \ +(up)[2] = ((unsigned long)(p)); + +#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) + +#define xany2scsi(up, p) \ +(up)[0] = ((long)(p)) >> 24; \ +(up)[1] = ((long)(p)) >> 16; \ +(up)[2] = ((long)(p)) >> 8; \ +(up)[3] = ((long)(p)); + +#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ + + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) + +#define MAX_CDB 12 +#define MAX_SENSE 14 +#define MAX_STATUS 32 + +struct ecb { /* Enhanced Control Block 6.1 */ + ushort cmdw; /* Command Word */ + /* Flag Word 1 */ + ushort cne:1, /* Control Block Chaining */ + :6, di:1, /* Disable Interrupt */ + :2, ses:1, /* Suppress Underrun error */ + :1, sg:1, /* Scatter/Gather */ + :1, dsb:1, /* Disable Status Block */ + ars:1; /* Automatic Request Sense */ + /* Flag Word 2 */ + ushort lun:3, /* Logical Unit */ + tag:1, /* Tagged Queuing */ + tt:2, /* Tag Type */ + nd:1, /* No Disconnect */ + :1, dat:1, /* Data transfer - check direction */ + dir:1, /* Direction of transfer 1 = datain */ + st:1, /* Suppress Transfer */ + chk:1, /* Calculate Checksum */ + :2, rec:1, :1; /* Error Recovery */ + ushort nil0; /* nothing */ + ulong dataptr; /* Data or Scatter List ptr */ + ulong datalen; /* Data or Scatter List len */ + ulong statusptr; /* Status Block ptr */ + ulong linkptr; /* Chain Address */ + ulong nil1; /* nothing */ + ulong senseptr; /* Sense Info Pointer */ + unchar senselen; /* Sense Length */ + unchar cdblen; /* CDB Length */ + ushort datacheck; /* Data checksum */ + unchar cdb[MAX_CDB]; /* CDB area */ + /* Hardware defined portion ends here, rest is driver defined */ + unchar sense[MAX_SENSE]; /* Sense area */ + unchar status[MAX_STATUS]; /* Status area */ + Scsi_Cmnd *SCpnt; /* Link to the SCSI Command Block */ + void (*done)(Scsi_Cmnd *); /* Completion Function */ +}; + +#define AHA1740CMD_NOP 0x00 /* No OP */ +#define AHA1740CMD_INIT 0x01 /* Initiator SCSI Command */ +#define AHA1740CMD_DIAG 0x05 /* Run Diagnostic Command */ +#define AHA1740CMD_SCSI 0x06 /* Initialize SCSI */ +#define AHA1740CMD_SENSE 0x08 /* Read Sense Information */ +#define AHA1740CMD_DOWN 0x09 /* Download Firmware (yeah, I bet!) */ +#define AHA1740CMD_RINQ 0x0a /* Read Host Adapter Inquiry Data */ +#define AHA1740CMD_TARG 0x10 /* Target SCSI Command */ + +int aha1740_detect(int); +int aha1740_command(Scsi_Cmnd *); +int aha1740_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int aha1740_abort(Scsi_Cmnd *, int); +const char *aha1740_info(void); +int aha1740_reset(Scsi_Cmnd *); +int aha1740_biosparam(int, int, int*); + +#define AHA1740_ECBS 32 +#define AHA1740_SCATTER 16 + +#ifndef NULL +#define NULL 0 +#endif + +#define AHA1740 {"Adaptec 1740", aha1740_detect, \ + aha1740_info, aha1740_command, \ + aha1740_queuecommand, \ + aha1740_abort, \ + aha1740_reset, \ + NULL, \ + aha1740_biosparam, \ + AHA1740_ECBS, 7, AHA1740_SCATTER, 1, 0, 0} + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.c new file mode 100644 index 000000000..157c5bdcc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.c @@ -0,0 +1,529 @@ +/* + * ASCII values for a number of symbolic constants, printing functions, + * etc. + */ + +#include +#include "../block/blk.h" +#include +#include "scsi.h" + +#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 +#undef CONSTANTS +#endif +#define CONSTANTS (CONST_CMD | CONST_STATUS | CONST_SENSE | CONST_XSENSE) +#endif + +#if (CONSTANTS & CONST_COMMAND) +static const char * group_0_commands[] = { +/* 00-03 */ "Test Unit Ready", "Rezero Unit", unknown, "Request Sense", +/* 04-07 */ "Format Unit", "Read Block Limits", unknown, "Reasssign Blocks", +/* 08-0d */ "Read (6)", unknown, "Write (6)", "Seek (6)", unknown, unknown, +/* 0e-12 */ unknown, "Read Reverse", "Write Filemarks", "Space", "Inquiry", +/* 13-16 */ unknown, "Recover Buffered Data", "Mode Select", "Reserve", +/* 17-1b */ "Release", "Copy", "Erase", "Mode Sense", "Start/Stop Unit", +/* 1c-1d */ "Receive Diagnostic", "Send Diagnostic", +/* 1e-1f */ "Prevent/Allow Medium Removal", unknown, +}; + + +static const char *group_1_commands[] = { +/* 20-22 */ unknown, unknown, unknown, +/* 23-28 */ unknown, unknown, "Read Capacity", unknown, unknown, "Read (10)", +/* 29-2d */ unknown, "Write (10)", "Seek (10)", unknown, unknown, +/* 2e-31 */ "Write Verify","Verify", "Search High", "Search Equal", +/* 32-34 */ "Search Low", "Set Limits", "Prefetch or Read Position", +/* 35-37 */ "Synchronize Cache","Lock/Unlock Cache", "Read Deffect Data", +/* 38-3c */ unknown, "Compare","Copy Verify", "Write Buffer", "Read Buffer", +/* 3d-39 */ unknown, "Read Long", unknown, +}; + + +static const char *group_2_commands[] = { +/* 40-41 */ "Change Definition", unknown, +/* 42-48 */ unknown, unknown, unknown, unknown, unknown, unknown, unknown, +/* 49-4f */ unknown, unknown, unknown, "Log Select", "Log Sense", unknown, +/* 50-55 */ unknown, unknown, unknown, unknown, unknown, "Mode Select (10)", +/* 56-5b */ unknown, unknown, unknown, unknown, "Mode Sense (10)", unknown, +/* 5c-5f */ unknown, unknown, unknown, +}; + + + +#define group(opcode) (((opcode) >> 5) & 7) + +#define RESERVED_GROUP 0 +#define VENDOR_GROUP 1 +#define NOTEXT_GROUP 2 + +static const char **commands[] = { +group_0_commands, group_1_commands, group_2_commands, +(const char **) RESERVED_GROUP, (const char **) RESERVED_GROUP, +(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) ]; + switch ((int) table) { + case RESERVED_GROUP: + printk("%s(0x%02x) ", reserved, opcode); + break; + case NOTEXT_GROUP: + printk("%s(0x%02x) ", unknown, opcode); + break; + case VENDOR_GROUP: + printk("%s(0x%02x) ", vendor, opcode); + break; + default: + printk("%s ",table[opcode & 0x31]); + } +} +#else /* CONST & CONST_COMMAND */ +static void print_opcode(int opcode) { + printk("0x%02x ", opcode); +} +#endif + +void print_command (unsigned char *command) { + int i,s; + print_opcode(command[0]); + for ( i = 1, s = COMMAND_SIZE(command[0]); i < s; ++i) + printk("%02x ", command[i]); + printk("\n"); +} + +#if (CONSTANTS & CONST_STATUS) +static const char * statuses[] = { +/* 0-4 */ "Good", "Check Condition", "Condition Good", unknown, "Busy", +/* 5-9 */ unknown, unknown, unknown, "Intermediate Good", unknown, +/* a-d */ "Interemediate Good", unknown, "Reservation Conflict", unknown, +/* e-f */ unknown, unknown, +}; +#endif + +void print_status (int status) { + status = (status >> 1) & 0xf; +#if (CONSTANTS & CONST_STATUS) + printk("%s ",statuses[status]); +#else + printk("0x%0x ", status); +#endif +} + +#if (CONSTANTS & CONST_XSENSE) +#define D 0x001 /* DIRECT ACCESS DEVICE (disk) */ +#define T 0x002 /* SEQUENTIAL ACCESS DEVICE (tape) */ +#define L 0x004 /* PRINTER DEVICE */ +#define P 0x008 /* PROCESSOR DEVICE */ +#define W 0x010 /* WRITE ONCE READ MULTIPLE DEVICE */ +#define R 0x020 /* READ ONLY (CD-ROM) DEVICE */ +#define S 0x040 /* SCANNER DEVICE */ +#define O 0x080 /* OPTICAL MEMORY DEVICE */ +#define M 0x100 /* MEDIA CHANGER DEVICE */ +#define C 0x200 /* COMMUNICATION DEVICE */ + +struct error_info{ + unsigned char code1, code2; + unsigned short int devices; + char * text; +}; + +struct error_info2{ + unsigned char code1, code2_min, code2_max; + unsigned short int devices; + char * text; +}; + +static struct error_info2 additional2[] = +{ + {0x40,0x00,0x7f,D,"Ram failure (%x)"}, + {0x40,0x80,0xff,D|T|L|P|W|R|S|O|M|C,"Diagnostic failure on component (%x)"}, + {0x41,0x00,0xff,D,"Data path failure (%x)"}, + {0x42,0x00,0xff,D,"Power-on or self-test failure (%x)"}, + {0, 0, 0, 0, NULL} +}; + +static struct error_info additional[] = +{ + {0x00,0x01,T,"Filemark detected"}, + {0x00,0x02,T|S,"End-of-partition/medium detected"}, + {0x00,0x03,T,"Setmark detected"}, + {0x00,0x04,T|S,"Beginning-of-partition/medium detected"}, + {0x00,0x05,T|S,"End-of-data detected"}, + {0x00,0x06,D|T|L|P|W|R|S|O|M|C,"I/O process terminated"}, + {0x00,0x11,R,"Audio play operation in progress"}, + {0x00,0x12,R,"Audio play operation paused"}, + {0x00,0x13,R,"Audio play operation successfully completed"}, + {0x00,0x14,R,"Audio play operation stopped due to error"}, + {0x00,0x15,R,"No current audio status to return"}, + {0x01,0x00,D|W|O,"No index/sector signal"}, + {0x02,0x00,D|W|R|O|M,"No seek complete"}, + {0x03,0x00,D|T|L|W|S|O,"Peripheral device write fault"}, + {0x03,0x01,T,"No write current"}, + {0x03,0x02,T,"Excessive write errors"}, + {0x04,0x00,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, cause not reportable"}, + {0x04,0x01,D|T|L|P|W|R|S|O|M|C, + "Logical unit is in process of becoming ready"}, + {0x04,0x02,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, initializing command required"}, + {0x04,0x03,D|T|L|P|W|R|S|O|M|C, + "Logical unit not ready, manual intervention required"}, + {0x04,0x04,D|T|L|O,"Logical unit not ready, format in progress"}, + {0x05,0x00,D|T|L|W|R|S|O|M|C,"Logical unit does not respond to selection"}, + {0x06,0x00,D|W|R|O|M,"No reference position found"}, + {0x07,0x00,D|T|L|W|R|S|O|M,"Multiple peripheral devices selected"}, + {0x08,0x00,D|T|L|W|R|S|O|M|C,"Logical unit communication failure"}, + {0x08,0x01,D|T|L|W|R|S|O|M|C,"Logical unit communication time-out"}, + {0x08,0x02,D|T|L|W|R|S|O|M|C,"Logical unit communication parity error"}, + {0x09,0x00,D|T|W|R|O,"Track following error"}, + {0x09,0x01,W|R|O,"Tracking servo failure"}, + {0x09,0x02,W|R|O,"Focus servo failure"}, + {0x09,0x03,W|R|O,"Spindle servo failure"}, + {0x0A,0x00,D|T|L|P|W|R|S|O|M|C,"Error log overflow"}, + {0x0C,0x00,T|S,"Write error"}, + {0x0C,0x01,D|W|O,"Write error recovered with auto reallocation"}, + {0x0C,0x02,D|W|O,"Write error - auto reallocation failed"}, + {0x10,0x00,D|W|O,"Id crc or ecc error"}, + {0x11,0x00,D|T|W|R|S|O,"Unrecovered read error"}, + {0x11,0x01,D|T|W|S|O,"Read retries exhausted"}, + {0x11,0x02,D|T|W|S|O,"Error too long to correct"}, + {0x11,0x03,D|T|W|S|O,"Multiple read errors"}, + {0x11,0x04,D|W|O,"Unrecovered read error - auto reallocate failed"}, + {0x11,0x05,W|R|O,"L-ec uncorrectable error"}, + {0x11,0x06,W|R|O,"Circ unrecovered error"}, + {0x11,0x07,W|O,"Data resychronization error"}, + {0x11,0x08,T,"Incomplete block read"}, + {0x11,0x09,T,"No gap found"}, + {0x11,0x0A,D|T|O,"Miscorrected error"}, + {0x11,0x0B,D|W|O,"Unrecovered read error - recommend reassignment"}, + {0x11,0x0C,D|W|O,"Unrecovered read error - recommend rewrite the data"}, + {0x12,0x00,D|W|O,"Address mark not found for id field"}, + {0x13,0x00,D|W|O,"Address mark not found for data field"}, + {0x14,0x00,D|T|L|W|R|S|O,"Recorded entity not found"}, + {0x14,0x01,D|T|W|R|O,"Record not found"}, + {0x14,0x02,T,"Filemark or setmark not found"}, + {0x14,0x03,T,"End-of-data not found"}, + {0x14,0x04,T,"Block sequence error"}, + {0x15,0x00,D|T|L|W|R|S|O|M,"Random positioning error"}, + {0x15,0x01,D|T|L|W|R|S|O|M,"Mechanical positioning error"}, + {0x15,0x02,D|T|W|R|O,"Positioning error detected by read of medium"}, + {0x16,0x00,D|W|O,"Data synchronization mark error"}, + {0x17,0x00,D|T|W|R|S|O,"Recovered data with no error correction applied"}, + {0x17,0x01,D|T|W|R|S|O,"Recovered data with retries"}, + {0x17,0x02,D|T|W|R|O,"Recovered data with positive head offset"}, + {0x17,0x03,D|T|W|R|O,"Recovered data with negative head offset"}, + {0x17,0x04,W|R|O,"Recovered data with retries and/or circ applied"}, + {0x17,0x05,D|W|R|O,"Recovered data using previous sector id"}, + {0x17,0x06,D|W|O,"Recovered data without ecc - data auto-reallocated"}, + {0x17,0x07,D|W|O,"Recovered data without ecc - recommend reassignment"}, + {0x18,0x00,D|T|W|R|O,"Recovered data with error correction applied"}, + {0x18,0x01,D|W|R|O,"Recovered data with error correction and retries applied"}, + {0x18,0x02,D|W|R|O,"Recovered data - data auto-reallocated"}, + {0x18,0x03,R,"Recovered data with circ"}, + {0x18,0x04,R,"Recovered data with lec"}, + {0x18,0x05,D|W|R|O,"Recovered data - recommend reassignment"}, + {0x19,0x00,D|O,"Defect list error"}, + {0x19,0x01,D|O,"Defect list not available"}, + {0x19,0x02,D|O,"Defect list error in primary list"}, + {0x19,0x03,D|O,"Defect list error in grown list"}, + {0x1A,0x00,D|T|L|P|W|R|S|O|M|C,"Parameter list length error"}, + {0x1B,0x00,D|T|L|P|W|R|S|O|M|C,"Synchronous data transfer error"}, + {0x1C,0x00,D|O,"Defect list not found"}, + {0x1C,0x01,D|O,"Primary defect list not found"}, + {0x1C,0x02,D|O,"Grown defect list not found"}, + {0x1D,0x00,D|W|O,"Miscompare during verify operation"}, + {0x1E,0x00,D|W|O,"Recovered id with ecc correction"}, + {0x20,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid command operation code"}, + {0x21,0x00,D|T|W|R|O|M,"Logical block address out of range"}, + {0x21,0x01,M,"Invalid element address"}, + {0x22,0x00,D,"Illegal function (should use 20 00, 24 00, or 26 00)"}, + {0x24,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in cdb"}, + {0x25,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit not supported"}, + {0x26,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid field in parameter list"}, + {0x26,0x01,D|T|L|P|W|R|S|O|M|C,"Parameter not supported"}, + {0x26,0x02,D|T|L|P|W|R|S|O|M|C,"Parameter value invalid"}, + {0x26,0x03,D|T|L|P|W|R|S|O|M|C,"Threshold parameters not supported"}, + {0x27,0x00,D|T|W|O,"Write protected"}, + {0x28,0x00,D|T|L|P|W|R|S|O|M|C,"Not ready to ready transition (medium may have changed)"}, + {0x28,0x01,M,"Import or export element accessed"}, + {0x29,0x00,D|T|L|P|W|R|S|O|M|C,"Power on, reset, or bus device reset occurred"}, + {0x2A,0x00,D|T|L|W|R|S|O|M|C,"Parameters changed"}, + {0x2A,0x01,D|T|L|W|R|S|O|M|C,"Mode parameters changed"}, + {0x2A,0x02,D|T|L|W|R|S|O|M|C,"Log parameters changed"}, + {0x2B,0x00,D|T|L|P|W|R|S|O|C,"Copy cannot execute since host cannot disconnect"}, + {0x2C,0x00,D|T|L|P|W|R|S|O|M|C,"Command sequence error"}, + {0x2C,0x01,S,"Too many windows specified"}, + {0x2C,0x02,S,"Invalid combination of windows specified"}, + {0x2D,0x00,T,"Overwrite error on update in place"}, + {0x2F,0x00,D|T|L|P|W|R|S|O|M|C,"Commands cleared by another initiator"}, + {0x30,0x00,D|T|W|R|O|M,"Incompatible medium installed"}, + {0x30,0x01,D|T|W|R|O,"Cannot read medium - unknown format"}, + {0x30,0x02,D|T|W|R|O,"Cannot read medium - incompatible format"}, + {0x30,0x03,D|T,"Cleaning cartridge installed"}, + {0x31,0x00,D|T|W|O,"Medium format corrupted"}, + {0x31,0x01,D|L|O,"Format command failed"}, + {0x32,0x00,D|W|O,"No defect spare location available"}, + {0x32,0x01,D|W|O,"Defect list update failure"}, + {0x33,0x00,T,"Tape length error"}, + {0x36,0x00,L,"Ribbon, ink, or toner failure"}, + {0x37,0x00,D|T|L|W|R|S|O|M|C,"Rounded parameter"}, + {0x39,0x00,D|T|L|W|R|S|O|M|C,"Saving parameters not supported"}, + {0x3A,0x00,D|T|L|W|R|S|O|M,"Medium not present"}, + {0x3B,0x00,T|L,"Sequential positioning error"}, + {0x3B,0x01,T,"Tape position error at beginning-of-medium"}, + {0x3B,0x02,T,"Tape position error at end-of-medium"}, + {0x3B,0x03,L,"Tape or electronic vertical forms unit not ready"}, + {0x3B,0x04,L,"Slew failure"}, + {0x3B,0x05,L,"Paper jam"}, + {0x3B,0x06,L,"Failed to sense top-of-form"}, + {0x3B,0x07,L,"Failed to sense bottom-of-form"}, + {0x3B,0x08,T,"Reposition error"}, + {0x3B,0x09,S,"Read past end of medium"}, + {0x3B,0x0A,S,"Read past beginning of medium"}, + {0x3B,0x0B,S,"Position past end of medium"}, + {0x3B,0x0C,S,"Position past beginning of medium"}, + {0x3B,0x0D,M,"Medium destination element full"}, + {0x3B,0x0E,M,"Medium source element empty"}, + {0x3D,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid bits in identify message"}, + {0x3E,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit has not self-configured yet"}, + {0x3F,0x00,D|T|L|P|W|R|S|O|M|C,"Target operating conditions have changed"}, + {0x3F,0x01,D|T|L|P|W|R|S|O|M|C,"Microcode has been changed"}, + {0x3F,0x02,D|T|L|P|W|R|S|O|M|C,"Changed operating definition"}, + {0x3F,0x03,D|T|L|P|W|R|S|O|M|C,"Inquiry data has changed"}, + {0x43,0x00,D|T|L|P|W|R|S|O|M|C,"Message error"}, + {0x44,0x00,D|T|L|P|W|R|S|O|M|C,"Internal target failure"}, + {0x45,0x00,D|T|L|P|W|R|S|O|M|C,"Select or reselect failure"}, + {0x46,0x00,D|T|L|P|W|R|S|O|M|C,"Unsuccessful soft reset"}, + {0x47,0x00,D|T|L|P|W|R|S|O|M|C,"Scsi parity error"}, + {0x48,0x00,D|T|L|P|W|R|S|O|M|C,"Initiator detected error message received"}, + {0x49,0x00,D|T|L|P|W|R|S|O|M|C,"Invalid message error"}, + {0x4A,0x00,D|T|L|P|W|R|S|O|M|C,"Command phase error"}, + {0x4B,0x00,D|T|L|P|W|R|S|O|M|C,"Data phase error"}, + {0x4C,0x00,D|T|L|P|W|R|S|O|M|C,"Logical unit failed self-configuration"}, + {0x4E,0x00,D|T|L|P|W|R|S|O|M|C,"Overlapped commands attempted"}, + {0x50,0x00,T,"Write append error"}, + {0x50,0x01,T,"Write append position error"}, + {0x50,0x02,T,"Position error related to timing"}, + {0x51,0x00,T|O,"Erase failure"}, + {0x52,0x00,T,"Cartridge fault"}, + {0x53,0x00,D|T|L|W|R|S|O|M,"Media load or eject failed"}, + {0x53,0x01,T,"Unload tape failure"}, + {0x53,0x02,D|T|W|R|O|M,"Medium removal prevented"}, + {0x54,0x00,P,"Scsi to host system interface failure"}, + {0x55,0x00,P,"System resource failure"}, + {0x57,0x00,R,"Unable to recover table-of-contents"}, + {0x58,0x00,O,"Generation does not exist"}, + {0x59,0x00,O,"Updated block read"}, + {0x5A,0x00,D|T|L|P|W|R|S|O|M,"Operator request or state change input (unspecified)"}, + {0x5A,0x01,D|T|W|R|O|M,"Operator medium removal request"}, + {0x5A,0x02,D|T|W|O,"Operator selected write protect"}, + {0x5A,0x03,D|T|W|O,"Operator selected write permit"}, + {0x5B,0x00,D|T|L|P|W|R|S|O|M,"Log exception"}, + {0x5B,0x01,D|T|L|P|W|R|S|O|M,"Threshold condition met"}, + {0x5B,0x02,D|T|L|P|W|R|S|O|M,"Log counter at maximum"}, + {0x5B,0x03,D|T|L|P|W|R|S|O|M,"Log list codes exhausted"}, + {0x5C,0x00,D|O,"Rpl status change"}, + {0x5C,0x01,D|O,"Spindles synchronized"}, + {0x5C,0x02,D|O,"Spindles not synchronized"}, + {0x60,0x00,S,"Lamp failure"}, + {0x61,0x00,S,"Video acquisition error"}, + {0x61,0x01,S,"Unable to acquire video"}, + {0x61,0x02,S,"Out of focus"}, + {0x62,0x00,S,"Scan head positioning error"}, + {0x63,0x00,R,"End of user area encountered on this track"}, + {0x64,0x00,R,"Illegal mode for this track"}, + {0, 0, 0, NULL} +}; +#endif + +#if (CONSTANTS & CONST_SENSE) +static char *snstext[] = { + "None","Recovered Error","Not Ready","Medium Error","Hardware Error", + "Illegal Request","Unit Attention","Data Protect","Blank Check", + "Key=E","Key=F","Filemark","End-Of-Medium","Incorrect Block Length", + "14","15"}; +#endif + + +/* Print sense information */ +void print_sense(char * devclass, Scsi_Cmnd * SCpnt) +{ + int i, s; + int sense_class, valid, code; + unsigned char * sense_buffer = SCpnt->sense_buffer; + char * error = NULL; + int dev = SCpnt->request.dev; + + sense_class = (sense_buffer[0] >> 4) & 0x07; + code = sense_buffer[0] & 0xf; + valid = sense_buffer[0] & 0x80; + + if (sense_class == 7) { + s = sense_buffer[7] + 8; + if(s > sizeof(SCpnt->sense_buffer)) s = sizeof(SCpnt->sense_buffer); + + if (!valid) + printk("extra data not valid "); + + if (sense_buffer[2] & 0x80) printk( "FMK "); + if (sense_buffer[2] & 0x40) printk( "EOM "); + if (sense_buffer[2] & 0x20) printk( "ILI "); + + switch (code) { + case 0x0: + error = "Current"; + break; + case 0x1: + error = "Deferred"; + break; + default: + error = "Invalid"; + } + + printk("%s error ", error); + +#if (CONSTANTS & CONST_SENSE) + if (sense_buffer[2] & 0x80) printk( "FMK "); + if (sense_buffer[2] & 0x40) printk( "EOM "); + if (sense_buffer[2] & 0x20) printk( "ILI "); + printk( "%s%x: sense key %s\n", devclass, dev, snstext[sense_buffer[2] & 0x0f]); +#else + printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]); +#endif + + /* Check to see if additional sense information is available */ + if(sense_buffer[7] + 7 < 13 || + (sense_buffer[12] == 0 && sense_buffer[13] == 0)) goto done; + +#if (CONSTANTS & CONST_XSENSE) + for(i=0; additional[i].text; i++) + if(additional[i].code1 == sense_buffer[12] && + additional[i].code2 == sense_buffer[13]) + printk("Additional sense indicates %s\n", additional[i].text); + + for(i=0; additional2[i].text; i++) + if(additional2[i].code1 == sense_buffer[12] && + additional2[i].code2_min >= sense_buffer[13] && + additional2[i].code2_max <= sense_buffer[13]) { + printk("Additional sense indicates "); + printk(additional2[i].text, sense_buffer[13]); + printk("\n"); + }; +#else + printk("ASC=%2x ASCQ=%2x\n", sense_buffer[12], sense_buffer[13]); +#endif + } else { + +#if (CONSTANTS & CONST_SENSE) + if (sense_buffer[0] < 15) + printk("%s%x: old sense key %s\n", devclass, dev, snstext[sense_buffer[0] & 0x0f]); + else +#endif + printk("%s%x: sns = %2x %2x\n", devclass, dev, sense_buffer[0], sense_buffer[2]); + + printk("Non-extended sense class %d code 0x%0x ", sense_class, code); + s = 4; + } + + done: + for (i = 0; i < s; ++i) + printk("0x%02x ", sense_buffer[i]); + + 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 *)) + +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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.h new file mode 100644 index 000000000..15f874417 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/constants.h @@ -0,0 +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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.c new file mode 100644 index 000000000..8043f70cf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.c @@ -0,0 +1,1480 @@ +/* fdomain.c -- Future Domain TMC-16x0 SCSI driver + * Created: Sun May 3 18:53:19 1992 by faith@cs.unc.edu + * Revised: Sun Jan 23 08:59:04 1994 by faith@cs.unc.edu + * Author: Rickard E. Faith, faith@cs.unc.edu + * Copyright 1992, 1993, 1994 Rickard E. Faith + * + * $Id: fdomain.c,v 5.9 1994/01/23 13:59:14 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 + * 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. + + ************************************************************************** + + DESCRIPTION: + + This is the Linux low-level SCSI driver for Future Domain TMC-1660/1680 + and TMC-1650/1670 SCSI host adapters. The 1650 and 1670 have a 25-pin + external connector, whereas the 1660 and 1680 have a SCSI-2 50-pin + high-density external connector. The 1670 and 1680 have floppy disk + controllers built in. + + Future Domain's older boards are based on the TMC-1800 chip, and the + driver was originally written for a TMC-1680 board with the TMC-1800 + chip. More recently, boards are being produced with the TMC-18C50 chip. + The latest and greatest board may not work with this driver. If you have + to patch this driver so that it will recognize your board's BIOS + signature, then the driver may fail to function after the board is + detected. + + If you have a TMC-8xx or TMC-9xx board, then this is not the driver for + your board. Please refer to the Seagate driver for more information and + possible support. + + + + REFERENCES USED: + + "TMC-1800 SCSI Chip Specification (FDC-1800T)", Future Domain Corporation, + 1990. + + "Technical Reference Manual: 18C50 SCSI Host Adapter Chip", Future Domain + Corporation, January 1992. + + "LXT SCSI Products: Specifications and OEM Technical Manual (Revision + B/September 1991)", Maxtor Corporation, 1991. + + "7213S product Manual (Revision P3)", Maxtor Corporation, 1992. + + "Draft Proposed American National Standard: Small Computer System + Interface - 2 (SCSI-2)", Global Engineering Documents. (X3T9.2/86-109, + revision 10h, October 17, 1991) + + Private communications, Drew Eckhardt (drew@cs.colorado.edu) and Eric + Youngdale (eric@tantalus.nrl.navy.mil), 1992. + + + + NOTES ON REFERENCES: + + The Maxtor manuals were free. Maxtor telephone technical support is + great! + + The Future Domain manuals were $25 and $35. They document the chip, not + the TMC-16x0 boards, so some information I had to guess at. In 1992, + Future Domain sold DOS BIOS source for $250 and the UN*X driver source was + $750, but these required a non-disclosure agreement, so even if I could + have afforded them, they would *not* have been useful for writing this + publically distributable driver. Future Domain technical support has + provided some information on the phone and have sent a few useful FAXs. + They have been much more helpful since they started to recognize that the + word "Linux" refers to an operating system :-). + + + + ALPHA TESTERS: + + There are many other alpha testers that come and go as the driver + develops. The people listed here were most helpful in times of greatest + need (mostly early on -- I've probably left out a few worthy people in + 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@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 + driver works with the 18C50 chip. + + All of the alpha testers deserve much thanks. + + + + NOTES ON USER DEFINABLE OPTIONS: + + DEBUG: This turns on the printing of various debug informaiton. + + ENABLE_PARITY: This turns on SCSI parity checking. With the current + driver, all attached devices must support SCSI parity. If none of your + devices support parity, then you can probably get the driver to work by + turning this option off. I have no way of testing this, however. + + FIFO_COUNT: The host adapter has an 8K cache. When this many 512 byte + blocks are filled by the SCSI device, an interrupt will be raised. + Therefore, this could be as low as 0, or as high as 16. Note, however, + that values which are too high or too low seem to prevent any interrupts + from occuring, and thereby lock up the machine. I have found that 2 is a + good number, but throughput may be increased by changing this value to + values which are close to 2. Please let me know if you try any different + values. + + DO_DETECT: This activates some old scan code which was needed before the + high level drivers got fixed. If you are having toruble with the driver, + 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: 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 +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "fdomain.h" +#include +#include +#include +#include + +#define VERSION "$Revision: 5.9 $" + +/* START OF USER DEFINABLE OPTIONS */ + +#define DEBUG 1 /* Enable debugging output */ +#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) */ + +/* END OF USER DEFINABLE OPTIONS */ + +#if DEBUG +#define EVERY_ACCESS 0 /* Write a line on every scsi access */ +#define ERRORS_ONLY 1 /* Only write a line if there is an error */ +#define DEBUG_DETECT 0 /* Debug fdomain_16x0_detect() */ +#define DEBUG_MESSAGES 1 /* Debug MESSAGE IN phase */ +#define DEBUG_ABORT 1 /* Debug abort() routine */ +#define DEBUG_RESET 1 /* Debug reset() routine */ +#define DEBUG_RACE 1 /* Debug interrupt-driven race condition */ +#else +#define EVERY_ACCESS 0 /* LEAVE THESE ALONE--CHANGE THE ONES ABOVE */ +#define ERRORS_ONLY 0 +#define DEBUG_DETECT 0 +#define DEBUG_MESSAGES 0 +#define DEBUG_ABORT 0 +#define DEBUG_RESET 0 +#define DEBUG_RACE 0 +#endif + +/* Errors are reported on the line, so we don't need to report them again */ +#if EVERY_ACCESS +#undef ERRORS_ONLY +#define ERRORS_ONLY 0 +#endif + +#if ENABLE_PARITY +#define PARITY_MASK 0x08 +#else +#define PARITY_MASK 0x00 +#endif + +enum chip_type { + unknown = 0x00, + tmc1800 = 0x01, + tmc18c50 = 0x02, +}; + +enum { + in_arbitration = 0x02, + in_selection = 0x04, + in_other = 0x08, + disconnect = 0x10, + aborted = 0x20, + sent_ident = 0x40, +}; + +enum in_port_type { + Read_SCSI_Data = 0, + SCSI_Status = 1, + TMC_Status = 2, + FIFO_Status = 3, /* tmc18c50 only */ + Interrupt_Cond = 4, /* tmc18c50 only */ + LSB_ID_Code = 5, + MSB_ID_Code = 6, + Read_Loopback = 7, + SCSI_Data_NoACK = 8, + Interrupt_Status = 9, + Configuration1 = 10, + Configuration2 = 11, /* tmc18c50 only */ + Read_FIFO = 12, + FIFO_Data_Count = 14 +}; + +enum out_port_type { + Write_SCSI_Data = 0, + SCSI_Cntl = 1, + Interrupt_Cntl = 2, + SCSI_Mode_Cntl = 3, + TMC_Cntl = 4, + Memory_Cntl = 5, /* tmc18c50 only */ + Write_Loopback = 7, + Write_FIFO = 12 +}; + +static int port_base = 0; +static void *bios_base = NULL; +static int bios_major = 0; +static int bios_minor = 0; +static int interrupt_level = 0; +static int this_host = 0; +static volatile int in_command = 0; +static Scsi_Cmnd *current_SC = NULL; +static enum chip_type chip = unknown; +static int adapter_mask = 0x40; +#if DEBUG_RACE +static volatile int in_interrupt_flag = 0; +#endif + +static int SCSI_Mode_Cntl_port; +static int FIFO_Data_Count_port; +static int Interrupt_Cntl_port; +static int Interrupt_Status_port; +static int Read_FIFO_port; +static int Read_SCSI_Data_port; +static int SCSI_Cntl_port; +static int SCSI_Data_NoACK_port; +static int SCSI_Status_port; +static int TMC_Cntl_port; +static int TMC_Status_port; +static int Write_FIFO_port; +static int Write_SCSI_Data_port; + +extern void fdomain_16x0_intr( int unused ); + +static void *addresses[] = { + (void *)0xc8000, + (void *)0xca000, + (void *)0xce000, + (void *)0xde000 }; +#define ADDRESS_COUNT (sizeof( addresses ) / sizeof( unsigned )) + +static unsigned short ports[] = { 0x140, 0x150, 0x160, 0x170 }; +#define PORT_COUNT (sizeof( ports ) / sizeof( unsigned short )) + +static unsigned short ints[] = { 3, 5, 10, 11, 12, 14, 15, 0 }; + +/* + + READ THIS BEFORE YOU ADD A SIGNATURE! + + READING THIS SHORT NOTE CAN SAVE YOU LOTS OF TIME! + + READ EVERY WORD, ESPECIALLY THE WORD *NOT* + + This driver works *ONLY* for Future Domain cards using the TMC-1800 or + the TMC-18C50 chip. This includes models TMC-1650, 1660, 1670, and 1680. + + The following BIOS signature signatures are for boards which do *NOT* + work with this driver (these TMC-8xx and TMC-9xx boards may work with the + Seagate driver): + + FUTURE DOMAIN CORP. (C) 1986-1988 V4.0I 03/16/88 + FUTURE DOMAIN CORP. (C) 1986-1989 V5.0C2/14/89 + FUTURE DOMAIN CORP. (C) 1986-1989 V6.0A7/28/89 + FUTURE DOMAIN CORP. (C) 1986-1990 V6.0105/31/90 + FUTURE DOMAIN CORP. (C) 1986-1990 V6.0209/18/90 + FUTURE DOMAIN CORP. (C) 1986-1990 V7.009/18/90 + FUTURE DOMAIN CORP. (C) 1992 V8.00.004/02/92 + +*/ + +struct signature { + char *signature; + int sig_offset; + int sig_length; + int major_bios_version; + int minor_bios_version; +} signatures[] = { + /* 1 2 3 4 5 6 */ + /* 123456789012345678901234567890123456789012345678901234567890 */ + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V2.07/28/89", 5, 50, 2, 0 }, + { "FUTURE DOMAIN CORP. (C) 1986-1990 1800-V1.07/28/89", 5, 50, 2, 0 }, + { "FUTURE DOMAIN CORP. (C) 1992 V3.00.004/02/92", 5, 44, 3, 0 }, + { "FUTURE DOMAIN TMC-18XX (C) 1993 V3.203/12/93", 5, 44, 3, 2 }, + { "FUTURE DOMAIN TMC-18XX", 5, 22, -1, -1 }, + + /* READ NOTICE ABOVE *BEFORE* YOU WASTE YOUR TIME ADDING A SIGANTURE + Also, fix the disk geometry code for your signature and send your + changes for faith@cs.unc.edu. Above all, do *NOT* change any old + signatures! + + Note that the last line will match a "generic" 18XX bios. Because + Future Domain has changed the host SCSI ID and/or the location of the + 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.) */ +}; + +#define SIGNATURE_COUNT (sizeof( signatures ) / sizeof( struct signature )) + +static void print_banner( void ) +{ + printk( "%s", fdomain_16x0_info() ); + printk( "Future Domain: BIOS version %d.%d, %s\n", + bios_major, bios_minor, + chip == tmc1800 ? "TMC-1800" + : (chip == tmc18c50 ? "TMC-18C50" : "Unknown") ); + + if (interrupt_level) { + printk( "Future Domain: BIOS at %x; port base at %x; using IRQ %d\n", + (unsigned)bios_base, port_base, interrupt_level ); + } else { + printk( "Future Domain: BIOS at %x; port base at %x; *NO* IRQ\n", + (unsigned)bios_base, port_base ); + } +} + +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); +} + +inline static void fdomain_make_bus_idle( void ) +{ + outb( 0, SCSI_Cntl_port ); + outb( 0, SCSI_Mode_Cntl_port ); + if (chip == tmc18c50) + outb( 0x21 | PARITY_MASK, TMC_Cntl_port ); /* Clear forced intr. */ + else + outb( 0x01 | PARITY_MASK, TMC_Cntl_port ); +} + +static int fdomain_is_valid_port( int port ) +{ + int options; + +#if DEBUG_DETECT + printk( " (%x%x),", + inb( port + MSB_ID_Code ), inb( port + LSB_ID_Code ) ); +#endif + + /* The MCA ID is a unique id for each MCA compatible board. We + are using ISA boards, but Future Domain provides the MCA ID + anyway. We can use this ID to ensure that this is a Future + Domain TMC-1660/TMC-1680. + */ + + if (inb( port + LSB_ID_Code ) != 0xe9) { /* test for 0x6127 id */ + if (inb( port + LSB_ID_Code ) != 0x27) return 0; + if (inb( port + MSB_ID_Code ) != 0x61) return 0; + chip = tmc1800; + } else { /* test for 0xe960 id */ + if (inb( port + MSB_ID_Code ) != 0x60) return 0; + chip = tmc18c50; + } + + /* We have a valid MCA ID for a TMC-1660/TMC-1680 Future Domain board. + Now, check to be sure the bios_base matches these ports. If someone + was unlucky enough to have purchased more than one Future Domain + board, then they will have to modify this code, as we only detect one + board here. [The one with the lowest bios_base.] */ + + options = inb( port + Configuration1 ); + +#if DEBUG_DETECT + printk( " Options = %x\n", options ); +#endif + + /* Check for board with lowest bios_base. */ + if (addresses[ (options & 0xc0) >> 6 ] != bios_base) + return 0; + interrupt_level = ints[ (options & 0x0e) >> 1 ]; + + return 1; +} + +static int fdomain_test_loopback( void ) +{ + int i; + int result; + + for (i = 0; i < 255; i++) { + outb( i, port_base + Write_Loopback ); + result = inb( port_base + Read_Loopback ); + if (i != result) + return 1; + } + return 0; +} + +int fdomain_16x0_detect( int hostnum ) +{ + int i, j; + int flag = 0; + struct sigaction sa; + int retcode; +#if DO_DETECT + const int buflen = 255; + Scsi_Cmnd SCinit; + unsigned char do_inquiry[] = { INQUIRY, 0, 0, 0, buflen, 0 }; + unsigned char do_request_sense[] = { REQUEST_SENSE, 0, 0, 0, buflen, 0 }; + unsigned char do_read_capacity[] = { READ_CAPACITY, + 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + unsigned char buf[buflen]; +#endif + +#if DEBUG_DETECT + printk( "fdomain_16x0_detect()," ); +#endif + + for (i = 0; !bios_base && i < ADDRESS_COUNT; i++) { +#if DEBUG_DETECT + printk( " %x(%x),", (unsigned)addresses[i], (unsigned)bios_base ); +#endif + for (j = 0; !bios_base && j < SIGNATURE_COUNT; j++) { + if (!memcmp( ((char *)addresses[i] + signatures[j].sig_offset), + signatures[j].signature, signatures[j].sig_length )) { + bios_major = signatures[j].major_bios_version; + bios_minor = signatures[j].minor_bios_version; + bios_base = addresses[i]; + } + } + } + + if (!bios_base) { +#if DEBUG_DETECT + printk( " FAILED: NO BIOS\n" ); +#endif + return 0; + } + + if (bios_major == 2) { + /* The TMC-1660/TMC-1680 has a RAM area just after the BIOS ROM. + Assuming the ROM is enabled (otherwise we wouldn't have been + able to read the ROM signature :-), then the ROM sets up the + RAM area with some magic numbers, such as a list of port + base addresses and a list of the disk "geometry" reported to + DOS (this geometry has nothing to do with physical geometry). + */ + + port_base = *((char *)bios_base + 0x1fcc) + + (*((char *)bios_base + 0x1fcd) << 8); + +#if DEBUG_DETECT + printk( " %x,", port_base ); +#endif + + for (flag = 0, i = 0; !flag && i < PORT_COUNT; i++) { + if (port_base == ports[i]) + ++flag; + } + + if (flag) + flag = fdomain_is_valid_port( port_base ); + } + + if (!flag) { /* Cannot get port base from BIOS RAM */ + + /* This is a bad sign. It usually means that someone patched the + BIOS signature list (the signatures variable) to contain a BIOS + signature for a board *OTHER THAN* the TMC-1660/TMC-1680. It + also means that we don't have a Version 2.0 BIOS :-) + */ + +#if DEBUG_DETECT + if (bios_major != 2) printk( " RAM FAILED, " ); +#endif + + /* Anyway, the alternative to finding the address in the RAM is + to just search through every possible port address for one + that is attached to the Future Domain card. Don't panic, + though, about reading all these random port addresses--there + are rumors that the Future Domain BIOS does something very + similar. + + 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 )) { +#if DEBUG_DETECT + printf( " (%x inuse),", port_base ); +#endif + continue; + } +#if DEBUG_DETECT + printk( " %x,", port_base ); +#endif + flag = fdomain_is_valid_port( port_base ); + } + } + + if (!flag) { +#if DEBUG_DETECT + printk( " FAILED: NO PORT\n" ); +#endif + return 0; /* Cannot find valid set of ports */ + } + + print_banner(); + + SCSI_Mode_Cntl_port = port_base + SCSI_Mode_Cntl; + FIFO_Data_Count_port = port_base + FIFO_Data_Count; + Interrupt_Cntl_port = port_base + Interrupt_Cntl; + Interrupt_Status_port = port_base + Interrupt_Status; + Read_FIFO_port = port_base + Read_FIFO; + Read_SCSI_Data_port = port_base + Read_SCSI_Data; + SCSI_Cntl_port = port_base + SCSI_Cntl; + SCSI_Data_NoACK_port = port_base + SCSI_Data_NoACK; + SCSI_Status_port = port_base + SCSI_Status; + TMC_Cntl_port = port_base + TMC_Cntl; + TMC_Status_port = port_base + TMC_Status; + Write_FIFO_port = port_base + Write_FIFO; + Write_SCSI_Data_port = port_base + Write_SCSI_Data; + + fdomain_16x0_reset( NULL ); + + if (fdomain_test_loopback()) { +#if DEBUG_DETECT + printk( "Future Domain: LOOPBACK TEST FAILED, FAILING DETECT!\n" ); +#endif + return 0; + } + + this_host = hostnum; + + /* Log IRQ with kernel */ + + if (!interrupt_level) { + panic( "Future Domain: *NO* interrupt level selected!\n" ); + } else { + /* Register the IRQ with the kernel */ + + sa.sa_handler = fdomain_16x0_intr; + sa.sa_flags = SA_INTERRUPT; + sa.sa_mask = 0; + sa.sa_restorer = NULL; + + retcode = irqaction( interrupt_level, &sa ); + + if (retcode < 0) { + if (retcode == -EINVAL) { + printk( "Future Domain: IRQ %d is bad!\n", interrupt_level ); + printk( " This shouldn't happen!\n" ); + printk( " Send mail to faith@cs.unc.edu\n" ); + } else if (retcode == -EBUSY) { + printk( "Future Domain: IRQ %d is already in use!\n", + interrupt_level ); + printk( " Please use another IRQ!\n" ); + } else { + printk( "Future Domain: Error getting IRQ %d\n", interrupt_level ); + printk( " This shouldn't happen!\n" ); + printk( " Send mail to faith@cs.unc.edu\n" ); + } + panic( "Future Domain: Driver requires interruptions\n" ); + } else { + printk( "Future Domain: IRQ %d requested from kernel\n", + interrupt_level ); + } + } + + /* 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; + } + +#if DO_DETECT + + /* These routines are here because of the way the SCSI bus behaves after + a reset. This appropriate behavior was not handled correctly by the + higher level SCSI routines when I first wrote this driver. Now, + however, correct scan routines are part of scsi.c and these routines + are no longer needed. However, this code is still good for + debugging. */ + + SCinit.request_buffer = SCinit.buffer = buf; + SCinit.request_bufflen = SCinit.bufflen = sizeof(buf)-1; + SCinit.use_sg = 0; + SCinit.lun = 0; + + printk( "Future Domain detection routine scanning for devices:\n" ); + for (i = 0; i < 8; i++) { + SCinit.target = i; + if (i == scsi_hosts[this_host].this_id) /* Skip host adapter */ + continue; + memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); + retcode = fdomain_16x0_command(&SCinit); + if (!retcode) { + memcpy(SCinit.cmnd, do_inquiry, sizeof(do_inquiry)); + retcode = fdomain_16x0_command(&SCinit); + if (!retcode) { + printk( " SCSI ID %d: ", i ); + for (j = 8; j < (buf[4] < 32 ? buf[4] : 32); j++) + printk( "%c", buf[j] >= 20 ? buf[j] : ' ' ); + memcpy(SCinit.cmnd, do_read_capacity, sizeof(do_read_capacity)); + retcode = fdomain_16x0_command(&SCinit); + if (!retcode) { + unsigned long blocks, size, capacity; + + blocks = (buf[0] << 24) | (buf[1] << 16) + | (buf[2] << 8) | buf[3]; + size = (buf[4] << 24) | (buf[5] << 16) | (buf[6] << 8) | buf[7]; + capacity = +( +(blocks / 1024L) * +(size * 10L)) / 1024L; + + printk( "%lu MB (%lu byte blocks)", + ((capacity + 5L) / 10L), size ); + } else { + memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); + retcode = fdomain_16x0_command(&SCinit); + } + printk ("\n" ); + } else { + memcpy(SCinit.cmnd, do_request_sense, sizeof(do_request_sense)); + retcode = fdomain_16x0_command(&SCinit); + } + } + } +#endif + + return 1; +} + +const char *fdomain_16x0_info(void) +{ + static char buffer[80]; + char *pt; + + strcpy( buffer, "Future Domain: TMC-16x0 SCSI driver, version" ); + if (strchr( VERSION, ':')) { /* Assume VERSION is an RCS Revision string */ + strcat( buffer, strchr( VERSION, ':' ) + 1 ); + pt = strrchr( buffer, '$') - 1; + if (!pt) /* Stripped RCS Revision string? */ + pt = buffer + strlen( buffer ) - 1; + if (*pt != ' ') + ++pt; + *pt++ = '\n'; + *pt = '\0'; + } else { /* Assume VERSION is a number */ + strcat( buffer, " " VERSION "\n" ); + } + + return buffer; +} + +#if 0 +static int fdomain_arbitrate( void ) +{ + int status = 0; + unsigned long timeout; + +#if EVERY_ACCESS + printk( "fdomain_arbitrate()\n" ); +#endif + + outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ + outb( adapter_mask, port_base + SCSI_Data_NoACK ); /* Set our id bit */ + outb( 0x04 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */ + + timeout = jiffies + 50; /* 500 mS */ + while (jiffies < timeout) { + status = inb( TMC_Status_port ); /* Read adapter status */ + if (status & 0x02) /* Arbitration complete */ + return 0; + } + + /* Make bus idle */ + fdomain_make_bus_idle(); + +#if EVERY_ACCESS + printk( "Arbitration failed, status = %x\n", status ); +#endif +#if ERRORS_ONLY + printk( "Future Domain: Arbitration failed, status = %x", status ); +#endif + return 1; +} +#endif + +static int fdomain_select( int target ) +{ + int status; + unsigned long timeout; + + + 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 ); + + timeout = jiffies + 25; /* 250mS */ + while (jiffies < timeout) { + status = inb( SCSI_Status_port ); /* Read adapter status */ + if (status & 1) { /* Busy asserted */ + /* Enable SCSI Bus (on error, should make bus idle with 0) */ + outb( 0x80, SCSI_Cntl_port ); + return 0; + } + } + /* Make bus idle */ + fdomain_make_bus_idle(); +#if EVERY_ACCESS + if (!target) printk( "Selection failed\n" ); +#endif +#if ERRORS_ONLY + if (!target) printk( "Future Domain: Selection failed" ); +#endif + return 1; +} + +void my_done( int error ) +{ + if (in_command) { + in_command = 0; + outb( 0x00, Interrupt_Cntl_port ); + fdomain_make_bus_idle(); + current_SC->result = error; + if (current_SC->scsi_done) + current_SC->scsi_done( current_SC ); + else panic( "Future Domain: current_SC->scsi_done() == NULL" ); + } else { + panic( "Future Domain: my_done() called outside of command\n" ); + } +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif +} + +void fdomain_16x0_intr( int unused ) +{ + int status; + int done = 0; + unsigned data_count; + + sti(); + + outb( 0x00, Interrupt_Cntl_port ); + + /* We usually have one spurious interrupt after each command. Ignore it. */ + if (!in_command || !current_SC) { /* Spurious interrupt */ +#if EVERY_ACCESS + printk( "Spurious interrupt, in_command = %d, current_SC = %x\n", + in_command, current_SC ); +#endif + return; + } + + /* Abort calls my_done, so we do nothing here. */ + if (current_SC->SCp.phase & aborted) { +#if DEBUG_ABORT + printk( "Interrupt after abort, ignoring\n" ); +#endif + /* + return; */ + } + +#if DEBUG_RACE + ++in_interrupt_flag; +#endif + + if (current_SC->SCp.phase & in_arbitration) { + status = inb( TMC_Status_port ); /* Read adapter status */ + if (!(status & 0x02)) { +#if EVERY_ACCESS + printk( " AFAIL " ); +#endif + my_done( DID_BUS_BUSY << 16 ); + return; + } + current_SC->SCp.phase = in_selection; + + outb( 0x40 | FIFO_COUNT, Interrupt_Cntl_port ); + + outb( 0x82, SCSI_Cntl_port ); /* Bus Enable + Select */ + outb( adapter_mask | (1 << current_SC->target), SCSI_Data_NoACK_port ); + + /* Stop arbitration and enable parity */ + outb( 0x10 | PARITY_MASK, TMC_Cntl_port ); +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif + return; + } else if (current_SC->SCp.phase & in_selection) { + status = inb( SCSI_Status_port ); + if (!(status & 0x01)) { + /* Try again, for slow devices */ + if (fdomain_select( current_SC->target )) { +#if EVERY_ACCESS + printk( " SFAIL " ); +#endif + my_done( DID_NO_CONNECT << 16 ); + return; + } else { +#if EVERY_ACCESS + printk( " AltSel " ); +#endif + /* Stop arbitration and enable parity */ + outb( 0x10 | PARITY_MASK, TMC_Cntl_port ); + } + } + current_SC->SCp.phase = in_other; + outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port ); + outb( 0x80, SCSI_Cntl_port ); +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif + return; + } + + /* current_SC->SCp.phase == in_other: this is the body of the routine */ + + status = inb( SCSI_Status_port ); + + if (status & 0x10) { /* REQ */ + + switch (status & 0x0e) { + + case 0x08: /* COMMAND OUT */ + outb( current_SC->cmnd[current_SC->SCp.sent_command++], + Write_SCSI_Data_port ); +#if EVERY_ACCESS + printk( "CMD = %x,", + current_SC->cmnd[ current_SC->SCp.sent_command - 1] ); +#endif + break; + case 0x00: /* DATA OUT -- tmc18c50 only */ + if (chip != tmc1800 && !current_SC->SCp.have_data_in) { + current_SC->SCp.have_data_in = -1; + outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); + } + break; + case 0x04: /* DATA IN -- tmc18c50 only */ + if (chip != tmc1800 && !current_SC->SCp.have_data_in) { + current_SC->SCp.have_data_in = 1; + outb( 0x90 | PARITY_MASK, TMC_Cntl_port ); + } + break; + case 0x0c: /* STATUS IN */ + current_SC->SCp.Status = inb( Read_SCSI_Data_port ); +#if EVERY_ACCESS + printk( "Status = %x, ", current_SC->SCp.Status ); +#endif +#if ERRORS_ONLY + if (current_SC->SCp.Status && current_SC->SCp.Status != 2) { + printk( "Future Domain: target = %d, command = %x, " + "Status = %x\n", + current_SC->target, current_SC->cmnd[0], + current_SC->SCp.Status ); + } +#endif + break; + case 0x0a: /* MESSAGE OUT */ + outb( MESSAGE_REJECT, Write_SCSI_Data_port ); /* Reject */ + break; + case 0x0e: /* MESSAGE IN */ + current_SC->SCp.Message = inb( Read_SCSI_Data_port ); +#if EVERY_ACCESS + printk( "Message = %x, ", current_SC->SCp.Message ); +#endif + if (!current_SC->SCp.Message) ++done; +#if DEBUG_MESSAGES || EVERY_ACCESS + if (current_SC->SCp.Message) { + printk( "Future Domain: Message = %x\n", + current_SC->SCp.Message ); + } +#endif + break; + } + } + + if (chip == tmc1800 + && !current_SC->SCp.have_data_in + && (current_SC->SCp.sent_command + >= COMMAND_SIZE( current_SC->cmnd[ 0 ] ))) { + /* We have to get the FIFO direction + correct, so I've made a table based + on the SCSI Standard of which commands + appear to require a DATA OUT phase. + */ + /* + p. 94: Command for all device types + CHANGE DEFINITION 40 DATA OUT + COMPARE 39 DATA OUT + COPY 18 DATA OUT + COPY AND VERIFY 3a DATA OUT + INQUIRY 12 + LOG SELECT 4c DATA OUT + LOG SENSE 4d + MODE SELECT (6) 15 DATA OUT + MODE SELECT (10) 55 DATA OUT + MODE SENSE (6) 1a + MODE SENSE (10) 5a + READ BUFFER 3c + RECEIVE DIAGNOSTIC RESULTS 1c + REQUEST SENSE 03 + SEND DIAGNOSTIC 1d DATA OUT + TEST UNIT READY 00 + WRITE BUFFER 3b DATA OUT + + p.178: Commands for direct-access devices (not listed on p. 94) + FORMAT UNIT 04 DATA OUT + LOCK-UNLOCK CACHE 36 + PRE-FETCH 34 + PREVENT-ALLOW MEDIUM REMOVAL 1e + READ (6)/RECEIVE 08 + READ (10) 3c + READ CAPACITY 25 + READ DEFECT DATA (10) 37 + READ LONG 3e + REASSIGN BLOCKS 07 DATA OUT + RELEASE 17 + RESERVE 16 DATA OUT + REZERO UNIT/REWIND 01 + SEARCH DATA EQUAL (10) 31 DATA OUT + SEARCH DATA HIGH (10) 30 DATA OUT + SEARCH DATA LOW (10) 32 DATA OUT + SEEK (6) 0b + SEEK (10) 2b + SET LIMITS (10) 33 + START STOP UNIT 1b + SYNCHRONIZE CACHE 35 + VERIFY (10) 2f + WRITE (6)/PRINT/SEND 0a DATA OUT + WRITE (10)/SEND 2a DATA OUT + WRITE AND VERIFY (10) 2e DATA OUT + WRITE LONG 3f DATA OUT + WRITE SAME 41 DATA OUT ? + + p. 261: Commands for sequential-access devices (not previously listed) + ERASE 19 + LOAD UNLOAD 1b + LOCATE 2b + READ BLOCK LIMITS 05 + READ POSITION 34 + READ REVERSE 0f + RECOVER BUFFERED DATA 14 + SPACE 11 + WRITE FILEMARKS 10 ? + + p. 298: Commands for printer devices (not previously listed) + ****** NOT SUPPORTED BY THIS DRIVER, since 0b is SEEK (6) ***** + SLEW AND PRINT 0b DATA OUT -- same as seek + STOP PRINT 1b + SYNCHRONIZE BUFFER 10 + + p. 315: Commands for processor devices (not previously listed) + + p. 321: Commands for write-once devices (not previously listed) + MEDIUM SCAN 38 + READ (12) a8 + SEARCH DATA EQUAL (12) b1 DATA OUT + SEARCH DATA HIGH (12) b0 DATA OUT + SEARCH DATA LOW (12) b2 DATA OUT + SET LIMITS (12) b3 + VERIFY (12) af + WRITE (12) aa DATA OUT + WRITE AND VERIFY (12) ae DATA OUT + + p. 332: Commands for CD-ROM devices (not previously listed) + PAUSE/RESUME 4b + PLAY AUDIO (10) 45 + PLAY AUDIO (12) a5 + PLAY AUDIO MSF 47 + PLAY TRACK RELATIVE (10) 49 + PLAY TRACK RELATIVE (12) a9 + READ HEADER 44 + READ SUB-CHANNEL 42 + READ TOC 43 + + p. 370: Commands for scanner devices (not previously listed) + GET DATA BUFFER STATUS 34 + GET WINDOW 25 + OBJECT POSITION 31 + SCAN 1b + SET WINDOW 24 DATA OUT + + p. 391: Commands for optical memory devices (not listed) + ERASE (10) 2c + ERASE (12) ac + MEDIUM SCAN 38 DATA OUT + READ DEFECT DATA (12) b7 + READ GENERATION 29 + READ UPDATED BLOCK 2d + UPDATE BLOCK 3d DATA OUT + + p. 419: Commands for medium changer devices (not listed) + EXCHANGE MEDIUM 46 + INITIALIZE ELEMENT STATUS 07 + MOVE MEDIUM a5 + POSITION TO ELEMENT 2b + READ ELEMENT STATUS b8 + REQUEST VOL. ELEMENT ADDRESS b5 + SEND VOLUME TAG b6 DATA OUT + + p. 454: Commands for communications devices (not listed previously) + GET MESSAGE (6) 08 + GET MESSAGE (10) 28 + GET MESSAGE (12) a8 + */ + + switch (current_SC->cmnd[0]) { + case CHANGE_DEFINITION: case COMPARE: case COPY: + case COPY_VERIFY: case LOG_SELECT: case MODE_SELECT: + case MODE_SELECT_10: case SEND_DIAGNOSTIC: case WRITE_BUFFER: + + case FORMAT_UNIT: case REASSIGN_BLOCKS: case RESERVE: + case SEARCH_EQUAL: case SEARCH_HIGH: case SEARCH_LOW: + case WRITE_6: case WRITE_10: case WRITE_VERIFY: + case 0x3f: case 0x41: + + case 0xb1: case 0xb0: case 0xb2: + case 0xaa: case 0xae: + + case 0x24: + + case 0x38: case 0x3d: + + case 0xb6: + + case 0xea: /* alternate number for WRITE LONG */ + + current_SC->SCp.have_data_in = -1; + outb( 0xd0 | PARITY_MASK, TMC_Cntl_port ); + break; + + case 0x00: + default: + + current_SC->SCp.have_data_in = 1; + outb( 0x90 | PARITY_MASK, TMC_Cntl_port ); + break; + } + } + + if (current_SC->SCp.have_data_in == -1) { /* DATA OUT */ + while ( (data_count = 0x2000 - inw( FIFO_Data_Count_port )) > 512 ) { +#if EVERY_ACCESS + printk( "DC=%d, ", data_count ) ; +#endif + if (data_count > current_SC->SCp.this_residual) + data_count = current_SC->SCp.this_residual; + if (data_count > 0) { +#if EVERY_ACCESS + printk( "%d OUT, ", data_count ); +#endif + if (data_count == 1) { + outb( *current_SC->SCp.ptr++, Write_FIFO_port ); + --current_SC->SCp.this_residual; + } else { + data_count >>= 1; + outsw( Write_FIFO_port, current_SC->SCp.ptr, data_count ); + current_SC->SCp.ptr += 2 * data_count; + current_SC->SCp.this_residual -= 2 * data_count; + } + } + if (!current_SC->SCp.this_residual) { + if (current_SC->SCp.buffers_residual) { + --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; + } else + break; + } + } + } + + if (current_SC->SCp.have_data_in == 1) { /* DATA IN */ + while ((data_count = inw( FIFO_Data_Count_port )) > 0) { +#if EVERY_ACCESS + printk( "DC=%d, ", data_count ); +#endif + if (data_count > current_SC->SCp.this_residual) + data_count = current_SC->SCp.this_residual; + if (data_count) { +#if EVERY_ACCESS + printk( "%d IN, ", data_count ); +#endif + if (data_count == 1) { + *current_SC->SCp.ptr++ = inb( Read_FIFO_port ); + --current_SC->SCp.this_residual; + } else { + data_count >>= 1; /* Number of words */ + insw( Read_FIFO_port, current_SC->SCp.ptr, data_count ); + current_SC->SCp.ptr += 2 * data_count; + current_SC->SCp.this_residual -= 2 * data_count; + } + } + if (!current_SC->SCp.this_residual + && current_SC->SCp.buffers_residual) { + --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 (done) { +#if EVERY_ACCESS + printk( " ** IN DONE %d ** ", current_SC->SCp.have_data_in ); +#endif + +#if ERRORS_ONLY + if (current_SC->cmnd[0] == REQUEST_SENSE && !current_SC->SCp.Status) { + if ((unsigned char)(*((char *)current_SC->request_buffer+2)) & 0x0f) { + unsigned char key; + unsigned char code; + unsigned char qualifier; + + key = (unsigned char)(*((char *)current_SC->request_buffer + 2)) + & 0x0f; + code = (unsigned char)(*((char *)current_SC->request_buffer + 12)); + qualifier = (unsigned char)(*((char *)current_SC->request_buffer + + 13)); + + if (!(key == UNIT_ATTENTION && (code == 0x29 || !code)) + && !(key == NOT_READY + && code == 0x04 + && (!qualifier || qualifier == 0x02 || qualifier == 0x01)) + && !(key == ILLEGAL_REQUEST && (code == 0x25 + || code == 0x24 + || !code))) + + printk( "Future Domain: REQUEST SENSE " + "Key = %x, Code = %x, Qualifier = %x\n", + key, code, qualifier ); + } + } +#endif +#if EVERY_ACCESS + printk( "BEFORE MY_DONE. . ." ); +#endif + my_done( (current_SC->SCp.Status & 0xff) + | ((current_SC->SCp.Message & 0xff) << 8) | (DID_OK << 16) ); +#if EVERY_ACCESS + printk( "RETURNING.\n" ); +#endif + + } else { + if (current_SC->SCp.phase & disconnect) { + outb( 0xd0 | FIFO_COUNT, Interrupt_Cntl_port ); + outb( 0x00, SCSI_Cntl_port ); + } else { + outb( 0x90 | FIFO_COUNT, Interrupt_Cntl_port ); + } + } +#if DEBUG_RACE + in_interrupt_flag = 0; +#endif + return; +} + +int fdomain_16x0_queue( Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + if (in_command) { + panic( "Future Domain: fdomain_16x0_queue() NOT REENTRANT!\n" ); + } +#if EVERY_ACCESS + printk( "queue: target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->target, + *(unsigned char *)SCpnt->cmnd, + SCpnt->use_sg, + SCpnt->request_bufflen ); +#endif + + fdomain_make_bus_idle(); + + current_SC = SCpnt; /* Save this for the done function */ + current_SC->scsi_done = done; + + /* Initialize static data */ + + 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 = 0; + current_SC->SCp.Message = 0; + current_SC->SCp.have_data_in = 0; + current_SC->SCp.sent_command = 0; + current_SC->SCp.phase = in_arbitration; + + /* Start arbitration */ + outb( 0x00, Interrupt_Cntl_port ); + outb( 0x00, SCSI_Cntl_port ); /* Disable data drivers */ + outb( adapter_mask, SCSI_Data_NoACK_port ); /* Set our id bit */ + ++in_command; + outb( 0x20, Interrupt_Cntl_port ); + outb( 0x14 | PARITY_MASK, TMC_Cntl_port ); /* Start arbitration */ + + return 0; +} + +/* The following code, which simulates the old-style command function, was + taken from Tommy Thorn's aha1542.c file. This code is Copyright (C) + 1992 Tommy Thorn. */ + +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; +} + +int fdomain_16x0_command( Scsi_Cmnd *SCpnt ) +{ + fdomain_16x0_queue( SCpnt, internal_done ); + + while (!internal_done_flag) + ; + internal_done_flag = 0; + return internal_done_errcode; +} + +/* End of code derived from Tommy Thorn's work. */ + +void print_info( Scsi_Cmnd *SCpnt ) +{ + unsigned int imr; + unsigned int irr; + unsigned int isr; + + print_banner(); + switch (SCpnt->SCp.phase) { + case in_arbitration: printk( "arbitration " ); break; + case in_selection: printk( "selection " ); break; + case in_other: printk( "other " ); break; + default: printk( "unknown " ); break; + } + + printk( "(%d), target = %d cmnd = 0x%02x pieces = %d size = %u\n", + SCpnt->SCp.phase, + SCpnt->target, + *(unsigned char *)SCpnt->cmnd, + SCpnt->use_sg, + SCpnt->request_bufflen ); + printk( "sent_command = %d, have_data_in = %d, timeout = %d\n", + SCpnt->SCp.sent_command, + SCpnt->SCp.have_data_in, + SCpnt->timeout ); +#if DEBUG_RACE + printk( "in_interrupt_flag = %d\n", in_interrupt_flag ); +#endif + + imr = (inb( 0x0a1 ) << 8) + inb( 0x21 ); + outb( 0x0a, 0xa0 ); + irr = inb( 0xa0 ) << 8; + outb( 0x0a, 0x20 ); + irr += inb( 0x20 ); + outb( 0x0b, 0xa0 ); + isr = inb( 0xa0 ) << 8; + outb( 0x0b, 0x20 ); + isr += inb( 0x20 ); + + /* Print out interesting information */ + printk( "IMR = 0x%04x", imr ); + if (imr & (1 << interrupt_level)) + printk( " (masked)" ); + printk( ", IRR = 0x%04x, ISR = 0x%04x\n", irr, isr ); + + printk( "SCSI Status = 0x%02x\n", inb( SCSI_Status_port ) ); + printk( "TMC Status = 0x%02x", inb( TMC_Status_port ) ); + if (inb( TMC_Status_port & 1)) + printk( " (interrupt)" ); + printk( "\n" ); + printk( "Interrupt Status = 0x%02x", inb( Interrupt_Status_port ) ); + if (inb( Interrupt_Status_port ) & 0x08) + printk( " (enabled)" ); + printk( "\n" ); + if (chip == tmc18c50) { + printk( "FIFO Status = 0x%02x\n", inb( port_base + FIFO_Status ) ); + printk( "Int. Condition = 0x%02x\n", + inb( port_base + Interrupt_Cond ) ); + } + printk( "Configuration 1 = 0x%02x\n", inb( port_base + Configuration1 ) ); + if (chip == tmc18c50) + printk( "Configuration 2 = 0x%02x\n", + inb( port_base + Configuration2 ) ); +} + +int fdomain_16x0_abort( Scsi_Cmnd *SCpnt, int code ) +{ + +#if EVERY_ACCESS || ERRORS_ONLY || DEBUG_ABORT + printk( "Future Domain: Abort " ); +#endif + + cli(); + if (!in_command) { +#if EVERY_ACCESS || ERRORS_ONLY + printk( " (not in command)\n" ); +#endif + sti(); + return 0; + } else { +#if EVERY_ACCESS || ERRORS_ONLY + printk( " code = %d\n", code ); +#endif + } + +#if DEBUG_ABORT + print_info( SCpnt ); +#endif + + fdomain_make_bus_idle(); + + current_SC->SCp.phase |= aborted; + + current_SC->result = code ? code : DID_ABORT; + + sti(); + + /* Aborts are not done well. . . */ + my_done( code << 16 ); + + return 0; +} + +int fdomain_16x0_reset( Scsi_Cmnd *SCpnt ) +{ +#if DEBUG_RESET + static int called_once = 0; +#endif + +#if ERRORS_ONLY + printk( "Future Domain: SCSI Bus Reset\n" ); +#endif + +#if DEBUG_RESET + if (called_once) print_info( current_SC ); + called_once = 1; +#endif + + outb( 1, SCSI_Cntl_port ); + do_pause( 2 ); + outb( 0, SCSI_Cntl_port ); + do_pause( 115 ); + outb( 0, SCSI_Mode_Cntl_port ); + outb( PARITY_MASK, TMC_Cntl_port ); + + /* Unless this is the very first call (i.e., SCPnt == NULL), everything + is probably hosed at this point. We will, however, try to keep + things going by informing the high-level code that we need help. */ + + if (SCpnt) + SCpnt->flags |= NEEDS_JUMPSTART; + + return 0; +} + +int fdomain_16x0_biosparam( int size, int dev, int *info_array ) +{ + int drive; + struct drive_info { + unsigned short cylinders; + unsigned char heads; + unsigned char sectors; + } *i; + + /* NOTES: + The RAM area starts at 0x1f00 from the bios_base address. + + For BIOS Version 2.0: + + The drive parameter table seems to start at 0x1f30. + The first byte's purpose is not known. + Next is the cylinder, head, and sector information. + The last 4 bytes appear to be the drive's size in sectors. + The other bytes in the drive parameter table are unknown. + If anyone figures them out, please send me mail, and I will + update these notes. + + Tape drives do not get placed in this table. + + There is another table at 0x1fea: + If the byte is 0x01, then the SCSI ID is not in use. + If the byte is 0x18 or 0x48, then the SCSI ID is in use, + although tapes don't seem to be in this table. I haven't + seen any other numbers (in a limited sample). + + 0x1f2d is a drive count (i.e., not including tapes) + + The table at 0x1fcc are I/O ports addresses for the various + operations. I calculate these by hand in this driver code. + + For BIOS Version 3.2: + + The drive parameter table starts at 0x1f70. Each entry is + 0x0a bytes long. Heads are one less than we need to report. + */ + + drive = MINOR(dev) / 16; + + if (bios_major == 2) { + i = (struct drive_info *)( (char *)bios_base + 0x1f31 + drive * 25 ); + info_array[0] = i->heads; + info_array[1] = i->sectors; + info_array[2] = i->cylinders; + } else if (bios_major == 3) { /* Appears to be the same for 3.0 and 3.2 */ + i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 ); + info_array[0] = i->heads + 1; + info_array[1] = i->sectors; + info_array[2] = i->cylinders; + } else { + /* How the data is stored in the RAM area is very BIOS-dependent. + Therefore, assume a version 3 layout, and check for validity. */ + + i = (struct drive_info *)( (char *)bios_base + 0x1f71 + drive * 10 ); + info_array[0] = i->heads + 1; + info_array[1] = i->sectors; + info_array[2] = i->cylinders; + + if (!info_array[0] + || !info_array[1] + || !info_array[2] + || 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] + = info_array[1] + = info_array[2] + = 0; + } + } + + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.h new file mode 100644 index 000000000..ef77738ab --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/fdomain.h @@ -0,0 +1,42 @@ +/* fdomain.h -- Header for Future Domain TMC-16x0 driver + * Created: Sun May 3 18:47:33 1992 by faith@cs.unc.edu + * Revised: Tue Jan 4 20:44:04 1994 by faith@cs.unc.edu + * Author: Rickard E. Faith, faith@cs.unc.edu + * Copyright 1992, 1993, 1994 Rickard E. Faith + * + * $Id: fdomain.h,v 5.3 1994/01/05 01:44:16 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 + * 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. + + */ + +#ifndef _FDOMAIN_H +#define _FDOMAIN_H + +int fdomain_16x0_detect( int ); +int fdomain_16x0_command( Scsi_Cmnd * ); +int fdomain_16x0_abort( Scsi_Cmnd *, int ); +const char *fdomain_16x0_info( void ); +int fdomain_16x0_reset( Scsi_Cmnd * ); +int fdomain_16x0_queue( Scsi_Cmnd *, void (*done)(Scsi_Cmnd *) ); +int fdomain_16x0_biosparam( int, int, int * ); + +#define FDOMAIN_16X0 { "Future Domain TMC-16x0", \ + fdomain_16x0_detect, \ + fdomain_16x0_info, \ + fdomain_16x0_command, \ + fdomain_16x0_queue, \ + fdomain_16x0_abort, \ + fdomain_16x0_reset, \ + NULL, \ + fdomain_16x0_biosparam, \ + 1, 6, 64 /* SG_NONE */, 1 ,0, 0 } +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/g_NCR5380.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/g_NCR5380.c new file mode 100644 index 000000000..91ebdda4f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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 +#if defined(CONFIG_SCSI_GENERIC_NCR5380) +/* Standard option */ +#define AUTOPROBE_IRQ + +#include +#include +#include +#include +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/g_NCR5380.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/g_NCR5380.h new file mode 100644 index 000000000..88a536f15 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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(Scsi_Cmnd *); + + +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.c new file mode 100644 index 000000000..63ea77dbf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.c @@ -0,0 +1,304 @@ +/* + * hosts.c Copyright (C) 1992 Drew Eckhardt + * mid to lowlevel SCSI driver interface by + * Drew Eckhardt + * + * + */ + + +/* + * 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 +#include "../block/blk.h" +#include +#include +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.h new file mode 100644 index 000000000..3780d7240 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/hosts.h @@ -0,0 +1,246 @@ +/* + * hosts.h Copyright (C) 1992 Drew Eckhardt + * mid to low-level SCSI driver interface header by + * Drew Eckhardt + * + * + * + * 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.3 1993/09/24 12:21:00 drew Exp drew $ +*/ + + +/* A jumpstart is often required when the reset() function is called - + many host adapters cannot do this cleanly, so they do nothing at all. + To get the command going again, these routines set this bit in the flags + so that a scsi_request_sense() is executed, and the command starts running + again */ + +#define NEEDS_JUMPSTART 0x20 + +#define SG_NONE 0 +#define SG_ALL 0xff + +/* The various choices mean: + NONE: Self evident. Host adapter is not capable of scatter-gather. + ALL: Means that the host adapter module can do scatter-gather, + and that there is no limit to the size of the table to which + we scatter/gather data. + Anything else: Indicates the maximum number of chains that can be + 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 + { + /* + The name pointer is a pointer to the name of the SCSI + device detected. + */ + + char *name; + + /* + The detect function shall return non zero on detection, + 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 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); + + /* + The info function will return whatever useful + information the developer sees fit. + */ + + const char *(* info)(void); + + /* + The command function takes a target, a command (this is a SCSI + command formatted as per the SCSI spec, nothing strange), a + data buffer pointer, and data buffer length pointer. The return + is a status int, bit fielded as follows : + Byte What + 0 SCSI status code + 1 SCSI 1 byte message + 2 host error return. + 3 mid level error return + */ + + int (* command)(Scsi_Cmnd *); + + /* + The QueueCommand function works in a similar manner + to the command function. It takes an additional parameter, + void (* done)(int host, int code) which is passed the host + # and exit result when the command is complete. + Host number is the POSITION IN THE hosts array of THIS + host adapter. + */ + + int (* queuecommand)(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); + + /* + Since the mid level driver handles time outs, etc, we want to + be able to abort the current command. Abort returns 0 if the + abortion was successful. If non-zero, the code passed to it + will be used as the return code, otherwise + DID_ABORT should be returned. + + Note that the scsi driver should "clean up" after itself, + resetting the bus, etc. if necessary. + */ + + int (* abort)(Scsi_Cmnd *, int); + + /* + The reset function will reset the SCSI bus. Any executing + commands should fail with a DID_RESET in the host byte. + The Scsi_Cmnd is passed so that the reset routine can figure + out which host adapter should be reset, and also which command + within the command block was responsible for the reset in + the first place. Some hosts do not implement a reset function, + and these hosts must call scsi_request_sense(SCpnt) to keep + the command alive. + */ + + int (* reset)(Scsi_Cmnd *); + /* + This function is used to select synchronous communications, + which will result in a higher data throughput. Not implemented + yet. + */ + + int (* slave_attach)(int, int); + /* + This function determines the bios parameters for a given + harddisk. These tend to be numbers that are made up by + the host adapter. Parameters: + size, device number, list (heads, sectors, cylinders) + */ + + int (* bios_param)(int, int, int []); + + /* + This determines if we will use a non-interrupt driven + or an interrupt driven scheme, It is set to the maximum number + of simulataneous commands a given host adapter will accept. + */ + int can_queue; + + /* + In many instances, especially where disconnect / reconnect are + supported, our host also has an ID on the SCSI bus. If this is + the case, then it must be reserved. Please set this_id to -1 if + your settup is in single initiator mode, and the host lacks an + ID. + */ + + int this_id; + + /* + This determines the degree to which the host adapter is capable + of scatter-gather. + */ + + short unsigned int sg_tablesize; + + /* + True if this host adapter can make good use of linked commands. + This will allow more than one command to be queued to a given + unit on a given host. Set this to the maximum number of command + blocks to be provided for each device. Set this to 1 for one + command block per lun, 2 for two, etc. Do not set this to 0. + You should make sure that the host adapter will do the right thing + before you try setting this above 1. + */ + + short cmd_per_lun; + /* + present contains counter indicating how many boards of this + type were found when we did the scan. + */ + + unsigned char present; + /* + true if this host adapter uses unchecked DMA onto an ISA bus. + */ + unsigned unchecked_isa_dma:1; + } Scsi_Host_Template; + +/* + The scsi_hosts array is the array containing the data for all + possible 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. +*/ + +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. +*/ + + +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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/pas16.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/pas16.c new file mode 100644 index 000000000..e7de2a17d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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 +#include +#include +#include +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/pas16.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/pas16.h new file mode 100644 index 000000000..1ebacb871 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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(Scsi_Cmnd *); + +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.c new file mode 100644 index 000000000..a2083b827 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.c @@ -0,0 +1,1710 @@ +/* + * scsi.c Copyright (C) 1992 Drew Eckhardt + * generic mid-level SCSI driver by + * Drew Eckhardt + * + * + * + * Bug correction thanks go to : + * Rik Faith + * Tommy Thorn + * Thomas Wuensche + * + * Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#include +#include +#include +#include + +#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.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 (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); +static void print_inquiry(unsigned char *data); +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, + scsi_devices an array of these specifing the address for each + (host, id, LUN) +*/ + +int NR_SCSI_DEVICES=0; + +Scsi_Device * scsi_devices = NULL; + +static unsigned char generic_sense[6] = {REQUEST_SENSE, 0,0,0, 255, 0}; + +/* We make this not static so that we can read the array with gdb. */ +/* static */ Scsi_Cmnd * last_cmnd = NULL; + +/* + * As the scsi do command functions are inteligent, and may need to + * redo a command, we need to keep track of the last command + * executed on each one. + */ + +#define WAS_RESET 0x01 +#define WAS_TIMEDOUT 0x02 +#define WAS_SENSE 0x04 +#define IS_RESETTING 0x08 +#define ASKED_FOR_SENSE 0x10 +/* #define NEEDS_JUMPSTART 0x20 defined in hosts.h */ + +/* + * This is the number of clock ticks we should wait before we time out + * and abort the command. This is for where the scsi.c module generates + * the command, not where it originates from a higher level, in which + * case the timeout is specified there. + * + * ABORT_TIMEOUT and RESET_TIMEOUT are the timeouts for RESET and ABORT + * respectively. + */ + +#ifdef DEBUG + #define SCSI_TIMEOUT 500 +#else + #define SCSI_TIMEOUT 100 +#endif + +#ifdef DEBUG + #define SENSE_TIMEOUT SCSI_TIMEOUT + #define ABORT_TIMEOUT SCSI_TIMEOUT + #define RESET_TIMEOUT SCSI_TIMEOUT +#else + #define SENSE_TIMEOUT 50 + #define RESET_TIMEOUT 50 + #define ABORT_TIMEOUT 50 + #define MIN_RESET_DELAY 100 +#endif + +/* The following devices are known not to tolerate a lun != 0 scan for + one reason or another. Some will respond to all luns, others will + lock up. */ + + struct blist{ + char * vendor; + char * model; + char * revision; /* Latest revision known to be bad. Not used yet */ + }; + +static struct blist blacklist[] = +{ + {"DENON","DRD-25X","V"}, /* A cdrom that locks up when probed at lun != 0 */ + {"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){ + int i = 0; + unsigned char * pnt; + for(i=0; 1; i++){ + if(blacklist[i].vendor == NULL) return 0; + pnt = &response_data[8]; + while(*pnt && *pnt == ' ') pnt++; + if(memcmp(blacklist[i].vendor, pnt, + strlen(blacklist[i].vendor))) continue; + pnt = &response_data[16]; + while(*pnt && *pnt == ' ') pnt++; + if(memcmp(blacklist[i].model, pnt, + strlen(blacklist[i].model))) continue; + return 1; + }; +}; + +/* + * As the actual SCSI command runs in the background, we must set up a + * flag that tells scan_scsis() when the result it has is valid. + * scan_scsis can set the_result to -1, and watch for it to become the + * actual return code for that call. the scan_scsis_done function() is + * our user specified completion function that is passed on to the + * scsi_do_cmd() function. + */ + +static volatile int in_scan = 0; +static int the_result; +static void scan_scsis_done (Scsi_Cmnd * SCpnt) + { + +#ifdef DEBUG + printk ("scan_scsis_done(%d, %06x)\n", SCpnt->host, SCpnt->result); +#endif + SCpnt->request.dev = 0xfffe; + } +/* + * Detecting SCSI devices : + * We scan all present host adapter's busses, from ID 0 to ID 6. + * We use the INQUIRY command, determine device type, and pass the ID / + * lun address of all sequential devices to the tape driver, all random + * devices to the disk driver. + */ + +static void scan_scsis (void) +{ + int dev, lun, type; + unsigned char scsi_cmd [12]; + unsigned char scsi_result [256]; + struct Scsi_Host * shpnt; + Scsi_Cmnd SCmd; + + ++in_scan; + lun = 0; + + SCmd.next = NULL; + SCmd.prev = NULL; + for (shpnt = scsi_hostlist; shpnt; shpnt = shpnt->next) + { + shpnt->host_queue = &SCmd; /* We need this so that + commands can time out */ + for (dev = 0; dev < 8; ++dev) + if (shpnt->this_id != dev) +/* + * We need the for so our continue, etc. work fine. + */ + +#ifdef NO_MULTI_LUN + for (lun = 0; lun < 1; ++lun) +#else + for (lun = 0; lun < 8; ++lun) +#endif + { + 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; + scsi_devices[NR_SCSI_DEVICES].device_wait = NULL; +/* + * Assume that the device will have handshaking problems, and then + * fix this field later if it turns out it doesn't. + */ + scsi_devices[NR_SCSI_DEVICES].borken = 1; + + scsi_cmd[0] = TEST_UNIT_READY; + scsi_cmd[1] = lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = 0; + + SCmd.host = shpnt; + SCmd.target = dev; + SCmd.lun = lun; + + SCmd.request.dev = 0xffff; /* Mark not busy */ + SCmd.use_sg = 0; + SCmd.old_use_sg = 0; + SCmd.transfersize = 0; + SCmd.underflow = 0; + SCmd.index = NR_SCSI_DEVICES; + + scsi_do_cmd (&SCmd, + (void *) scsi_cmd, (void *) + scsi_result, 256, scan_scsis_done, + SCSI_TIMEOUT + 400, 5); + + while (SCmd.request.dev != 0xfffe); +#if defined(DEBUG) || defined(DEBUG_INIT) + printk("scsi: scan SCSIS id %d lun %d\n", dev, lun); + printk("scsi: return code %08x\n", SCmd.result); +#endif + + + if(SCmd.result) { + if ((driver_byte(SCmd.result) & DRIVER_SENSE) && + ((SCmd.sense_buffer[0] & 0x70) >> 4) == 7) { + if (SCmd.sense_buffer[2] &0xe0) + continue; /* No devices here... */ + if(((SCmd.sense_buffer[2] & 0xf) != NOT_READY) && + ((SCmd.sense_buffer[2] & 0xf) != UNIT_ATTENTION)) + continue; + } + else + break; + }; + +#if defined (DEBUG) || defined(DEBUG_INIT) + printk("scsi: performing INQUIRY\n"); +#endif + + /* + * Build an INQUIRY command block. + */ + + scsi_cmd[0] = INQUIRY; + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[2] = 0; + scsi_cmd[3] = 0; + scsi_cmd[4] = 255; + scsi_cmd[5] = 0; + + SCmd.request.dev = 0xffff; /* Mark not busy */ + + scsi_do_cmd (&SCmd, + (void *) scsi_cmd, (void *) + scsi_result, 256, scan_scsis_done, + SCSI_TIMEOUT, 3); + + while (SCmd.request.dev != 0xfffe); + + the_result = SCmd.result; + +#if defined(DEBUG) || defined(DEBUG_INIT) + if (!the_result) + printk("scsi: INQUIRY successful\n"); + else + printk("scsi: INQUIRY failed with code %08x\n"); +#endif + + if(the_result) break; + + /* skip other luns on this device */ + + if (!the_result) + { + scsi_devices[NR_SCSI_DEVICES]. + removable = (0x80 & + scsi_result[1]) >> 7; + scsi_devices[NR_SCSI_DEVICES].lockable = + scsi_devices[NR_SCSI_DEVICES].removable; + scsi_devices[NR_SCSI_DEVICES]. + changed = 0; + scsi_devices[NR_SCSI_DEVICES]. + access_count = 0; + scsi_devices[NR_SCSI_DEVICES]. + busy = 0; +/* + * Currently, all sequential devices are assumed to be tapes, + * all random devices disk, with the appropriate read only + * flags set for ROM / WORM treated as RO. + */ + + switch (type = scsi_result[0]) + { + case TYPE_TAPE : + case TYPE_DISK : + case TYPE_MOD : + scsi_devices[NR_SCSI_DEVICES].writeable = 1; + break; + case TYPE_WORM : + case TYPE_ROM : + scsi_devices[NR_SCSI_DEVICES].writeable = 0; + break; + default : +#if 0 +#ifdef DEBUG + printk("scsi: unknown type %d\n", type); + print_inquiry(scsi_result); +#endif +#endif + type = -1; + } + + scsi_devices[NR_SCSI_DEVICES].random = + (type == TYPE_TAPE) ? 0 : 1; + scsi_devices[NR_SCSI_DEVICES].type = type; + + if (type != -1) + { + print_inquiry(scsi_result); + switch(type){ + case TYPE_TAPE: + printk("Detected scsi tape st%d at scsi%d, id %d, lun %d\n", MAX_ST, + 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, + shpnt->host_no , dev, lun); + if(NR_SR != -1) ++MAX_SR; + break; + case TYPE_DISK: + case TYPE_MOD: + printk("Detected scsi disk sd%c at scsi%d, id %d, lun %d\n", 'a'+MAX_SD, + 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 + * problems when used with the Seagate controllers. Before we + * know what type of device we're talking to, we assume it's + * borken and then change it here if it turns out that it isn't + * a TEXEL drive. + */ + + 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 + * integrating my seagate patches which do multiple I_T_L nexuses. + */ + +#ifdef notyet + || (strncmp("1.06", (char *) &scsi_result[[, 4) != 0) +#endif + ) + scsi_devices[NR_SCSI_DEVICES].borken = 0; + + + /* These devices need this "key" to unlock the device + so we can use it */ + if(memcmp("INSITE", &scsi_result[8], 6) == 0 && + (memcmp("Floptical F*8I", &scsi_result[16], 16) == 0 + || memcmp("I325VM", &scsi_result[16], 6) == 0)) { + printk("Unlocked floptical drive.\n"); + scsi_devices[NR_SCSI_DEVICES].lockable = 0; + scsi_cmd[0] = MODE_SENSE; + scsi_cmd[1] = (lun << 5) & 0xe0; + scsi_cmd[2] = 0x2e; + scsi_cmd[3] = 0; + scsi_cmd[4] = 0x2a; + scsi_cmd[5] = 0; + + SCmd.request.dev = 0xffff; /* Mark not busy */ + + scsi_do_cmd (&SCmd, + (void *) scsi_cmd, (void *) + scsi_result, 0x2a, scan_scsis_done, + SCSI_TIMEOUT, 3); + + while (SCmd.request.dev != 0xfffe); + }; + + ++NR_SCSI_DEVICES; + /* Some scsi devices cannot be polled for lun != 0 + due to firmware bugs */ + if(blacklisted(scsi_result)) break; + /* Some scsi-1 peripherals do not handle lun != 0. + I am assuming that scsi-2 peripherals do better */ + if((scsi_result[2] & 0x07) == 1 && + (scsi_result[3] & 0x0f) == 0) break; + } + } /* if result == DID_OK ends */ + } /* for lun ends */ + shpnt->host_queue = NULL; /* No longer needed here */ + } /* if present */ + + printk("scsi : detected "); + if(NR_SD != -1) + printk("%d SCSI disk%s ", MAX_SD, (MAX_SD != 1) ? "s" : ""); + + if(NR_ST != -1) + printk("%d tape%s ", MAX_ST, (MAX_ST != 1) ? "s" : ""); + + if(NR_SR != -1) + printk("%d CD-ROM drive%s ", MAX_SR, (MAX_SR != 1) ? "s" : ""); + + printk("total.\n"); + in_scan = 0; +} /* scan_scsis ends */ + +/* + * Flag bits for the internal_timeout array + */ + +#define NORMAL_TIMEOUT 0 +#define IN_ABORT 1 +#define IN_RESET 2 +/* + This is our time out function, called when the timer expires for a + given host adapter. It will attempt to abort the currently executing + command, that failing perform a kernel panic. +*/ + +static void scsi_times_out (Scsi_Cmnd * SCpnt) + { + + switch (SCpnt->internal_timeout & (IN_ABORT | IN_RESET)) + { + case NORMAL_TIMEOUT: + if (!in_scan) + printk("SCSI host %d timed out - aborting command\n", + 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->host_no); + if (!scsi_reset (SCpnt)) + return; + case IN_RESET: + case (IN_ABORT | IN_RESET): + panic("Unable to reset scsi host %d\n",SCpnt->host->host_no); + default: + INTERNAL_ERROR; + } + + } + + +/* This function takes a quick look at a request, and decides if it +can be queued now, or if there would be a stall while waiting for +something else to finish. This routine assumes that interrupts are +turned off when entering the routine. It is the responsibility +of the calling code to ensure that this is the case. */ + +Scsi_Cmnd * request_queueable (struct request * req, int index) +{ + 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"); + + if (req && req->dev <= 0) + panic("Invalid device in allocate_device"); + + SCpnt = scsi_devices[index].host->host_queue; + while(SCpnt){ + if(SCpnt->target == scsi_devices[index].id && + SCpnt->lun == scsi_devices[index].lun) + if(SCpnt->request.dev < 0) break; + SCpnt = SCpnt->next; + }; + + if (!SCpnt) 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)); + 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 */ + }; + + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ + SCpnt->old_use_sg = 0; + SCpnt->transfersize = 0; + SCpnt->underflow = 0; + return SCpnt; +} + +/* This function returns a structure pointer that will be valid for +the device. The wait parameter tells us whether we should wait for +the unit to become free or not. We are also able to tell this routine +not to return a descriptor if the host is unable to accept any more +commands for the time being. We need to keep in mind that there is no +guarantee that the host remain not busy. Keep in mind the +request_queueable function also knows the internal allocation scheme +of the packets for each device */ + +Scsi_Cmnd * allocate_device (struct request ** reqp, int index, int wait) +{ + 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; + + if ((index < 0) || (index > NR_SCSI_DEVICES)) + panic ("Index number in allocate_device() is out of range.\n"); + + if (reqp) req = *reqp; + + /* 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; + + while (1==1){ + SCpnt = host->host_queue; + while(SCpnt){ + if(SCpnt->target == scsi_devices[index].id && + SCpnt->lun == scsi_devices[index].lun) { + SCwait = SCpnt; + if(SCpnt->request.dev < 0) break; + }; + SCpnt = SCpnt->next; + }; + cli(); + /* See if this request has already been queued by an interrupt routine */ + if (req && ((req->dev < 0) || (req->dev != dev))) { + sti(); + return NULL; + }; + if (!SCpnt || SCpnt->request.dev >= 0) /* Might have changed */ + { + sti(); + if(!wait) return NULL; + if (!SCwait) { + printk("Attempt to allocate device index %d, target %d, lun %d\n", + index, scsi_devices[index].id ,scsi_devices[index].lun); + panic("No device found in allocate_device\n"); + }; + SCSI_SLEEP(&scsi_devices[SCwait->index].device_wait, + (SCwait->request.dev > 0)); + } else { + if (req) { + memcpy(&SCpnt->request, req, sizeof(struct request)); + 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 */ + }; + sti(); + break; + }; + }; + + SCpnt->use_sg = 0; /* Reset the scatter-gather flag */ + SCpnt->old_use_sg = 0; + SCpnt->transfersize = 0; /* No default transfer size */ + SCpnt->underflow = 0; /* Do not flag underflow conditions */ + return SCpnt; +} + +/* + This is inline because we have stack problemes if we recurse to deeply. +*/ + +inline void internal_cmnd (Scsi_Cmnd * SCpnt) + { + int temp; + struct Scsi_Host * host; +#ifdef DEBUG_DELAY + int clock; +#endif + + if ((unsigned long) &SCpnt < current->kernel_stack_page) + panic("Kernel stack overflow."); + + host = SCpnt->host; + +/* + We will wait MIN_RESET_DELAY clock ticks after the last reset so + we can avoid the drive not being ready. +*/ +temp = host->last_reset; +while (jiffies < temp); + +update_timeout(SCpnt, SCpnt->timeout_per_command); + +/* + We will use a queued command if possible, otherwise we will emulate the + queing and calling of completion function ourselves. +*/ +#ifdef DEBUG + printk("internal_cmnd (host = %d, target = %d, command = %08x, buffer = %08x, \n" + "bufflen = %d, done = %08x)\n", SCpnt->host->host_no, SCpnt->target, SCpnt->cmnd, SCpnt->buffer, SCpnt->bufflen, SCpnt->done); +#endif + + if (host->hostt->can_queue) + { +#ifdef DEBUG + printk("queuecommand : routine at %08x\n", + host->hostt->queuecommand); +#endif + host->hostt->queuecommand (SCpnt, scsi_done); + } + else + { + +#ifdef DEBUG + printk("command() : routine at %08x\n", host->hostt->command); +#endif + 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->host_no, temp, done); +#endif + scsi_done(SCpnt); + } +#ifdef DEBUG + printk("leaving internal_cmnd()\n"); +#endif + } + +static void scsi_request_sense (Scsi_Cmnd * SCpnt) + { + cli(); + SCpnt->flags |= WAS_SENSE | ASKED_FOR_SENSE; + update_timeout(SCpnt, SENSE_TIMEOUT); + sti(); + + + memcpy ((void *) SCpnt->cmnd , (void *) generic_sense, + sizeof(generic_sense)); + + SCpnt->cmnd[1] = SCpnt->lun << 5; + SCpnt->cmnd[4] = sizeof(SCpnt->sense_buffer); + + SCpnt->request_buffer = &SCpnt->sense_buffer; + SCpnt->request_bufflen = sizeof(SCpnt->sense_buffer); + SCpnt->use_sg = 0; + internal_cmnd (SCpnt); + SCpnt->use_sg = SCpnt->old_use_sg; + } + + + +/* + scsi_do_cmd sends all the commands out to the low-level driver. It + handles the specifics required for each low level driver - ie queued + or non queud. It also prevents conflicts when different high level + drivers go for the same host at the same time. +*/ + +void scsi_do_cmd (Scsi_Cmnd * SCpnt, const void *cmnd , + void *buffer, unsigned bufflen, void (*done)(Scsi_Cmnd *), + int timeout, int retries + ) + { + struct Scsi_Host * host = SCpnt->host; + +#ifdef DEBUG + { + int i; + 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->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) + { + panic ("Invalid or not present host. %d\n", host->host_no); + } + + +/* + We must prevent reentrancy to the lowlevel host driver. This prevents + it - we enter a loop until the host we want to talk to is not busy. + Race conditions are prevented, as interrupts are disabled inbetween the + time we check for the host being not busy, and the time we mark it busy + ourselves. +*/ + + while (1==1){ + cli(); + if (host->hostt->can_queue + && host->host_busy >= host->hostt->can_queue) + { + sti(); + SCSI_SLEEP(&host->host_wait, + (host->host_busy >= host->hostt->can_queue)); + } else { + host->host_busy++; + sti(); + break; + }; + }; +/* + Our own function scsi_done (which marks the host as not busy, disables + the timeout counter, etc) will be called by us or by the + scsi_hosts[host].queuecommand() function needs to also call + the completion function for the high level driver. + +*/ + + memcpy ((void *) SCpnt->data_cmnd , (void *) cmnd, 12); +#if 0 + SCpnt->host = host; + SCpnt->target = target; + SCpnt->lun = (SCpnt->data_cmnd[1] >> 5); +#endif + SCpnt->bufflen = bufflen; + SCpnt->buffer = buffer; + SCpnt->flags=0; + SCpnt->retries=0; + SCpnt->allowed=retries; + SCpnt->done = done; + SCpnt->timeout_per_command = timeout; + + 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); + SCpnt->request_buffer = buffer; + SCpnt->request_bufflen = bufflen; + SCpnt->old_use_sg = SCpnt->use_sg; + + /* Start the timer ticking. */ + + SCpnt->internal_timeout = 0; + internal_cmnd (SCpnt); + +#ifdef DEBUG + printk ("Leaving scsi_do_cmd()\n"); +#endif + } + + + +/* + The scsi_done() function disables the timeout timer for the scsi host, + marks the host as not busy, and calls the user specified completion + function for that host's current command. +*/ + +static void reset (Scsi_Cmnd * SCpnt) +{ +#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(SCpnt->flags & NEEDS_JUMPSTART) { + SCpnt->flags &= ~NEEDS_JUMPSTART; + scsi_request_sense (SCpnt); + }; +} + + + +static int check_sense (Scsi_Cmnd * SCpnt) + { + /* If there is no sense information, request it. If we have already + requested it, there is no point in asking again - the firmware must be + confused. */ + if (((SCpnt->sense_buffer[0] & 0x70) >> 4) != 7) { + if(!(SCpnt->flags & ASKED_FOR_SENSE)) + return SUGGEST_SENSE; + else + return SUGGEST_RETRY; + } + + SCpnt->flags &= ~ASKED_FOR_SENSE; + +#ifdef DEBUG_INIT + printk("scsi%d : ", SCpnt->host->host_no); + print_sense("", SCpnt); + printk("\n"); +#endif + if (SCpnt->sense_buffer[2] &0xe0) + return SUGGEST_ABORT; + + switch (SCpnt->sense_buffer[2] & 0xf) + { + case NO_SENSE: + return 0; + case RECOVERED_ERROR: + if (scsi_devices[SCpnt->index].type == TYPE_TAPE) + return SUGGEST_IS_OK; + else + return 0; + + case ABORTED_COMMAND: + return SUGGEST_RETRY; + case NOT_READY: + case UNIT_ATTENTION: + return SUGGEST_ABORT; + + /* these three are not supported */ + case COPY_ABORTED: + case VOLUME_OVERFLOW: + case MISCOMPARE: + + case MEDIUM_ERROR: + return SUGGEST_REMAP; + case BLANK_CHECK: + case DATA_PROTECT: + case HARDWARE_ERROR: + case ILLEGAL_REQUEST: + default: + return SUGGEST_ABORT; + } + } + +/* This function is the mid-level interrupt routine, which decides how + * to handle error conditions. Each invocation of this function must + * do one and *only* one of the following: + * + * (1) Call last_cmnd[host].done. This is done for fatal errors and + * normal completion, and indicates that the handling for this + * request is complete. + * (2) Call internal_cmnd to requeue the command. This will result in + * scsi_done being called again when the retry is complete. + * (3) Call scsi_request_sense. This asks the host adapter/drive for + * more information about the error condition. When the information + * is available, scsi_done will be called again. + * (4) Call reset(). This is sort of a last resort, and the idea is that + * this may kick things loose and get the drive working again. reset() + * automatically calls scsi_request_sense, and thus scsi_done will be + * called again once the reset is complete. + * + * If none of the above actions are taken, the drive in question + * will hang. If more than one of the above actions are taken by + * scsi_done, then unpredictable behavior will result. + */ +static void scsi_done (Scsi_Cmnd * SCpnt) + { + int status=0; + int exit=0; + int checked; + int oldto; + struct Scsi_Host * host = SCpnt->host; + int result = SCpnt->result; + oldto = update_timeout(SCpnt, 0); + +#define FINISHED 0 +#define MAYREDO 1 +#define REDO 3 +#define PENDING 4 + +#ifdef DEBUG + printk("In scsi_done(host = %d, result = %06x)\n", host->host_no, result); +#endif + switch (host_byte(result)) + { + case DID_OK: + if (SCpnt->flags & IS_RESETTING) + { + SCpnt->flags &= ~IS_RESETTING; + status = REDO; + break; + } + + if (status_byte(result) && (SCpnt->flags & WAS_SENSE)) + /* Failed to obtain sense information */ + { + SCpnt->flags &= ~WAS_SENSE; + SCpnt->internal_timeout &= ~SENSE_TIMEOUT; + + if (!(SCpnt->flags & WAS_RESET)) + { + printk("scsi%d : target %d lun %d request sense failed, performing reset.\n", + SCpnt->host->host_no, SCpnt->target, SCpnt->lun); + reset(SCpnt); + return; + } + else + { + exit = (DRIVER_HARD | SUGGEST_ABORT); + status = FINISHED; + } + } + else switch(msg_byte(result)) + { + case COMMAND_COMPLETE: + switch (status_byte(result)) + { + case GOOD: + if (SCpnt->flags & WAS_SENSE) + { +#ifdef DEBUG + printk ("In scsi_done, GOOD status, COMMAND COMPLETE, parsing sense information.\n"); +#endif + + SCpnt->flags &= ~WAS_SENSE; + SCpnt->internal_timeout &= ~SENSE_TIMEOUT; + + switch (checked = check_sense(SCpnt)) + { + case SUGGEST_SENSE: + case 0: +#ifdef DEBUG + printk("NO SENSE. status = REDO\n"); +#endif + + update_timeout(SCpnt, oldto); + status = REDO; + break; + case SUGGEST_IS_OK: + break; + case SUGGEST_REMAP: + case SUGGEST_RETRY: +#ifdef DEBUG + printk("SENSE SUGGEST REMAP or SUGGEST RETRY - status = MAYREDO\n"); +#endif + + status = MAYREDO; + exit = DRIVER_SENSE | SUGGEST_RETRY; + break; + case SUGGEST_ABORT: +#ifdef DEBUG + printk("SENSE SUGGEST ABORT - status = FINISHED"); +#endif + + status = FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + default: + printk ("Internal error %s %d \n", __FILE__, + __LINE__); + } + } + else + { +#ifdef DEBUG + printk("COMMAND COMPLETE message returned, status = FINISHED. \n"); +#endif + + exit = DRIVER_OK; + status = FINISHED; + } + break; + + case CHECK_CONDITION: + switch (check_sense(SCpnt)) + { + case 0: + update_timeout(SCpnt, oldto); + status = REDO; + break; + case SUGGEST_REMAP: + case SUGGEST_RETRY: + status = MAYREDO; + exit = DRIVER_SENSE | SUGGEST_RETRY; + break; + case SUGGEST_ABORT: + status = FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + case SUGGEST_SENSE: + scsi_request_sense (SCpnt); + status = PENDING; + break; + } + break; + + case CONDITION_GOOD: + case INTERMEDIATE_GOOD: + case INTERMEDIATE_C_GOOD: + break; + + case BUSY: + update_timeout(SCpnt, oldto); + status = REDO; + break; + + case RESERVATION_CONFLICT: + printk("scsi%d : RESERVATION CONFLICT performing reset.\n", + SCpnt->host->host_no); + reset(SCpnt); + return; +#if 0 + exit = DRIVER_SOFT | SUGGEST_ABORT; + status = MAYREDO; + break; +#endif + default: + printk ("Internal error %s %d \n" + "status byte = %d \n", __FILE__, + __LINE__, status_byte(result)); + + } + break; + default: + panic("scsi: unsupported message byte %d recieved\n", msg_byte(result)); + } + break; + case DID_TIME_OUT: +#ifdef DEBUG + printk("Host returned DID_TIME_OUT - "); +#endif + + if (SCpnt->flags & WAS_TIMEDOUT) + { +#ifdef DEBUG + printk("Aborting\n"); +#endif + exit = (DRIVER_TIMEOUT | SUGGEST_ABORT); + } + else + { +#ifdef DEBUG + printk ("Retrying.\n"); +#endif + SCpnt->flags |= WAS_TIMEDOUT; + status = REDO; + } + break; + case DID_BUS_BUSY: + case DID_PARITY: + status = REDO; + break; + case DID_NO_CONNECT: +#ifdef DEBUG + printk("Couldn't connect.\n"); +#endif + exit = (DRIVER_HARD | SUGGEST_ABORT); + break; + case DID_ERROR: + status = MAYREDO; + exit = (DRIVER_HARD | SUGGEST_ABORT); + break; + case DID_BAD_TARGET: + case DID_ABORT: + exit = (DRIVER_INVALID | SUGGEST_ABORT); + break; + case DID_RESET: + if(msg_byte(result) == GOOD && + status_byte(result) == CHECK_CONDITION) { + switch (check_sense(SCpnt)) { + case 0: + update_timeout(SCpnt, oldto); + status = REDO; + break; + case SUGGEST_REMAP: + case SUGGEST_RETRY: + status = MAYREDO; + exit = DRIVER_SENSE | SUGGEST_RETRY; + break; + case SUGGEST_ABORT: + status = FINISHED; + exit = DRIVER_SENSE | SUGGEST_ABORT; + break; + case SUGGEST_SENSE: + scsi_request_sense (SCpnt); + status = PENDING; + break; + } + } else { + status=REDO; + exit = SUGGEST_RETRY; + } + break; + default : + exit = (DRIVER_ERROR | SUGGEST_DIE); + } + + switch (status) + { + case FINISHED: + case PENDING: + break; + case MAYREDO: + +#ifdef DEBUG + printk("In MAYREDO, allowing %d retries, have %d\n", + SCpnt->allowed, SCpnt->retries); +#endif + + if ((++SCpnt->retries) < SCpnt->allowed) + { + if ((SCpnt->retries >= (SCpnt->allowed >> 1)) + && !(SCpnt->flags & WAS_RESET)) + { + printk("scsi%d : reseting for second half of retries.\n", + SCpnt->host->host_no); + reset(SCpnt); + break; + } + + } + else + { + status = FINISHED; + break; + } + /* fall through to REDO */ + + case REDO: + if (SCpnt->flags & WAS_SENSE) + scsi_request_sense(SCpnt); + else + { + memcpy ((void *) SCpnt->cmnd, + (void*) SCpnt->data_cmnd, + sizeof(SCpnt->data_cmnd)); + SCpnt->request_buffer = SCpnt->buffer; + SCpnt->request_bufflen = SCpnt->bufflen; + SCpnt->use_sg = SCpnt->old_use_sg; + internal_cmnd (SCpnt); + }; + break; + default: + INTERNAL_ERROR; + } + + if (status == FINISHED) + { + #ifdef DEBUG + printk("Calling done function - at address %08x\n", SCpnt->done); + #endif + 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); + } + + +#undef FINISHED +#undef REDO +#undef MAYREDO +#undef PENDING + } + +/* + The scsi_abort function interfaces with the abort() function of the host + we are aborting, and causes the current command to not complete. The + caller should deal with any error messages or status returned on the + next call. + + This will not be called rentrantly for a given host. +*/ + +/* + Since we're nice guys and specified that abort() and reset() + can be non-reentrant. The internal_timeout flags are used for + this. +*/ + + +int scsi_abort (Scsi_Cmnd * SCpnt, int why) + { + int temp, oldto; + struct Scsi_Host * host = SCpnt->host; + + while(1) + { + cli(); + if (SCpnt->internal_timeout & IN_ABORT) + { + sti(); + while (SCpnt->internal_timeout & IN_ABORT); + } + else + { + SCpnt->internal_timeout |= IN_ABORT; + oldto = update_timeout(SCpnt, ABORT_TIMEOUT); + + + sti(); + if (!host->host_busy || !host->hostt->abort(SCpnt, why)) + temp = 0; + else + temp = 1; + + cli(); + SCpnt->internal_timeout &= ~IN_ABORT; + update_timeout(SCpnt, oldto); + sti(); + return temp; + } + } + } + +int scsi_reset (Scsi_Cmnd * SCpnt) + { + int temp, oldto; + Scsi_Cmnd * SCpnt1; + struct Scsi_Host * host = SCpnt->host; + +#ifdef DEBUG + printk("Danger Will Robinson! - SCSI bus for host %d is being reset.\n",host->host_no); +#endif + while (1) { + cli(); + if (SCpnt->internal_timeout & IN_RESET) + { + sti(); + while (SCpnt->internal_timeout & IN_RESET); + } + else + { + SCpnt->internal_timeout |= IN_RESET; + oldto = update_timeout(SCpnt, RESET_TIMEOUT); + + if (host->host_busy) + { + sti(); + SCpnt1 = host->host_queue; + while(SCpnt1) { + if ((SCpnt1->request.dev > 0) && + !(SCpnt1->flags & IS_RESETTING) && + !(SCpnt1->internal_timeout & IN_ABORT)) + scsi_abort(SCpnt1, DID_RESET); + SCpnt1 = SCpnt1->next; + }; + + temp = host->hostt->reset(SCpnt); + } + else + { + host->host_busy++; + + sti(); + temp = host->hostt->reset(SCpnt); + host->last_reset = jiffies; + host->host_busy--; + } + + cli(); + SCpnt->internal_timeout &= ~IN_RESET; + update_timeout(SCpnt, oldto); + sti(); + return temp; + } + } + } + + +static void scsi_main_timeout(void) + { + /* + We must not enter update_timeout with a timeout condition still pending. + */ + + int timed_out; + struct Scsi_Host * host; + Scsi_Cmnd * SCpnt = NULL; + + do { + cli(); + + /* + Find all timers such that they have 0 or negative (shouldn't happen) + time remaining on them. + */ + + timed_out = 0; + for(host = scsi_hostlist; host; host = host->next) { + SCpnt = host->host_queue; + while (SCpnt){ + if (SCpnt->timeout > 0 && SCpnt->timeout <= time_elapsed) + { + sti(); + SCpnt->timeout = 0; + scsi_times_out(SCpnt); + ++timed_out; + cli(); + } + SCpnt = SCpnt->next; + }; + }; + update_timeout(NULL, 0); + } while (timed_out); + sti(); + } + +/* + The strategy is to cause the timer code to call scsi_times_out() + when the soonest timeout is pending. + The arguments are used when we are queueing a new command, because + we do not want to subtract the time used from this time, but when we + set the timer, we want to take this value into account. +*/ + +static int update_timeout(Scsi_Cmnd * SCset, int timeout) + { + unsigned int least, used; + unsigned int oldto; + struct Scsi_Host * host; + Scsi_Cmnd * SCpnt = NULL; + + cli(); + +/* + Figure out how much time has passed since the last time the timeouts + were updated +*/ + used = (time_start) ? (jiffies - time_start) : 0; + +/* + Find out what is due to timeout soonest, and adjust all timeouts for + the amount of time that has passed since the last time we called + update_timeout. +*/ + + oldto = 0; + + if(SCset){ + oldto = SCset->timeout - used; + SCset->timeout = timeout + used; + }; + + least = 0xffffffff; + + 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; + SCpnt = SCpnt->next; + }; + }; + +/* + If something is due to timeout again, then we will set the next timeout + interrupt to occur. Otherwise, timeouts are disabled. +*/ + + if (least != 0xffffffff) + { + time_start = jiffies; + timer_table[SCSI_TIMER].expires = (time_elapsed = least) + jiffies; + timer_active |= 1 << SCSI_TIMER; + } + else + { + timer_table[SCSI_TIMER].expires = time_start = time_elapsed = 0; + timer_active &= ~(1 << SCSI_TIMER); + } + sti(); + return oldto; + } + + +static unsigned short * dma_malloc_freelist = NULL; +static unsigned int dma_sectors = 0; +unsigned int dma_free_sectors = 0; +unsigned int need_isa_buffer = 0; +static unsigned char * dma_malloc_buffer = NULL; + +void *scsi_malloc(unsigned int len) +{ + unsigned int nbits, mask; + int i, j; + if((len & 0x1ff) || len > 4096) + panic("Inappropriate buffer size requested"); + + cli(); + nbits = len >> 9; + mask = (1 << nbits) - 1; + + for(i=0;i < (dma_sectors >> 4); i++) + for(j=0; j<17-nbits; j++){ + if ((dma_malloc_freelist[i] & (mask << j)) == 0){ + dma_malloc_freelist[i] |= (mask << j); + sti(); + dma_free_sectors -= nbits; +#ifdef DEBUG + printk("SMalloc: %d %x ",len, dma_malloc_buffer + (i << 13) + (j << 9)); +#endif + return (void *) ((unsigned long) dma_malloc_buffer + (i << 13) + (j << 9)); + }; + }; + sti(); + return NULL; /* Nope. No more */ +} + +int scsi_free(void *obj, unsigned int len) +{ + int offset; + int page, sector, nbits, mask; + +#ifdef DEBUG + printk("Sfree %x %d\n",obj, len); +#endif + + offset = ((int) obj) - ((int) dma_malloc_buffer); + + if (offset < 0) panic("Bad offset"); + page = offset >> 13; + sector = offset >> 9; + if(sector >= dma_sectors) panic ("Bad page"); + + sector = (offset >> 9) & 15; + nbits = len >> 9; + mask = (1 << nbits) - 1; + + if ((mask << sector) > 0xffff) panic ("Bad memory alignment"); + + cli(); + if(dma_malloc_freelist[page] & (mask << sector) != (mask<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; + SCpnt->request.dev = -1; /* Mark not busy */ + SCpnt->use_sg = 0; + SCpnt->old_use_sg = 0; + SCpnt->underflow = 0; + SCpnt->transfersize = 0; + SCpnt->host_scribble = NULL; + host = scsi_devices[i].host; + if(host->host_queue) + host->host_queue->prev = SCpnt; + SCpnt->next = host->host_queue; + SCpnt->prev = NULL; + host->host_queue = SCpnt; + SCpnt++; + }; + }; + }; + + memory_start = (int) SCpnt; + + if (NR_SD > 0 || NR_SR > 0 || NR_ST > 0) + dma_sectors = 16; /* Base value we use */ + + for (i = 0; i < NR_SCSI_DEVICES; ++i) { + struct Scsi_Host * host; + host = scsi_devices[i].host; + + if(scsi_devices[i].type != TYPE_TAPE) + dma_sectors += ((host->sg_tablesize * + sizeof(struct scatterlist) + 511) >> 9) * + host->hostt->cmd_per_lun; + + if(host->unchecked_isa_dma && + memory_end > ISA_DMA_THRESHOLD && + scsi_devices[i].type != TYPE_TAPE) { + dma_sectors += (PAGE_SIZE >> 9) * host->sg_tablesize * + host->hostt->cmd_per_lun; + need_isa_buffer++; + }; + }; + + dma_sectors = (dma_sectors + 15) & 0xfff0; + dma_free_sectors = dma_sectors; /* This must be a multiple of 16 */ + + memory_start = (memory_start + 3) & 0xfffffffc; + dma_malloc_freelist = (unsigned short *) memory_start; + memory_start += dma_sectors >> 3; + memset(dma_malloc_freelist, 0, dma_sectors >> 3); + + if(memory_start & 1) memory_start++; /* Some host adapters require + buffers to be word aligned */ + dma_malloc_buffer = (unsigned char *) memory_start; + memory_start += dma_sectors << 9; + + 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); /* init scsi CDROMs */ + memory_start = sg_init(memory_start, memory_end); /* init scsi generic */ + + return memory_start; + } + +static void print_inquiry(unsigned char *data) +{ + int i; + + printk(" Vendor: "); + for (i = 8; i < 16; i++) + { + if (data[i] >= 0x20 && i < data[4] + 5) + printk("%c", data[i]); + else + printk(" "); + } + + printk(" Model: "); + for (i = 16; i < 32; i++) + { + if (data[i] >= 0x20 && i < data[4] + 5) + printk("%c", data[i]); + else + printk(" "); + } + + printk(" Rev: "); + for (i = 32; i < 36; i++) + { + if (data[i] >= 0x20 && i < data[4] + 5) + printk("%c", data[i]); + else + printk(" "); + } + + printk("\n"); + + i = data[0] & 0x1f; + + 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"); + else + printk("\n"); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.h new file mode 100644 index 000000000..381b86bbe --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi.h @@ -0,0 +1,531 @@ +/* + * scsi.h Copyright (C) 1992 Drew Eckhardt + * generic SCSI package header file by + * Drew Eckhardt + * + * + * + * Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#ifndef _SCSI_H +#define _SCSI_H + +/* + $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. + +*/ + +/* + SCSI opcodes +*/ + +#define TEST_UNIT_READY 0x00 +#define REZERO_UNIT 0x01 +#define REQUEST_SENSE 0x03 +#define FORMAT_UNIT 0x04 +#define READ_BLOCK_LIMITS 0x05 +#define REASSIGN_BLOCKS 0x07 +#define READ_6 0x08 +#define WRITE_6 0x0a +#define SEEK_6 0x0b +#define READ_REVERSE 0x0f +#define WRITE_FILEMARKS 0x10 +#define SPACE 0x11 +#define INQUIRY 0x12 +#define RECOVER_BUFFERED_DATA 0x14 +#define MODE_SELECT 0x15 +#define RESERVE 0x16 +#define RELEASE 0x17 +#define COPY 0x18 +#define ERASE 0x19 +#define MODE_SENSE 0x1a +#define START_STOP 0x1b +#define RECEIVE_DIAGNOSTIC 0x1c +#define SEND_DIAGNOSTIC 0x1d +#define ALLOW_MEDIUM_REMOVAL 0x1e + +#define READ_CAPACITY 0x25 +#define READ_10 0x28 +#define WRITE_10 0x2a +#define SEEK_10 0x2b +#define WRITE_VERIFY 0x2e +#define VERIFY 0x2f +#define SEARCH_HIGH 0x30 +#define SEARCH_EQUAL 0x31 +#define SEARCH_LOW 0x32 +#define SET_LIMITS 0x33 +#define PRE_FETCH 0x34 +#define READ_POSITION 0x34 +#define SYNCRONIZE_CACHE 0x35 +#define LOCK_UNLOCK_CACHE 0x36 +#define READ_DEFECT_DATA 0x37 +#define COMPARE 0x39 +#define COPY_VERIFY 0x3a +#define WRITE_BUFFER 0x3b +#define READ_BUFFER 0x3c +#define READ_LONG 0x3e +#define CHANGE_DEFINITION 0x40 +#define LOG_SELECT 0x4c +#define LOG_SENSE 0x4d +#define MODE_SELECT_10 0x55 +#define MODE_SENSE_10 0x5a + +extern const unsigned char scsi_command_size[8]; +#define COMMAND_SIZE(opcode) scsi_command_size[((opcode) >> 5) & 7] + +/* + MESSAGE CODES +*/ + +#define COMMAND_COMPLETE 0x00 +#define EXTENDED_MESSAGE 0x01 +#define SAVE_POINTERS 0x02 +#define RESTORE_POINTERS 0x03 +#define DISCONNECT 0x04 +#define INITIATOR_ERROR 0x05 +#define ABORT 0x06 +#define MESSAGE_REJECT 0x07 +#define NOP 0x08 +#define MSG_PARITY_ERROR 0x09 +#define LINKED_CMD_COMPLETE 0x0a +#define LINKED_FLG_CMD_COMPLETE 0x0b +#define BUS_DEVICE_RESET 0x0c + +#define 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) |\ + ((lun) & 0x07)) + + +/* + Status codes +*/ + +#define GOOD 0x00 +#define CHECK_CONDITION 0x01 +#define CONDITION_GOOD 0x02 +#define BUSY 0x04 +#define INTERMEDIATE_GOOD 0x08 +#define INTERMEDIATE_C_GOOD 0x0a +#define RESERVATION_CONFLICT 0x0c + +#define STATUS_MASK 0x1e + +/* + the return of the status word will be in the following format : + The low byte is the status returned by the SCSI command, + with vendor specific bits masked. + + The next byte is the message which followed the SCSI status. + This allows a stos to be used, since the Intel is a little + endian machine. + + The final byte is a host return code, which is one of the following. + + IE + lsb msb + status msg host code + + Our errors returned by OUR driver, NOT SCSI message. Orr'd with + SCSI message passed back to driver . +*/ + +/* NO error */ +#define DID_OK 0x00 +/* Couldn't connect before timeout period */ +#define DID_NO_CONNECT 0x01 +/* BUS stayed busy through time out period */ +#define DID_BUS_BUSY 0x02 +/* TIMED OUT for other reason */ +#define DID_TIME_OUT 0x03 +/* BAD target. */ +#define DID_BAD_TARGET 0x04 +/* Told to abort for some other reason */ +#define DID_ABORT 0x05 +/* + Parity error +*/ +#define DID_PARITY 0x06 +/* + Internal error +*/ +#define DID_ERROR 0x07 +/* + Reset by somebody. +*/ +#define DID_RESET 0x08 +/* + Got an interrupt we weren't expecting. +*/ +#define DID_BAD_INTR 0x09 + +/* + Driver status +*/ +#define DRIVER_OK 0x00 + +/* + These indicate the error that occured, and what is available. +*/ + +#define DRIVER_BUSY 0x01 +#define DRIVER_SOFT 0x02 +#define DRIVER_MEDIA 0x03 +#define DRIVER_ERROR 0x04 + +#define DRIVER_INVALID 0x05 +#define DRIVER_TIMEOUT 0x06 +#define DRIVER_HARD 0x07 + +#define SUGGEST_RETRY 0x10 +#define SUGGEST_ABORT 0x20 +#define SUGGEST_REMAP 0x30 +#define SUGGEST_DIE 0x40 +#define SUGGEST_SENSE 0x80 +#define SUGGEST_IS_OK 0xff + +#define DRIVER_SENSE 0x08 + +#define DRIVER_MASK 0x0f +#define SUGGEST_MASK 0xf0 + +/* + + SENSE KEYS +*/ + +#define NO_SENSE 0x00 +#define RECOVERED_ERROR 0x01 +#define NOT_READY 0x02 +#define MEDIUM_ERROR 0x03 +#define HARDWARE_ERROR 0x04 +#define ILLEGAL_REQUEST 0x05 +#define UNIT_ATTENTION 0x06 +#define DATA_PROTECT 0x07 +#define BLANK_CHECK 0x08 +#define COPY_ABORTED 0x0a +#define ABORTED_COMMAND 0x0b +#define VOLUME_OVERFLOW 0x0d +#define MISCOMPARE 0x0e + + +/* + DEVICE TYPES + +*/ + +#define TYPE_DISK 0x00 +#define TYPE_TAPE 0x01 +#define TYPE_WORM 0x04 /* Treated as ROM by our system */ +#define TYPE_ROM 0x05 +#define TYPE_MOD 0x07 /* Magneto-optical disk - treated as TYPE_DISK */ +#define TYPE_NO_LUN 0x7f + + +#define MAX_COMMAND_SIZE 12 +/* + SCSI command sets + +*/ + +#define SCSI_UNKNOWN 0 +#define SCSI_1 1 +#define SCSI_1_CCS 2 +#define SCSI_2 3 + +/* + Every SCSI command starts with a one byte OP-code. + The next byte's high three bits are the LUN of the + device. Any multi-byte quantities are stored high byte + first, and may have a 5 bit MSB in the same byte + as the LUN. +*/ + + +/* + The scsi_device struct contains what we know about each given scsi + device. +*/ + +typedef struct scsi_device { + unsigned char 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; + unsigned removable:1; + unsigned random:1; + unsigned changed:1; /* Data invalid due to media change */ + unsigned busy:1; /* Used to prevent races */ + 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 +*/ + +#define status_byte(result) (((result) >> 1) & 0xf) +#define msg_byte(result) (((result) >> 8) & 0xff) +#define host_byte(result) (((result) >> 16) & 0xff) +#define driver_byte(result) (((result) >> 24) & 0xff) +#define sugestion(result) (driver_byte(result) & SUGGEST_MASK) + +#define sense_class(sense) (((sense) >> 4) & 0x7) +#define sense_error(sense) ((sense) & 0xf) +#define sense_valid(sense) ((sense) & 0x80); + +/* + These are the SCSI devices available on the system. +*/ + +extern int NR_SCSI_DEVICES; +extern Scsi_Device * scsi_devices; +/* + Initializes all SCSI devices. This scans all scsi busses. +*/ + +extern unsigned long scsi_dev_init (unsigned long, unsigned long); + +struct scatterlist { + char * address; /* Location data is to be transferred to */ + char * alt_address; /* Location of actual if address is a + dma indirect buffer. NULL otherwise */ + unsigned short length; + }; + +#define ISA_DMA_THRESHOLD (0x00ffffff) + +void * scsi_malloc(unsigned int); +int scsi_free(void *, unsigned int); +extern unsigned int dma_free_sectors; /* How much room do we have left */ +extern unsigned int need_isa_buffer; /* True if some devices need indirection + buffers */ + +/* + The Scsi_Cmnd structure is used by scsi.c internally, and for communication with + low level drivers that support multiple outstanding commands. +*/ +typedef struct scsi_pointer { + char * ptr; /* data pointer */ + int this_residual; /* left in this buffer */ + struct scatterlist *buffer; /* which buffer */ + int buffers_residual; /* how many buffers left */ + + volatile int Status; + volatile int Message; + volatile int have_data_in; + volatile int sent_command; + volatile int phase; +} Scsi_Pointer; + +typedef struct scsi_cmnd { + 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[12]; + unsigned request_bufflen; /* Actual request size */ + + void * request_buffer; /* Actual requested buffer */ + +/* These elements define the operation we ultimately want to perform */ + unsigned char data_cmnd[12]; + unsigned short old_use_sg; /* We save use_sg here when requesting + sense info */ + unsigned short use_sg; /* Number of pieces of scatter-gather */ + unsigned short sglist_len; /* size of malloc'd scatter-gather list */ + unsigned bufflen; /* Size of data buffer */ + void *buffer; /* Data buffer */ + + unsigned underflow; /* Return error if less than this amount is + transfered */ + + unsigned transfersize; /* How much we are guranteed to transfer with + each SCSI transfer (ie, between disconnect / + reconnects. Probably == sector size */ + + + + struct request request; /* A copy of the command we are working on*/ + + unsigned char sense_buffer[16]; /* Sense for this command, if needed*/ + + + int retries; + int allowed; + int timeout_per_command, timeout_total, timeout; +/* + * We handle the timeout differently if it happens when a reset, + * abort, etc are in process. + */ + + unsigned volatile char internal_timeout; + + unsigned flags; + +/* These variables are for the cdrom only. Once we have variable size buffers + in the buffer cache, they will go away. */ + int this_count; +/* End of special cdrom variables */ + + /* Low-level done function - can be used by low-level driver to point + to completion function. Not used by mid/upper level code. */ + void (*scsi_done)(struct scsi_cmnd *); + + void (*done)(struct scsi_cmnd *); /* Mid-level done function */ + +/* The following fields can be written to by the host specific code. + Everything else should be left alone. */ + + Scsi_Pointer SCp; /* Scratchpad used by some host adapters */ + + unsigned char * host_scribble; /* The host adapter is allowed to + call scsi_malloc and get some memory + and hang it here. The host adapter + is also expected to call scsi_free + to release this memory. (The memory + obtained by scsi_malloc is guaranteed + to be at an address < 16Mb). */ + + int result; /* Status code from lower level driver */ + + unsigned char tag; /* SCSI-II queued command tag */ + } Scsi_Cmnd; + +/* + scsi_abort aborts the current command that is executing on host host. + The error code, if non zero is returned in the host byte, otherwise + DID_ABORT is returned in the hostbyte. +*/ + +extern int scsi_abort (Scsi_Cmnd *, int code); + +extern void scsi_do_cmd (Scsi_Cmnd *, const void *cmnd , + void *buffer, unsigned bufflen, void (*done)(struct scsi_cmnd *), + int timeout, int retries); + + +extern Scsi_Cmnd * allocate_device(struct request **, int, int); + +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, 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 *); + +extern unsigned long sr_init(unsigned long, unsigned long); +extern unsigned long sr_init1(unsigned long, unsigned long); +extern void sr_attach(Scsi_Device *); + +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 != SCSI_TAPE_MAJOR) +static void end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors) +{ + struct request * req; + struct buffer_head * bh; + struct task_struct * p; + + req = &SCpnt->request; + req->errors = 0; + if (!uptodate) { + printk(DEVICE_NAME " I/O error: dev %04x, sector %lu\n", + req->dev,req->sector); + } + + do { + if ((bh = req->bh) != NULL) { + req->bh = bh->b_reqnext; + req->nr_sectors -= bh->b_size >> 9; + req->sector += bh->b_size >> 9; + bh->b_reqnext = NULL; + bh->b_uptodate = uptodate; + unlock_buffer(bh); + sectors -= bh->b_size >> 9; + if ((bh = req->bh) != NULL) { + req->current_nr_sectors = bh->b_size >> 9; + if (req->nr_sectors < req->current_nr_sectors) { + req->nr_sectors = req->current_nr_sectors; + printk("end_scsi_request: buffer-list destroyed\n"); + } + } + } + } while(sectors && bh); + if (req->bh){ + req->buffer = bh->b_data; + return; + }; + DEVICE_OFF(req->dev); + if ((p = req->waiting) != NULL) { + req->waiting = NULL; + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } + req->dev = -1; + wake_up(&scsi_devices[SCpnt->index].device_wait); + return; +} + + +/* This is just like INIT_REQUEST, but we need to be aware of the fact + that an interrupt may start another request, so we run this with interrupts + turned off */ + +#define INIT_SCSI_REQUEST \ + if (!CURRENT) {\ + CLEAR_INTR; \ + sti(); \ + return; \ + } \ + if (MAJOR(CURRENT->dev) != MAJOR_NR) \ + panic(DEVICE_NAME ": request list destroyed"); \ + if (CURRENT->bh) { \ + if (!CURRENT->bh->b_lock) \ + panic(DEVICE_NAME ": block not locked"); \ + } +#endif + +#define SCSI_SLEEP(QUEUE, CONDITION) { \ + if (CONDITION) { \ + struct wait_queue wait = { current, NULL}; \ + add_wait_queue(QUEUE, &wait); \ +sleep_repeat: \ + current->state = TASK_UNINTERRUPTIBLE; \ + if (CONDITION) { \ + schedule(); \ + goto sleep_repeat; \ + } \ + remove_wait_queue(QUEUE, &wait); \ + current->state = TASK_RUNNING; \ + }; } + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.c new file mode 100644 index 000000000..4fe973e75 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.c @@ -0,0 +1,515 @@ +/* $Id: scsi_debug.c,v 1.1 1992/07/24 06:27:38 root Exp root $ + * linux/kernel/scsi_debug.c + * + * Copyright (C) 1992 Eric Youngdale + * Simulate a host adapter with 2 disks attached. Do a lot of checking + * to make sure that we are not getting blocks mixed up, and panic if + * anything out of the ordinary is seen. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" + +/* Number of real scsi disks that will be detected ahead of time */ +static int NR_REAL=-1; + +#define MAJOR_NR SCSI_DISK_MAJOR +#define START_PARTITION 4 +#define SCSI_DEBUG_TIMER 20 +/* Number of jiffies to wait before completing a command */ +#define DISK_SPEED 10 +#define CAPACITY (0x80000) + +static int starts[] = {4, 1000, 50000, CAPACITY, 0}; +static int npart = 0; + +#include "scsi_debug.h" +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + +#define VERIFY1_DEBUG(RW) \ + if (bufflen != 1024) {printk("%d", bufflen); panic("(1)Bad bufflen");}; \ + start = 0; \ + if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1]; \ + if (bh){ \ + if (bh->b_size != 1024) panic ("Wrong bh size"); \ + if ((bh->b_blocknr << 1) + start != block) \ + { printk("Wrong bh block# %d %d ",bh->b_blocknr, block); \ + panic ("Wrong bh block#");}; \ + if (bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\ + }; + +#if 0 +/* This had been in the VERIFY_DEBUG macro, but it fails if there is already + a disk on the system */ + if ((SCpnt->request.dev & 0xfff0) != ((target + NR_REAL) << 4) +(MAJOR_NR << 8)){ \ + printk("Dev #s %x %x ",SCpnt->request.dev, target); \ + panic ("Bad target");}; \ + +#endif + +#define VERIFY_DEBUG(RW) \ + if (bufflen != 1024 && (!SCpnt->use_sg)) {printk("%x %d\n ",bufflen, SCpnt->use_sg); panic("Bad bufflen");}; \ + start = 0; \ + if ((SCpnt->request.dev & 0xf) > npart) panic ("Bad partition"); \ + if ((SCpnt->request.dev & 0xf) != 0) start = starts[(SCpnt->request.dev & 0xf) - 1]; \ + if (SCpnt->request.cmd != RW) panic ("Wrong operation"); \ + if (SCpnt->request.sector + start != block) panic("Wrong block."); \ + if (SCpnt->request.current_nr_sectors != 2 && (!SCpnt->use_sg)) panic ("Wrong # blocks"); \ + if (SCpnt->request.bh){ \ + if (SCpnt->request.bh->b_size != 1024) panic ("Wrong bh size"); \ + if ((SCpnt->request.bh->b_blocknr << 1) + start != block) \ + { printk("Wrong bh block# %d %d ",SCpnt->request.bh->b_blocknr, block); \ + panic ("Wrong bh block#");}; \ + if (SCpnt->request.bh->b_dev != SCpnt->request.dev) panic ("Bad bh target");\ + }; + +static volatile void (*do_done[SCSI_DEBUG_MAILBOXES])(Scsi_Cmnd *) = {NULL, }; +static int scsi_debug_host = 0; +extern void scsi_debug_interrupt(); + +volatile Scsi_Cmnd * SCint[SCSI_DEBUG_MAILBOXES] = {NULL,}; +static volatile unsigned int timeout[SCSI_DEBUG_MAILBOXES] ={0,}; + +static char sense_buffer[128] = {0,}; + +static void scsi_dump(Scsi_Cmnd * SCpnt, int flag){ + int i; +#if 0 + unsigned char * pnt; +#endif + unsigned int * lpnt; + struct scatterlist * sgpnt = NULL; + printk("use_sg: %d",SCpnt->use_sg); + if (SCpnt->use_sg){ + sgpnt = (struct scatterlist *) SCpnt->buffer; + for(i=0; iuse_sg; i++) { + lpnt = (int *) sgpnt[i].alt_address; + printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); + if (lpnt) printk(" (Alt %x) ",lpnt[15]); + }; + } else { + printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); + lpnt = (int *) SCpnt->request.buffer; + if (lpnt) printk(" (Alt %x) ",lpnt[15]); + }; + lpnt = (unsigned int *) SCpnt; + for (i=0;icmnd; + struct partition * p; + int block, start; + struct buffer_head * bh = NULL; + unsigned char * buff; + int nbytes, sgcount; + int scsi_debug_errsts; + struct scatterlist * sgpnt; + int target = SCpnt->target; + int bufflen = SCpnt->request_bufflen; + int i; + sgcount = 0; + sgpnt = NULL; + + DEB(if (target > 1) { SCpnt->result = DID_TIME_OUT << 16;done(SCpnt);return 0;}); + + buff = (unsigned char *) SCpnt->request_buffer; + + if(target>=2 || SCpnt->lun != 0) { + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + }; + + switch(*cmd){ + case REQUEST_SENSE: + printk("Request sense...\n"); +#ifndef DEBUG + { int i; + printk("scsi_debug: Requesting sense buffer (%x %x %x %d):", SCpnt, buff, done, bufflen); + for(i=0;i<12;i++) printk("%d ",sense_buffer[i]); + printk("\n"); + }; +#endif + memset(buff, 0, bufflen); + memcpy(buff, sense_buffer, bufflen); + memset(sense_buffer, 0, sizeof(sense_buffer)); + SCpnt->result = 0; + done(SCpnt); + return 0; + case ALLOW_MEDIUM_REMOVAL: + if(cmd[4]) printk("Medium removal inhibited..."); + else printk("Medium removal enabled..."); + scsi_debug_errsts = 0; + break; + case INQUIRY: + printk("Inquiry...(%x %d)\n", buff, bufflen); + memset(buff, 0, bufflen); + buff[0] = TYPE_DISK; + buff[1] = 0x80; /* Removable disk */ + buff[2] = 1; + memcpy(&buff[8],"Foo Inc",7); + memcpy(&buff[16],"XYZZY",5); + memcpy(&buff[32],"1",1); + scsi_debug_errsts = 0; + break; + case TEST_UNIT_READY: + printk("Test unit ready.\n"); + if (buff) + memset(buff, 0, bufflen); + scsi_debug_errsts = 0; + break; + case READ_CAPACITY: + printk("Read Capacity\n"); + if(NR_REAL < 0) NR_REAL = (SCpnt->request.dev >> 4) & 0x0f; + memset(buff, 0, bufflen); + buff[0] = (CAPACITY >> 24); + buff[1] = (CAPACITY >> 16) & 0xff; + buff[2] = (CAPACITY >> 8) & 0xff; + buff[3] = CAPACITY & 0xff; + buff[6] = 2; /* 512 byte sectors */ + scsi_debug_errsts = 0; + break; + case READ_10: + case READ_6: +#ifdef DEBUG + printk("Read..."); +#endif + if ((*cmd) == READ_10) + block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + else + block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + VERIFY_DEBUG(READ); + printk("(r%d)",SCpnt->request.nr_sectors); + nbytes = bufflen; + if(SCpnt->use_sg){ + sgcount = 0; + sgpnt = (struct scatterlist *) buff; + buff = sgpnt[sgcount].address; + bufflen = sgpnt[sgcount].length; + bh = SCpnt->request.bh; + }; + scsi_debug_errsts = 0; + do{ + VERIFY1_DEBUG(READ); + memset(buff, 0, bufflen); +/* If this is block 0, then we want to read the partition table for this + device. Let's make one up */ + if(block == 0 && target == 0) { + *((unsigned short *) (buff+510)) = 0xAA55; + p = (struct partition* ) (buff + 0x1be); + npart = 0; + while(starts[npart+1]){ + p->start_sect = starts[npart]; + p->nr_sects = starts[npart+1] - starts [npart]; + p->sys_ind = 0x81; /* Linux partition */ + p++; + npart++; + }; + scsi_debug_errsts = 0; + break; + }; +#ifdef DEBUG + if (SCpnt->use_sg) printk("Block %x (%d %d)\n",block, SCpnt->request.nr_sectors, + SCpnt->request.current_nr_sectors); +#endif + /* Simulate a disk change */ + if(block == 0xfff0) { + sense_buffer[0] = 0x70; + sense_buffer[2] = UNIT_ATTENTION; + starts[0] += 10; + starts[1] += 10; + starts[2] += 10; + +#ifdef DEBUG + { int i; + printk("scsi_debug: Filling sense buffer:"); + for(i=0;i<12;i++) printk("%d ",sense_buffer[i]); + printk("\n"); + }; +#endif + scsi_debug_errsts = (COMMAND_COMPLETE << 8) | (CHECK_CONDITION << 1); + break; + } /* End phony disk change code */ + memset(buff, 0, bufflen); + memcpy(buff, &target, sizeof(target)); + memcpy(buff+sizeof(target), cmd, 24); + memcpy(buff+60, &block, sizeof(block)); + memcpy(buff+64, SCpnt, sizeof(Scsi_Cmnd)); + nbytes -= bufflen; + if(SCpnt->use_sg){ + memcpy(buff+128, bh, sizeof(struct buffer_head)); + block += bufflen >> 9; + bh = bh->b_reqnext; + sgcount++; + if (nbytes) { + if(!bh) panic("Too few blocks for linked request."); + buff = sgpnt[sgcount].address; + bufflen = sgpnt[sgcount].length; + }; + } + } while(nbytes); + if (SCpnt->use_sg && !scsi_debug_errsts) + if(bh) scsi_dump(SCpnt, 0); + break; + case WRITE_10: + case WRITE_6: +#ifdef DEBUG + printk("Write\n"); +#endif + if ((*cmd) == WRITE_10) + block = cmd[5] + (cmd[4] << 8) + (cmd[3] << 16) + (cmd[2] << 24); + else + block = cmd[3] + (cmd[2] << 8) + ((cmd[1] & 0x1f) << 16); + VERIFY_DEBUG(WRITE); + printk("(w%d)",SCpnt->request.nr_sectors); + if (SCpnt->use_sg){ + if ((bufflen >> 9) != SCpnt->request.nr_sectors) + panic ("Trying to write wrong number of blocks\n"); + sgpnt = (struct scatterlist *) buff; + buff = sgpnt[sgcount].address; + }; +#if 0 + if (block != *((unsigned long *) (buff+60))) { + printk("%x %x :",block, *((unsigned long *) (buff+60))); + scsi_dump(SCpnt,1); + panic("Bad block written.\n"); + }; +#endif + scsi_debug_errsts = 0; + break; + default: + printk("Unknown command %d\n",*cmd); + SCpnt->result = DID_NO_CONNECT << 16; + done(SCpnt); + return 0; + }; + + cli(); + for(i=0;i= SCSI_DEBUG_MAILBOXES || SCint[i] != 0) + panic("Unable to find empty SCSI_DEBUG command slot.\n"); + + SCint[i] = SCpnt; + + if (done) { + DEB(printk("scsi_debug_queuecommand: now waiting for interrupt ");); + if (do_done[i]) + printk("scsi_debug_queuecommand: Two concurrent queuecommand?\n"); + else + do_done[i] = done; + } + else + printk("scsi_debug_queuecommand: done cant be NULL\n"); + + timeout[i] = jiffies+DISK_SPEED; + +/* If no timers active, then set this one */ + if ((timer_active & (1 << SCSI_DEBUG_TIMER)) == 0) { + timer_table[SCSI_DEBUG_TIMER].expires = timeout[i]; + timer_active |= 1 << SCSI_DEBUG_TIMER; + }; + + SCpnt->result = scsi_debug_errsts; + sti(); + +#if 0 + printk("Sending command (%d %x %d %d)...", i, done, timeout[i],jiffies); +#endif + + return 0; +} + +volatile static int internal_done_flag = 0; +volatile static int internal_done_errcode = 0; +static void internal_done(Scsi_Cmnd * SCpnt) +{ + internal_done_errcode = SCpnt->result; + ++internal_done_flag; +} + +int scsi_debug_command(Scsi_Cmnd * SCpnt) +{ + DEB(printk("scsi_debug_command: ..calling scsi_debug_queuecommand\n")); + scsi_debug_queuecommand(SCpnt, internal_done); + + while (!internal_done_flag); + internal_done_flag = 0; + return internal_done_errcode; +} + +/* A "high" level interrupt handler. This should be called once per jiffy + to simulate a regular scsi disk. We use a timer to do this. */ + +static void scsi_debug_intr_handle(void) +{ + Scsi_Cmnd * SCtmp; + int i, pending; + void (*my_done)(Scsi_Cmnd *); + int to; + + timer_table[SCSI_DEBUG_TIMER].expires = 0; + timer_active &= ~(1 << SCSI_DEBUG_TIMER); + + repeat: + cli(); + for(i=0;i jiffies) { + if (pending > timeout[i]) pending = timeout[i]; + continue; + }; + }; + if (pending && pending != INT_MAX) { + timer_table[SCSI_DEBUG_TIMER].expires = + (pending <= jiffies ? jiffies+1 : pending); + timer_active |= 1 << SCSI_DEBUG_TIMER; + }; + sti(); + return; + }; + + if(i < SCSI_DEBUG_MAILBOXES){ + timeout[i] = 0; + my_done = do_done[i]; + do_done[i] = NULL; + to = timeout[i]; + timeout[i] = 0; + SCtmp = (Scsi_Cmnd *) SCint[i]; + SCint[i] = NULL; + sti(); + + if (!my_done) { + printk("scsi_debug_intr_handle: Unexpected interrupt\n"); + return; + } + +#ifdef DEBUG + printk("In intr_handle..."); + printk("...done %d %x %d %d\n",i , my_done, to, jiffies); + printk("In intr_handle: %d %x %x\n",i, SCtmp, my_done); +#endif + + my_done(SCtmp); +#ifdef DEBUG + printk("Called done.\n"); +#endif + }; + goto repeat; +} + + +int scsi_debug_detect(int hostnum) +{ + scsi_debug_host = hostnum; + timer_table[SCSI_DEBUG_TIMER].fn = scsi_debug_intr_handle; + timer_table[SCSI_DEBUG_TIMER].expires = 0; + return 1; +} + +int scsi_debug_abort(Scsi_Cmnd * SCpnt,int i) +{ + int j; + void (*my_done)(Scsi_Cmnd *); + DEB(printk("scsi_debug_abort\n")); + SCpnt->result = i << 16; + for(j=0;j> 11; + if (info[2] >= 1024) info[2] = 1024; + return 0; +} + +int scsi_debug_reset(Scsi_Cmnd * SCpnt) +{ + int i; + void (*my_done)(Scsi_Cmnd *); + DEB(printk("scsi_debug_reset called\n")); + for(i=0;iresult = DID_ABORT << 16; + my_done = do_done[i]; + my_done(SCint[i]); + cli(); + SCint[i] = NULL; + do_done[i] = NULL; + timeout[i] = 0; + sti(); + }; + return 0; +} + +char *scsi_debug_info(void) +{ + static char buffer[] = " "; /* looks nicer without anything here */ + return buffer; +} + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.h new file mode 100644 index 000000000..725b37e94 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_debug.h @@ -0,0 +1,27 @@ +#ifndef _SCSI_DEBUG_H + +#include + +int scsi_debug_detect(int); +int scsi_debug_command(Scsi_Cmnd *); +int scsi_debug_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int scsi_debug_abort(Scsi_Cmnd *, int); +int scsi_debug_biosparam(int, int*); +char *scsi_debug_info(void); +int scsi_debug_reset(Scsi_Cmnd *); + +#ifndef NULL + #define NULL 0 +#endif + +#define SCSI_DEBUG_MAILBOXES 8 + +#define SCSI_DEBUG {"SCSI DEBUG", scsi_debug_detect, \ + scsi_debug_info, scsi_debug_command, \ + scsi_debug_queuecommand, \ + scsi_debug_abort, \ + scsi_debug_reset, \ + NULL, \ + scsi_debug_biosparam, \ + SCSI_DEBUG_MAILBOXES, 7, SG_ALL, 1, 0, 1} +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.c new file mode 100644 index 000000000..a5ea18349 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.c @@ -0,0 +1,305 @@ +#include +#include +#include + +#include +#include +#include +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "scsi_ioctl.h" + +#define MAX_RETRIES 5 +#define MAX_TIMEOUT 200 +#define MAX_BUF 4096 + +#define max(a,b) (((a) > (b)) ? (a) : (b)) + +/* + * If we are told to probe a host, we will return 0 if the host is not + * present, 1 if the host is present, and will return an identifying + * string at *arg, if arg is non null, filling to the length stored at + * (int *) arg + */ + +static int ioctl_probe(struct Scsi_Host * host, void *buffer) +{ + int temp; + unsigned int len,slen; + const char * string; + + if ((temp = host->hostt->present) && buffer) { + len = get_fs_long ((unsigned long *) buffer); + string = host->hostt->info(); + slen = strlen(string); + if (len > slen) + len = slen + 1; + verify_area(VERIFY_WRITE, buffer, len); + memcpy_tofs (buffer, string, len); + } + return temp; +} + +/* + * + * The SCSI_IOCTL_SEND_COMMAND ioctl sends a command out to the SCSI host. + * The MAX_TIMEOUT and MAX_RETRIES variables are used. + * + * dev is the SCSI device struct ptr, *(int *) arg is the length of the + * input data, if any, not including the command string & counts, + * *((int *)arg + 1) is the output buffer size in bytes. + * + * *(char *) ((int *) arg)[2] the actual command byte. + * + * Note that no more than MAX_BUF data bytes will be transfered. Since + * SCSI block device size is 512 bytes, I figured 1K was good. + * but (WDE) changed it to 8192 to handle large bad track buffers. + * ERY: I changed this to a dynamic allocation using scsi_malloc - we were + * getting a kernel stack overflow which was crashing the system when we + * were using 8192 bytes. + * + * This size *does not* include the initial lengths that were passed. + * + * The SCSI command is read from the memory location immediately after the + * length words, and the input data is right after the command. The SCSI + * routines know the command size based on the opcode decode. + * + * The output area is then filled in starting from the command byte. + */ + +static void scsi_ioctl_done (Scsi_Cmnd * SCpnt) +{ + struct request * req; + struct task_struct * p; + + req = &SCpnt->request; + req->dev = 0xfffe; /* Busy, but indicate request done */ + + if ((p = req->waiting) != NULL) { + req->waiting = NULL; + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } +} + +static int ioctl_internal_command(Scsi_Device *dev, char * cmd) +{ + int result; + Scsi_Cmnd * SCpnt; + + SCpnt = allocate_device(NULL, dev->index, 1); + scsi_do_cmd(SCpnt, cmd, NULL, 0, + scsi_ioctl_done, MAX_TIMEOUT, + MAX_RETRIES); + + if (SCpnt->request.dev != 0xfffe){ + SCpnt->request.waiting = current; + current->state = TASK_UNINTERRUPTIBLE; + while (SCpnt->request.dev != 0xfffe) schedule(); + }; + + if(driver_byte(SCpnt->result) != 0) + switch(SCpnt->sense_buffer[2] & 0xf) { + case ILLEGAL_REQUEST: + if(cmd[0] == ALLOW_MEDIUM_REMOVAL) dev->lockable = 0; + else printk("SCSI device (ioctl) reports ILLEGAL REQUEST.\n"); + break; + case NOT_READY: /* This happens if there is no disc in drive */ + if(dev->removable){ + printk("Device not ready. Make sure there is a disc in the drive.\n"); + break; + }; + case UNIT_ATTENTION: + if (dev->removable){ + dev->changed = 1; + SCpnt->result = 0; /* This is no longer considered an error */ + printk("Disc change detected.\n"); + break; + }; + default: /* Fall through for non-removable media */ + printk("SCSI CD error: host %d id %d lun %d return code = %x\n", + dev->host->host_no, + dev->id, + dev->lun, + SCpnt->result); + printk("\tSense class %x, sense error %x, extended sense %x\n", + sense_class(SCpnt->sense_buffer[0]), + sense_error(SCpnt->sense_buffer[0]), + SCpnt->sense_buffer[2] & 0xf); + + }; + + result = SCpnt->result; + SCpnt->request.dev = -1; /* Mark as not busy */ + wake_up(&scsi_devices[SCpnt->index].device_wait); + return result; +} + +static int ioctl_command(Scsi_Device *dev, void *buffer) +{ + char * buf; + char cmd[12]; + char * cmd_in; + Scsi_Cmnd * SCpnt; + unsigned char opcode; + int inlen, outlen, cmdlen; + int needed; + int result; + + if (!buffer) + return -EINVAL; + + inlen = get_fs_long((unsigned long *) buffer); + outlen = get_fs_long( ((unsigned long *) buffer) + 1); + + cmd_in = (char *) ( ((int *)buffer) + 2); + opcode = get_fs_byte(cmd_in); + + needed = (inlen > outlen ? inlen : outlen); + if(needed){ + needed = (needed + 511) & ~511; + if (needed > MAX_BUF) needed = MAX_BUF; + buf = (char *) scsi_malloc(needed); + if (!buf) return -ENOMEM; + } else + buf = NULL; + + memcpy_fromfs ((void *) cmd, cmd_in, cmdlen = COMMAND_SIZE (opcode)); + memcpy_fromfs ((void *) buf, (void *) (cmd_in + cmdlen), inlen > MAX_BUF ? MAX_BUF : inlen); + + cmd[1] = ( cmd[1] & 0x1f ) | (dev->lun << 5); + +#ifndef DEBUG_NO_CMD + + SCpnt = allocate_device(NULL, dev->index, 1); + + scsi_do_cmd(SCpnt, cmd, buf, needed, scsi_ioctl_done, MAX_TIMEOUT, + MAX_RETRIES); + + if (SCpnt->request.dev != 0xfffe){ + SCpnt->request.waiting = current; + current->state = TASK_UNINTERRUPTIBLE; + while (SCpnt->request.dev != 0xfffe) schedule(); + }; + + + /* If there was an error condition, pass the info back to the user. */ + if(SCpnt->result) { + result = verify_area(VERIFY_WRITE, cmd_in, sizeof(SCpnt->sense_buffer)); + if (result) + return result; + memcpy_tofs((void *) cmd_in, SCpnt->sense_buffer, sizeof(SCpnt->sense_buffer)); + } else { + + result = verify_area(VERIFY_WRITE, cmd_in, (outlen > MAX_BUF) ? MAX_BUF : outlen); + if (result) + return result; + memcpy_tofs ((void *) cmd_in, buf, (outlen > MAX_BUF) ? MAX_BUF : outlen); + }; + result = SCpnt->result; + SCpnt->request.dev = -1; /* Mark as not busy */ + if (buf) scsi_free(buf, needed); + wake_up(&scsi_devices[SCpnt->index].device_wait); + return result; +#else + { + int i; + printk("scsi_ioctl : device %d. command = ", dev->id); + for (i = 0; i < 12; ++i) + printk("%02x ", cmd[i]); + printk("\nbuffer ="); + for (i = 0; i < 20; ++i) + printk("%02x ", buf[i]); + printk("\n"); + printk("inlen = %d, outlen = %d, cmdlen = %d\n", + inlen, outlen, cmdlen); + printk("buffer = %d, cmd_in = %d\n", buffer, cmd_in); + } + return 0; +#endif +} + + + +/* + the scsi_ioctl() function differs from most ioctls in that it does + not take a major/minor number as the dev filed. Rather, it takes + a pointer to a scsi_devices[] element, a structure. +*/ +int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) +{ + char scsi_cmd[12]; + + if ((cmd != 0 && dev->index > NR_SCSI_DEVICES)) + 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->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, arg); + case SCSI_IOCTL_SEND_COMMAND: + if(!suser()) return -EACCES; + return ioctl_command((Scsi_Device *) dev, arg); + case SCSI_IOCTL_DOORLOCK: + if (!dev->removable || !dev->lockable) return 0; + scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = SCSI_REMOVAL_PREVENT; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd); + break; + case SCSI_IOCTL_DOORUNLOCK: + if (!dev->removable || !dev->lockable) return 0; + scsi_cmd[0] = ALLOW_MEDIUM_REMOVAL; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = SCSI_REMOVAL_ALLOW; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd); + case SCSI_IOCTL_TEST_UNIT_READY: + scsi_cmd[0] = TEST_UNIT_READY; + scsi_cmd[1] = dev->lun << 5; + scsi_cmd[2] = scsi_cmd[3] = scsi_cmd[5] = 0; + scsi_cmd[4] = 0; + return ioctl_internal_command((Scsi_Device *) dev, scsi_cmd); + break; + default : + return -EINVAL; + } + return -EINVAL; +} + +/* + * Just like scsi_ioctl, only callable from kernel space with no + * fs segment fiddling. + */ + +int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg) { + unsigned long oldfs; + int tmp; + oldfs = get_fs(); + set_fs(get_ds()); + tmp = scsi_ioctl (dev, cmd, arg); + set_fs(oldfs); + return tmp; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.h new file mode 100644 index 000000000..dac9548ca --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/scsi_ioctl.h @@ -0,0 +1,20 @@ +#ifndef _SCSI_IOCTL_H +#define _SCSI_IOCTL_H + +#define SCSI_IOCTL_PROBE_HOST 0 +#define SCSI_IOCTL_SEND_COMMAND 1 +#define SCSI_IOCTL_TEST_UNIT_READY 2 +/* The door lock/unlock constants are compatible with Sun constants for + the cdrom */ +#define SCSI_IOCTL_DOORLOCK 0x5380 /* lock the eject mechanism */ +#define SCSI_IOCTL_DOORUNLOCK 0x5381 /* unlock the mechanism */ + +#define SCSI_REMOVAL_PREVENT 1 +#define SCSI_REMOVAL_ALLOW 0 + +extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); +extern int kernel_scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); + +#endif + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.c new file mode 100644 index 000000000..7bb847a8c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.c @@ -0,0 +1,970 @@ +/* + * sd.c Copyright (C) 1992 Drew Eckhardt + * Linux scsi disk driver by + * Drew Eckhardt + * + * + * + * Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR SCSI_DISK_MAJOR +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "sd.h" +#include "scsi_ioctl.h" +#include "constants.h" + +#include + +/* +static const char RCSid[] = "$Header:"; +*/ + +#define MAX_RETRIES 5 + +/* + * Time out in seconds + */ + +#define SD_TIMEOUT 300 + +struct hd_struct * sd; + +int NR_SD=0; +int MAX_SD=0; +Scsi_Disk * rscsi_disks; +static int * sd_sizes; +static int * sd_blocksizes; + +extern int sd_ioctl(struct inode *, struct file *, unsigned int, unsigned long); + +static sd_init_onedisk(int); + +static void requeue_sd_request (Scsi_Cmnd * SCpnt); + +static int sd_open(struct inode * inode, struct file * filp) +{ + int target; + target = DEVICE_NR(MINOR(inode->i_rdev)); + + if(target >= NR_SD || !rscsi_disks[target].device) + return -ENODEV; /* No such device */ + +/* Make sure that only one process can do a check_change_disk at one time. + This is also used to lock out further access when the partition table is being re-read. */ + + while (rscsi_disks[target].device->busy); + + if(rscsi_disks[target].device->removable) { + check_disk_change(inode->i_rdev); + + if(!rscsi_disks[target].device->access_count) + sd_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); + }; + rscsi_disks[target].device->access_count++; + return 0; +} + +static void sd_release(struct inode * inode, struct file * file) +{ + int target; + sync_dev(inode->i_rdev); + + target = DEVICE_NR(MINOR(inode->i_rdev)); + + rscsi_disks[target].device->access_count--; + + if(rscsi_disks[target].device->removable) { + if(!rscsi_disks[target].device->access_count) + sd_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + }; +} + +static void sd_geninit(void); + +static struct file_operations sd_fops = { + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + sd_ioctl, /* ioctl */ + NULL, /* mmap */ + sd_open, /* open code */ + sd_release, /* release */ + block_fsync /* fsync */ +}; + +static struct gendisk sd_gendisk = { + MAJOR_NR, /* Major number */ + "sd", /* Major name */ + 4, /* Bits to shift to get real from partition */ + 1 << 4, /* Number of partitions per real */ + 0, /* maximum number of real */ + sd_geninit, /* init function */ + NULL, /* hd struct */ + NULL, /* block sizes */ + 0, /* number */ + NULL, /* internal */ + NULL /* next */ +}; + +static void sd_geninit (void) +{ + int i; + + for (i = 0; i < NR_SD; ++i) + sd[i << 4].nr_sects = rscsi_disks[i].capacity; + sd_gendisk.nr_real = NR_SD; +} + +/* + rw_intr is the interrupt routine for the device driver. It will + be notified on the end of a SCSI read / write, and + will take on of several actions based on success or failure. +*/ + +static void rw_intr (Scsi_Cmnd *SCpnt) +{ + int result = SCpnt->result; + int this_count = SCpnt->bufflen >> 9; + +#ifdef DEBUG + printk("sd%d : rw_intr(%d, %d)\n", MINOR(SCpnt->request.dev), SCpnt->host->host_no, result); +#endif + +/* + First case : we assume that the command succeeded. One of two things will + happen here. Either we will be finished, or there will be more + sectors that we were unable to read last time. +*/ + + if (!result) { + +#ifdef DEBUG + printk("sd%d : %d sectors remain.\n", MINOR(SCpnt->request.dev), SCpnt->request.nr_sectors); + printk("use_sg is %d\n ",SCpnt->use_sg); +#endif + if (SCpnt->use_sg) { + struct scatterlist * sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for(i=0; iuse_sg; i++) { +#ifdef DEBUG + printk(":%x %x %d\n",sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); +#endif + if (sgpnt[i].alt_address) { + if (SCpnt->request.cmd == READ) + memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); + scsi_free(sgpnt[i].address, sgpnt[i].length); + }; + }; + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + } else { + if (SCpnt->buffer != SCpnt->request.buffer) { +#ifdef DEBUG + printk("nosg: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); +#endif + if (SCpnt->request.cmd == READ) + memcpy(SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); + scsi_free(SCpnt->buffer, SCpnt->bufflen); + }; + }; +/* + * If multiple sectors are requested in one buffer, then + * they will have been finished off by the first command. If + * not, then we have a multi-buffer command. + */ + if (SCpnt->request.nr_sectors > this_count) + { + SCpnt->request.errors = 0; + + if (!SCpnt->request.bh) + { +#ifdef DEBUG + printk("sd%d : handling page request, no buffer\n", + MINOR(SCpnt->request.dev)); +#endif +/* + The SCpnt->request.nr_sectors field is always done in 512 byte sectors, + even if this really isn't the case. +*/ + panic("sd.c: linked page request (%lx %x)", + SCpnt->request.sector, this_count); + } + } + end_scsi_request(SCpnt, 1, this_count); + requeue_sd_request(SCpnt); + return; + } + +/* Free up any indirection buffers we allocated for DMA purposes. */ + if (SCpnt->use_sg) { + struct scatterlist * sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for(i=0; iuse_sg; i++) { +#ifdef DEBUG + printk("err: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); +#endif + if (sgpnt[i].alt_address) { + scsi_free(sgpnt[i].address, sgpnt[i].length); + }; + }; + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + } else { +#ifdef DEBUG + printk("nosgerr: %x %x %d\n",SCpnt->request.buffer, SCpnt->buffer, + SCpnt->bufflen); +#endif + if (SCpnt->buffer != SCpnt->request.buffer) + scsi_free(SCpnt->buffer, SCpnt->bufflen); + }; + +/* + Now, if we were good little boys and girls, Santa left us a request + sense buffer. We can extract information from this, so we + can choose a block to remap, etc. +*/ + + if (driver_byte(result) != 0) { + if (sugestion(result) == SUGGEST_REMAP) { +#ifdef REMAP +/* + Not yet implemented. A read will fail after being remapped, + a write will call the strategy routine again. +*/ + if rscsi_disks[DEVICE_NR(SCpnt->request.dev)].remap + { + result = 0; + } + else + +#endif + } + + if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { + if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { + if(rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->removable) { + /* detected disc change. set a bit and quietly refuse */ + /* further access. */ + + rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->changed = 1; + end_scsi_request(SCpnt, 0, this_count); + requeue_sd_request(SCpnt); + return; + } + } + } + + +/* If we had an ILLEGAL REQUEST returned, then we may have +performed an unsupported command. The only thing this should be would +be a ten byte read where only a six byte read was supportted. Also, +on a system where READ CAPACITY failed, we mave have read past the end +of the disk. +*/ + + if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { + if (rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten) { + rscsi_disks[DEVICE_NR(SCpnt->request.dev)].ten = 0; + requeue_sd_request(SCpnt); + result = 0; + } else { + } + } + } /* 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->host_no, + rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->id, + rscsi_disks[DEVICE_NR(SCpnt->request.dev)].device->lun, result); + + if (driver_byte(result) & DRIVER_SENSE) + print_sense("sd", SCpnt); + end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); + requeue_sd_request(SCpnt); + return; + } +} + +/* + requeue_sd_request() is the request handler function for the sd driver. + Its function in life is to take block device requests, and translate + them to SCSI commands. +*/ + +static void do_sd_request (void) +{ + Scsi_Cmnd * SCpnt = NULL; + struct request * req = NULL; + int flag = 0; + while (1==1){ + cli(); + if (CURRENT != NULL && CURRENT->dev == -1) { + sti(); + return; + }; + + INIT_SCSI_REQUEST; + + +/* We have to be careful here. allocate_device will get a free pointer, but + there is no guarantee that it is queueable. In normal usage, we want to + call this, because other types of devices may have the host all tied up, + and we want to make sure that we have at least one request pending for this + type of device. We can also come through here while servicing an + interrupt, because of the need to start another command. If we call + allocate_device more than once, then the system can wedge if the command + is not queueable. The request_queueable function is safe because it checks + to make sure that the host is able to take another command before it returns + a pointer. */ + + if (flag++ == 0) + SCpnt = allocate_device(&CURRENT, + rscsi_disks[DEVICE_NR(MINOR(CURRENT->dev))].device->index, 0); + 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 + make a big difference on systems with more than one disk drive. We want + to have the interrupts off when monkeying with the request list, because + otherwise the kernel might try and slip in a request inbetween somewhere. */ + + if (!SCpnt && NR_SD > 1){ + struct request *req1; + req1 = NULL; + cli(); + req = CURRENT; + while(req){ + SCpnt = request_queueable(req, + rscsi_disks[DEVICE_NR(MINOR(req->dev))].device->index); + if(SCpnt) break; + req1 = req; + req = req->next; + }; + if (SCpnt && req->dev == -1) { + if (req == CURRENT) + CURRENT = CURRENT->next; + else + req1->next = req->next; + }; + sti(); + }; + + if (!SCpnt) return; /* Could not find anything to do */ + + wake_up(&wait_for_request); + + /* Queue command */ + requeue_sd_request(SCpnt); + }; /* While */ +} + +static void requeue_sd_request (Scsi_Cmnd * SCpnt) +{ + int dev, block, this_count; + unsigned char cmd[10]; + char * buff; + +repeat: + + if(SCpnt->request.dev <= 0) { + do_sd_request(); + return; + } + + dev = MINOR(SCpnt->request.dev); + block = SCpnt->request.sector; + this_count = 0; + +#ifdef DEBUG + printk("Doing sd request, dev = %d, block = %d\n", dev, block); +#endif + + if (dev >= (NR_SD << 4) || block + SCpnt->request.nr_sectors > sd[dev].nr_sects) + { + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + + block += sd[dev].start_sect; + dev = DEVICE_NR(dev); + + if (rscsi_disks[dev].device->changed) + { +/* + * quietly refuse to do anything to a changed disc until the changed bit has been reset + */ + /* printk("SCSI disk has been changed. Prohibiting further I/O.\n"); */ + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + +#ifdef DEBUG + printk("sd%d : real dev = /dev/sd%d, block = %d\n", MINOR(SCpnt->request.dev), dev, block); +#endif + + switch (SCpnt->request.cmd) + { + case WRITE : + if (!rscsi_disks[dev].device->writeable) + { + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + } + cmd[0] = WRITE_6; + break; + case READ : + cmd[0] = READ_6; + break; + default : + panic ("Unknown sd command %d\n", SCpnt->request.cmd); + } + + SCpnt->this_count = 0; + + if (!SCpnt->request.bh || + (SCpnt->request.nr_sectors == SCpnt->request.current_nr_sectors)) { + + /* case of page request (i.e. raw device), or unlinked buffer */ + this_count = SCpnt->request.nr_sectors; + buff = SCpnt->request.buffer; + SCpnt->use_sg = 0; + + } else if (SCpnt->host->sg_tablesize == 0 || + (need_isa_buffer && + dma_free_sectors < 10)) { + + /* Case of host adapter that cannot scatter-gather. We also + come here if we are running low on DMA buffer memory. We set + a threshold higher than that we would need for this request so + we leave room for other requests. Even though we would not need + it all, we need to be conservative, because if we run low enough + we have no choice but to panic. */ + + 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"); + + this_count = SCpnt->request.current_nr_sectors; + buff = SCpnt->request.buffer; + SCpnt->use_sg = 0; + + } else { + + /* Scatter-gather capable host adapter */ + struct buffer_head * bh; + struct scatterlist * sgpnt; + int count, this_count_max; + bh = SCpnt->request.bh; + this_count = 0; + this_count_max = (rscsi_disks[dev].ten ? 0xffff : 0xff); + count = 0; + 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++; + bh = bh->b_reqnext; + }; + SCpnt->use_sg = count; /* Number of chains */ + count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/ + while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) + count = count << 1; + SCpnt->sglist_len = count; + sgpnt = (struct scatterlist * ) scsi_malloc(count); + if (!sgpnt) { + printk("Warning - running *really* short on DMA buffers\n"); + SCpnt->use_sg = 0; /* No memory left - bail out */ + this_count = SCpnt->request.current_nr_sectors; + buff = SCpnt->request.buffer; + } else { + buff = (char *) sgpnt; + count = 0; + bh = SCpnt->request.bh; + for(count = 0, bh = SCpnt->request.bh; count < SCpnt->use_sg; + count++, bh = bh->b_reqnext) { + sgpnt[count].address = bh->b_data; + sgpnt[count].alt_address = NULL; + sgpnt[count].length = bh->b_size; + if (((int) sgpnt[count].address) + sgpnt[count].length > + 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 + pressing need, and we would be screwed if we ran out */ + if(dma_free_sectors < (bh->b_size >> 9) + 5) { + sgpnt[count].address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + }; +/* If we start running low on DMA buffers, we abort the scatter-gather + operation, and free all of the memory we have allocated. We want to + ensure that all scsi operations are able to do at least a non-scatter/gather + operation */ + if(sgpnt[count].address == NULL){ /* Out of dma memory */ + printk("Warning: Running low on SCSI DMA buffers"); + /* Try switching back to a non scatter-gather operation. */ + while(--count >= 0){ + if(sgpnt[count].alt_address) + scsi_free(sgpnt[count].address, sgpnt[count].length); + }; + this_count = SCpnt->request.current_nr_sectors; + buff = SCpnt->request.buffer; + SCpnt->use_sg = 0; + scsi_free(buff, SCpnt->sglist_len); + break; + }; + + if (SCpnt->request.cmd == WRITE) + memcpy(sgpnt[count].address, sgpnt[count].alt_address, + sgpnt[count].length); + }; + }; /* for loop */ + }; /* Able to malloc sgpnt */ + }; /* Host adapter capable of scatter-gather */ + +/* Now handle the possibility of DMA to addresses > 16Mb */ + + if(SCpnt->use_sg == 0){ + if (((int) buff) + (this_count << 9) > ISA_DMA_THRESHOLD && + (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) + memcpy(buff, (char *)SCpnt->request.buffer, this_count << 9); + }; + }; + +#ifdef DEBUG + printk("sd%d : %s %d/%d 512 byte blocks.\n", MINOR(SCpnt->request.dev), + (SCpnt->request.cmd == WRITE) ? "writing" : "reading", + this_count, SCpnt->request.nr_sectors); +#endif + + cmd[1] = (SCpnt->lun << 5) & 0xe0; + + if (rscsi_disks[dev].sector_size == 1024){ + if(block & 1) panic("sd.c:Bad block number requested"); + if(this_count & 1) panic("sd.c:Bad block number requested"); + block = block >> 1; + this_count = this_count >> 1; + }; + + if (rscsi_disks[dev].sector_size == 256){ + block = block << 1; + this_count = this_count << 1; + }; + + if (((this_count > 0xff) || (block > 0x1fffff)) && rscsi_disks[dev].ten) + { + if (this_count > 0xffff) + this_count = 0xffff; + + cmd[0] += READ_10 - READ_6 ; + cmd[2] = (unsigned char) (block >> 24) & 0xff; + cmd[3] = (unsigned char) (block >> 16) & 0xff; + cmd[4] = (unsigned char) (block >> 8) & 0xff; + cmd[5] = (unsigned char) block & 0xff; + cmd[6] = cmd[9] = 0; + cmd[7] = (unsigned char) (this_count >> 8) & 0xff; + cmd[8] = (unsigned char) this_count & 0xff; + } + else + { + if (this_count > 0xff) + this_count = 0xff; + + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); + cmd[2] = (unsigned char) ((block >> 8) & 0xff); + cmd[3] = (unsigned char) block & 0xff; + cmd[4] = (unsigned char) this_count; + cmd[5] = 0; + } + +/* + * We shouldn't disconnect in the middle of a sector, so with a dumb + * host adapter, it's safe to assume that we can at least transfer + * this many bytes between each connect / disconnect. + */ + + SCpnt->transfersize = rscsi_disks[dev].sector_size; + SCpnt->underflow = this_count << 9; + + scsi_do_cmd (SCpnt, (void *) cmd, buff, + this_count * rscsi_disks[dev].sector_size, + rw_intr, SD_TIMEOUT, MAX_RETRIES); +} + +int check_scsidisk_media_change(int full_dev, int flag){ + int retval; + int target; + struct inode inode; + + target = DEVICE_NR(MINOR(full_dev)); + + if (target >= NR_SD) { + printk("SCSI disk request error: invalid device.\n"); + return 0; + }; + + if(!rscsi_disks[target].device->removable) return 0; + + inode.i_rdev = full_dev; /* This is all we really need here */ + retval = sd_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0); + + if(retval){ /* Unable to test, unit probably not ready. This usually + means there is no disc in the drive. Mark as changed, + and we will figure it out later once the drive is + available again. */ + + rscsi_disks[target].device->changed = 1; + return 1; /* This will force a flush, if called from + check_disk_change */ + }; + + retval = rscsi_disks[target].device->changed; + if(!flag) rscsi_disks[target].device->changed = 0; + return retval; +} + +static void sd_init_done (Scsi_Cmnd * SCpnt) +{ + struct request * req; + struct task_struct * p; + + req = &SCpnt->request; + req->dev = 0xfffe; /* Busy, but indicate request done */ + + if ((p = req->waiting) != NULL) { + req->waiting = NULL; + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } +} + +static int sd_init_onedisk(int i) +{ + int j = 0; + unsigned char cmd[10]; + unsigned char *buffer; + char spintime; + int the_result, retries; + Scsi_Cmnd * SCpnt; + + /* We need to retry the READ_CAPACITY because a UNIT_ATTENTION is considered + a fatal error, and many devices report such an error just after a scsi + bus reset. */ + + SCpnt = allocate_device(NULL, rscsi_disks[i].device->index, 1); + buffer = (unsigned char *) scsi_malloc(512); + + spintime = 0; + + /* Spin up drives, as required. Only do this at boot time */ + if (current == task[0]){ + do{ + cmd[0] = TEST_UNIT_READY; + cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + memset ((void *) &cmd[2], 0, 8); + SCpnt->request.dev = 0xffff; /* Mark as really busy again */ + SCpnt->sense_buffer[0] = 0; + SCpnt->sense_buffer[2] = 0; + + scsi_do_cmd (SCpnt, + (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); + + while(SCpnt->request.dev != 0xfffe); + + the_result = SCpnt->result; + + /* Look for non-removable devices that return NOT_READY. Issue command + to spin up drive for these cases. */ + if(the_result && !rscsi_disks[i].device->removable && + SCpnt->sense_buffer[2] == NOT_READY) { + int time1; + if(!spintime){ + printk( "sd%d: Spinning up disk...", i ); + cmd[0] = START_STOP; + cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + cmd[1] |= 1; /* Return immediately */ + memset ((void *) &cmd[2], 0, 8); + cmd[4] = 1; /* Start spin cycle */ + SCpnt->request.dev = 0xffff; /* Mark as really busy again */ + SCpnt->sense_buffer[0] = 0; + SCpnt->sense_buffer[2] = 0; + + scsi_do_cmd (SCpnt, + (void *) cmd, (void *) buffer, + 512, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); + + while(SCpnt->request.dev != 0xfffe); + + spintime = jiffies; + }; + + time1 = jiffies; + while(jiffies < time1 + 100); /* Wait 1 second for next try */ + printk( "." ); + }; + } while(the_result && spintime && spintime+5000 > jiffies); + if (spintime) { + if (the_result) + printk( "not responding...\n" ); + else + printk( "ready\n" ); + } + }; /* current == task[0] */ + + + retries = 3; + do { + cmd[0] = READ_CAPACITY; + cmd[1] = (rscsi_disks[i].device->lun << 5) & 0xe0; + memset ((void *) &cmd[2], 0, 8); + memset ((void *) buffer, 0, 8); + SCpnt->request.dev = 0xffff; /* Mark as really busy again */ + SCpnt->sense_buffer[0] = 0; + SCpnt->sense_buffer[2] = 0; + + scsi_do_cmd (SCpnt, + (void *) cmd, (void *) buffer, + 8, sd_init_done, SD_TIMEOUT, + MAX_RETRIES); + + if (current == task[0]) + while(SCpnt->request.dev != 0xfffe); + else + if (SCpnt->request.dev != 0xfffe){ + SCpnt->request.waiting = current; + current->state = TASK_UNINTERRUPTIBLE; + while (SCpnt->request.dev != 0xfffe) schedule(); + }; + + the_result = SCpnt->result; + retries--; + + } while(the_result && retries); + + SCpnt->request.dev = -1; /* Mark as not busy */ + + wake_up(&scsi_devices[SCpnt->index].device_wait); + + /* Wake up a process waiting for device*/ + + /* + * The SCSI standard says "READ CAPACITY is necessary for self confuring software" + * While not mandatory, support of READ CAPACITY is strongly encouraged. + * We used to die if we couldn't successfully do a READ CAPACITY. + * But, now we go on about our way. The side effects of this are + * + * 1. We can't know block size with certainty. I have said "512 bytes is it" + * as this is most common. + * + * 2. Recovery from when some one attempts to read past the end of the raw device will + * be slower. + */ + + if (the_result) + { + printk ("sd%d : READ CAPACITY failed.\n" + "sd%d : status = %x, message = %02x, host = %d, driver = %02x \n", + i,i, + status_byte(the_result), + msg_byte(the_result), + host_byte(the_result), + driver_byte(the_result) + ); + if (driver_byte(the_result) & DRIVER_SENSE) + printk("sd%d : extended sense code = %1x \n", i, SCpnt->sense_buffer[2] & 0xf); + else + printk("sd%d : sense not available. \n", i); + + printk("sd%d : block size assumed to be 512 bytes, disk size 1GB. \n", i); + rscsi_disks[i].capacity = 0x1fffff; + rscsi_disks[i].sector_size = 512; + + /* Set dirty bit for removable devices if not ready - sometimes drives + will not report this properly. */ + if(rscsi_disks[i].device->removable && + SCpnt->sense_buffer[2] == NOT_READY) + rscsi_disks[i].device->changed = 1; + + } + else + { + rscsi_disks[i].capacity = (buffer[0] << 24) | + (buffer[1] << 16) | + (buffer[2] << 8) | + buffer[3]; + + rscsi_disks[i].sector_size = (buffer[4] << 24) | + (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + + if (rscsi_disks[i].sector_size != 512 && + rscsi_disks[i].sector_size != 1024 && + rscsi_disks[i].sector_size != 256) + { + printk ("sd%d : unsupported sector size %d.\n", + i, rscsi_disks[i].sector_size); + if(rscsi_disks[i].device->removable){ + rscsi_disks[i].capacity = 0; + } else { + printk ("scsi : deleting disk entry.\n"); + for (j=i; j < NR_SD - 1;) + rscsi_disks[j] = rscsi_disks[++j]; + --i; + --NR_SD; + scsi_free(buffer, 512); + return i; + }; + } + if(rscsi_disks[i].sector_size == 1024) + rscsi_disks[i].capacity <<= 1; /* Change this into 512 byte sectors */ + if(rscsi_disks[i].sector_size == 256) + rscsi_disks[i].capacity >>= 1; /* Change this into 512 byte sectors */ + } + + rscsi_disks[i].ten = 1; + rscsi_disks[i].remap = 1; + scsi_free(buffer, 512); + return i; +} + +/* + The sd_init() function looks at all SCSI drives present, determines + their size, and reads partition table entries for them. +*/ + +unsigned long sd_init(unsigned long memory_start, unsigned long memory_end) +{ + int i; + + if (register_blkdev(MAJOR_NR,"sd",&sd_fops)) { + printk("Unable to get major %d for SCSI disk\n",MAJOR_NR); + return memory_start; + } + if (MAX_SD == 0) return memory_start; + + sd_sizes = (int *) memory_start; + memory_start += (MAX_SD << 4) * sizeof(int); + memset(sd_sizes, 0, (MAX_SD << 4) * sizeof(int)); + + sd_blocksizes = (int *) memory_start; + memory_start += (MAX_SD << 4) * sizeof(int); + for(i=0;i<(MAX_SD << 4);i++) sd_blocksizes[i] = 1024; + blksize_size[MAJOR_NR] = sd_blocksizes; + + sd = (struct hd_struct *) memory_start; + memory_start += (MAX_SD << 4) * sizeof(struct hd_struct); + + sd_gendisk.max_nr = MAX_SD; + sd_gendisk.part = sd; + sd_gendisk.sizes = sd_sizes; + sd_gendisk.real_devices = (void *) rscsi_disks; + + for (i = 0; i < NR_SD; ++i) + i = sd_init_onedisk(i); + + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + + /* If our host adapter is capable of scatter-gather, then we increase + the read-ahead to 16 blocks (32 sectors). If not, we use + a two block (4 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 */ + + sd_gendisk.next = gendisk_head; + gendisk_head = &sd_gendisk; + return memory_start; +} + +unsigned long sd_init1(unsigned long mem_start, unsigned long mem_end){ + rscsi_disks = (Scsi_Disk *) mem_start; + mem_start += MAX_SD * sizeof(Scsi_Disk); + return mem_start; +}; + +void sd_attach(Scsi_Device * SDp){ + rscsi_disks[NR_SD++].device = SDp; + if(NR_SD > MAX_SD) panic ("scsi_devices corrupt (sd)"); +}; + +#define DEVICE_BUSY rscsi_disks[target].device->busy +#define USAGE rscsi_disks[target].device->access_count +#define CAPACITY rscsi_disks[target].capacity +#define MAYBE_REINIT sd_init_onedisk(target) +#define GENDISK_STRUCT sd_gendisk + +/* This routine is called to flush all partitions and partition tables + for a changed scsi disk, and then re-read the new partition table. + If we are revalidating a disk because of a media change, then we + enter with usage == 0. If we are using an ioctl, we automatically have + usage == 1 (we need an open channel to use an ioctl :-), so this + is our limit. + */ +int revalidate_scsidisk(int dev, int maxusage){ + int target, major; + struct gendisk * gdev; + int max_p; + int start; + int i; + + target = DEVICE_NR(MINOR(dev)); + gdev = &GENDISK_STRUCT; + + cli(); + if (DEVICE_BUSY || USAGE > maxusage) { + sti(); + printk("Device busy for revalidation (usage=%d)\n", USAGE); + return -EBUSY; + }; + DEVICE_BUSY = 1; + sti(); + + max_p = gdev->max_p; + start = target << gdev->minor_shift; + major = MAJOR_NR << 8; + + for (i=max_p - 1; i >=0 ; i--) { + sync_dev(major | start | i); + invalidate_inodes(major | start | i); + invalidate_buffers(major | start | i); + gdev->part[start+i].start_sect = 0; + gdev->part[start+i].nr_sects = 0; + }; + +#ifdef MAYBE_REINIT + MAYBE_REINIT; +#endif + + gdev->part[start].nr_sects = CAPACITY; + resetup_one_dev(gdev, target); + + DEVICE_BUSY = 0; + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.h new file mode 100644 index 000000000..efa63e315 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd.h @@ -0,0 +1,46 @@ +/* + * sd.h Copyright (C) 1992 Drew Eckhardt + * SCSI disk driver header file by + * Drew Eckhardt + * + * + * + * Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ +#ifndef _SD_H + #define _SD_H +/* + $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/sd.h,v 1.1 1992/07/24 06:27:38 root Exp root $ +*/ + +#ifndef _SCSI_H +#include "scsi.h" +#endif + +#ifndef _GENDISK_H +#include +#endif + +/* + This is an arbitrary constant, and may be changed to whatever + suits your purposes. Note that smaller will get you a few bytes + more in kernel space if that is your thing. +*/ + +extern struct hd_struct * sd; + +typedef struct { + unsigned capacity; /* size in blocks */ + unsigned sector_size; /* size in bytes */ + Scsi_Device *device; + unsigned char sector_bit_size; /* sector_size = 2 to the bit size power */ + unsigned char sector_bit_shift; /* power of 2 sectors per FS block */ + unsigned ten:1; /* support ten byte read / write */ + unsigned remap:1; /* support remapping */ + } Scsi_Disk; + +extern Scsi_Disk * rscsi_disks; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd_ioctl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd_ioctl.c new file mode 100644 index 000000000..f51ec664a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sd_ioctl.c @@ -0,0 +1,68 @@ +#include +#include +#include +#include +#include + +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "scsi_ioctl.h" +#include "hosts.h" +#include "sd.h" + +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 error; + struct Scsi_Host * host; + int diskinfo[4]; + struct hd_geometry *loc = (struct hd_geometry *) arg; + + switch (cmd) { + case HDIO_REQ: /* Return BIOS disk parameters */ + if (!loc) return -EINVAL; + error = verify_area(VERIFY_WRITE, loc, sizeof(*loc)); + if (error) + return error; + host = rscsi_disks[MINOR(dev) >> 4].device->host; + diskinfo[0] = 0; + diskinfo[1] = 0; + diskinfo[2] = 0; + if(host->hostt->bios_param != NULL) + host->hostt->bios_param(rscsi_disks[MINOR(dev) >> 4].capacity, + dev, + &diskinfo[0]); + put_fs_byte(diskinfo[0], + (char *) &loc->heads); + put_fs_byte(diskinfo[1], + (char *) &loc->sectors); + put_fs_word(diskinfo[2], + (short *) &loc->cylinders); + put_fs_long(sd[MINOR(inode->i_rdev)].start_sect, + (long *) &loc->start); + return 0; + case BLKGETSIZE: /* Return device size */ + if (!arg) return -EINVAL; + error = verify_area(VERIFY_WRITE, (long *) arg, sizeof(long)); + if (error) + return error; + put_fs_long(sd[MINOR(inode->i_rdev)].nr_sects, + (long *) arg); + return 0; + case BLKFLSBUF: + if(!suser()) return -EACCES; + if(!inode->i_rdev) return -EINVAL; + fsync_dev(inode->i_rdev); + invalidate_buffers(inode->i_rdev); + return 0; + + case BLKRRPART: /* Re-read partition tables */ + return revalidate_scsidisk(dev, 1); + default: + return scsi_ioctl(rscsi_disks[MINOR(dev) >> 4].device , cmd, (void *) arg); + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.c new file mode 100644 index 000000000..32baed732 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.c @@ -0,0 +1,1711 @@ +/* + * seagate.c Copyright (C) 1992, 1993 Drew Eckhardt + * low level scsi driver for ST01/ST02, Future Domain TMC-885, + * TMC-950 by + * + * Drew Eckhardt + * + * + * + * Note : TMC-880 boards don't work because they have two bits in + * the status register flipped, I'll fix this "RSN" + * + * This card does all the I/O via memory mapped I/O, so there is no need + * to check or snarf a region of the I/O address space. + */ + +/* + * 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 + * + * -DARBITRATE will cause the host adapter to arbitrate for the + * bus for better SCSI-II compatability, rather than just + * waiting for BUS FREE and then doing its thing. Should + * let us do one command per Lun when I integrate my + * reorganization changes into the distribution sources. + * + * -DSLOW_HANDSHAKE will allow compatability with broken devices that don't + * handshake fast enough (ie, some CD ROM's) for the Seagate + * code. + * + * -DSLOW_RATE=x, x some number will let you specify a default + * transfer rate if handshaking isn't working correctly. + */ + +#include + +#if defined(CONFIG_SCSI_SEAGATE) || defined(CONFIG_SCSI_FD_8xx) +#include +#include +#include +#include +#include +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "seagate.h" +#include "constants.h" + + +#ifndef IRQ +#define IRQ 5 +#endif + +#if (defined(FAST32) && !defined(FAST)) +#define FAST +#endif + +#if defined(SLOW_RATE) && !defined(SLOW_HANDSHAKE) +#define SLOW_HANDSHAKE +#endif + +#if defined(SLOW_HANDSHAKE) && !defined(SLOW_RATE) +#define SLOW_RATE 50 +#endif + + +#if defined(LINKED) +#undef LINKED /* Linked commands are currently broken ! */ +#endif + +static int internal_command(unsigned char target, unsigned char lun, + const void *cmnd, + void *buff, int bufflen, int reselect); + +static int incommand; /* + set if arbitration has finished and we are + in some command phase. + */ + +static void *base_address = NULL; /* + Where the card ROM starts, + used to calculate memory mapped + register location. + */ +static volatile int abort_confirm = 0; + +static volatile void *st0x_cr_sr; /* + control register write, + status register read. + 256 bytes in length. + + Read is status of SCSI BUS, + as per STAT masks. + + */ + + +static volatile void *st0x_dr; /* + data register, read write + 256 bytes in length. + */ + + +static volatile int st0x_aborted=0; /* + set when we are aborted, ie by a time out, etc. + */ + +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[] = { + (char *) 0xc8000, (char *) 0xca000, (char *) 0xcc000, + (char *) 0xce000, (char *) 0xdc000, (char *) 0xde000 +}; + +typedef struct { + char *signature ; + unsigned offset; + unsigned length; + unsigned char type; +} Signature; + +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" + */ + +{"SEAGATE SCSI BIOS ",16, 17, SEAGATE}, +{"SEAGATE SCSI BIOS ",17, 17, SEAGATE}, + +/* + * However, future domain makes several incompatable SCSI boards, so specific + * signatures must be used. + */ + +{"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 */ +} +; + +#define NUM_SIGNATURES (sizeof(signatures) / sizeof(Signature)) +#endif /* n OVERRIDE */ + +/* + * hostno stores the hostnumber, as told to us by the init routine. + */ + +static int hostno = -1; +static void seagate_reconnect_intr(int); + +#ifdef FAST +static int fast = 1; +#endif + +#ifdef SLOW_HANDSHAKE +/* + * Support for broken devices : + * The Seagate board has a handshaking problem. Namely, a lack + * thereof for slow devices. You can blast 600K/second through + * it if you are polling for each byte, more if you do a blind + * transfer. In the first case, with a fast device, REQ will + * transition high-low or high-low-high before your loop restarts + * and you'll have no problems. In the second case, the board + * will insert wait states for up to 13.2 usecs for REQ to + * transition low->high, and everything will work. + * + * However, there's nothing in the state machine that says + * you *HAVE* to see a high-low-high set of transitions before + * sending the next byte, and slow things like the Trantor CD ROMS + * will break because of this. + * + * So, we need to slow things down, which isn't as simple as it + * seems. We can't slow things down period, because then people + * who don't recompile their kernels will shoot me for ruining + * their performance. We need to do it on a case per case basis. + * + * The best for performance will be to, only for borken devices + * (this is stored on a per-target basis in the scsi_devices array) + * + * Wait for a low->high transition before continuing with that + * transfer. If we timeout, continue anyways. We don't need + * a long timeout, because REQ should only be asserted until the + * corresponding ACK is recieved and processed. + * + * Note that we can't use the system timer for this, because of + * resolution, and we *really* can't use the timer chip since + * gettimeofday() and the beeper routines use that. So, + * the best thing for us to do will be to calibrate a timing + * loop in the initialization code using the timer chip before + * gettimeofday() can screw with it. + */ + +static int borken_calibration = 0; +static void borken_init (void) { + register int count = 0, start = jiffies + 1, stop = start + 25; + + while (jiffies < start); + for (;jiffies < stop; ++count); + +/* + * Ok, we now have a count for .25 seconds. Convert to a + * count per second and divide by transer rate in K. + */ + + borken_calibration = (count * 4) / (SLOW_RATE*1024); + + if (borken_calibration < 1) + borken_calibration = 1; +#if (DEBUG & DEBUG_BORKEN) + printk("scsi%d : borken calibrated to %dK/sec, %d cycles per transfer\n", + hostno, BORKEN_RATE, borken_calibration); +#endif +} + +static inline void borken_wait(void) { + register int count; + for (count = borken_calibration; count && (STATUS & STAT_REQ); + --count); + if (count) +#if (DEBUG & DEBUG_BORKEN) + printk("scsi%d : borken timeout\n", hostno); +#else + ; +#endif +} + +#endif /* def SLOW_HANDSHAKE */ + +int seagate_st0x_detect (int hostnum) + { +#ifndef OVERRIDE + int i,j; +#endif +static struct sigaction seagate_sigaction = { + &seagate_reconnect_intr, + 0, + SA_INTERRUPT, + NULL +}; + +/* + * First, we try for the manual override. + */ +#ifdef DEBUG + printk("Autodetecting seagate ST0x\n"); +#endif + + if (hostno != -1) + { + printk ("ERROR : seagate_st0x_detect() called twice.\n"); + return 0; + } + + /* 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; + +/* CONTROLLER is used to override controller (SEAGATE or FD). PM: 07/01/93 */ +#ifdef CONTROLLER + controller_type = CONTROLLER; +#else +#error Please use -DCONTROLLER=SEAGATE or -DCONTROLLER=FD to override controller type +#endif /* CONTROLLER */ +#ifdef DEBUG + printk("Base address overridden to %x, controller type is %s\n", + base_address,controller_type == SEAGATE ? "SEAGATE" : "FD"); +#endif +#else /* OVERIDE */ +/* + * To detect this card, we simply look for the signature + * from the BIOS version notice in all the possible locations + * of the ROM's. This has a nice sideeffect of not trashing + * any register locations that might be used by something else. + * + * XXX - note that we probably should be probing the address + * space for the on-board RAM instead. + */ + + for (i = 0; i < (sizeof (seagate_bases) / sizeof (char * )); ++i) + for (j = 0; !base_address && j < NUM_SIGNATURES; ++j) + if (!memcmp ((void *) (seagate_bases[i] + + signatures[j].offset), (void *) signatures[j].signature, + signatures[j].length)) { + base_address = (void *) seagate_bases[i]; + controller_type = signatures[j].type; + } +#endif /* OVERIDE */ + } /* (! controller_type) */ + + scsi_hosts[hostnum].this_id = (controller_type == SEAGATE) ? 7 : 6; + + if (base_address) + { + st0x_cr_sr =(void *) (((unsigned char *) base_address) + (controller_type == SEAGATE ? 0x1a00 : 0x1c00)); + st0x_dr = (void *) (((unsigned char *) base_address ) + (controller_type == SEAGATE ? 0x1c00 : 0x1e00)); +#ifdef DEBUG + printk("ST0x detected. Base address = %x, cr = %x, dr = %x\n", base_address, st0x_cr_sr, st0x_dr); +#endif +/* + * At all times, we will use IRQ 5. Should also check for IRQ3 if we + * loose our first interrupt. + */ + hostno = hostnum; + if (irqaction((int) irq, &seagate_sigaction)) { + printk("scsi%d : unable to allocate IRQ%d\n", + hostno, (int) irq); + return 0; + } +#ifdef SLOW_HANDSHAKE + borken_init(); +#endif + + return 1; + } + else + { +#ifdef DEBUG + printk("ST0x not detected.\n"); +#endif + return 0; + } + } + +const char *seagate_st0x_info(void) { + static char buffer[256]; + sprintf(buffer, "scsi%d : %s at irq %d address %p options :" +#ifdef ARBITRATE +" ARBITRATE" +#endif +#ifdef SLOW_HANDSHAKE +" SLOW_HANDSHAKE" +#endif +#ifdef FAST +#ifdef FAST32 +" FAST32" +#else +" FAST" +#endif +#endif + +#ifdef LINKED +" LINKED" +#endif + "\n", hostno, (controller_type == SEAGATE) ? "seagate" : + "FD TMC-8xx", irq, base_address); + return buffer; +} + +/* + * These are our saved pointers for the outstanding command that is + * waiting for a reconnect + */ + +static unsigned char current_target, current_lun; +static unsigned char *current_cmnd, *current_data; +static int current_nobuffs; +static struct scatterlist *current_buffer; +static int current_bufflen; + +#ifdef LINKED + +/* + * linked_connected indicates weather or not we are currently connected to + * linked_target, linked_lun and in an INFORMATION TRANSFER phase, + * using linked commands. + */ + +static int linked_connected = 0; +static unsigned char linked_target, linked_lun; +#endif + + +static void (*done_fn)(Scsi_Cmnd *) = NULL; +static Scsi_Cmnd * SCint = NULL; + +/* + * These control whether or not disconnect / reconnect will be attempted, + * or are being attempted. + */ + +#define NO_RECONNECT 0 +#define RECONNECT_NOW 1 +#define CAN_RECONNECT 2 + +#ifdef LINKED + +/* + * LINKED_RIGHT indicates that we are currently connected to the correct target + * for this command, LINKED_WRONG indicates that we are connected to the wrong + * target. Note that these imply CAN_RECONNECT. + */ + +#define LINKED_RIGHT 3 +#define LINKED_WRONG 4 +#endif + +/* + * This determines if we are expecting to reconnect or not. + */ + +static int should_reconnect = 0; + +/* + * The seagate_reconnect_intr routine is called when a target reselects the + * host adapter. This occurs on the interrupt triggered by the target + * asserting SEL. + */ + +static void seagate_reconnect_intr (int unused) + { + int temp; + Scsi_Cmnd * SCtmp; + +/* enable all other interrupts. */ + sti(); +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : seagate_reconnect_intr() called\n", hostno); +#endif + + if (!should_reconnect) + printk("scsi%d: unexpected interrupt.\n", hostno); + else { + should_reconnect = 0; + +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : internal_command(" + "%d, %08x, %08x, %d, RECONNECT_NOW\n", hostno, + current_target, current_data, current_bufflen); +#endif + + temp = internal_command (current_target, current_lun, + current_cmnd, current_data, current_bufflen, + RECONNECT_NOW); + + if (msg_byte(temp) != DISCONNECT) { + if (done_fn) { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : done_fn(%d,%08x)", hostno, + hostno, temp); +#endif + if(!SCint) panic("SCint == NULL in seagate"); + SCtmp = SCint; + SCint = NULL; + SCtmp->result = temp; + done_fn (SCtmp); + } else + printk("done_fn() not defined.\n"); + } + } + } + +/* + * The seagate_st0x_queue_command() function provides a queued interface + * to the seagate SCSI driver. Basically, it just passes control onto the + * seagate_command() function, after fixing it so that the done_fn() + * is set to the one passed to the function. We have to be very careful, + * because there are some commands on some devices that do not disconnect, + * and if we simply call the done_fn when the command is done then another + * command is started and queue_command is called again... We end up + * overflowing the kernel stack, and this tends not to be such a good idea. + */ + +static int recursion_depth = 0; + +int seagate_st0x_queue_command (Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) + { + int result, reconnect; + Scsi_Cmnd * SCtmp; + + done_fn = done; + current_target = SCpnt->target; + current_lun = SCpnt->lun; + (const void *) current_cmnd = SCpnt->cmnd; + current_data = (unsigned char *) SCpnt->request_buffer; + current_bufflen = SCpnt->request_bufflen; + SCint = SCpnt; + if(recursion_depth) { + return 0; + }; + recursion_depth++; + do{ +#ifdef LINKED +/* + * Set linked command bit in control field of SCSI command. + */ + + current_cmnd[COMMAND_SIZE(current_cmnd[0])] |= 0x01; + if (linked_connected) { +#if (DEBUG & DEBUG_LINKED) + printk("scsi%d : using linked commands, current I_T_L nexus is ", + hostno); +#endif + if ((linked_target == current_target) && + (linked_lun == current_lun)) { +#if (DEBUG & DEBUG_LINKED) + printk("correct\n"); +#endif + reconnect = LINKED_RIGHT; + } else { +#if (DEBUG & DEBUG_LINKED) + printk("incorrect\n"); +#endif + reconnect = LINKED_WRONG; + } + } else +#endif /* LINKED */ + reconnect = CAN_RECONNECT; + + + + + + result = internal_command (SCint->target, SCint->lun, SCint->cmnd, SCint->request_buffer, + SCint->request_bufflen, + reconnect); + if (msg_byte(result) == DISCONNECT) break; + SCtmp = SCint; + SCint = NULL; + SCtmp->result = result; + done_fn (SCtmp); + } while(SCint); + recursion_depth--; + return 0; + } + +int seagate_st0x_command (Scsi_Cmnd * SCpnt) { + return internal_command (SCpnt->target, SCpnt->lun, SCpnt->cmnd, SCpnt->request_buffer, + SCpnt->request_bufflen, + (int) NO_RECONNECT); +} + +static int internal_command(unsigned char target, unsigned char lun, const void *cmnd, + void *buff, int bufflen, int reselect) { + int len = 0; + unsigned char *data = NULL; + struct scatterlist *buffer = NULL; + int nobuffs = 0; + int clock; + int temp; +#ifdef SLOW_HANDSHAKE + int borken; /* Does the current target require Very Slow I/O ? */ +#endif + + +#if (DEBUG & PHASE_DATAIN) || (DEBUG & PHASE_DATOUT) + int transfered = 0; +#endif + +#if (((DEBUG & PHASE_ETC) == PHASE_ETC) || (DEBUG & PRINT_COMMAND) || \ + (DEBUG & PHASE_EXIT)) + int i; +#endif + +#if ((DEBUG & PHASE_ETC) == PHASE_ETC) + int phase=0, newphase; +#endif + + int done = 0; + unsigned char status = 0; + unsigned char message = 0; + register unsigned char status_read; + + unsigned transfersize = 0, underflow = 0; + + incommand = 0; + st0x_aborted = 0; + +#ifdef SLOW_HANDSHAKE + borken = (int) scsi_devices[SCint->index].borken; +#endif + +#if (DEBUG & PRINT_COMMAND) + printk ("scsi%d : target = %d, command = ", hostno, target); + print_command((unsigned char *) cmnd); + printk("\n"); +#endif + +#if (DEBUG & PHASE_RESELECT) + switch (reselect) { + case RECONNECT_NOW : + printk("scsi%d : reconnecting\n", hostno); + break; +#ifdef LINKED + case LINKED_RIGHT : + printk("scsi%d : connected, can reconnect\n", hostno); + break; + case LINKED_WRONG : + printk("scsi%d : connected to wrong target, can reconnect\n", + hostno); + break; +#endif + case CAN_RECONNECT : + printk("scsi%d : allowed to reconnect\n", hostno); + break; + default : + printk("scsi%d : not allowed to reconnect\n", hostno); + } +#endif + + + if (target == (controller_type == SEAGATE ? 7 : 6)) + return DID_BAD_TARGET; + +/* + * We work it differently depending on if this is is "the first time," + * or a reconnect. If this is a reselct phase, then SEL will + * be asserted, and we must skip selection / arbitration phases. + */ + + switch (reselect) { + case RECONNECT_NOW: +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : phase RESELECT \n", hostno); +#endif + +/* + * At this point, we should find the logical or of our ID and the original + * target's ID on the BUS, with BSY, SEL, and I/O signals asserted. + * + * After ARBITRATION phase is completed, only SEL, BSY, and the + * target ID are asserted. A valid initator ID is not on the bus + * until IO is asserted, so we must wait for that. + */ + + for (clock = jiffies + 10, temp = 0; (jiffies < clock) && + !(STATUS & STAT_IO);); + + if (jiffies >= clock) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : RESELECT timed out while waiting for IO .\n", + hostno); +#endif + return (DID_BAD_INTR << 16); + } + +/* + * After I/O is asserted by the target, we can read our ID and its + * ID off of the BUS. + */ + + if (!((temp = DATA) & (controller_type == SEAGATE ? 0x80 : 0x40))) + { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : detected reconnect request to different target.\n" + "\tData bus = %d\n", hostno, temp); +#endif + return (DID_BAD_INTR << 16); + } + + if (!(temp & (1 << current_target))) + { + printk("scsi%d : Unexpected reselect interrupt. Data bus = %d\n", + hostno, temp); + return (DID_BAD_INTR << 16); + } + + buffer=current_buffer; + cmnd=current_cmnd; /* WDE add */ + data=current_data; /* WDE add */ + len=current_bufflen; /* WDE add */ + nobuffs=current_nobuffs; + +/* + * We have determined that we have been selected. At this point, + * we must respond to the reselection by asserting BSY ourselves + */ + +#if 1 + CONTROL = (BASE_CMD | CMD_DRVR_ENABLE | CMD_BSY); +#else + CONTROL = (BASE_CMD | CMD_BSY); +#endif + +/* + * The target will drop SEL, and raise BSY, at which time we must drop + * BSY. + */ + + for (clock = jiffies + 10; (jiffies < clock) && (STATUS & STAT_SEL);); + + if (jiffies >= clock) + { + CONTROL = (BASE_CMD | CMD_INTR); +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : RESELECT timed out while waiting for SEL.\n", + hostno); +#endif + return (DID_BAD_INTR << 16); + } + + CONTROL = BASE_CMD; + +/* + * At this point, we have connected with the target and can get + * on with our lives. + */ + break; + case CAN_RECONNECT: + +#ifdef LINKED +/* + * This is a bletcherous hack, just as bad as the Unix #! interpreter stuff. + * If it turns out we are using the wrong I_T_L nexus, the easiest way to deal + * with it is to go into our INFORMATION TRANSFER PHASE code, send a ABORT + * message on MESSAGE OUT phase, and then loop back to here. + */ + +connect_loop : + +#endif + +#if (DEBUG & PHASE_BUS_FREE) + printk ("scsi%d : phase = BUS FREE \n", hostno); +#endif + +/* + * BUS FREE PHASE + * + * On entry, we make sure that the BUS is in a BUS FREE + * phase, by insuring that both BSY and SEL are low for + * at least one bus settle delay. Several reads help + * eliminate wire glitch. + */ + + clock = jiffies + ST0X_BUS_FREE_DELAY; + +#if !defined (ARBITRATE) + while (((STATUS | STATUS | STATUS) & + (STAT_BSY | STAT_SEL)) && + (!st0x_aborted) && (jiffies < clock)); + + if (jiffies > clock) + return retcode(DID_BUS_BUSY); + else if (st0x_aborted) + return retcode(st0x_aborted); +#endif + +#if (DEBUG & PHASE_SELECTION) + printk("scsi%d : phase = SELECTION\n", hostno); +#endif + + clock = jiffies + ST0X_SELECTION_DELAY; + +/* + * Arbitration/selection procedure : + * 1. Disable drivers + * 2. Write HOST adapter address bit + * 3. Set start arbitration. + * 4. We get either ARBITRATION COMPLETE or SELECT at this + * point. + * 5. OR our ID and targets on bus. + * 6. Enable SCSI drivers and asserted SEL and ATTN + */ + +#if defined(ARBITRATE) + cli(); + CONTROL = 0; + DATA = (controller_type == SEAGATE) ? 0x80 : 0x40; + CONTROL = CMD_START_ARB; + sti(); + while (!((status_read = STATUS) & (STAT_ARB_CMPL | STAT_SEL)) && + (jiffies < clock) && !st0x_aborted); + + if (!(status_read & STAT_ARB_CMPL)) { +#if (DEBUG & PHASE_SELECTION) + if (status_read & STAT_SEL) + printk("scsi%d : arbitration lost\n", hostno); + else + printk("scsi%d : arbitration timeout.\n", hostno); +#endif + CONTROL = BASE_CMD; + return retcode(DID_NO_CONNECT); + }; + +#if (DEBUG & PHASE_SELECTION) + printk("scsi%d : arbitration complete\n", hostno); +#endif +#endif + + +/* + * When the SCSI device decides that we're gawking at it, it will + * respond by asserting BUSY on the bus. + * + * Note : the Seagate ST-01/02 product manual says that we should + * twiddle the DATA register before the control register. However, + * this does not work reliably so we do it the other way arround. + * + * Probably could be a problem with arbitration too, we really should + * try this with a SCSI protocol or logic analyzer to see what is + * going on. + */ + cli(); + DATA = (unsigned char) ((1 << target) | (controller_type == SEAGATE ? 0x80 : 0x40)); + CONTROL = BASE_CMD | CMD_DRVR_ENABLE | CMD_SEL | + (reselect ? CMD_ATTN : 0); + sti(); + while (!((status_read = STATUS) & STAT_BSY) && + (jiffies < clock) && !st0x_aborted) + +#if 0 && (DEBUG & PHASE_SELECTION) + { + temp = clock - jiffies; + + if (!(jiffies % 5)) + printk("seagate_st0x_timeout : %d \r",temp); + + } + printk("Done. \n"); + printk("scsi%d : status = %02x, seagate_st0x_timeout = %d, aborted = %02x \n", + hostno, status_read, temp, st0x_aborted); +#else + ; +#endif + + + if ((jiffies >= clock) && !(status_read & STAT_BSY)) + { +#if (DEBUG & PHASE_SELECTION) + printk ("scsi%d : NO CONNECT with target %d, status = %x \n", + hostno, target, STATUS); +#endif + return retcode(DID_NO_CONNECT); + } + +/* + * If we have been aborted, and we have a command in progress, IE the + * target still has BSY asserted, then we will reset the bus, and + * notify the midlevel driver to expect sense. + */ + + if (st0x_aborted) { + CONTROL = BASE_CMD; + if (STATUS & STAT_BSY) { + printk("scsi%d : BST asserted after we've been aborted.\n", + hostno); + seagate_st0x_reset(NULL); + return retcode(DID_RESET); + } + return retcode(st0x_aborted); + } + +/* Establish current pointers. Take into account scatter / gather */ + + if ((nobuffs = SCint->use_sg)) { +#if (DEBUG & DEBUG_SG) + { + int i; + printk("scsi%d : scatter gather requested, using %d buffers.\n", + hostno, nobuffs); + for (i = 0; i < nobuffs; ++i) + printk("scsi%d : buffer %d address = %08x length = %d\n", + hostno, i, buffer[i].address, buffer[i].length); + } +#endif + + buffer = (struct scatterlist *) SCint->buffer; + len = buffer->length; + data = (unsigned char *) buffer->address; + } else { +#if (DEBUG & DEBUG_SG) + printk("scsi%d : scatter gather not requested.\n", hostno); +#endif + buffer = NULL; + len = SCint->request_bufflen; + data = (unsigned char *) SCint->request_buffer; + } + +#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT)) + printk("scsi%d : len = %d\n", hostno, len); +#endif + + break; +#ifdef LINKED + case LINKED_RIGHT: + break; + case LINKED_WRONG: + break; +#endif + } + +/* + * There are several conditions under which we wish to send a message : + * 1. When we are allowing disconnect / reconnect, and need to establish + * the I_T_L nexus via an IDENTIFY with the DiscPriv bit set. + * + * 2. When we are doing linked commands, are have the wrong I_T_L nexus + * established and want to send an ABORT message. + */ + + + CONTROL = BASE_CMD | CMD_DRVR_ENABLE | + (((reselect == CAN_RECONNECT) +#ifdef LINKED + || (reselect == LINKED_WRONG) +#endif + ) ? CMD_ATTN : 0) ; + +/* + * INFORMATION TRANSFER PHASE + * + * The nasty looking read / write inline assembler loops we use for + * DATAIN and DATAOUT phases are approximately 4-5 times as fast as + * the 'C' versions - since we're moving 1024 bytes of data, this + * really adds up. + */ + +#if ((DEBUG & PHASE_ETC) == PHASE_ETC) + printk("scsi%d : phase = INFORMATION TRANSFER\n", hostno); +#endif + + incommand = 1; + transfersize = SCint->transfersize; + underflow = SCint->underflow; + + +/* + * Now, we poll the device for status information, + * and handle any requests it makes. Note that since we are unsure of + * how much data will be flowing across the system, etc and cannot + * make reasonable timeouts, that we will instead have the midlevel + * driver handle any timeouts that occur in this phase. + */ + + while (((status_read = STATUS) & STAT_BSY) && !st0x_aborted && !done) + { +#ifdef PARITY + if (status_read & STAT_PARITY) + { + printk("scsi%d : got parity error\n", hostno); + st0x_aborted = DID_PARITY; + } +#endif + + if (status_read & STAT_REQ) + { +#if ((DEBUG & PHASE_ETC) == PHASE_ETC) + if ((newphase = (status_read & REQ_MASK)) != phase) + { + phase = newphase; + switch (phase) + { + case REQ_DATAOUT: + printk("scsi%d : phase = DATA OUT\n", + hostno); + break; + case REQ_DATAIN : + printk("scsi%d : phase = DATA IN\n", + hostno); + break; + case REQ_CMDOUT : + printk("scsi%d : phase = COMMAND OUT\n", + hostno); + break; + case REQ_STATIN : + printk("scsi%d : phase = STATUS IN\n", + hostno); + break; + case REQ_MSGOUT : + printk("scsi%d : phase = MESSAGE OUT\n", + hostno); + break; + case REQ_MSGIN : + printk("scsi%d : phase = MESSAGE IN\n", + hostno); + break; + default : + printk("scsi%d : phase = UNKNOWN\n", + hostno); + st0x_aborted = DID_ERROR; + } + } +#endif + switch (status_read & REQ_MASK) + { + case REQ_DATAOUT : +/* + * If we are in fast mode, then we simply splat the data out + * in word-sized chunks as fast as we can. + */ + +#ifdef FAST +if (!len) { +#if 0 + printk("scsi%d: underflow to target %d lun %d \n", + hostno, target, lun); + st0x_aborted = DID_ERROR; + fast = 0; +#endif + break; +} + +if (fast && transfersize && !(len % transfersize) && (len >= transfersize) +#ifdef FAST32 + && !(transfersize % 4) +#endif + ) { +#if (DEBUG & DEBUG_FAST) + printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" + " len = %d, data = %08x\n", hostno, SCint->underflow, + SCint->transfersize, len, data); +#endif + + __asm__(" + cld; +" +#ifdef FAST32 +" shr $2, %%ecx; +1: lodsl; + movl %%eax, (%%edi); +" +#else +"1: lodsb; + movb %%al, (%%edi); +" +#endif +" loop 1b;" : : + /* input */ + "D" (st0x_dr), "S" (data), "c" (SCint->transfersize) : + /* clobbered */ + "eax", "ecx", "esi" ); + + len -= transfersize; + data += transfersize; + +#if (DEBUG & DEBUG_FAST) + printk("scsi%d : FAST transfer complete len = %d data = %08x\n", + hostno, len, data); +#endif + + +} else +#endif + +{ +/* + * We loop as long as we are in a data out phase, there is data to send, + * and BSY is still active. + */ + __asm__ ( + +/* + Local variables : + len = ecx + data = esi + st0x_cr_sr = ebx + st0x_dr = edi + + Test for any data here at all. +*/ + "\torl %%ecx, %%ecx + jz 2f + + cld + + movl _st0x_cr_sr, %%ebx + movl _st0x_dr, %%edi + +1: movb (%%ebx), %%al\n" +/* + Test for BSY +*/ + + "\ttest $1, %%al + jz 2f\n" + +/* + Test for data out phase - STATUS & REQ_MASK should be REQ_DATAOUT, which is 0. +*/ + "\ttest $0xe, %%al + jnz 2f \n" +/* + Test for REQ +*/ + "\ttest $0x10, %%al + jz 1b + lodsb + movb %%al, (%%edi) + loop 1b + +2: + ": +/* output */ +"=S" (data), "=c" (len) : +/* input */ +"0" (data), "1" (len) : +/* clobbered */ +"eax", "ebx", "edi"); +} + + if (!len && nobuffs) { + --nobuffs; + ++buffer; + len = buffer->length; + data = (unsigned char *) buffer->address; +#if (DEBUG & DEBUG_SG) + printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n", + hostno, len, data); +#endif + } + break; + + case REQ_DATAIN : +#ifdef SLOW_HANDSHAKE + if (borken) { +#if (DEBUG & (PHASE_DATAIN)) + transfered += len; +#endif + for (; len && (STATUS & (REQ_MASK | STAT_REQ)) == (REQ_DATAIN | + STAT_REQ); --len) { + *data++ = DATA; + borken_wait(); +} +#if (DEBUG & (PHASE_DATAIN)) + transfered -= len; +#endif + } else +#endif +#ifdef FAST +if (fast && transfersize && !(len % transfersize) && (len >= transfersize) +#ifdef FAST32 + && !(transfersize % 4) +#endif + ) { +#if (DEBUG & DEBUG_FAST) + printk("scsi%d : FAST transfer, underflow = %d, transfersize = %d\n" + " len = %d, data = %08x\n", hostno, SCint->underflow, + SCint->transfersize, len, data); +#endif + __asm__(" + cld; +" +#ifdef FAST32 +" shr $2, %%ecx; +1: movl (%%esi), %%eax; + stosl; +" +#else +"1: movb (%%esi), %%al; + stosb; +" +#endif + +" loop 1b;" : : + /* input */ + "S" (st0x_dr), "D" (data), "c" (SCint->transfersize) : + /* clobbered */ + "eax", "ecx", "edi"); + + len -= transfersize; + data += transfersize; + +#if (DEBUG & PHASE_DATAIN) + printk("scsi%d: transfered += %d\n", hostno, transfersize); + transfered += transfersize; +#endif + +#if (DEBUG & DEBUG_FAST) + printk("scsi%d : FAST transfer complete len = %d data = %08x\n", + hostno, len, data); +#endif + +} else +#endif +{ + +#if (DEBUG & PHASE_DATAIN) + printk("scsi%d: transfered += %d\n", hostno, len); + transfered += len; /* Assume we'll transfer it all, then + subtract what we *didn't* transfer */ +#endif + +/* + * We loop as long as we are in a data in phase, there is room to read, + * and BSY is still active + */ + + __asm__ ( +/* + Local variables : + ecx = len + edi = data + esi = st0x_cr_sr + ebx = st0x_dr + + Test for room to read +*/ + "\torl %%ecx, %%ecx + jz 2f + + cld + movl _st0x_cr_sr, %%esi + movl _st0x_dr, %%ebx + +1: movb (%%esi), %%al\n" +/* + Test for BSY +*/ + + "\ttest $1, %%al + jz 2f\n" + +/* + Test for data in phase - STATUS & REQ_MASK should be REQ_DATAIN, = STAT_IO, which is 4. +*/ + "\tmovb $0xe, %%ah + andb %%al, %%ah + cmpb $0x04, %%ah + jne 2f\n" + +/* + Test for REQ +*/ + "\ttest $0x10, %%al + jz 1b + + movb (%%ebx), %%al + stosb + loop 1b\n" + +"2:\n" + : +/* output */ +"=D" (data), "=c" (len) : +/* input */ +"0" (data), "1" (len) : +/* clobbered */ +"eax","ebx", "esi"); + +#if (DEBUG & PHASE_DATAIN) + printk("scsi%d: transfered -= %d\n", hostno, len); + transfered -= len; /* Since we assumed all of Len got + * transfered, correct our mistake */ +#endif +} + + if (!len && nobuffs) { + --nobuffs; + ++buffer; + len = buffer->length; + data = (unsigned char *) buffer->address; +#if (DEBUG & DEBUG_SG) + printk("scsi%d : next scatter-gather buffer len = %d address = %08x\n", + hostno, len, data); +#endif + } + + break; + + case REQ_CMDOUT : + while (((status_read = STATUS) & STAT_BSY) && + ((status_read & REQ_MASK) == REQ_CMDOUT)) + if (status_read & STAT_REQ) { + DATA = *(unsigned char *) cmnd; + cmnd = 1+(unsigned char *) cmnd; +#ifdef SLOW_HANDSHAKE + if (borken) + borken_wait(); +#endif + } + break; + + case REQ_STATIN : + status = DATA; + break; + + case REQ_MSGOUT : +/* + * We can only have sent a MSG OUT if we requested to do this + * by raising ATTN. So, we must drop ATTN. + */ + + CONTROL = BASE_CMD | CMD_DRVR_ENABLE; +/* + * If we are reconecting, then we must send an IDENTIFY message in + * response to MSGOUT. + */ + switch (reselect) { + case CAN_RECONNECT: + DATA = IDENTIFY(1, lun); + +#if (DEBUG & (PHASE_RESELECT | PHASE_MSGOUT)) + printk("scsi%d : sent IDENTIFY message.\n", hostno); +#endif + break; +#ifdef LINKED + case LINKED_WRONG: + DATA = ABORT; + linked_connected = 0; + reselect = CAN_RECONNECT; + goto connect_loop; +#if (DEBUG & (PHASE_MSGOUT | DEBUG_LINKED)) + printk("scsi%d : sent ABORT message to cancle incorrect I_T_L nexus.\n", hostno); +#endif +#endif /* LINKED */ +#if (DEBUG & DEBUG_LINKED) + printk("correct\n"); +#endif + default: + DATA = NOP; + printk("scsi%d : target %d requested MSGOUT, sent NOP message.\n", hostno, target); + } + break; + + case REQ_MSGIN : + switch (message = DATA) { + case DISCONNECT : + should_reconnect = 1; + current_data = data; /* WDE add */ + current_buffer = buffer; + current_bufflen = len; /* WDE add */ + current_nobuffs = nobuffs; +#ifdef LINKED + linked_connected = 0; +#endif + done=1; +#if (DEBUG & (PHASE_RESELECT | PHASE_MSGIN)) + printk("scsi%d : disconnected.\n", hostno); +#endif + break; + +#ifdef LINKED + case LINKED_CMD_COMPLETE: + case LINKED_FLG_CMD_COMPLETE: +#endif + case COMMAND_COMPLETE : +/* + * Note : we should check for underflow here. + */ +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : command complete.\n", hostno); +#endif + done = 1; + break; + case ABORT : +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : abort message.\n", hostno); +#endif + done=1; + break; + case SAVE_POINTERS : + current_buffer = buffer; + current_bufflen = len; /* WDE add */ + current_data = data; /* WDE mod */ + current_nobuffs = nobuffs; +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : pointers saved.\n", hostno); +#endif + break; + case RESTORE_POINTERS: + buffer=current_buffer; + cmnd=current_cmnd; + data=current_data; /* WDE mod */ + len=current_bufflen; + nobuffs=current_nobuffs; +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : pointers restored.\n", hostno); +#endif + break; + default: + +/* + * IDENTIFY distinguishes itself from the other messages by setting the + * high byte. + * + * Note : we need to handle at least one outstanding command per LUN, + * and need to hash the SCSI command for that I_T_L nexus based on the + * known ID (at this point) and LUN. + */ + + if (message & 0x80) { +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : IDENTIFY message received from id %d, lun %d.\n", + hostno, target, message & 7); +#endif + } else { + +/* + * We should go into a MESSAGE OUT phase, and send a MESSAGE_REJECT + * if we run into a message that we don't like. The seagate driver + * needs some serious restructuring first though. + */ + +#if (DEBUG & PHASE_MSGIN) + printk("scsi%d : unknown message %d from target %d.\n", + hostno, message, target); +#endif + } + } + break; + + default : + printk("scsi%d : unknown phase.\n", hostno); + st0x_aborted = DID_ERROR; + } + +#ifdef SLOW_HANDSHAKE +/* + * I really don't care to deal with borken devices in each single + * byte transfer case (ie, message in, message out, status), so + * I'll do the wait here if necessary. + */ + if (borken) + borken_wait(); +#endif + + } /* if ends */ + } /* while ends */ + +#if (DEBUG & (PHASE_DATAIN | PHASE_DATAOUT | PHASE_EXIT)) + printk("scsi%d : Transfered %d bytes\n", hostno, transfered); +#endif + +#if (DEBUG & PHASE_EXIT) +#if 0 /* Doesn't work for scatter / gather */ + printk("Buffer : \n"); + for (i = 0; i < 20; ++i) + printk ("%02x ", ((unsigned char *) data)[i]); /* WDE mod */ + printk("\n"); +#endif + printk("scsi%d : status = ", hostno); + print_status(status); + printk("message = %02x\n", message); +#endif + + +/* We shouldn't reach this until *after* BSY has been deasserted */ +#ifdef notyet + if (st0x_aborted) { + if (STATUS & STAT_BSY) { + seagate_st0x_reset(NULL); + st0x_aborted = DID_RESET; + } + abort_confirm = 1; + } +#endif + +#ifdef LINKED +else { +/* + * Fix the message byte so that unsuspecting high level drivers don't + * puke when they see a LINKED COMMAND message in place of the COMMAND + * COMPLETE they may be expecting. Shouldn't be necessary, but it's + * better to be on the safe side. + * + * A non LINKED* message byte will indicate that the command completed, + * and we are now disconnected. + */ + + switch (message) { + case LINKED_CMD_COMPLETE : + case LINKED_FLG_CMD_COMPLETE : + message = COMMAND_COMPLETE; + linked_target = current_target; + linked_lun = current_lun; + linked_connected = 1; +#if (DEBUG & DEBUG_LINKED) + printk("scsi%d : keeping I_T_L nexus established for linked command.\n", + hostno); +#endif +/* + * We also will need to adjust status to accomodate intermediate conditions. + */ + if ((status == INTERMEDIATE_GOOD) || + (status == INTERMEDIATE_C_GOOD)) + status = GOOD; + + break; +/* + * We should also handle what are "normal" termination messages + * here (ABORT, BUS_DEVICE_RESET?, and COMMAND_COMPLETE individually, + * and flake if things aren't right. + */ + + default : +#if (DEBUG & DEBUG_LINKED) + printk("scsi%d : closing I_T_L nexus.\n", hostno); +#endif + linked_connected = 0; + } + } +#endif /* LINKED */ + + + + + if (should_reconnect) { +#if (DEBUG & PHASE_RESELECT) + printk("scsi%d : exiting seagate_st0x_queue_command() with reconnect enabled.\n", + hostno); +#endif + CONTROL = BASE_CMD | CMD_INTR ; + } else + CONTROL = BASE_CMD; + + return retcode (st0x_aborted); + } + +int seagate_st0x_abort (Scsi_Cmnd * SCpnt, int code) + { + if (code) + st0x_aborted = code; + else + st0x_aborted = DID_ABORT; + + return 0; + } + +/* + the seagate_st0x_reset function resets the SCSI bus +*/ + +int seagate_st0x_reset (Scsi_Cmnd * SCpnt) + { + unsigned clock; + /* + No timeouts - this command is going to fail because + it was reset. + */ + +#ifdef DEBUG + printk("In seagate_st0x_reset()\n"); +#endif + + + /* assert RESET signal on SCSI bus. */ + + CONTROL = BASE_CMD | CMD_RST; + clock=jiffies+2; + + + /* Wait. */ + + while (jiffies < clock); + + CONTROL = BASE_CMD; + + st0x_aborted = DID_RESET; + +#ifdef DEBUG + printk("SCSI bus reset.\n"); +#endif + if(SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + return 0; + } + +#ifdef CONFIG_BLK_DEV_SD + +#include +#include "sd.h" +#include "scsi_ioctl.h" + +int seagate_st0x_biosparam(int size, int dev, int* ip) { + unsigned char buf[256 + sizeof(int) * 2], cmd[6], *data, *page; + int *sizes, result, formatted_sectors, total_sectors; + int cylinders, heads, sectors; + + Scsi_Device *disk; + + disk = rscsi_disks[MINOR(dev) >> 4].device; + +/* + * Only SCSI-I CCS drives and later implement the necessary mode sense + * pages. + */ + + if (disk->scsi_level < 2) + return -1; + + sizes = (int *) buf; + data = (unsigned char *) (sizes + 2); + + cmd[0] = MODE_SENSE; + cmd[1] = (disk->lun << 5) & 0xe5; + cmd[2] = 0x04; /* Read page 4, rigid disk geometry page current values */ + cmd[3] = 0; + cmd[4] = 255; + cmd[5] = 0; + +/* + * We are transfering 0 bytes in the out direction, and expect to get back + * 24 bytes for each mode page. + */ + + sizes[0] = 0; + sizes[1] = 256; + + memcpy (data, cmd, 6); + + if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { +/* + * The mode page lies beyond the MODE SENSE header, with length 4, and + * the BLOCK DESCRIPTOR, with length header[3]. + */ + + page = data + 4 + data[3]; + heads = (int) page[5]; + cylinders = (page[2] << 16) | (page[3] << 8) | page[4]; + + cmd[2] = 0x03; /* Read page 3, format page current values */ + memcpy (data, cmd, 6); + + if (!(result = kernel_scsi_ioctl (disk, SCSI_IOCTL_SEND_COMMAND, (void *) buf))) { + page = data + 4 + data[3]; + sectors = (page[10] << 8) | page[11]; + + +/* + * Get the total number of formatted sectors from the block descriptor, + * so we can tell how many are being used for alternates. + */ + + formatted_sectors = (data[4 + 1] << 16) | (data[4 + 2] << 8) | + data[4 + 3] ; + + total_sectors = (heads * cylinders * sectors); + +/* + * Adjust the real geometry by subtracting + * (spare sectors / (heads * tracks)) cylinders from the number of cylinders. + * + * It appears that the CE cylinder CAN be a partial cylinder. + */ + + +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) + result = -1; + else + cylinders -= ((total_sectors - formatted_sectors) / (heads * sectors)); + +/* + * Now, we need to do a sanity check on the geometry to see if it is + * BIOS compatable. The maximum BIOS geometry is 1024 cylinders * + * 256 heads * 64 sectors. + */ + + if ((cylinders > 1024) || (sectors > 64)) + result = -1; + else { + ip[0] = heads; + ip[1] = sectors; + ip[2] = cylinders; + } + +/* + * There should be an alternate mapping for things the seagate doesn't + * understand, but I couldn't say what it is with reasonable certainty. + */ + + } + } + + return result; +} +#endif /* CONFIG_BLK_DEV_SD */ + +#endif /* defined(CONFIG_SCSI_SEGATE) */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.h new file mode 100644 index 000000000..fff3e3918 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/seagate.h @@ -0,0 +1,137 @@ +/* + * seagate.h Copyright (C) 1992 Drew Eckhardt + * low level scsi driver header for ST01/ST02 by + * Drew Eckhardt + * + * + */ + +#ifndef _SEAGATE_H + #define SEAGATE_H +/* + $Header +*/ +#ifndef ASM +int seagate_st0x_detect(int); +int seagate_st0x_command(Scsi_Cmnd *); +int seagate_st0x_queue_command(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); + +int seagate_st0x_abort(Scsi_Cmnd *, int); +const char *seagate_st0x_info(void); +int seagate_st0x_reset(Scsi_Cmnd *); + +#ifndef NULL + #define NULL 0 +#endif + +#ifdef CONFIG_BLK_DEV_SD +int seagate_st0x_biosparam(int, int, int*); +#else +#define seagate_st0x_biosparam NULL +#endif + +#define SEAGATE_ST0X {"Seagate ST-01/ST-02", seagate_st0x_detect, \ + seagate_st0x_info, seagate_st0x_command, \ + seagate_st0x_queue_command, seagate_st0x_abort, \ + seagate_st0x_reset, NULL, seagate_st0x_biosparam, \ + 1, 7, SG_ALL, 1, 0, 0} +#endif + + +/* + defining PARITY causes parity data to be checked +*/ + +#define PARITY + + +/* + Thanks to Brian Antoine for the example code in his Messy-Loss ST-01 + driver, and Mitsugu Suzuki for information on the ST-01 + SCSI host. +*/ + +/* + CONTROL defines +*/ + +#define CMD_RST 0x01 +#define CMD_SEL 0x02 +#define CMD_BSY 0x04 +#define CMD_ATTN 0x08 +#define CMD_START_ARB 0x10 +#define CMD_EN_PARITY 0x20 +#define CMD_INTR 0x40 +#define CMD_DRVR_ENABLE 0x80 + +/* + STATUS +*/ + +#define STAT_BSY 0x01 +#define STAT_MSG 0x02 +#define STAT_IO 0x04 +#define STAT_CD 0x08 +#define STAT_REQ 0x10 +#define STAT_SEL 0x20 +#define STAT_PARITY 0x40 +#define STAT_ARB_CMPL 0x80 + +/* + REQUESTS +*/ + +#define REQ_MASK (STAT_CD | STAT_IO | STAT_MSG) +#define REQ_DATAOUT 0 +#define REQ_DATAIN STAT_IO +#define REQ_CMDOUT STAT_CD +#define REQ_STATIN (STAT_CD | STAT_IO) +#define REQ_MSGOUT (STAT_MSG | STAT_CD) +#define REQ_MSGIN (STAT_MSG | STAT_CD | STAT_IO) + +extern volatile int seagate_st0x_timeout; + +#ifdef PARITY + #define BASE_CMD CMD_EN_PARITY +#else + #define BASE_CMD 0 +#endif + +/* + Debugging code +*/ + +#define PHASE_BUS_FREE 1 +#define PHASE_ARBITRATION 2 +#define PHASE_SELECTION 4 +#define PHASE_DATAIN 8 +#define PHASE_DATAOUT 0x10 +#define PHASE_CMDOUT 0x20 +#define PHASE_MSGIN 0x40 +#define PHASE_MSGOUT 0x80 +#define PHASE_STATUSIN 0x100 +#define PHASE_ETC (PHASE_DATAIN | PHASE_DATA_OUT | PHASE_CMDOUT | PHASE_MSGIN | PHASE_MSGOUT | PHASE_STATUSIN) +#define PRINT_COMMAND 0x200 +#define PHASE_EXIT 0x400 +#define PHASE_RESELECT 0x800 +#define DEBUG_FAST 0x1000 +#define DEBUG_SG 0x2000 +#define DEBUG_LINKED 0x4000 +#define DEBUG_BORKEN 0x8000 + +/* + * Control options - these are timeouts specified in .01 seconds. + */ + +/* 30, 20 work */ +#define ST0X_BUS_FREE_DELAY 25 +#define ST0X_SELECTION_DELAY 25 + +#define eoi() __asm__("push %%eax\nmovb $0x20, %%al\noutb %%al, $0x20\npop %%eax"::) + +#define SEAGATE 1 /* these determine the type of the controller */ +#define FD 2 + + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.c new file mode 100644 index 000000000..39e11d4f0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.c @@ -0,0 +1,336 @@ +/* + 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "scsi_ioctl.h" +#include "sg.h" + +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 (sizesignal & ~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 (countpending) + { + 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(SCSI_GENERIC_MAJOR,"sg",&sg_fops)) + { + printk("Unable to get major %d for generic SCSI device\n", + SCSI_GENERIC_MAJOR); + 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sg.h new file mode 100644 index 000000000..a28c8dbab --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.c new file mode 100644 index 000000000..380cedeae --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.c @@ -0,0 +1,751 @@ +/* + * sr.c by David Giller + * + * adapted from: + * sd.c Copyright (C) 1992 Drew Eckhardt + * Linux scsi disk driver by + * Drew Eckhardt + * + * + * + * Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR SCSI_CDROM_MAJOR +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "sr.h" +#include "scsi_ioctl.h" /* For the door lock/unlock commands */ +#include "constants.h" + +#define MAX_RETRIES 1 +#define SR_TIMEOUT 500 + +int NR_SR=0; +int MAX_SR=0; +Scsi_CD * scsi_CDs; +static int * sr_sizes; + +static int * sr_blocksizes; + +static int sr_open(struct inode *, struct file *); +static void get_sectorsize(int); + +extern int sr_ioctl(struct inode *, struct file *, unsigned int, unsigned long); + +void requeue_sr_request (Scsi_Cmnd * SCpnt); + +static void sr_release(struct inode * inode, struct file * file) +{ + sync_dev(inode->i_rdev); + if(! --scsi_CDs[MINOR(inode->i_rdev)].device->access_count) + sr_ioctl(inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); +} + +static struct file_operations sr_fops = +{ + NULL, /* lseek - default */ + block_read, /* read - general block-dev read */ + block_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + sr_ioctl, /* ioctl */ + NULL, /* mmap */ + sr_open, /* no special open code */ + sr_release, /* release */ + NULL /* fsync */ +}; + +/* + * This function checks to see if the media has been changed in the + * CDROM drive. It is possible that we have already sensed a change, + * or the drive may have sensed one and not yet reported it. We must + * be ready for either case. This function always reports the current + * value of the changed bit. If flag is 0, then the changed bit is reset. + * This function could be done as an ioctl, but we would need to have + * an inode for that to work, and we do not always have one. + */ + +int check_cdrom_media_change(int full_dev, int flag){ + int retval, target; + struct inode inode; + + target = MINOR(full_dev); + + if (target >= NR_SR) { + printk("CD-ROM request error: invalid device.\n"); + return 0; + }; + + inode.i_rdev = full_dev; /* This is all we really need here */ + retval = sr_ioctl(&inode, NULL, SCSI_IOCTL_TEST_UNIT_READY, 0); + + if(retval){ /* Unable to test, unit probably not ready. This usually + means there is no disc in the drive. Mark as changed, + and we will figure it out later once the drive is + available again. */ + + scsi_CDs[target].device->changed = 1; + return 1; /* This will force a flush, if called from + check_disk_change */ + }; + + retval = scsi_CDs[target].device->changed; + if(!flag) { + scsi_CDs[target].device->changed = 0; + /* If the disk changed, the capacity will now be different, + so we force a re-read of this information */ + if (retval) scsi_CDs[target].needs_sector_size = 1; + }; + return retval; +} + +/* + * rw_intr is the interrupt routine for the device driver. It will be notified on the + * end of a SCSI read / write, and will take on of several actions based on success or failure. + */ + +static void rw_intr (Scsi_Cmnd * SCpnt) +{ + int result = SCpnt->result; + int this_count = SCpnt->this_count; + +#ifdef DEBUG + printk("sr.c done: %x %x\n",result, SCpnt->request.bh->b_data); +#endif + if (!result) + { /* No error */ + if (SCpnt->use_sg == 0) { + if (SCpnt->buffer != SCpnt->request.buffer) + { + int offset; + offset = (SCpnt->request.sector % 4) << 9; + memcpy((char *)SCpnt->request.buffer, + (char *)SCpnt->buffer + offset, + this_count << 9); + /* Even though we are not using scatter-gather, we look + ahead and see if there is a linked request for the + other half of this buffer. If there is, then satisfy + it. */ + if((offset == 0) && this_count == 2 && + SCpnt->request.nr_sectors > this_count && + SCpnt->request.bh && + SCpnt->request.bh->b_reqnext && + SCpnt->request.bh->b_reqnext->b_size == 1024) { + memcpy((char *)SCpnt->request.bh->b_reqnext->b_data, + (char *)SCpnt->buffer + 1024, + 1024); + this_count += 2; + }; + + scsi_free(SCpnt->buffer, 2048); + } + } else { + struct scatterlist * sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for(i=0; iuse_sg; i++) { + if (sgpnt[i].alt_address) { + if (sgpnt[i].alt_address != sgpnt[i].address) { + memcpy(sgpnt[i].alt_address, sgpnt[i].address, sgpnt[i].length); + }; + scsi_free(sgpnt[i].address, sgpnt[i].length); + }; + }; + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + if(SCpnt->request.sector % 4) this_count -= 2; +/* See if there is a padding record at the end that needs to be removed */ + if(this_count > SCpnt->request.nr_sectors) + this_count -= 2; + }; + +#ifdef DEBUG + printk("(%x %x %x) ",SCpnt->request.bh, SCpnt->request.nr_sectors, + this_count); +#endif + if (SCpnt->request.nr_sectors > this_count) + { + SCpnt->request.errors = 0; + if (!SCpnt->request.bh) + panic("sr.c: linked page request (%lx %x)", + SCpnt->request.sector, this_count); + } + + end_scsi_request(SCpnt, 1, this_count); /* All done */ + requeue_sr_request(SCpnt); + return; + } /* Normal completion */ + + /* We only come through here if we have an error of some kind */ + +/* Free up any indirection buffers we allocated for DMA purposes. */ + if (SCpnt->use_sg) { + struct scatterlist * sgpnt; + int i; + sgpnt = (struct scatterlist *) SCpnt->buffer; + for(i=0; iuse_sg; i++) { + if (sgpnt[i].alt_address) { + scsi_free(sgpnt[i].address, sgpnt[i].length); + }; + }; + scsi_free(SCpnt->buffer, SCpnt->sglist_len); /* Free list of scatter-gather pointers */ + } else { + if (SCpnt->buffer != SCpnt->request.buffer) + scsi_free(SCpnt->buffer, SCpnt->bufflen); + }; + + if (driver_byte(result) != 0) { + if ((SCpnt->sense_buffer[0] & 0x7f) == 0x70) { + if ((SCpnt->sense_buffer[2] & 0xf) == UNIT_ATTENTION) { + /* detected disc change. set a bit and quietly refuse */ + /* further access. */ + + scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->changed = 1; + end_scsi_request(SCpnt, 0, this_count); + requeue_sr_request(SCpnt); + return; + } + } + + if (SCpnt->sense_buffer[2] == ILLEGAL_REQUEST) { + printk("CD-ROM error: Drive reports ILLEGAL REQUEST.\n"); + if (scsi_CDs[DEVICE_NR(SCpnt->request.dev)].ten) { + scsi_CDs[DEVICE_NR(SCpnt->request.dev)].ten = 0; + requeue_sr_request(SCpnt); + result = 0; + return; + } else { + printk("CD-ROM error: Drive reports %d.\n", SCpnt->sense_buffer[2]); + end_scsi_request(SCpnt, 0, this_count); + requeue_sr_request(SCpnt); /* Do next request */ + return; + } + + } + + if (SCpnt->sense_buffer[2] == NOT_READY) { + printk("CDROM not ready. Make sure you have a disc in the drive.\n"); + end_scsi_request(SCpnt, 0, this_count); + requeue_sr_request(SCpnt); /* Do next request */ + return; + }; + } + + /* 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->host_no, + scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->id, + scsi_CDs[DEVICE_NR(SCpnt->request.dev)].device->lun, + result); + + if (status_byte(result) == CHECK_CONDITION) + print_sense("sr", SCpnt); + + end_scsi_request(SCpnt, 0, SCpnt->request.current_nr_sectors); + requeue_sr_request(SCpnt); + } +} + +static int sr_open(struct inode * inode, struct file * filp) +{ + if(MINOR(inode->i_rdev) >= NR_SR || + !scsi_CDs[MINOR(inode->i_rdev)].device) return -ENODEV; /* No such device */ + + check_disk_change(inode->i_rdev); + + if(!scsi_CDs[MINOR(inode->i_rdev)].device->access_count++) + sr_ioctl(inode, NULL, SCSI_IOCTL_DOORLOCK, 0); + + /* If this device did not have media in the drive at boot time, then + we would have been unable to get the sector size. Check to see if + this is the case, and try again. + */ + + if(scsi_CDs[MINOR(inode->i_rdev)].needs_sector_size) + get_sectorsize(MINOR(inode->i_rdev)); + + return 0; +} + + +/* + * do_sr_request() is the request handler function for the sr driver. Its function in life + * is to take block device requests, and translate them to SCSI commands. + */ + +static void do_sr_request (void) +{ + Scsi_Cmnd * SCpnt = NULL; + struct request * req = NULL; + int flag = 0; + + while (1==1){ + cli(); + if (CURRENT != NULL && CURRENT->dev == -1) { + sti(); + return; + }; + + INIT_SCSI_REQUEST; + + if (flag++ == 0) + SCpnt = allocate_device(&CURRENT, + scsi_CDs[DEVICE_NR(MINOR(CURRENT->dev))].device->index, 0); + 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 + make a big difference on systems with more than one disk drive. We want + to have the interrupts off when monkeying with the request list, because + otherwise the kernel might try and slip in a request inbetween somewhere. */ + + if (!SCpnt && NR_SR > 1){ + struct request *req1; + req1 = NULL; + cli(); + req = CURRENT; + while(req){ + SCpnt = request_queueable(req, + scsi_CDs[DEVICE_NR(MINOR(req->dev))].device->index); + if(SCpnt) break; + req1 = req; + req = req->next; + }; + if (SCpnt && req->dev == -1) { + if (req == CURRENT) + CURRENT = CURRENT->next; + else + req1->next = req->next; + }; + sti(); + }; + + if (!SCpnt) + return; /* Could not find anything to do */ + + wake_up(&wait_for_request); + +/* Queue command */ + requeue_sr_request(SCpnt); + }; /* While */ +} + +void requeue_sr_request (Scsi_Cmnd * SCpnt) +{ + unsigned int dev, block, realcount; + unsigned char cmd[10], *buffer, tries; + int this_count, start, end_rec; + + tries = 2; + + repeat: + if(SCpnt->request.dev <= 0) { + do_sr_request(); + return; + } + + dev = MINOR(SCpnt->request.dev); + block = SCpnt->request.sector; + buffer = NULL; + this_count = 0; + + if (dev >= NR_SR) + { + /* printk("CD-ROM request error: invalid device.\n"); */ + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + tries = 2; + goto repeat; + } + + if (!scsi_CDs[dev].use) + { + /* printk("CD-ROM request error: device marked not in use.\n"); */ + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + tries = 2; + goto repeat; + } + + if (scsi_CDs[dev].device->changed) + { +/* + * quietly refuse to do anything to a changed disc until the changed bit has been reset + */ + /* printk("CD-ROM has been changed. Prohibiting further I/O.\n"); */ + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + tries = 2; + goto repeat; + } + + switch (SCpnt->request.cmd) + { + case WRITE: + end_scsi_request(SCpnt, 0, SCpnt->request.nr_sectors); + goto repeat; + break; + case READ : + cmd[0] = READ_6; + break; + default : + panic ("Unknown sr command %d\n", SCpnt->request.cmd); + } + + cmd[1] = (SCpnt->lun << 5) & 0xe0; + +/* + Now do the grungy work of figuring out which sectors we need, and + where in memory we are going to put them. + + The variables we need are: + + this_count= number of 512 byte sectors being read + block = starting cdrom sector to read. + realcount = # of cdrom sectors to read + + The major difference between a scsi disk and a scsi cdrom +is that we will always use scatter-gather if we can, because we can +work around the fact that the buffer cache has a block size of 1024, +and we have 2048 byte sectors. This code should work for buffers that +are any multiple of 512 bytes long. */ + + SCpnt->use_sg = 0; + + if (SCpnt->host->sg_tablesize > 0 && + (!need_isa_buffer || + dma_free_sectors >= 10)) { + struct buffer_head * bh; + struct scatterlist * sgpnt; + int count, this_count_max; + bh = SCpnt->request.bh; + this_count = 0; + count = 0; + this_count_max = (scsi_CDs[dev].ten ? 0xffff : 0xff) << 4; + /* Calculate how many links we can use. First see if we need + a padding record at the start */ + this_count = SCpnt->request.sector % 4; + if(this_count) count++; + 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++; + bh = bh->b_reqnext; + }; + /* Fix up in case of an odd record at the end */ + end_rec = 0; + if(this_count % 4) { + if (count < SCpnt->host->sg_tablesize) { + count++; + end_rec = (4 - (this_count % 4)) << 9; + this_count += 4 - (this_count % 4); + } else { + count--; + this_count -= (this_count % 4); + }; + }; + SCpnt->use_sg = count; /* Number of chains */ + count = 512;/* scsi_malloc can only allocate in chunks of 512 bytes*/ + while( count < (SCpnt->use_sg * sizeof(struct scatterlist))) + count = count << 1; + SCpnt->sglist_len = count; + sgpnt = (struct scatterlist * ) scsi_malloc(count); + if (!sgpnt) { + printk("Warning - running *really* short on DMA buffers\n"); + SCpnt->use_sg = 0; /* No memory left - bail out */ + } else { + buffer = (unsigned char *) sgpnt; + count = 0; + bh = SCpnt->request.bh; + if(SCpnt->request.sector % 4) { + sgpnt[count].length = (SCpnt->request.sector % 4) << 9; + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + if(!sgpnt[count].address) panic("SCSI DMA pool exhausted."); + sgpnt[count].alt_address = sgpnt[count].address; /* Flag to delete + if needed */ + count++; + }; + for(bh = SCpnt->request.bh; count < SCpnt->use_sg; + count++, bh = bh->b_reqnext) { + if (bh) { /* Need a placeholder at the end of the record? */ + sgpnt[count].address = bh->b_data; + sgpnt[count].length = bh->b_size; + sgpnt[count].alt_address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(end_rec); + if(!sgpnt[count].address) panic("SCSI DMA pool exhausted."); + sgpnt[count].length = end_rec; + sgpnt[count].alt_address = sgpnt[count].address; + if (count+1 != SCpnt->use_sg) panic("Bad sr request list"); + break; + }; + if (((int) sgpnt[count].address) + sgpnt[count].length > + 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 + pressing need, and we would be screwed if we ran out */ + if(dma_free_sectors < (sgpnt[count].length >> 9) + 5) { + sgpnt[count].address = NULL; + } else { + sgpnt[count].address = (char *) scsi_malloc(sgpnt[count].length); + }; +/* If we start running low on DMA buffers, we abort the scatter-gather + operation, and free all of the memory we have allocated. We want to + ensure that all scsi operations are able to do at least a non-scatter/gather + operation */ + if(sgpnt[count].address == NULL){ /* Out of dma memory */ + printk("Warning: Running low on SCSI DMA buffers"); + /* Try switching back to a non scatter-gather operation. */ + while(--count >= 0){ + if(sgpnt[count].alt_address) + scsi_free(sgpnt[count].address, sgpnt[count].length); + }; + SCpnt->use_sg = 0; + scsi_free(buffer, SCpnt->sglist_len); + break; + }; /* if address == NULL */ + }; /* if need DMA fixup */ + }; /* for loop to fill list */ +#ifdef DEBUG + printk("SG: %d %d %d %d %d *** ",SCpnt->use_sg, SCpnt->request.sector, + this_count, + SCpnt->request.current_nr_sectors, + SCpnt->request.nr_sectors); + for(count=0; countuse_sg; count++) + printk("SGlist: %d %x %x %x\n", count, + sgpnt[count].address, + sgpnt[count].alt_address, + sgpnt[count].length); +#endif + }; /* Able to allocate scatter-gather list */ + }; + + if (SCpnt->use_sg == 0){ + /* We cannot use scatter-gather. Do this the old fashion way */ + if (!SCpnt->request.bh) + this_count = SCpnt->request.nr_sectors; + else + this_count = (SCpnt->request.bh->b_size >> 9); + + start = block % 4; + if (start) + { + this_count = ((this_count > 4 - start) ? + (4 - start) : (this_count)); + buffer = (unsigned char *) scsi_malloc(2048); + } + else if (this_count < 4) + { + buffer = (unsigned char *) scsi_malloc(2048); + } + else + { + this_count -= this_count % 4; + buffer = (unsigned char *) SCpnt->request.buffer; + if (((int) buffer) + (this_count << 9) > ISA_DMA_THRESHOLD & + (SCpnt->host->unchecked_isa_dma)) + buffer = (unsigned char *) scsi_malloc(this_count << 9); + } + }; + + if (scsi_CDs[dev].sector_size == 2048) + block = block >> 2; /* These are the sectors that the cdrom uses */ + else + block = block & 0xfffffffc; + + realcount = (this_count + 3) / 4; + + if (scsi_CDs[dev].sector_size == 512) realcount = realcount << 2; + + if (((realcount > 0xff) || (block > 0x1fffff)) && scsi_CDs[dev].ten) + { + if (realcount > 0xffff) + { + realcount = 0xffff; + this_count = realcount * (scsi_CDs[dev].sector_size >> 9); + } + + cmd[0] += READ_10 - READ_6 ; + cmd[2] = (unsigned char) (block >> 24) & 0xff; + cmd[3] = (unsigned char) (block >> 16) & 0xff; + cmd[4] = (unsigned char) (block >> 8) & 0xff; + cmd[5] = (unsigned char) block & 0xff; + cmd[6] = cmd[9] = 0; + cmd[7] = (unsigned char) (realcount >> 8) & 0xff; + cmd[8] = (unsigned char) realcount & 0xff; + } + else + { + if (realcount > 0xff) + { + realcount = 0xff; + this_count = realcount * (scsi_CDs[dev].sector_size >> 9); + } + + cmd[1] |= (unsigned char) ((block >> 16) & 0x1f); + cmd[2] = (unsigned char) ((block >> 8) & 0xff); + cmd[3] = (unsigned char) block & 0xff; + cmd[4] = (unsigned char) realcount; + cmd[5] = 0; + } + +#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; + scsi_do_cmd (SCpnt, (void *) cmd, buffer, + realcount * scsi_CDs[dev].sector_size, + rw_intr, SR_TIMEOUT, MAX_RETRIES); +} + +unsigned long sr_init1(unsigned long mem_start, unsigned long mem_end){ + scsi_CDs = (Scsi_CD *) mem_start; + mem_start += MAX_SR * sizeof(Scsi_CD); + return mem_start; +}; + +void sr_attach(Scsi_Device * SDp){ + scsi_CDs[NR_SR++].device = SDp; + if(NR_SR > MAX_SR) panic ("scsi_devices corrupt (sr)"); +}; + +static void sr_init_done (Scsi_Cmnd * SCpnt) +{ + struct request * req; + struct task_struct * p; + + req = &SCpnt->request; + req->dev = 0xfffe; /* Busy, but indicate request done */ + + if ((p = req->waiting) != NULL) { + req->waiting = NULL; + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } +} + +static void get_sectorsize(int i){ + unsigned char cmd[10]; + unsigned char buffer[513]; + int the_result, retries; + Scsi_Cmnd * SCpnt; + + SCpnt = allocate_device(NULL, scsi_CDs[i].device->index, 1); + + retries = 3; + do { + cmd[0] = READ_CAPACITY; + cmd[1] = (scsi_CDs[i].device->lun << 5) & 0xe0; + memset ((void *) &cmd[2], 0, 8); + SCpnt->request.dev = 0xffff; /* Mark as really busy */ + + memset(buffer, 0, 8); + + scsi_do_cmd (SCpnt, + (void *) cmd, (void *) buffer, + 512, sr_init_done, SR_TIMEOUT, + MAX_RETRIES); + + if (current == task[0]) + while(SCpnt->request.dev != 0xfffe); + else + if (SCpnt->request.dev != 0xfffe){ + SCpnt->request.waiting = current; + current->state = TASK_UNINTERRUPTIBLE; + while (SCpnt->request.dev != 0xfffe) schedule(); + }; + + the_result = SCpnt->result; + retries--; + + } while(the_result && retries); + + SCpnt->request.dev = -1; /* Mark as not busy */ + + wake_up(&scsi_devices[SCpnt->index].device_wait); + + if (the_result) { + scsi_CDs[i].capacity = 0x1fffff; + scsi_CDs[i].sector_size = 2048; /* A guess, just in case */ + scsi_CDs[i].needs_sector_size = 1; + } else { + scsi_CDs[i].capacity = (buffer[0] << 24) | + (buffer[1] << 16) | (buffer[2] << 8) | buffer[3]; + scsi_CDs[i].sector_size = (buffer[4] << 24) | + (buffer[5] << 16) | (buffer[6] << 8) | buffer[7]; + if(scsi_CDs[i].sector_size == 0) scsi_CDs[i].sector_size = 2048; + if(scsi_CDs[i].sector_size != 2048 && + scsi_CDs[i].sector_size != 512) { + printk ("scd%d : unsupported sector size %d.\n", + i, scsi_CDs[i].sector_size); + scsi_CDs[i].capacity = 0; + scsi_CDs[i].needs_sector_size = 1; + }; + if(scsi_CDs[i].sector_size == 2048) + scsi_CDs[i].capacity *= 4; + scsi_CDs[i].needs_sector_size = 0; + }; +} + +unsigned long sr_init(unsigned long memory_start, unsigned long memory_end) +{ + int i; + + if (register_blkdev(MAJOR_NR,"sr",&sr_fops)) { + printk("Unable to get major %d for SCSI-CD\n",MAJOR_NR); + return memory_start; + } + if(MAX_SR == 0) return memory_start; + + sr_sizes = (int *) memory_start; + memory_start += MAX_SR * sizeof(int); + memset(sr_sizes, 0, MAX_SR * sizeof(int)); + + sr_blocksizes = (int *) memory_start; + memory_start += MAX_SR * sizeof(int); + for(i=0;ihost->sg_tablesize) + read_ahead[MAJOR_NR] = 32; /* 32 sector read-ahead. Always removable. */ + else + read_ahead[MAJOR_NR] = 4; /* 4 sector read-ahead */ + + return memory_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.h new file mode 100644 index 000000000..c02356759 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr.h @@ -0,0 +1,37 @@ +/* + * sr.h by David Giller + * CD-ROM disk driver header file + * + * adapted from: + * sd.h Copyright (C) 1992 Drew Eckhardt + * SCSI disk driver header file by + * Drew Eckhardt + * + * + * + * Modified by Eric Youngdale eric@tantalus.nrl.navy.mil to + * add scatter-gather, multiple outstanding request, and other + * enhancements. + */ + +#ifndef _SR_H +#define _SR_H + +#include "scsi.h" + +typedef struct + { + unsigned capacity; /* size in blocks */ + unsigned sector_size; /* size in bytes */ + Scsi_Device *device; + unsigned char sector_bit_size; /* sector size = 2^sector_bit_size */ + unsigned char sector_bit_shift; /* sectors/FS block = 2^sector_bit_shift*/ + unsigned needs_sector_size:1; /* needs to get sector size */ + unsigned ten:1; /* support ten byte commands */ + unsigned remap:1; /* support remapping */ + unsigned use:1; /* is this device still supportable */ + } Scsi_CD; + +extern Scsi_CD * scsi_CDs; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr_ioctl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr_ioctl.c new file mode 100644 index 000000000..c572fd0bf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/sr_ioctl.c @@ -0,0 +1,386 @@ +#include +#include +#include +#include +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" +#include "sr.h" +#include "scsi_ioctl.h" + +#include + +#define IOCTL_RETRIES 3 +/* The CDROM is fairly slow, so we need a little extra time */ +#define IOCTL_TIMEOUT 200 + +extern int scsi_ioctl (Scsi_Device *dev, int cmd, void *arg); + +static void sr_ioctl_done(Scsi_Cmnd * SCpnt) +{ + struct request * req; + struct task_struct * p; + + req = &SCpnt->request; + req->dev = 0xfffe; /* Busy, but indicate request done */ + + if ((p = req->waiting) != NULL) { + req->waiting = NULL; + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } +} + +/* We do our own retries because we want to know what the specific + error code is. Normally the UNIT_ATTENTION code will automatically + clear after one error */ + +static int do_ioctl(int target, unsigned char * sr_cmd, void * buffer, unsigned buflength) +{ + Scsi_Cmnd * SCpnt; + int result; + + SCpnt = allocate_device(NULL, scsi_CDs[target].device->index, 1); + scsi_do_cmd(SCpnt, + (void *) sr_cmd, buffer, buflength, sr_ioctl_done, + IOCTL_TIMEOUT, IOCTL_RETRIES); + + + if (SCpnt->request.dev != 0xfffe){ + SCpnt->request.waiting = current; + current->state = TASK_UNINTERRUPTIBLE; + while (SCpnt->request.dev != 0xfffe) schedule(); + }; + + result = SCpnt->result; + +/* Minimal error checking. Ignore cases we know about, and report the rest. */ + if(driver_byte(result) != 0) + switch(SCpnt->sense_buffer[2] & 0xf) { + case UNIT_ATTENTION: + scsi_CDs[target].device->changed = 1; + printk("Disc change detected.\n"); + break; + case NOT_READY: /* This happens if there is no disc in drive */ + printk("CDROM not ready. Make sure there is a disc in the drive.\n"); + break; + case ILLEGAL_REQUEST: + printk("CDROM (ioctl) reports ILLEGAL REQUEST.\n"); + break; + default: + printk("SCSI CD error: host %d id %d lun %d return code = %03x\n", + scsi_CDs[target].device->host->host_no, + scsi_CDs[target].device->id, + scsi_CDs[target].device->lun, + result); + printk("\tSense class %x, sense error %x, extended sense %x\n", + sense_class(SCpnt->sense_buffer[0]), + sense_error(SCpnt->sense_buffer[0]), + SCpnt->sense_buffer[2] & 0xf); + + }; + + result = SCpnt->result; + SCpnt->request.dev = -1; /* Deallocate */ + wake_up(&scsi_devices[SCpnt->index].device_wait); + /* Wake up a process waiting for device*/ + return result; +} + +int sr_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg) +{ + u_char sr_cmd[10]; + + int dev = inode->i_rdev; + int result, target; + + target = MINOR(dev); + if (target >= NR_SR) return -ENODEV; + + switch (cmd) + { + /* Sun-compatible */ + case CDROMPAUSE: + + sr_cmd[0] = SCMD_PAUSE_RESUME; + sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; + sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; + sr_cmd[8] = 0; + sr_cmd[9] = 0; + + result = do_ioctl(target, sr_cmd, NULL, 255); + return result; + + case CDROMRESUME: + + sr_cmd[0] = SCMD_PAUSE_RESUME; + sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = 0; + sr_cmd[5] = sr_cmd[6] = sr_cmd[7] = 0; + sr_cmd[8] = 1; + sr_cmd[9] = 0; + + result = do_ioctl(target, sr_cmd, NULL, 255); + + return result; + + case CDROMPLAYMSF: + { + struct cdrom_msf msf; + memcpy_fromfs(&msf, (void *) arg, sizeof(msf)); + + sr_cmd[0] = SCMD_PLAYAUDIO_MSF; + sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[2] = 0; + sr_cmd[3] = msf.cdmsf_min0; + sr_cmd[4] = msf.cdmsf_sec0; + sr_cmd[5] = msf.cdmsf_frame0; + sr_cmd[6] = msf.cdmsf_min1; + sr_cmd[7] = msf.cdmsf_sec1; + sr_cmd[8] = msf.cdmsf_frame1; + sr_cmd[9] = 0; + + result = do_ioctl(target, sr_cmd, NULL, 255); + return result; + } + + case CDROMPLAYTRKIND: + { + struct cdrom_ti ti; + memcpy_fromfs(&ti, (void *) arg, sizeof(ti)); + + sr_cmd[0] = SCMD_PLAYAUDIO_TI; + sr_cmd[1] = scsi_CDs[target].device->lun << 5; + sr_cmd[2] = 0; + sr_cmd[3] = 0; + sr_cmd[4] = ti.cdti_trk0; + sr_cmd[5] = ti.cdti_ind0; + sr_cmd[6] = 0; + sr_cmd[7] = ti.cdti_trk1; + sr_cmd[8] = ti.cdti_ind1; + sr_cmd[9] = 0; + + result = do_ioctl(target, sr_cmd, NULL, 255); + + return result; + } + + case CDROMREADTOCHDR: + { + struct cdrom_tochdr tochdr; + char * buffer; + + sr_cmd[0] = SCMD_READ_TOC; + sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ + sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; + sr_cmd[6] = 0; + sr_cmd[7] = 0; /* MSB of length (12) */ + sr_cmd[8] = 12; /* LSB of length */ + sr_cmd[9] = 0; + + 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)); + + return result; + } + + case CDROMREADTOCENTRY: + { + struct cdrom_tocentry tocentry; + char * buffer; + + verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_tocentry)); + memcpy_fromfs (&tocentry, (void *) arg, sizeof (struct cdrom_tocentry)); + + sr_cmd[0] = SCMD_READ_TOC; + sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ + sr_cmd[2] = sr_cmd[3] = sr_cmd[4] = sr_cmd[5] = 0; + sr_cmd[6] = tocentry.cdte_track; + sr_cmd[7] = 0; /* MSB of length (12) */ + sr_cmd[8] = 12; /* LSB of length */ + sr_cmd[9] = 0; + + 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]; + tocentry.cdte_addr.msf.second = buffer[10]; + tocentry.cdte_addr.msf.frame = buffer[11]; + tocentry.cdte_ctrl = buffer[5] & 0xf; + } + 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)); + + return result; + } + + case CDROMSTOP: + sr_cmd[0] = START_STOP; + sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; + sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; + sr_cmd[4] = 0; + + result = do_ioctl(target, sr_cmd, NULL, 255); + return result; + + case CDROMSTART: + sr_cmd[0] = START_STOP; + sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 1; + sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; + sr_cmd[4] = 1; + + result = do_ioctl(target, sr_cmd, NULL, 255); + return result; + + case CDROMEJECT: + if (scsi_CDs[target].device -> access_count == 1) + sr_ioctl (inode, NULL, SCSI_IOCTL_DOORUNLOCK, 0); + + sr_cmd[0] = START_STOP; + sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 1; + sr_cmd[2] = sr_cmd[3] = sr_cmd[5] = 0; + sr_cmd[4] = 0x02; + + if (!(result = do_ioctl(target, sr_cmd, NULL, 255))) + scsi_CDs[target].device -> changed = 1; + + return result; + + case CDROMVOLCTRL: + { + char * buffer, * mask; + struct cdrom_volctrl volctrl; + + verify_area (VERIFY_READ, (void *) arg, sizeof (struct cdrom_volctrl)); + memcpy_fromfs (&volctrl, (void *) arg, sizeof (struct cdrom_volctrl)); + + /* First we get the current params so we can just twiddle the volume */ + + sr_cmd[0] = MODE_SENSE; + sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; + sr_cmd[2] = 0xe; /* Want mode page 0xe, CDROM audio params */ + sr_cmd[3] = 0; + sr_cmd[4] = 28; + sr_cmd[5] = 0; + + 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; + } + + sr_cmd[0] = MODE_SENSE; + sr_cmd[1] = (scsi_CDs[target].device -> lun) << 5; + sr_cmd[2] = 0x4e; /* Want the mask for mode page 0xe */ + sr_cmd[3] = 0; + sr_cmd[4] = 28; + sr_cmd[5] = 0; + + 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; + } + + /* Now mask and substitute our own volume and reuse the rest */ + buffer[0] = 0; /* Clear reserved field */ + + buffer[21] = volctrl.channel0 & mask[21]; + buffer[23] = volctrl.channel1 & mask[23]; + buffer[25] = volctrl.channel2 & mask[25]; + buffer[27] = volctrl.channel3 & mask[27]; + + sr_cmd[0] = MODE_SELECT; + sr_cmd[1] = ((scsi_CDs[target].device -> lun) << 5) | 0x10; /* Params are SCSI-2 */ + sr_cmd[2] = sr_cmd[3] = 0; + sr_cmd[4] = 28; + sr_cmd[5] = 0; + + 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; + + sr_cmd[0] = SCMD_READ_SUBCHANNEL; + sr_cmd[1] = ((scsi_CDs[target].device->lun) << 5) | 0x02; /* MSF format */ + sr_cmd[2] = 0x40; /* I do want the subchannel info */ + sr_cmd[3] = 0x01; /* Give me current position info */ + sr_cmd[4] = sr_cmd[5] = 0; + sr_cmd[6] = 0; + sr_cmd[7] = 0; + sr_cmd[8] = 16; + sr_cmd[9] = 0; + + 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; + subchnl.cdsc_ctrl = buffer[5] & 0xf; + subchnl.cdsc_trk = buffer[6]; + subchnl.cdsc_ind = buffer[7]; + + subchnl.cdsc_reladdr.msf.minute = buffer[13]; + subchnl.cdsc_reladdr.msf.second = buffer[14]; + subchnl.cdsc_reladdr.msf.frame = buffer[15]; + subchnl.cdsc_absaddr.msf.minute = buffer[9]; + 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; + } + + case CDROMREADMODE2: + return -EINVAL; + case CDROMREADMODE1: + return -EINVAL; + + RO_IOCTLS(dev,arg); + default: + return scsi_ioctl(scsi_CDs[target].device,cmd,(void *) arg); + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.c new file mode 100644 index 000000000..1e5c2e9a7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.c @@ -0,0 +1,1475 @@ +/* + SCSI Tape Driver for Linux + + Version 0.02 for Linux 0.98.4 and Eric Youngdale's new scsi driver + + History: + Rewritten from Dwayne Forsyth's SCSI tape driver by Kai Makisara. + Contribution and ideas from several people including Eric Youngdale and + Wolfgang Denk. + + Features: + - support for different block sizes and internal buffering + - support for fixed and variable block size (within buffer limit; + blocksize set to zero) + - *nix-style ioctl with codes from mtio.h from the QIC-02 driver by + Hennus Bergman (command MTSETBLK added) + - character device + - rewind and non-rewind devices + - capability to handle several tape drives simultaneously + - one buffer if one drive, two buffers if more than one drive (limits the + number of simultaneously open drives to two) + - write behind + - seek and tell (Tandberg compatible and SCSI-2) + + Devices: + Autorewind devices have minor numbers equal to the tape numbers (0 > ). + Nonrewind device has the minor number equal to tape number + 128. + + Problems: + The end of media detection works correctly in writing only if the drive + writes the buffer contents after the early-warning mark. If you want to + be sure that EOM is reported correctly, you should uncomment the line + defining ST_NO_DELAYED_WRITES. Note that when delayed writes are disabled + each write byte count must be an integral number of blocks. + + Copyright 1992, 1993 Kai Makisara + email makisara@vtinsx.ins.vtt.fi or Kai.Makisara@vtt.fi + + Last modified: Thu Nov 25 21:49:02 1993 by root@kai.home +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define MAJOR_NR SCSI_TAPE_MAJOR +#include "../block/blk.h" +#include "scsi.h" +#include "scsi_ioctl.h" +#include "st.h" +#include "constants.h" + +/* Uncomment the following if you want the rewind, etc. commands return + before command completion. */ +/* #define ST_NOWAIT */ + +/* Uncomment the following if you want the tape to be positioned correctly + within file after close (the tape is positioned correctly with respect + to the filemarks even wihout ST_IN_FILE_POS defined */ +/* #define ST_IN_FILE_POS */ + +/* Uncomment the following if you want recovered write errors to be + fatal. */ +/* #define ST_RECOVERED_WRITE_FATAL */ + +/* Uncomment the following if you want all data from a write command to + be written to tape before the command returns. Disables write-behind. */ +/* #define ST_NO_DELAYED_WRITES */ + +/* Number of ST_BLOCK_SIZE blocks in the buffers */ +#define ST_BUFFER_BLOCKS 64 +/* Write-behind can be disabled by setting ST_WRITE_THRESHOLD_BLOCKS equal + to or larger than ST_BUFFER_BLOCKS */ +#define ST_WRITE_THRESHOLD_BLOCKS 60 +#define ST_BLOCK_SIZE 512 +#define ST_BUFFER_SIZE (ST_BUFFER_BLOCKS * ST_BLOCK_SIZE) +#define ST_WRITE_THRESHOLD (ST_WRITE_THRESHOLD_BLOCKS * ST_BLOCK_SIZE) + +#ifdef ST_NO_DELAYED_WRITES +#undef ST_WRITE_THRESHOLD_BLOCKS +#define ST_WRITE_THRESHOLD_BLOCKS ST_BUFFER_BLOCKS +#endif + +/* The buffer size should fit into the 24 bits reserved for length in the + 6-byte SCSI read and write commands. */ +#if ST_BUFFER_SIZE >= (2 << 24 - 1) +#error "Buffer size should not exceed (2 << 24 - 1) bytes!" +#endif + +/* #define DEBUG */ + +#define MAX_RETRIES 0 +#define MAX_READY_RETRIES 5 +#define NO_TAPE NOT_READY + +#define ST_TIMEOUT 9000 +#define ST_LONG_TIMEOUT 200000 + +static int st_nbr_buffers; +static ST_buffer *st_buffers[2]; + +static Scsi_Tape * scsi_tapes; +int NR_ST=0; +int MAX_ST=0; + +static int st_int_ioctl(struct inode * inode,struct file * file, + unsigned int cmd_in, unsigned long arg); + + + + +/* Convert the result to success code */ + static int +st_chk_result(Scsi_Cmnd * SCpnt) +{ + int dev = SCpnt->request.dev; + int result = SCpnt->result; + unsigned char * sense = SCpnt->sense_buffer; + char *stp; + + if (!result && SCpnt->sense_buffer[0] == 0) + return 0; +#ifdef DEBUG + printk("st%d: Error: %x\n", dev, result); + print_sense("st", SCpnt); +#endif +/* if ((sense[0] & 0x70) == 0x70 && + ((sense[2] & 0x80) )) + return 0; */ + if ((sense[0] & 0x70) == 0x70 && + sense[2] == RECOVERED_ERROR +#ifdef ST_RECOVERED_WRITE_FATAL + && SCpnt->cmnd[0] != WRITE_6 + && SCpnt->cmnd[0] != WRITE_FILEMARKS +#endif + ) { + scsi_tapes[dev].recover_count++; + if (SCpnt->cmnd[0] == READ_6) + stp = "read"; + else if (SCpnt->cmnd[0] == WRITE_6) + stp = "write"; + else + stp = "ioctl"; + printk("st%d: Recovered %s error (%d).\n", dev, stp, + scsi_tapes[dev].recover_count); + return 0; + } + return (-EIO); +} + + +/* Wakeup from interrupt */ + static void +st_sleep_done (Scsi_Cmnd * SCpnt) +{ + int st_nbr, remainder; + Scsi_Tape * STp; + + if ((st_nbr = SCpnt->request.dev) < NR_ST && st_nbr >= 0) { + STp = &(scsi_tapes[st_nbr]); + if ((STp->buffer)->writing && + (SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + /* EOM at write-behind, has all been written? */ + if ((SCpnt->sense_buffer[0] & 0x80) != 0) + remainder = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else + remainder = 0; + if ((SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW || + remainder > 0) + (STp->buffer)->last_result = SCpnt->result; /* Error */ + else + (STp->buffer)->last_result = INT_MAX; /* OK */ + } + else + (STp->buffer)->last_result = SCpnt->result; + (STp->buffer)->last_result_fatal = st_chk_result(SCpnt); + if ((STp->buffer)->writing) + SCpnt->request.dev = -1; + else + SCpnt->request.dev = 0xffff; + if ((STp->buffer)->writing <= 0) + wake_up( &(STp->waiting) ); + } +#ifdef DEBUG + else + printk("st?: Illegal interrupt device %x\n", st_nbr); +#endif +} + + +#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS +/* Handle the write-behind checking */ + static void +write_behind_check(int dev) +{ + Scsi_Tape * STp; + ST_buffer * STbuffer; + + STp = &(scsi_tapes[dev]); + STbuffer = STp->buffer; + + cli(); + if (STbuffer->last_result < 0) { + STbuffer->writing = (- STbuffer->writing); + sleep_on( &(STp->waiting) ); + STbuffer->writing = (- STbuffer->writing); + } + sti(); + + if (STbuffer->writing < STbuffer->buffer_bytes) + memcpy(STbuffer->b_data, + STbuffer->b_data + STbuffer->writing, + STbuffer->buffer_bytes - STbuffer->writing); + STbuffer->buffer_bytes -= STbuffer->writing; + STbuffer->writing = 0; + + return; +} +#endif + + +/* Flush the write buffer (never need to write if variable blocksize). */ + static int +flush_write_buffer(int dev) +{ + int offset, transfer, blks; + int result; + unsigned char cmd[10]; + Scsi_Cmnd *SCpnt; + Scsi_Tape *STp = &(scsi_tapes[dev]); + +#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS + if ((STp->buffer)->writing) { + write_behind_check(dev); + if ((STp->buffer)->last_result_fatal) { +#ifdef DEBUG + printk("st%d: Async write error %x.\n", dev, + (STp->buffer)->last_result); +#endif + if ((STp->buffer)->last_result == INT_MAX) + return (-ENOSPC); + return (-EIO); + } + } +#endif + + result = 0; + if (STp->dirty == 1) { + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + + offset = (STp->buffer)->buffer_bytes; + transfer = ((offset + STp->block_size - 1) / + STp->block_size) * STp->block_size; +#ifdef DEBUG + printk("st%d: Flushing %d bytes.\n", dev, transfer); +#endif + memset((STp->buffer)->b_data + offset, 0, transfer - offset); + + SCpnt->sense_buffer[0] = 0; + memset(cmd, 0, 10); + cmd[0] = WRITE_6; + cmd[1] = 1; + blks = transfer / STp->block_size; + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + SCpnt->request.dev = dev; + scsi_do_cmd (SCpnt, + (void *) cmd, (STp->buffer)->b_data, transfer, + st_sleep_done, ST_TIMEOUT, MAX_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if ((STp->buffer)->last_result_fatal != 0) { + printk("st%d: Error on flush.\n", dev); + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40) && + (SCpnt->sense_buffer[2] & 0x0f) != VOLUME_OVERFLOW) { + STp->dirty = 0; + (STp->buffer)->buffer_bytes = 0; + result = (-ENOSPC); + } + else + result = (-EIO); + } + else { + STp->dirty = 0; + (STp->buffer)->buffer_bytes = 0; + } + SCpnt->request.dev = -1; /* Mark as not busy */ + } + return result; +} + + +/* Flush the tape buffer. The tape will be positioned correctly unless + seek_next is true. */ + static int +flush_buffer(struct inode * inode, struct file * filp, int seek_next) +{ + int dev; + int backspace, result; + Scsi_Tape * STp; + ST_buffer * STbuffer; + + dev = MINOR(inode->i_rdev) & 127; + STp = &(scsi_tapes[dev]); + STbuffer = STp->buffer; + + if (STp->rw == ST_WRITING) /* Writing */ + return flush_write_buffer(dev); + + if (STp->block_size == 0) + return 0; + + backspace = ((STp->buffer)->buffer_bytes + + (STp->buffer)->read_pointer) / STp->block_size - + ((STp->buffer)->read_pointer + STp->block_size - 1) / + STp->block_size; + (STp->buffer)->buffer_bytes = 0; + (STp->buffer)->read_pointer = 0; + result = 0; + if (!seek_next) { + if ((STp->eof == ST_FM) && !STp->eof_hit) { + result = st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */ + if (!result) { + STp->eof = ST_NOEOF; + STp->eof_hit = 0; + } + } + if (!result && backspace > 0) + result = st_int_ioctl(inode, filp, MTBSR, backspace); + } + return result; + +} + + +/* Open the device */ + static int +scsi_tape_open(struct inode * inode, struct file * filp) +{ + int dev; + unsigned short flags; + int i; + unsigned char cmd[10]; + Scsi_Cmnd * SCpnt; + Scsi_Tape * STp; + + dev = MINOR(inode->i_rdev) & 127; + if (dev >= NR_ST) + return (-ENODEV); + STp = &(scsi_tapes[dev]); + if (STp->in_use) { + printk("st%d: Device already in use.\n", dev); + return (-EBUSY); + } + + /* Allocate buffer for this user */ + for (i=0; i < st_nbr_buffers; i++) + if (!st_buffers[i]->in_use) + break; + if (i >= st_nbr_buffers) { + printk("st%d: No free buffers.\n", dev); + return (-EBUSY); + } + STp->buffer = st_buffers[i]; + (STp->buffer)->in_use = 1; + (STp->buffer)->writing = 0; + STp->in_use = 1; + + flags = filp->f_flags; + STp->write_prot = ((flags & O_ACCMODE) == O_RDONLY); + + STp->dirty = 0; + STp->rw = ST_IDLE; + STp->eof = ST_NOEOF; + STp->eof_hit = 0; + STp->recover_count = 0; + + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + if (!SCpnt) { + printk("st%d: Tape request not allocated", dev); + return (-EBUSY); + } + + SCpnt->sense_buffer[0]=0; + memset ((void *) &cmd[0], 0, 10); + cmd[0] = TEST_UNIT_READY; + SCpnt->request.dev = dev; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) (STp->buffer)->b_data, + ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT, + MAX_READY_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == UNIT_ATTENTION) { /* New media? */ + SCpnt->sense_buffer[0]=0; + memset ((void *) &cmd[0], 0, 10); + cmd[0] = TEST_UNIT_READY; + SCpnt->request.dev = dev; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) (STp->buffer)->b_data, + ST_BLOCK_SIZE, st_sleep_done, ST_LONG_TIMEOUT, + MAX_READY_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + } + + if ((STp->buffer)->last_result_fatal != 0) { + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x0f) == NO_TAPE) + printk("st%d: No tape.\n", dev); + else + printk("st%d: Error %x.\n", dev, SCpnt->result); + (STp->buffer)->in_use = 0; + STp->in_use = 0; + SCpnt->request.dev = -1; /* Mark as not busy */ + return (-EIO); + } + + SCpnt->sense_buffer[0]=0; + memset ((void *) &cmd[0], 0, 10); + cmd[0] = READ_BLOCK_LIMITS; + SCpnt->request.dev = dev; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) (STp->buffer)->b_data, + ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if (!SCpnt->result && !SCpnt->sense_buffer[0]) { + STp->max_block = ((STp->buffer)->b_data[1] << 16) | + ((STp->buffer)->b_data[2] << 8) | (STp->buffer)->b_data[3]; + STp->min_block = ((STp->buffer)->b_data[4] << 8) | + (STp->buffer)->b_data[5]; +#ifdef DEBUG + printk("st%d: Block limits %d - %d bytes.\n", dev, STp->min_block, + STp->max_block); +#endif + } + else { + STp->min_block = STp->max_block = (-1); +#ifdef DEBUG + printk("st%d: Can't read block limits.\n", dev); +#endif + } + + SCpnt->sense_buffer[0]=0; + memset ((void *) &cmd[0], 0, 10); + cmd[0] = MODE_SENSE; + cmd[4] = 12; + SCpnt->request.dev = dev; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) (STp->buffer)->b_data, + ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if ((STp->buffer)->last_result_fatal != 0) { +#ifdef DEBUG + printk("st%d: No Mode Sense.\n", dev); +#endif + (STp->buffer)->b_data[2] = + (STp->buffer)->b_data[3] = 0; + } + SCpnt->request.dev = -1; /* Mark as not busy */ + +#ifdef DEBUG + printk("st%d: Mode sense. Length %d, medium %x, WBS %x, BLL %d\n", dev, + (STp->buffer)->b_data[0], (STp->buffer)->b_data[1], + (STp->buffer)->b_data[2], (STp->buffer)->b_data[3]); +#endif + + if ((STp->buffer)->b_data[3] >= 8) { + STp->drv_buffer = ((STp->buffer)->b_data[2] >> 4) & 7; + STp->density = (STp->buffer)->b_data[4]; + STp->block_size = (STp->buffer)->b_data[9] * 65536 + + (STp->buffer)->b_data[10] * 256 + (STp->buffer)->b_data[11]; +#ifdef DEBUG + printk( + "st%d: Density %x, tape length: %x, blocksize: %d, drv buffer: %d\n", + dev, STp->density, (STp->buffer)->b_data[5] * 65536 + + (STp->buffer)->b_data[6] * 256 + (STp->buffer)->b_data[7], + STp->block_size, STp->drv_buffer); +#endif + if (STp->block_size > ST_BUFFER_SIZE) { + printk("st%d: Blocksize %d too large for buffer.\n", dev, + STp->block_size); + (STp->buffer)->in_use = 0; + STp->in_use = 0; + return (-EIO); + } + + } + else + STp->block_size = ST_BLOCK_SIZE; + + if (STp->block_size > 0) { + (STp->buffer)->buffer_blocks = ST_BUFFER_SIZE / STp->block_size; + (STp->buffer)->buffer_size = + (STp->buffer)->buffer_blocks * STp->block_size; + } + else { + (STp->buffer)->buffer_blocks = 1; + (STp->buffer)->buffer_size = ST_BUFFER_SIZE; + } + (STp->buffer)->buffer_bytes = (STp->buffer)->read_pointer = 0; + +#ifdef DEBUG + printk("st%d: Block size: %d, buffer size: %d (%d blocks).\n", dev, + STp->block_size, (STp->buffer)->buffer_size, + (STp->buffer)->buffer_blocks); +#endif + + if ((STp->buffer)->b_data[2] & 0x80) { + STp->write_prot = 1; +#ifdef DEBUG + printk( "st%d: Write protected\n", dev); +#endif + } + + return 0; +} + + +/* Close the device*/ + static void +scsi_tape_close(struct inode * inode, struct file * filp) +{ + int dev; + int result; + int rewind; + static unsigned char cmd[10]; + Scsi_Cmnd * SCpnt; + Scsi_Tape * STp; + + dev = MINOR(inode->i_rdev); + rewind = (dev & 0x80) == 0; + dev = dev & 127; + STp = &(scsi_tapes[dev]); + + if ( STp->rw == ST_WRITING) { + + result = flush_write_buffer(dev); + +#ifdef DEBUG + printk("st%d: File length %d bytes.\n", dev, filp->f_pos); +#endif + + if (result == 0 || result == (-ENOSPC)) { + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + + SCpnt->sense_buffer[0] = 0; + memset(cmd, 0, 10); + cmd[0] = WRITE_FILEMARKS; + cmd[4] = 1; + SCpnt->request.dev = dev; + scsi_do_cmd( SCpnt, + (void *) cmd, (void *) (STp->buffer)->b_data, + ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if ((STp->buffer)->last_result_fatal != 0) + printk("st%d: Error on write filemark.\n", dev); + + SCpnt->request.dev = -1; /* Mark as not busy */ + } + +#ifdef DEBUG + printk("st%d: Buffer flushed, EOF written\n", dev); +#endif + } + else if (!rewind) { +#ifndef ST_IN_FILE_POS + if ((STp->eof == ST_FM) && !STp->eof_hit) + st_int_ioctl(inode, filp, MTBSF, 1); /* Back over the EOF hit */ +#else + flush_buffer(inode, filp, 0); +#endif + } + + if (rewind) + st_int_ioctl(inode, filp, MTREW, 1); + + (STp->buffer)->in_use = 0; + STp->in_use = 0; + + return; +} + + +/* Write command */ + static int +st_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + int dev; + int total, do_count, blks, retval, transfer; + int write_threshold; + static unsigned char cmd[10]; + char *b_point; + Scsi_Cmnd * SCpnt; + Scsi_Tape * STp; + + dev = MINOR(inode->i_rdev) & 127; + STp = &(scsi_tapes[dev]); +#ifdef DEBUG + if (!STp->in_use) { + printk("st%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + + if (STp->write_prot) + return (-EACCES); + + if (STp->block_size == 0 && count > ST_BUFFER_SIZE) + return (-EOVERFLOW); + + if (STp->rw == ST_READING) { + retval = flush_buffer(inode, filp, 0); + if (retval) + return retval; + STp->rw = ST_WRITING; + } + +#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS + if ((STp->buffer)->writing) { + write_behind_check(dev); + if ((STp->buffer)->last_result_fatal) { +#ifdef DEBUG + printk("st%d: Async write error %x.\n", dev, + (STp->buffer)->last_result); +#endif + if ((STp->buffer)->last_result == INT_MAX) { + retval = (-ENOSPC); /* All has been written */ + STp->eof = ST_EOM_OK; + } + else + retval = (-EIO); + return retval; + } + } +#endif + + if (STp->eof == ST_EOM_OK) + return (-ENOSPC); + else if (STp->eof == ST_EOM_ERROR) + return (-EIO); + +#ifdef ST_NO_DELAYED_WRITES + if (STp->block_size != 0 && (count % STp->block_size) != 0) + return (-EIO); /* Write must be integral number of blocks */ + write_threshold = 1; +#else + write_threshold = (STp->buffer)->buffer_size; +#endif + + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + + total = count; + + memset(cmd, 0, 10); + cmd[0] = WRITE_6; + cmd[1] = (STp->block_size != 0); + + STp->rw = ST_WRITING; + + b_point = buf; + while( +#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS + STp->block_size != 0 && + ((STp->buffer)->buffer_bytes + count) > + write_threshold) +#else + (STp->block_size == 0 && count > 0) || + ((STp->buffer)->buffer_bytes + count) >= + write_threshold) +#endif + { + if (STp->block_size == 0) + do_count = count; + else { + do_count = (STp->buffer)->buffer_size - (STp->buffer)->buffer_bytes; + if (do_count > count) + do_count = count; + } + memcpy_fromfs((STp->buffer)->b_data + + (STp->buffer)->buffer_bytes, b_point, do_count); + + if (STp->block_size == 0) + blks = do_count; + else + blks = ((STp->buffer)->buffer_bytes + do_count) / + STp->block_size; + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + SCpnt->sense_buffer[0] = 0; + SCpnt->request.dev = dev; + scsi_do_cmd (SCpnt, + (void *) cmd, (STp->buffer)->b_data, + (STp->buffer)->buffer_size, + st_sleep_done, ST_TIMEOUT, MAX_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if ((STp->buffer)->last_result_fatal != 0) { +#ifdef DEBUG + printk("st%d: Error on write:\n", dev); +#endif + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70 && + (SCpnt->sense_buffer[2] & 0x40)) { + if (STp->block_size != 0 && (SCpnt->sense_buffer[0] & 0x80) != 0) + transfer = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else if (STp->block_size == 0 && + (SCpnt->sense_buffer[2] & 0x0f) == VOLUME_OVERFLOW) + transfer = do_count; + else + transfer = 0; + if (STp->block_size != 0) + transfer *= STp->block_size; + if (transfer <= do_count) { + filp->f_pos += do_count - transfer; + count -= do_count - transfer; + STp->eof = ST_EOM_OK; + retval = (-ENOSPC); /* EOM within current request */ +#ifdef DEBUG + printk("st%d: EOM with %d bytes unwritten.\n", + dev, transfer); +#endif + } + else { + STp->eof = ST_EOM_ERROR; + retval = (-EIO); /* EOM for old data */ +#ifdef DEBUG + printk("st%d: EOM with lost data.\n", dev); +#endif + } + } + else + retval = (-EIO); + + SCpnt->request.dev = -1; /* Mark as not busy */ + (STp->buffer)->buffer_bytes = 0; + STp->dirty = 0; + if (count < total) + return total - count; + else + return retval; + } + filp->f_pos += do_count; + b_point += do_count; + count -= do_count; + (STp->buffer)->buffer_bytes = 0; + STp->dirty = 0; + } + if (count != 0) { + STp->dirty = 1; + memcpy_fromfs((STp->buffer)->b_data + + (STp->buffer)->buffer_bytes,b_point,count); + filp->f_pos += count; + (STp->buffer)->buffer_bytes += count; + count = 0; + } + + if ((STp->buffer)->last_result_fatal != 0) { + SCpnt->request.dev = -1; + return (STp->buffer)->last_result_fatal; + } + +#if ST_WRITE_THRESHOLD_BLOCKS < ST_BUFFER_BLOCKS + if ((STp->buffer)->buffer_bytes >= ST_WRITE_THRESHOLD || + STp->block_size == 0) { + /* Schedule an asynchronous write */ + if (STp->block_size == 0) + (STp->buffer)->writing = (STp->buffer)->buffer_bytes; + else + (STp->buffer)->writing = ((STp->buffer)->buffer_bytes / + STp->block_size) * STp->block_size; + STp->dirty = 0; + + if (STp->block_size == 0) + blks = (STp->buffer)->writing; + else + blks = (STp->buffer)->writing / STp->block_size; + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + SCpnt->result = (STp->buffer)->last_result = -1; + SCpnt->sense_buffer[0] = 0; + SCpnt->request.dev = dev; + scsi_do_cmd (SCpnt, + (void *) cmd, (STp->buffer)->b_data, + (STp->buffer)->writing, + st_sleep_done, ST_TIMEOUT, MAX_RETRIES); + } + else +#endif + SCpnt->request.dev = -1; /* Mark as not busy */ + + return( total); +} + + +/* Read command */ + static int +st_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int dev; + int total; + int transfer, blks, bytes; + static unsigned char cmd[10]; + Scsi_Cmnd * SCpnt; + Scsi_Tape * STp; + + dev = MINOR(inode->i_rdev) & 127; + STp = &(scsi_tapes[dev]); +#ifdef DEBUG + if (!STp->in_use) { + printk("st%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + + if (STp->block_size == 0 && count > ST_BUFFER_SIZE) + return (-EOVERFLOW); + + if (STp->rw == ST_WRITING) { + transfer = flush_buffer(inode, filp, 0); + if (transfer) + return transfer; + STp->rw = ST_READING; + } + +#ifdef DEBUG + if (STp->eof != ST_NOEOF) + printk("st%d: EOF flag up. Bytes %d\n", dev, + (STp->buffer)->buffer_bytes); +#endif + if (((STp->buffer)->buffer_bytes == 0) && + STp->eof == ST_EOM_OK) /* EOM or Blank Check */ + return (-EIO); + + STp->rw = ST_READING; + + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + + for (total = 0; total < count; ) { + + if ((STp->buffer)->buffer_bytes == 0 && + STp->eof == ST_NOEOF) { + + memset(cmd, 0, 10); + cmd[0] = READ_6; + cmd[1] = (STp->block_size != 0); + if (STp->block_size == 0) + blks = bytes = count; + else { + blks = (STp->buffer)->buffer_blocks; + bytes = blks * STp->block_size; + } + cmd[2] = blks >> 16; + cmd[3] = blks >> 8; + cmd[4] = blks; + + SCpnt->sense_buffer[0] = 0; + SCpnt->request.dev = dev; + scsi_do_cmd (SCpnt, + (void *) cmd, (STp->buffer)->b_data, + (STp->buffer)->buffer_size, + st_sleep_done, ST_TIMEOUT, MAX_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + (STp->buffer)->read_pointer = 0; + STp->eof_hit = 0; + + if ((STp->buffer)->last_result_fatal) { +#ifdef DEBUG + printk("st%d: Sense: %2x %2x %2x %2x %2x %2x %2x %2x\n", dev, + SCpnt->sense_buffer[0], SCpnt->sense_buffer[1], + SCpnt->sense_buffer[2], SCpnt->sense_buffer[3], + SCpnt->sense_buffer[4], SCpnt->sense_buffer[5], + SCpnt->sense_buffer[6], SCpnt->sense_buffer[7]); +#endif + if ((SCpnt->sense_buffer[0] & 0x70) == 0x70) { /* extended sense */ + + if ((SCpnt->sense_buffer[2] & 0xe0) != 0) { /* EOF, EOM, or ILI */ + + if ((SCpnt->sense_buffer[0] & 0x80) != 0) + transfer = (SCpnt->sense_buffer[3] << 24) | + (SCpnt->sense_buffer[4] << 16) | + (SCpnt->sense_buffer[5] << 8) | SCpnt->sense_buffer[6]; + else + transfer = 0; + if (STp->block_size == 0 && + (SCpnt->sense_buffer[2] & 0x0f) == MEDIUM_ERROR) + transfer = bytes; + + if (SCpnt->sense_buffer[2] & 0x20) { + if (STp->block_size == 0) { + if (transfer <= 0) + transfer = 0; + (STp->buffer)->buffer_bytes = count - transfer; + } + else { + printk("st%d: Incorrect block size.\n", dev); + SCpnt->request.dev = -1; /* Mark as not busy */ + return (-EIO); + } + } + else if (SCpnt->sense_buffer[2] & 0x40) { + STp->eof = ST_EOM_OK; + if (STp->block_size == 0) + (STp->buffer)->buffer_bytes = count - transfer; + else + (STp->buffer)->buffer_bytes = + ((STp->buffer)->buffer_blocks - transfer) * + STp->block_size; +#ifdef DEBUG + printk("st%d: EOM detected (%d bytes read).\n", dev, + (STp->buffer)->buffer_bytes); +#endif + } + else if (SCpnt->sense_buffer[2] & 0x80) { + STp->eof = ST_FM; + if (STp->block_size == 0) + (STp->buffer)->buffer_bytes = 0; + else + (STp->buffer)->buffer_bytes = + ((STp->buffer)->buffer_blocks - transfer) * + STp->block_size; +#ifdef DEBUG + printk( + "st%d: EOF detected (%d bytes read, transferred %d bytes).\n", + dev, (STp->buffer)->buffer_bytes, total); +#endif + } /* end of EOF, EOM, ILI test */ + } + else { /* nonzero sense key */ +#ifdef DEBUG + printk("st%d: Tape error while reading.\n", dev); +#endif + SCpnt->request.dev = -1; + if (total) + return total; + else + return -EIO; + } + } + else { + transfer = (STp->buffer)->last_result_fatal; + SCpnt->request.dev = -1; /* Mark as not busy */ + return transfer; + } + } + else /* Read successful */ + (STp->buffer)->buffer_bytes = bytes; + + } /* if ((STp->buffer)->buffer_bytes == 0 && + STp->eof == ST_NOEOF) */ + + if ((STp->buffer)->buffer_bytes > 0) { +#ifdef DEBUG + if (STp->eof != ST_NOEOF) + printk("st%d: EOF up. Left %d, needed %d.\n", dev, + (STp->buffer)->buffer_bytes, count - total); +#endif + transfer = (STp->buffer)->buffer_bytes < count - total ? + (STp->buffer)->buffer_bytes : count - total; + memcpy_tofs(buf, (STp->buffer)->b_data + + (STp->buffer)->read_pointer,transfer); + filp->f_pos += transfer; + buf += transfer; + total += transfer; + (STp->buffer)->buffer_bytes -= transfer; + (STp->buffer)->read_pointer += transfer; + } + else if (STp->eof != ST_NOEOF) { + STp->eof_hit = 1; + SCpnt->request.dev = -1; /* Mark as not busy */ + if (total == 0 && STp->eof == ST_FM) + STp->eof = 0; + if (total == 0 && STp->eof == ST_EOM_OK) + return (-EIO); /* ST_EOM_ERROR not used in read */ + return total; + } + + if (STp->block_size == 0) + count = total; /* Read only one variable length block */ + + } /* for (total = 0; total < count; ) */ + + SCpnt->request.dev = -1; /* Mark as not busy */ + + return total; +} + + +/* Internal ioctl function */ + static int +st_int_ioctl(struct inode * inode,struct file * file, + unsigned int cmd_in, unsigned long arg) +{ + int dev = MINOR(inode->i_rdev); + int timeout = ST_LONG_TIMEOUT; + long ltmp; + int ioctl_result; + unsigned char cmd[10]; + Scsi_Cmnd * SCpnt; + Scsi_Tape * STp; + + dev = dev & 127; + STp = &(scsi_tapes[dev]); + + memset(cmd, 0, 10); + switch (cmd_in) { + case MTFSF: + case MTFSFM: + cmd[0] = SPACE; + cmd[1] = 0x01; /* Space FileMarks */ + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +#ifdef DEBUG + printk("st%d: Spacing tape forward over %d filemarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + break; + case MTBSF: + case MTBSFM: + cmd[0] = SPACE; + cmd[1] = 0x01; /* Space FileMarks */ + ltmp = (-arg); + cmd[2] = (ltmp >> 16); + cmd[3] = (ltmp >> 8); + cmd[4] = ltmp; +#ifdef DEBUG + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk("st%d: Spacing tape backward over %d filemarks.\n", dev, (-ltmp)); +#endif + break; + case MTFSR: + cmd[0] = SPACE; + cmd[1] = 0x00; /* Space Blocks */ + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; +#ifdef DEBUG + printk("st%d: Spacing tape forward %d blocks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + break; + case MTBSR: + cmd[0] = SPACE; + cmd[1] = 0x00; /* Space Blocks */ + ltmp = (-arg); + cmd[2] = (ltmp >> 16); + cmd[3] = (ltmp >> 8); + cmd[4] = ltmp; +#ifdef DEBUG + if (cmd[2] & 0x80) + ltmp = 0xff000000; + ltmp = ltmp | (cmd[2] << 16) | (cmd[3] << 8) | cmd[4]; + printk("st%d: Spacing tape backward %d blocks.\n", dev, (-ltmp)); +#endif + break; + case MTWEOF: + if (STp->write_prot) + return (-EACCES); + cmd[0] = WRITE_FILEMARKS; + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; + timeout = ST_TIMEOUT; +#ifdef DEBUG + printk("st%d: Writing %d filemarks.\n", dev, + cmd[2] * 65536 + cmd[3] * 256 + cmd[4]); +#endif + break; + case MTREW: + cmd[0] = REZERO_UNIT; +#ifdef ST_NOWAIT + cmd[1] = 1; /* Don't wait for completion */ + timeout = ST_TIMEOUT; +#endif +#ifdef DEBUG + printk("st%d: Rewinding tape.\n", dev); +#endif + break; + case MTOFFL: + cmd[0] = START_STOP; +#ifdef ST_NOWAIT + cmd[1] = 1; /* Don't wait for completion */ + timeout = ST_TIMEOUT; +#endif +#ifdef DEBUG + printk("st%d: Unloading tape.\n", dev); +#endif + break; + case MTNOP: +#ifdef DEBUG + printk("st%d: No op on tape.\n", dev); +#endif + return 0; /* Should do something ? */ + break; + case MTRETEN: + cmd[0] = START_STOP; +#ifdef ST_NOWAIT + cmd[1] = 1; /* Don't wait for completion */ + timeout = ST_TIMEOUT; +#endif + cmd[4] = 3; +#ifdef DEBUG + printk("st%d: Retensioning tape.\n", dev); +#endif + break; + case MTEOM: + cmd[0] = SPACE; + cmd[1] = 3; +#ifdef DEBUG + printk("st%d: Spacing to end of recorded medium.\n", dev); +#endif + break; + case MTERASE: + if (STp->write_prot) + return (-EACCES); + cmd[0] = ERASE; + cmd[1] = 1; /* To the end of tape */ +#ifdef DEBUG + printk("st%d: Erasing tape.\n", dev); +#endif + break; + case MTSEEK: + if ((STp->device)->scsi_level < SCSI_2) { + cmd[0] = QFA_SEEK_BLOCK; + cmd[2] = (arg >> 16); + cmd[3] = (arg >> 8); + cmd[4] = arg; + cmd[5] = 0; + } + else { + cmd[0] = SEEK_10; + cmd[1] = 4; + cmd[3] = (arg >> 24); + cmd[4] = (arg >> 16); + cmd[5] = (arg >> 8); + cmd[6] = arg; + } +#ifdef ST_NOWAIT + cmd[1] |= 1; /* Don't wait for completion */ + timeout = ST_TIMEOUT; +#endif +#ifdef DEBUG + printk("st%d: Seeking tape to block %d.\n", dev, arg); +#endif + break; + case MTSETBLK: /* Set block length */ + case MTSETDENSITY: /* Set tape density */ + case MTSETDRVBUFFER: /* Set drive buffering */ + if (STp->dirty || (STp->buffer)->buffer_bytes != 0) + return (-EIO); /* Not allowed if data in buffer */ + if (cmd_in == MTSETBLK && + arg != 0 && + (arg < STp->min_block || arg > STp->max_block || + arg > ST_BUFFER_SIZE)) { + printk("st%d: Illegal block size.\n", dev); + return (-EINVAL); + } + cmd[0] = MODE_SELECT; + cmd[4] = 12; + + memset((STp->buffer)->b_data, 0, 12); + if (cmd_in == MTSETDRVBUFFER) + (STp->buffer)->b_data[2] = (arg & 7) << 4; + else + (STp->buffer)->b_data[2] = + STp->drv_buffer << 4; + (STp->buffer)->b_data[3] = 8; /* block descriptor length */ + if (cmd_in == MTSETDENSITY) + (STp->buffer)->b_data[4] = arg; + else + (STp->buffer)->b_data[4] = STp->density; + if (cmd_in == MTSETBLK) + ltmp = arg; + else + ltmp = STp->block_size; + (STp->buffer)->b_data[9] = (ltmp >> 16); + (STp->buffer)->b_data[10] = (ltmp >> 8); + (STp->buffer)->b_data[11] = ltmp; + timeout = ST_TIMEOUT; +#ifdef DEBUG + if (cmd_in == MTSETBLK) + printk("st%d: Setting block size to %d bytes.\n", dev, + (STp->buffer)->b_data[9] * 65536 + + (STp->buffer)->b_data[10] * 256 + + (STp->buffer)->b_data[11]); + else if (cmd_in == MTSETDENSITY) + printk("st%d: Setting density code to %x.\n", dev, + (STp->buffer)->b_data[4]); + else + printk("st%d: Setting drive buffer code to %d.\n", dev, + ((STp->buffer)->b_data[2] >> 4) & 7); +#endif + break; + default: + printk("st%d: Unknown st_ioctl command %x.\n", dev, cmd_in); + return (-ENOSYS); + } + + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + SCpnt->sense_buffer[0] = 0; + SCpnt->request.dev = dev; + scsi_do_cmd(SCpnt, + (void *) cmd, (void *) (STp->buffer)->b_data, ST_BLOCK_SIZE, + st_sleep_done, timeout, MAX_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + ioctl_result = (STp->buffer)->last_result_fatal; + + SCpnt->request.dev = -1; /* Mark as not busy */ + + if (!ioctl_result) { + if (cmd_in == MTBSFM) + ioctl_result = st_int_ioctl(inode, file, MTFSF, 1); + else if (cmd_in == MTFSFM) + ioctl_result = st_int_ioctl(inode, file, MTBSF, 1); + else if (cmd_in == MTSETBLK) { + STp->block_size = arg; + if (arg != 0) { + (STp->buffer)->buffer_blocks = + ST_BUFFER_SIZE / STp->block_size; + (STp->buffer)->buffer_size = + (STp->buffer)->buffer_blocks * STp->block_size; + } + else { + (STp->buffer)->buffer_blocks = 1; + (STp->buffer)->buffer_size = ST_BUFFER_SIZE; + } + (STp->buffer)->buffer_bytes = + (STp->buffer)->read_pointer = 0; + } + else if (cmd_in == MTSETDRVBUFFER) + STp->drv_buffer = arg; + else if (cmd_in == MTSETDENSITY) + STp->density = arg; + if (cmd_in == MTEOM || cmd_in == MTWEOF) { + STp->eof = ST_EOM_OK; + STp->eof_hit = 0; + } + else if (cmd_in != MTSETBLK && cmd_in != MTNOP) { + STp->eof = ST_NOEOF; + STp->eof_hit = 0; + } + } + + return ioctl_result ; +} + + + +/* The ioctl command */ + static int +st_ioctl(struct inode * inode,struct file * file, + unsigned int cmd_in, unsigned long arg) +{ + int dev = MINOR(inode->i_rdev); + int i, cmd, result; + struct mtop mtc; + struct mtpos mt_pos; + unsigned char scmd[10]; + Scsi_Cmnd *SCpnt; + Scsi_Tape *STp; + + dev = dev & 127; + STp = &(scsi_tapes[dev]); +#ifdef DEBUG + if (!STp->in_use) { + printk("st%d: Incorrect device.\n", dev); + return (-EIO); + } +#endif + + cmd = cmd_in & IOCCMD_MASK; + if (cmd == (MTIOCTOP & IOCCMD_MASK)) { + + if (((cmd_in & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(mtc)) + return (-EINVAL); + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(mtc)); + if (i) + return i; + + memcpy_fromfs((char *) &mtc, (char *)arg, sizeof(struct mtop)); + + i = flush_buffer(inode, file, mtc.mt_op == MTSEEK || + mtc.mt_op == MTREW || mtc.mt_op == MTOFFL || + mtc.mt_op == MTRETEN || mtc.mt_op == MTEOM); + if (i < 0) + return i; + + return st_int_ioctl(inode, file, mtc.mt_op, mtc.mt_count); + } + else if (cmd == (MTIOCGET & IOCCMD_MASK)) { + + if (((cmd_in & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtget)) + return (-EINVAL); + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct mtget)); + if (i) + return i; + + memcpy_tofs((char *)arg, (char *)(STp->buffer)->mt_status, + sizeof(struct mtget)); + return 0; + } + else if (cmd == (MTIOCPOS & IOCCMD_MASK)) { +#ifdef DEBUG + printk("st%d: get tape position.\n", dev); +#endif + if (((cmd_in & IOCSIZE_MASK) >> IOCSIZE_SHIFT) != sizeof(struct mtpos)) + return (-EINVAL); + + i = flush_buffer(inode, file, 0); + if (i < 0) + return i; + + i = verify_area(VERIFY_WRITE, (void *)arg, sizeof(struct mtpos)); + if (i) + return i; + + SCpnt = allocate_device(NULL, (STp->device)->index, 1); + + SCpnt->sense_buffer[0]=0; + memset (scmd, 0, 10); + if ((STp->device)->scsi_level < SCSI_2) { + scmd[0] = QFA_REQUEST_BLOCK; + scmd[4] = 3; + } + else { + scmd[0] = READ_POSITION; + scmd[1] = 1; + } + SCpnt->request.dev = dev; + SCpnt->sense_buffer[0] = 0; + scsi_do_cmd(SCpnt, + (void *) scmd, (void *) (STp->buffer)->b_data, + ST_BLOCK_SIZE, st_sleep_done, ST_TIMEOUT, MAX_READY_RETRIES); + + if (SCpnt->request.dev == dev) sleep_on( &(STp->waiting) ); + + if ((STp->buffer)->last_result_fatal != 0) { + mt_pos.mt_blkno = (-1); +#ifdef DEBUG + printk("st%d: Can't read tape position.\n", dev); +#endif + result = (-EIO); + } + else { + result = 0; + if ((STp->device)->scsi_level < SCSI_2) + mt_pos.mt_blkno = ((STp->buffer)->b_data[0] << 16) + + ((STp->buffer)->b_data[1] << 8) + + (STp->buffer)->b_data[2]; + else + mt_pos.mt_blkno = ((STp->buffer)->b_data[4] << 24) + + ((STp->buffer)->b_data[5] << 16) + + ((STp->buffer)->b_data[6] << 8) + + (STp->buffer)->b_data[7]; + + } + + SCpnt->request.dev = -1; /* Mark as not busy */ + + memcpy_tofs((char *)arg, (char *) (&mt_pos), sizeof(struct mtpos)); + return result; + } + else + return scsi_ioctl(STp->device, cmd_in, (void *) arg); +} + + + +static struct file_operations st_fops = { + NULL, /* lseek - default */ + st_read, /* read - general block-dev read */ + st_write, /* write - general block-dev write */ + NULL, /* readdir - bad */ + NULL, /* select */ + st_ioctl, /* ioctl */ + NULL, /* mmap */ + scsi_tape_open, /* open */ + scsi_tape_close, /* release */ + NULL /* fsync */ +}; + +void st_attach(Scsi_Device * SDp){ + scsi_tapes[NR_ST++].device = SDp; + if(NR_ST > MAX_ST) panic ("scsi_devices corrupt (st)"); +}; + +unsigned long st_init1(unsigned long mem_start, unsigned long mem_end){ + scsi_tapes = (Scsi_Tape *) mem_start; + mem_start += MAX_ST * sizeof(Scsi_Tape); + return mem_start; +}; + +/* Driver initialization */ +unsigned long st_init(unsigned long mem_start, unsigned long mem_end) +{ + int i; + + if (register_chrdev(MAJOR_NR,"st",&st_fops)) { + printk("Unable to get major %d for SCSI tapes\n",MAJOR_NR); + return mem_start; + } + if (NR_ST == 0) return mem_start; + +#ifdef DEBUG + printk("st: Init tape.\n"); +#endif + + for (i=0; i < NR_ST; ++i) { + scsi_tapes[i].capacity = 0xfffff; + scsi_tapes[i].dirty = 0; + scsi_tapes[i].rw = ST_IDLE; + scsi_tapes[i].eof = ST_NOEOF; + scsi_tapes[i].waiting = NULL; + scsi_tapes[i].in_use = 0; + scsi_tapes[i].drv_buffer = 1; /* Try buffering if no mode sense */ + scsi_tapes[i].density = 0; + } + + + /* Allocate the buffers */ + if (NR_ST == 1) + st_nbr_buffers = 1; + else + st_nbr_buffers = 2; + for (i=0; i < st_nbr_buffers; i++) { + st_buffers[i] = (ST_buffer *) mem_start; +#ifdef DEBUG + printk("st: Buffer address: %p\n", st_buffers[i]); +#endif + mem_start += sizeof(ST_buffer) - 1 + ST_BUFFER_BLOCKS * ST_BLOCK_SIZE; + st_buffers[i]->mt_status = (struct mtget *) mem_start; + mem_start += sizeof(struct mtget); + st_buffers[i]->in_use = 0; + st_buffers[i]->writing = 0; + + /* "generic" status */ + memset((void *) st_buffers[i]->mt_status, 0, sizeof(struct mtget)); + st_buffers[i]->mt_status->mt_type = MT_ISSCSI1; + } + + return mem_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.h new file mode 100644 index 000000000..7b530faa6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/st.h @@ -0,0 +1,61 @@ + +#ifndef _ST_H + #define _ST_H +/* + $Header: /usr/src/linux/kernel/blk_drv/scsi/RCS/st.h,v 1.1 1992/04/24 18:01:50 root Exp root $ +*/ + +#ifndef _SCSI_H +#include "scsi.h" +#endif + +typedef struct { + int in_use; + struct mtget * mt_status; + int buffer_size; + int buffer_blocks; + int buffer_bytes; + int read_pointer; + int writing; + int last_result; + int last_result_fatal; + unsigned char b_data[1]; +} ST_buffer; + +typedef struct { + unsigned capacity; + struct wait_queue * waiting; + Scsi_Device* device; + unsigned dirty:1; + unsigned rw:2; + unsigned eof:2; + unsigned write_prot:1; + unsigned in_use:1; + unsigned eof_hit:1; + unsigned drv_buffer:3; + unsigned char density; + ST_buffer * buffer; + int block_size; + int min_block; + int max_block; + int recover_count; + Scsi_Cmnd SCpnt; +} Scsi_Tape; + +/* Values of eof */ +#define ST_NOEOF 0 +#define ST_FM 1 +#define ST_EOM_OK 2 +#define ST_EOM_ERROR 3 + +/* Values of rw */ +#define ST_IDLE 0 +#define ST_READING 1 +#define ST_WRITING 2 + +/* Positioning SCSI-commands for Tandberg, etc. drives */ +#define QFA_REQUEST_BLOCK 0x02 +#define QFA_SEEK_BLOCK 0x0c + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/t128.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/t128.c new file mode 100644 index 000000000..55314056c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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 +#include +#include +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/t128.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/t128.h new file mode 100644 index 000000000..453118a20 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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(Scsi_Cmnd *); + +#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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.c new file mode 100644 index 000000000..d34667a0f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.c @@ -0,0 +1,1112 @@ +/* + * 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 +#include +#include +#include +#include + +#include +#include +#include +#include + +#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; +} + +#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(Scsi_Cmnd * SCpnt) +{ + int flags; + register int i; +#if (ULTRASTOR_DEBUG & UD_RESET) + printk("US14F: reset: called\n"); +#endif + + if(config.slot) { + if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + 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 0 + if (dkinfo[2] > 1024) + dkinfo[2] = 1024; +#endif + 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(NULL); + 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/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.h new file mode 100644 index 000000000..07312271e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/ultrastor.h @@ -0,0 +1,83 @@ +/* + * ultrastor.c (C) 1991 David B. Gentzel + * Low-level scsi driver for UltraStor 14F + * by David B. Gentzel, Whitfield Software Services, Carnegie, PA + * (gentzel@nova.enet.dec.com) + * 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 + +int ultrastor_detect(int); +const char *ultrastor_info(void); +int ultrastor_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int ultrastor_abort(Scsi_Cmnd *, int); +int ultrastor_reset(Scsi_Cmnd *); +int ultrastor_biosparam(int, int, int *); + +#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/24F/34F", ultrastor_detect, ultrastor_info, 0, \ + ultrastor_queuecommand, ultrastor_abort, ultrastor_reset, \ + 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_MULTI_CMD 0x0020 +#define UD_CSIR 0x0040 +#define UD_ERROR 0x0080 + +/* #define PORT_OVERRIDE 0x330 */ + +/* 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 + +/* MSCP field values */ + +/* Opcode */ +#define OP_HOST_ADAPTER 0x1 +#define OP_SCSI 0x2 +#define OP_RESET 0x4 + +/* Date Transfer Direction */ +#define DTD_SCSI 0x0 +#define DTD_IN 0x1 +#define DTD_OUT 0x2 +#define DTD_NONE 0x3 + +/* Host Adapter command subcodes */ +#define HA_CMD_INQUIRY 0x1 +#define HA_CMD_SELF_DIAG 0x2 +#define HA_CMD_READ_BUFF 0x3 +#define HA_CMD_WRITE_BUFF 0x4 + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.c new file mode 100644 index 000000000..b64f56fed --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.c @@ -0,0 +1,622 @@ +/* $Id: wd7000.c,v 1.2 1994/01/15 06:02:32 drew Exp $ + * linux/kernel/wd7000.c + * + * Copyright (C) 1992 Thomas Wuensche + * closely related to the aha1542 driver from Tommy Thorn + * ( as close as different hardware allows on a lowlevel-driver :-) ) + * + * Revised (and renamed) by John Boyd to + * accomodate Eric Youngdale's modifications to scsi.c. Nov 1992. + * + * Additional changes to support scatter/gather. Dec. 1992. tw/jb + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../block/blk.h" +#include "scsi.h" +#include "hosts.h" + +/* #define DEBUG */ + +#include "wd7000.h" + + +#ifdef DEBUG +#define DEB(x) x +#else +#define DEB(x) +#endif + + +/* + Driver data structures: + - mb and scbs are required for interfacing with the host adapter. + An SCB has extra fields not visible to the adapter; mb's + _cannot_ do this, since the adapter assumes they are contiguous in + memory, 4 bytes each, with ICMBs following OGMBs, and uses this fact + to access them. + - An icb is for host-only (non-SCSI) commands. ICBs are 16 bytes each; + the additional bytes are used only by the driver. + - For now, a pool of SCBs are kept in global storage by this driver, + and are allocated and freed as needed. + + The 7000-FASST2 marks OGMBs empty as soon as it has _started_ a command, + not when it has finished. Since the SCB must be around for completion, + problems arise when SCBs correspond to OGMBs, which may be reallocated + earlier (or delayed unnecessarily until a command completes). + Mailboxes are used as transient data structures, simply for + carrying SCB addresses to/from the 7000-FASST2. + + Note also since SCBs are not "permanently" associated with mailboxes, + there is no need to keep a global list of Scsi_Cmnd pointers indexed + by OGMB. Again, SCBs reference their Scsi_Cmnds directly, so mailbox + indices need not be involved. +*/ + +static struct { + struct wd_mailbox ogmb[OGMB_CNT]; + struct wd_mailbox icmb[ICMB_CNT]; +} mb; +static int next_ogmb = 0; /* to reduce contention at mailboxes */ + +static Scb scbs[MAX_SCBS]; +static Scb *scbfree = NULL; + +static int wd7000_host = 0; +static unchar controlstat = 0; + +static unchar rev_1 = 0, rev_2 = 0; /* filled in by wd7000_revision */ + +#define wd7000_intr_ack() outb(0,INTR_ACK) + +#define WAITnexttimeout 3000000 + + +static inline void wd7000_enable_intr(void) +{ + controlstat |= INT_EN; + outb(controlstat,CONTROL); +} + + +static inline void wd7000_enable_dma(void) +{ + controlstat |= DMA_EN; + outb(controlstat,CONTROL); + set_dma_mode(DMA_CH, DMA_MODE_CASCADE); + enable_dma(DMA_CH); +} + + +#define WAIT(port, mask, allof, noneof) \ + { register WAITbits; \ + register WAITtimeout = WAITnexttimeout; \ + while (1) { \ + WAITbits = inb(port) & (mask); \ + if ((WAITbits & (allof)) == (allof) && ((WAITbits & (noneof)) == 0)) \ + break; \ + if (--WAITtimeout == 0) goto fail; \ + } \ + } + + +static inline void delay( unsigned how_long ) +{ + unsigned long time = jiffies + how_long; + + while (jiffies < time); +} + + +static inline int command_out(unchar *cmdp, int len) +{ + while (len--) { + WAIT(ASC_STAT, STATMASK, CMD_RDY, 0); + outb(*cmdp++, COMMAND); + } + return 1; + +fail: + printk("wd7000_out WAIT failed(%d): ", len+1); + return 0; +} + +static inline Scb *alloc_scb(void) +{ + Scb *scb; + unsigned long flags; + + save_flags(flags); + cli(); + + if (scbfree == NULL) { + panic("wd7000: can't allocate free SCB.\n"); + restore_flags(flags); + return NULL; + } + scb = scbfree; scbfree = scb->next; + memset(scb, 0, sizeof(Scb)); scb->next = NULL; + + restore_flags(flags); + + return scb; +} + + +static inline void free_scb( Scb *scb ) +{ + unsigned long flags; + + save_flags(flags); + cli(); + + memset(scb, 0, sizeof(Scb)); + scb->next = scbfree; scbfree = scb; + + restore_flags(flags); +} + + +static inline void init_scbs(void) +{ + int i; + unsigned long flags; + + save_flags(flags); + cli(); + + scbfree = &(scbs[0]); + for (i = 0; i < MAX_SCBS-1; i++) scbs[i].next = &(scbs[i+1]); + scbs[MAX_SCBS-1].next = NULL; + + restore_flags(flags); +} + + +static int mail_out( Scb *scbptr ) +/* + * Note: this can also be used for ICBs; just cast to the parm type. + */ +{ + int i, ogmb; + unsigned long flags; + + DEB(printk("wd7000_scb_out: %06x");) + + /* We first look for a free outgoing mailbox */ + save_flags(flags); + cli(); + ogmb = next_ogmb; + for (i = 0; i < OGMB_CNT; i++) { + if (mb.ogmb[ogmb].status == 0) { + DEB(printk(" using OGMB %x",ogmb)); + mb.ogmb[ogmb].status = 1; + any2scsi(mb.ogmb[ogmb].scbptr, scbptr); + + next_ogmb = (ogmb+1) % OGMB_CNT; + break; + } else + ogmb = (++ogmb) % OGMB_CNT; + } + restore_flags(flags); + DEB(printk(", scb is %x",scbptr);) + + if (i >= OGMB_CNT) { + DEB(printk(", no free OGMBs.\n");) + /* Alternatively, issue "interrupt on free OGMB", and sleep... */ + return 0; + } + + wd7000_enable_intr(); + do { + WAIT(ASC_STAT,STATMASK,CMD_RDY,0); + outb(START_OGMB|ogmb, COMMAND); + WAIT(ASC_STAT,STATMASK,CMD_RDY,0); + } while (inb(ASC_STAT) & CMD_REJ); + + DEB(printk(", awaiting interrupt.\n");) + return 1; + +fail: + DEB(printk(", WAIT timed out.\n");) + return 0; +} + + +int make_code(unsigned hosterr, unsigned scsierr) +{ +#ifdef DEBUG + int in_error = hosterr; +#endif + + switch ((hosterr>>8)&0xff){ + case 0: /* Reserved */ + hosterr = DID_ERROR; + break; + case 1: /* Command Complete, no errors */ + hosterr = DID_OK; + break; + case 2: /* Command complete, error logged in scb status (scsierr) */ + hosterr = DID_OK; + break; + case 4: /* Command failed to complete - timeout */ + hosterr = DID_TIME_OUT; + break; + case 5: /* Command terminated; Bus reset by external device */ + hosterr = DID_RESET; + break; + case 6: /* Unexpected Command Received w/ host as target */ + hosterr = DID_BAD_TARGET; + break; + case 80: /* Unexpected Reselection */ + case 81: /* Unexpected Selection */ + hosterr = DID_BAD_INTR; + break; + case 82: /* Abort Command Message */ + hosterr = DID_ABORT; + break; + case 83: /* SCSI Bus Software Reset */ + case 84: /* SCSI Bus Hardware Reset */ + hosterr = DID_RESET; + break; + default: /* Reserved */ + hosterr = DID_ERROR; + break; + } +#ifdef DEBUG + if (scsierr||hosterr) + printk("\nSCSI command error: SCSI %02x host %04x return %d", + scsierr,in_error,hosterr); +#endif + return scsierr | (hosterr << 16); +} + + +static void wd7000_scsi_done(Scsi_Cmnd * SCpnt) +{ + DEB(printk("wd7000_scsi_done: %06x\n",SCpnt);) + SCpnt->SCp.phase = 0; +} + + +void wd7000_intr_handle(int irq) +{ + int flag, icmb, errstatus, icmb_status; + int host_error, scsi_error; + Scb *scb; /* for SCSI commands */ + unchar *icb; /* for host commands */ + Scsi_Cmnd *SCpnt; + + flag = inb(INTR_STAT); + DEB(printk("wd7000_intr_handle: intr stat = %02x",flag);) + + if (!(inb(ASC_STAT)&0x80)){ + DEB(printk("\nwd7000_intr_handle: phantom interrupt...\n");) + wd7000_intr_ack(); + return; + } + + /* check for an incoming mailbox */ + if ((flag & 0x40) == 0) { + /* for a free OGMB - need code for this case... */ + DEB(printk("wd7000_intr_handle: free outgoing mailbox\n");) + wd7000_intr_ack(); + return; + } + /* The interrupt is for an incoming mailbox */ + icmb = flag & 0x3f; + scb = (struct scb *) scsi2int(mb.icmb[icmb].scbptr); + icmb_status = mb.icmb[icmb].status; + mb.icmb[icmb].status = 0; + +#ifdef DEBUG + printk(" ICMB %d posted for SCB/ICB %06x, status %02x, vue %02x", + icmb, scb, icmb_status, scb->vue ); +#endif + + if (!(scb->op & 0x80)) { /* an SCB is done */ + SCpnt = scb->SCpnt; + if (--(SCpnt->SCp.phase) <= 0) { /* all scbs for SCpnt are done */ + host_error = scb->vue | (icmb_status << 8); + scsi_error = scb->status; + errstatus = make_code(host_error,scsi_error); + SCpnt->result = errstatus; + + if (SCpnt->host_scribble != NULL) + scsi_free(SCpnt->host_scribble,WD7000_SCRIBBLE); + free_scb(scb); + + SCpnt->scsi_done(SCpnt); + } + } else { /* an ICB is done */ + icb = (unchar *) scb; + icb[ICB_STATUS] = icmb_status; + icb[ICB_PHASE] = 0; + } + + wd7000_intr_ack(); + DEB(printk(".\n");) + return; +} + + +int wd7000_queuecommand(Scsi_Cmnd * SCpnt, void (*done)(Scsi_Cmnd *)) +{ + Scb *scb; + Sgb *sgb; + unchar *cdb; + unchar idlun; + short cdblen; + + cdb = (unchar *) SCpnt->cmnd; + cdblen = COMMAND_SIZE(*cdb); + idlun = ((SCpnt->target << 5) & 0xe0) | (SCpnt->lun & 7); + SCpnt->scsi_done = done; + SCpnt->SCp.phase = 1; + scb = alloc_scb(); + scb->idlun = idlun; + memcpy(scb->cdb, cdb, cdblen); + scb->direc = 0x40; /* Disable direction check */ + scb->SCpnt = SCpnt; /* so we can find stuff later */ + SCpnt->host_scribble = NULL; + DEB(printk("request_bufflen is %x, bufflen is %x\n",\ + SCpnt->request_bufflen, SCpnt->bufflen);) + + if (SCpnt->use_sg) { + struct scatterlist *sg = (struct scatterlist *) SCpnt->request_buffer; + unsigned i; + + if (scsi_hosts[wd7000_host].sg_tablesize <= 0) { + panic("wd7000_queuecommand: scatter/gather not supported.\n"); + } +#ifdef DEBUG + printk("Using scatter/gather with %d elements.\n",SCpnt->use_sg); +#endif + /* + Allocate memory for a scatter/gather-list in wd7000 format. + Save the pointer at host_scribble. + */ +#ifdef DEBUG + if (SCpnt->use_sg > WD7000_SG) + panic("WD7000: requesting too many scatterblocks\n"); +#endif + SCpnt->host_scribble = (unsigned char *) scsi_malloc(WD7000_SCRIBBLE); + sgb = (Sgb *) SCpnt->host_scribble; + if (sgb == NULL) + panic("wd7000_queuecommand: scsi_malloc() failed.\n"); + + scb->op = 1; + any2scsi(scb->dataptr, sgb); + any2scsi(scb->maxlen, SCpnt->use_sg * sizeof (Sgb) ); + + for (i = 0; i < SCpnt->use_sg; i++) { + any2scsi(sgb->ptr, sg[i].address); + any2scsi(sgb->len, sg[i].length); + sgb++; + } + DEB(printk("Using %d bytes for %d scatter/gather blocks\n",\ + scsi2int(scb->maxlen), SCpnt->use_sg);) + } else { + scb->op = 0; + any2scsi(scb->dataptr, SCpnt->request_buffer); + any2scsi(scb->maxlen, SCpnt->request_bufflen); + } + + return mail_out(scb); +} + + +int wd7000_command(Scsi_Cmnd *SCpnt) +{ + wd7000_queuecommand(SCpnt, wd7000_scsi_done); + + while (SCpnt->SCp.phase > 0); /* phase counts scbs down to 0 */ + + return SCpnt->result; +} + + +int wd7000_init(void) +{ int i; + unchar init_block[] = { + INITIALIZATION, 7, BUS_ON, BUS_OFF, 0, 0, 0, 0, OGMB_CNT, ICMB_CNT + }; + + /* Reset the adapter. */ + outb(SCSI_RES|ASC_RES, CONTROL); + delay(1); /* reset pulse: this is 10ms, only need 25us */ + outb(0,CONTROL); controlstat = 0; + /* + Wait 2 seconds, then expect Command Port Ready. + + I suspect something else needs to be done here, but I don't know + what. The OEM doc says power-up diagnostics take 2 seconds, and + indeed, SCSI commands submitted before then will time out, but + none of what follows seems deterred by _not_ waiting 2 secs. + */ + delay(200); + + WAIT(ASC_STAT, STATMASK, CMD_RDY, 0); + DEB(printk("wd7000_init: Power-on Diagnostics finished\n");) + if (((i=inb(INTR_STAT)) != 1) && (i != 7)) { + panic("wd7000_init: Power-on Diagnostics error\n"); + return 0; + } + + /* Clear mailboxes */ + memset(&mb,0,sizeof (mb)); + /* Set up SCB free list */ + init_scbs(); + + /* Set up init block */ + any2scsi(init_block+5,&mb); + /* Execute init command */ + if (!command_out(init_block,sizeof(init_block))) { + panic("WD-7000 Initialization failed.\n"); + return 0; + } + + /* Wait until init finished */ + WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0); + outb(DISABLE_UNS_INTR, COMMAND); + WAIT(ASC_STAT, STATMASK, CMD_RDY | ASC_INI, 0); + + /* Enable Interrupt and DMA */ + if (request_irq(IRQ_LVL, wd7000_intr_handle)) { + panic("Unable to allocate IRQ for WD-7000.\n"); + return 0; + }; + if(request_dma(DMA_CH)) { + panic("Unable to allocate DMA channel for WD-7000.\n"); + free_irq(IRQ_LVL); + return 0; + }; + wd7000_enable_dma(); + wd7000_enable_intr(); + + printk("WD-7000 initialized.\n"); + return 1; + fail: + return 0; /* 0 = not ok */ +} + + +void wd7000_revision(void) +{ + volatile unchar icb[ICB_LEN] = {0x8c}; /* read firmware revision level */ + + icb[ICB_PHASE] = 1; + mail_out( (struct scb *) icb ); + while (icb[ICB_PHASE]) /* wait for completion */; + rev_1 = icb[1]; + rev_2 = icb[2]; + + /* + For boards at rev 7.0 or later, enable scatter/gather. + */ + if (rev_1 >= 7) scsi_hosts[wd7000_host].sg_tablesize = WD7000_SG; +} + + +static const char *wd_bases[] = {(char *)0xce000,(char *)0xd8000}; + +typedef struct { + char * signature; + unsigned offset; + unsigned length; +} Signature; + +static const Signature signatures[] = {{"SSTBIOS",0xd,0x7}}; + +#define NUM_SIGNATURES (sizeof(signatures)/sizeof(Signature)) + + +int wd7000_detect(int hostnum) +/* + * return non-zero on detection + */ +{ + int i,j; + char const *base_address = NULL; + + if(check_region(IO_BASE, 4)) return 0; /* IO ports in use */ + for(i=0;i<(sizeof(wd_bases)/sizeof(char *));i++){ + for(j=0;jtarget, SCpnt->lun); + { int j; unchar *cdbj = (unchar *) SCpnt->cmnd; + for (j=0; j < COMMAND_SIZE(*cdbj); j++) printk(" %02x", *(cdbj++)); + printk(" result %08x\n", SCpnt->result); + } +#endif + return 0; +} + + +/* We do not implement a reset function here, but the upper level code assumes + that it will get some kind of response for the command in SCpnt. We must + oblige, or the command will hang the scsi system */ + +int wd7000_reset(Scsi_Cmnd * SCpnt) +{ +#ifdef DEBUG + printk("wd7000_reset\n"); +#endif + if (SCpnt) SCpnt->flags |= NEEDS_JUMPSTART; + return 0; +} + + +int wd7000_biosparam(int size, int dev, int* ip) +/* + * This is borrowed directly from aha1542.c, but my disks are organized + * this way, so I think it will work OK. + */ +{ + ip[0] = 64; + ip[1] = 32; + ip[2] = size >> 11; +/* if (ip[2] >= 1024) ip[2] = 1024; */ + return 0; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.h new file mode 100644 index 000000000..ab8b2a586 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/scsi/wd7000.h @@ -0,0 +1,205 @@ +#ifndef _WD7000_H + +/* $Id: $ + * + * Header file for the WD-7000 driver for Linux + * + * $Log: $ + * Revision 1.1 1992/07/24 06:27:38 root + * Initial revision + * + * Revision 1.1 1992/07/05 08:32:32 root + * Initial revision + * + * Revision 1.1 1992/05/15 18:38:05 root + * Initial revision + * + * Revision 1.1 1992/04/02 03:23:13 drew + * Initial revision + * + * Revision 1.3 1992/01/27 14:46:29 tthorn + * *** empty log message *** + * + */ + +#include + +#undef STATMASK +#undef CONTROL + +#define IO_BASE 0x350 +#define IRQ_LVL 15 +#define DMA_CH 6 +#define OGMB_CNT 8 +#define ICMB_CNT 16 + +/* I/O Port interface 4.2 */ +/* READ */ +#define ASC_STAT IO_BASE +#define INT_IM 0x80 /* Interrupt Image Flag */ +#define CMD_RDY 0x40 /* Command Port Ready */ +#define CMD_REJ 0x20 /* Command Port Byte Rejected */ +#define ASC_INI 0x10 /* ASC Initialized Flag */ +#define STATMASK 0xf0 /* The lower 4 Bytes are reserved */ + +/* This register serves two purposes + * Diagnostics error code + * Interrupt Status + */ +#define INTR_STAT ASC_STAT+1 +#define ANYINTR 0x80 /* Mailbox Service possible/required */ +#define IMB 0x40 /* 1 Incoming / 0 Outgoing */ +#define MBMASK 0x3f +/* if MSb is zero, the lower bits are diagnostic status * + * Diagnostics: + * 01 No diagnostic error occurred + * 02 RAM failure + * 03 FIFO R/W failed + * 04 SBIC register read/write failed + * 05 Initialization D-FF failed + * 06 Host IRQ D-FF failed + * 07 ROM checksum error + * Interrupt status (bitwise): + * 10NNNNNN outgoing mailbox NNNNNN is free + * 11NNNNNN incoming mailbox NNNNNN needs service + */ + +/* WRITE */ +#define COMMAND ASC_STAT +/* + * COMMAND opcodes + */ +#define NO_OP 0 +#define INITIALIZATION 1 /* initialization after reset (10 bytes) */ +#define DISABLE_UNS_INTR 2 /* disable unsolicited interrupts */ +#define ENABLE_UNS_INTR 3 /* enable unsolicited interrupts */ +#define INTR_ON_FREE_OGMB 4 /* interrupt on free OGMB */ +#define SCSI_SOFT_RESET 5 /* SCSI soft reset */ +#define SCSI_HARD_RESET 6 /* SCSI hard reset acknowledge */ +#define START_OGMB 0x80 /* start command in OGMB (n) */ +#define SCAN_OGMBS 0xc0 /* start multiple commands, signature (n) */ + /* where (n) = lower 6 bits */ +/* + * For INITIALIZATION: + */ +#define BUS_ON 48 /* x 125ns, 48 = 6000ns, BIOS uses 8000ns */ +#define BUS_OFF 24 /* x 125ns, 24 = 3000ns, BIOS uses 1875ns */ + +#define INTR_ACK ASC_STAT+1 + + +#define CONTROL ASC_STAT+2 +#define INT_EN 0x08 /* Interrupt Enable */ +#define DMA_EN 0x04 /* DMA Enable */ +#define SCSI_RES 0x02 /* SCSI Reset */ +#define ASC_RES 0x01 /* ASC Reset */ + +/* Mailbox Definition */ + +struct wd_mailbox{ + unchar status; + unchar scbptr[3]; +}; + + +/* These belong in scsi.h also */ +#undef any2scsi +#define any2scsi(up, p) \ +(up)[0] = (((long)(p)) >> 16); \ +(up)[1] = ((long)(p)) >> 8; \ +(up)[2] = ((long)(p)); + +#define scsi2int(up) ( (((long)*(up)) << 16) + (((long)(up)[1]) << 8) + ((long)(up)[2]) ) + +#define xany2scsi(up, p) \ +(up)[0] = ((long)(p)) >> 24; \ +(up)[1] = ((long)(p)) >> 16; \ +(up)[2] = ((long)(p)) >> 8; \ +(up)[3] = ((long)(p)); + +#define xscsi2int(up) ( (((long)(up)[0]) << 24) + (((long)(up)[1]) << 16) \ + + (((long)(up)[2]) << 8) + ((long)(up)[3]) ) + +#define MAX_CDB 12 +#define MAX_SENSE 14 + +typedef struct scb { /* Command Control Block 5.4.1 */ + unchar op; /* Command Control Block Operation Code */ + unchar idlun; /* op=0,2:Target Id, op=1:Initiator Id */ + /* Outbound data transfer, length is checked*/ + /* Inbound data transfer, length is checked */ + /* Logical Unit Number */ + unchar cdb[12]; /* SCSI Command Block */ + unchar status; /* SCSI Return Status */ + unchar vue; /* Vendor Unique Error Code */ + unchar maxlen[3]; /* Maximum Data Transfer Length */ + unchar dataptr[3]; /* SCSI Data Block Pointer */ + unchar linkptr[3]; /* Next Command Link Pointer */ + unchar direc; /* Transfer Direction */ + unchar reserved2[6]; /* SCSI Command Descriptor Block */ + /* end of hardware SCB */ + Scsi_Cmnd *SCpnt; /* Scsi_Cmnd using this SCB */ + struct scb *next; /* for lists of scbs */ +} Scb; + +/* + * WD7000-specific scatter/gather element structure + */ +typedef struct sgb { + unchar len[3]; + unchar ptr[3]; +} Sgb; + +/* + * Note: MAX_SCBS _must_ be defined large enough to keep ahead of the + * demand for SCBs, which will be at most WD7000_Q * WD7000_SG. 1 is + * added to each because they can be 0. + */ +#define MAX_SCBS ((WD7000_Q+1) * (WD7000_SG+1)) + +/* + * The driver is written to allow host-only commands to be executed. These + * use a 16-byte block called an ICB. + * + * (Currently, only wd7000_info uses this, to get the firmware rev. level.) + */ +#define ICB_STATUS 16 /* set to icmb status by wd7000_intr_handle */ +#define ICB_PHASE 17 /* set to 0 by wd7000_intr_handle */ +#define ICB_LEN 18 /* actually 16; this includes the above */ + +int wd7000_detect(int); +int wd7000_command(Scsi_Cmnd *); +int wd7000_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); +int wd7000_abort(Scsi_Cmnd *, int); +const char *wd7000_info(void); +int wd7000_reset(Scsi_Cmnd *); +int wd7000_biosparam(int, int, int*); + +#ifndef NULL + #define NULL 0 +#endif + +/* + * Define WD7000_SG to be the number of Sgbs that will fit in a block of + * size WD7000_SCRIBBLE. WD7000_SCRIBBLE must be 512, 1024, 2048, or 4096. + * + * The sg_tablesize value will default to SG_NONE for older boards (before + * rev 7.0), but will be changed to WD7000_SG when a newer board is + * detected. + */ +#define WD7000_SCRIBBLE 512 + +#define WD7000_Q OGMB_CNT +#define WD7000_SG (WD7000_SCRIBBLE / sizeof(Sgb)) + +#define WD7000 {\ + "Western Digital WD-7000", \ + wd7000_detect, \ + wd7000_info, wd7000_command, \ + wd7000_queuecommand, \ + wd7000_abort, \ + wd7000_reset, \ + NULL, \ + wd7000_biosparam, \ + WD7000_Q, 7, SG_NONE, 1, 0, 1} +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.blurb b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.blurb new file mode 100644 index 000000000..92aebccbf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.blurb @@ -0,0 +1,12 @@ +NOTE! This driver version is not compatible with the version 1.0c. + This means you have to use the latest version of the snd-util + package (2.0). The earlier ones (from 1.0) will not work. If you have + other programs using ioctl calls of the driver, they must be + recompiled. Most of them will not work without some source + modifications. + + ******** LINUX VERSION 0.99.14 OR LATER IS REQUIRED ******* + + See sound/Readme for more details + + Hannu diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.indent.pro b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.indent.pro new file mode 100644 index 000000000..46686555b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/.indent.pro @@ -0,0 +1,8 @@ +-bad +-bap +-nfca +-bl +-psl +-di16 +-lp +-ip5 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/CHANGELOG b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/CHANGELOG new file mode 100644 index 000000000..78168dd5d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/CHANGELOG @@ -0,0 +1,55 @@ +Changelog for version 2.4 +------------------------- + +Since 2.3b +- Fixed bug which made it impossible to make long recordings to disk. + Recording was not restarted after a buffer overflow situation. +- Limited mixer support for GUS. +- Numerous improvements to the GUS driver by Andrew Robinson. Including + some click removal etc. + +Since 2.3 +- Fixed some minor bugs in the SB16 driver. + +Since 2.2b +- Full SB16 DSP support. 8/16 bit, mono/stereo +- The SCO and FreeBSD versions should be in sync now. There are some + problems with SB16 and GUS in the freebsd versions. + The DMA buffer allocation of the SCO version has been polished but + there could still be some problems. At least it hogs memory. + The DMA channel + configuration method used in the sco/System is a hack. +- Support for the MPU emulation of the SB16. +- Some big arrays are now allocated boot time. This makes the bss segment + smaller which makes it possible to use the full driver with + NetBSD. These arrays are not allocated if no suitable soundcard is available. +- Fixed a bug in the compute_and_set_volume in gus_wave.c +- Fixed the too fast mono playback problem of SB Pro and PAS16. + +Since 2.2 +- Stereo recording for SB Pro. Somehow it was missing and nobody + had noticed it earlier. +- Minor polishing. +- Interpreting of boot time arguments (sound=) for Linux. +- Breakup of sb_dsp.c. Parts of the code has been moved to + sb_mixer.c and sb_midi.c + +Since 2.1 +- Preliminary support for SB16. + - The SB16 mixer is supported in it's native mode. + - Digitized voice capability up to 44.1 kHz/8 bit/mono + (16 bit and stereo support coming in the next release). +- Fixed some bugs in the digitized voice driver for PAS16. +- Proper initialization of the SB emulation of latest PAS16 models. + +- Significantly improved /dev/dsp and /dev/audio support. + - Now supports half duplex mode. It's now possible to record and + playback without closing and reopening the device. + - It's possible to use smaller buffers than earlier. There is a new + ioctl(fd, SNDCTL_DSP_SUBDIVIDE, &n) where n should be 1, 2 or 4. + This call instructs the driver to use smaller buffers. The default + buffer size (0.5 to 1.0 seconds) is divided by n. Should be called + immediately after opening the device. + +Since 2.0 +Just cosmetic changes. diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/COPYING b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/COPYING new file mode 100644 index 000000000..d1509c500 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/COPYING @@ -0,0 +1,25 @@ +/* + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Makefile new file mode 100644 index 000000000..dcf00d5ed --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Makefile @@ -0,0 +1,74 @@ +# Makefile for the Linux sound card driver +# +# Note 2! The CFLAGS definitions are now inherited from the +# parent makes. (hopefully) +# +# + +VERSION = 2.4 +TARGET_OS = linux + +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< + +OBJS = soundcard.o audio.o dmabuf.o sb_dsp.o dev_table.o \ + opl3.o sequencer.o midibuf.o sb_card.o pas2_card.o adlib_card.o \ + pas2_pcm.o pas2_mixer.o pas2_midi.o gus_card.o gus_wave.o mpu401.o \ + gus_midi.o gus_vol.o patmgr.o sb_mixer.o sb16_dsp.o sb_midi.o \ + sb16_midi.o sound_switch.o + +all: local.h sound.a + +/usr/include/sys/soundcard.h: + @echo "WARNING! Your /usr/include/sys/soundcard.h not found." + @echo "Please make a new /usr/include/sys/soundcard.h containing" + @echo "just a line #include " + +sound.a: $(OBJS) + -rm -f sound.a + $(AR) rcs sound.a $(OBJS) + sync + +clean: + rm -f core core.* *.o *.a tmp_make *~ x z *% + rm -f configure sound_stub.c + for i in *.c;do rm -f `basename $$i .c`.s;done + +indent: + for n in *.c;do echo indent $$n;indent $$n;done + +local.h: + $(MAKE) clean + $(MAKE) config + $(MAKE) dep + +config: configure /usr/include/sys/soundcard.h + @echo Compiling Sound Driver v $(VERSION) for Linux + @./configure > local.h + @echo \#define SOUND_VERSION_STRING \"$(VERSION)\" >> local.h + @echo \#define SOUND_CONFIG_DATE \"`date`\" >> local.h + @echo \#define SOUND_CONFIG_BY \"`whoami`\" >> local.h + @echo \#define SOUND_CONFIG_HOST \"`hostname`\" >> local.h + @echo \#define SOUND_CONFIG_DOMAIN \"`domainname`\" >> local.h + +clrconf: + rm -f local.h .depend + +configure: configure.c /usr/include/sys/soundcard.h + $(HOSTCC) -o configure configure.c + @cat .blurb + +dep: + $(MAKE) /usr/include/sys/soundcard.h + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme new file mode 100644 index 000000000..bd47edef7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme @@ -0,0 +1,242 @@ +Release notes for the Linux Sound Driver 2.4 +-------------------------------------------- + +NOTE! The sound driver is a part of the Linux kernel distribution also. + Check that your kernel doesn't have more recent version than this + when installing a separately distributed sound driver. The + version number of this driver is defined in the makefile. + +This version contains a driver for the SB16 also. +The SB16 driver requires separate DMA channels for the 8 and 16 bit +modes. There should be a way to share the 8 bit DMA channels between +these modes but this feature is not supported yet. +The SB16 DSP support is by Joerg Schubert (jsb@sth.ruhr-uni-bochum.de). + +The SB16 driver has also the Midi input capability even at the same +time with the /dev/dsp. Also the WaveBlaster daughter board is supported. +No support for the ASP chip yet (the ASP chip can be installed but it's +not used by the driver). + +You will need the snd-util-2.4.tar.gz and snd-data-0.1.tar.Z +packages to use this driver. They should be in the same +ftp site or BBS from where you got this driver. For +example at nic.funet.fi:pub/OS/Linux/*. + +There is a new version of the tracker program available (tracker-3_19.lzh) but +I don't know where it is available. The tracker 3.10 has bugs and it don't work +without some fixes. Look at the README of the snd-util-2.3. + +If you are looking for the installation instructions, please +look at linux/Readme. + +This version supports the following soundcards: +GUS, SoundBlaster, SB Pro, SB16, Pro Audio Spectrum 16 and AdLib. +In addition there is rather limited support for MPU-401. +(and compatible) midi cards. Also the OPL-3 synthesizer +Most of the features of the /dev/sequencer device file are +available just for GUS owners. + +NOTE! There are separate driver for CD-ROMS supported by + some soundcards. The driver for CDU31A (Fusion 16) is + called cdu31a-0.6.diff.z. It will be contained in the + Linux version 0.99.12. The driver for the CD-ROM of SB Pro + is sbpcd0.4.tar.gz (these were the latest versions when I wrote + this). These files should be at least at sunsite.unc.edu. + Also the SCSI interface of the PAS16 should be supported by + Linux 0.99.13k and later. + + There is also a driver for joystick. Look for file joystick-0.5.tar.gz + (sunsite). + + +Compatibility with the earlier versions +--------------------------------------- + +In this version the ultrasound.h no longer includes the sys/soundcard.h +You have to change the gmod.c of the snd-util-2.0 package and to add an +include for it. + +IMPORTANT!!!!!!!!!!!!!!!!!!!!!! + +This version is not binary or source compatible with the version 1.0c. + +The ioctl() interface has changed completely since version 1.0c. All +programs using this driver must be at least recompiled. +The snd-util-2.0 package contains some utilities for this version. + +The version 1.0c and earlier used a 'nonportable' ioctl calling scheme +where the input argument was passed by value and the output value was +returned as the functional return. For example setting the speed of +/dev/dsp were done as the following: + + int actual_speed; + actual_speed = ioctl(fd, SOUND_PCM_WRITE_RATE, 44100); + +After version 1.99.0 this must be done as the following: + + int actual_speed = 44100; + ioctl(fd, SOUND_PCM_WRITE_RATE, &actual_speed); + +If you have an application written for the version 1.0, you should search +for the strings SNDCTL_ and SOUND_ and to check the parameters. +The following ioctl calls have changed: + + SNDCTL_SEQ_GETOUTCOUNT + SNDCTL_SEQ_GETINCOUNT + SNDCTL_SEQ_TESTMIDI + SNDCTL_DSP_SPEED + SNDCTL_DSP_STEREO + SNDCTL_DSP_GETBLKSIZE + SNDCTL_DSP_SAMPLESIZE + SOUND_PCM_WRITE_CHANNELS + SOUND_PCM_WRITE_FILTER + SOUND_PCM_READ_RATE + SOUND_PCM_READ_CHANNELS + SOUND_PCM_READ_BITS + SOUND_PCM_READ_FILTER + SOUND_PCM_WRITE_BITS + SOUND_PCM_WRITE_RATE + SOUND_MIXER_READ_* (several ones) + SOUND_MIXER_WRITE_* (several ones) + +Since the this version will support more than one synthesizer devices +at the same time, the ioctl(SNDCTL_FM_LOAD_INSTR) is obsolete. In addition +there is some new fields which must be initialized. Look at the sbiset.c in +the snd-util-2.0 package for further info. + +This version is almost 100% compatible with the alpha test version (1.99.9). The +difference is in the installation procedure. + +Using this driver with other operating systems than Linux +--------------------------------------------------------- + +This package contains just the Linux version. The version 2.3 +for SCO is available at nic.funet.fi:pub/OS/Linux/ALPHA/sound. +The version 2.3 doesn't work well with xxxxxBSD. Use the version +2.3 for them. + +/dev/sndstat +------------ + +The /dev/sndstat is now available in the SCO and BSD versions also. + +This is a new devicefile for debugging purposes. A better place for +it is in the /proc -directory but I was just too lazy to implement it +properly. The /dev/sndstat (major 14, minor 6) is a file which returns +info about the current configuration (see the example below). If you +send me a error/problem report, please include a printout from this +device to your message (cat /dev/sndstat). + +Note! This device file is currently present only in the Linux version + of this driver. + +------ cut here --- cat /dev/sndstat example -------- +Sound Driver:1.99.7 (Fri Jul 9 17:01:47 GMT 1993 root@lucifer.savolai.fi) +Config options: 0x00000d4b + +HW config: +Type 4: Gravis Ultrasound at 0x210 irq 15 drq 6 +Type 3: ProAudioSpectrum at 0x388 irq 10 drq 3 +Type 2: SoundBlaster at 0x220 irq 7 drq 1 +Type 1: AdLib at 0x388 irq 0 drq 0 + +PCM devices: +00: Gravis UltraSound +01: Pro Audio Spectrum +02: SoundBlaster 2.0 + +Synth devices: +00: Gravis UltraSound +01: Yamaha OPL-3 + +Midi devices: +00: Gravis UltraSound +01: Pro Audio Spectrum + +Mixer(s) installed +------ cut here ---- End of Example ----------- + +Known bugs/limitations +---------------------- + +- High speed recording of long audio samples (>20 second) to disk + is not possible. Everything works until next sync() which delays the + recording process too much. A delay longer than 0.1 to 0.3 seconds is + too much. +- The SB16 driver sometimes swaps the left and right channels together. +- Midi input doesn't work with SB and SB Pro (SB16 works). +- It's not possible to open /dev/dsp (or /dev/audio) while the + /dev/sequencer is open for output and GUS is the only soundcard + installed. It's possible if /dev/dsp is opened before /dev/sequencer + but at this time the GUS is not available for access via /dev/sequencer. + This is a limitation of the driver. +- MPU-401 driver hangs the computer on boot if there is no MPU-401 installed. + It uses by default the I/O port 0x330 whic is used by Adaptec 1542 SCSI + adapter. +- There are some problems in midi input with MPU-401 and the SB16 midi + (MPU-401 emulation). This makes it impossible to read long sysex dumps + using these devices. +- The /dev/sequencer playback to GUS sounds sometimes rather weird. Hitting + ^C and playing again should solve this problem. This is propably caused by + incompatibilities between GUS and certain VLB motherboards (like mine). + Try to avoid + switching between VTs while patches are being loaded to the GUS. + This problem disappears completely if you define GUS_PATCH_NO_DMA in the + local.h (after make config in linux). The drawback is that patch loading + without DMA takes several times longer than with DMA. +- There is a skeleton of the patch manager support. It don't work in + this version. + + +Future development +------------------ + +- Since this driver is no longer just the Linux Sound Driver, it's time + to give it a new name. I have planned to use name VoxWare. +- I'm writing a Hacker's guide to the VoxWare sound driver. Should + be ready within this(/next) year (alpha version). +- Completion of the ISC, SCO and BSD ports. Port to SVR4.2. +- I'm interested to implement/include support for new soundcards and + operating systems. + + Hint for the soundcard and OS manufacturers: + I'm collecting soundcards (high end ones) and SDKs for them. In + addition I'm collecting PC operating systems. I will be happy if + somebody sends me such items. In addition such kind of donation + makes it easier to change the VoxWare driver to support your + soundcard or operating system. However, please contact me before + sending anything. + +I will propably release some fix versions within this and next year. At +least when the non-Linux versions get ready. The next major release (3.0) +will be quite complete rewrite and released after about a year (end of 94 or +beginning of 95). + + +Contributors +------------ + +This driver contains code by several contributors. In addition several other +persons have given usefull suggestions. The following is a list of major +contributors. (I could have forgotten some names.) + + Craig Metz 1/2 of the PAS16 Mixer and PCM support + Rob Hooft Volume computation algorithm for the FM synth. + Mika Liljeberg uLaw encoding and decoding routines + Greg Lee Volume computation algorithm for the GUS and + lot's of valuable suggestions. + Andy Warner ISC port + Jim Lowe FreeBSD port + Anders Baekgaard Bughunting and valuable suggestions. + Joerg Schubert SB16 DSP support. + Andrew Robinson Improvements to the GUS driver + +Regards, + +Hannu Savolainen +hsavolai@cs.helsinki.fi + +Snail mail: Hannu Savolainen + Pallaksentie 4 A 2 + 00970 Helsinki + Finland diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme.linux b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme.linux new file mode 100644 index 000000000..d585f5968 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/Readme.linux @@ -0,0 +1,253 @@ +Sound Driver version 2.4 for Linux +---------------------------------- + +NOTE! The sound driver is now a part of the Linux kernel distribution. + Check that your kernel doesn't have more recent version than this + when installing a separately distributed sound driver. The + version number of this driver is defined in the makefile. + +Installation +------------ + +- Since this driver is a part of the Linux kernel distribution, no + special steps are required to build the driver itself. + +- In case you are installing a separately distributed sound driver, + you have to do some additional steps. + - Remove all files from the linux/drivers/sound. Old files could + sometimes cause trouble. + - cd linux/drivers. + - gunzip -c snd-driv-X.Y.tar.gz|tar xvf - + - cd ./sound + - cp soundcard.h ultrasound.h /usr/include/linux + +- To build the device files for this driver, you need to run the enclosed + shell script (at the end of this file). + +- Create /usr/include/sys/soundcard.h whic contains just a line: +#include + +- Create /usr/include/sys/ultrasound.h whic contains just a line: +#include + +Boot time configuration (using lilo) +------------------------------------ + +This version of the sound driver has capability to accept the configuration +parameters from the boot loader (for example lilo). By default the +driver is booted using the parameters given before compiling the driver +('make config' or 'make soundconf'). If the kernel is booted using lilo and +the boot command is given manually, it's possible to give the configuration +parameters on the command line. Just hold down the key when lilo +starts. Then give the boot command manually and append a sound= argument +to the boot command line. For example: + +lilo boot: linux sound=0x222071,0x138800 + +The sound= argument could contain several configuration entries separated by a +comma. Each option gives the configuration for one sound device. +Give the options in the order given below. Other order of use is undefined. +Each option is encoded as the following: + + 0xTaaaId, where + || || + || |+---- d = DMA channel (0, 1, 3, 5, 6 or 7) + || +----- I = IRQ (HEXADECIMAL!!! 1=1, ..., 9=9, 10=a, ..., 15=f) + |+-------- aaa = I/O address (hexadecimal) + +---------- T = device type 1=FM Synth (YM3812 or OPL3) + 2=SoundBlaster (1.0 to 2.0, Pro, 16) + 3=ProAudioSpectrum16 + 4=Gravis UltraSound + 5=MPU-401 UART midi + 6=SB16 (16 bit DMA number) + 7=SB16 Midi (MPU-401 emulation) + +These are the configuration templates for various soundcards: + + 0) Disable the sound driver + + sound=0 + + 1) AdLib + + sound=0x138800 + + 2) SoundBlaster family and compatibles + + sound=0x2220Id,0x138800 (remember to set the IRQ and DMA) + or if you have SB16 or SB16ASP, you have to use the following: + (use the same IRQ (the I colums) in all three places. The + the D is the 16 bit DMA channel (5 to 7) and the d is + the 8 bit one (1 or 3). The X is the 2nd digit of the + midi IO address (3 or 0)). + sound=0x2220Id,0x6220ID,0x73X0I0,0x138800 + + 3) ProAudioSpectrum16, ProAudioStudio16, Logitech Soundman16 etc. + + sound=0x3388Id,0x2220Id,0x138800 (set the DMAs and IRQs) + + 4) Gravis UltraSound + + sound=0x42X0Id (X is 1, 2, 3 or 4. Set the DMA and IRQ) + + 5) MPU-401 + + sound=0x5aaaI0 + +If you have more than one soundcards, you have to concatenate the options +for each of the cards. There cannot be more than one sound= argument in the +command line. For example use "sound=0x5aaaI0,0x138800" if you have AdLib +and MPU-401 on your system. +If there are two or more sound= arguments +in the boot command line, just the last one takes effect. The earlier ones +will be ignored silently. + +The boot time configuration feature is intended mainly for distributors of +precompiled kernels. When this feature is used, drivers for all of the +cards have to be enabled before compiling the driver. The configurator program +doesn't enable MPU-401 when the full driver option is selected. It must be +enabled by uncommenting "#define EXCLUDE_MPU401" in the sound/local.h. + +Important note! + +The sound driver is enabled by default. If the kernel is booted without +using the sound=0 option, the sound driver is initialized using the compile +time parameters. This could be dangerous (specially if the MPU-401 driver +is enabled with I/O address 0x330 (used by AHA-1542 also)). If you want to +compile the driver to be inactive by default, you have to append a +#define SND_DEFAULT_ENABLE 0 +to the sound/local.h before compiling the driver. + +Remember to check that the sound setup routine is included in the +bootparams structure in linux/init/main.c. It should contain the following +lines: + +#ifdef CONFIG_SOUND + { "sound=", sound_setup }, +#endif + +In case these lines were not there, you have to insert them (the driver works +without them but it's not possible to give the boot time parameters for the +sound driver). Add also the following line somewhere near the beginning of +linux/init/main.c: + +extern void sound_setup(char *str, int *ints); + +Problems +-------- + +If you have any kind of problems, there is a debugging feature which +could help you to solve the problem. To use it, just execute the +command: + + cat /dev/sndstat + +and look at the output. It should display some usefull info about the +driver configuration. If there is no /dev/sndstat +(/dev/sndstat: No such file or directory), ensure that you have executed the +soundinstall script (at the end of this file). The message: +/dev/dsp: No such device means that you don't have the sound driver installed +on your kernel or the driver version is earlier than 1.99.6. + + +- /dev/???????: No such file or directory. +Run the script at the end of this file. + +- /dev/???????: No such device. +You have not booted with a kernel containing the driver or the I/O address +configuration doesn't match your hardaware. + +- The module player (str) plays just a second and then stops completely. +You have incorrect IRQ settings (usual with SB cards). + +- There is pauses in the playback of the module player (str). +The str program requires more than 40% of the speed of a 486/50 to play +without pauses at 44 kHz speed. A 386/25 can hardly play faster than 22 kHz. +You should use lower speed (-s speed), buy a faster computer or a Gravis +UltraSound card. (If you already have GUS, you should use gmod and not the +str). If the DSP_BUFFSIZE in the sound/local.h is less than (nr_channels* +speed_in_Hz * (bits/8))/2, it could explain the pausing problem. Also check +that the turbo swich is on and don't run applications like weather forecasting +on background. Sometimes (very rarely) an IRQ conflict can cause similar +problems with SB cards. +If you want to play modules on a 386sx while recompiling the world, buy a GUS. +It runs without burning your CPU. + +Hannu Savolainen +hsavolai@cs.helsinki.fi + +----------------- cut here ------------------------------ +#!/bin/sh +# +# soudinstall +# +# by Craig Metz - cmetz@thor.tjhsst.edu +# +# Create the devices +# +# Mixer (14, 0) +# +if [ -e /dev/mixer ]; then + rm -f /dev/mixer +fi +mknod -m 666 /dev/mixer c 14 0 + +if [ -e /dev/mixer1 ]; then + rm -f /dev/mixer1 +fi +mknod -m 666 /dev/mixer1 c 14 16 +# +# Sequencer (14, 1) +# +if [ -e /dev/sequencer ]; then + rm -f /dev/sequencer +fi +mknod -m 666 /dev/sequencer c 14 1 +# +# MIDI (14, 2) [ Not implemented ] +# +if [ -e /dev/midi ]; then + rm -f /dev/midi +fi +mknod -m 666 /dev/midi c 14 2 +# +# DSP (14, 3) +# +if [ -e /dev/dsp ]; then + rm -f /dev/dsp +fi +mknod -m 666 /dev/dsp c 14 3 +# +# SPARC audio (14, 4) [ Not fully implemented ] +# +if [ -e /dev/audio ]; then + rm -f /dev/audio +fi +mknod -m 666 /dev/audio c 14 4 +# +# DSP2 (14, 19) /dev/dsp for the second soundcard. +# Also the SB emulation part of the +# PAS16 card. +# +if [ -e /dev/dsp1 ]; then + rm -f /dev/dsp1 +fi +mknod -m 666 /dev/dsp1 c 14 19 +# +# SPARC audio1 (14, 20) [ Not fully implemented ] +# /dev/audio for the second soundcard. +# Also the SB emulation part of the +# PAS16 card. +# +if [ -e /dev/audio1 ]; then + rm -f /dev/audio1 +fi +mknod -m 666 /dev/audio1 c 14 20 +# +# /dev/sndstat (14,6) For debugging purposes +# +if [ -e /dev/sndstat ]; then + rm -f /dev/sndstat +fi +mknod -m 666 /dev/sndstat c 14 6 +exit 0 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/adlib_card.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/adlib_card.c new file mode 100644 index 000000000..3b7df5ebd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/adlib_card.c @@ -0,0 +1,51 @@ +/* + * sound/adlib_card.c + * + * Detection routine for the AdLib card. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812) + +long +attach_adlib_card (long mem_start, struct address_info *hw_config) +{ + + if (opl3_detect (FM_MONO)) + { + mem_start = opl3_init (mem_start); + } + return mem_start; +} + +int +probe_adlib (struct address_info *hw_config) +{ + return opl3_detect (FM_MONO); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/audio.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/audio.c new file mode 100644 index 000000000..03d6b7fca --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/audio.c @@ -0,0 +1,353 @@ +/* + * sound/audio.c + * + * Device file manager for /dev/audio + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD +#ifndef EXCLUDE_AUDIO + +#include "ulaw.h" + +#define ON 1 +#define OFF 0 + +static int wr_buff_no[MAX_DSP_DEV]; /* != -1, if there is a + * incomplete output block */ +static int wr_buff_size[MAX_DSP_DEV], wr_buff_ptr[MAX_DSP_DEV]; + +static int audio_mode[MAX_DSP_DEV]; +#define AM_NONE 0 +#define AM_WRITE 1 +#define AM_READ 2 + +static char *wr_dma_buf[MAX_DSP_DEV]; + +int +audio_open (int dev, struct fileinfo *file) +{ + int ret; + int bits; + int dev_type = dev & 0x0f; + int mode = file->mode & O_ACCMODE; + + dev = dev >> 4; + + if (dev_type == SND_DEV_DSP16) + bits = 16; + else + bits = 8; + + if ((ret = DMAbuf_open (dev, mode)) < 0) + return ret; + + if (DMAbuf_ioctl (dev, SNDCTL_DSP_SAMPLESIZE, bits, 1) != bits) + { + audio_release (dev, file); + return RET_ERROR (ENXIO); + } + + wr_buff_no[dev] = -1; + audio_mode[dev] = AM_NONE; + + return ret; +} + +void +audio_release (int dev, struct fileinfo *file) +{ + int mode; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + + DMAbuf_release (dev, mode); +} + +#ifdef NO_INLINE_ASM +static void +translate_bytes (const unsigned char *table, unsigned char *buff, unsigned long n) +{ + unsigned long i; + + for (i = 0; i < n; ++i) + buff[i] = table[buff[i]]; +} + +#else +extern inline void +translate_bytes (const void *table, void *buff, unsigned long n) +{ + __asm__ ("cld\n" + "1:\tlodsb\n\t" + "xlatb\n\t" + "stosb\n\t" + "loop 1b\n\t": + :"b" ((long) table), "c" (n), "D" ((long) buff), "S" ((long) buff) + :"bx", "cx", "di", "si", "ax"); +} + +#endif + +int +audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + int c, p, l; + int err; + int dev_type = dev & 0x0f; + + dev = dev >> 4; + + p = 0; + c = count; + + if (audio_mode[dev] == AM_READ) /* Direction changed */ + { + wr_buff_no[dev] = -1; + } + + audio_mode[dev] = AM_WRITE; + + if (!count) /* Flush output */ + { + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return 0; + } + + while (c) + { /* Perform output blocking */ + if (wr_buff_no[dev] < 0) /* There is no incomplete buffers */ + { + if ((wr_buff_no[dev] = DMAbuf_getwrbuffer (dev, &wr_dma_buf[dev], &wr_buff_size[dev])) < 0) + return wr_buff_no[dev]; + wr_buff_ptr[dev] = 0; + } + + l = c; + if (l > (wr_buff_size[dev] - wr_buff_ptr[dev])) + l = (wr_buff_size[dev] - wr_buff_ptr[dev]); + + if (!dsp_devs[dev]->copy_from_user) + { /* No device specific copy routine */ + COPY_FROM_USER (&wr_dma_buf[dev][wr_buff_ptr[dev]], buf, p, l); + } + else + dsp_devs[dev]->copy_from_user (dev, + wr_dma_buf[dev], wr_buff_ptr[dev], buf, p, l); + + + /* Insert local processing here */ + + if (dev_type == SND_DEV_AUDIO) + { +#ifdef linux + /* This just allows interrupts while the conversion is running */ + __asm__ ("sti"); +#endif + translate_bytes (ulaw_dsp, &wr_dma_buf[dev][wr_buff_ptr[dev]], l); + } + + c -= l; + p += l; + wr_buff_ptr[dev] += l; + + if (wr_buff_ptr[dev] >= wr_buff_size[dev]) + { + if ((err = DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev])) < 0) + return err; + + wr_buff_no[dev] = -1; + } + + } + + return count; +} + +int +audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + int c, p, l; + char *dmabuf; + int buff_no; + int dev_type = dev & 0x0f; + + dev = dev >> 4; + p = 0; + c = count; + + if (audio_mode[dev] == AM_WRITE) + { + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + } + + audio_mode[dev] = AM_READ; + + while (c) + { + if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &l)) < 0) + return buff_no; + + if (l > c) + l = c; + + /* Insert any local processing here. */ + + if (dev_type == SND_DEV_AUDIO) + { +#ifdef linux + /* This just allows interrupts while the conversion is running */ + __asm__ ("sti"); +#endif + + translate_bytes (dsp_ulaw, dmabuf, l); + } + + COPY_TO_USER (buf, p, dmabuf, l); + + DMAbuf_rmchars (dev, buff_no, l); + + p += l; + c -= l; + } + + return count - c; +} + +int +audio_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg) +{ + int dev_type = dev & 0x0f; + dev = dev >> 4; + + switch (cmd) + { + case SNDCTL_DSP_SYNC: + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return DMAbuf_ioctl (dev, cmd, arg, 0); + break; + + case SNDCTL_DSP_POST: + if (wr_buff_no[dev] >= 0) + { + DMAbuf_start_output (dev, wr_buff_no[dev], wr_buff_ptr[dev]); + + wr_buff_no[dev] = -1; + } + return 0; + break; + + case SNDCTL_DSP_RESET: + wr_buff_no[dev] = -1; + return DMAbuf_ioctl (dev, cmd, arg, 0); + break; + + default: + if (dev_type == SND_DEV_AUDIO) + return RET_ERROR (EIO); + + return DMAbuf_ioctl (dev, cmd, arg, 0); + } +} + +long +audio_init (long mem_start) +{ + return mem_start; +} + +#else +/* Stub versions */ + +int +audio_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + return RET_ERROR (EIO); +} + +int +audio_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + return RET_ERROR (EIO); +} + +int +audio_open (int dev, struct fileinfo *file) + { + return RET_ERROR (ENXIO); + } + +void +audio_release (int dev, struct fileinfo *file) + { + }; +int +audio_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg) +{ + return RET_ERROR (EIO); +} + +int +audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig) +{ + return RET_ERROR (EIO); +} + +long +audio_init (long mem_start) +{ + return mem_start; +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/configure.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/configure.c new file mode 100644 index 000000000..f6e4cb66c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/configure.c @@ -0,0 +1,550 @@ +/* + * sound/configure.c - Configuration program for the Linux Sound Driver + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include + +#define B(x) (1 << (x)) + +/* + * Option numbers + */ + +#define OPT_PAS 0 +#define OPT_SB 1 +#define OPT_ADLIB 2 +#define OPT_LAST_MUTUAL 2 + +#define OPT_GUS 3 +#define OPT_MPU401 4 + +#define OPT_HIGHLEVEL 5 +#define OPT_SBPRO 5 +#define OPT_SB16 6 +#define OPT_AUDIO 7 +#define OPT_MIDI_AUTO 8 +#define OPT_MIDI 9 +#define OPT_YM3812_AUTO 10 /* Select this automaticly if user selects + * MIDI or AdLib driver */ +#define OPT_YM3812 11 /* Select this if the previous one was not + * selected */ +#define OPT_SEQUENCER 12 +#define OPT_CHIP_MIDI 13 /* New support added at UW - Milwauklee UW - + * Milwauklee */ +#define OPT_LAST 12 + +#define ANY_DEVS (B(OPT_AUDIO)|B(OPT_MIDI)|B(OPT_SEQUENCER)|B(OPT_GUS)|B(OPT_MPU401)) + +typedef struct + { + unsigned long conditions; + unsigned long exclusive_options; + char macro[20]; + int verify; + int alias; + int default_answ; + } + +hw_entry; + + +/* + * The rule table for the driver options. The first field defines a set of + * options which must be selected before this entry can be selected. The + * second field is a set of options which are not allowed with this one. If + * the fourth field is zero, the option is selected without asking + * confirmation from the user. + * + * With this version of the rule table it is possible to select just one type of + * hardware. + * + * NOTE! Keep the following table and the questions array in sync with the + * option numbering! + */ + +hw_entry hw_table[] = +{ +/* 0 */ + {0, 0, "PAS", 1, 0, 0}, + {0, 0, "SB", 1, 0, 0}, + {0, B (OPT_PAS) | B (OPT_SB), "ADLIB", 1, 0, 0}, + +/* 3 */ + {0, 0, "GUS", 1, 0, 0}, + {0, 0, "MPU401", 1, 0, 0}, + {B (OPT_SB), B (OPT_PAS), "SBPRO", 1, 0, 1}, + {B (OPT_SB) | B (OPT_SBPRO), B (OPT_PAS), "SB16", 1, 0, 1}, + {B (OPT_SB) | B (OPT_PAS) | B (OPT_GUS), 0, "AUDIO", 1, 0, 1}, + {B (OPT_MPU401), 0, "MIDI_AUTO", 0, OPT_MIDI, 0}, + {B (OPT_SB) | B (OPT_PAS) | B (OPT_MPU401) | B (OPT_GUS), 0, "MIDI", 1, 0, 1}, + {B (OPT_ADLIB), 0, "YM3812_AUTO", 0, OPT_YM3812, 0}, + {B (OPT_SB) | B (OPT_PAS) | B (OPT_ADLIB), B (OPT_YM3812_AUTO), "YM3812", 1, 0, 1}, +/* 10 */ + {B (OPT_MIDI) | B (OPT_YM3812) | B (OPT_YM3812_AUTO) | B (OPT_GUS), 0, "SEQUENCER", 0, 0, 1}, + {0, 0, "CHIP_MIDI", 1, 0, 0} +}; + +char *questions[] = +{ + "ProAudioSpectrum 16 support", + "SoundBlaster support", + "AdLib support", + "Gravis Ultrasound support", + "MPU-401 support (NOT for SB16)", + + "SoundBlaster Pro support", + "SoundBlaster 16 support", + "digitized voice support", + "This should not be asked", + "MIDI interface support", + "This should not be asked", + "FM synthesizer (YM3812/OPL-3) support", + "/dev/sequencer support", + "MIDI on CHIP support" +}; + +unsigned long selected_options = 0; +int sb_dma = 0; + +int +can_select_option (int nr) +{ + switch (nr) + { + case 0: + fprintf (stderr, "The SoundBlaster, AdLib and ProAudioSpectrum\n" + "cards cannot be installed at the same time\n"); + fprintf (stderr, "\nSelect at most one of them:\n"); + fprintf (stderr, " - ProAudioSpectrum 16\n"); + fprintf (stderr, " - SoundBlaster / SB Pro\n"); + fprintf (stderr, " (Could be selected with PAS16 also\n" + " since there is a SB emulation on it)\n"); + fprintf (stderr, " - AdLib\n"); + fprintf (stderr, "\nDon't enable SoundBlaster if you have GUS at 0x220!\n\n"); + break; + + case OPT_LAST_MUTUAL + 1: + fprintf (stderr, "\nThe following cards should work with any other cards.\n" + "CAUTION! Don't enable MPU-401 if you don't have it.\n"); + break; + + case OPT_HIGHLEVEL: + fprintf (stderr, "\nSelect one or more of the following options\n"); + break; + + + } + + if (hw_table[nr].conditions) + if (!(hw_table[nr].conditions & selected_options)) + return 0; + + if (hw_table[nr].exclusive_options) + if (hw_table[nr].exclusive_options & selected_options) + return 0; + + return 1; +} + +int +think_positively (int def_answ) +{ + char answ[512]; + int len; + + if ((len = read (0, &answ, sizeof (answ))) < 1) + { + fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); + + perror ("stdin"); + printf ("#undef CONFIGURE_SOUNDCARD\n"); + printf ("#undef KERNEL_SOUNDCARD\n"); + exit (-1); + } + + if (len < 2) /* There is an additional LF at the end */ + return def_answ; + + answ[len - 1] = 0; + + if (!strcmp (answ, "y") || !strcmp (answ, "Y")) + return 1; + + return 0; +} + +int +ask_value (char *format, int default_answer) +{ + char answ[512]; + int len, num; + +play_it_again_Sam: + + if ((len = read (0, &answ, sizeof (answ))) < 1) + { + fprintf (stderr, "\n\nERROR! Cannot read stdin\n"); + + perror ("stdin"); + printf ("#undef CONFIGURE_SOUNDCARD\n"); + printf ("#undef KERNEL_SOUNDCARD\n"); + exit (-1); + } + + if (len < 2) /* There is an additional LF at the end */ + return default_answer; + + answ[len - 1] = 0; + + if (sscanf (answ, format, &num) != 1) + { + fprintf (stderr, "Illegal format. Try again: "); + goto play_it_again_Sam; + } + + return num; +} + +int +main (int argc, char *argv[]) +{ + int i, num, def_size, full_driver = 1; + char answ[10]; + + printf ("/*\tGenerated by configure. Don't edit!!!!\t*/\n\n"); + + fprintf (stderr, "\nConfiguring the sound support\n\n"); + + fprintf (stderr, "Do you want to include full version of the sound driver (n/y) ? "); + + if (think_positively (0)) + { + selected_options = 0xffffffff & ~B (OPT_MPU401); + fprintf (stderr, "Note! MPU-401 driver was not enabled\n"); + full_driver = 1; + } + else + { + fprintf (stderr, "Do you want to DISABLE the Sound Driver (n/y) ?"); + if (think_positively (0)) + { + printf ("#undef CONFIGURE_SOUNDCARD\n"); + printf ("#undef KERNEL_SOUNDCARD\n"); + exit (0); + } + /* Partial driver */ + + full_driver = 0; + + for (i = 0; i <= OPT_LAST; i++) + if (can_select_option (i)) + { + if (!(selected_options & B (i))) /* Not selected yet */ + if (!hw_table[i].verify) + { + if (hw_table[i].alias) + selected_options |= B (hw_table[i].alias); + else + selected_options |= B (i); + } + else + { + int def_answ = hw_table[i].default_answ; + + fprintf (stderr, + def_answ ? " %s (y/n) ? " : " %s (n/y) ? ", + questions[i]); + if (think_positively (def_answ)) + if (hw_table[i].alias) + selected_options |= B (hw_table[i].alias); + else + selected_options |= B (i); + } + } + } + + if (selected_options & B(OPT_SB16)) + selected_options |= B(OPT_SBPRO); + + if (!(selected_options & ANY_DEVS)) + { + printf ("#undef CONFIGURE_SOUNDCARD\n"); + printf ("#undef KERNEL_SOUNDCARD\n"); + fprintf (stderr, "\n*** This combination is useless. Sound driver disabled!!! ***\n\n"); + exit (0); + } + else + printf ("#define KERNEL_SOUNDCARD\n"); + + for (i = 0; i <= OPT_LAST; i++) + if (!hw_table[i].alias) + if (selected_options & B (i)) + printf ("#undef EXCLUDE_%s\n", hw_table[i].macro); + else + printf ("#define EXCLUDE_%s\n", hw_table[i].macro); + + + printf ("#define EXCLUDE_PRO_MIDI\n"); + printf ("#define EXCLUDE_CHIP_MIDI\n"); + + /* + * IRQ and DMA settings + */ + printf ("\n"); + +#if defined(linux) + if (selected_options & B (OPT_SB) && selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) + { + fprintf (stderr, "\nIRQ number for SoundBlaster?\n" + "The IRQ adress is defined by the jumpers on your card and\n" + "7 is the factory default. Valid values are 9, 5, 7 and 10.\n" + "Enter the value: "); + + num = ask_value ("%d", 7); + if (num != 9 && num != 5 && num != 7 && num != 10) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 7; + } + fprintf (stderr, "SoundBlaster IRQ set to %d\n", num); + printf ("#define SBC_IRQ %d\n", num); + + if (selected_options & B (OPT_SBPRO)) + { + + fprintf (stderr, "\nDMA channel for SoundBlaster?\n" + "For SB 1.0, 1.5 and 2.0 this MUST be 1\n" + "SB Pro supports DMA channels 0, 1 and 3 (jumper)\n" + "For SB16 give the 8 bit DMA# here\n" + "The default value is 1\n" + "Enter the value: "); + + num = ask_value ("%d", 1); + if (num < 0 || num > 3) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 1; + } + fprintf (stderr, "SoundBlaster DMA set to %d\n", num); + printf ("#define SBC_DMA %d\n", num); + sb_dma = num; + } + + if (selected_options & B (OPT_SB16)) + { + + fprintf (stderr, "\n16 bit DMA channel for SoundBlaster 16?\n" + "Possible values are 5, 6 or 7\n" + "The default value is 6\n" + "Enter the value: "); + + num = ask_value ("%d", 6); + if ((num < 5 || num > 7) && (num != sb_dma)) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 6; + } + fprintf (stderr, "SoundBlaster DMA set to %d\n", num); + printf ("#define SB16_DMA %d\n", num); + + fprintf (stderr, "\nI/O base for SB16 Midi?\n" + "Possible values are 300 and 330\n" + "The factory default is 330\n" + "Enter the SB16 Midi I/O base: "); + + num = ask_value ("%x", 0x330); + fprintf (stderr, "SB16 Midi I/O base set to %03x\n", num); + printf ("#define SB16MIDI_BASE 0x%03x\n", num); + } + } + + if (selected_options & B (OPT_PAS)) + { + if (selected_options & (B (OPT_AUDIO) | B (OPT_MIDI))) + { + fprintf (stderr, "\nIRQ number for ProAudioSpectrum?\n" + "The recommended value is the IRQ used under DOS.\n" + "Please refer to the ProAudioSpectrum User's Guide.\n" + "The default value is 10.\n" + "Enter the value: "); + + num = ask_value ("%d", 10); + if (num == 6 || num < 3 || num > 15 || num == 2) /* Illegal */ + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 10; + } + fprintf (stderr, "ProAudioSpectrum IRQ set to %d\n", num); + printf ("#define PAS_IRQ %d\n", num); + } + + if (selected_options & B (OPT_AUDIO)) + { + fprintf (stderr, "\nDMA number for ProAudioSpectrum?\n" + "The recommended value is the DMA channel under DOS.\n" + "Please refer to the ProAudioSpectrum User's Guide.\n" + "The default value is 3\n" + "Enter the value: "); + + num = ask_value ("%d", 3); + if (num == 4 || num < 0 || num > 7) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 3; + } + fprintf (stderr, "\nProAudioSpectrum DMA set to %d\n", num); + printf ("#define PAS_DMA %d\n", num); + } + } + + if (selected_options & B (OPT_GUS)) + { + fprintf (stderr, "\nI/O base for Gravis Ultrasound?\n" + "Valid choises are 210, 220, 230, 240, 250 or 260\n" + "The factory default is 220\n" + "Enter the GUS I/O base: "); + + num = ask_value ("%x", 0x220); + if ((num > 0x260) || ((num & 0xf0f) != 0x200) || ((num & 0x0f0) > 0x060)) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 0x220; + } + + if ((selected_options & B (OPT_SB)) && (num == 0x220)) + { + fprintf (stderr, "FATAL ERROR!!!!!!!!!!!!!!\n" + "\t0x220 cannot be used if SoundBlaster is enabled.\n" + "\tRun the config again.\n"); + printf ("#undef CONFIGURE_SOUNDCARD\n"); + printf ("#undef KERNEL_SOUNDCARD\n"); + exit (-1); + } + fprintf (stderr, "GUS I/O base set to %03x\n", num); + printf ("#define GUS_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for Gravis UltraSound?\n" + "The recommended value is the IRQ used under DOS.\n" + "Please refer to the Gravis Ultrasound User's Guide.\n" + "The default value is 15.\n" + "Enter the value: "); + + num = ask_value ("%d", 15); + if (num == 6 || num < 3 || num > 15 || num == 2) /* Invalid */ + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 15; + } + fprintf (stderr, "Gravis UltraSound IRQ set to %d\n", num); + printf ("#define GUS_IRQ %d\n", num); + + fprintf (stderr, "\nDMA number for Gravis UltraSound?\n" + "The recommended value is the DMA channel under DOS.\n" + "Please refer to the Gravis Ultrasound User's Guide.\n" + "The default value is 6\n" + "Enter the value: "); + + num = ask_value ("%d", 6); + if (num == 4 || num < 0 || num > 7) + { + fprintf (stderr, "*** Illegal input! ***\n"); + num = 6; + } + fprintf (stderr, "\nGravis UltraSound DMA set to %d\n", num); + printf ("#define GUS_DMA %d\n", num); + } + + if (selected_options & B (OPT_MPU401)) + { + fprintf (stderr, "\nI/O base for MPU-401?\n" + "The factory default is 330\n" + "Enter the MPU-401 I/O base: "); + + num = ask_value ("%x", 0x330); + fprintf (stderr, "MPU-401 I/O base set to %03x\n", num); + printf ("#define MPU_BASE 0x%03x\n", num); + + fprintf (stderr, "\nIRQ number for MPU-401?\n" + "Valid numbers are: 3, 4, 5, 7 and 9(=2).\n" + "The default value is 5.\n" + "Enter the value: "); + + num = ask_value ("%d", 5); + if (num == 6 || num < 3 || num > 15) /* Used for floppy */ + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = 5; + } + fprintf (stderr, "MPU-401 IRQ set to %d\n", num); + printf ("#define MPU_IRQ %d\n", num); + } +#endif + + if (selected_options & B (OPT_AUDIO)) + { + def_size = 16384; + + if (selected_options & (B (OPT_SBPRO) | B (OPT_PAS) | B(OPT_SB16))) + def_size = 32768; + +#ifndef __386BSD__ + if (((selected_options & B (OPT_PAS)) || (selected_options & B (OPT_SB16))) && + !full_driver) + def_size = 65536; /* PAS16 or SB16 */ +#endif + + fprintf (stderr, "\nSelect the DMA buffer size (4096, 16384, 32768 or 65536 bytes)\n" + "%d is recommended value for this configuration.\n" + "Enter the value: ", def_size); + + num = ask_value ("%d", def_size); + if (num != 4096 && num != 16384 && num != 32768 && num != 65536) + { + + fprintf (stderr, "*** Illegal input! ***\n"); + num = def_size; + } + fprintf (stderr, "The DMA buffer size set to %d\n", num); + printf ("#define DSP_BUFFSIZE %d\n", num); + } + + printf ("#define SELECTED_SOUND_OPTIONS\t0x%08x\n", selected_options); + fprintf (stderr, "The sound driver is now configured.\n"); + +#if defined(SCO) || defined(ISC) || defined(SYSV) + fprintf(stderr, "Rember to update the System file\n"); +#endif + + exit (0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dev_table.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dev_table.c new file mode 100644 index 000000000..ca0e5145f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dev_table.c @@ -0,0 +1,205 @@ +/* + * sound/dev_table.c + * + * Device call tables. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define _DEV_TABLE_C_ +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +long +sndtable_init (long mem_start) +{ + int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + + for (i = 0; i < (n - 1); i++) + if (supported_drivers[i].enabled) + if (supported_drivers[i].probe (&supported_drivers[i].config)) + { +#ifndef SHORT_BANNERS + printk ("snd%d", + supported_drivers[i].card_type); +#endif + + mem_start = supported_drivers[i].attach (mem_start, &supported_drivers[i].config); +#ifndef SHORT_BANNERS + printk (" at 0x%x irq %d drq %d\n", + supported_drivers[i].config.io_base, + supported_drivers[i].config.irq, + supported_drivers[i].config.dma); +#endif + } + else + supported_drivers[i].enabled=0; /* Mark as not detected */ + return mem_start; +} + +int +sndtable_probe (int unit, struct address_info *hw_config) +{ + int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + + if (!unit) + return TRUE; + + for (i = 0; i < (n - 1); i++) + if (supported_drivers[i].card_type == unit) + { + supported_drivers[i].config.io_base = hw_config->io_base; + supported_drivers[i].config.irq = hw_config->irq; + supported_drivers[i].config.dma = hw_config->dma; + if (supported_drivers[i].probe (hw_config)) return 1; + supported_drivers[i].enabled=0; /* Mark as not detected */ + return 0; + } + + return FALSE; +} + +int +sndtable_init_card (int unit, struct address_info *hw_config) +{ + int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + + if (!unit) + { + if (sndtable_init (0) != 0) + panic ("snd: Invalid memory allocation\n"); + return TRUE; + } + + for (i = 0; i < (n - 1); i++) + if (supported_drivers[i].card_type == unit) + { + supported_drivers[i].config.io_base = hw_config->io_base; + supported_drivers[i].config.irq = hw_config->irq; + supported_drivers[i].config.dma = hw_config->dma; + + if (supported_drivers[i].attach (0, hw_config) != 0) + panic ("snd#: Invalid memory allocation\n"); + return TRUE; + } + + return FALSE; +} + +int +sndtable_get_cardcount (void) +{ + return num_dspdevs + num_mixers + num_synths + num_midis; +} + +#ifdef linux +void sound_setup(char *str, int *ints) +{ + int i, n = sizeof (supported_drivers) / sizeof (struct card_info); + +/* + * First disable all drivers + */ + + for (i=0;i> 20; + + if (card_type > 127) + { + /* Add any future extensions here*/ + return; + } + + ioaddr = (val & 0x000fff00) >> 8; + irq = (val & 0x000000f0) >> 4; + dma = (val & 0x0000000f); + + ptr = -1; + for (j=0;j /* need byte IO */ + +#define deb_outb(x,y) {printk("out %02x, %02x\n", x, y);outb(x,y);} + + +#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER +#define outb outb_p +#endif + +/* + * NOTES about DMA transfers: + * + * controller 1: channels 0-3, byte operations, ports 00-1F + * controller 2: channels 4-7, word operations, ports C0-DF + * + * - ALL registers are 8 bits only, regardless of transfer size + * - channel 4 is not used - cascades 1 into 2. + * - channels 0-3 are byte - addresses/counts are for physical bytes + * - channels 5-7 are word - addresses/counts are for physical words + * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries + * - transfer count loaded to registers is 1 less than actual count + * - controller 2 offsets are all even (2x offsets for controller 1) + * - page registers for 5-7 don't use data bit 0, represent 128K pages + * - page registers for 0-3 use bit 0, represent 64K pages + * + * DMA transfers are limited to the lower 16MB of _physical_ memory. + * Note that addresses loaded into registers must be _physical_ addresses, + * not logical addresses (which may differ if paging is active). + * + * Address mapping for channels 0-3: + * + * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses) + * | ... | | ... | | ... | + * | ... | | ... | | ... | + * | ... | | ... | | ... | + * P7 ... P0 A7 ... A0 A7 ... A0 + * | Page | Addr MSB | Addr LSB | (DMA registers) + * + * Address mapping for channels 5-7: + * + * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses) + * | ... | \ \ ... \ \ \ ... \ \ + * | ... | \ \ ... \ \ \ ... \ (not used) + * | ... | \ \ ... \ \ \ ... \ + * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0 + * | Page | Addr MSB | Addr LSB | (DMA registers) + * + * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses + * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at + * the hardware level, so odd-byte transfers aren't possible). + * + * Transfer count (_not # bytes_) is limited to 64K, represented as actual + * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more, + * and up to 128K bytes may be transferred on channels 5-7 in one operation. + * + */ + +#define MAX_DMA_CHANNELS 8 + +/* 8237 DMA controllers */ +#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ +#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ + +/* DMA controller registers */ +#define DMA1_CMD_REG 0x08 /* command register (w) */ +#define DMA1_STAT_REG 0x08 /* status register (r) */ +#define DMA1_REQ_REG 0x09 /* request register (w) */ +#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ +#define DMA1_MODE_REG 0x0B /* mode register (w) */ +#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ +#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ +#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ +#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ +#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ + +#define DMA2_CMD_REG 0xD0 /* command register (w) */ +#define DMA2_STAT_REG 0xD0 /* status register (r) */ +#define DMA2_REQ_REG 0xD2 /* request register (w) */ +#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ +#define DMA2_MODE_REG 0xD6 /* mode register (w) */ +#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ +#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ +#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ +#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ +#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ + +#define DMA_ADDR_0 0x00 /* DMA address registers */ +#define DMA_ADDR_1 0x02 +#define DMA_ADDR_2 0x04 +#define DMA_ADDR_3 0x06 +#define DMA_ADDR_4 0xC0 +#define DMA_ADDR_5 0xC4 +#define DMA_ADDR_6 0xC8 +#define DMA_ADDR_7 0xCC + +#define DMA_CNT_0 0x01 /* DMA count registers */ +#define DMA_CNT_1 0x03 +#define DMA_CNT_2 0x05 +#define DMA_CNT_3 0x07 +#define DMA_CNT_4 0xC2 +#define DMA_CNT_5 0xC6 +#define DMA_CNT_6 0xCA +#define DMA_CNT_7 0xCE + +#define DMA_PAGE_0 0x87 /* DMA page registers */ +#define DMA_PAGE_1 0x83 +#define DMA_PAGE_2 0x81 +#define DMA_PAGE_3 0x82 +#define DMA_PAGE_5 0x8B +#define DMA_PAGE_6 0x89 +#define DMA_PAGE_7 0x8A + +#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ +#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ +#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ + +/* enable/disable a specific DMA channel */ +static __inline__ void enable_dma(unsigned int dmanr) +{ + if (dmanr<=3) + deb_outb(dmanr, DMA1_MASK_REG) + else + deb_outb(dmanr & 3, DMA2_MASK_REG); +} + +static __inline__ void disable_dma(unsigned int dmanr) +{ + if (dmanr<=3) + deb_outb(dmanr | 4, DMA1_MASK_REG) + else + deb_outb((dmanr & 3) | 4, DMA2_MASK_REG); +} + +/* Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + * Use this once to initialize the FF to a known state. + * After that, keep track of it. :-) + * --- In order to do that, the DMA routines below should --- + * --- only be used while interrupts are disabled! --- + */ +static __inline__ void clear_dma_ff(unsigned int dmanr) +{ + if (dmanr<=3) + deb_outb(0, DMA1_CLEAR_FF_REG) + else + deb_outb(0, DMA2_CLEAR_FF_REG); +} + +/* set mode (above) for a specific DMA channel */ +static __inline__ void set_dma_mode(unsigned int dmanr, char mode) +{ + if (dmanr<=3) + deb_outb(mode | dmanr, DMA1_MODE_REG) + else + deb_outb(mode | (dmanr&3), DMA2_MODE_REG); +} + +/* Set only the page register bits of the transfer address. + * This is used for successive transfers when we know the contents of + * the lower 16 bits of the DMA current address register, but a 64k boundary + * may have been crossed. + */ +static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) +{ + switch(dmanr) { + case 0: + deb_outb(pagenr, DMA_PAGE_0); + break; + case 1: + deb_outb(pagenr, DMA_PAGE_1); + break; + case 2: + deb_outb(pagenr, DMA_PAGE_2); + break; + case 3: + deb_outb(pagenr, DMA_PAGE_3); + break; + case 5: + deb_outb(pagenr & 0xfe, DMA_PAGE_5); + break; + case 6: + deb_outb(pagenr & 0xfe, DMA_PAGE_6); + break; + case 7: + deb_outb(pagenr & 0xfe, DMA_PAGE_7); + break; + } +} + + +/* Set transfer address & page bits for specific DMA channel. + * Assumes dma flipflop is clear. + */ +static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) +{ + set_dma_page(dmanr, a>>16); + if (dmanr <= 3) { + deb_outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); + deb_outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ) + } else { + deb_outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); + deb_outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); + } +} + + +/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for + * a specific DMA channel. + * You must ensure the parameters are valid. + * NOTE: from a manual: "the number of transfers is one more + * than the initial word count"! This is taken into account. + * Assumes dma flip-flop is clear. + * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. + */ +static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) +{ + count--; + if (dmanr <= 3) { + deb_outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); + deb_outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); + } else { + deb_outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); + deb_outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); + } +} + + +/* Get DMA residue count. After a DMA transfer, this + * should return zero. Reading this while a DMA transfer is + * still in progress will return unpredictable results. + * If called before the channel has been used, it may return 1. + * Otherwise, it returns the number of _bytes_ left to transfer. + * + * Assumes DMA flip-flop is clear. + */ +static __inline__ int get_dma_residue(unsigned int dmanr) +{ + unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE + : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; + + /* using short to get 16-bit wrap around */ + unsigned short count; + + count = 1 + inb(io_port); + count += inb(io_port) << 8; + + return (dmanr<=3)? count : (count<<1); +} + + +/* These are in kernel/dma.c: */ +extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */ +extern void free_dma(unsigned int dmanr); /* release it again */ + + +#endif /* _ASM_DMA_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dmabuf.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dmabuf.c new file mode 100644 index 000000000..b3a6ae232 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/dmabuf.c @@ -0,0 +1,901 @@ +/* + * sound/dmabuf.c + * + * The DMA buffer manager for digitized voice applications + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#include "sound_calls.h" + +#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_GUS) + +#define MAX_SUB_BUFFERS (32*MAX_REALTIME_FACTOR) + +/* + * The DSP channel can be used either for input or output. Variable + * 'dma_mode' will be set when the program calls read or write first time + * after open. Current version doesn't support mode changes without closing + * and reopening the device. Support for this feature may be implemented in a + * future version of this driver. + */ + +#define DMODE_NONE 0 +#define DMODE_OUTPUT 1 +#define DMODE_INPUT 2 + +DEFINE_WAIT_QUEUES (dev_sleeper[MAX_DSP_DEV], dev_sleep_flag[MAX_DSP_DEV]); + +static int dma_mode[MAX_DSP_DEV] = +{0}; /* DMODE_INPUT, DMODE_OUTPUT or DMODE_NONE */ + +static volatile int dmabuf_interrupted[MAX_DSP_DEV] = +{0}; + +/* + * Pointers to raw buffers + */ + +char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT] = +{ + {NULL}}; +unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; +int snd_raw_count[MAX_DSP_DEV]; + +/* + * Device state tables + */ + +static int dev_busy[MAX_DSP_DEV]; +static int dev_needs_restart[MAX_DSP_DEV]; +static int dev_modes[MAX_DSP_DEV]; +static int dev_active[MAX_DSP_DEV]; +static int dev_started[MAX_DSP_DEV]; +static int dev_qlen[MAX_DSP_DEV]; +static int dev_qhead[MAX_DSP_DEV]; +static int dev_qtail[MAX_DSP_DEV]; +static int dev_underrun[MAX_DSP_DEV]; +static int bufferalloc_done[MAX_DSP_DEV] = +{0}; + +/* + * Logical buffers for each devices + */ + +static int dev_nbufs[MAX_DSP_DEV]; /* # of logical buffers ( >= + * sound_buffcounts[dev] */ +static int dev_counts[MAX_DSP_DEV][MAX_SUB_BUFFERS]; +static int dev_subdivision[MAX_DSP_DEV]; +static unsigned long dev_buf_phys[MAX_DSP_DEV][MAX_SUB_BUFFERS]; +static char *dev_buf[MAX_DSP_DEV][MAX_SUB_BUFFERS] = + {{NULL}}; +static int dev_buffsize[MAX_DSP_DEV]; + +static void +reorganize_buffers (int dev) +{ + /* + * This routine breaks the physical device buffers to logical ones. + */ + + unsigned i, p, n; + unsigned sr, nc, sz, bsz; + + sr = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_RATE, 0, 1); + nc = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_CHANNELS, 0, 1); + sz = dsp_devs[dev]->ioctl (dev, SOUND_PCM_READ_BITS, 0, 1); + + if (sr < 1 || nc < 1 || sz < 1) + { + printk ("SOUND: Invalid PCM parameters[%d] sr=%d, nc=%d, sz=%d\n", dev, sr, nc, sz); + sr = DSP_DEFAULT_SPEED; + nc = 1; + sz = 8; + } + + sz /= 8; /* Convert # of bits -> # of bytes */ + + sz = sr * nc * sz; + + /* + * Compute a buffer size not exeeding 1 second. + */ + + bsz = sound_buffsizes[dev]; + + while (bsz > sz) + bsz >>= 1; /* Divide by 2 */ + + if (sound_buffcounts[dev] == 1 && bsz == sound_buffsizes[dev]) + bsz >>= 1; /* Need at least 2 buffers */ + + if (dev_subdivision[dev] == 0) + dev_subdivision[dev] = 1; /* Default value */ + + bsz /= dev_subdivision[dev]; /* Use smaller buffers */ + + if (bsz == 0) bsz = 4096; /* Just a sanity check */ + + while ((sound_buffsizes[dev]*sound_buffcounts[dev])/bsz > MAX_SUB_BUFFERS) + bsz <<= 1; /* Too much buffers */ + + dev_buffsize[dev] = bsz; + n = 0; + + /* + * Now computing addresses for the logical buffers + */ + + for (i = 0; i < snd_raw_count[dev]; i++) + { + p = 0; + + while ((p + bsz) <= sound_buffsizes[dev]) + { + dev_buf[dev][n] = snd_raw_buf[dev][i] + p; + dev_buf_phys[dev][n] = snd_raw_buf_phys[dev][i] + p; + p += bsz; + n++; + } + } + + dev_nbufs[dev] = n; + + for (i = 0; i < dev_nbufs[dev]; i++) + { + dev_counts[dev][i] = 0; + } + + bufferalloc_done[dev] = 1; +} + +static void +dma_init_buffers(int dev) +{ + RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); + dev_underrun[dev] = 0; + + dev_busy[dev] = 1; + + bufferalloc_done[dev] = 0; + + dev_active[dev] = dev_qlen[dev] = dev_qtail[dev] = dev_qhead[dev] = 0; + dev_needs_restart[dev] = dev_started[dev] = 0; + dma_mode[dev] = DMODE_NONE; +} + +int +DMAbuf_open (int dev, int mode) +{ + int retval; + + if (dev >= num_dspdevs) + { + printk ("PCM device %d not installed.\n", dev); + return RET_ERROR (ENXIO); + } + + if (dev_busy[dev]) + return RET_ERROR (EBUSY); + + if (!dsp_devs[dev]) + { + printk ("DSP device %d not initialized\n", dev); + return RET_ERROR (ENXIO); + } + +#ifdef USE_RUNTIME_DMAMEM + sound_dma_malloc(dev); +#endif + + if (snd_raw_buf[dev][0] == NULL) + return RET_ERROR (ENOSPC); /* Memory allocation failed during boot */ + + if ((retval = dsp_devs[dev]->open (dev, mode)) < 0) + return retval; + + dev_modes[dev] = mode; + dev_subdivision[dev] = 0; + + dma_init_buffers(dev); + dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_BITS, 8, 1); + dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_CHANNELS, 1, 1); + dsp_devs[dev]->ioctl (dev, SOUND_PCM_WRITE_RATE, DSP_DEFAULT_SPEED, 1); + + return 0; +} + +static void +dma_reset (int dev) +{ + int retval; + unsigned long flags; + + DISABLE_INTR(flags); + dsp_devs[dev]->reset (dev); + dsp_devs[dev]->close (dev); + + if ((retval = dsp_devs[dev]->open (dev, dev_modes[dev])) < 0) + printk("Sound: Reset failed - Can't reopen device\n"); + RESTORE_INTR(flags); + + dma_init_buffers(dev); + reorganize_buffers(dev); +} + +static int +dma_sync (int dev) +{ + unsigned long flags; + unsigned long time; + int timed_out; + + if (dma_mode[dev] == DMODE_OUTPUT) + { + DISABLE_INTR (flags); + + timed_out = 0; + time = GET_TIME (); + + while ((!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || + dmabuf_interrupted[dev]) && !timed_out) + && dev_qlen[dev]) + { + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 10 * HZ); + if ((GET_TIME () - time) > (10 * HZ)) + timed_out = 1; + } + RESTORE_INTR (flags); + + /* + * Some devices such as GUS have huge amount of on board RAM for the + * audio data. We have to wait util the device has finished playing. + */ + + DISABLE_INTR (flags); + if (dsp_devs[dev]->has_output_drained) /* Device has hidden buffers */ + { + while (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || + dmabuf_interrupted[dev]) + && !dsp_devs[dev]->has_output_drained (dev)) + { + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], HZ / 4); + } + } + RESTORE_INTR (flags); + } + return dev_qlen[dev]; +} + +int +DMAbuf_release (int dev, int mode) +{ + + if (!(PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev]) || + dmabuf_interrupted[dev]) + && (dma_mode[dev] == DMODE_OUTPUT)) + { + dma_sync (dev); + } + +#ifdef USE_RUNTIME_DMAMEM + sound_dma_free(dev); +#endif + + dsp_devs[dev]->reset (dev); + + dsp_devs[dev]->close (dev); + + dma_mode[dev] = DMODE_NONE; + dev_busy[dev] = 0; + + return 0; +} + +int +DMAbuf_getrdbuffer (int dev, char **buf, int *len) +{ + unsigned long flags; + int err = EIO; + + DISABLE_INTR (flags); + if (!dev_qlen[dev]) + { + if (dev_needs_restart[dev]) + { + dma_reset(dev); + dev_needs_restart[dev] = 0; + } + + if (dma_mode[dev] == DMODE_OUTPUT) /* Was output -> direction change */ + { + dma_sync(dev); + dma_reset(dev); + dma_mode[dev] = DMODE_NONE; + } + + if (!bufferalloc_done[dev]) + reorganize_buffers (dev); + + if (!dma_mode[dev]) + { + int err; + + if ((err = dsp_devs[dev]->prepare_for_input (dev, + dev_buffsize[dev], dev_nbufs[dev])) < 0) + { + RESTORE_INTR (flags); + return err; + } + dma_mode[dev] = DMODE_INPUT; + } + + if (!dev_active[dev]) + { + dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], + dev_buffsize[dev], 0, + !sound_dma_automode[dev] || + !dev_started[dev]); + dev_active[dev] = 1; + dev_started[dev] = 1; + } + + /* Wait for the next block */ + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); + if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) + { + printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); + err = EIO; + SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); + } + else + err = EINTR; + } + RESTORE_INTR (flags); + + if (!dev_qlen[dev]) + return RET_ERROR (err); + + *buf = &dev_buf[dev][dev_qhead[dev]][dev_counts[dev][dev_qhead[dev]]]; + *len = dev_buffsize[dev] - dev_counts[dev][dev_qhead[dev]]; + + return dev_qhead[dev]; +} + +int +DMAbuf_rmchars (int dev, int buff_no, int c) +{ + int p = dev_counts[dev][dev_qhead[dev]] + c; + + if (p >= dev_buffsize[dev]) + { /* This buffer is now empty */ + dev_counts[dev][dev_qhead[dev]] = 0; + dev_qlen[dev]--; + dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev]; + } + else + dev_counts[dev][dev_qhead[dev]] = p; + + return 0; +} + +int +DMAbuf_read (int dev, snd_rw_buf * user_buf, int count) +{ + char *dmabuf; + int buff_no, c, err; + + /* + * This routine returns at most 'count' bytes from the dsp input buffers. + * Returns negative value if there is an error. + */ + + if ((buff_no = DMAbuf_getrdbuffer (dev, &dmabuf, &c)) < 0) + return buff_no; + + if (c > count) + c = count; + + COPY_TO_USER (user_buf, 0, dmabuf, c); + + if ((err = DMAbuf_rmchars (dev, buff_no, c)) < 0) + return err; + return c; + +} + +int +DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + switch (cmd) + { + case SNDCTL_DSP_RESET: + dma_reset (dev); + return 0; + break; + + case SNDCTL_DSP_SYNC: + dma_sync (dev); + dma_reset (dev); + return 0; + break; + + case SNDCTL_DSP_GETBLKSIZE: + if (!bufferalloc_done[dev]) + reorganize_buffers (dev); + + return IOCTL_OUT (arg, dev_buffsize[dev]); + break; + + case SNDCTL_DSP_SUBDIVIDE: + { + int fact = IOCTL_IN(arg); + + if (fact == 0) + { + fact = dev_subdivision[dev]; + if (fact == 0) fact = 1; + return IOCTL_OUT(arg, fact); + } + + if (dev_subdivision[dev] != 0) /* Too late to change */ + return RET_ERROR(EINVAL); + + if (fact > MAX_REALTIME_FACTOR) return RET_ERROR(EINVAL); + + if (fact != 1 && fact != 2 && fact != 4 && fact != 8 && fact !=16) + return RET_ERROR(EINVAL); + + dev_subdivision[dev] = fact; + return IOCTL_OUT(arg, fact); + } + break; + + default: + return dsp_devs[dev]->ioctl (dev, cmd, arg, local); + } + + return RET_ERROR (EIO); +} + +int +DMAbuf_getwrbuffer (int dev, char **buf, int *size) +{ + unsigned long flags; + int err = EIO; + + if (dma_mode[dev] == DMODE_INPUT) /* Was input -> Direction change */ + { + dma_reset(dev); + dma_mode[dev] = DMODE_NONE; + } + else + if (dev_needs_restart[dev]) /* Restart buffering */ + { + dma_sync(dev); + dma_reset(dev); + } + + dev_needs_restart[dev] = 0; + + if (!bufferalloc_done[dev]) + reorganize_buffers (dev); + + if (!dma_mode[dev]) + { + int err; + + dma_mode[dev] = DMODE_OUTPUT; + if ((err = dsp_devs[dev]->prepare_for_output (dev, + dev_buffsize[dev], dev_nbufs[dev])) < 0) + return err; + } + + + DISABLE_INTR (flags); + + RESET_WAIT_QUEUE (dev_sleeper[dev], dev_sleep_flag[dev]); + + if (dev_qlen[dev] == dev_nbufs[dev]) + { + if (!dev_active[dev]) + { + printk ("Soundcard warning: DMA not activated %d/%d\n", + dev_qlen[dev], dev_nbufs[dev]); + return RET_ERROR (EIO); + } + + /* Wait for free space */ + DO_SLEEP (dev_sleeper[dev], dev_sleep_flag[dev], 2 * HZ); + if (TIMED_OUT (dev_sleeper[dev], dev_sleep_flag[dev])) + { + printk ("Sound: DMA timed out - IRQ/DRQ config error?\n"); + err = EIO; + SET_ABORT_FLAG (dev_sleeper[dev], dev_sleep_flag[dev]); + } + else if (PROCESS_ABORTING (dev_sleeper[dev], dev_sleep_flag[dev])) + err = EINTR; + } + RESTORE_INTR (flags); + + if (dev_qlen[dev] == dev_nbufs[dev]) + return RET_ERROR (err); /* We have got signal (?) */ + + *buf = dev_buf[dev][dev_qtail[dev]]; + *size = dev_buffsize[dev]; + dev_counts[dev][dev_qtail[dev]] = 0; + + return dev_qtail[dev]; +} + +int +DMAbuf_start_output (int dev, int buff_no, int l) +{ + if (buff_no != dev_qtail[dev]) + printk ("Soundcard warning: DMA buffers out of sync %d != %d\n", buff_no, dev_qtail[dev]); + + dev_qlen[dev]++; + + dev_counts[dev][dev_qtail[dev]] = l; + + dev_needs_restart[dev] = (l != dev_buffsize[dev]); + + dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev]; + + if (!dev_active[dev]) + { + dev_active[dev] = 1; + dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], + dev_counts[dev][dev_qhead[dev]], 0, + !sound_dma_automode[dev] || !dev_started[dev]); + dev_started[dev] = 1; + } + + return 0; +} + +int +DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) +{ + int chan = sound_dsp_dmachan[dev]; + unsigned long flags; + + /* + * This function is not as portable as it should be. + */ + + /* + * The count must be one less than the actual size. This is handled by + * set_dma_addr() + */ + + if (sound_dma_automode[dev]) + { /* Auto restart mode. Transfer the whole + * buffer */ +#ifdef linux + DISABLE_INTR (flags); + disable_dma (chan); + clear_dma_ff (chan); + set_dma_mode (chan, dma_mode | DMA_AUTOINIT); + set_dma_addr (chan, snd_raw_buf_phys[dev][0]); + set_dma_count (chan, sound_buffsizes[dev]); + enable_dma (chan); + RESTORE_INTR (flags); +#else + +#ifdef __386BSD__ + printk ("sound: Invalid DMA mode for device %d\n", dev); + + isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, + snd_raw_buf_phys[dev][0], + sound_buffsizes[dev], + chan); +#else +#if defined(ISC) || defined(SCO) +#ifndef DMAMODE_AUTO + printk ("sound: Invalid DMA mode for device %d\n", dev); +#endif + dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode) +#ifdef DMAMODE_AUTO + | DMAMODE_AUTO +#endif + , + snd_raw_buf_phys[dev][0], count); + dma_enable (chan); +#else +# error This routine is not valid for this OS. +#endif +#endif + +#endif + } + else + { +#ifdef linux + DISABLE_INTR (flags); + disable_dma (chan); + clear_dma_ff (chan); + set_dma_mode (chan, dma_mode); + set_dma_addr (chan, physaddr); + set_dma_count (chan, count); + enable_dma (chan); + RESTORE_INTR (flags); +#else +#ifdef __386BSD__ + isa_dmastart ((dma_mode == DMA_MODE_READ) ? B_READ : B_WRITE, + physaddr, + count, + chan); +#else + +#if defined(ISC) || defined(SCO) + dma_param (chan, ((dma_mode == DMA_MODE_READ) ? DMA_Rdmode : DMA_Wrmode), + physaddr, count); + dma_enable (chan); +#else +# error This routine is not valid for this OS. +#endif /* !ISC */ +#endif + +#endif + } + + return count; +} + +long +DMAbuf_init (long mem_start) +{ + int i; + + /* + * In this version the DMA buffer allocation is done by sound_mem_init() + * which is called by init/main.c + */ + + for (i = 0; i < MAX_DSP_DEV; i++) + { + dev_qlen[i] = 0; + dev_qhead[i] = 0; + dev_qtail[i] = 0; + dev_active[i] = 0; + dev_busy[i] = 0; + bufferalloc_done[i] = 0; + } + + return mem_start; +} + +void +DMAbuf_outputintr (int dev, int underrun_flag) +{ + unsigned long flags; + + dev_qlen[dev]--; + dev_qhead[dev] = (dev_qhead[dev] + 1) % dev_nbufs[dev]; + dev_active[dev] = 0; + + if (dev_qlen[dev]) + { + dsp_devs[dev]->output_block (dev, dev_buf_phys[dev][dev_qhead[dev]], + dev_counts[dev][dev_qhead[dev]], 1, + !sound_dma_automode[dev]); + dev_active[dev] = 1; + } + else + if (underrun_flag) + { + dev_underrun[dev]++; + dsp_devs[dev]->halt_xfer (dev); + dev_needs_restart[dev] = 1; + } + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) + { + WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); + } + RESTORE_INTR (flags); +} + +void +DMAbuf_inputintr (int dev) +{ + unsigned long flags; + + if (!dev_busy[dev]) + { + dsp_devs[dev]->close (dev); + } + else if (dev_qlen[dev] == (dev_nbufs[dev] - 1)) + { + printk("Sound: Recording overrun\n"); + dev_underrun[dev]++; + dsp_devs[dev]->halt_xfer (dev); + dev_active[dev] = 0; + dev_needs_restart[dev] = 1; + } + else + { + dev_qlen[dev]++; + dev_qtail[dev] = (dev_qtail[dev] + 1) % dev_nbufs[dev]; + + dsp_devs[dev]->start_input (dev, dev_buf_phys[dev][dev_qtail[dev]], + dev_buffsize[dev], 1, + !sound_dma_automode[dev]); + dev_active[dev] = 1; + } + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (dev_sleeper[dev], dev_sleep_flag[dev])) + { + WAKE_UP (dev_sleeper[dev], dev_sleep_flag[dev]); + } + RESTORE_INTR (flags); +} + +int +DMAbuf_open_dma (int dev) +{ + unsigned long flags; + int chan = sound_dsp_dmachan[dev]; + + if (ALLOC_DMA_CHN (chan)) + { + printk ("Unable to grab DMA%d for the audio driver\n", chan); + return 0; + } + + DISABLE_INTR (flags); +#ifdef linux + disable_dma (chan); + clear_dma_ff (chan); +#endif + RESTORE_INTR (flags); + + return 1; +} + +void +DMAbuf_close_dma (int dev) +{ + int chan = sound_dsp_dmachan[dev]; + + DMAbuf_reset_dma (chan); + RELEASE_DMA_CHN (chan); +} + +void +DMAbuf_reset_dma (int chan) +{ +} + +/* + * The sound_mem_init() is called by mem_init() immediately after mem_map is + * initialized and before free_page_list is created. + * + * This routine allocates DMA buffers at the end of available physical memory ( + * <16M) and marks pages reserved at mem_map. + */ + +#else +/* Stub versions if audio services not included */ + +int +DMAbuf_open (int dev, int mode) +{ + return RET_ERROR (ENXIO); +} + +int +DMAbuf_release (int dev, int mode) +{ + return 0; +} + +int +DMAbuf_read (int dev, snd_rw_buf * user_buf, int count) +{ + return RET_ERROR (EIO); +} + +int +DMAbuf_getwrbuffer (int dev, char **buf, int *size) +{ + return RET_ERROR (EIO); +} + +int +DMAbuf_getrdbuffer (int dev, char **buf, int *len) +{ + return RET_ERROR (EIO); +} + +int +DMAbuf_rmchars (int dev, int buff_no, int c) +{ + return RET_ERROR (EIO); +} + +int +DMAbuf_start_output (int dev, int buff_no, int l) +{ + return RET_ERROR (EIO); +} + +int +DMAbuf_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + return RET_ERROR (EIO); +} + +long +DMAbuf_init (long mem_start) +{ + return mem_start; +} + +int +DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode) +{ + return RET_ERROR (EIO); +} + +int +DMAbuf_open_dma (int chan) +{ + return RET_ERROR (ENXIO); +} + +void +DMAbuf_close_dma (int chan) +{ + return; +} + +void +DMAbuf_reset_dma (int chan) +{ + return; +} + +void +DMAbuf_inputintr (int dev) +{ + return; +} + +void +DMAbuf_outputintr (int dev, int underrun_flag) +{ + return; +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/finetune.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/finetune.h new file mode 100644 index 000000000..b86a0eb15 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/finetune.h @@ -0,0 +1,49 @@ +#ifdef SEQUENCER_C +/* + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + + unsigned short finetune_table[128] = + { +/* 0 */ 9439, 9447, 9456, 9464, 9473, 9481, 9490, 9499, +/* 8 */ 9507, 9516, 9524, 9533, 9542, 9550, 9559, 9567, +/* 16 */ 9576, 9585, 9593, 9602, 9611, 9619, 9628, 9637, +/* 24 */ 9645, 9654, 9663, 9672, 9680, 9689, 9698, 9707, +/* 32 */ 9715, 9724, 9733, 9742, 9750, 9759, 9768, 9777, +/* 40 */ 9786, 9795, 9803, 9812, 9821, 9830, 9839, 9848, +/* 48 */ 9857, 9866, 9874, 9883, 9892, 9901, 9910, 9919, +/* 56 */ 9928, 9937, 9946, 9955, 9964, 9973, 9982, 9991, +/* 64 */ 10000, 10009, 10018, 10027, 10036, 10045, 10054, 10063, +/* 72 */ 10072, 10082, 10091, 10100, 10109, 10118, 10127, 10136, +/* 80 */ 10145, 10155, 10164, 10173, 10182, 10191, 10201, 10210, +/* 88 */ 10219, 10228, 10237, 10247, 10256, 10265, 10274, 10284, +/* 96 */ 10293, 10302, 10312, 10321, 10330, 10340, 10349, 10358, +/* 104 */ 10368, 10377, 10386, 10396, 10405, 10415, 10424, 10433, +/* 112 */ 10443, 10452, 10462, 10471, 10481, 10490, 10499, 10509, +/* 120 */ 10518, 10528, 10537, 10547, 10556, 10566, 10576, 10585 + }; +#else + extern unsigned short finetune_table[128]; +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_card.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_card.c new file mode 100644 index 000000000..d031a456f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_card.c @@ -0,0 +1,142 @@ +/* + * sound/gus_card.c + * + * Detection routine for the Gravis Ultrasound. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) + +#include "gus_hw.h" + +void gusintr (int); + +int gus_base, gus_irq, gus_dma; + +long +attach_gus_card (long mem_start, struct address_info *hw_config) +{ + int io_addr; + + snd_set_irq_handler (hw_config->irq, gusintr); + + if (gus_wave_detect (hw_config->io_base)) /* Try first the default */ + { + mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma); +#ifndef EXCLUDE_MIDI + mem_start = gus_midi_init (mem_start); +#endif + return mem_start; + } + +#ifndef EXCLUDE_GUS_IODETECT + + /* + * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) + */ + + for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) + if (io_addr != hw_config->io_base) /* Already tested */ + if (gus_wave_detect (io_addr)) + { + printk (" WARNING! GUS found at %x, config was %x ", io_addr, hw_config->io_base); + mem_start = gus_wave_init (mem_start, hw_config->irq, hw_config->dma); +#ifndef EXCLUDE_MIDI + mem_start = gus_midi_init (mem_start); +#endif + return mem_start; + } + +#endif + + return mem_start; /* Not detected */ +} + +int +probe_gus (struct address_info *hw_config) +{ + int io_addr; + + if (gus_wave_detect (hw_config->io_base)) + return 1; + +#ifndef EXCLUDE_GUS_IODETECT + + /* + * Look at the possible base addresses (0x2X0, X=1, 2, 3, 4, 5, 6) + */ + + for (io_addr = 0x210; io_addr <= 0x260; io_addr += 0x10) + if (io_addr != hw_config->io_base) /* Already tested */ + if (gus_wave_detect (io_addr)) + return 1; + +#endif + + return 0; +} + +void +gusintr (int unit) +{ + unsigned char src; + +#ifdef linux + sti(); +#endif + + while (1) + { + if (!(src = INB (u_IrqStatus))) + return; + + if (src & DMA_TC_IRQ) + { + guswave_dma_irq (); + } + + if (src & (MIDI_TX_IRQ | MIDI_RX_IRQ)) + { +#ifndef EXCLUDE_MIDI + gus_midi_interrupt (0); +#endif + } + + if (src & (GF1_TIMER1_IRQ | GF1_TIMER2_IRQ)) + { + printk ("T"); + gus_write8 (0x45, 0); /* Timer control */ + } + + if (src & (WAVETABLE_IRQ | ENVELOPE_IRQ)) + { + gus_voice_irq (); + } + } +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_hw.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_hw.h new file mode 100644 index 000000000..48233e7e1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_hw.h @@ -0,0 +1,35 @@ + +/* + * I/O addresses + */ + +#define u_Base (gus_base + 0x000) +#define u_Mixer u_Base +#define u_Status (gus_base + 0x006) +#define u_TimerControl (gus_base + 0x008) +#define u_TimerData (gus_base + 0x009) +#define u_IRQDMAControl (gus_base + 0x00b) +#define u_MidiControl (gus_base + 0x100) +#define MIDI_RESET 0x03 +#define MIDI_ENABLE_XMIT 0x20 +#define MIDI_ENABLE_RCV 0x80 +#define u_MidiStatus u_MidiControl +#define MIDI_RCV_FULL 0x01 +#define MIDI_XMIT_EMPTY 0x02 +#define MIDI_FRAME_ERR 0x10 +#define MIDI_OVERRUN 0x20 +#define MIDI_IRQ_PEND 0x80 +#define u_MidiData (gus_base + 0x101) +#define u_Voice (gus_base + 0x102) +#define u_Command (gus_base + 0x103) +#define u_DataLo (gus_base + 0x104) +#define u_DataHi (gus_base + 0x105) +#define u_IrqStatus u_Status +# define MIDI_TX_IRQ 0x01 /* pending MIDI xmit IRQ */ +# define MIDI_RX_IRQ 0x02 /* pending MIDI recv IRQ */ +# define GF1_TIMER1_IRQ 0x04 /* general purpose timer */ +# define GF1_TIMER2_IRQ 0x08 /* general purpose timer */ +# define WAVETABLE_IRQ 0x20 /* pending wavetable IRQ */ +# define ENVELOPE_IRQ 0x40 /* pending volume envelope IRQ */ +# define DMA_TC_IRQ 0x80 /* pending dma tc IRQ */ +#define u_DRAMIO (gus_base + 0x107) diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_midi.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_midi.c new file mode 100644 index 000000000..5e06f7f23 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_midi.c @@ -0,0 +1,283 @@ +/* + * sound/gus2_midi.c + * + * The low level driver for the GUS Midi Interface. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#include "gus_hw.h" + +#if !defined(EXCLUDE_GUS) && !defined(EXCLUDE_MIDI) + +static int midi_busy = 0, input_opened = 0; +static int my_dev; +static int output_used = 0; +static volatile unsigned char gus_midi_control; + +static void (*midi_input_intr) (int dev, unsigned char data); + +static unsigned char tmp_queue[256]; +static volatile int qlen; +static volatile unsigned char qhead, qtail; +extern int gus_base, gus_irq, gus_dma; + +#define GUS_MIDI_STATUS() INB(u_MidiStatus) + +static int +gus_midi_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + + if (midi_busy) + { + printk ("GUS: Midi busy\n"); + return RET_ERROR (EBUSY); + } + + OUTB (MIDI_RESET, u_MidiControl); + gus_delay (); + + gus_midi_control = 0; + input_opened = 0; + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + { + gus_midi_control |= MIDI_ENABLE_RCV; + input_opened = 1; + } + + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + { + gus_midi_control |= MIDI_ENABLE_XMIT; + } + + OUTB (gus_midi_control, u_MidiControl); /* Enable */ + + midi_busy = 1; + qlen = qhead = qtail = output_used = 0; + midi_input_intr = input; + + return 0; +} + +static int +dump_to_midi (unsigned char midi_byte) +{ + unsigned long flags; + int ok = 0; + + output_used = 1; + + DISABLE_INTR (flags); + + if (GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY) + { + ok = 1; + OUTB (midi_byte, u_MidiData); + } + else + { + /* Enable Midi xmit interrupts (again) */ + gus_midi_control |= MIDI_ENABLE_XMIT; + OUTB (gus_midi_control, u_MidiControl); + } + + RESTORE_INTR (flags); + return ok; +} + +static void +gus_midi_close (int dev) +{ + /* Reset FIFO pointers, disable intrs */ + + OUTB (MIDI_RESET, u_MidiControl); + midi_busy = 0; +} + +static int +gus_midi_out (int dev, unsigned char midi_byte) +{ + + unsigned long flags; + + /* + * Drain the local queue first + */ + + DISABLE_INTR (flags); + + while (qlen && dump_to_midi (tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + RESTORE_INTR (flags); + + /* + * Output the byte if the local queue is empty. + */ + + if (!qlen) + if (dump_to_midi (midi_byte)) + return 1; /* OK */ + + /* + * Put to the local queue + */ + + if (qlen >= 256) + return 0; /* Local queue full */ + + DISABLE_INTR (flags); + + tmp_queue[qtail] = midi_byte; + qlen++; + qtail++; + + RESTORE_INTR (flags); + + return 1; +} + +static int +gus_midi_start_read (int dev) +{ + return 0; +} + +static int +gus_midi_end_read (int dev) +{ + return 0; +} + +static int +gus_midi_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EINVAL); +} + +static void +gus_midi_kick (int dev) +{ +} + +static int +gus_midi_buffer_status (int dev) +{ + unsigned long flags; + + if (!output_used) + return 0; + + DISABLE_INTR (flags); + + if (qlen && dump_to_midi (tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + RESTORE_INTR (flags); + + return (qlen > 0) | !(GUS_MIDI_STATUS () & MIDI_XMIT_EMPTY); +} + +static struct midi_operations gus_midi_operations = +{ + {"Gravis UltraSound", 0, 0, SNDCARD_GUS}, + gus_midi_open, + gus_midi_close, + gus_midi_ioctl, + gus_midi_out, + gus_midi_start_read, + gus_midi_end_read, + gus_midi_kick, + NULL, /* command */ + gus_midi_buffer_status +}; + +long +gus_midi_init (long mem_start) +{ + OUTB (MIDI_RESET, u_MidiControl); + + my_dev = num_midis; + midi_devs[num_midis++] = &gus_midi_operations; + return mem_start; +} + +void +gus_midi_interrupt (int dummy) +{ + unsigned char stat, data; + unsigned long flags; + + DISABLE_INTR (flags); + + stat = GUS_MIDI_STATUS (); + + if (stat & MIDI_RCV_FULL) + { + data = INB (u_MidiData); + if (input_opened) + midi_input_intr (my_dev, data); + } + + if (stat & MIDI_XMIT_EMPTY) + { + while (qlen && dump_to_midi (tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + if (!qlen) + { + /* Disable Midi output interrupts, since no data in the buffer */ + gus_midi_control &= ~MIDI_ENABLE_XMIT; + OUTB (gus_midi_control, u_MidiControl); + } + } + + if (stat & MIDI_FRAME_ERR) + printk ("Midi framing error\n"); + if (stat & MIDI_OVERRUN && input_opened) + printk ("GUS: Midi input overrun\n"); + + RESTORE_INTR (flags); +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_vol.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_vol.c new file mode 100644 index 000000000..ea3ece358 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_vol.c @@ -0,0 +1,112 @@ +/* + * gus_vol.c - Compute volume for GUS. + * + * Greg Lee 1993. + */ +#include "sound_config.h" +#ifndef EXCLUDE_GUS + +#define GUS_VOLUME gus_wave_volume + + +extern int gus_wave_volume; + +/* + * Calculate gus volume from note velocity, main volume, expression, and + * intrinsic patch volume given in patch library. Expression is multiplied + * in, so it emphasizes differences in note velocity, while main volume is + * added in -- I don't know whether this is right, but it seems reasonable to + * me. (In the previous stage, main volume controller messages were changed + * to expression controller messages, if they were found to be used for + * dynamic volume adjustments, so here, main volume can be assumed to be + * constant throughout a song.) + * + * Intrinsic patch volume is added in, but if over 64 is also multiplied in, so + * we can give a big boost to very weak voices like nylon guitar and the + * basses. The normal value is 64. Strings are assigned lower values. + */ +unsigned short +gus_adagio_vol (int vel, int mainv, int xpn, int voicev) +{ + int i, m, n, x; + + + /* + * A voice volume of 64 is considered neutral, so adjust the main volume if + * something other than this neutral value was assigned in the patch + * library. + */ + x = 256 + 6 * (voicev - 64); + + /* + * Boost expression by voice volume above neutral. + */ + if (voicev > 65) + xpn += voicev - 64; + xpn += (voicev - 64) / 2; + + /* + * Combine multiplicative and level components. + */ + x = vel * xpn * 6 + (voicev / 4) * x; + +#ifdef GUS_VOLUME + /* + * Further adjustment by installation-specific master volume control + * (default 60). + */ + x = (x * GUS_VOLUME * GUS_VOLUME) / 10000; +#endif + +#ifdef GUS_USE_CHN_MAIN_VOLUME + /* + * Experimental support for the channel main volume + */ + + mainv = (mainv / 2) + 64; /* Scale to 64 to 127 */ + x = (x * mainv * mainv) / 16384; +#endif + + if (x < 2) + return (0); + else if (x >= 65535) + return ((15 << 8) | 255); + + /* + * Convert to gus's logarithmic form with 4 bit exponent i and 8 bit + * mantissa m. + */ + n = x; + i = 7; + if (n < 128) + { + while (i > 0 && n < (1 << i)) + i--; + } + else + while (n > 255) + { + n >>= 1; + i++; + } + /* + * Mantissa is part of linear volume not expressed in exponent. (This is + * not quite like real logs -- I wonder if it's right.) + */ + m = x - (1 << i); + + /* + * Adjust mantissa to 8 bits. + */ + if (m > 0) + { + if (i > 8) + m >>= i - 8; + else if (i < 8) + m <<= 8 - i; + } + + return ((i << 8) + m); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_wave.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_wave.c new file mode 100644 index 000000000..aea174d27 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/gus_wave.c @@ -0,0 +1,3420 @@ + +/* + * sound/gus_wave.c + * + * Driver for the Gravis UltraSound wave table synth. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" +#include +#include "gus_hw.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_GUS) + +#define MAX_SAMPLE 128 +#define MAX_PATCH 256 + +struct voice_info + { + unsigned long orig_freq; + unsigned long current_freq; + unsigned long mode; + int bender; + int bender_range; + int panning; + int midi_volume; + unsigned int initial_volume; + unsigned int current_volume; + int loop_irq_mode, loop_irq_parm; +#define LMODE_FINISH 1 +#define LMODE_PCM 2 +#define LMODE_PCM_STOP 3 + int volume_irq_mode, volume_irq_parm; +#define VMODE_HALT 1 +#define VMODE_ENVELOPE 2 +#define VMODE_START_NOTE 3 + + int env_phase; + unsigned char env_rate[6]; + unsigned char env_offset[6]; + + /* + * Volume computation parameters for gus_adagio_vol() + */ + int main_vol, expression_vol, patch_vol; + + /* Variables for "Ultraclick" removal */ + int dev_pending, note_pending, volume_pending, sample_pending; + char kill_pending; + long offset_pending; + + }; + +extern int gus_base; +extern int gus_irq, gus_dma; +extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT]; +extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; +extern int snd_raw_count[MAX_DSP_DEV]; +static long gus_mem_size = 0; +static long free_mem_ptr = 0; +static int gus_busy = 0; +static int nr_voices = 0; +static int gus_devnum = 0; +static int volume_base, volume_scale, volume_method; +static int gus_line_vol = 100, gus_mic_vol = 0; +static int gus_recmask = SOUND_MASK_MIC; +static int recording_active = 0; + +#define VOL_METHOD_ADAGIO 1 +int gus_wave_volume = 60; +int gus_pcm_volume = 80; +static unsigned char mix_image = 0x00; + +/* + * Current version of this driver doesn't allow synth and PCM functions + * at the same time. The active_device specifies the active driver + */ +static int active_device = 0; + +#define GUS_DEV_WAVE 1 /* + * * * Wave table synth */ +#define GUS_DEV_PCM_DONE 2 /* + * * * PCM device, transfer done */ +#define GUS_DEV_PCM_CONTINUE 3 /* + * * * PCM device, transfer the + * second * * * chn */ + +static int gus_sampling_speed; +static int gus_sampling_channels; +static int gus_sampling_bits; + +DEFINE_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); + +/* + * Variables and buffers for PCM output + */ +#define MAX_PCM_BUFFERS (32*MAX_REALTIME_FACTOR) /* + * * * Don't + * * * change + * + */ + +static int pcm_bsize, /* + * Current blocksize + */ + pcm_nblk, /* + * Current # of blocks + */ + pcm_banksize; /* + + * + * * * * # bytes allocated for channels */ +static int pcm_datasize[MAX_PCM_BUFFERS]; /* + + * + * * * * Actual # of bytes + * in blk * */ +static volatile int pcm_head, pcm_tail, pcm_qlen; /* + + * + * * * * DRAM queue + * */ +static volatile int pcm_active; +static int pcm_opened = 0; +static int pcm_current_dev; +static int pcm_current_block; +static unsigned long pcm_current_buf; +static int pcm_current_count; +static int pcm_current_intrflag; + +struct voice_info voices[32]; + +static int freq_div_table[] = +{ + 44100, /* + * 14 + */ + 41160, /* + * 15 + */ + 38587, /* + * 16 + */ + 36317, /* + * 17 + */ + 34300, /* + * 18 + */ + 32494, /* + * 19 + */ + 30870, /* + * 20 + */ + 29400, /* + * 21 + */ + 28063, /* + * 22 + */ + 26843, /* + * 23 + */ + 25725, /* + * 24 + */ + 24696, /* + * 25 + */ + 23746, /* + * 26 + */ + 22866, /* + * 27 + */ + 22050, /* + * 28 + */ + 21289, /* + * 29 + */ + 20580, /* + * 30 + */ + 19916, /* + * 31 + */ + 19293 /* + * 32 + */ +}; + +static struct patch_info *samples; +static long sample_ptrs[MAX_SAMPLE + 1]; +static int sample_map[32]; +static int free_sample; + + +static int patch_table[MAX_PATCH]; +static int patch_map[32]; + +static struct synth_info gus_info = +{"Gravis UltraSound", 0, SYNTH_TYPE_SAMPLE, SAMPLE_TYPE_GUS, 0, 16, 0, MAX_PATCH}; + +static void gus_poke (long addr, unsigned char data); +static void compute_and_set_volume (int voice, int volume, int ramp_time); +extern unsigned short gus_adagio_vol (int vel, int mainv, int xpn, int voicev); +static void compute_volume (int voice, int volume); +static void do_volume_irq (int voice); +static void set_input_volumes(void); + +#define INSTANT_RAMP -1 /* + * * * Dont use ramping */ +#define FAST_RAMP 0 /* + * * * Fastest possible ramp */ + +static void +reset_sample_memory (void) +{ + int i; + + for (i = 0; i <= MAX_SAMPLE; i++) + sample_ptrs[i] = -1; + for (i = 0; i < 32; i++) + sample_map[i] = -1; + for (i = 0; i < 32; i++) + patch_map[i] = -1; + + gus_poke (0, 0); /* + * Put silence here + */ + gus_poke (1, 0); + + free_mem_ptr = 2; + free_sample = 0; + + for (i = 0; i < MAX_PATCH; i++) + patch_table[i] = -1; +} + +void +gus_delay (void) +{ + int i; + + for (i = 0; i < 7; i++) + INB (u_DRAMIO); +} + +static void +gus_poke (long addr, unsigned char data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + OUTB (0x43, u_Command); + OUTB (addr & 0xff, u_DataLo); + OUTB ((addr >> 8) & 0xff, u_DataHi); + + OUTB (0x44, u_Command); + OUTB ((addr >> 16) & 0xff, u_DataHi); + OUTB (data, u_DRAMIO); + RESTORE_INTR (flags); +} + +static unsigned char +gus_peek (long addr) +{ + unsigned long flags; + unsigned char tmp; + + DISABLE_INTR (flags); + OUTB (0x43, u_Command); + OUTB (addr & 0xff, u_DataLo); + OUTB ((addr >> 8) & 0xff, u_DataHi); + + OUTB (0x44, u_Command); + OUTB ((addr >> 16) & 0xff, u_DataHi); + tmp = INB (u_DRAMIO); + RESTORE_INTR (flags); + + return tmp; +} + +void +gus_write8 (int reg, unsigned int data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + OUTB (reg, u_Command); + OUTB ((unsigned char) (data & 0xff), u_DataHi); + + RESTORE_INTR (flags); +} + +unsigned char +gus_read8 (int reg) +{ + unsigned long flags; + unsigned char val; + + DISABLE_INTR (flags); + OUTB (reg | 0x80, u_Command); + val = INB (u_DataHi); + RESTORE_INTR (flags); + + return val; +} + +unsigned char +gus_look8 (int reg) +{ + unsigned long flags; + unsigned char val; + + DISABLE_INTR (flags); + OUTB (reg, u_Command); + val = INB (u_DataHi); + RESTORE_INTR (flags); + + return val; +} + +void +gus_write16 (int reg, unsigned int data) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + OUTB (reg, u_Command); + + OUTB ((unsigned char) (data & 0xff), u_DataLo); + OUTB ((unsigned char) ((data >> 8) & 0xff), u_DataHi); + + RESTORE_INTR (flags); +} + +unsigned short +gus_read16 (int reg) +{ + unsigned long flags; + unsigned char hi, lo; + + DISABLE_INTR (flags); + + OUTB (reg | 0x80, u_Command); + + lo = INB (u_DataLo); + hi = INB (u_DataHi); + + RESTORE_INTR (flags); + + return ((hi << 8) & 0xff00) | lo; +} + +void +gus_write_addr (int reg, unsigned long address, int is16bit) +{ + unsigned long hold_address; + + if (is16bit) + { + /* + * Special processing required for 16 bit patches + */ + + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + + gus_write16 (reg, (unsigned short) ((address >> 7) & 0xffff)); + gus_write16 (reg + 1, (unsigned short) ((address << 9) & 0xffff)); +} + +static void +gus_select_voice (int voice) +{ + if (voice < 0 || voice > 31) + return; + + OUTB (voice, u_Voice); +} + +static void +gus_select_max_voices (int nvoices) +{ + if (nvoices < 14) + nvoices = 14; + if (nvoices > 32) + nvoices = 32; + + nr_voices = nvoices; + + gus_write8 (0x0e, (nvoices - 1) | 0xc0); +} + +static void +gus_voice_on (unsigned int mode) +{ + gus_write8 (0x00, (unsigned char) (mode & 0xfc)); + gus_delay (); + gus_write8 (0x00, (unsigned char) (mode & 0xfc)); +} + +static void +gus_voice_off (void) +{ + gus_write8 (0x00, gus_read8 (0x00) | 0x03); +} + +static void +gus_voice_mode (unsigned int m) +{ + unsigned char mode = (unsigned char) (m & 0xff); + + gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); /* + * Don't + * start + * or + * stop + * * + * voice + */ + gus_delay (); + gus_write8 (0x00, (gus_read8 (0x00) & 0x03) | (mode & 0xfc)); +} + +static void +gus_voice_freq (unsigned long freq) +{ + unsigned long divisor = freq_div_table[nr_voices - 14]; + unsigned short fc; + + fc = (unsigned short) (((freq << 9) + (divisor >> 1)) / divisor); + fc = fc << 1; + + gus_write16 (0x01, fc); +} + +static void +gus_voice_volume (unsigned int vol) +{ + gus_write8 (0x0d, 0x03); /* + * Stop ramp before setting volume + */ + gus_write16 (0x09, (unsigned short) (vol << 4)); +} + +static void +gus_voice_balance (unsigned int balance) +{ + gus_write8 (0x0c, (unsigned char) (balance & 0xff)); +} + +static void +gus_ramp_range (unsigned int low, unsigned int high) +{ + gus_write8 (0x07, (unsigned char) ((low >> 4) & 0xff)); + gus_write8 (0x08, (unsigned char) ((high >> 4) & 0xff)); +} + +static void +gus_ramp_rate (unsigned int scale, unsigned int rate) +{ + gus_write8 (0x06, (unsigned char) (((scale & 0x03) << 6) | (rate & 0x3f))); +} + +static void +gus_rampon (unsigned int m) +{ + unsigned char mode = (unsigned char) (m & 0xff); + + gus_write8 (0x0d, mode & 0xfc); + gus_delay (); + gus_write8 (0x0d, mode & 0xfc); +} + +static void +gus_ramp_mode (unsigned int m) +{ + unsigned char mode = (unsigned char) (m & 0xff); + + gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); /* + * Don't + * start + * or + * stop + * * + * ramping + */ + gus_delay (); + gus_write8 (0x0d, (gus_read8 (0x0d) & 0x03) | (mode & 0xfc)); +} + +static void +gus_rampoff (void) +{ + gus_write8 (0x0d, 0x03); +} + +static void +gus_set_voice_pos (int voice, long position) +{ + int sample_no; + + if ((sample_no = sample_map[voice]) != -1) + if (position < samples[sample_no].len) + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].offset_pending = position; + else + gus_write_addr (0x0a, sample_ptrs[sample_no] + position, + samples[sample_no].mode & WAVE_16_BITS); +} + +static void +gus_voice_init (int voice) +{ + unsigned long flags; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_volume (0); + gus_write_addr (0x0a, 0, 0); /* + * Set current position to 0 + */ + gus_write8 (0x00, 0x03); /* + * Voice off + */ + gus_write8 (0x0d, 0x03); /* + * Ramping off + */ + RESTORE_INTR (flags); + +} + +static void +gus_voice_init2 (int voice) +{ + voices[voice].panning = 0; + voices[voice].mode = 0; + voices[voice].orig_freq = 20000; + voices[voice].current_freq = 20000; + voices[voice].bender = 0; + voices[voice].bender_range = 200; + voices[voice].initial_volume = 0; + voices[voice].current_volume = 0; + voices[voice].loop_irq_mode = 0; + voices[voice].loop_irq_parm = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].volume_irq_parm = 0; + voices[voice].env_phase = 0; + voices[voice].main_vol = 127; + voices[voice].patch_vol = 127; + voices[voice].expression_vol = 127; + voices[voice].sample_pending = -1; +} + +static void +step_envelope (int voice) +{ + unsigned vol, prev_vol, phase; + unsigned char rate; + + if (voices[voice].mode & WAVE_SUSTAIN_ON && voices[voice].env_phase == 2) + { + gus_rampoff (); + return; /* + * Sustain + */ + } + + if (voices[voice].env_phase >= 5) + { + /* + * Shoot the voice off + */ + + gus_voice_init (voice); + return; + } + + prev_vol = voices[voice].current_volume; + gus_voice_volume (prev_vol); + phase = ++voices[voice].env_phase; + + compute_volume (voice, voices[voice].midi_volume); + + vol = voices[voice].initial_volume * voices[voice].env_offset[phase] / 255; + rate = voices[voice].env_rate[phase]; + gus_write8 (0x06, rate); /* + * Ramping rate + */ + + voices[voice].volume_irq_mode = VMODE_ENVELOPE; + + if (((vol - prev_vol) / 64) == 0) /* + * No significant volume change + */ + { + step_envelope (voice); /* + * Continue with the next phase + */ + return; + } + + if (vol > prev_vol) + { + if (vol >= (4096 - 64)) + vol = 4096 - 65; + gus_ramp_range (0, vol); + gus_rampon (0x20); /* + * Increasing, irq + */ + } + else + { + if (vol <= 64) + vol = 65; + gus_ramp_range (vol, 4030); + gus_rampon (0x60); /* + * Decreasing, irq + */ + } + voices[voice].current_volume = vol; +} + +static void +init_envelope (int voice) +{ + voices[voice].env_phase = -1; + voices[voice].current_volume = 64; + + step_envelope (voice); +} + +static void +start_release (int voice) +{ + if (gus_read8 (0x00) & 0x03) + return; /* + * Voice already stopped + */ + + voices[voice].env_phase = 2; /* + * Will be incremented by step_envelope + */ + + voices[voice].current_volume = + voices[voice].initial_volume = + gus_read16 (0x09) >> 4; /* + * Get current volume + */ + + voices[voice].mode &= ~WAVE_SUSTAIN_ON; + gus_rampoff (); + step_envelope (voice); +} + +static void +gus_voice_fade (int voice) +{ + int instr_no = sample_map[voice], is16bits; + + if (instr_no < 0 || instr_no > MAX_SAMPLE) + { + gus_write8 (0x00, 0x03); /* + * Hard stop + */ + return; + } + + is16bits = (samples[instr_no].mode & WAVE_16_BITS) ? 1 : 0; /* + * 8 or 16 + * bit + * samples + */ + + if (voices[voice].mode & WAVE_ENVELOPES) + { + start_release (voice); + return; + } + + /* + * Ramp the volume down but not too quickly. + */ + if ((gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ + { + gus_voice_off (); + gus_rampoff (); + gus_voice_init (voice); + return; + } + + gus_ramp_range (65, 4030); + gus_ramp_rate (2, 4); + gus_rampon (0x40 | 0x20); /* + * Down, once, irq + */ + voices[voice].volume_irq_mode = VMODE_HALT; +} + +static void +gus_reset (void) +{ + int i; + + gus_select_max_voices (24); + volume_base = 3071; + volume_scale = 4; + volume_method = VOL_METHOD_ADAGIO; + + for (i = 0; i < 32; i++) + { + gus_voice_init (i); /* + * Turn voice off + */ + gus_voice_init2 (i); + } + + INB (u_Status); /* + * Touch the status register + */ + + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ + +} + +static void +gus_initialize (void) +{ + unsigned long flags; + unsigned char dma_image, irq_image, tmp; + + static unsigned char gus_irq_map[16] = + {0, 0, 1, 3, 0, 2, 0, 4, 0, 0, 0, 5, 6, 0, 0, 7}; + + static unsigned char gus_dma_map[8] = + {0, 1, 0, 2, 0, 3, 4, 5}; + + DISABLE_INTR (flags); + + gus_write8 (0x4c, 0); /* + * Reset GF1 + */ + gus_delay (); + gus_delay (); + + gus_write8 (0x4c, 1); /* + * Release Reset + */ + gus_delay (); + gus_delay (); + + /* + * Clear all interrupts + */ + + gus_write8 (0x41, 0); /* + * DMA control + */ + gus_write8 (0x45, 0); /* + * Timer control + */ + gus_write8 (0x49, 0); /* + * Sample control + */ + + gus_select_max_voices (24); + + INB (u_Status); /* + * Touch the status register + */ + + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ + + gus_reset (); /* + * Resets all voices + */ + + gus_look8 (0x41); /* + * Clear any pending DMA IRQs + */ + gus_look8 (0x49); /* + * Clear any pending sample IRQs + */ + gus_read8 (0x0f); /* + * Clear pending IRQs + */ + + gus_write8 (0x4c, 7); /* + * Master reset | DAC enable | IRQ enable + */ + + /* + * Set up for Digital ASIC + */ + + OUTB (0x05, gus_base + 0x0f); + + mix_image |= 0x02; /* + * Disable line out + */ + OUTB (mix_image, u_Mixer); + + OUTB (0x00, u_IRQDMAControl); + + OUTB (0x00, gus_base + 0x0f); + + /* + * Now set up the DMA and IRQ interface + * + * The GUS supports two IRQs and two DMAs. + * + * Just one DMA channel is used. This prevents simultaneous ADC and DAC. + * Adding this support requires significant changes to the dmabuf.c, dsp.c + * and audio.c also. + */ + + irq_image = 0; + tmp = gus_irq_map[gus_irq]; + if (!tmp) + printk ("Warning! GUS IRQ not selected\n"); + irq_image |= tmp; + irq_image |= 0x40; /* + * Combine IRQ1 (GF1) and IRQ2 (Midi) + */ + + dma_image = 0x40; /* + * Combine DMA1 (DRAM) and IRQ2 (ADC) + */ + tmp = gus_dma_map[gus_dma]; + if (!tmp) + printk ("Warning! GUS DMA not selected\n"); + dma_image |= tmp; + + /* + * For some reason the IRQ and DMA addresses must be written twice + */ + + /* + * Doing it first time + */ + + OUTB (mix_image, u_Mixer); /* + * Select DMA control + */ + OUTB (dma_image | 0x80, u_IRQDMAControl); /* + * Set DMA address + */ + + OUTB (mix_image | 0x40, u_Mixer); /* + * Select IRQ control + */ + OUTB (irq_image, u_IRQDMAControl); /* + * Set IRQ address + */ + + /* + * Doing it second time + */ + + OUTB (mix_image, u_Mixer); /* + * Select DMA control + */ + OUTB (dma_image, u_IRQDMAControl); /* + * Set DMA address + */ + + OUTB (mix_image | 0x40, u_Mixer); /* + * Select IRQ control + */ + OUTB (irq_image, u_IRQDMAControl); /* + * Set IRQ address + */ + + gus_select_voice (0); /* + * This disables writes to IRQ/DMA reg + */ + + mix_image &= ~0x02; /* + * Enable line out + */ + mix_image |= 0x08; /* + * Enable IRQ + */ + OUTB (mix_image, u_Mixer); /* + * Turn mixer channels on + * Note! Mic in is left off. + */ + + gus_select_voice (0); /* + * This disables writes to IRQ/DMA reg + */ + + gusintr (0); /* + * Serve pending interrupts + */ + RESTORE_INTR (flags); +} + +int +gus_wave_detect (int baseaddr) +{ + unsigned long i; + unsigned long loc; + + gus_base = baseaddr; + + gus_write8 (0x4c, 0); /* Reset GF1 */ + gus_delay (); + gus_delay (); + + gus_write8 (0x4c, 1); /* Release Reset */ + gus_delay (); + gus_delay (); + + /* See if there is first block there.... */ + gus_poke (0L, 0xaa); + if (gus_peek (0L) != 0xaa) + return (0); + + /* Now zero it out so that I can check for mirroring .. */ + gus_poke (0L, 0x00); + for (i = 1L; i < 1024L; i++) + { + int n, failed; + + /* check for mirroring ... */ + if (gus_peek (0L) != 0) + break; + loc = i << 10; + + for (n = loc - 1, failed = 0; n <= loc; n++) + { + gus_poke (loc, 0xaa); + if (gus_peek (loc) != 0xaa) + failed = 1; + + gus_poke (loc, 0x55); + if (gus_peek (loc) != 0x55) + failed = 1; + } + + if (failed) + break; + } + gus_mem_size = i << 10; + return 1; +} + +static int +guswave_ioctl (int dev, + unsigned int cmd, unsigned int arg) +{ + + switch (cmd) + { + case SNDCTL_SYNTH_INFO: + gus_info.nr_voices = nr_voices; + IOCTL_TO_USER ((char *) arg, 0, &gus_info, sizeof (gus_info)); + return 0; + break; + + case SNDCTL_SEQ_RESETSAMPLES: + reset_sample_memory (); + return 0; + break; + + case SNDCTL_SEQ_PERCMODE: + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return gus_mem_size - free_mem_ptr - 32; + + default: + return RET_ERROR (EINVAL); + } +} + +static int +guswave_set_instr (int dev, int voice, int instr_no) +{ + int sample_no; + + if (instr_no < 0 || instr_no > MAX_PATCH) + return RET_ERROR (EINVAL); + + if (voice < 0 || voice > 31) + return RET_ERROR (EINVAL); + + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + { + voices[voice].sample_pending = instr_no; + return 0; + } + + sample_no = patch_table[instr_no]; + patch_map[voice] = -1; + + if (sample_no < 0) + { + printk ("GUS: Undefined patch %d for voice %d\n", instr_no, voice); + return RET_ERROR (EINVAL); /* + * Patch not defined + */ + } + + if (sample_ptrs[sample_no] == -1) /* + * Sample not loaded + */ + { + printk ("GUS: Sample #%d not loaded for patch %d (voice %d)\n", sample_no, instr_no, voice); + return RET_ERROR (EINVAL); + } + + sample_map[voice] = sample_no; + patch_map[voice] = instr_no; + return 0; +} + +static int +#ifdef FUTURE_VERSION +guswave_kill_note (int dev, int voice, int note, int velocity) +#else +guswave_kill_note (int dev, int voice, int velocity) +#endif +{ + unsigned long flags; + + DISABLE_INTR (flags); + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].kill_pending = 1; + else + { + gus_select_voice (voice); + gus_voice_fade (voice); + } + RESTORE_INTR (flags); + + return 0; +} + +static void +guswave_aftertouch (int dev, int voice, int pressure) +{ + short lo_limit, hi_limit; + unsigned long flags; + + return; /* + * Currently disabled + */ + + if (voice < 0 || voice > 31) + return; + + if (voices[voice].mode & WAVE_ENVELOPES && voices[voice].env_phase != 2) + return; /* + * Don't mix with envelopes + */ + + if (pressure < 32) + { + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_rampoff (); + compute_and_set_volume (voice, 255, 0); /* + * Back to original volume + */ + RESTORE_INTR (flags); + return; + } + + hi_limit = voices[voice].current_volume; + lo_limit = hi_limit * 99 / 100; + if (lo_limit < 65) + lo_limit = 65; + + DISABLE_INTR (flags); + gus_select_voice (voice); + if (hi_limit > (4095 - 65)) + { + hi_limit = 4095 - 65; + gus_voice_volume (hi_limit); + } + gus_ramp_range (lo_limit, hi_limit); + gus_ramp_rate (3, 8); + gus_rampon (0x58); /* + * Bidirectional, Down, Loop + */ + RESTORE_INTR (flags); +} + +static void +guswave_panning (int dev, int voice, int value) +{ + if (voice >= 0 || voice < 32) + voices[voice].panning = value; +} + +static void +compute_volume (int voice, int volume) +{ + if (volume < 128) + voices[voice].midi_volume = volume; + + switch (volume_method) + { + case VOL_METHOD_ADAGIO: + voices[voice].initial_volume = + gus_adagio_vol (voices[voice].midi_volume, voices[voice].main_vol, + voices[voice].expression_vol, + voices[voice].patch_vol); + break; + + default: + voices[voice].initial_volume = volume_base + + (voices[voice].midi_volume * volume_scale); + } + + if (voices[voice].initial_volume > 4030) + voices[voice].initial_volume = 4030; +} + +static void +compute_and_set_volume (int voice, int volume, int ramp_time) +{ + int current, target, rate; + unsigned long flags; + + DISABLE_INTR (flags); +/* + * CAUTION! Interrupts disabled. Enable them before returning + */ + + gus_select_voice (voice); + + compute_volume (voice, volume); + voices[voice].current_volume = voices[voice].initial_volume; + + current = gus_read16 (0x09) >> 4; + target = voices[voice].initial_volume; + + if (ramp_time == INSTANT_RAMP) + { + gus_rampoff (); + gus_voice_volume (target); + RESTORE_INTR (flags); + return; + } + + if (ramp_time == FAST_RAMP) + rate = 63; + else + rate = 16; + gus_ramp_rate (0, rate); + + if ((target - current) / 64 == 0) /* + * Too close + */ + { + gus_rampoff (); + gus_voice_volume (target); + RESTORE_INTR (flags); + return; + } + + if (target > current) + { + if (target > (4095 - 65)) + target = 4095 - 65; + gus_ramp_range (current, target); + gus_rampon (0x00); /* + * Ramp up, once, no irq + */ + } + else + { + if (target < 65) + target = 65; + + gus_ramp_range (target, current); + gus_rampon (0x40); /* + * Ramp down, once, no irq + */ + } + RESTORE_INTR (flags); +} + +static void +dynamic_volume_change (int voice) +{ + unsigned char status; + unsigned long flags; + + DISABLE_INTR (flags); + gus_select_voice (voice); + status = gus_read8 (0x00); /* + * Voice status + */ + RESTORE_INTR (flags); + + if (status & 0x03) + return; /* + * Voice not started + */ + + if (!(voices[voice].mode & WAVE_ENVELOPES)) + { + compute_and_set_volume (voice, voices[voice].midi_volume, 1); + return; + } + + /* + * Voice is running and has envelopes. + */ + + DISABLE_INTR (flags); + gus_select_voice (voice); + status = gus_read8 (0x0d); /* + * Ramping status + */ + RESTORE_INTR (flags); + + if (status & 0x03) /* + * Sustain phase? + */ + { + compute_and_set_volume (voice, voices[voice].midi_volume, 1); + return; + } + + if (voices[voice].env_phase < 0) + return; + + compute_volume (voice, voices[voice].midi_volume); + +#if 0 /* + * * * Is this really required */ + voices[voice].current_volume = + gus_read16 (0x09) >> 4; /* + * Get current volume + */ + + voices[voice].env_phase--; + step_envelope (voice); +#endif +} + +static void +guswave_controller (int dev, int voice, int ctrl_num, int value) +{ + unsigned long flags; + unsigned long freq; + + if (voice < 0 || voice > 31) + return; + + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; + + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + { + freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + voices[voice].current_freq = freq; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (freq); + RESTORE_INTR (flags); + } + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; +#ifdef FUTURE_VERSION + case CTL_EXPRESSION: + value /= 128; +#endif + case CTRL_EXPRESSION: + volume_method = VOL_METHOD_ADAGIO; + voices[voice].expression_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change (voice); + break; + +#ifdef FUTURE_VERSION + case CTL_PAN: + voices[voice].panning = (value * 2) - 128; + break; + + case CTL_MAIN_VOLUME: + value = (value * 100) / 16383; +#endif + + case CTRL_MAIN_VOLUME: + volume_method = VOL_METHOD_ADAGIO; + voices[voice].main_vol = value; + if (voices[voice].volume_irq_mode != VMODE_START_NOTE) + dynamic_volume_change (voice); + break; + + default: /* + * Ignore + */ + break; + } +} + +static int +guswave_start_note2 (int dev, int voice, int note_num, int volume) +{ + int sample, best_sample, best_delta, delta_freq; + int is16bits, samplep, patch, pan; + unsigned long note_freq, base_note, freq, flags; + unsigned char mode = 0; + + if (voice < 0 || voice > 31) + { + printk ("GUS: Invalid voice\n"); + return RET_ERROR (EINVAL); + } + + if (note_num == 255) + { + if (voices[voice].mode & WAVE_ENVELOPES) + { + voices[voice].midi_volume = volume; + dynamic_volume_change (voice); + return 0; + } + + compute_and_set_volume (voice, volume, 1); + return 0; + } + + if ((patch = patch_map[voice]) == -1) + { + return RET_ERROR (EINVAL); + } + + if ((samplep = patch_table[patch]) == -1) + { + return RET_ERROR (EINVAL); + } + + note_freq = note_to_freq (note_num); + + /* + * Find a sample within a patch so that the note_freq is between low_note + * and high_note. + */ + sample = -1; + + best_sample = samplep; + best_delta = 1000000; + while (samplep >= 0 && sample == -1) + { + delta_freq = note_freq - samples[samplep].base_note; + if (delta_freq < 0) + delta_freq = -delta_freq; + if (delta_freq < best_delta) + { + best_sample = samplep; + best_delta = delta_freq; + } + if (samples[samplep].low_note <= note_freq && note_freq <= samples[samplep].high_note) + sample = samplep; + else + samplep = samples[samplep].key; /* + * Follow link + */ + } + if (sample == -1) + sample = best_sample; + + if (sample == -1) + { + printk ("GUS: Patch %d not defined for note %d\n", patch, note_num); + return 0; /* + * Should play default patch ??? + */ + } + + is16bits = (samples[sample].mode & WAVE_16_BITS) ? 1 : 0; /* + * 8 or 16 + * bit + * samples + */ + voices[voice].mode = samples[sample].mode; + voices[voice].patch_vol = samples[sample].volume; + + if (voices[voice].mode & WAVE_ENVELOPES) + { + int i; + + for (i = 0; i < 6; i++) + { + voices[voice].env_rate[i] = samples[sample].env_rate[i]; + voices[voice].env_offset[i] = samples[sample].env_offset[i]; + } + } + + sample_map[voice] = sample; + + base_note = samples[sample].base_note / 100; /* + * To avoid overflows + */ + note_freq /= 100; + + freq = samples[sample].base_freq * note_freq / base_note; + + voices[voice].orig_freq = freq; + + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ + + freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); + voices[voice].current_freq = freq; + + pan = (samples[sample].panning + voices[voice].panning) / 32; + pan += 7; + if (pan < 0) + pan = 0; + if (pan > 15) + pan = 15; + + if (samples[sample].mode & WAVE_16_BITS) + { + mode |= 0x04; /* + * 16 bits + */ + if ((sample_ptrs[sample] >> 18) != + ((sample_ptrs[sample] + samples[sample].len) >> 18)) + printk ("GUS: Sample address error\n"); + } + + /************************************************************************* + * CAUTION! Interrupts disabled. Don't return before enabling + *************************************************************************/ + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_off (); /* + * It may still be running + */ + gus_rampoff (); + if (voices[voice].mode & WAVE_ENVELOPES) + { + compute_volume (voice, volume); + init_envelope (voice); + } + else + compute_and_set_volume (voice, volume, 0); + + if (samples[sample].mode & WAVE_LOOP_BACK) + gus_write_addr (0x0a, sample_ptrs[sample] + samples[sample].len - + voices[voice].offset_pending, is16bits); /* Sample + * start=end */ + else + gus_write_addr (0x0a, sample_ptrs[sample] + voices[voice].offset_pending, + is16bits); /* Sample start=begin */ + + if (samples[sample].mode & WAVE_LOOPING) + { + mode |= 0x08; /* + * Looping on + */ + + if (samples[sample].mode & WAVE_BIDIR_LOOP) + mode |= 0x10; /* + * Bidirectional looping on + */ + + if (samples[sample].mode & WAVE_LOOP_BACK) + { + gus_write_addr (0x0a, + sample_ptrs[sample] + samples[sample].loop_end - + voices[voice].offset_pending, is16bits); + mode |= 0x40; + } + + gus_write_addr (0x02, sample_ptrs[sample] + samples[sample].loop_start, is16bits); /* + * Loop + * start + * location + */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].loop_end, is16bits); /* + * Loop + * end + * location + */ + } + else + { + mode |= 0x20; /* + * Loop irq at the end + */ + voices[voice].loop_irq_mode = LMODE_FINISH; /* + * Ramp it down at + * the * end + */ + voices[voice].loop_irq_parm = 1; + gus_write_addr (0x02, sample_ptrs[sample], is16bits); /* + * Loop start + * location + */ + gus_write_addr (0x04, sample_ptrs[sample] + samples[sample].len-1, is16bits); /* + * Loop + * end + * location + */ + } + gus_voice_freq (freq); + gus_voice_balance (pan); + gus_voice_on (mode); + RESTORE_INTR (flags); + + return 0; +} + +/* + * * New guswave_start_note by Andrew J. Robinson attempts to minimize + * clicking * when the note playing on the voice is changed. It uses volume + * ramping. */ + +static int +guswave_start_note (int dev, int voice, int note_num, int volume) +{ + long int flags; + int mode; + int ret_val = 0; + + DISABLE_INTR (flags); + if (note_num == 255) + { + if (voices[voice].volume_irq_mode == VMODE_START_NOTE) + voices[voice].volume_pending = volume; + else + ret_val = guswave_start_note2 (dev, voice, note_num, volume); + } + else + { + gus_select_voice (voice); + mode = gus_read8 (0x00); + if (mode & 0x20) + gus_write8 (0x00, mode & 0xdf); /* No interrupt! */ + + voices[voice].offset_pending = 0; + voices[voice].kill_pending = 0; + voices[voice].volume_irq_mode = 0; + voices[voice].loop_irq_mode = 0; + + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr (voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + + if ((mode & 0x01) || ((gus_read16 (0x09) >> 4) < 2065)) + { + ret_val = guswave_start_note2 (dev, voice, note_num, volume); + } + else + { + voices[voice].dev_pending = dev; + voices[voice].note_pending = note_num; + voices[voice].volume_pending = volume; + voices[voice].volume_irq_mode = VMODE_START_NOTE; + + gus_rampoff (); + gus_ramp_range (2000, 4065); + gus_ramp_rate (0, 63); /* Fastest possible rate */ + gus_rampon (0x20 | 0x40); /* Ramp down, once, irq */ + } + } + RESTORE_INTR (flags); + return ret_val; +} + +static void +guswave_reset (int dev) +{ + int i; + + for (i = 0; i < 32; i++) + { + gus_voice_init (i); + gus_voice_init2 (i); + } +} + +static int +guswave_open (int dev, int mode) +{ + int err; + + if (gus_busy) + return RET_ERROR (EBUSY); + + gus_initialize (); + + if ((err = DMAbuf_open_dma (gus_devnum))) + return err; + + RESET_WAIT_QUEUE (dram_sleeper, dram_sleep_flag); + gus_busy = 1; + active_device = GUS_DEV_WAVE; + + gus_reset (); + + return 0; +} + +static void +guswave_close (int dev) +{ + gus_busy = 0; + active_device = 0; + gus_reset (); + + DMAbuf_close_dma (gus_devnum); +} + +static int +guswave_load_patch (int dev, int format, snd_rw_buf * addr, + int offs, int count, int pmgr_flag) +{ + struct patch_info patch; + int instr; + long sizeof_patch; + + unsigned long blk_size, blk_end, left, src_offs, target; + + sizeof_patch = (long) &patch.data[0] - (long) &patch; /* + * Size of + * the header + * * info + */ + + if (format != GUS_PATCH) + { + printk ("GUS Error: Invalid patch format (key) 0x%x\n", format); + return RET_ERROR (EINVAL); + } + + if (count < sizeof_patch) + { + printk ("GUS Error: Patch header too short\n"); + return RET_ERROR (EINVAL); + } + + count -= sizeof_patch; + + if (free_sample >= MAX_SAMPLE) + { + printk ("GUS: Sample table full\n"); + return RET_ERROR (ENOSPC); + } + + /* + * Copy the header from user space but ignore the first bytes which have + * been transferred already. + */ + + COPY_FROM_USER (&((char *) &patch)[offs], addr, offs, sizeof_patch - offs); + + instr = patch.instr_no; + + if (instr < 0 || instr > MAX_PATCH) + { + printk ("GUS: Invalid patch number %d\n", instr); + return RET_ERROR (EINVAL); + } + + if (count < patch.len) + { + printk ("GUS Warning: Patch record too short (%d<%d)\n", + count, (int) patch.len); + patch.len = count; + } + + if (patch.len <= 0 || patch.len > gus_mem_size) + { + printk ("GUS: Invalid sample length %d\n", (int) patch.len); + return RET_ERROR (EINVAL); + } + + if (patch.mode & WAVE_LOOPING) + { + if (patch.loop_start < 0 || patch.loop_start >= patch.len) + { + printk ("GUS: Invalid loop start\n"); + return RET_ERROR (EINVAL); + } + + if (patch.loop_end < patch.loop_start || patch.loop_end > patch.len) + { + printk ("GUS: Invalid loop end\n"); + return RET_ERROR (EINVAL); + } + } + + free_mem_ptr = (free_mem_ptr + 31) & ~31; /* + * Alignment 32 bytes + */ + +#define GUS_BANK_SIZE (256*1024) + + if (patch.mode & WAVE_16_BITS) + { + /* + * 16 bit samples must fit one 256k bank. + */ + if (patch.len >= GUS_BANK_SIZE) + { + printk ("GUS: Sample (16 bit) too long %d\n", (int) patch.len); + return RET_ERROR (ENOSPC); + } + + if ((free_mem_ptr / GUS_BANK_SIZE) != + ((free_mem_ptr + patch.len) / GUS_BANK_SIZE)) + { + unsigned long tmp_mem = /* + * Align to 256K*N + */ + ((free_mem_ptr / GUS_BANK_SIZE) + 1) * GUS_BANK_SIZE; + + if ((tmp_mem + patch.len) > gus_mem_size) + return RET_ERROR (ENOSPC); + + free_mem_ptr = tmp_mem; /* + * This leaves unusable memory + */ + } + } + + if ((free_mem_ptr + patch.len) > gus_mem_size) + return RET_ERROR (ENOSPC); + + sample_ptrs[free_sample] = free_mem_ptr; + + /* + * Tremolo is not possible with envelopes + */ + + if (patch.mode & WAVE_ENVELOPES) + patch.mode &= ~WAVE_TREMOLO; + + memcpy ((char *) &samples[free_sample], &patch, sizeof_patch); + + /* + * Link this_one sample to the list of samples for patch 'instr'. + */ + + samples[free_sample].key = patch_table[instr]; + patch_table[instr] = free_sample; + + /* + * Use DMA to transfer the wave data to the DRAM + */ + + left = patch.len; + src_offs = 0; + target = free_mem_ptr; + + while (left) /* + * Not all moved + */ + { + blk_size = sound_buffsizes[gus_devnum]; + if (blk_size > left) + blk_size = left; + + /* + * DMA cannot cross 256k bank boundaries. Check for that. + */ + blk_end = target + blk_size; + + if ((target >> 18) != (blk_end >> 18)) + { /* + * Have to split the block + */ + + blk_end &= ~(256 * 1024 - 1); + blk_size = blk_end - target; + } + +#if defined(GUS_NO_DMA) || defined(GUS_PATCH_NO_DMA) + /* + * For some reason the DMA is not possible. We have to use PIO. + */ + { + long i; + unsigned char data; + + for (i = 0; i < blk_size; i++) + { + GET_BYTE_FROM_USER (data, addr, sizeof_patch + i); + if (patch.mode & WAVE_UNSIGNED) + + if (!(patch.mode & WAVE_16_BITS) || (i & 0x01)) + data ^= 0x80; /* + * Convert to signed + */ + gus_poke (target + i, data); + } + } +#else /* + * * * GUS_NO_DMA */ + { + unsigned long address, hold_address; + unsigned char dma_command; + unsigned long flags; + + /* + * OK, move now. First in and then out. + */ + + COPY_FROM_USER (snd_raw_buf[gus_devnum][0], + addr, sizeof_patch + src_offs, + blk_size); + + DISABLE_INTR (flags); /******** INTERRUPTS DISABLED NOW ********/ + gus_write8 (0x41, 0); /* + * Disable GF1 DMA + */ + DMAbuf_start_dma (gus_devnum, snd_raw_buf_phys[gus_devnum][0], + blk_size, DMA_MODE_WRITE); + + /* + * Set the DRAM address for the wave data + */ + + address = target; + + if (sound_dsp_dmachan[gus_devnum] > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + + gus_write16 (0x42, (address >> 4) & 0xffff); /* + * DRAM DMA address + */ + + /* + * Start the DMA transfer + */ + + dma_command = 0x21; /* + * IRQ enable, DMA start + */ + if (patch.mode & WAVE_UNSIGNED) + dma_command |= 0x80; /* + * Invert MSB + */ + if (patch.mode & WAVE_16_BITS) + dma_command |= 0x40; /* + * 16 bit _DATA_ + */ + if (sound_dsp_dmachan[gus_devnum] > 3) + dma_command |= 0x04; /* + * 16 bit DMA channel + */ + + gus_write8 (0x41, dma_command); /* + * Let's go luteet (=bugs) + */ + + /* + * Sleep here until the DRAM DMA done interrupt is served + */ + active_device = GUS_DEV_WAVE; + + DO_SLEEP (dram_sleeper, dram_sleep_flag, HZ); + if (TIMED_OUT (dram_sleeper, dram_sleep_flag)) + printk ("GUS: DMA Transfer timed out\n"); + RESTORE_INTR (flags); + } +#endif /* + * * * GUS_NO_DMA */ + + /* + * Now the next part + */ + + left -= blk_size; + src_offs += blk_size; + target += blk_size; + + gus_write8 (0x41, 0); /* + * Stop DMA + */ + } + + free_mem_ptr += patch.len; + + if (!pmgr_flag) + pmgr_inform (dev, PM_E_PATCH_LOADED, instr, free_sample, 0, 0); + free_sample++; + return 0; +} + +static void +guswave_hw_control (int dev, unsigned char *event) +{ + int voice, cmd; + unsigned short p1, p2; + unsigned long plong, flags; + + cmd = event[2]; + voice = event[3]; + p1 = *(unsigned short *) &event[4]; + p2 = *(unsigned short *) &event[6]; + plong = *(unsigned long *) &event[4]; + + if ((voices[voice].volume_irq_mode == VMODE_START_NOTE) && + (cmd != _GUS_VOICESAMPLE) && (cmd != _GUS_VOICE_POS)) + do_volume_irq (voice); + + switch (cmd) + { + + case _GUS_NUMVOICES: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_select_max_voices (p1); + RESTORE_INTR (flags); + break; + + case _GUS_VOICESAMPLE: + guswave_set_instr (dev, voice, p1); + break; + + case _GUS_VOICEON: + DISABLE_INTR (flags); + gus_select_voice (voice); + p1 &= ~0x20; /* + * Disable intr + */ + gus_voice_on (p1); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEOFF: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_off (); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEFADE: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_fade (voice); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEMODE: + DISABLE_INTR (flags); + gus_select_voice (voice); + p1 &= ~0x20; /* + * Disable intr + */ + gus_voice_mode (p1); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEBALA: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_balance (p1); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEFREQ: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (plong); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEVOL: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_volume (p1); + RESTORE_INTR (flags); + break; + + case _GUS_VOICEVOL2: /* + * Just update the voice value + */ + voices[voice].initial_volume = + voices[voice].current_volume = p1; + break; + + case _GUS_RAMPRANGE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* + * NO-NO + */ + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_ramp_range (p1, p2); + RESTORE_INTR (flags); + break; + + case _GUS_RAMPRATE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* + * NO-NO + */ + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_ramp_rate (p1, p2); + RESTORE_INTR (flags); + break; + + case _GUS_RAMPMODE: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* + * NO-NO + */ + DISABLE_INTR (flags); + gus_select_voice (voice); + p1 &= ~0x20; /* + * Disable intr + */ + gus_ramp_mode (p1); + RESTORE_INTR (flags); + break; + + case _GUS_RAMPON: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* + * NO-NO + */ + DISABLE_INTR (flags); + gus_select_voice (voice); + p1 &= ~0x20; /* + * Disable intr + */ + gus_rampon (p1); + RESTORE_INTR (flags); + break; + + case _GUS_RAMPOFF: + if (voices[voice].mode & WAVE_ENVELOPES) + break; /* + * NO-NO + */ + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_rampoff (); + RESTORE_INTR (flags); + break; + + case _GUS_VOLUME_SCALE: + volume_base = p1; + volume_scale = p2; + break; + + case _GUS_VOICE_POS: + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_set_voice_pos (voice, plong); + RESTORE_INTR (flags); + break; + + default:; + } +} + +static int +gus_sampling_set_speed (int speed) +{ + if (speed <= 0) + return gus_sampling_speed; + + if (speed > 44100) + speed = 44100; + + gus_sampling_speed = speed; + return speed; +} + +static int +gus_sampling_set_channels (int channels) +{ + if (!channels) + return gus_sampling_channels; + if (channels > 2) + channels = 2; + if (channels < 1) + channels = 1; + gus_sampling_channels = channels; + return channels; +} + +static int +gus_sampling_set_bits (int bits) +{ + if (!bits) + return gus_sampling_bits; + + if (bits != 8 && bits != 16) + bits = 8; + + gus_sampling_bits = bits; + return bits; +} + +static int +gus_sampling_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return gus_sampling_set_speed (arg); + return IOCTL_OUT (arg, gus_sampling_set_speed (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_RATE: + if (local) + return gus_sampling_speed; + return IOCTL_OUT (arg, gus_sampling_speed); + break; + + case SNDCTL_DSP_STEREO: + if (local) + return gus_sampling_set_channels (arg + 1) - 1; + return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg) + 1) - 1); + break; + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return gus_sampling_set_channels (arg); + return IOCTL_OUT (arg, gus_sampling_set_channels (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_CHANNELS: + if (local) + return gus_sampling_channels; + return IOCTL_OUT (arg, gus_sampling_channels); + break; + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return gus_sampling_set_bits (arg); + return IOCTL_OUT (arg, gus_sampling_set_bits (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_BITS: + if (local) + return gus_sampling_bits; + return IOCTL_OUT (arg, gus_sampling_bits); + + case SOUND_PCM_WRITE_FILTER: /* + * NOT YET IMPLEMENTED + */ + return IOCTL_OUT (arg, RET_ERROR (EINVAL)); + break; + + case SOUND_PCM_READ_FILTER: + return IOCTL_OUT (arg, RET_ERROR (EINVAL)); + break; + + default: + return RET_ERROR (EINVAL); + } + return RET_ERROR (EINVAL); +} + +static void +gus_sampling_reset (int dev) +{ +} + +static int +gus_sampling_open (int dev, int mode) +{ +#ifdef GUS_NO_DMA + printk ("GUS: DMA mode not enabled. Device not supported\n"); + return RET_ERROR (ENXIO); +#endif + + if (gus_busy) + return RET_ERROR (EBUSY); + + gus_initialize (); + + gus_busy = 1; + active_device = 0; + + gus_reset (); + reset_sample_memory (); + gus_select_max_voices (14); + + pcm_active = 0; + pcm_opened = 1; + if (mode & OPEN_READ) + { + recording_active = 1; + set_input_volumes(); + } + + return 0; +} + +static void +gus_sampling_close (int dev) +{ + gus_reset (); + gus_busy = 0; + pcm_opened = 0; + active_device = 0; + + if (recording_active) + set_input_volumes(); + + recording_active = 0; +} + +static void +gus_sampling_update_volume (void) +{ + unsigned long flags; + int voice; + + DISABLE_INTR (flags); + if (pcm_active && pcm_opened) + for (voice = 0; voice < gus_sampling_channels; voice++) + { + gus_select_voice (voice); + gus_rampoff (); + gus_voice_volume (1530 + (25 * gus_pcm_volume)); + gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); + } + RESTORE_INTR (flags); +} + +static void +play_next_pcm_block (void) +{ + unsigned long flags; + int speed = gus_sampling_speed; + int this_one, is16bits, chn; + unsigned long dram_loc; + unsigned char mode[2], ramp_mode[2]; + + if (!pcm_qlen) + return; + + this_one = pcm_head; + + for (chn = 0; chn < gus_sampling_channels; chn++) + { + mode[chn] = 0x00; + ramp_mode[chn] = 0x03; /* + * Ramping and rollover off + */ + + if (chn == 0) + { + mode[chn] |= 0x20; /* + * Loop irq + */ + voices[chn].loop_irq_mode = LMODE_PCM; + } + + if (gus_sampling_bits != 8) + { + is16bits = 1; + mode[chn] |= 0x04; /* + * 16 bit data + */ + } + else + is16bits = 0; + + dram_loc = this_one * pcm_bsize; + dram_loc += chn * pcm_banksize; + + if (this_one == (pcm_nblk - 1)) /* + * Last of the DRAM buffers + */ + { + mode[chn] |= 0x08; /* + * Enable loop + */ + ramp_mode[chn] = 0x03; /* + * Disable rollover + */ + } + else + { + if (chn == 0) + ramp_mode[chn] = 0x04; /* + * Enable rollover bit + */ + } + + DISABLE_INTR (flags); + gus_select_voice (chn); + gus_voice_freq (speed); + + if (gus_sampling_channels == 1) + gus_voice_balance (7); /* + * mono + */ + else if (chn == 0) + gus_voice_balance (0); /* + * left + */ + else + gus_voice_balance (15); /* + * right + */ + + if (!pcm_active) /* + * Voice not started yet + */ + { + /* + * The playback was not started yet (or there has been a pause). + * Start the voice (again) and ask for a rollover irq at the end of + * this_one block. If this_one one is last of the buffers, use just + * the normal loop with irq. + */ + + gus_voice_off (); /* + * It could already be running + */ + gus_rampoff (); + gus_voice_volume (1530 + (25 * gus_pcm_volume)); + gus_ramp_range (65, 1530 + (25 * gus_pcm_volume)); + + gus_write_addr (0x0a, dram_loc, is16bits); /* + * Starting position + */ + gus_write_addr (0x02, chn * pcm_banksize, is16bits); /* + * Loop start + * location + */ + + if (chn != 0) + gus_write_addr (0x04, pcm_banksize + (pcm_bsize * pcm_nblk), + is16bits); /* + * Loop end location + */ + } + + if (chn == 0) + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* + * Loop + * end + * location + */ + else + mode[chn] |= 0x08; /* + * Enable loop + */ + + if (pcm_datasize[this_one] != pcm_bsize) + { + /* + * Incomplete block. Possibly the last one. + */ + if (chn == 0) + { + mode[chn] &= ~0x08; /* + * Disable loop + */ + mode[chn] |= 0x20; /* + * Enable loop IRQ + */ + voices[0].loop_irq_mode = LMODE_PCM_STOP; + ramp_mode[chn] = 0x03; /* + * No rollover bit + */ + } + else + { + gus_write_addr (0x04, dram_loc + pcm_datasize[this_one], is16bits); /* + * Loop + * end + * location + */ + mode[chn] &= ~0x08; /* + * Disable loop + */ + } + } + + RESTORE_INTR (flags); + } + + for (chn = 0; chn < gus_sampling_channels; chn++) + { + DISABLE_INTR (flags); + gus_select_voice (chn); + gus_write8 (0x0d, ramp_mode[chn]); + gus_voice_on (mode[chn]); + RESTORE_INTR (flags); + } + + pcm_active = 1; +} + +static void +gus_transfer_output_block (int dev, unsigned long buf, + int total_count, int intrflag, int chn) +{ + /* + * This routine transfers one block of audio data to the DRAM. In mono mode + * it's called just once. When in stereo mode, this_one routine is called + * once for both channels. + * + * The left/mono channel data is transferred to the beginning of dram and the + * right data to the area pointed by gus_page_size. + */ + + int this_one, count; + unsigned long flags; + unsigned char dma_command; + unsigned long address, hold_address; + + DISABLE_INTR (flags); + + count = total_count / gus_sampling_channels; + + if (chn == 0) + { + if (pcm_qlen >= pcm_nblk) + printk ("GUS Warning: PCM buffers out of sync\n"); + + this_one = pcm_current_block = pcm_tail; + pcm_qlen++; + pcm_tail = (pcm_tail + 1) % pcm_nblk; + pcm_datasize[this_one] = count; + } + else + this_one = pcm_current_block; + + gus_write8 (0x41, 0); /* + * Disable GF1 DMA + */ + DMAbuf_start_dma (dev, buf + (chn * count), count, DMA_MODE_WRITE); + + address = this_one * pcm_bsize; + address += chn * pcm_banksize; + + if (sound_dsp_dmachan[dev] > 3) + { + hold_address = address; + address = address >> 1; + address &= 0x0001ffffL; + address |= (hold_address & 0x000c0000L); + } + + gus_write16 (0x42, (address >> 4) & 0xffff); /* + * DRAM DMA address + */ + + dma_command = 0x21; /* + * IRQ enable, DMA start + */ + + if (gus_sampling_bits != 8) + dma_command |= 0x40; /* + * 16 bit _DATA_ + */ + else + dma_command |= 0x80; /* + * Invert MSB + */ + + if (sound_dsp_dmachan[dev] > 3) + dma_command |= 0x04; /* + * 16 bit DMA channel + */ + + gus_write8 (0x41, dma_command); /* + * Kick on + */ + + if (chn == (gus_sampling_channels - 1)) /* + * Last channel + */ + { + /* + * Last (right or mono) channel data + */ + active_device = GUS_DEV_PCM_DONE; + if (!pcm_active && (pcm_qlen > 2 || count < pcm_bsize)) + { + play_next_pcm_block (); + } + } + else /* + * * * Left channel data. The right channel + * is * * * transferred after DMA interrupt */ + active_device = GUS_DEV_PCM_CONTINUE; + + RESTORE_INTR (flags); +} + +static void +gus_sampling_output_block (int dev, unsigned long buf, int total_count, + int intrflag, int restart_dma) +{ + pcm_current_buf = buf; + pcm_current_count = total_count; + pcm_current_intrflag = intrflag; + pcm_current_dev = dev; + gus_transfer_output_block (dev, buf, total_count, intrflag, 0); +} + +static void +gus_sampling_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) +{ + unsigned long flags; + unsigned char mode; + + DISABLE_INTR (flags); + + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + mode = 0xa0; /* + * DMA IRQ enable, invert MSB + */ + + if (sound_dsp_dmachan[dev] > 3) + mode |= 0x04; /* + * 16 bit DMA channel + */ + if (gus_sampling_channels > 1) + mode |= 0x02; /* + * Stereo + */ + mode |= 0x01; /* + * DMA enable + */ + + gus_write8 (0x49, mode); + + RESTORE_INTR (flags); +} + +static int +gus_sampling_prepare_for_input (int dev, int bsize, int bcount) +{ + unsigned int rate; + + rate = (9878400 / (gus_sampling_speed + 2)) / 16; + + gus_write8 (0x48, rate & 0xff); /* + * Set sampling frequency + */ + + if (gus_sampling_bits != 8) + { + printk ("GUS Error: 16 bit recording not supported\n"); + return RET_ERROR (EINVAL); + } + + return 0; +} + +static int +gus_sampling_prepare_for_output (int dev, int bsize, int bcount) +{ + int i; + + long mem_ptr, mem_size; + + mem_ptr = 0; + mem_size = gus_mem_size / gus_sampling_channels; + + if (mem_size > (256 * 1024)) + mem_size = 256 * 1024; + + pcm_bsize = bsize / gus_sampling_channels; + pcm_head = pcm_tail = pcm_qlen = 0; + + pcm_nblk = MAX_PCM_BUFFERS; + if ((pcm_bsize * pcm_nblk) > mem_size) + pcm_nblk = mem_size / pcm_bsize; + + for (i = 0; i < pcm_nblk; i++) + pcm_datasize[i] = 0; + + pcm_banksize = pcm_nblk * pcm_bsize; + + if (gus_sampling_bits != 8 && pcm_banksize == (256 * 1024)) + pcm_nblk--; + + return 0; +} + +static int +gus_has_output_drained (int dev) +{ + return !pcm_qlen; +} + +static void +gus_copy_from_user (int dev, char *localbuf, int localoffs, + snd_rw_buf * userbuf, int useroffs, int len) +{ + if (gus_sampling_channels == 1) + { + COPY_FROM_USER (&localbuf[localoffs], userbuf, useroffs, len); + } + else if (gus_sampling_bits == 8) + { + int in_left = useroffs; + int in_right = useroffs + 1; + char *out_left, *out_right; + int i; + + len /= 2; + localoffs /= 2; + out_left = &localbuf[localoffs]; + out_right = out_left + pcm_bsize; + + for (i = 0; i < len; i++) + { + GET_BYTE_FROM_USER (*out_left++, userbuf, in_left); + in_left += 2; + GET_BYTE_FROM_USER (*out_right++, userbuf, in_right); + in_right += 2; + } + } + else + { + int in_left = useroffs; + int in_right = useroffs + 1; + short *out_left, *out_right; + int i; + + len /= 4; + localoffs /= 4; + + out_left = (short *) &localbuf[localoffs]; + out_right = out_left + (pcm_bsize / 2); + + for (i = 0; i < len; i++) + { + GET_SHORT_FROM_USER (*out_left++, (short *) userbuf, in_left); + in_left += 2; + GET_SHORT_FROM_USER (*out_right++, (short *) userbuf, in_right); + in_right += 2; + } + } +} + +static struct audio_operations gus_sampling_operations = +{ + "Gravis UltraSound", + gus_sampling_open, + gus_sampling_close, + gus_sampling_output_block, + gus_sampling_start_input, + gus_sampling_ioctl, + gus_sampling_prepare_for_input, + gus_sampling_prepare_for_output, + gus_sampling_reset, + gus_sampling_reset, + gus_has_output_drained, + gus_copy_from_user +}; + +#ifdef FUTURE_VERSION +static void +guswave_bender (int dev, int voice, int value) +{ + int freq; + unsigned long flags; + + voices[voice].bender = value - 8192; + freq = compute_finetune (voices[voice].orig_freq, value, voices[voice].bender_range); + voices[voice].current_freq = freq; + + DISABLE_INTR (flags); + gus_select_voice (voice); + gus_voice_freq (freq); + RESTORE_INTR (flags); +} +#endif + +static int +guswave_patchmgr (int dev, struct patmgr_info *rec) +{ + int i, n; + + switch (rec->command) + { + case PM_GET_DEVTYPE: + rec->parm1 = PMTYPE_WAVE; + return 0; + break; + + case PM_GET_NRPGM: + rec->parm1 = MAX_PATCH; + return 0; + break; + + case PM_GET_PGMMAP: + rec->parm1 = MAX_PATCH; + + for (i = 0; i < MAX_PATCH; i++) + { + int ptr = patch_table[i]; + + rec->data.data8[i] = 0; + + while (ptr >= 0 && ptr < free_sample) + { + rec->data.data8[i]++; + ptr = samples[ptr].key; /* + * Follow link + */ + } + } + return 0; + break; + + case PM_GET_PGM_PATCHES: + { + int ptr = patch_table[rec->parm1]; + + n = 0; + + while (ptr >= 0 && ptr < free_sample) + { + rec->data.data32[n++] = ptr; + ptr = samples[ptr].key; /* + * Follow link + */ + } + } + rec->parm1 = n; + return 0; + break; + + case PM_GET_PATCH: + { + int ptr = rec->parm1; + struct patch_info *pat; + + if (ptr < 0 || ptr >= free_sample) + return RET_ERROR (EINVAL); + + memcpy (rec->data.data8, (char *) &samples[ptr], + sizeof (struct patch_info)); + + pat = (struct patch_info *) rec->data.data8; + + pat->key = GUS_PATCH; /* + * Restore patch type + */ + rec->parm1 = sample_ptrs[ptr]; /* + * DRAM address + */ + rec->parm2 = sizeof (struct patch_info); + } + return 0; + break; + + case PM_SET_PATCH: + { + int ptr = rec->parm1; + struct patch_info *pat; + + if (ptr < 0 || ptr >= free_sample) + return RET_ERROR (EINVAL); + + pat = (struct patch_info *) rec->data.data8; + + if (pat->len > samples[ptr].len) /* + * Cannot expand sample + */ + return RET_ERROR (EINVAL); + + pat->key = samples[ptr].key; /* + * Ensure the link is correct + */ + + memcpy ((char *) &samples[ptr], rec->data.data8, + sizeof (struct patch_info)); + + pat->key = GUS_PATCH; + } + return 0; + break; + + case PM_READ_PATCH: /* + * Returns a block of wave data from the DRAM + */ + { + int sample = rec->parm1; + int n; + long offs = rec->parm2; + int l = rec->parm3; + + if (sample < 0 || sample >= free_sample) + return RET_ERROR (EINVAL); + + if (offs < 0 || offs >= samples[sample].len) + return RET_ERROR (EINVAL); /* + * Invalid offset + */ + + n = samples[sample].len - offs; /* + * Nr of bytes left + */ + + if (l > n) + l = n; + + if (l > sizeof (rec->data.data8)) + l = sizeof (rec->data.data8); + + if (l <= 0) + return RET_ERROR (EINVAL); /* + * Was there a bug? + */ + + offs += sample_ptrs[sample]; /* + * Begin offsess + offset to DRAM + */ + + for (n = 0; n < l; n++) + rec->data.data8[n] = gus_peek (offs++); + rec->parm1 = n; /* + * Nr of bytes copied + */ + } + return 0; + break; + + case PM_WRITE_PATCH: /* + * Writes a block of wave data to the DRAM + */ + { + int sample = rec->parm1; + int n; + long offs = rec->parm2; + int l = rec->parm3; + + if (sample < 0 || sample >= free_sample) + return RET_ERROR (EINVAL); + + if (offs < 0 || offs >= samples[sample].len) + return RET_ERROR (EINVAL); /* + * Invalid offset + */ + + n = samples[sample].len - offs; /* + * Nr of bytes left + */ + + if (l > n) + l = n; + + if (l > sizeof (rec->data.data8)) + l = sizeof (rec->data.data8); + + if (l <= 0) + return RET_ERROR (EINVAL); /* + * Was there a bug? + */ + + offs += sample_ptrs[sample]; /* + * Begin offsess + offset to DRAM + */ + + for (n = 0; n < l; n++) + gus_poke (offs++, rec->data.data8[n]); + rec->parm1 = n; /* + * Nr of bytes copied + */ + } + return 0; + break; + + default: + return RET_ERROR (EINVAL); + } +} + +static struct synth_operations guswave_operations = +{ + &gus_info, +#ifdef FUTURE_VERSION + 0, +#endif + SYNTH_TYPE_SAMPLE, + SAMPLE_TYPE_GUS, + guswave_open, + guswave_close, + guswave_ioctl, + guswave_kill_note, + guswave_start_note, + guswave_set_instr, + guswave_reset, + guswave_hw_control, + guswave_load_patch, + guswave_aftertouch, + guswave_controller, + guswave_panning, + guswave_patchmgr, +#ifdef FUTURE_VERSION + guswave_bender +#endif +}; + +static void +set_input_volumes(void) +{ + unsigned long flags; + unsigned char mask = 0xff & ~0x06; /* Just line out enabled */ + + DISABLE_INTR(flags); + +/* + * Enable channels having vol > 10% + * Note! bit 0x01 means line in DISABLED while 0x04 means + * mic in ENABLED. + */ + if (gus_line_vol > 10) mask &= ~0x01; + if (gus_mic_vol > 10) mask |= 0x04; + + if (recording_active) + { +/* + * Disable channel, if not selected for recording + */ + if (!(gus_recmask & SOUND_MASK_LINE)) mask |= 0x01; + if (!(gus_recmask & SOUND_MASK_MIC)) mask &= ~0x04; + } + + mix_image &= ~0x07; + mix_image |= mask & 0x07; + OUTB (mix_image, u_Mixer); + + RESTORE_INTR(flags); +} + +static int +gus_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ +#define MIX_DEVS (SOUND_MASK_MIC|SOUND_MASK_LINE| \ + SOUND_MASK_SYNTH|SOUND_MASK_PCM) + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + gus_recmask = IOCTL_IN(arg) & MIX_DEVS; + if (!(gus_recmask & (SOUND_MASK_MIC|SOUND_MASK_LINE))) + gus_recmask = SOUND_MASK_MIC; + /* Note! Input volumes are updated during next open for recording */ + return IOCTL_OUT (arg, gus_recmask); + break; + + case SOUND_MIXER_MIC: + { + int vol = IOCTL_IN (arg) & 0xff; + if (vol < 0) vol = 0; + if (vol > 100) vol = 100; + gus_mic_vol = vol; + set_input_volumes(); + return IOCTL_OUT (arg, vol | (vol << 8)); + } + break; + + case SOUND_MIXER_LINE: + { + int vol = IOCTL_IN (arg) & 0xff; + if (vol < 0) vol = 0; + if (vol > 100) vol = 100; + gus_line_vol = vol; + set_input_volumes(); + return IOCTL_OUT (arg, vol | (vol << 8)); + } + break; + + case SOUND_MIXER_PCM: + gus_pcm_volume = IOCTL_IN (arg) & 0xff; + if (gus_pcm_volume < 0) + gus_pcm_volume = 0; + if (gus_pcm_volume > 100) + gus_pcm_volume = 100; + gus_sampling_update_volume (); + return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + { + int voice; + + gus_wave_volume = IOCTL_IN (arg) & 0xff; + + if (gus_wave_volume < 0) + gus_wave_volume = 0; + if (gus_wave_volume > 100) + gus_wave_volume = 100; + + if (active_device == GUS_DEV_WAVE) + for (voice = 0; voice < nr_voices; voice++) + dynamic_volume_change (voice); /* + * Apply the new + * volume + */ + + return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); + } + break; + + default: + return RET_ERROR (EINVAL); + } + else + switch (cmd & 0xff) /* + * Return parameters + */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, gus_recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, MIX_DEVS); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, 0); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, SOUND_MASK_MIC|SOUND_MASK_LINE); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, 0); + break; + + case SOUND_MIXER_MIC: + return IOCTL_OUT (arg, gus_mic_vol | (gus_mic_vol << 8)); + break; + + case SOUND_MIXER_LINE: + return IOCTL_OUT (arg, gus_line_vol | (gus_line_vol << 8)); + break; + + case SOUND_MIXER_PCM: + return IOCTL_OUT (arg, gus_pcm_volume | (gus_pcm_volume << 8)); + break; + + case SOUND_MIXER_SYNTH: + return IOCTL_OUT (arg, gus_wave_volume | (gus_wave_volume << 8)); + break; + + default: + return RET_ERROR (EINVAL); + } + } + else + return RET_ERROR (EINVAL); +} + +static struct mixer_operations gus_mixer_operations = +{ + gus_mixer_ioctl +}; + +long +gus_wave_init (long mem_start, int irq, int dma) +{ + printk (" ", (int) gus_mem_size / 1024); + + if (irq < 0 || irq > 15) + { + printk ("ERROR! Invalid IRQ#%d. GUS Disabled", irq); + return mem_start; + } + + if (dma < 0 || dma > 7) + { + printk ("ERROR! Invalid DMA#%d. GUS Disabled", dma); + return mem_start; + } + + gus_irq = irq; + gus_dma = dma; + + if (num_synths >= MAX_SYNTH_DEV) + printk ("GUS Error: Too many synthesizers\n"); + else + synth_devs[num_synths++] = &guswave_operations; + + PERMANENT_MALLOC (struct patch_info *, samples, + (MAX_SAMPLE + 1) * sizeof (*samples), mem_start); + + reset_sample_memory (); + + gus_initialize (); + + if (num_dspdevs < MAX_DSP_DEV) + { + dsp_devs[gus_devnum = num_dspdevs++] = &gus_sampling_operations; + sound_dsp_dmachan[gus_devnum] = dma; + sound_buffcounts[gus_devnum] = 1; + sound_buffsizes[gus_devnum] = DSP_BUFFSIZE; + sound_dma_automode[gus_devnum] = 0; + } + else + printk ("GUS: Too many PCM devices available\n"); + + if (num_mixers < MAX_MIXER_DEV) /* + * Don't install if there is another + * mixer + */ + mixer_devs[num_mixers++] = &gus_mixer_operations; + + return mem_start; +} + +static void +do_loop_irq (int voice) +{ + unsigned char tmp; + int mode, parm; + unsigned long flags; + + DISABLE_INTR (flags); + gus_select_voice (voice); + + tmp = gus_read8 (0x00); + tmp &= ~0x20; /* + * Disable wave IRQ for this_one voice + */ + gus_write8 (0x00, tmp); + + mode = voices[voice].loop_irq_mode; + voices[voice].loop_irq_mode = 0; + parm = voices[voice].loop_irq_parm; + + switch (mode) + { + + case LMODE_FINISH: /* + * Final loop finished, shoot volume down + */ + + if ((gus_read16 (0x09) >> 4) < 100) /* + * Get current volume + */ + { + gus_voice_off (); + gus_rampoff (); + gus_voice_init (voice); + break; + } + gus_ramp_range (65, 4065); + gus_ramp_rate (0, 63); /* + * Fastest possible rate + */ + gus_rampon (0x20 | 0x40); /* + * Ramp down, once, irq + */ + voices[voice].volume_irq_mode = VMODE_HALT; + break; + + case LMODE_PCM_STOP: + pcm_active = 0; /* + * Requires extensive processing + */ + case LMODE_PCM: + { + int orig_qlen = pcm_qlen; + + pcm_qlen--; + pcm_head = (pcm_head + 1) % pcm_nblk; + if (pcm_qlen) + { + play_next_pcm_block (); + } + else + { /* + * Out of data. Just stop the voice + */ + gus_voice_off (); + gus_rampoff (); + pcm_active = 0; + } + + if (orig_qlen == pcm_nblk) + { + DMAbuf_outputintr (gus_devnum, 0); + } + } + break; + + default:; + } + RESTORE_INTR (flags); +} + +static void +do_volume_irq (int voice) +{ + unsigned char tmp; + int mode, parm; + unsigned long flags; + + DISABLE_INTR (flags); + + gus_select_voice (voice); + + tmp = gus_read8 (0x0d); + tmp &= ~0x20; /* + * Disable volume ramp IRQ + */ + gus_write8 (0x0d, tmp); + + mode = voices[voice].volume_irq_mode; + voices[voice].volume_irq_mode = 0; + parm = voices[voice].volume_irq_parm; + + switch (mode) + { + case VMODE_HALT: /* + * Decay phase finished + */ + gus_voice_init (voice); + break; + + case VMODE_ENVELOPE: + gus_rampoff (); + step_envelope (voice); + break; + + case VMODE_START_NOTE: + guswave_start_note2 (voices[voice].dev_pending, voice, + voices[voice].note_pending, voices[voice].volume_pending); + if (voices[voice].kill_pending) + guswave_kill_note (voices[voice].dev_pending, voice, 0); + if (voices[voice].sample_pending >= 0) + { + guswave_set_instr (voices[voice].dev_pending, voice, + voices[voice].sample_pending); + voices[voice].sample_pending = -1; + } + break; + + default:; + } + + RESTORE_INTR (flags); +} + +void +gus_voice_irq (void) +{ + unsigned long wave_ignore = 0, volume_ignore = 0; + unsigned long voice_bit; + + unsigned char src, voice; + + while (1) + { + src = gus_read8 (0x0f); /* + * Get source info + */ + voice = src & 0x1f; + src &= 0xc0; + + if (src == (0x80 | 0x40)) + return; /* + * No interrupt + */ + + voice_bit = 1 << voice; + + if (!(src & 0x80)) /* + * Wave IRQ pending + */ + if (!(wave_ignore & voice_bit) && voice < nr_voices) /* + * Not done + * yet + */ + { + wave_ignore |= voice_bit; + do_loop_irq (voice); + } + + if (!(src & 0x40)) /* + * Volume IRQ pending + */ + if (!(volume_ignore & voice_bit) && voice < nr_voices) /* + * Not done + * yet + */ + { + volume_ignore |= voice_bit; + do_volume_irq (voice); + } + } +} + +void +guswave_dma_irq (void) +{ + unsigned char status; + + status = gus_look8 (0x41); /* + * Get DMA IRQ Status + */ + if (status & 0x40) /* + * DMA Irq pending + */ + switch (active_device) + { + case GUS_DEV_WAVE: + if (SOMEONE_WAITING (dram_sleeper, dram_sleep_flag)) + WAKE_UP (dram_sleeper, dram_sleep_flag); + break; + + case GUS_DEV_PCM_CONTINUE: + gus_transfer_output_block (pcm_current_dev, pcm_current_buf, + pcm_current_count, + pcm_current_intrflag, 1); + break; + + case GUS_DEV_PCM_DONE: + if (pcm_qlen < pcm_nblk) + { + DMAbuf_outputintr (gus_devnum, pcm_qlen == 0); + } + break; + + default:; + } + + status = gus_look8 (0x49); /* + * Get Sampling IRQ Status + */ + if (status & 0x40) /* + * Sampling Irq pending + */ + { + DMAbuf_inputintr (gus_devnum); + } + +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/midibuf.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/midibuf.c new file mode 100644 index 000000000..54b7266ad --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/midibuf.c @@ -0,0 +1,123 @@ +/* + * sound/midibuf.c + * + * Device file manager for /dev/midi + * + * NOTE! This part of the driver is currently just a stub. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_MPU401) + +#if 0 +#include "midiioctl.h" +#include "midivar.h" +#endif + +static int midibuf_busy = 0; + +int +MIDIbuf_open (int dev, struct fileinfo *file) +{ + int mode, err; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + if (midibuf_busy) + return RET_ERROR (EBUSY); + + if (!mpu401_dev) + { + printk ("Midi: MPU-401 compatible Midi interface not present\n"); + return RET_ERROR (ENXIO); + } + + if ((err = midi_devs[mpu401_dev]->open (mpu401_dev, mode, NULL, NULL)) < 0) + return err; + + midibuf_busy = 1; + + return RET_ERROR (ENXIO); +} + +void +MIDIbuf_release (int dev, struct fileinfo *file) +{ + int mode; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + midi_devs[mpu401_dev]->close (mpu401_dev); + midibuf_busy = 0; +} + +int +MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + + dev = dev >> 4; + + return count; +} + + +int +MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + dev = dev >> 4; + + return RET_ERROR (EIO); +} + +int +MIDIbuf_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg) +{ + dev = dev >> 4; + + switch (cmd) + { + + default: + return midi_devs[0]->ioctl (dev, cmd, arg); + } +} + +void +MIDIbuf_bytes_received (int dev, unsigned char *buf, int count) +{ +} + +long +MIDIbuf_init (long mem_start) +{ + return mem_start; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/mpu401.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/mpu401.c new file mode 100644 index 000000000..8be8fee57 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/mpu401.c @@ -0,0 +1,321 @@ +/* + * sound/mpu401.c + * + * The low level driver for Roland MPU-401 compatible Midi cards. + * + * This version supports just the DUMB UART mode. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#if !defined(EXCLUDE_MPU401) && !defined(EXCLUDE_MIDI) + +#define DATAPORT (mpu401_base) /* MPU-401 Data I/O Port on IBM */ +#define COMDPORT (mpu401_base+1) /* MPU-401 Command Port on IBM */ +#define STATPORT (mpu401_base+1) /* MPU-401 Status Port on IBM */ + +#define mpu401_status() INB(STATPORT) +#define input_avail() (!(mpu401_status()&INPUT_AVAIL)) +#define output_ready() (!(mpu401_status()&OUTPUT_READY)) +#define mpu401_cmd(cmd) OUTB(cmd, COMDPORT) +#define mpu401_read() INB(DATAPORT) +#define mpu401_write(byte) OUTB(byte, DATAPORT) + +#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */ +#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */ +#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */ +#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */ +#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */ + +static int mpu401_opened = 0; +static int mpu401_base = 0x330; +static int mpu401_irq; +static int mpu401_detected = 0; +static int my_dev; + +static int reset_mpu401 (void); +static void (*midi_input_intr) (int dev, unsigned char data); + +static void +mpu401_input_loop (void) +{ + int count; + + count = 10; + + while (count) /* Not timed out */ + if (input_avail ()) + { + unsigned char c = mpu401_read (); + + count = 100; + + if (mpu401_opened & OPEN_READ) + midi_input_intr (my_dev, c); + } + else + while (!input_avail () && count) + count--; +} + +void +mpuintr (int unit) +{ + if (input_avail ()) + mpu401_input_loop (); +} + +/* + * It looks like there is no input interrupts in the UART mode. Let's try + * polling. + */ + +static void +poll_mpu401 (unsigned long dummy) +{ + unsigned long flags; + + DEFINE_TIMER(mpu401_timer, poll_mpu401); + + if (!(mpu401_opened & OPEN_READ)) + return; /* No longer required */ + + DISABLE_INTR (flags); + + if (input_avail ()) + mpu401_input_loop (); + + ACTIVATE_TIMER(mpu401_timer, poll_mpu401, 1); /* Come back later */ + + RESTORE_INTR (flags); +} + +static int +mpu401_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + if (mpu401_opened) + { + printk ("MPU-401: Midi busy\n"); + return RET_ERROR (EBUSY); + } + + mpu401_input_loop (); + + midi_input_intr = input; + mpu401_opened = mode; + poll_mpu401 (0); /* Enable input polling */ + + return 0; +} + +static void +mpu401_close (int dev) +{ + mpu401_opened = 0; +} + +static int +mpu401_out (int dev, unsigned char midi_byte) +{ + int timeout; + unsigned long flags; + + /* + * Test for input since pending input seems to block the output. + */ + + DISABLE_INTR (flags); + + if (input_avail ()) + mpu401_input_loop (); + + RESTORE_INTR (flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */ + + if (!output_ready ()) + { + printk ("MPU-401: Timeout\n"); + return 0; + } + + mpu401_write (midi_byte); + return 1; +} + +static int +mpu401_command (int dev, unsigned char midi_byte) +{ + return 1; +} + +static int +mpu401_start_read (int dev) +{ + return 0; +} + +static int +mpu401_end_read (int dev) +{ + return 0; +} + +static int +mpu401_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EINVAL); +} + +static void +mpu401_kick (int dev) +{ +} + +static int +mpu401_buffer_status (int dev) +{ + return 0; /* No data in buffers */ +} + +static struct midi_operations mpu401_operations = +{ + {"MPU-401", 0, 0, SNDCARD_MPU401}, + mpu401_open, + mpu401_close, + mpu401_ioctl, + mpu401_out, + mpu401_start_read, + mpu401_end_read, + mpu401_kick, + mpu401_command, + mpu401_buffer_status +}; + + +long +attach_mpu401 (long mem_start, struct address_info *hw_config) +{ + int ok, timeout; + unsigned long flags; + + mpu401_base = hw_config->io_base; + mpu401_irq = hw_config->irq; + + if (!mpu401_detected) + return RET_ERROR (EIO); + + DISABLE_INTR (flags); + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + mpu401_cmd (UART_MODE_ON); + + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail ()) + if (mpu401_read () == MPU_ACK) + ok = 1; + + RESTORE_INTR (flags); + + printk (" "); + + my_dev = num_midis; + mpu401_dev = num_midis; + midi_devs[num_midis++] = &mpu401_operations; + return mem_start; +} + +static int +reset_mpu401 (void) +{ + unsigned long flags; + int ok, timeout, n; + + /* + * Send the RESET command. Try again if no success at the first time. + */ + + ok = 0; + + DISABLE_INTR (flags); + + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + mpu401_cmd (MPU_RESET); /* Send MPU-401 RESET Command */ + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail ()) + if (mpu401_read () == MPU_ACK) + ok = 1; + + } + + mpu401_opened = 0; + if (ok) + mpu401_input_loop (); /* Flush input before enabling interrupts */ + + RESTORE_INTR (flags); + + return ok; +} + + +int +probe_mpu401 (struct address_info *hw_config) +{ + int ok = 0; + + mpu401_base = hw_config->io_base; + mpu401_irq = hw_config->irq; + + if (snd_set_irq_handler (mpu401_irq, mpuintr) < 0) + return 0; + + ok = reset_mpu401 (); + + mpu401_detected = ok; + return ok; +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.c new file mode 100644 index 000000000..09e27654f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.c @@ -0,0 +1,943 @@ +/* + * sound/opl3.c + * + * A low level driver for Yamaha YM3812 and OPL-3 -chips + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* Major improvements to the FM handling 30AUG92 by Rob Hooft, */ +/* hooft@chem.ruu.nl */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_YM3812) + +#include "opl3.h" + +#define MAX_VOICE 18 +#define OFFS_4OP 11 /* Definitions for the operators OP3 and OP4 + * begin here */ + +static int opl3_enabled = 0; +static int left_address = 0x388, right_address = 0x388, both_address = 0; + +static int nr_voices = 9; +static int logical_voices[MAX_VOICE] = +{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17}; + +struct voice_info + { + unsigned char keyon_byte; + long bender; + long bender_range; + unsigned long orig_freq; + unsigned long current_freq; + int mode; + }; + +static struct voice_info voices[MAX_VOICE]; + +static struct sbi_instrument *instrmap; +static struct sbi_instrument *active_instrument[MAX_VOICE] = +{NULL}; + +static struct synth_info fm_info = +{"AdLib", 0, SYNTH_TYPE_FM, FM_TYPE_ADLIB, 0, 9, 0, SBFM_MAXINSTR, 0}; + +static int already_initialized = 0; + +static int opl3_ok = 0; +static int opl3_busy = 0; +static int fm_model = 0; /* 0=no fm, 1=mono, 2=SB Pro 1, 3=SB Pro 2 */ + +static int store_instr (int instr_no, struct sbi_instrument *instr); +static void freq_to_fnum (int freq, int *block, int *fnum); +static void opl3_command (int io_addr, unsigned int addr, unsigned int val); +static int opl3_kill_note (int dev, int voice, int velocity); +static unsigned char connection_mask = 0x00; + +void +enable_opl3_mode (int left, int right, int both) +{ + opl3_enabled = 1; + left_address = left; + right_address = right; + both_address = both; + fm_info.capabilities = SYNTH_CAP_OPL3; + fm_info.synth_subtype = FM_TYPE_OPL3; +} + +static void +enter_4op_mode (void) +{ + int i; + static int voices_4op[MAX_VOICE] = + {0, 1, 2, 9, 10, 11, 6, 7, 8, 15, 16, 17}; + + connection_mask = 0x3f; + opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x3f); /* Select all 4-OP + * voices */ + for (i = 0; i < 3; i++) + physical_voices[i].voice_mode = 4; + for (i = 3; i < 6; i++) + physical_voices[i].voice_mode = 0; + + for (i = 9; i < 12; i++) + physical_voices[i].voice_mode = 4; + for (i = 12; i < 15; i++) + physical_voices[i].voice_mode = 0; + + for (i = 0; i < 12; i++) + logical_voices[i] = voices_4op[i]; + nr_voices = 12; +} + +static int +opl3_ioctl (int dev, + unsigned int cmd, unsigned int arg) +{ + switch (cmd) + { + + case SNDCTL_FM_LOAD_INSTR: + { + struct sbi_instrument ins; + + IOCTL_FROM_USER ((char *) &ins, (char *) arg, 0, sizeof (ins)); + + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) + { + printk ("FM Error: Invalid instrument number %d\n", ins.channel); + return RET_ERROR (EINVAL); + } + + pmgr_inform (dev, PM_E_PATCH_LOADED, ins.channel, 0, 0, 0); + return store_instr (ins.channel, &ins); + } + break; + + case SNDCTL_SYNTH_INFO: + fm_info.nr_voices = (nr_voices == 12) ? 6 : nr_voices; + + IOCTL_TO_USER ((char *) arg, 0, &fm_info, sizeof (fm_info)); + return 0; + break; + + case SNDCTL_SYNTH_MEMAVL: + return 0x7fffffff; + break; + + case SNDCTL_FM_4OP_ENABLE: + if (opl3_enabled) + enter_4op_mode (); + return 0; + break; + + default: + return RET_ERROR (EINVAL); + } + +} + +int +opl3_detect (int ioaddr) +{ + /* + * This function returns 1 if the FM chicp is present at the given I/O port + * The detection algorithm plays with the timer built in the FM chip and + * looks for a change in the status register. + * + * Note! The timers of the FM chip are not connected to AdLib (and compatible) + * boards. + * + * Note2! The chip is initialized if detected. + */ + + unsigned char stat1, stat2; + int i; + + if (already_initialized) + { + return 0; /* Do avoid duplicate initializations */ + } + + if (opl3_enabled) + ioaddr = left_address; + + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM + * chicp */ + + stat1 = INB (ioaddr); /* Read status register */ + + if ((stat1 & 0xE0) != 0x00) + { + return 0; /* Should be 0x00 */ + } + + opl3_command (ioaddr, TIMER1_REGISTER, 0xff); /* Set timer 1 to 0xff */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, + TIMER2_MASK | TIMER1_START); /* Unmask and start timer 1 */ + + /* + * Now we have to delay at least 80 msec + */ + + for (i = 0; i < 50; i++) + tenmicrosec (); /* To be sure */ + + stat2 = INB (ioaddr); /* Read status after timers have expired */ + + /* Stop the timers */ + + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, TIMER1_MASK | TIMER2_MASK); /* Reset timers 1 and 2 */ + opl3_command (ioaddr, TIMER_CONTROL_REGISTER, IRQ_RESET); /* Reset the IRQ of FM + * chicp */ + + if ((stat2 & 0xE0) != 0xc0) + { + return 0; /* There is no YM3812 */ + } + + /* There is a FM chicp in this address. Now set some default values. */ + + for (i = 0; i < 9; i++) + opl3_command (ioaddr, KEYON_BLOCK + i, 0); /* Note off */ + + opl3_command (ioaddr, TEST_REGISTER, ENABLE_WAVE_SELECT); + opl3_command (ioaddr, PERCUSSION_REGISTER, 0x00); /* Melodic mode. */ + + return 1; +} + +static int +opl3_kill_note (int dev, int voice, int velocity) +{ + struct physical_voice_info *map; + + if (voice < 0 || voice >= nr_voices) + return 0; + + map = &physical_voices[logical_voices[voice]]; + + DEB (printk ("Kill note %d\n", voice)); + + if (map->voice_mode == 0) + return 0; + + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, voices[voice].keyon_byte & ~0x20); + + voices[voice].keyon_byte = 0; + voices[voice].bender = 0; + voices[voice].bender_range = 200; /* 200 cents = 2 semitones */ + voices[voice].orig_freq = 0; + voices[voice].current_freq = 0; + voices[voice].mode = 0; + + return 0; +} + +#define HIHAT 0 +#define CYMBAL 1 +#define TOMTOM 2 +#define SNARE 3 +#define BDRUM 4 +#define UNDEFINED TOMTOM +#define DEFAULT TOMTOM + +static int +store_instr (int instr_no, struct sbi_instrument *instr) +{ + + if (instr->key != FM_PATCH && (instr->key != OPL3_PATCH || !opl3_enabled)) + printk ("FM warning: Invalid patch format field (key) 0x%x\n", instr->key); + memcpy ((char *) &(instrmap[instr_no]), (char *) instr, sizeof (*instr)); + + return 0; +} + +static int +opl3_set_instr (int dev, int voice, int instr_no) +{ + if (voice < 0 || voice >= nr_voices) + return 0; + + if (instr_no < 0 || instr_no >= SBFM_MAXINSTR) + return 0; + + active_instrument[voice] = &instrmap[instr_no]; + return 0; +} + +/* + * The next table looks magical, but it certainly is not. Its values have + * been calculated as table[i]=8*log(i/64)/log(2) with an obvious exception + * for i=0. This log-table converts a linear volume-scaling (0..127) to a + * logarithmic scaling as present in the FM-synthesizer chips. so : Volume + * 64 = 0 db = relative volume 0 and: Volume 32 = -6 db = relative + * volume -8 it was implemented as a table because it is only 128 bytes and + * it saves a lot of log() calculations. (RH) + */ +char fm_volume_table[128] = +{-64, -48, -40, -35, -32, -29, -27, -26, /* 0 - 7 */ + -24, -23, -21, -20, -19, -18, -18, -17, /* 8 - 15 */ + -16, -15, -15, -14, -13, -13, -12, -12, /* 16 - 23 */ + -11, -11, -10, -10, -10, -9, -9, -8, /* 24 - 31 */ + -8, -8, -7, -7, -7, -6, -6, -6,/* 32 - 39 */ + -5, -5, -5, -5, -4, -4, -4, -4,/* 40 - 47 */ + -3, -3, -3, -3, -2, -2, -2, -2,/* 48 - 55 */ + -2, -1, -1, -1, -1, 0, 0, 0, /* 56 - 63 */ + 0, 0, 0, 1, 1, 1, 1, 1, /* 64 - 71 */ + 1, 2, 2, 2, 2, 2, 2, 2, /* 72 - 79 */ + 3, 3, 3, 3, 3, 3, 3, 4, /* 80 - 87 */ + 4, 4, 4, 4, 4, 4, 4, 5, /* 88 - 95 */ + 5, 5, 5, 5, 5, 5, 5, 5, /* 96 - 103 */ + 6, 6, 6, 6, 6, 6, 6, 6, /* 104 - 111 */ + 6, 7, 7, 7, 7, 7, 7, 7, /* 112 - 119 */ + 7, 7, 7, 8, 8, 8, 8, 8}; /* 120 - 127 */ + +static void +calc_vol (unsigned char *regbyte, int volume) +{ + int level = (~*regbyte & 0x3f); + + if (level) + level += fm_volume_table[volume]; + + if (level > 0x3f) + level = 0x3f; + if (level < 0) + level = 0; + + *regbyte = (*regbyte & 0xc0) | (~level & 0x3f); +} + +static void +set_voice_volume (int voice, int volume) +{ + unsigned char vol1, vol2, vol3, vol4; + struct sbi_instrument *instr; + struct physical_voice_info *map; + + if (voice < 0 || voice >= nr_voices) + return; + + map = &physical_voices[logical_voices[voice]]; + + instr = active_instrument[voice]; + + if (!instr) + instr = &instrmap[0]; + + if (instr->channel < 0) + return; + + if (voices[voice].mode == 0) + return; + + if (voices[voice].mode == 2) + { /* 2 OP voice */ + + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + + if ((instr->operators[10] & 0x01)) + { /* Additive synthesis */ + calc_vol (&vol1, volume); + calc_vol (&vol2, volume); + } + else + { /* FM synthesis */ + calc_vol (&vol2, volume); + } + + opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); /* Modulator volume */ + opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); /* Carrier volume */ + } + else + { /* 4 OP voice */ + int connection; + + vol1 = instr->operators[2]; + vol2 = instr->operators[3]; + vol3 = instr->operators[OFFS_4OP + 2]; + vol4 = instr->operators[OFFS_4OP + 3]; + + /* + * The connection method for 4 OP voices is defined by the rightmost + * bits at the offsets 10 and 10+OFFS_4OP + */ + + connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + + switch (connection) + { + case 0: + calc_vol (&vol4, volume); /* Just the OP 4 is carrier */ + break; + + case 1: + calc_vol (&vol2, volume); + calc_vol (&vol4, volume); + break; + + case 2: + calc_vol (&vol1, volume); + calc_vol (&vol4, volume); + break; + + case 3: + calc_vol (&vol1, volume); + calc_vol (&vol3, volume); + calc_vol (&vol4, volume); + break; + + default:/* Why ?? */ ; + } + + opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], vol1); + opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], vol2); + opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], vol3); + opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], vol4); + } +} + +static int +opl3_start_note (int dev, int voice, int note, int volume) +{ + unsigned char data, fpc; + int block, fnum, freq, voice_mode; + struct sbi_instrument *instr; + struct physical_voice_info *map; + + if (voice < 0 || voice >= nr_voices) + return 0; + + map = &physical_voices[logical_voices[voice]]; + + if (map->voice_mode == 0) + return 0; + + if (note == 255) /* Just change the volume */ + { + set_voice_volume (voice, volume); + return 0; + } + + /* Kill previous note before playing */ + opl3_command (map->ioaddr, KSL_LEVEL + map->op[1], 0xff); /* Carrier volume to min */ + opl3_command (map->ioaddr, KSL_LEVEL + map->op[0], 0xff); /* Modulator volume to */ + + if (map->voice_mode == 4) + { + opl3_command (map->ioaddr, KSL_LEVEL + map->op[2], 0xff); + opl3_command (map->ioaddr, KSL_LEVEL + map->op[3], 0xff); + } + + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, 0x00); /* Note off */ + + instr = active_instrument[voice]; + + if (!instr) + instr = &instrmap[0]; + + if (instr->channel < 0) + { + printk ( + "OPL3: Initializing voice %d with undefined instrument\n", + voice); + return 0; + } + + if (map->voice_mode == 2 && instr->key == OPL3_PATCH) + return 0; /* Cannot play */ + + voice_mode = map->voice_mode; + + if (voice_mode == 4) + { + int voice_shift; + + voice_shift = (map->ioaddr == left_address) ? 0 : 3; + voice_shift += map->voice_num; + + if (instr->key != OPL3_PATCH) /* Just 2 OP patch */ + { + voice_mode = 2; + connection_mask &= ~(1 << voice_shift); + } + else + { + connection_mask |= (1 << voice_shift); + } + + opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask); + } + + /* Set Sound Characteristics */ + opl3_command (map->ioaddr, AM_VIB + map->op[0], instr->operators[0]); + opl3_command (map->ioaddr, AM_VIB + map->op[1], instr->operators[1]); + + /* Set Attack/Decay */ + opl3_command (map->ioaddr, ATTACK_DECAY + map->op[0], instr->operators[4]); + opl3_command (map->ioaddr, ATTACK_DECAY + map->op[1], instr->operators[5]); + + /* Set Sustain/Release */ + opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[0], instr->operators[6]); + opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[1], instr->operators[7]); + + /* Set Wave Select */ + opl3_command (map->ioaddr, WAVE_SELECT + map->op[0], instr->operators[8]); + opl3_command (map->ioaddr, WAVE_SELECT + map->op[1], instr->operators[9]); + + /* Set Feedback/Connection */ + fpc = instr->operators[10]; + if (!(fpc & 0x30)) + fpc |= 0x30; /* Ensure that at least one chn is enabled */ + opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num, + fpc); + + /* + * If the voice is a 4 OP one, initialize the operators 3 and 4 also + */ + + if (voice_mode == 4) + { + + /* Set Sound Characteristics */ + opl3_command (map->ioaddr, AM_VIB + map->op[2], instr->operators[OFFS_4OP + 0]); + opl3_command (map->ioaddr, AM_VIB + map->op[3], instr->operators[OFFS_4OP + 1]); + + /* Set Attack/Decay */ + opl3_command (map->ioaddr, ATTACK_DECAY + map->op[2], instr->operators[OFFS_4OP + 4]); + opl3_command (map->ioaddr, ATTACK_DECAY + map->op[3], instr->operators[OFFS_4OP + 5]); + + /* Set Sustain/Release */ + opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[2], instr->operators[OFFS_4OP + 6]); + opl3_command (map->ioaddr, SUSTAIN_RELEASE + map->op[3], instr->operators[OFFS_4OP + 7]); + + /* Set Wave Select */ + opl3_command (map->ioaddr, WAVE_SELECT + map->op[2], instr->operators[OFFS_4OP + 8]); + opl3_command (map->ioaddr, WAVE_SELECT + map->op[3], instr->operators[OFFS_4OP + 9]); + + /* Set Feedback/Connection */ + fpc = instr->operators[OFFS_4OP + 10]; + if (!(fpc & 0x30)) + fpc |= 0x30; /* Ensure that at least one chn is enabled */ + opl3_command (map->ioaddr, FEEDBACK_CONNECTION + map->voice_num + 3, fpc); + } + + voices[voice].mode = voice_mode; + + set_voice_volume (voice, volume); + + freq = voices[voice].orig_freq = note_to_freq (note) / 1000; + + /* + * Since the pitch bender may have been set before playing the note, we + * have to calculate the bending now. + */ + + freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); + voices[voice].current_freq = freq; + + freq_to_fnum (freq, &block, &fnum); + + /* Play note */ + + data = fnum & 0xff; /* Least significant bits of fnumber */ + opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); + voices[voice].keyon_byte = data; + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); + if (voice_mode == 4) + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num + 3, data); + + return 0; +} + +static void +freq_to_fnum (int freq, int *block, int *fnum) +{ + int f, octave; + + /* Converts the note frequency to block and fnum values for the FM chip */ + /* First try to compute the block -value (octave) where the note belongs */ + + f = freq; + + octave = 5; + + if (f == 0) + octave = 0; + else if (f < 261) + { + while (f < 261) + { + octave--; + f <<= 1; + } + } + else if (f > 493) + { + while (f > 493) + { + octave++; + f >>= 1; + } + } + + if (octave > 7) + octave = 7; + + *fnum = freq * (1 << (20 - octave)) / 49716; + *block = octave; +} + +static void +opl3_command (int io_addr, unsigned int addr, unsigned int val) +{ + int i; + + /* + * The original 2-OP synth requires a quite long delay after writing to a + * register. The OPL-3 survives with just two INBs + */ + + OUTB ((unsigned char)(addr & 0xff), io_addr); /* Select register */ + + if (!opl3_enabled) + tenmicrosec (); + else + for (i = 0; i < 2; i++) + INB (io_addr); + + OUTB ((unsigned char)(val & 0xff), io_addr + 1); /* Write to register */ + + if (!opl3_enabled) + { + tenmicrosec (); + tenmicrosec (); + tenmicrosec (); + } + else + for (i = 0; i < 2; i++) + INB (io_addr); +} + +static void +opl3_reset (int dev) +{ + int i; + + for (i = 0; i < nr_voices; i++) + { + opl3_command (physical_voices[logical_voices[i]].ioaddr, + KSL_LEVEL + physical_voices[logical_voices[i]].op[0], 0xff); /* OP1 volume to min */ + + opl3_command (physical_voices[logical_voices[i]].ioaddr, + KSL_LEVEL + physical_voices[logical_voices[i]].op[1], 0xff); /* OP2 volume to min */ + + if (physical_voices[logical_voices[i]].voice_mode == 4) /* 4 OP voice */ + { + opl3_command (physical_voices[logical_voices[i]].ioaddr, + KSL_LEVEL + physical_voices[logical_voices[i]].op[2], 0xff); /* OP3 volume to min */ + + opl3_command (physical_voices[logical_voices[i]].ioaddr, + KSL_LEVEL + physical_voices[logical_voices[i]].op[3], 0xff); /* OP4 volume to min */ + } + + opl3_kill_note (dev, i, 64); + } + + if (opl3_enabled) + { + nr_voices = 18; + + for (i = 0; i < 18; i++) + logical_voices[i] = i; + + for (i = 0; i < 18; i++) + physical_voices[i].voice_mode = 2; + + } + +} + +static int +opl3_open (int dev, int mode) +{ + if (!opl3_ok) + return RET_ERROR (ENXIO); + if (opl3_busy) + return RET_ERROR (EBUSY); + opl3_busy = 1; + + connection_mask = 0x00; /* Just 2 OP voices */ + if (opl3_enabled) + opl3_command (right_address, CONNECTION_SELECT_REGISTER, connection_mask); + return 0; +} + +static void +opl3_close (int dev) +{ + opl3_busy = 0; + nr_voices = opl3_enabled ? 18 : 9; + fm_info.nr_drums = 0; + fm_info.perc_mode = 0; + + opl3_reset (dev); +} + +static void +opl3_hw_control (int dev, unsigned char *event) +{ +} + +static int +opl3_load_patch (int dev, int format, snd_rw_buf * addr, + int offs, int count, int pmgr_flag) +{ + struct sbi_instrument ins; + + if (count < sizeof (ins)) + { + printk ("FM Error: Patch record too short\n"); + return RET_ERROR (EINVAL); + } + + COPY_FROM_USER (&((char *) &ins)[offs], (char *) addr, offs, sizeof (ins) - offs); + + if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) + { + printk ("FM Error: Invalid instrument number %d\n", ins.channel); + return RET_ERROR (EINVAL); + } + ins.key = format; + + return store_instr (ins.channel, &ins); +} + +static void +opl3_panning (int dev, int voice, int pressure) +{ +} + +#define SET_VIBRATO(cell) { \ + tmp = instr->operators[(cell-1)+(((cell-1)/2)*OFFS_4OP)]; \ + if (pressure > 110) \ + tmp |= 0x40; /* Vibrato on */ \ + opl3_command (map->ioaddr, AM_VIB + map->op[cell-1], tmp);} + +static void +opl3_aftertouch (int dev, int voice, int pressure) +{ + int tmp; + struct sbi_instrument *instr; + struct physical_voice_info *map; + + if (voice < 0 || voice >= nr_voices) + return; + + map = &physical_voices[logical_voices[voice]]; + + DEB (printk ("Aftertouch %d\n", voice)); + + if (map->voice_mode == 0) + return; + + /* + * Adjust the amount of vibrato depending the pressure + */ + + instr = active_instrument[voice]; + + if (!instr) + instr = &instrmap[0]; + + if (voices[voice].mode == 4) + { + int connection = ((instr->operators[10] & 0x01) << 1) | (instr->operators[10 + OFFS_4OP] & 0x01); + + switch (connection) + { + case 0: + SET_VIBRATO (4); + break; + + case 1: + SET_VIBRATO (2); + SET_VIBRATO (4); + break; + + case 2: + SET_VIBRATO (1); + SET_VIBRATO (4); + break; + + case 3: + SET_VIBRATO (1); + SET_VIBRATO (3); + SET_VIBRATO (4); + break; + + } + /* Not implemented yet */ + } + else + { + SET_VIBRATO (1); + + if ((instr->operators[10] & 0x01)) /* Additive synthesis */ + SET_VIBRATO (2); + } +} + +#undef SET_VIBRATO + +static void +opl3_controller (int dev, int voice, int ctrl_num, int value) +{ + unsigned char data; + int block, fnum, freq; + struct physical_voice_info *map; + + if (voice < 0 || voice >= nr_voices) + return; + + map = &physical_voices[logical_voices[voice]]; + + if (map->voice_mode == 0) + return; + + switch (ctrl_num) + { + case CTRL_PITCH_BENDER: + voices[voice].bender = value; + if (!value) + return; + if (!(voices[voice].keyon_byte & 0x20)) + return; /* Not keyed on */ + + freq = compute_finetune (voices[voice].orig_freq, voices[voice].bender, voices[voice].bender_range); + voices[voice].current_freq = freq; + + freq_to_fnum (freq, &block, &fnum); + + data = fnum & 0xff; /* Least significant bits of fnumber */ + opl3_command (map->ioaddr, FNUM_LOW + map->voice_num, data); + + data = 0x20 | ((block & 0x7) << 2) | ((fnum >> 8) & 0x3); /* KEYON|OCTAVE|MS bits + * of f-num */ + voices[voice].keyon_byte = data; + opl3_command (map->ioaddr, KEYON_BLOCK + map->voice_num, data); + break; + + case CTRL_PITCH_BENDER_RANGE: + voices[voice].bender_range = value; + break; + } +} + +static int +opl3_patchmgr (int dev, struct patmgr_info *rec) +{ + return RET_ERROR (EINVAL); +} + +static struct synth_operations opl3_operations = +{ + &fm_info, + SYNTH_TYPE_FM, + FM_TYPE_ADLIB, + opl3_open, + opl3_close, + opl3_ioctl, + opl3_kill_note, + opl3_start_note, + opl3_set_instr, + opl3_reset, + opl3_hw_control, + opl3_load_patch, + opl3_aftertouch, + opl3_controller, + opl3_panning, + opl3_patchmgr +}; + +long +opl3_init (long mem_start) +{ + int i; + + PERMANENT_MALLOC(struct sbi_instrument*, instrmap, + SBFM_MAXINSTR*sizeof(*instrmap), mem_start); + + synth_devs[num_synths++] = &opl3_operations; + fm_model = 0; + opl3_ok = 1; + if (opl3_enabled) + { + printk (" "); + fm_model = 2; + nr_voices = 18; + fm_info.nr_drums = 0; + fm_info.capabilities |= SYNTH_CAP_OPL3; +#ifndef SCO + strcpy (fm_info.name, "Yamaha OPL-3"); +#endif + + for (i = 0; i < 18; i++) + if (physical_voices[i].ioaddr == USE_LEFT) + physical_voices[i].ioaddr = left_address; + else + physical_voices[i].ioaddr = right_address; + + + opl3_command (right_address, OPL3_MODE_REGISTER, OPL3_ENABLE); /* Enable OPL-3 mode */ + opl3_command (right_address, CONNECTION_SELECT_REGISTER, 0x00); /* Select all 2-OP + * voices */ + } + else + { + printk (" "); + fm_model = 1; + nr_voices = 9; + fm_info.nr_drums = 0; + + for (i = 0; i < 18; i++) + physical_voices[i].ioaddr = left_address; + }; + + already_initialized = 1; + for (i = 0; i < SBFM_MAXINSTR; i++) + instrmap[i].channel = -1; + + return mem_start; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.h new file mode 100644 index 000000000..ea7901fc6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/opl3.h @@ -0,0 +1,260 @@ +/* + * opl3.h - Definitions of the OPL-3 registers + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * The OPL-3 mode is switched on by writing 0x01, to the offset 5 + * of the right side. + * + * Another special register at the right side is at offset 4. It contains + * a bit mask defining which voices are used as 4 OP voices. + * + * The percussive mode is implemented in the left side only. + * + * With the above exeptions the both sides can be operated independently. + * + * A 4 OP voice can be created by setting the corresponding + * bit at offset 4 of the right side. + * + * For example setting the rightmost bit (0x01) changes the + * first voice on the right side to the 4 OP mode. The fourth + * voice is made inaccessible. + * + * If a voice is set to the 2 OP mode, it works like 2 OP modes + * of the original YM3812 (AdLib). In addition the voice can + * be connected the left, right or both stereo channels. It can + * even be left unconnected. This works with 4 OP voices also. + * + * The stereo connection bits are located in the FEEDBACK_CONNECTION + * register of the voice (0xC0-0xC8). In 4 OP voices these bits are + * in the second half of the voice. + */ + +/* + * Register numbers for the global registers + */ + +#define TEST_REGISTER 0x01 +#define ENABLE_WAVE_SELECT 0x20 + +#define TIMER1_REGISTER 0x02 +#define TIMER2_REGISTER 0x03 +#define TIMER_CONTROL_REGISTER 0x04 /* Left side */ +#define IRQ_RESET 0x80 +#define TIMER1_MASK 0x40 +#define TIMER2_MASK 0x20 +#define TIMER1_START 0x01 +#define TIMER2_START 0x02 + +#define CONNECTION_SELECT_REGISTER 0x04 /* Right side */ +#define RIGHT_4OP_0 0x01 +#define RIGHT_4OP_1 0x02 +#define RIGHT_4OP_2 0x04 +#define LEFT_4OP_0 0x08 +#define LEFT_4OP_1 0x10 +#define LEFT_4OP_2 0x20 + +#define OPL3_MODE_REGISTER 0x05 /* Right side */ +#define OPL3_ENABLE 0x01 + +#define KBD_SPLIT_REGISTER 0x08 /* Left side */ +#define COMPOSITE_SINE_WAVE_MODE 0x80 /* Don't use with OPL-3? */ +#define KEYBOARD_SPLIT 0x40 + +#define PERCUSSION_REGISTER 0xbd /* Left side only */ +#define TREMOLO_DEPTH 0x80 +#define VIBRATO_DEPTH 0x40 +#define PERCUSSION_ENABLE 0x20 +#define BASSDRUM_ON 0x10 +#define SNAREDRUM_ON 0x08 +#define TOMTOM_ON 0x04 +#define CYMBAL_ON 0x02 +#define HIHAT_ON 0x01 + +/* + * Offsets to the register banks for operators. To get the + * register number just add the operator offset to the bank offset + * + * AM/VIB/EG/KSR/Multiple (0x20 to 0x35) + */ + #define AM_VIB 0x20 + #define TREMOLO_ON 0x80 + #define VIBRATO_ON 0x40 + #define SUSTAIN_ON 0x20 + #define KSR 0x10 /* Key scaling rate */ + #define MULTIPLE_MASK 0x0f /* Frequency multiplier */ + + /* + * KSL/Total level (0x40 to 0x55) + */ +#define KSL_LEVEL 0x40 +#define KSL_MASK 0xc0 /* Envelope scaling bits */ +#define TOTAL_LEVEL_MASK 0x3f /* Strength (volume) of OP */ + +/* + * Attack / Decay rate (0x60 to 0x75) + */ +#define ATTACK_DECAY 0x60 +#define ATTACK_MASK 0xf0 +#define DECAY_MASK 0x0f + +/* + * Sustain level / Release rate (0x80 to 0x95) + */ +#define SUSTAIN_RELEASE 0x80 +#define SUSTAIN_MASK 0xf0 +#define RELEASE_MASK 0x0f + +/* + * Wave select (0xE0 to 0xF5) + */ +#define WAVE_SELECT 0xe0 + +/* + * Offsets to the register banks for voices. Just add to the + * voice number to get the register number. + * + * F-Number low bits (0xA0 to 0xA8). + */ +#define FNUM_LOW 0xa0 + +/* + * F-number high bits / Key on / Block (octave) (0xB0 to 0xB8) + */ +#define KEYON_BLOCK 0xb0 +#define KEYON_BIT 0x20 +#define BLOCKNUM_MASK 0x1c +#define FNUM_HIGH_MASK 0x03 + +/* + * Feedback / Connection (0xc0 to 0xc8) + * + * These registers have two new bits when the OPL-3 mode + * is selected. These bits controls connecting the voice + * to the stereo channels. For 4 OP voices this bit is + * defined in the second half of the voice (add 3 to the + * register offset). + * + * For 4 OP voices the connection bit is used in the + * both halfs (gives 4 ways to connect the operators). + */ +#define FEEDBACK_CONNECTION 0xc0 +#define FEEDBACK_MASK 0x0e /* Valid just for 1st OP of a voice */ +#define CONNECTION_BIT 0x01 +/* + * In the 4 OP mode there is four possible configurations how the + * operators can be connected together (in 2 OP modes there is just + * AM or FM). The 4 OP connection mode is defined by the rightmost + * bit of the FEEDBACK_CONNECTION (0xC0-0xC8) on the both halfs. + * + * First half Second half Mode + * + * +---+ + * v | + * 0 0 >+-1-+--2--3--4--> + * + * + * + * +---+ + * | | + * 0 1 >+-1-+--2-+ + * |-> + * >--3----4-+ + * + * +---+ + * | | + * 1 0 >+-1-+-----+ + * |-> + * >--2--3--4-+ + * + * +---+ + * | | + * 1 1 >+-1-+--+ + * | + * >--2--3-+-> + * | + * >--4----+ + */ +#define STEREO_BITS 0x30 /* OPL-3 only */ +#define VOICE_TO_LEFT 0x10 +#define VOICE_TO_RIGHT 0x20 + +/* + * Definition table for the physical voices + */ + +struct physical_voice_info { + unsigned char voice_num; + unsigned char voice_mode; /* 0=unavailable, 2=2 OP, 4=4 OP */ + unsigned short ioaddr; /* I/O port (left or right side) */ + unsigned char op[4]; /* Operator offsets */ + }; + +/* + * There is 18 possible 2 OP voices + * (9 in the left and 9 in the right). + * The first OP is the modulator and 2nd is the carrier. + * + * The first three voices in the both sides may be connected + * with another voice to a 4 OP voice. For example voice 0 + * can be connected with voice 3. The operators of voice 3 are + * used as operators 3 and 4 of the new 4 OP voice. + * In this case the 2 OP voice number 0 is the 'first half' and + * voice 3 is the second. + */ + +#define USE_LEFT 0 +#define USE_RIGHT 1 + +static struct physical_voice_info physical_voices[18] = +{ +/* No Mode Side OP1 OP2 OP3 OP4 */ +/* --------------------------------------------------- */ + { 0, 2, USE_LEFT, {0x00, 0x03, 0x08, 0x0b}}, + { 1, 2, USE_LEFT, {0x01, 0x04, 0x09, 0x0c}}, + { 2, 2, USE_LEFT, {0x02, 0x05, 0x0a, 0x0d}}, + + { 3, 2, USE_LEFT, {0x08, 0x0b, 0x00, 0x00}}, + { 4, 2, USE_LEFT, {0x09, 0x0c, 0x00, 0x00}}, + { 5, 2, USE_LEFT, {0x0a, 0x0d, 0x00, 0x00}}, + + { 6, 2, USE_LEFT, {0x10, 0x13, 0x00, 0x00}}, /* Used by percussive voices */ + { 7, 2, USE_LEFT, {0x11, 0x14, 0x00, 0x00}}, /* if the percussive mode */ + { 8, 2, USE_LEFT, {0x12, 0x15, 0x00, 0x00}}, /* is selected */ + + { 0, 2, USE_RIGHT, {0x00, 0x03, 0x08, 0x0b}}, + { 1, 2, USE_RIGHT, {0x01, 0x04, 0x09, 0x0c}}, + { 2, 2, USE_RIGHT, {0x02, 0x05, 0x0a, 0x0d}}, + + { 3, 2, USE_RIGHT, {0x08, 0x0b, 0x00, 0x00}}, + { 4, 2, USE_RIGHT, {0x09, 0x0c, 0x00, 0x00}}, + { 5, 2, USE_RIGHT, {0x0a, 0x0d, 0x00, 0x00}}, + + { 6, 2, USE_RIGHT, {0x10, 0x13, 0x00, 0x00}}, + { 7, 2, USE_RIGHT, {0x11, 0x14, 0x00, 0x00}}, + { 8, 2, USE_RIGHT, {0x12, 0x15, 0x00, 0x00}} +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/os.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/os.h new file mode 100644 index 000000000..bff4a4338 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/os.h @@ -0,0 +1,154 @@ +/* + * OS Specific settings for Linux + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define ALLOW_SELECT + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +typedef char snd_rw_buf; + +#define FALSE 0 +#define TRUE 1 + +#define COPY_FROM_USER(d, s, o, c) memcpy_fromfs((d), &((s)[o]), (c)) +#define COPY_TO_USER(d, o, s, c) memcpy_tofs(&((d)[o]), (s), (c)) +#define IOCTL_FROM_USER(d, s, o, c) memcpy_fromfs((d), &((s)[o]), (c)) +#define IOCTL_TO_USER(d, o, s, c) memcpy_tofs(&((d)[o]), (s), (c)) + +#define GET_BYTE_FROM_USER(target, addr, offs) target = get_fs_byte(&((addr)[offs])) +#define GET_SHORT_FROM_USER(target, addr, offs) target = get_fs_word(&((addr)[offs])) +#define GET_WORD_FROM_USER(target, addr, offs) target = get_fs_long((long*)&((addr)[offs])) +#define PUT_WORD_TO_USER(addr, offs, data) put_fs_long(data, (long*)&((addr)[offs])) +#define IOCTL_IN(arg) get_fs_long((long *)(arg)) +#define IOCTL_OUT(arg, ret) snd_ioctl_return((int *)arg, ret) + +struct snd_wait { + int mode; int aborting; + }; + +#define DEFINE_WAIT_QUEUE(name, flag) static struct wait_queue *name = NULL; \ + static volatile struct snd_wait flag = {0} +#define DEFINE_WAIT_QUEUES(name, flag) static struct wait_queue *name = {NULL}; \ + static volatile struct snd_wait flag = {{0}} +#define RESET_WAIT_QUEUE(q, f) {f.aborting = 0;f.mode = WK_NONE;} +#define PROCESS_ABORTING(q, f) (f.aborting | (current->signal & ~current->blocked)) +#define SET_ABORT_FLAG(q, f) f.aborting = 1 +#define TIMED_OUT(q, f) (f.mode & WK_TIMEOUT) +#define DO_SLEEP(q, f, time_limit) \ + { unsigned long tl;\ + if (time_limit) tl = current->timeout = jiffies + (time_limit); \ + else tl = 0xffffffff; \ + f.mode = WK_SLEEP;interruptible_sleep_on(&q); \ + if (!(f.mode & WK_WAKEUP)) \ + { \ + if (current->signal & ~current->blocked) \ + f.aborting = 1; \ + else \ + if (jiffies >= tl) f.mode |= WK_TIMEOUT; \ + } \ + f.mode &= ~WK_SLEEP; \ + } +#define SOMEONE_WAITING(q, f) (f.mode & WK_SLEEP) +#define WAKE_UP(q, f) {f.mode = WK_WAKEUP;wake_up(&q);} + +#define ALLOC_DMA_CHN(chn) request_dma(chn) +#define RELEASE_DMA_CHN(chn) free_dma(chn) + +#define GET_TIME() jiffies +#define RELEASE_IRQ free_irq +#define RET_ERROR(err) -err + +/* DISABLE_INTR is used to disable interrupts. + These macros store the current flags to the (unsigned long) variable given + as a parameter. RESTORE_INTR returns the interrupt ebable bit to state + before DISABLE_INTR or ENABLE_INTR */ + +#define DISABLE_INTR(flags) __asm__ __volatile__("pushfl ; popl %0 ; cli":"=r" (flags)); +#define RESTORE_INTR(flags) __asm__ __volatile__("pushl %0 ; popfl": \ + :"r" (flags)); +/* + KERNEL_MALLOC() allocates requested number of memory and + KERNEL_FREE is used to free it. + These macros are never called from interrupt, in addition the + nbytes will never be more than 4096 bytes. Generally the driver + will allocate memory in blocks of 4k. If the kernel has just a + page level memory allocation, 4K can be safely used as the size + (the nbytes parameter can be ignored). +*/ +#define KERNEL_MALLOC(nbytes) kmalloc(nbytes, GFP_KERNEL) +#define KERNEL_FREE(addr) kfree(addr) + +/* + * The macro PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) + * returns size bytes of + * (kernel virtual) memory which will never get freed by the driver. + * This macro is called only during boot. The linux_ptr is a linux specific + * parameter which should be ignored in other operating systems. + * The mem_ptr is a pointer variable where the macro assigns pointer to the + * memory area. The type is the type of the mem_ptr. + */ +#define PERMANENT_MALLOC(typecast, mem_ptr, size, linux_ptr) \ + {mem_ptr = (typecast)linux_ptr; \ + linux_ptr += (size);} + +/* + * The macro DEFINE_TIMER defines variables for the ACTIVATE_TIMER if + * required. The name is the variable/name to be used and the proc is + * the procedure to be called when the timer expires. + */ + +#define DEFINE_TIMER(name, proc) \ + static struct timer_list name = \ + {NULL, 0, 0, proc} + +/* + * The ACTIVATE_TIMER requests system to call 'proc' after 'time' ticks. + */ + +#define ACTIVATE_TIMER(name, proc, time) \ + {name.expires = time; \ + add_timer (&name);} + +#define INB inb +#define OUTB outb diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas.h new file mode 100644 index 000000000..797c8fdbc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas.h @@ -0,0 +1,250 @@ +/* */ +/* Port addresses and bit fields for the Media Vision Pro AudioSpectrum second generation sound cards. */ +/* */ +/* Feel free to use this header file in any application you create that has support for the Media Vision */ +/* Pro AudioSpectrum second generation sound cards. Other uses prohibited without prior permission. */ +/* */ +/* - cmetz@thor.tjhsst.edu */ +/* */ +/* Notes: */ +/* */ +/* * All of these ports go into the MVD101 multimedia controller chip, which then signals the other chips to do */ +/* the actual work. Many ports like the FM ones functionally attach directly to the destination chip though */ +/* they don't actually have a direct connection. */ +/* */ +/* * The PAS2 series cards have an MVD101 multimedia controller chip, the original PAS cards don't. The original */ +/* PAS cards are pretty defunct now, so no attempt is made here to support them. */ +/* */ +/* * The PAS2 series cards are all really different at the hardware level, though the MVD101 hides some of the */ +/* incompatibilities, there still are differences that need to be accounted for. */ +/* */ +/* Card CD-ROM interface PCM chip Mixer chip FM chip */ +/* PAS Plus Sony proprietary (Crystal?) 8-bit DAC National OPL3 */ +/* PAS 16 Zilog SCSI MVA416 16-bit Codec MVA508 OPL3 */ +/* CDPC Sony proprietary Sony 16-bit Codec National OPL3 */ +/* Fusion CD 16 Sony proprietary MVA416 16-bit Codec MVA508 OPL3 */ +/* Fusion CD Sony proprietary (Crystal?) 8-bit DAC National OPL3 */ +/* */ +#define PAS_DEFAULT_BASE 0x388 + +/* Symbolic Name Value R W Subsystem Description */ +#define SPEAKER_CONTROL 0x61 /* W PC speaker Control register */ +#define SPEAKER_CONTROL_GHOST 0x738B /* R W PC speaker Control ghost register */ +#define SPEAKER_TIMER_CONTROL 0x43 /* W PC speaker Timer control register */ +#define SPEAKER_TIMER_CONTROL_GHOST 0x778B /* R W PC speaker Timer control register ghost */ +#define SPEAKER_TIMER_DATA 0x42 /* W PC speaker Timer data register */ +#define SPEAKER_TIMER_DATA_GHOST 0x138A /* R W PC speaker Timer data register ghost */ + +#define WARM_BOOT 0x41 /* W Control Used to detect system warm boot */ +#define WARM_BOOT_GHOST 0x7789 /* ? W Control Use to get the card to fake warm boot */ +#define MASTER_DECODE 0x9A01 /* W Control Address >> 2 of card base address */ +#define PRESCALE_DIVIDER 0xBF8A /* R W PCM Ration between Codec clock and master clock */ +#define WAIT_STATE 0xBF88 /* R W Control Four-bit bus wait-state count (~140ns ea.) */ +#define BOARD_REV_ID 0x2789 /* R Control Extended Board Revision ID */ + +#define SYSTEM_CONFIGURATION_1 0x8388 /* R W Control */ + #define S_C_1_PCS_ENABLE 0x01 /* R W PC speaker 1=enable, 0=disable PC speaker emulation */ + #define S_C_1_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=14.31818Mhz/12, 0=28.224Mhz master clock */ + #define S_C_1_FM_EMULATE_CLOCK 0x04 /* R W FM 1=use 28.224Mhz/2, 0=use 14.31818Mhz clock */ + #define S_C_1_PCS_STEREO 0x10 /* R W PC speaker 1=enable PC speaker stereo effect, 0=disable */ + #define S_C_1_PCS_REALSOUND 0x20 /* R W PC speaker 1=enable RealSound enhancement, 0=disable */ + #define S_C_1_FORCE_EXT_RESET 0x40 /* R W Control Force external reset */ + #define S_C_1_FORCE_INT_RESET 0x80 /* R W Control Force internal reset */ +#define SYSTEM_CONFIGURATION_2 0x8389 /* R W Control */ + #define S_C_2_PCM_OVERSAMPLING 0x03 /* R W PCM 00=0x, 01=2x, 10=4x, 11=reserved */ + #define S_C_2_PCM_16_BIT 0x04 /* R W PCM 1=16-bit, 0=8-bit samples */ +#define SYSTEM_CONFIGURATION_3 0x838A /* R W Control */ + #define S_C_3_PCM_CLOCK_SELECT 0x02 /* R W PCM 1=use 1.008Mhz clock for PCM, 0=don't */ +#define SYSTEM_CONFIGURATION_4 0x838B /* R W Control CD-ROM interface controls */ + +#define IO_CONFIGURATION_1 0xF388 /* R W Control */ + #define I_C_1_BOOT_RESET_ENABLE 0x80 /* R W Control 1=reset board on warm boot, 0=don't */ +#define IO_CONFIGURATION_2 0xF389 /* R W Control */ + #define I_C_2_PCM_DMA_DISABLED 0x00 /* R W PCM PCM DMA disabled */ +#define IO_CONFIGURATION_3 0xF38A /* R W Control */ + #define I_C_3_PCM_IRQ_DISABLED 0x00 /* R W PCM PCM IRQ disabled */ + +#define COMPATIBILITY_ENABLE 0xF788 /* R W Control */ + #define C_E_MPU401_ENABLE 0x01 /* R W MIDI 1=enable, 0=disable MPU401 MIDI emulation */ + #define C_E_SB_ENABLE 0x02 /* R W PCM 1=enable, 0=disable Sound Blaster emulation */ + #define C_E_SB_ACTIVE 0x04 /* R PCM "Sound Blaster Interrupt active" */ + #define C_E_MPU401_ACTIVE 0x08 /* R MIDI "MPU UART mode active" */ + #define C_E_PCM_COMPRESSION 0x10 /* R W PCM 1=enable, 0=disabled compression */ +#define EMULATION_ADDRESS 0xF789 /* R W Control */ + #define E_A_SB_BASE 0x0f /* R W PCM bits A4-A7 for SB base port */ + #define E_A_MPU401_BASE 0xf0 /* R W MIDI bits A4-A7 for MPU401 base port */ +#define EMULATION_CONFIGURATION 0xFB8A /* R W ***** Only valid on newer PAS2 cards (?) ***** */ + #define E_C_MPU401_IRQ 0x07 /* R W MIDI MPU401 emulation IRQ */ + #define E_C_SB_IRQ 0x38 /* R W PCM SB emulation IRQ */ + #define E_C_SB_DMA 0xC0 /* R W PCM SB emulation DMA */ + +#define OPERATION_MODE_1 0xEF8B /* R Control */ + #define O_M_1_CDROM_TYPE 0x03 /* R CD-ROM 3=SCSI, 2=Sony, 0=no CD-ROM interface */ + #define O_M_1_FM_TYPE 0x04 /* R FM 1=sterero, 0=mono FM chip */ + #define O_M_1_PCM_TYPE 0x08 /* R PCM 1=16-bit Codec, 0=8-bit DAC */ +#define OPERATION_MODE_2 0xFF8B /* R Control */ + #define O_M_2_PCS_ENABLED 0x02 /* R PC speaker PC speaker emulation 1=enabled, 0=disabled */ + #define O_M_2_BUS_TIMING 0x10 /* R Control 1=AT bus timing, 0=XT bus timing */ + #define O_M_2_BOARD_REVISION 0xe0 /* R Control Board revision */ + +#define INTERRUPT_MASK 0x0B8B /* R W Control */ + #define I_M_FM_LEFT_IRQ_ENABLE 0x01 /* R W FM Enable FM left interrupt */ + #define I_M_FM_RIGHT_IRQ_ENABLE 0x02 /* R W FM Enable FM right interrupt */ + #define I_M_PCM_RATE_IRQ_ENABLE 0x04 /* R W PCM Enable Sample Rate interrupt */ + #define I_M_PCM_BUFFER_IRQ_ENABLE 0x08 /* R W PCM Enable Sample Buffer interrupt */ + #define I_M_MIDI_IRQ_ENABLE 0x10 /* R W MIDI Enable MIDI interrupt */ + #define I_M_BOARD_REV 0xE0 /* R Control Board revision */ + +#define INTERRUPT_STATUS 0x0B89 /* R W Control */ + #define I_S_FM_LEFT_IRQ 0x01 /* R W FM Left FM Interrupt Pending */ + #define I_S_FM_RIGHT_IRQ 0x02 /* R W FM Right FM Interrupt Pending */ + #define I_S_PCM_SAMPLE_RATE_IRQ 0x04 /* R W PCM Sample Rate Interrupt Pending */ + #define I_S_PCM_SAMPLE_BUFFER_IRQ 0x08 /* R W PCM Sample Buffer Interrupt Pending */ + #define I_S_MIDI_IRQ 0x10 /* R W MIDI MIDI Interrupt Pending */ + #define I_S_PCM_CHANNEL 0x20 /* R W PCM 1=right, 0=left */ + #define I_S_RESET_ACTIVE 0x40 /* R W Control Reset is active (Timed pulse not finished) */ + #define I_S_PCM_CLIPPING 0x80 /* R W PCM Clipping has occurred */ + +#define FILTER_FREQUENCY 0x0B8A /* R W Control */ + #define F_F_FILTER_DISABLED 0x00 /* R W Mixer No filter */ +#if 0 + struct { /* R W Mixer Filter translation */ + unsigned int freq:24; + unsigned int value:8; + } F_F_FILTER_translate[] = + { { 73500, 0x01 }, /* 73500Hz - divide by 16 */ + { 65333, 0x02 }, /* 65333Hz - divide by 18 */ + { 49000, 0x09 }, /* 49000Hz - divide by 24 */ + { 36750, 0x11 }, /* 36750Hz - divide by 32 */ + { 24500, 0x19 }, /* 24500Hz - divide by 48 */ + { 18375, 0x07 }, /* 18375Hz - divide by 64 */ + { 12783, 0x0f }, /* 12783Hz - divide by 92 */ + { 12250, 0x04 }, /* 12250Hz - divide by 96 */ + { 9188, 0x17 }, /* 9188Hz - divide by 128 */ + { 6125, 0x1f }, /* 6125Hz - divide by 192 */ + }; +#endif + #define F_F_MIXER_UNMUTE 0x20 /* R W Mixer 1=disable, 0=enable board mute */ + #define F_F_PCM_RATE_COUNTER 0x40 /* R W PCM 1=enable, 0=disable sample rate counter */ + #define F_F_PCM_BUFFER_COUNTER 0x80 /* R W PCM 1=enable, 0=disable sample buffer counter */ + +#define PAS_NONE 0 +#define PAS_PLUS 1 +#define PAS_CDPC 2 +#define PAS_16 3 +#define PAS_16D 4 + +#ifdef DEFINE_TRANSLATIONS + char I_C_2_PCM_DMA_translate[] = /* R W PCM PCM DMA channel value translations */ + { 4, 1, 2, 3, 0, 5, 6, 7 }; + char I_C_3_PCM_IRQ_translate[] = /* R W PCM PCM IRQ level value translation */ + { 0, 0, 1, 2, 3, 4, 5, 6, 0, 0, 7, 8, 9, 0, 10, 11 }; + char E_C_MPU401_IRQ_translate[] = /* R W MIDI MPU401 emulation IRQ value translation */ + { 0x00, 0x00, 0x01, 0x02, 0x00, 0x03, 0x00, 0x04, 0x00, 0x00, 0x05, 0x06, 0x07 }; + char E_C_SB_IRQ_translate[] = /* R W PCM SB emulation IRQ translate */ + { 0x00, 0x00, 0x08, 0x10, 0x00, 0x18, 0x00, 0x20, 0x00, 0x00, 0x28, 0x30, 0x38, 0, 0 }; + char E_C_SB_DMA_translate[] = /* R W PCM SB emulation DMA translate */ + { 0x00, 0x40, 0x80, 0xC0, 0, 0, 0, 0 }; + char O_M_1_to_card[] = /* R W Control Translate (OM1 & 0x0f) to card type */ + { 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 4, 0, 2, 3 }; +#else + extern char I_C_2_PCM_DMA_translate[]; /* R W PCM PCM DMA channel value translations */ + extern char I_C_3_PCM_IRQ_translate[]; /* R W PCM PCM IRQ level value translation */ + extern char E_C_MPU401_IRQ_translate[]; /* R W MIDI MPU401 emulation IRQ value translation */ + extern char E_C_SB_IRQ_translate[]; /* R W PCM SB emulation IRQ translate */ + extern char E_C_SB_DMA_translate[]; /* R W PCM SB emulation DMA translate */ + extern char O_M_1_to_card[]; /* R W Control Translate (OM1 & 0x0f) to card type */ +#endif + +#define PARALLEL_MIXER 0x078B /* W Mixer Documented for MVD101 as FM Mono Right decode?? */ + #define P_M_MV508_ADDRESS 0x80 /* W Mixer MVD508 Address/mixer select */ + #define P_M_MV508_DATA 0x00 + #define P_M_MV508_LEFT 0x20 /* W Mixer MVD508 Left channel select */ + #define P_M_MV508_RIGHT 0x40 /* W Mixer MVD508 Right channel select */ + #define P_M_MV508_BOTH 0x00 /* W Mixer MVD508 Both channel select */ + #define P_M_MV508_MIXER 0x10 /* W Mixer MVD508 Select a mixer (rather than a volume) */ + #define P_M_MV508_VOLUME 0x00 + + #define P_M_MV508_INPUTMIX 0x20 /* W Mixer MVD508 Select mixer A */ + #define P_M_MV508_OUTPUTMIX 0x00 /* W Mixer MVD508 Select mixer B */ + + #define P_M_MV508_MASTER_A 0x01 /* W Mixer MVD508 Master volume control A (output) */ + #define P_M_MV508_MASTER_B 0x02 /* W Mixer MVD508 Master volume control B (DSP input) */ + #define P_M_MV508_BASS 0x03 /* W Mixer MVD508 Bass control */ + #define P_M_MV508_TREBLE 0x04 /* W Mixer MVD508 Treble control */ + #define P_M_MV508_MODE 0x05 /* W Mixer MVD508 Master mode control */ + + #define P_M_MV508_LOUDNESS 0x04 /* W Mixer MVD508 Mode control - Loudness filter */ + #define P_M_MV508_ENHANCE_BITS 0x03 + #define P_M_MV508_ENHANCE_NONE 0x00 /* W Mixer MVD508 Mode control - No stereo enhancement */ + #define P_M_MV508_ENHANCE_40 0x01 /* W Mixer MVD508 Mode control - 40% stereo enhancement */ + #define P_M_MV508_ENHANCE_60 0x02 /* W Mixer MVD508 Mode control - 60% stereo enhancement */ + #define P_M_MV508_ENHANCE_80 0x03 /* W Mixer MVD508 Mode control - 80% stereo enhancement */ + + #define P_M_MV508_FM 0x00 /* W Mixer MVD508 Channel 0 - FM */ + #define P_M_MV508_IMIXER 0x01 /* W Mixer MVD508 Channel 1 - Input mixer (rec monitor) */ + #define P_M_MV508_LINE 0x02 /* W Mixer MVD508 Channel 2 - Line in */ + #define P_M_MV508_CDROM 0x03 /* W Mixer MVD508 Channel 3 - CD-ROM */ + #define P_M_MV508_MIC 0x04 /* W Mixer MVD508 Channel 4 - Microphone */ + #define P_M_MV508_PCM 0x05 /* W Mixer MVD508 Channel 5 - PCM */ + #define P_M_MV508_SPEAKER 0x06 /* W Mixer MVD508 Channel 6 - PC Speaker */ + #define P_M_MV508_SB 0x07 /* W Mixer MVD508 Channel 7 - SB DSP */ + +#define SERIAL_MIXER 0xB88 /* R W Control Serial mixer control (used other ways) */ + #define S_M_PCM_RESET 0x01 /* R W PCM Codec/DSP reset */ + #define S_M_FM_RESET 0x02 /* R W FM FM chip reset */ + #define S_M_SB_RESET 0x04 /* R W PCM SB emulation chip reset */ + #define S_M_MIXER_RESET 0x10 /* R W Mixer Mixer chip reset */ + #define S_M_INTEGRATOR_ENABLE 0x40 /* R W Speaker Enable PC speaker integrator (FORCE RealSound) */ + #define S_M_OPL3_DUAL_MONO 0x80 /* R W FM Set the OPL-3 to dual mono mode */ + +#define PCM_CONTROL 0xF8A /* R W PCM PCM Control Register */ + #define P_C_MIXER_CROSS_FIELD 0x0f + #define P_C_MIXER_CROSS_R_TO_R 0x01 /* R W Mixer Connect Right to Right */ + #define P_C_MIXER_CROSS_L_TO_R 0x02 /* R W Mixer Connect Left to Right */ + #define P_C_MIXER_CROSS_R_TO_L 0x04 /* R W Mixer Connect Right to Left */ + #define P_C_MIXER_CROSS_L_TO_L 0x08 /* R W Mixer Connect Left to Left */ + #define P_C_PCM_DAC_MODE 0x10 /* R W PCM Playback (DAC) mode */ + #define P_C_PCM_ADC_MODE 0x00 /* R W PCM Record (ADC) mode */ + #define P_C_PCM_MONO 0x20 /* R W PCM Mono mode */ + #define P_C_PCM_STEREO 0x00 /* R W PCM Stereo mode */ + #define P_C_PCM_ENABLE 0x40 /* R W PCM Enable PCM engine */ + #define P_C_PCM_DMA_ENABLE 0x80 /* R W PCM Enable DRQ */ + +#define SAMPLE_COUNTER_CONTROL 0x138B /* R W PCM Sample counter control register */ + #define S_C_C_SQUARE_WAVE 0x04 /* R W PCM Square wave generator (use for sample rate) */ + #define S_C_C_RATE 0x06 /* R W PCM Rate generator (use for sample buffer count) */ + #define S_C_C_LSB_THEN_MSB 0x30 /* R W PCM Change all 16 bits, LSB first, then MSB */ + + /* MVD101 and SDK documentations have S_C_C_SAMPLE_RATE and S_C_C_SAMPLE_BUFFER transposed. Only one works :-) */ + #define S_C_C_SAMPLE_RATE 0x00 /* R W PCM Select sample rate timer */ + #define S_C_C_SAMPLE_BUFFER 0x40 /* R W PCM Select sample buffer counter */ + + #define S_C_C_PC_SPEAKER 0x80 /* R W PCM Select PC speaker counter */ + +#define SAMPLE_RATE_TIMER 0x1388 /* W PCM Sample rate timer register (PCM wait interval) */ +#define SAMPLE_BUFFER_COUNTER 0x1389 /* R W PCM Sample buffer counter (DMA buffer size) */ + +#define MIDI_CONTROL 0x178b /* R W MIDI Midi control register */ + #define M_C_ENA_TSTAMP_IRQ 0x01 /* R W MIDI Enable Time Stamp Interrupts */ + #define M_C_ENA_TME_COMP_IRQ 0x02 /* R W MIDI Enable time compare interrupts */ + #define M_C_ENA_INPUT_IRQ 0x04 /* R W MIDI Enable input FIFO interrupts */ + #define M_C_ENA_OUTPUT_IRQ 0x08 /* R W MIDI Enable output FIFO interrupts */ + #define M_C_ENA_OUTPUT_HALF_IRQ 0x10 /* R W MIDI Enable output FIFO half full interrupts */ + #define M_C_RESET_INPUT_FIFO 0x20 /* R W MIDI Reset input FIFO pointer */ + #define M_C_RESET_OUTPUT_FIFO 0x40 /* R W MIDI Reset output FIFO pointer */ + #define M_C_ENA_THRU_MODE 0x80 /* R W MIDI Echo input to output (THRU) */ + +#define MIDI_STATUS 0x1B88 /* R W MIDI Midi (interrupt) status register */ + #define M_S_TIMESTAMP 0x01 /* R W MIDI Midi time stamp interrupt occurred */ + #define M_S_COMPARE 0x02 /* R W MIDI Midi compare time interrupt occurred */ + #define M_S_INPUT_AVAIL 0x04 /* R W MIDI Midi input data available interrupt occurred */ + #define M_S_OUTPUT_EMPTY 0x08 /* R W MIDI Midi output FIFO empty interrupt occurred */ + #define M_S_OUTPUT_HALF_EMPTY 0x10 /* R W MIDI Midi output FIFO half empty interrupt occurred */ + #define M_S_INPUT_OVERRUN 0x20 /* R W MIDI Midi input overrun error occurred */ + #define M_S_OUTPUT_OVERRUN 0x40 /* R W MIDI Midi output overrun error occurred */ + #define M_S_FRAMING_ERROR 0x80 /* R W MIDI Midi input framing error occurred */ + +#define MIDI_FIFO_STATUS 0x1B89 /* R W MIDI Midi fifo status */ +#define MIDI_DATA 0x178A /* R W MIDI Midi data register */ +#define MIDI_INPUT_AVAILABLE 0x0f /* RW MIDI */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_card.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_card.c new file mode 100644 index 000000000..98a2f92ea --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_card.c @@ -0,0 +1,359 @@ +#define _PAS2_CARD_C_ +#define SND_SA_INTERRUPT +/* + * sound/pas2_card.c + * + * Detection routine for the Pro Audio Spectrum cards. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS) + +#define DEFINE_TRANSLATIONS +#include "pas.h" + +/* + * The Address Translation code is used to convert I/O register addresses to + * be relative to the given base -register + */ + +int translat_code; +static int pas_intr_mask = 0; +static int pas_irq = 0; + +static char pas_model; +static char *pas_model_names[] = +{"", "Pro AudioSpectrum+", "CDPC", "Pro AudioSpectrum 16", "Pro AudioSpectrum 16D"}; + +/* pas_read() and pas_write() are equivalents of INB() and OUTB() */ +/* These routines perform the I/O address translation required */ +/* to support other than the default base address */ + +unsigned char +pas_read (int ioaddr) +{ + return INB (ioaddr ^ translat_code); +} + +void +pas_write (unsigned char data, int ioaddr) +{ + OUTB (data, ioaddr ^ translat_code); +} + +void +pas2_msg (char *foo) +{ + printk (" PAS2: %s.\n", foo); +} + +/******************* Begin of the Interrupt Handler ********************/ + +void +pasintr (int unused) +{ + int status; + + status = pas_read (INTERRUPT_STATUS); + pas_write (status, INTERRUPT_STATUS); /* Clear interrupt */ + + if (status & I_S_PCM_SAMPLE_BUFFER_IRQ) + { +#ifndef EXCLUDE_AUDIO + pas_pcm_interrupt (status, 1); +#endif + status &= ~I_S_PCM_SAMPLE_BUFFER_IRQ; + } + if (status & I_S_MIDI_IRQ) + { +#ifndef EXCLUDE_MIDI +#ifdef EXCLUDE_PRO_MIDI + pas_midi_interrupt (); +#endif +#endif + status &= ~I_S_MIDI_IRQ; + } + +} + +int +pas_set_intr (int mask) +{ + int err; + + if (!mask) + return 0; + + if (!pas_intr_mask) + { + if ((err = snd_set_irq_handler (pas_irq, pasintr)) < 0) + return err; + } + pas_intr_mask |= mask; + + pas_write (pas_intr_mask, INTERRUPT_MASK); + return 0; +} + +int +pas_remove_intr (int mask) +{ + if (!mask) + return 0; + + pas_intr_mask &= ~mask; + pas_write (pas_intr_mask, INTERRUPT_MASK); + + if (!pas_intr_mask) + { + snd_release_irq (pas_irq); + } + return 0; +} + +/******************* End of the Interrupt handler **********************/ + +/******************* Begin of the Initialization Code ******************/ + +int +config_pas_hw (struct address_info *hw_config) +{ + char ok = 1; + + pas_irq = hw_config->irq; + + pas_write (0x00, INTERRUPT_MASK); + + pas_write (0x36, SAMPLE_COUNTER_CONTROL); /* Local timer control + * register */ + + pas_write (0x36, SAMPLE_RATE_TIMER); /* Sample rate timer (16 bit) */ + pas_write (0, SAMPLE_RATE_TIMER); + + pas_write (0x74, SAMPLE_COUNTER_CONTROL); /* Local timer control + * register */ + + pas_write (0x74, SAMPLE_BUFFER_COUNTER); /* Sample count register (16 + * bit) */ + pas_write (0, SAMPLE_BUFFER_COUNTER); + + pas_write (F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER | F_F_MIXER_UNMUTE | 1, FILTER_FREQUENCY); + pas_write (P_C_PCM_DMA_ENABLE | P_C_PCM_MONO | P_C_PCM_DAC_MODE | P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R, PCM_CONTROL); + pas_write (S_M_PCM_RESET | S_M_FM_RESET | S_M_SB_RESET | S_M_MIXER_RESET /* | S_M_OPL3_DUAL_MONO */ , SERIAL_MIXER); + + pas_write (I_C_1_BOOT_RESET_ENABLE, IO_CONFIGURATION_1); + + if (pas_irq < 0 || pas_irq > 15) + { + printk ("PAS2: Invalid IRQ %d", pas_irq); + ok = 0; + } + else + { + pas_write (I_C_3_PCM_IRQ_translate[pas_irq], IO_CONFIGURATION_3); + if (!I_C_3_PCM_IRQ_translate[pas_irq]) + { + printk ("PAS2: Invalid IRQ %d", pas_irq); + ok = 0; + } + } + + if (hw_config->dma < 0 || hw_config->dma > 7) + { + printk ("PAS2: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } + else + { + pas_write (I_C_2_PCM_DMA_translate[hw_config->dma], IO_CONFIGURATION_2); + if (!I_C_2_PCM_DMA_translate[hw_config->dma]) + { + printk ("PAS2: Invalid DMA selection %d", hw_config->dma); + ok = 0; + } + } + +/* + * This fixes the timing problems of the PAS due to the Symphony chipset + * as per Media Vision. Only define this if your PAS doesn't work correctly. + */ +#ifdef SYMPHONY_PAS + OUTB(0x05,0xa8); + OUTB(0x60,0xa9); +#endif + +#ifdef BROKEN_BUS_CLOCK + pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND | S_C_1_FM_EMULATE_CLOCK, SYSTEM_CONFIGURATION_1); +#else + /* pas_write(S_C_1_PCS_ENABLE, SYSTEM_CONFIGURATION_1); */ + pas_write (S_C_1_PCS_ENABLE | S_C_1_PCS_STEREO | S_C_1_PCS_REALSOUND, SYSTEM_CONFIGURATION_1); +#endif + pas_write (0x18, SYSTEM_CONFIGURATION_3); /* ??? */ + + pas_write (F_F_MIXER_UNMUTE | 0x01, FILTER_FREQUENCY); /* Sets mute off and + * selects filter rate + * of 17.897 kHz */ + + if (pas_model == PAS_16 || pas_model == PAS_16D) + pas_write (8, PRESCALE_DIVIDER); + else + pas_write (0, PRESCALE_DIVIDER); + + pas_write (P_M_MV508_ADDRESS | 5, PARALLEL_MIXER); + pas_write (5, PARALLEL_MIXER); + +#if !defined(EXCLUDE_SB_EMULATION) || !defined(EXCLUDE_SB) + + { + struct address_info *sb_config; + + if ((sb_config=sound_getconf(SNDCARD_SB))) + { + unsigned char irq_dma; + + /* Turn on Sound Blaster compatibility */ + /* bit 1 = SB emulation */ + /* bit 0 = MPU401 emulation (CDPC only :-( ) */ + pas_write (0x02, COMPATIBILITY_ENABLE); + + /* "Emulation address" */ + pas_write ((sb_config->io_base >> 4) & 0x0f, EMULATION_ADDRESS); + + if (!E_C_SB_DMA_translate[sb_config->dma]) + printk("\n\nPAS16 Warning: Invalid SB DMA %d\n\n", + sb_config->dma); + + if (!E_C_SB_IRQ_translate[sb_config->irq]) + printk("\n\nPAS16 Warning: Invalid SB IRQ %d\n\n", + sb_config->irq); + + irq_dma = E_C_SB_DMA_translate[sb_config->dma] | + E_C_SB_IRQ_translate[sb_config->irq]; + + pas_write(irq_dma, EMULATION_CONFIGURATION); + } + } +#endif + + if (!ok) + pas2_msg ("Driver not enabled"); + + return ok; +} + +int +detect_pas_hw (struct address_info *hw_config) +{ + unsigned char board_id, foo; + + /* + * WARNING: Setting an option like W:1 or so that disables warm boot reset + * of the card will screw up this detect code something fierce. Adding code + * to handle this means possibly interfering with other cards on the bus if + * you have something on base port 0x388. SO be forewarned. + */ + + OUTB (0xBC, MASTER_DECODE); /* Talk to first board */ + OUTB (hw_config->io_base >> 2, MASTER_DECODE); /* Set base address */ + translat_code = PAS_DEFAULT_BASE ^ hw_config->io_base; + pas_write (1, WAIT_STATE); /* One wait-state */ + + board_id = pas_read (INTERRUPT_MASK); + + if (board_id == 0xff) + return 0; + + /* + * We probably have a PAS-series board, now check for a PAS2-series board + * by trying to change the board revision bits. PAS2-series hardware won't + * let you do this - the bits are read-only. + */ + + foo = board_id ^ 0xe0; + + pas_write (foo, INTERRUPT_MASK); + foo = INB (INTERRUPT_MASK); + pas_write (board_id, INTERRUPT_MASK); + + if (board_id != foo) /* Not a PAS2 */ + return 0; + + pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f]; + + return pas_model; +} + +long +attach_pas_card (long mem_start, struct address_info *hw_config) +{ + pas_irq = hw_config->irq; + + if (detect_pas_hw (hw_config)) + { + + if ((pas_model = O_M_1_to_card[pas_read (OPERATION_MODE_1) & 0x0f])) + { + printk (" <%s rev %d>", pas_model_names[(int) pas_model], pas_read (BOARD_REV_ID)); + } + + if (config_pas_hw (hw_config)) + { + +#ifndef EXCLUDE_AUDIO + mem_start = pas_pcm_init (mem_start, hw_config); +#endif + +# if !defined(EXCLUDE_SB_EMULATION) && !defined(EXCLUDE_SB) + + sb_dsp_disable_midi (); /* The SB emulation don't support + * midi */ +# endif + +#ifndef EXCLUDE_YM3812 + enable_opl3_mode (0x388, 0x38a, 0); +#endif + +#ifndef EXCLUDE_MIDI +#ifdef EXCLUDE_PRO_MIDI + mem_start = pas_midi_init (mem_start); +#endif +#endif + + pas_init_mixer (); + } + } + + return mem_start; +} + +int +probe_pas (struct address_info *hw_config) +{ + return detect_pas_hw (hw_config); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_midi.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_midi.c new file mode 100644 index 000000000..13cf97dca --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_midi.c @@ -0,0 +1,295 @@ +/* + * sound/pas2_midi.c + * + * The low level driver for the PAS Midi Interface. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#include "pas.h" + +#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_MIDI) && defined(EXCLUDE_PRO_MIDI) + +static int midi_busy = 0, input_opened = 0; +static int my_dev; +static volatile int ofifo_bytes = 0; + +static unsigned char tmp_queue[256]; +static volatile int qlen; +static volatile unsigned char qhead, qtail; + +static void (*midi_input_intr) (int dev, unsigned char data); + +static int +pas_midi_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + int err; + unsigned long flags; + unsigned char ctrl; + + + if (midi_busy) + { + printk ("PAS2: Midi busy\n"); + return RET_ERROR (EBUSY); + } + + /* Reset input and output FIFO pointers */ + pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, + MIDI_CONTROL); + + DISABLE_INTR (flags); + + if ((err = pas_set_intr (I_M_MIDI_IRQ_ENABLE)) < 0) + return err; + + /* Enable input available and output FIFO empty interrupts */ + + ctrl = 0; + input_opened = 0; + midi_input_intr = input; + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + { + ctrl |= M_C_ENA_INPUT_IRQ;/* Enable input */ + input_opened = 1; + } + + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + { + ctrl |= M_C_ENA_OUTPUT_IRQ | /* Enable output */ + M_C_ENA_OUTPUT_HALF_IRQ; + } + + pas_write (ctrl, + MIDI_CONTROL); + + /* Acknowledge any pending interrupts */ + + pas_write (0xff, MIDI_STATUS); + ofifo_bytes = 0; + + RESTORE_INTR (flags); + + midi_busy = 1; + qlen = qhead = qtail = 0; + return 0; +} + +static void +pas_midi_close (int dev) +{ + + /* Reset FIFO pointers, disable intrs */ + pas_write (M_C_RESET_INPUT_FIFO | M_C_RESET_OUTPUT_FIFO, MIDI_CONTROL); + + pas_remove_intr (I_M_MIDI_IRQ_ENABLE); + midi_busy = 0; +} + +static int +dump_to_midi (unsigned char midi_byte) +{ + int fifo_space, x; + + fifo_space = ((x = pas_read (MIDI_FIFO_STATUS)) >> 4) & 0x0f; + + if (fifo_space == 15 || (fifo_space < 2 && ofifo_bytes > 13)) /* Fifo full */ + { + return 0; /* Upper layer will call again */ + } + + ofifo_bytes++; + + pas_write (midi_byte, MIDI_DATA); + + return 1; +} + +static int +pas_midi_out (int dev, unsigned char midi_byte) +{ + + unsigned long flags; + + /* + * Drain the local queue first + */ + + DISABLE_INTR (flags); + + while (qlen && dump_to_midi (tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + RESTORE_INTR (flags); + + /* + * Output the byte if the local queue is empty. + */ + + if (!qlen) + if (dump_to_midi (midi_byte)) + return 1; /* OK */ + + /* + * Put to the local queue + */ + + if (qlen >= 256) + return 0; /* Local queue full */ + + DISABLE_INTR (flags); + + tmp_queue[qtail] = midi_byte; + qlen++; + qtail++; + + RESTORE_INTR (flags); + + return 1; +} + +static int +pas_midi_start_read (int dev) +{ + return 0; +} + +static int +pas_midi_end_read (int dev) +{ + return 0; +} + +static int +pas_midi_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EINVAL); +} + +static void +pas_midi_kick (int dev) +{ + ofifo_bytes = 0; +} + +static int +pas_buffer_status (int dev) +{ + return !qlen; +} + +static struct midi_operations pas_midi_operations = +{ + {"Pro Audio Spectrum", 0, 0, SNDCARD_PAS}, + pas_midi_open, + pas_midi_close, + pas_midi_ioctl, + pas_midi_out, + pas_midi_start_read, + pas_midi_end_read, + pas_midi_kick, + NULL, /* command */ + pas_buffer_status +}; + +long +pas_midi_init (long mem_start) +{ + my_dev = num_midis; + midi_devs[num_midis++] = &pas_midi_operations; + return mem_start; +} + +void +pas_midi_interrupt (void) +{ + unsigned char stat; + int i, incount; + unsigned long flags; + + stat = pas_read (MIDI_STATUS); + + if (stat & M_S_INPUT_AVAIL) /* Input byte available */ + { + incount = pas_read (MIDI_FIFO_STATUS) & 0x0f; /* Input FIFO count */ + if (!incount) + incount = 16; + + for (i = 0; i < incount; i++) + if (input_opened) + { + midi_input_intr (my_dev, pas_read (MIDI_DATA)); + } + else + pas_read (MIDI_DATA); /* Flush */ + } + + if (stat & (M_S_OUTPUT_EMPTY | M_S_OUTPUT_HALF_EMPTY)) + { + if (!(stat & M_S_OUTPUT_EMPTY)) + { + ofifo_bytes = 8; + } + else + { + ofifo_bytes = 0; + } + + DISABLE_INTR (flags); + + while (qlen && dump_to_midi (tmp_queue[qhead])) + { + qlen--; + qhead++; + } + + RESTORE_INTR (flags); + } + + if (stat & M_S_FRAMING_ERROR) + printk ("MIDI framing error\n"); + + if (stat & M_S_OUTPUT_OVERRUN) + { + printk ("MIDI output overrun %x,%x,%d \n", pas_read (MIDI_FIFO_STATUS), stat, ofifo_bytes); + ofifo_bytes = 100; + } + + pas_write (stat, MIDI_STATUS);/* Acknowledge interrupts */ +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_mixer.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_mixer.c new file mode 100644 index 000000000..63be9e5b6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_mixer.c @@ -0,0 +1,500 @@ +#define _PAS2_MIXER_C_ + +/* + * sound/pas2_mixer.c + * + * Mixer routines for the Pro Audio Spectrum cards. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_PAS) + +#include "pas.h" + +#define TRACE(what) /* (what) */ + +extern int translat_code; + +static int rec_devices = (SOUND_MASK_MIC); /* Default recording source */ +static int mode_control = 0; + +#define POSSIBLE_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_ALTPCM) + +#define SUPPORTED_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_ALTPCM | SOUND_MASK_IMIX | \ + SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE | SOUND_MASK_RECLEV | \ + SOUND_MASK_MUTE | SOUND_MASK_ENHANCE | SOUND_MASK_LOUD) + +static unsigned short levels[SOUND_MIXER_NRDEVICES] = +{ + 0x3232, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x5050, /* FM */ + 0x4b4b, /* PCM */ + 0x3232, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x4b4b, /* Mic */ + 0x4b4b, /* CD */ + 0x6464, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x6464}; /* Recording level */ + +static int +mixer_output (int right_vol, int left_vol, int div, int bits, + int mixer /* Input or output mixer */ ) +{ + int left = left_vol * div / 100; + int right = right_vol * div / 100; + + /* + * The Revision D cards have a problem with their MVA508 interface. The + * kludge-o-rama fix is to make a 16-bit quantity with identical LSB and + * MSBs out of the output byte and to do a 16-bit out to the mixer port - + * 1. We don't need to do this because the call to pas_write more than + * compensates for the timing problems. + */ + + if (bits & P_M_MV508_MIXER) + { /* Select input or output mixer */ + left |= mixer; + right |= mixer; + } + + if (bits == P_M_MV508_BASS || bits == P_M_MV508_TREBLE) + { /* Bass and trebble are mono devices */ + pas_write (P_M_MV508_ADDRESS | bits, PARALLEL_MIXER); + pas_write (left, PARALLEL_MIXER); + right_vol = left_vol; + } + else + { + pas_write (P_M_MV508_ADDRESS | P_M_MV508_LEFT | bits, PARALLEL_MIXER); + pas_write (left, PARALLEL_MIXER); + pas_write (P_M_MV508_ADDRESS | P_M_MV508_RIGHT | bits, PARALLEL_MIXER); + pas_write (right, PARALLEL_MIXER); + } + + return (left_vol | (right_vol << 8)); +} + +void +set_mode (int new_mode) +{ + pas_write (P_M_MV508_ADDRESS | P_M_MV508_MODE, PARALLEL_MIXER); + pas_write (new_mode, PARALLEL_MIXER); + + mode_control = new_mode; +} + +static int +pas_mixer_set (int whichDev, unsigned int level) +{ + int left, right, devmask, changed, i, mixer = 0; + + TRACE (printk ("static int pas_mixer_set(int whichDev = %d, unsigned int level = %X)\n", whichDev, level)); + + left = level & 0x7f; + right = (level & 0x7f00) >> 8; + + if (whichDev < SOUND_MIXER_NRDEVICES) + if ((1 << whichDev) & rec_devices) + mixer = P_M_MV508_INPUTMIX; + else + mixer = P_M_MV508_OUTPUTMIX; + + switch (whichDev) + { + case SOUND_MIXER_VOLUME: /* Master volume (0-63) */ + levels[whichDev] = mixer_output (right, left, 63, P_M_MV508_MASTER_A, 0); + break; + + /* + * Note! Bass and Treble are mono devices. Will use just the left + * channel. + */ + case SOUND_MIXER_BASS: /* Bass (0-12) */ + levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_BASS, 0); + break; + case SOUND_MIXER_TREBLE: /* Treble (0-12) */ + levels[whichDev] = mixer_output (right, left, 12, P_M_MV508_TREBLE, 0); + break; + + case SOUND_MIXER_SYNTH: /* Internal synthesizer (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_FM, mixer); + break; + case SOUND_MIXER_PCM: /* PAS PCM (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_PCM, mixer); + break; + case SOUND_MIXER_ALTPCM: /* SB PCM (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SB, mixer); + break; + case SOUND_MIXER_SPEAKER: /* PC speaker (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_SPEAKER, mixer); + break; + case SOUND_MIXER_LINE: /* External line (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_LINE, mixer); + break; + case SOUND_MIXER_CD: /* CD (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_CDROM, mixer); + break; + case SOUND_MIXER_MIC: /* External microphone (0-31) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_MIC, mixer); + break; + case SOUND_MIXER_IMIX: /* Recording monitor (0-31) (Only available + * on the Output Mixer) */ + levels[whichDev] = mixer_output (right, left, 31, P_M_MV508_MIXER | P_M_MV508_IMIXER, + P_M_MV508_OUTPUTMIX); + break; + case SOUND_MIXER_RECLEV: /* Recording level (0-15) */ + levels[whichDev] = mixer_output (right, left, 15, P_M_MV508_MASTER_B, 0); + break; + + case SOUND_MIXER_MUTE: + return 0; + break; + + case SOUND_MIXER_ENHANCE: + i = 0; + level &= 0x7f; + if (level) + i = (level / 20) - 1; + + mode_control &= ~P_M_MV508_ENHANCE_BITS; + mode_control |= P_M_MV508_ENHANCE_BITS; + set_mode (mode_control); + + if (i) + i = (i + 1) * 20; + return i; + break; + + case SOUND_MIXER_LOUD: + mode_control &= ~P_M_MV508_LOUDNESS; + if (level) + mode_control |= P_M_MV508_LOUDNESS; + set_mode (mode_control); + return !!level; /* 0 or 1 */ + break; + + case SOUND_MIXER_RECSRC: + devmask = level & POSSIBLE_RECORDING_DEVICES; + + changed = devmask ^ rec_devices; + rec_devices = devmask; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + if (changed & (1 << i)) + { + pas_mixer_set (i, levels[i]); + } + return rec_devices; + break; + + default: + return RET_ERROR (EINVAL); + } + + return (levels[whichDev]); +} + +/*****/ + +static int +mixer_set_levels (struct sb_mixer_levels *user_l) +{ +#define cmix(v) ((((v.r*100+7)/15)<<8)| ((v.l*100+7)/15)) + + struct sb_mixer_levels l; + + IOCTL_FROM_USER ((char *) &l, (char *) user_l, 0, sizeof (l)); + + if (l.master.l & ~0xF || l.master.r & ~0xF + || l.line.l & ~0xF || l.line.r & ~0xF + || l.voc.l & ~0xF || l.voc.r & ~0xF + || l.fm.l & ~0xF || l.fm.r & ~0xF + || l.cd.l & ~0xF || l.cd.r & ~0xF + || l.mic & ~0x7) + return (RET_ERROR (EINVAL)); + + pas_mixer_set (SOUND_MIXER_VOLUME, cmix (l.master)); + pas_mixer_set (SOUND_MIXER_LINE, cmix (l.line)); + pas_mixer_set (SOUND_MIXER_PCM, cmix (l.voc)); + pas_mixer_set (SOUND_MIXER_ALTPCM, cmix (l.voc)); + pas_mixer_set (SOUND_MIXER_SYNTH, cmix (l.fm)); + pas_mixer_set (SOUND_MIXER_CD, cmix (l.cd)); + pas_mixer_set (SOUND_MIXER_MIC, ((l.mic * 100 + 3) / 7) | (((l.mic * 100 + 3) / 7) << 8)); + return (0); +} + +/* + * This sets aspects of the Mixer that are not volume levels. (Recording + * source, filter level, I/O filtering, and stereo.) + */ +static int +mixer_set_params (struct sb_mixer_params *user_p) +{ + struct sb_mixer_params p; + S_BYTE val; + int src; + unsigned long flags; + + IOCTL_FROM_USER ((char *) &p, (char *) user_p, 0, sizeof (p)); + + if (p.record_source != SRC_MIC + && p.record_source != SRC_CD + && p.record_source != SRC_LINE) + return (RET_ERROR (EINVAL)); + + /* + * I'm not sure if this is The Right Thing. Should stereo be entirely + * under control of DSP? I like being able to toggle it while a sound is + * playing, so I do this... because I can. + */ + + DISABLE_INTR (flags); + + val = (pas_read (PCM_CONTROL) & ~P_C_MIXER_CROSS_FIELD) | P_C_MIXER_CROSS_R_TO_R | P_C_MIXER_CROSS_L_TO_L; + if (!p.dsp_stereo) + val |= (P_C_MIXER_CROSS_R_TO_L | P_C_MIXER_CROSS_L_TO_R); /* Mono */ + pas_write (val, PCM_CONTROL); + + RESTORE_INTR (flags); + + switch (p.record_source) + { + case SRC_CD: + src = SOUND_MASK_CD; + break; + + case SRC_LINE: + src = SOUND_MASK_LINE; + break; + + default: + src = SOUND_MASK_MIC; + break; + } + + pas_mixer_set (SOUND_MIXER_RECSRC, src); + + /* + * setmixer (OUT_FILTER, ((dsp_stereo ? STEREO_DAC : MONO_DAC) | + * (p.filter_output ? FILT_ON : FILT_OFF))); + */ + return (0); +} + +static int +getmixer (int dev, int chn) +{ + if (chn == P_M_MV508_RIGHT) + { + return (levels[dev] >> 8) & 0x7f; + } + else + { + return levels[dev] & 0x7f; + } +} + +/* Read the current mixer level settings into the user's struct. */ +static int +mixer_get_levels (struct sb_mixer_levels *user_l) +{ + + struct sb_mixer_levels l; + + l.master.r = ((((levels[SOUND_MIXER_VOLUME] >> 8) & 0x7f) * 15) + 50) / 100; /* Master */ + l.master.l = (((levels[SOUND_MIXER_VOLUME] & 0x7f) * 15) + 50) / 100; /* Master */ + + l.line.r = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_RIGHT) * 15) + 50) / 100; /* Line */ + l.line.l = ((getmixer (SOUND_MIXER_LINE, P_M_MV508_LEFT) * 15) + 50) / 100; + + l.voc.r = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_RIGHT) * 15) + 50) / 100; /* DAC */ + l.voc.l = ((getmixer (SOUND_MIXER_PCM, P_M_MV508_LEFT) * 15) + 50) / 100; + + l.fm.r = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_RIGHT) * 15) + 50) / 100; /* FM */ + l.fm.l = ((getmixer (SOUND_MIXER_SYNTH, P_M_MV508_LEFT) * 15) + 50) / 100; + + l.cd.r = ((getmixer (SOUND_MIXER_CD, P_M_MV508_RIGHT) * 15) + 50) / 100; /* CD */ + l.cd.l = ((getmixer (SOUND_MIXER_CD, P_M_MV508_LEFT) * 15) + 50) / 100; + + l.mic = ((getmixer (SOUND_MIXER_MIC, P_M_MV508_LEFT) * 7) + 50) / 100; /* Microphone */ + + IOCTL_TO_USER ((char *) user_l, 0, (char *) &l, sizeof (l)); + return (0); +} + +/* Read the current mixer parameters into the user's struct. */ +static int +mixer_get_params (struct sb_mixer_params *user_params) +{ + S_BYTE val; + struct sb_mixer_params params; + + switch (rec_devices) + { + case SOUND_MASK_CD: + params.record_source = SRC_CD; + break; + + case SOUND_MASK_LINE: + params.record_source = SRC_LINE; + break; + + case SOUND_MASK_MIC: + params.record_source = SRC_MIC; + break; + + default: + params.record_source = SRC_MIC; + pas_mixer_set (SOUND_MIXER_RECSRC, SOUND_MASK_MIC); /* Adjust */ + } + + params.hifreq_filter = OFF; + params.filter_input = OFF; + params.filter_output = OFF; + + val = INB (PCM_CONTROL); + params.dsp_stereo = ((val & P_C_MIXER_CROSS_FIELD) == (P_C_MIXER_CROSS_L_TO_L | P_C_MIXER_CROSS_R_TO_R)); + + IOCTL_TO_USER ((char *) user_params, 0, (char *) ¶ms, sizeof (params)); + return (0); +} + +/*****/ + +static void +pas_mixer_reset (void) +{ + int foo; + + TRACE (printk ("pas2_mixer.c: void pas_mixer_reset(void)\n")); + + for (foo = 0; foo < SOUND_MIXER_NRDEVICES; foo++) + pas_mixer_set (foo, levels[foo]); + + set_mode (P_M_MV508_LOUDNESS | P_M_MV508_ENHANCE_40); +} + +int +pas_mixer_ioctl (int dev, unsigned int cmd, unsigned int arg) +{ + TRACE (printk ("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + + if (((cmd >> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + return IOCTL_OUT (arg, pas_mixer_set (cmd & 0xff, IOCTL_IN (arg))); + else + { /* Read parameters */ + + switch (cmd & 0xff) + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, rec_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE)); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, SUPPORTED_MIXER_DEVICES); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, 0); /* No special capabilities */ + break; + + case SOUND_MIXER_MUTE: + return IOCTL_OUT (arg, 0); /* No mute yet */ + break; + + case SOUND_MIXER_ENHANCE: + if (!(mode_control & P_M_MV508_ENHANCE_BITS)) + return IOCTL_OUT (arg, 0); + return IOCTL_OUT (arg, ((mode_control & P_M_MV508_ENHANCE_BITS) + 1) * 20); + break; + + case SOUND_MIXER_LOUD: + if (mode_control & P_M_MV508_LOUDNESS) + return IOCTL_OUT (arg, 1); + return IOCTL_OUT (arg, 0); + break; + + default: + return IOCTL_OUT (arg, levels[cmd & 0xff]); + } + } + } + else + { + switch (cmd) + { + case MIXER_IOCTL_SET_LEVELS: + mixer_set_levels ((struct sb_mixer_levels *) arg); + return mixer_get_levels ((struct sb_mixer_levels *) arg); + case MIXER_IOCTL_SET_PARAMS: + mixer_set_params ((struct sb_mixer_params *) arg); + return mixer_get_params ((struct sb_mixer_params *) arg); + case MIXER_IOCTL_READ_LEVELS: + return mixer_get_levels ((struct sb_mixer_levels *) arg); + case MIXER_IOCTL_READ_PARAMS: + return mixer_get_params ((struct sb_mixer_params *) arg); + case MIXER_IOCTL_RESET: + pas_mixer_reset (); + return (0); + default: + return RET_ERROR (EINVAL); + } + } + return RET_ERROR (EINVAL); +} + +static struct mixer_operations pas_mixer_operations = +{ + pas_mixer_ioctl +}; + +int +pas_init_mixer (void) +{ + pas_mixer_reset (); + + mixer_devs[num_mixers++] = &pas_mixer_operations; + return 1; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_pcm.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_pcm.c new file mode 100644 index 000000000..b396f6153 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/pas2_pcm.c @@ -0,0 +1,428 @@ +#define _PAS2_PCM_C_ +/* + * sound/pas2_pcm.c + * + * The low level driver for the Pro Audio Spectrum ADC/DAC. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#include "pas.h" + +#if !defined(EXCLUDE_PAS) && !defined(EXCLUDE_AUDIO) + +#define TRACE(WHAT) /* (WHAT) */ + +#define PAS_PCM_INTRBITS (0x08) +/* Sample buffer timer interrupt enable */ + +#define PCM_NON 0 +#define PCM_DAC 1 +#define PCM_ADC 2 + +static unsigned long pcm_speed = 0; /* sampling rate */ +static unsigned char pcm_channels = 1; /* channels/sample (1 or 2) */ +static unsigned char pcm_bits = 8; /* bits/sample (8 or 16) */ +static unsigned char pcm_filter = 0; /* filter FLAG */ +static unsigned char pcm_mode = PCM_NON; +static unsigned long pcm_count = 0; +static unsigned short pcm_bitsok = 8; /* mask of OK bits */ +static int my_devnum = 0; + +int +pcm_set_speed (int arg) +{ + int foo, tmp; + unsigned long flags; + + if (arg > 44100) + arg = 44100; + if (arg < 5000) + arg = 5000; + + foo = 1193180 / arg; + arg = 1193180 / foo; + + if (pcm_channels & 2) + foo = foo >> 1; + + pcm_speed = arg; + + tmp = pas_read (FILTER_FREQUENCY); + + DISABLE_INTR (flags); + + pas_write (tmp & ~(F_F_PCM_RATE_COUNTER | F_F_PCM_BUFFER_COUNTER), FILTER_FREQUENCY); + pas_write (S_C_C_SAMPLE_RATE | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); + pas_write (foo & 0xff, SAMPLE_RATE_TIMER); + pas_write ((foo >> 8) & 0xff, SAMPLE_RATE_TIMER); + pas_write (tmp, FILTER_FREQUENCY); + + RESTORE_INTR (flags); + + return pcm_speed; +} + +int +pcm_set_channels (int arg) +{ + + if ((arg != 1) && (arg != 2)) + return pcm_channels; + + if (arg != pcm_channels) + { + pas_write (pas_read (PCM_CONTROL) ^ P_C_PCM_MONO, PCM_CONTROL); + + pcm_channels = arg; + pcm_set_speed (pcm_speed);/* The speed must be reinitialized */ + } + + return pcm_channels; +} + +int +pcm_set_bits (int arg) +{ + if ((arg & pcm_bitsok) != arg) + return pcm_bits; + + if (arg != pcm_bits) + { + pas_write (pas_read (SYSTEM_CONFIGURATION_2) ^ S_C_2_PCM_16_BIT, SYSTEM_CONFIGURATION_2); + + pcm_bits = arg; + } + + return pcm_bits; +} + +static int +pas_pcm_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + TRACE (printk ("pas2_pcm.c: static int pas_pcm_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg)); + + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return pcm_set_speed (arg); + return IOCTL_OUT (arg, pcm_set_speed (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_RATE: + if (local) + return pcm_speed; + return IOCTL_OUT (arg, pcm_speed); + break; + + case SNDCTL_DSP_STEREO: + if (local) + return pcm_set_channels (arg + 1) - 1; + return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg) + 1) - 1); + break; + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return pcm_set_channels (arg); + return IOCTL_OUT (arg, pcm_set_channels (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_CHANNELS: + if (local) + return pcm_channels; + return IOCTL_OUT (arg, pcm_channels); + break; + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return pcm_set_bits (arg); + return IOCTL_OUT (arg, pcm_set_bits (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_BITS: + if (local) + return pcm_bits; + return IOCTL_OUT (arg, pcm_bits); + + case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ + if (IOCTL_IN (arg) > 1) + return IOCTL_OUT (arg, RET_ERROR (EINVAL)); + break; + + pcm_filter = IOCTL_IN (arg); + case SOUND_PCM_READ_FILTER: + return IOCTL_OUT (arg, pcm_filter); + break; + + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static void +pas_pcm_reset (int dev) +{ + TRACE (printk ("pas2_pcm.c: static void pas_pcm_reset(void)\n")); + + pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, PCM_CONTROL); +} + +static int +pas_pcm_open (int dev, int mode) +{ + int err; + + TRACE (printk ("pas2_pcm.c: static int pas_pcm_open(int mode = %X)\n", mode)); + + if ((err = pas_set_intr (PAS_PCM_INTRBITS)) < 0) + return err; + + if (!DMAbuf_open_dma (dev)) + { + pas_remove_intr (PAS_PCM_INTRBITS); + return RET_ERROR (EBUSY); + } + + pcm_count = 0; + + return 0; +} + +static void +pas_pcm_close (int dev) +{ + unsigned long flags; + + TRACE (printk ("pas2_pcm.c: static void pas_pcm_close(void)\n")); + + DISABLE_INTR (flags); + + pas_pcm_reset (dev); + DMAbuf_close_dma (dev); + pas_remove_intr (PAS_PCM_INTRBITS); + pcm_mode = PCM_NON; + + RESTORE_INTR (flags); +} + +static void +pas_pcm_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) +{ + unsigned long flags, cnt; + + TRACE (printk ("pas2_pcm.c: static void pas_pcm_output_block(char *buf = %P, int count = %X)\n", buf, count)); + + cnt = count; + if (sound_dsp_dmachan[dev] > 3) + cnt >>= 1; + + if (sound_dma_automode[dev] && + intrflag && + cnt == pcm_count) + return; /* Auto mode on. No need to react */ + + DISABLE_INTR (flags); + + pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, + PCM_CONTROL); + + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (sound_dsp_dmachan[dev] > 3) + count >>= 1; + + if (count != pcm_count) + { + pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); + pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); + pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); + pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + + pcm_count = count; + } + pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); + pas_write (pas_read (PCM_CONTROL) | P_C_PCM_ENABLE | P_C_PCM_DAC_MODE, PCM_CONTROL); + + pcm_mode = PCM_DAC; + + RESTORE_INTR (flags); +} + +static void +pas_pcm_start_input (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) +{ + unsigned long flags; + int cnt; + + TRACE (printk ("pas2_pcm.c: static void pas_pcm_start_input(char *buf = %P, int count = %X)\n", buf, count)); + + cnt = count; + if (sound_dsp_dmachan[dev] > 3) + cnt >>= 1; + + if (sound_dma_automode[my_devnum] && + intrflag && + cnt == pcm_count) + return; /* Auto mode on. No need to react */ + + DISABLE_INTR (flags); + + if (restart_dma) + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (sound_dsp_dmachan[dev] > 3) + count >>= 1; + + if (count != pcm_count) + { + pas_write (pas_read (FILTER_FREQUENCY) & ~F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + pas_write (S_C_C_SAMPLE_BUFFER | S_C_C_LSB_THEN_MSB | S_C_C_SQUARE_WAVE, SAMPLE_COUNTER_CONTROL); + pas_write (count & 0xff, SAMPLE_BUFFER_COUNTER); + pas_write ((count >> 8) & 0xff, SAMPLE_BUFFER_COUNTER); + pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER, FILTER_FREQUENCY); + + pcm_count = count; + } + pas_write (pas_read (FILTER_FREQUENCY) | F_F_PCM_BUFFER_COUNTER | F_F_PCM_RATE_COUNTER, FILTER_FREQUENCY); + pas_write ((pas_read (PCM_CONTROL) | P_C_PCM_ENABLE) & ~P_C_PCM_DAC_MODE, PCM_CONTROL); + + pcm_mode = PCM_ADC; + + RESTORE_INTR (flags); +} + +static int +pas_pcm_prepare_for_input (int dev, int bsize, int bcount) +{ + return 0; +} +static int +pas_pcm_prepare_for_output (int dev, int bsize, int bcount) +{ + return 0; +} + +static struct audio_operations pas_pcm_operations = +{ + "Pro Audio Spectrum", + pas_pcm_open, /* */ + pas_pcm_close, /* */ + pas_pcm_output_block, /* */ + pas_pcm_start_input, /* */ + pas_pcm_ioctl, /* */ + pas_pcm_prepare_for_input, /* */ + pas_pcm_prepare_for_output, /* */ + pas_pcm_reset, /* */ + pas_pcm_reset, /* halt_xfer */ + NULL, /* has_output_drained */ + NULL /* copy_from_user */ +}; + +long +pas_pcm_init (long mem_start, struct address_info *hw_config) +{ + TRACE (printk ("pas2_pcm.c: long pas_pcm_init(long mem_start = %X)\n", mem_start)); + + pcm_bitsok = 8; + if (pas_read (OPERATION_MODE_1) & O_M_1_PCM_TYPE) + pcm_bitsok |= 16; + + pcm_set_speed (DSP_DEFAULT_SPEED); + + if (num_dspdevs < MAX_DSP_DEV) + { + dsp_devs[my_devnum = num_dspdevs++] = &pas_pcm_operations; + sound_dsp_dmachan[my_devnum] = hw_config->dma; +#ifndef PAS_NO_AUTODMA + if (hw_config->dma > 3) + { + sound_buffcounts[my_devnum] = 1; + sound_buffsizes[my_devnum] = 2 * 65536; + sound_dma_automode[my_devnum] = 1; + } + else + { + sound_buffcounts[my_devnum] = 1; + sound_buffsizes[my_devnum] = DSP_BUFFSIZE; + sound_dma_automode[my_devnum] = 1; + } +#else + sound_buffcounts[my_devnum] = 2; + sound_buffsizes[my_devnum] = DSP_BUFFSIZE; + sound_dma_automode[my_devnum] = 0; +#endif + } + else + printk ("PAS2: Too many PCM devices available\n"); + + return mem_start; +} + +void +pas_pcm_interrupt (unsigned char status, int cause) +{ + if (cause == 1) /* PCM buffer done */ + { + /* + * Halt the PCM first. Otherwise we don't have time to start a new + * block before the PCM chip proceeds to the next sample + */ + + if (!sound_dma_automode[my_devnum]) + { + pas_write (pas_read (PCM_CONTROL) & ~P_C_PCM_ENABLE, + PCM_CONTROL); + } + + switch (pcm_mode) + { + + case PCM_DAC: + DMAbuf_outputintr (my_devnum, 1); + break; + + case PCM_ADC: + DMAbuf_inputintr (my_devnum); + break; + + default: + printk ("PAS: Unexpected PCM interrupt\n"); + } + } +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/patmgr.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/patmgr.c new file mode 100644 index 000000000..f5697ae26 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/patmgr.c @@ -0,0 +1,262 @@ +/* + * sound/patmgr.c + * + * The patch maneger interface for the /dev/sequencer + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define PATMGR_C +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SEQUENCER) + +DEFINE_WAIT_QUEUES (server_procs[MAX_SYNTH_DEV], + server_wait_flag[MAX_SYNTH_DEV]); + +static struct patmgr_info *mbox[MAX_SYNTH_DEV] = +{NULL}; +static volatile int msg_direction[MAX_SYNTH_DEV] = +{0}; + +static int pmgr_opened[MAX_SYNTH_DEV] = +{0}; + +#define A_TO_S 1 +#define S_TO_A 2 + +DEFINE_WAIT_QUEUE (appl_proc, appl_wait_flag); + +int +pmgr_open (int dev) +{ + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (pmgr_opened[dev]) + return RET_ERROR (EBUSY); + pmgr_opened[dev] = 1; + + RESET_WAIT_QUEUE (server_procs[dev], server_wait_flag[dev]); + + return 0; +} + +void +pmgr_release (int dev) +{ + + if (mbox[dev]) /* Killed in action. Inform the client */ + { + + mbox[dev]->key = PM_ERROR; + mbox[dev]->parm1 = RET_ERROR (EIO); + + if (SOMEONE_WAITING (appl_proc, appl_wait_flag)) + WAKE_UP (appl_proc, appl_wait_flag); + } + + pmgr_opened[dev] = 0; +} + +int +pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + unsigned long flags; + int ok = 0; + + if (count != sizeof (struct patmgr_info)) + { + printk ("PATMGR%d: Invalid read count\n", dev); + return RET_ERROR (EIO); + } + + while (!ok && !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev])) + { + DISABLE_INTR (flags); + + while (!(mbox[dev] && msg_direction[dev] == A_TO_S) && + !PROCESS_ABORTING (server_procs[dev], server_wait_flag[dev])) + { + DO_SLEEP (server_procs[dev], server_wait_flag[dev], 0); + } + + if (mbox[dev] && msg_direction[dev] == A_TO_S) + { + COPY_TO_USER (buf, 0, (char *) mbox[dev], count); + msg_direction[dev] = 0; + ok = 1; + } + + RESTORE_INTR (flags); + + } + + if (!ok) + return RET_ERROR (EINTR); + return count; +} + +int +pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + unsigned long flags; + + if (count < 4) + { + printk ("PATMGR%d: Write count < 4\n", dev); + return RET_ERROR (EIO); + } + + COPY_FROM_USER (mbox[dev], buf, 0, 4); + + if (*(unsigned char *) mbox[dev] == SEQ_FULLSIZE) + { + int tmp_dev; + + tmp_dev = ((unsigned short *) mbox[dev])[2]; + if (tmp_dev != dev) + return RET_ERROR (ENXIO); + + return synth_devs[dev]->load_patch (dev, *(unsigned short *) mbox[dev], + buf, 4, count, 1); + } + + if (count != sizeof (struct patmgr_info)) + { + printk ("PATMGR%d: Invalid write count\n", dev); + return RET_ERROR (EIO); + } + + /* + * If everything went OK, there should be a preallocated buffer in the + * mailbox and a client waiting. + */ + + DISABLE_INTR (flags); + + if (mbox[dev] && !msg_direction[dev]) + { + COPY_FROM_USER (&((char *) mbox[dev])[4], buf, 4, count - 4); + msg_direction[dev] = S_TO_A; + + if (SOMEONE_WAITING (appl_proc, appl_wait_flag)) + { + WAKE_UP (appl_proc, appl_wait_flag); + } + } + + RESTORE_INTR (flags); + + return count; +} + +int +pmgr_access (int dev, struct patmgr_info *rec) +{ + unsigned long flags; + int err = 0; + + DISABLE_INTR (flags); + + if (mbox[dev]) + printk (" PATMGR: Server %d mbox full. Why?\n", dev); + else + { + rec->key = PM_K_COMMAND; + mbox[dev] = rec; + msg_direction[dev] = A_TO_S; + + if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev])) + { + WAKE_UP (server_procs[dev], server_wait_flag[dev]); + } + + DO_SLEEP (appl_proc, appl_wait_flag, 0); + + if (msg_direction[dev] != S_TO_A) + { + rec->key = PM_ERROR; + rec->parm1 = RET_ERROR (EIO); + } + else if (rec->key == PM_ERROR) + { + err = rec->parm1; + if (err > 0) + err = -err; + } + + mbox[dev] = NULL; + msg_direction[dev] = 0; + } + + RESTORE_INTR (flags); + + return err; +} + +int +pmgr_inform (int dev, int event, unsigned long p1, unsigned long p2, + unsigned long p3, unsigned long p4) +{ + unsigned long flags; + int err = 0; + + if (!pmgr_opened[dev]) + return 0; + + DISABLE_INTR (flags); + + if (mbox[dev]) + printk (" PATMGR: Server %d mbox full. Why?\n", dev); + else + { + mbox[dev] = + (struct patmgr_info *) KERNEL_MALLOC (sizeof (struct patmgr_info)); + + mbox[dev]->key = PM_K_EVENT; + mbox[dev]->command = event; + mbox[dev]->parm1 = p1; + mbox[dev]->parm2 = p2; + mbox[dev]->parm3 = p3; + msg_direction[dev] = A_TO_S; + + if (SOMEONE_WAITING (server_procs[dev], server_wait_flag[dev])) + { + WAKE_UP (server_procs[dev], server_wait_flag[dev]); + } + + DO_SLEEP (appl_proc, appl_wait_flag, 0); + if (mbox[dev]) + KERNEL_FREE (mbox[dev]); + mbox[dev] = NULL; + msg_direction[dev] = 0; + } + + RESTORE_INTR (flags); + + return err; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb.h new file mode 100644 index 000000000..bb8ae12d7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb.h @@ -0,0 +1,28 @@ +#define DSP_RESET (sbc_base + 0x6) +#define DSP_READ (sbc_base + 0xA) +#define DSP_WRITE (sbc_base + 0xC) +#define DSP_COMMAND (sbc_base + 0xC) +#define DSP_STATUS (sbc_base + 0xC) +#define DSP_DATA_AVAIL (sbc_base + 0xE) +#define DSP_DATA_AVL16 (sbc_base + 0xF) +#define MIXER_ADDR (sbc_base + 0x4) +#define MIXER_DATA (sbc_base + 0x5) +#define OPL3_LEFT (sbc_base + 0x0) +#define OPL3_RIGHT (sbc_base + 0x2) +#define OPL3_BOTH (sbc_base + 0x8) +/* DSP Commands */ + +#define DSP_CMD_SPKON 0xD1 +#define DSP_CMD_SPKOFF 0xD3 +#define DSP_CMD_DMAON 0xD0 +#define DSP_CMD_DMAOFF 0xD4 + +#define IMODE_NONE 0 +#define IMODE_OUTPUT 1 +#define IMODE_INPUT 2 +#define IMODE_INIT 3 +#define IMODE_MIDI 4 + +#define NORMAL_MIDI 0 +#define UART_MIDI 1 + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_dsp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_dsp.c new file mode 100644 index 000000000..02040c7bd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_dsp.c @@ -0,0 +1,608 @@ +/* + * sound/sb16_dsp.c + * + * The low level driver for the SoundBlaster DSP chip. + * + * (C) 1993 J. Schubert (jsb@sth.ruhr-uni-bochum.de) + * + * based on SB-driver by (C) Hannu Savolainen + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define DEB(x) +#define DEB1(x) +/* +#define DEB_DMARES +*/ +#include "sound_config.h" +#include "sb.h" +#include "sb_mixer.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_AUDIO) && !defined(EXCLUDE_SBPRO) + +extern int sbc_base; + +static int sb16_dsp_ok = 0; /* Set to 1 after successful initialization */ +static int dsp_16bit = 0; +static int dsp_stereo = 0; +static int dsp_current_speed = 8000;/*DSP_DEFAULT_SPEED;*/ +static int dsp_busy = 0; +static int dma16, dma8; +static unsigned long dsp_count = 0; + +static int irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT or + IMODE_NONE */ +static int my_dev = 0; + +static volatile int intr_active = 0; + +static int sb16_dsp_open (int dev, int mode); +static void sb16_dsp_close (int dev); +static void sb16_dsp_output_block (int dev, unsigned long buf, int count,int intrflag, int dma_restart); +static void sb16_dsp_start_input (int dev, unsigned long buf, int count,int intrflag, int dma_restart); +static int sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local); +static int sb16_dsp_prepare_for_input (int dev, int bsize, int bcount); +static int sb16_dsp_prepare_for_output (int dev, int bsize, int bcount); +static void sb16_dsp_reset (int dev); +static void sb16_dsp_halt (int dev); +static int dsp_set_speed (int); +static int dsp_set_stereo (int); +static void dsp_cleanup (void); +int sb_reset_dsp (void); + +static struct audio_operations sb16_dsp_operations = +{ + "SoundBlaster 16", + sb16_dsp_open, + sb16_dsp_close, + sb16_dsp_output_block, + sb16_dsp_start_input, + sb16_dsp_ioctl, + sb16_dsp_prepare_for_input, + sb16_dsp_prepare_for_output, + sb16_dsp_reset, + sb16_dsp_halt, + NULL, + NULL +}; + +static int sb_dsp_command01 (unsigned char val) +{ + int i=1<<16; + + while(--i & (!INB (DSP_STATUS) & 0x80)); + if(!i) + printk("SB16 sb_dsp_command01 Timeout\n"); + return sb_dsp_command(val); +} + +static int wait_data_avail(int t) +{ + int loopc=5000000; + t+=GET_TIME(); + do { + if(INB(DSP_DATA_AVAIL) & 0x80) + return 1; + } while(--loopc && GET_TIME() 44100) mode = 44100; + dsp_current_speed=mode; + } + return mode; +} + +static int dsp_set_stereo(int mode) +{ +DEB(printk("dsp_set_stereo(%d)\n",mode)); + + dsp_stereo=mode; + + return mode; +} + +static int dsp_set_bits(int arg) { +DEB(printk("dsp_set_bits(%d)\n",arg)); + + if (arg) + switch(arg) { + case 8: + dsp_16bit=0; break; + case 16: + dsp_16bit=1; break; + default: + return RET_ERROR(EINVAL); + } + return dsp_16bit? 16:8; +} + +static int +sb16_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg,int local) +{ + switch (cmd) { + case SOUND_PCM_WRITE_RATE: + if(local) + return dsp_set_speed(arg); + return IOCTL_OUT (arg, dsp_set_speed (IOCTL_IN (arg))); + + case SOUND_PCM_READ_RATE: + if(local) + return dsp_current_speed; + return IOCTL_OUT (arg, dsp_current_speed); + + case SNDCTL_DSP_STEREO: + if (local) + return dsp_set_stereo(arg); + return IOCTL_OUT (arg, dsp_set_stereo(IOCTL_IN(arg))); + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return dsp_set_stereo(arg-1)+1; + return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1); + + case SOUND_PCM_READ_CHANNELS: + if (local) + return dsp_stereo+1; + return IOCTL_OUT (arg, dsp_stereo+1); + + case SNDCTL_DSP_SAMPLESIZE: + if (local) + return dsp_set_bits (arg); + return IOCTL_OUT (arg, dsp_set_bits (IOCTL_IN (arg))); + + case SOUND_PCM_READ_BITS: + if (local) + return dsp_16bit?16:8; + return IOCTL_OUT (arg, dsp_16bit?16:8); + + case SOUND_PCM_WRITE_FILTER: /* NOT YET IMPLEMENTED */ + if (IOCTL_IN (arg) > 1) + return IOCTL_OUT (arg, RET_ERROR (EINVAL)); + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static int +sb16_dsp_open (int dev, int mode) +{ + int retval; + +DEB(printk("sb16_dsp_open()\n")); + if (!sb16_dsp_ok) + { + printk ("SB16 Error: SoundBlaster board not installed\n"); + return RET_ERROR(ENXIO); + } + + if (intr_active) + return RET_ERROR(EBUSY); + + retval = sb_get_irq (); + if (retval<0) + return retval; + + if (ALLOC_DMA_CHN (dma8)) + { + printk ("SB16: Unable to grab DMA%d\n", dma8); + sb_free_irq(); + return RET_ERROR(EBUSY); + } + + if (dma16 != dma8) + if (ALLOC_DMA_CHN (dma16)) + { + printk ("SB16: Unable to grab DMA%d\n", dma16); + sb_free_irq(); + RELEASE_DMA_CHN (dma8); + return RET_ERROR(EBUSY); + } + + dsp_ini2(); + + irq_mode = IMODE_NONE; + dsp_busy = 1; + + return 0; +} + +static void +sb16_dsp_close (int dev) +{ + unsigned long flags; +DEB(printk("sb16_dsp_close()\n")); + sb_dsp_command01(0xd9); + sb_dsp_command01(0xd5); + + DISABLE_INTR (flags); + RELEASE_DMA_CHN (dma8); + + if (dma16 != dma8) + RELEASE_DMA_CHN (dma16); + sb_free_irq (); + dsp_cleanup (); + dsp_busy = 0; + RESTORE_INTR (flags); +} + +static void +sb16_dsp_output_block (int dev, unsigned long buf, int count,int intrflag, int dma_restart) +{ + unsigned long flags, cnt; + + cnt = count; + if (dsp_16bit) + cnt >>= 1; + cnt--; + +#ifdef DEB_DMARES + printk("output_block: %x %d %d\n",buf,count,intrflag); + if(intrflag) { + int pos,chan=sound_dsp_dmachan[dev]; + DISABLE_INTR (flags); + clear_dma_ff(chan); + disable_dma(chan); + pos=get_dma_residue(chan); + enable_dma(chan); + RESTORE_INTR (flags); + printk("dmapos=%d %x\n",pos,pos); + } +#endif + if (sound_dma_automode[dev] && + intrflag && + cnt == dsp_count) { + irq_mode = IMODE_OUTPUT; + intr_active = 1; + return; /* Auto mode on. No need to react */ + } + DISABLE_INTR (flags); + + if (dma_restart) + { + sb16_dsp_halt(dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + } + sb_dsp_command (0x41); + sb_dsp_command ((unsigned char)((dsp_current_speed >> 8) & 0xff)); + sb_dsp_command ((unsigned char)(dsp_current_speed & 0xff)); + sb_dsp_command ((unsigned char)(dsp_16bit ? 0xb6 : 0xc6)); + sb_dsp_command ((unsigned char)((dsp_stereo ? 0x20 : 0) + + (dsp_16bit ? 0x10:0))); + sb_dsp_command01 ((unsigned char)(cnt&0xff)); + sb_dsp_command ((unsigned char)(cnt>>8)); + /* sb_dsp_command (0); + sb_dsp_command (0); */ + + RESTORE_INTR (flags); + dsp_count=cnt; + irq_mode = IMODE_OUTPUT; + intr_active = 1; +} + +static void +sb16_dsp_start_input (int dev, unsigned long buf, int count,int intrflag, int dma_restart) +{ + unsigned long flags, cnt; + + cnt = count; + if (dsp_16bit) + cnt >>= 1; + cnt--; + +#ifdef DEB_DMARES +printk("start_input: %x %d %d\n",buf,count,intrflag); + if(intrflag) { + int pos,chan=sound_dsp_dmachan[dev]; + DISABLE_INTR (flags); + clear_dma_ff(chan); + disable_dma(chan); + pos=get_dma_residue(chan); + enable_dma(chan); + RESTORE_INTR (flags); + printk("dmapos=%d %x\n",pos,pos); + } +#endif + if (sound_dma_automode[dev] && + intrflag && + cnt == dsp_count) { + irq_mode = IMODE_INPUT; + intr_active = 1; + return; /* Auto mode on. No need to react */ + } + DISABLE_INTR (flags); + + if (dma_restart) + { + sb16_dsp_halt(dev); + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + } + + sb_dsp_command (0x42); + sb_dsp_command ((unsigned char)((dsp_current_speed >> 8) & 0xff)); + sb_dsp_command ((unsigned char)(dsp_current_speed & 0xff)); + sb_dsp_command ((unsigned char)(dsp_16bit ? 0xbe : 0xce)); + sb_dsp_command ((unsigned char)((dsp_stereo ? 0x20 : 0) + + (dsp_16bit ? 0x10:0))); + sb_dsp_command01 ((unsigned char)(cnt&0xff)); + sb_dsp_command ((unsigned char)(cnt>>8)); + + /* sb_dsp_command (0); + sb_dsp_command (0); */ + RESTORE_INTR (flags); + dsp_count=cnt; + irq_mode = IMODE_INPUT; + intr_active = 1; +} + +static int +sb16_dsp_prepare_for_input (int dev, int bsize, int bcount) +{ + sound_dsp_dmachan[my_dev] = dsp_16bit? dma16:dma8; + dsp_count = 0; + dsp_cleanup (); + return 0; +} + +static int +sb16_dsp_prepare_for_output (int dev, int bsize, int bcount) +{ + sound_dsp_dmachan[my_dev] = dsp_16bit? dma16:dma8; + dsp_count = 0; + dsp_cleanup (); + return 0; +} + +static void +dsp_cleanup (void) +{ + irq_mode = IMODE_NONE; + intr_active = 0; +} + +static void +sb16_dsp_reset (int dev) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + sb_reset_dsp (); + dsp_cleanup (); + + RESTORE_INTR (flags); +} + +static void +sb16_dsp_halt (int dev) +{ + if (dsp_16bit) + { + sb_dsp_command01(0xd9); + sb_dsp_command01(0xd5); + } + else + { + sb_dsp_command01(0xda); + sb_dsp_command01(0xd0); + } +} + +static void +set_irq_hw(int level) { + int ival; + switch(level) { + case 5: + ival=2; break; + case 7: + ival=4; break; + case 10: + ival=8; break; + default: + printk("SB16_IRQ_LEVEL %d does not exist\n",level); + return; + } + sb_setmixer(IRQ_NR,ival); +} + +long +sb16_dsp_init (long mem_start, struct address_info *hw_config) +{ + int i, major, minor; + + major = minor = 0; + sb_dsp_command (0xe1); /* Get version */ + + for (i = 1000; i; i--) { + if (INB (DSP_DATA_AVAIL) & 0x80) + { /* wait for Data Ready */ + if (major == 0) + major = INB (DSP_READ); + else + { + minor = INB (DSP_READ); + break; + } + } + } + +#ifndef SCO + sprintf (sb16_dsp_operations.name, "SoundBlaster 16 %d.%d", major, minor); +#endif + + printk (" <%s>", sb16_dsp_operations.name); + + if (num_dspdevs < MAX_DSP_DEV) + { + dsp_devs[my_dev = num_dspdevs++] = &sb16_dsp_operations; + sound_dsp_dmachan[my_dev] = hw_config->dma; + sound_buffcounts[my_dev] = 1; + sound_buffsizes[my_dev] = DSP_BUFFSIZE; + sound_dma_automode[my_dev] = 1; + } + else + printk ("SB: Too many DSP devices available\n"); + sb16_dsp_ok = 1; + return mem_start; +} + +int +sb16_dsp_detect (struct address_info *hw_config) +{ + struct address_info *sb_config; + + if (sb16_dsp_ok) + return 1; /* Already initialized */ + + if (!(sb_config=sound_getconf(SNDCARD_SB))) + { + printk("SB16 Error: Plain SB not configured\n"); + return 0; + } + + if (sbc_base != hw_config->io_base) + printk("Warning! SB16 I/O != SB I/O\n"); + + /* sb_setmixer(OPSW,0xf); + if(sb_getmixer(OPSW)!=0xf) + return 0; */ + + if (!sb_reset_dsp ()) + return 0; + + if (hw_config->irq != sb_config->irq) + { + printk("SB16 Error: Invalid IRQ number %d/%d\n", + sb_config->irq, hw_config->irq); + return 0; + } + + if (hw_config->dma < 4) + if (hw_config->dma != sb_config->dma) + { + printk("SB16 Error: Invalid DMA channel %d/%d\n", + sb_config->dma, hw_config->dma); + return 0; + } + + dma16 = hw_config->dma; + dma8 = sb_config->dma; + set_irq_hw(hw_config->irq); + sb_setmixer(DMA_NR, (1<dma) | (1<dma)); + + DEB(printk ("SoundBlaster 16: IRQ %d DMA %d OK\n",hw_config->irq,hw_config->dma)); + +/* + dsp_showmessage(0xe3,99); +*/ + sb16_dsp_ok = 1; + return 1; +} + +void +sb16_dsp_interrupt (int unused) +{ + int data; + data = INB (DSP_DATA_AVL16); /* Interrupt acknowledge */ + + if (intr_active) + switch (irq_mode) + { + case IMODE_OUTPUT: + intr_active = 0; + DMAbuf_outputintr (my_dev, 1); + break; + + case IMODE_INPUT: + intr_active = 0; + DMAbuf_inputintr (my_dev); + break; + + default: + printk ("SoundBlaster: Unexpected interrupt\n"); + } +} +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_midi.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_midi.c new file mode 100644 index 000000000..2fc475ae9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb16_midi.c @@ -0,0 +1,314 @@ +/* + * sound/sb16_midi.c + * + * The low level driver for the MPU-401 UART emulation of the SB16. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#if !defined(EXCLUDE_SB) && !defined(EXCLUDE_SB16) && !defined(EXCLUDE_MIDI) + +#define DATAPORT (sb16midi_base) /* MPU-401 Data I/O Port on IBM */ +#define COMDPORT (sb16midi_base+1) /* MPU-401 Command Port on IBM */ +#define STATPORT (sb16midi_base+1) /* MPU-401 Status Port on IBM */ + +#define sb16midi_status() INB(STATPORT) +#define input_avail() (!(sb16midi_status()&INPUT_AVAIL)) +#define output_ready() (!(sb16midi_status()&OUTPUT_READY)) +#define sb16midi_cmd(cmd) OUTB(cmd, COMDPORT) +#define sb16midi_read() INB(DATAPORT) +#define sb16midi_write(byte) OUTB(byte, DATAPORT) + +#define OUTPUT_READY 0x40 /* Mask for Data Read Redy Bit */ +#define INPUT_AVAIL 0x80 /* Mask for Data Send Ready Bit */ +#define MPU_ACK 0xFE /* MPU-401 Acknowledge Response */ +#define MPU_RESET 0xFF /* MPU-401 Total Reset Command */ +#define UART_MODE_ON 0x3F /* MPU-401 "Dumb UART Mode" */ + +static int sb16midi_opened = 0; +static int sb16midi_base = 0x330; +static int sb16midi_detected = 0; +static int my_dev; + +static int reset_sb16midi (void); +static void (*midi_input_intr) (int dev, unsigned char data); + +static void +sb16midi_input_loop (void) +{ + int count; + + count = 10; + + while (count) /* Not timed out */ + if (input_avail ()) + { + unsigned char c = sb16midi_read (); + + count = 100; + + if (sb16midi_opened & OPEN_READ) + midi_input_intr (my_dev, c); + } + else + while (!input_avail () && count) + count--; +} + +void +sb16midiintr (int unit) +{ + if (input_avail ()) + sb16midi_input_loop (); +} + +/* + * It looks like there is no input interrupts in the UART mode. Let's try + * polling. + */ + +static void +poll_sb16midi (unsigned long dummy) +{ + unsigned long flags; + + DEFINE_TIMER(sb16midi_timer, poll_sb16midi); + + if (!(sb16midi_opened & OPEN_READ)) + return; /* No longer required */ + + DISABLE_INTR (flags); + + if (input_avail ()) + sb16midi_input_loop (); + + ACTIVATE_TIMER(sb16midi_timer, poll_sb16midi, 1); /* Come back later */ + + RESTORE_INTR (flags); +} + +static int +sb16midi_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + if (sb16midi_opened) + { + return RET_ERROR (EBUSY); + } + + sb16midi_input_loop (); + + midi_input_intr = input; + sb16midi_opened = mode; + poll_sb16midi (0); /* Enable input polling */ + + return 0; +} + +static void +sb16midi_close (int dev) +{ + sb16midi_opened = 0; +} + +static int +sb16midi_out (int dev, unsigned char midi_byte) +{ + int timeout; + unsigned long flags; + + /* + * Test for input since pending input seems to block the output. + */ + + DISABLE_INTR (flags); + + if (input_avail ()) + sb16midi_input_loop (); + + RESTORE_INTR (flags); + + /* + * Sometimes it takes about 13000 loops before the output becomes ready + * (After reset). Normally it takes just about 10 loops. + */ + + for (timeout = 30000; timeout > 0 && !output_ready (); timeout--); /* Wait */ + + if (!output_ready ()) + { + printk ("MPU-401: Timeout\n"); + return 0; + } + + sb16midi_write (midi_byte); + return 1; +} + +static int +sb16midi_command (int dev, unsigned char midi_byte) +{ + return 1; +} + +static int +sb16midi_start_read (int dev) +{ + return 0; +} + +static int +sb16midi_end_read (int dev) +{ + return 0; +} + +static int +sb16midi_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EINVAL); +} + +static void +sb16midi_kick (int dev) +{ +} + +static int +sb16midi_buffer_status (int dev) +{ + return 0; /* No data in buffers */ +} + +static struct midi_operations sb16midi_operations = +{ + {"SoundBlaster MPU-401", 0, 0, SNDCARD_SB16MIDI}, + sb16midi_open, + sb16midi_close, + sb16midi_ioctl, + sb16midi_out, + sb16midi_start_read, + sb16midi_end_read, + sb16midi_kick, + sb16midi_command, + sb16midi_buffer_status +}; + + +long +attach_sb16midi (long mem_start, struct address_info *hw_config) +{ + int ok, timeout; + unsigned long flags; + + sb16midi_base = hw_config->io_base; + + if (!sb16midi_detected) + return RET_ERROR (EIO); + + DISABLE_INTR (flags); + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + sb16midi_cmd (UART_MODE_ON); + + ok = 0; + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail ()) + if (sb16midi_read () == MPU_ACK) + ok = 1; + + RESTORE_INTR (flags); + + printk (" "); + + my_dev = num_midis; + midi_devs[num_midis++] = &sb16midi_operations; + return mem_start; +} + +static int +reset_sb16midi (void) +{ + unsigned long flags; + int ok, timeout, n; + + /* + * Send the RESET command. Try again if no success at the first time. + */ + + ok = 0; + + DISABLE_INTR (flags); + + for (n = 0; n < 2 && !ok; n++) + { + for (timeout = 30000; timeout < 0 && !output_ready (); timeout--); /* Wait */ + sb16midi_cmd (MPU_RESET); /* Send MPU-401 RESET Command */ + + /* + * Wait at least 25 msec. This method is not accurate so let's make the + * loop bit longer. Cannot sleep since this is called during boot. + */ + + for (timeout = 50000; timeout > 0 && !ok; timeout--) + if (input_avail ()) + if (sb16midi_read () == MPU_ACK) + ok = 1; + + } + + sb16midi_opened = 0; + if (ok) + sb16midi_input_loop (); /* Flush input before enabling interrupts */ + + RESTORE_INTR (flags); + + return ok; +} + + +int +probe_sb16midi (struct address_info *hw_config) +{ + int ok = 0; + + sb16midi_base = hw_config->io_base; + + if (sb_get_irq () < 0) + return 0; + + ok = reset_sb16midi (); + + sb16midi_detected = ok; + return ok; +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_card.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_card.c new file mode 100644 index 000000000..ef90b4bef --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_card.c @@ -0,0 +1,52 @@ +/* + * sound/sb_card.c + * + * Detection routine for the SoundBlaster cards. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) + +long +attach_sb_card (long mem_start, struct address_info *hw_config) +{ +#if !defined(EXCLUDE_AUDIO) || !defined(EXCLUDE_MIDI) + if (!sb_dsp_detect (hw_config)) + return mem_start; + mem_start = sb_dsp_init (mem_start, hw_config); +#endif + + return mem_start; +} + +int +probe_sb (struct address_info *hw_config) +{ + return sb_dsp_detect (hw_config); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_dsp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_dsp.c new file mode 100644 index 000000000..d6297e5b6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_dsp.c @@ -0,0 +1,739 @@ +/* + * sound/sb_dsp.c + * + * The low level driver for the SoundBlaster DSP chip. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) + +#include "sb.h" +#include "sb_mixer.h" +#undef SB_TEST_IRQ + +int sbc_base = 0; +static int sbc_irq = 0; + +/* + * The DSP channel can be used either for input or output. Variable + * 'sb_irq_mode' will be set when the program calls read or write first time + * after open. Current version doesn't support mode changes without closing + * and reopening the device. Support for this feature may be implemented in a + * future version of this driver. + */ + +int sb_dsp_ok = 0; /* Set to 1 after successful initialization */ +static int midi_disabled = 0; +int sb_dsp_highspeed = 0; +static int major=1, minor=0; /* DSP version */ +static int dsp_stereo = 0; +static int dsp_current_speed = DSP_DEFAULT_SPEED; +static int sb16 = 0; +static int irq_verified = 0; + +int sb_midi_mode = NORMAL_MIDI; +int sb_midi_busy = 0; /* 1 if the process has output to MIDI */ +int sb_dsp_busy = 0; + +volatile int sb_irq_mode = IMODE_NONE; /* IMODE_INPUT, IMODE_OUTPUT + * or IMODE_NONE */ +static volatile int irq_ok = 0; + +int sb_dsp_model = 1; /* 1=SB, 2=SB Pro */ +int sb_duplex_midi = 0; +static int my_dev = 0; + +volatile int sb_intr_active = 0; + +static int dsp_speed (int); +static int dsp_set_stereo (int mode); +int sb_dsp_command (unsigned char val); + +#if !defined(EXCLUDE_MIDI) || !defined(EXCLUDE_AUDIO) + +/* Common code for the midi and pcm functions */ + +int +sb_dsp_command (unsigned char val) +{ + int i, limit; + + limit = GET_TIME () + 10; /* The timeout is 0.1 secods */ + + /* + * Note! the i<500000 is an emergency exit. The sb_dsp_command() is sometimes + * called while interrupts are disabled. This means that the timer is + * disabled also. However the timeout situation is a abnormal condition. + * Normally the DSP should be ready to accept commands after just couple of + * loops. + */ + + for (i = 0; i < 500000 && GET_TIME () < limit; i++) + { + if ((INB (DSP_STATUS) & 0x80) == 0) + { + OUTB (val, DSP_COMMAND); + return 1; + } + } + + printk ("SoundBlaster: DSP Command(%x) Timeout.\n", val); + printk ("IRQ conflict???\n"); + return 0; +} + +void +sbintr (int unit) +{ + int status, data; + +#ifndef EXCLUDE_SBPRO + if (sb16) + { + unsigned char src = sb_getmixer (IRQ_STAT); /* Interrupt source register */ + +#ifndef EXCLUDE_SB16 + if (src & 3) sb16_dsp_interrupt(unit); + +#ifndef EXCLUDE_MIDI + if (src & 4) sb16midiintr (unit); /* MPU401 interrupt */ +#endif + +#endif + + if (!(src & 1)) + return; /* Not a DSP interupt */ + } +#endif + + status = INB (DSP_DATA_AVAIL);/* Clear interrupt */ + + if (sb_intr_active) + switch (sb_irq_mode) + { + case IMODE_OUTPUT: + sb_intr_active = 0; + DMAbuf_outputintr (my_dev, 1); + break; + + case IMODE_INPUT: + sb_intr_active = 0; + DMAbuf_inputintr (my_dev); + /* A complete buffer has been input. Let's start new one */ + break; + + case IMODE_INIT: + sb_intr_active = 0; + irq_ok = 1; + break; + + case IMODE_MIDI: + printk ("+"); + data = INB (DSP_READ); + printk ("%x", data); + + break; + + default: + printk ("SoundBlaster: Unexpected interrupt\n"); + } +} + +static int sb_irq_usecount = 0; + +int +sb_get_irq(void) +{ + int ok; + + if (!sb_irq_usecount) + if ((ok=snd_set_irq_handler(sbc_irq, sbintr))<0) return ok; + + sb_irq_usecount++; + + return 0; +} + +void +sb_free_irq(void) +{ + if (!sb_irq_usecount) return; + + sb_irq_usecount--; + + if (!sb_irq_usecount) snd_release_irq(sbc_irq); +} + +int +sb_reset_dsp (void) +{ + int loopc; + + OUTB (1, DSP_RESET); + tenmicrosec (); + OUTB (0, DSP_RESET); + tenmicrosec (); + tenmicrosec (); + tenmicrosec (); + + for (loopc = 0; loopc < 1000 && !(INB (DSP_DATA_AVAIL) & 0x80); loopc++); /* Wait for data + * available status */ + + if (INB (DSP_READ) != 0xAA) + return 0; /* Sorry */ + + return 1; +} + +#endif + +#ifndef EXCLUDE_AUDIO + +static void +dsp_speaker (char state) +{ + if (state) + sb_dsp_command (DSP_CMD_SPKON); + else + sb_dsp_command (DSP_CMD_SPKOFF); +} + +static int +dsp_speed (int speed) +{ + unsigned char tconst; + unsigned long flags; + + if (speed < 4000) + speed = 4000; + + if (speed > 44100) + speed = 44100; /* Invalid speed */ + + if (sb_dsp_model == 1 && speed > 22050) + speed = 22050; + /* SB Classic doesn't support higher speed */ + + + if (dsp_stereo && speed > 22050) + speed = 22050; + /* Max. stereo speed is 22050 */ + + if ((speed > 22050) && sb_midi_busy) + { + printk ("SB Warning: High speed DSP not possible simultaneously with MIDI output\n"); + speed = 22050; + } + + if (dsp_stereo) + speed *= 2; + + /* Now the speed should be valid */ + + if (speed > 22050) + { /* High speed mode */ + int tmp; + + tconst = (unsigned char) ((65536 - + ((256000000+speed/2) / speed)) >> 8); + sb_dsp_highspeed = 1; + + DISABLE_INTR (flags); + if (sb_dsp_command (0x40)) + sb_dsp_command (tconst); + RESTORE_INTR (flags); + + tmp = 65536 - (tconst << 8); + speed = (256000000+tmp/2) / tmp; + } + else + { + int tmp; + + sb_dsp_highspeed = 0; + tconst = (256 - ((1000000+speed/2) / speed)) & 0xff; + + DISABLE_INTR (flags); + if (sb_dsp_command (0x40)) /* Set time constant */ + sb_dsp_command (tconst); + RESTORE_INTR (flags); + + tmp = 256 - tconst; + speed = (1000000+tmp/2) / tmp; + } + + if (dsp_stereo) + speed /= 2; + + dsp_current_speed = speed; + return speed; +} + +static int +dsp_set_stereo (int mode) +{ + dsp_stereo = 0; + +#ifdef EXCLUDE_SBPRO + return 0; +#else + if (sb_dsp_model == 1 || sb16) + return 0; /* Sorry no stereo */ + + if (mode && sb_midi_busy) + { + printk ("SB Warning: Stereo DSP not possible simultaneously with MIDI output\n"); + return 0; + } + + dsp_stereo = !!mode; + return dsp_stereo; +#endif +} + +static void +sb_dsp_output_block (int dev, unsigned long buf, int count, + int intrflag, int restart_dma) +{ + unsigned long flags; + + if (!sb_irq_mode) + dsp_speaker (ON); + + sb_irq_mode = IMODE_OUTPUT; + DMAbuf_start_dma (dev, buf, count, DMA_MODE_WRITE); + + if (sound_dsp_dmachan[dev] > 3) + count >>= 1; + count--; + + if (sb_dsp_highspeed) + { + DISABLE_INTR (flags); + if (sb_dsp_command (0x48)) /* High speed size */ + { + sb_dsp_command ((unsigned char)(count & 0xff)); + sb_dsp_command ((unsigned char)((count >> 8) & 0xff)); + sb_dsp_command (0x91); /* High speed 8 bit DAC */ + } + else + printk ("SB Error: Unable to start (high speed) DAC\n"); + RESTORE_INTR (flags); + } + else + { + DISABLE_INTR (flags); + if (sb_dsp_command (0x14)) /* 8-bit DAC (DMA) */ + { + sb_dsp_command ((unsigned char)(count & 0xff)); + sb_dsp_command ((unsigned char)((count >> 8) & 0xff)); + } + else + printk ("SB Error: Unable to start DAC\n"); + RESTORE_INTR (flags); + } + sb_intr_active = 1; +} + +static void +sb_dsp_start_input (int dev, unsigned long buf, int count, int intrflag, + int restart_dma) +{ + /* Start a DMA input to the buffer pointed by dmaqtail */ + + unsigned long flags; + + if (!sb_irq_mode) + dsp_speaker (OFF); + + sb_irq_mode = IMODE_INPUT; + DMAbuf_start_dma (dev, buf, count, DMA_MODE_READ); + + if (sound_dsp_dmachan[dev] > 3) + count >>= 1; + count--; + + if (sb_dsp_highspeed) + { + DISABLE_INTR (flags); + if (sb_dsp_command (0x48)) /* High speed size */ + { + sb_dsp_command ((unsigned char)(count & 0xff)); + sb_dsp_command ((unsigned char)((count >> 8) & 0xff)); + sb_dsp_command (0x99); /* High speed 8 bit ADC */ + } + else + printk ("SB Error: Unable to start (high speed) ADC\n"); + RESTORE_INTR (flags); + } + else + { + DISABLE_INTR (flags); + if (sb_dsp_command (0x24)) /* 8-bit ADC (DMA) */ + { + sb_dsp_command ((unsigned char)(count & 0xff)); + sb_dsp_command ((unsigned char)((count >> 8) & 0xff)); + } + else + printk ("SB Error: Unable to start ADC\n"); + RESTORE_INTR (flags); + } + + sb_intr_active = 1; +} + +static void +dsp_cleanup (void) +{ + sb_intr_active = 0; +} + +static int +sb_dsp_prepare_for_input (int dev, int bsize, int bcount) +{ + dsp_cleanup (); + dsp_speaker (OFF); + + if (major == 3) /* SB Pro */ + { + if (dsp_stereo) + sb_dsp_command(0xa8); + else + sb_dsp_command(0xa0); + + dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels + * changes */ + } + return 0; +} + +static int +sb_dsp_prepare_for_output (int dev, int bsize, int bcount) +{ + dsp_cleanup (); + dsp_speaker (ON); + +#ifndef EXCLUDE_SBPRO + if (major == 3) /* SB Pro */ + { + sb_mixer_set_stereo(dsp_stereo); + dsp_speed (dsp_current_speed);/* Speed must be recalculated if #channels + * changes */ + } +#endif + return 0; +} + +static void +sb_dsp_halt_xfer (int dev) +{ +} + +static int +verify_irq (void) +{ +#if 0 + DEFINE_WAIT_QUEUE(testq, testf); + + irq_ok = 0; + + if (sb_get_irq () == -1) + { + printk ("*** SB Error: Irq %d already in use\n", sbc_irq); + return 0; + } + + + sb_irq_mode = IMODE_INIT; + + sb_dsp_command (0xf2); /* This should cause immediate interrupt */ + + DO_SLEEP(testq, testf, HZ / 5); + + sb_free_irq(); + + if (!irq_ok) + { + printk ("SB Warning: IRQ%d test not passed!", sbc_irq); + irq_ok = 1; + } +#else + irq_ok = 1; +#endif + return irq_ok; +} + +static int +sb_dsp_open (int dev, int mode) +{ + int retval; + + if (!sb_dsp_ok) + { + printk ("SB Error: SoundBlaster board not installed\n"); + return RET_ERROR (ENXIO); + } + + if (sb_intr_active || (sb_midi_busy && sb_midi_mode == UART_MIDI)) + { + printk ("SB: PCM not possible during MIDI input\n"); + return RET_ERROR (EBUSY); + } + + if (!irq_verified) + { + verify_irq(); + irq_verified = 1; + } + else + if (!irq_ok) + printk("SB Warning: Incorrect IRQ setting %d\n", + sbc_irq); + + retval = sb_get_irq (); + if (retval) + return retval; + + if (!DMAbuf_open_dma (dev)) + { + sb_free_irq (); + printk ("SB: DMA Busy\n"); + return RET_ERROR (EBUSY); + } + + sb_irq_mode = IMODE_NONE; + + sb_dsp_busy = 1; + + return 0; +} + +static void +sb_dsp_close (int dev) +{ + DMAbuf_close_dma (dev); + sb_free_irq (); + dsp_cleanup (); + dsp_speaker (OFF); + sb_dsp_busy = 0; + sb_dsp_highspeed = 0; +} + +static int +sb_dsp_ioctl (int dev, unsigned int cmd, unsigned int arg, int local) +{ + switch (cmd) + { + case SOUND_PCM_WRITE_RATE: + if (local) + return dsp_speed (arg); + return IOCTL_OUT (arg, dsp_speed (IOCTL_IN (arg))); + break; + + case SOUND_PCM_READ_RATE: + if (local) + return dsp_current_speed; + return IOCTL_OUT (arg, dsp_current_speed); + break; + + case SOUND_PCM_WRITE_CHANNELS: + if (local) + return dsp_set_stereo (arg - 1) + 1; + return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg) - 1) + 1); + break; + + case SOUND_PCM_READ_CHANNELS: + if (local) + return dsp_stereo + 1; + return IOCTL_OUT (arg, dsp_stereo + 1); + break; + + case SNDCTL_DSP_STEREO: + if (local) + return dsp_set_stereo (arg); + return IOCTL_OUT (arg, dsp_set_stereo (IOCTL_IN (arg))); + break; + + case SOUND_PCM_WRITE_BITS: + case SOUND_PCM_READ_BITS: + if (local) + return 8; + return IOCTL_OUT (arg, 8);/* Only 8 bits/sample supported */ + break; + + case SOUND_PCM_WRITE_FILTER: + case SOUND_PCM_READ_FILTER: + return RET_ERROR (EINVAL); + break; + + default: + return RET_ERROR (EINVAL); + } + + return RET_ERROR (EINVAL); +} + +static void +sb_dsp_reset (int dev) +{ + unsigned long flags; + + DISABLE_INTR (flags); + + sb_reset_dsp (); + dsp_cleanup (); + + RESTORE_INTR (flags); +} + +#endif + +int +sb_dsp_detect (struct address_info *hw_config) +{ + sbc_base = hw_config->io_base; + sbc_irq = hw_config->irq; + + if (sb_dsp_ok) + return 0; /* Already initialized */ + + if (!sb_reset_dsp ()) + return 0; + + return 1; /* Detected */ +} + +#ifndef EXCLUDE_AUDIO +static struct audio_operations sb_dsp_operations = +{ + "SoundBlaster", + sb_dsp_open, + sb_dsp_close, + sb_dsp_output_block, + sb_dsp_start_input, + sb_dsp_ioctl, + sb_dsp_prepare_for_input, + sb_dsp_prepare_for_output, + sb_dsp_reset, + sb_dsp_halt_xfer, + NULL, /* has_output_drained */ + NULL /* copy_from_user */ +}; + +#endif + +long +sb_dsp_init (long mem_start, struct address_info *hw_config) +{ + int i; + + major = minor = 0; + sb_dsp_command (0xe1); /* Get version */ + + for (i = 1000; i; i--) + { + if (INB (DSP_DATA_AVAIL) & 0x80) + { /* wait for Data Ready */ + if (major == 0) + major = INB (DSP_READ); + else + { + minor = INB (DSP_READ); + break; + } + } + } + + if (major == 2 || major == 3) + sb_duplex_midi = 1; + + if (major == 4) + sb16 = 1; + + if (major >= 3) + sb_dsp_model = 2; + +#ifndef EXCLUDE_SBPRO + if (major >= 3) + sb_mixer_init(major); +#endif + +#ifndef EXCLUDE_YM3812 + if (major > 3 || (major == 3 && minor > 0)) /* SB Pro2 or later */ + { + enable_opl3_mode (OPL3_LEFT, OPL3_RIGHT, OPL3_BOTH); + } +#endif + + if (major >= 3) + { +#ifndef SCO + sprintf (sb_dsp_operations.name, "SoundBlaster Pro %d.%d", major, minor); +#endif + } + else + { +#ifndef SCO + sprintf (sb_dsp_operations.name, "SoundBlaster %d.%d", major, minor); +#endif + } + + printk (" <%s>", sb_dsp_operations.name); + +#ifndef EXCLUDE_AUDIO +# if !defined(EXCLUDE_SB16) && !defined(EXCLUDE_SBPRO) + if (!sb16) /* There is a better driver for SB16 */ +# endif + if (num_dspdevs < MAX_DSP_DEV) + { + dsp_devs[my_dev = num_dspdevs++] = &sb_dsp_operations; + sound_buffcounts[my_dev] = DSP_BUFFCOUNT; + sound_buffsizes[my_dev] = DSP_BUFFSIZE; + sound_dsp_dmachan[my_dev] = hw_config->dma; + sound_dma_automode[my_dev] = 0; + } + else + printk ("SB: Too many DSP devices available\n"); +#endif + +#ifndef EXCLUDE_MIDI + if (!midi_disabled && !sb16) /* Midi don't work in the SB emulation mode + * of PAS, SB16 has better midi interface */ + sb_midi_init(major); +#endif + + sb_dsp_ok = 1; + return mem_start; +} + +void +sb_dsp_disable_midi (void) +{ + midi_disabled = 1; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_midi.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_midi.c new file mode 100644 index 000000000..b5bdd2114 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_midi.c @@ -0,0 +1,197 @@ +/* + * sound/sb_dsp.c + * + * The low level driver for the SoundBlaster DS chips. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_MIDI) + +#include "sb.h" +#undef SB_TEST_IRQ + +/* + * The DSP channel can be used either for input or output. Variable + * 'sb_irq_mode' will be set when the program calls read or write first time + * after open. Current version doesn't support mode changes without closing + * and reopening the device. Support for this feature may be implemented in a + * future version of this driver. + */ + +extern int sb_dsp_ok; /* Set to 1 after successful initialization */ + +extern int sb_midi_mode; +extern int sb_midi_busy; /* 1 if the process has output to MIDI */ +extern int sb_dsp_busy; +extern int sb_dsp_highspeed; + +extern volatile int sb_irq_mode; /* IMODE_INPUT, IMODE_OUTPUT + * or IMODE_NONE */ +extern int sb_dsp_model; /* 1=SB, 2=SB Pro */ +extern int sb_duplex_midi; +extern int sb_intr_active; + +static int +sb_midi_open (int dev, int mode, + void (*input) (int dev, unsigned char data), + void (*output) (int dev) +) +{ + int ret; + + if (!sb_dsp_ok) + { + printk ("SB Error: MIDI hardware not installed\n"); + return RET_ERROR (ENXIO); + } + + if (mode != OPEN_WRITE && !sb_duplex_midi) + { + if (num_midis == 1) + printk ("SoundBlaster: Midi input not currently supported\n"); + return RET_ERROR (EPERM); + } + + sb_midi_mode = NORMAL_MIDI; + if (mode != OPEN_WRITE) + { + if (sb_dsp_busy || sb_intr_active) + return RET_ERROR (EBUSY); + sb_midi_mode = UART_MIDI; + } + + if (sb_dsp_highspeed) + { + printk ("SB Error: Midi output not possible during stereo or high speed audio\n"); + return RET_ERROR (EBUSY); + } + + if (sb_midi_mode == UART_MIDI) + { + sb_irq_mode = IMODE_MIDI; + + sb_reset_dsp (); + + if (!sb_dsp_command (0x35)) + return RET_ERROR (EIO); /* Enter the UART mode */ + sb_intr_active = 1; + + if ((ret = sb_get_irq ()) < 0) + { + sb_reset_dsp (); + return 0; /* IRQ not free */ + } + } + + sb_midi_busy = 1; + + return 0; +} + +static void +sb_midi_close (int dev) +{ + if (sb_midi_mode == UART_MIDI) + { + sb_reset_dsp (); /* The only way to kill the UART mode */ + sb_free_irq (); + } + sb_intr_active = 0; + sb_midi_busy = 0; +} + +static int +sb_midi_out (int dev, unsigned char midi_byte) +{ + unsigned long flags; + + sb_midi_busy = 1; /* Kill all notes after close */ + + if (sb_midi_mode == NORMAL_MIDI) + { + DISABLE_INTR (flags); + if (sb_dsp_command (0x38)) + sb_dsp_command (midi_byte); + else + printk ("SB Error: Unable to send a MIDI byte\n"); + RESTORE_INTR (flags); + } + else + sb_dsp_command (midi_byte); /* UART write */ + + return 1; +} + +static int +sb_midi_start_read (int dev) +{ + if (sb_midi_mode != UART_MIDI) + { + printk ("SoundBlaster: MIDI input not implemented.\n"); + return RET_ERROR (EPERM); + } + return 0; +} + +static int +sb_midi_end_read (int dev) +{ + if (sb_midi_mode == UART_MIDI) + { + sb_reset_dsp (); + sb_intr_active = 0; + } + return 0; +} + +static int +sb_midi_ioctl (int dev, unsigned cmd, unsigned arg) +{ + return RET_ERROR (EPERM); +} + +static struct midi_operations sb_midi_operations = +{ + {"SoundBlaster", 0, 0, SNDCARD_SB}, + sb_midi_open, + sb_midi_close, + sb_midi_ioctl, + sb_midi_out, + sb_midi_start_read, + sb_midi_end_read, + NULL, /* Kick */ + NULL, /* command */ + NULL /* buffer_status */ +}; + +void +sb_midi_init(int model) +{ + midi_devs[num_midis++] = &sb_midi_operations; +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.c new file mode 100644 index 000000000..afd49c548 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.c @@ -0,0 +1,353 @@ + +/* + * sound/sb_mixer.c + * + * The low level mixer driver for the SoundBlaster Pro and SB16 cards. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#if defined(CONFIGURE_SOUNDCARD) && !defined(EXCLUDE_SB) && !defined(EXCLUDE_SBPRO) +#define __SB_MIXER_C__ + +#include "sb.h" +#include "sb_mixer.h" +#undef SB_TEST_IRQ + +extern int sbc_base; + +static int mixer_initialized = 0; + +static int supported_rec_devices; +static int supported_devices; +static int recmask = 0; +static int mixer_model; +static int mixer_caps; +static mixer_tab *iomap; + +void +sb_setmixer (unsigned int port, unsigned int value) +{ + unsigned long flags; + + DISABLE_INTR(flags); + OUTB ((unsigned char)(port & 0xff), MIXER_ADDR); /* Select register */ + tenmicrosec (); + OUTB ((unsigned char)(value & 0xff), MIXER_DATA); + tenmicrosec (); + RESTORE_INTR(flags); +} + +int +sb_getmixer (unsigned int port) +{ + int val; + unsigned long flags; + + DISABLE_INTR(flags); + OUTB ((unsigned char)(port & 0xff), MIXER_ADDR); /* Select register */ + tenmicrosec (); + val = INB (MIXER_DATA); + tenmicrosec (); + RESTORE_INTR(flags); + + return val; +} + +void +sb_mixer_set_stereo(int mode) +{ + if (!mixer_initialized) return; + + sb_setmixer (OUT_FILTER, ((sb_getmixer (OUT_FILTER) & ~STEREO_DAC) + | (mode ? STEREO_DAC : MONO_DAC))); +} + +static int +detect_mixer (void) +{ + /* + * Detect the mixer by changing parameters of two volume channels. If the + * values read back match with the values written, the mixer is there (is + * it?) + */ + sb_setmixer (FM_VOL, 0xff); + sb_setmixer (VOC_VOL, 0x33); + + if (sb_getmixer (FM_VOL) != 0xff) + return 0; /* No match */ + if (sb_getmixer (VOC_VOL) != 0x33) + return 0; + + return 1; +} + +static void +change_bits(unsigned char *regval, int dev, int chn, int newval) +{ + unsigned char mask; + int shift; + + mask = (1 << (*iomap)[dev][chn].nbits)-1; + newval = ((newval * mask) + 50) / 100; /* Scale it */ + + shift = (*iomap)[dev][chn].bitoffs-(*iomap)[dev][LEFT_CHN].nbits+1; + + *regval &= ~(mask << shift); /* Filter out the previous value */ + *regval |= (newval & mask) << shift; /* Set the new value */ +} + +static int +sb_mixer_get(int dev) +{ + if (!((1<> 8; + + int regoffs; + unsigned char val; + + if (left > 100) left = 100; + if (right > 100) right = 100; + + if (dev > 31) return RET_ERROR(EINVAL); + + if (!(supported_devices & (1 << dev))) /* Not supported */ + return RET_ERROR(EINVAL); + + regoffs = (*iomap)[dev][LEFT_CHN].regno; + + if (regoffs == 0) + return RET_ERROR(EINVAL); + + val = sb_getmixer(regoffs); + change_bits(&val, dev, LEFT_CHN, left); + + levels[dev] = left|(left << 8); + + if ((*iomap)[dev][RIGHT_CHN].regno != regoffs) /* Change register */ + { + sb_setmixer(regoffs, val); /* Save the old one */ + regoffs = (*iomap)[dev][RIGHT_CHN].regno; + + if (regoffs == 0) + return left|(left << 8); /* Just left channel present */ + + val = sb_getmixer(regoffs); /* Read the new one */ + } + + change_bits(&val, dev, RIGHT_CHN, right); + sb_setmixer(regoffs, val); + + levels[dev] = left | (right << 8); + return left | (right << 8); +} + +static void +set_recsrc(int src) +{ + sb_setmixer(RECORD_SRC, (sb_getmixer(RECORD_SRC)&~7) | (src&0x7)); +} + +static int +set_recmask(int mask) +{ + int devmask, i; + unsigned char regimageL, regimageR; + + devmask = mask & supported_rec_devices; + + switch (mixer_model) + { + case 3: + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* More than one devices selected. Drop the + * previous selection */ + devmask &= ~recmask; + } + + if (devmask != SOUND_MASK_MIC && + devmask != SOUND_MASK_LINE && + devmask != SOUND_MASK_CD) + { /* More than one devices selected. Default to + * mic */ + devmask = SOUND_MASK_MIC; + } + + + if (devmask ^ recmask)/* Input source changed */ + { + switch (devmask) + { + + case SOUND_MASK_MIC: + set_recsrc (SRC_MIC); + break; + + case SOUND_MASK_LINE: + set_recsrc (SRC_LINE); + break; + + case SOUND_MASK_CD: + set_recsrc (SRC_CD); + break; + + default: + set_recsrc (SRC_MIC); + } + } + + break; + + case 4: + if (!devmask) devmask = SOUND_MASK_MIC; + + regimageL = regimageR = 0; + for (i=0;i> 8) & 0xff) == 'M') + { + if (cmd & IOC_IN) + switch (cmd & 0xff) + { + case SOUND_MIXER_RECSRC: + return IOCTL_OUT(arg, set_recmask(IOCTL_IN(arg))); + break; + + default: + return IOCTL_OUT (arg, sb_mixer_set (cmd & 0xff, IOCTL_IN (arg))); + } + else + switch (cmd & 0xff) /* Return parameters */ + { + + case SOUND_MIXER_RECSRC: + return IOCTL_OUT (arg, recmask); + break; + + case SOUND_MIXER_DEVMASK: + return IOCTL_OUT (arg, supported_devices); + break; + + case SOUND_MIXER_STEREODEVS: + return IOCTL_OUT (arg, supported_devices & + ~(SOUND_MASK_MIC|SOUND_MASK_SPEAKER)); + break; + + case SOUND_MIXER_RECMASK: + return IOCTL_OUT (arg, supported_rec_devices); + break; + + case SOUND_MIXER_CAPS: + return IOCTL_OUT (arg, mixer_caps); + break; + + default: + return IOCTL_OUT (arg, sb_mixer_get (cmd & 0xff)); + } + } + else + return RET_ERROR (EINVAL); +} + +static struct mixer_operations sb_mixer_operations = +{ + sb_mixer_ioctl +}; + +static void +sb_mixer_reset(void) +{ + int i; + + for (i = 0; i < SOUND_MIXER_NRDEVICES; i++) + sb_mixer_set (i, levels[i]); + set_recmask(SOUND_MASK_MIC); +} + +void +sb_mixer_init(int major_model) +{ + sb_setmixer(0x00, 0); /* Reset mixer */ + + if (!detect_mixer()) return; /* No mixer. Why? */ + + mixer_initialized = 1; + mixer_model = major_model; + + switch (major_model) + { + case 3: + mixer_caps = SOUND_CAP_EXCL_INPUT; + supported_devices = SBPRO_MIXER_DEVICES; + supported_rec_devices = SBPRO_RECORDING_DEVICES; + iomap = &sbpro_mix; + break; + + case 4: + mixer_caps = 0; + supported_devices = SB16_MIXER_DEVICES; + supported_rec_devices = SB16_RECORDING_DEVICES; + iomap = &sb16_mix; + break; + + default: + printk("SB Warning: Unsupported mixer type\n"); + return; + } + + mixer_devs[num_mixers++] = &sb_mixer_operations; + sb_mixer_reset(); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.h new file mode 100644 index 000000000..304af6423 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sb_mixer.h @@ -0,0 +1,172 @@ +/* + * sound/sb_mixer.h + * + * Definitions for the SB Pro and SB16 mixers + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ +#define SBPRO_RECORDING_DEVICES (SOUND_MASK_LINE | SOUND_MASK_MIC | SOUND_MASK_CD) + +#define SBPRO_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_VOLUME) + +#define SB16_RECORDING_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD) + +#define SB16_MIXER_DEVICES (SOUND_MASK_SYNTH | SOUND_MASK_PCM | SOUND_MASK_SPEAKER | SOUND_MASK_LINE | SOUND_MASK_MIC | \ + SOUND_MASK_CD | SOUND_MASK_RECLEV | \ + SOUND_MASK_VOLUME | SOUND_MASK_BASS | SOUND_MASK_TREBLE) + +/* + * Mixer registers + * + * NOTE! RECORD_SRC == IN_FILTER + */ + +/* + * Mixer registers of SB Pro + */ +#define VOC_VOL 0x04 +#define MIC_VOL 0x0A +#define MIC_MIX 0x0A +#define RECORD_SRC 0x0C +#define IN_FILTER 0x0C +#define OUT_FILTER 0x0E +#define MASTER_VOL 0x22 +#define FM_VOL 0x26 +#define CD_VOL 0x28 +#define LINE_VOL 0x2E +#define IRQ_NR 0x80 +#define DMA_NR 0x81 +#define IRQ_STAT 0x82 +#define OPSW 0x3c + +#define FREQ_HI (1 << 3)/* Use High-frequency ANFI filters */ +#define FREQ_LOW 0 /* Use Low-frequency ANFI filters */ +#define FILT_ON 0 /* Yes, 0 to turn it on, 1 for off */ +#define FILT_OFF (1 << 5) + +#define MONO_DAC 0x00 +#define STEREO_DAC 0x02 + +/* + * Mixer registers of SB16 + */ +#define SB16_IMASK_L 0x3d +#define SB16_IMASK_R 0x3e + +#define LEFT_CHN 0 +#define RIGHT_CHN 1 + +struct mixer_def { + unsigned int regno: 8; + unsigned int bitoffs:4; + unsigned int nbits:4; +}; + + +typedef struct mixer_def mixer_tab[32][2]; +typedef struct mixer_def mixer_ent; + +#define MIX_ENT(name, reg_l, bit_l, len_l, reg_r, bit_r, len_r) \ + {{reg_l, bit_l, len_l}, {reg_r, bit_r, len_r}} + +#ifdef __SB_MIXER_C__ +mixer_tab sbpro_mix = { +MIX_ENT(SOUND_MIXER_VOLUME, 0x22, 7, 4, 0x22, 3, 4), +MIX_ENT(SOUND_MIXER_BASS, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_TREBLE, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_SYNTH, 0x26, 7, 4, 0x26, 3, 4), +MIX_ENT(SOUND_MIXER_PCM, 0x04, 7, 4, 0x04, 3, 4), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x2e, 7, 4, 0x2e, 3, 4), +MIX_ENT(SOUND_MIXER_MIC, 0x0a, 2, 3, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_CD, 0x28, 7, 4, 0x28, 3, 4), +MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0x00, 0, 0, 0x00, 0, 0) +}; + +mixer_tab sb16_mix = { +MIX_ENT(SOUND_MIXER_VOLUME, 0x30, 7, 5, 0x31, 7, 5), +MIX_ENT(SOUND_MIXER_BASS, 0x46, 7, 4, 0x47, 7, 4), +MIX_ENT(SOUND_MIXER_TREBLE, 0x44, 7, 4, 0x45, 7, 4), +MIX_ENT(SOUND_MIXER_SYNTH, 0x34, 7, 5, 0x35, 7, 5), +MIX_ENT(SOUND_MIXER_PCM, 0x32, 7, 5, 0x33, 7, 5), +MIX_ENT(SOUND_MIXER_SPEAKER, 0x3b, 7, 2, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_LINE, 0x38, 7, 5, 0x39, 7, 5), +MIX_ENT(SOUND_MIXER_MIC, 0x3a, 7, 5, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_CD, 0x36, 7, 5, 0x37, 7, 5), +MIX_ENT(SOUND_MIXER_IMIX, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_ALTPCM, 0x00, 0, 0, 0x00, 0, 0), +MIX_ENT(SOUND_MIXER_RECLEV, 0x3f, 7, 2, 0x40, 7, 2) +}; + +static unsigned short levels[SOUND_MIXER_NRDEVICES] = +{ + 0x5a5a, /* Master Volume */ + 0x3232, /* Bass */ + 0x3232, /* Treble */ + 0x4b4b, /* FM */ + 0x4b4b, /* PCM */ + 0x4b4b, /* PC Speaker */ + 0x4b4b, /* Ext Line */ + 0x0000, /* Mic */ + 0x4b4b, /* CD */ + 0x4b4b, /* Recording monitor */ + 0x4b4b, /* SB PCM */ + 0x4b4b}; /* Recording level */ + +static unsigned char sb16_recmasks_L[SOUND_MIXER_NRDEVICES] = +{ + 0x00, /* SOUND_MIXER_VOLUME */ + 0x00, /* SOUND_MIXER_BASS */ + 0x00, /* SOUND_MIXER_TREBLE */ + 0x40, /* SOUND_MIXER_SYNTH */ + 0x00, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x10, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x04, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00 /* SOUND_MIXER_RECLEV */ +}; + +static unsigned char sb16_recmasks_R[SOUND_MIXER_NRDEVICES] = +{ + 0x00, /* SOUND_MIXER_VOLUME */ + 0x00, /* SOUND_MIXER_BASS */ + 0x00, /* SOUND_MIXER_TREBLE */ + 0x20, /* SOUND_MIXER_SYNTH */ + 0x00, /* SOUND_MIXER_PCM */ + 0x00, /* SOUND_MIXER_SPEAKER */ + 0x08, /* SOUND_MIXER_LINE */ + 0x01, /* SOUND_MIXER_MIC */ + 0x02, /* SOUND_MIXER_CD */ + 0x00, /* SOUND_MIXER_IMIX */ + 0x00, /* SOUND_MIXER_ALTPCM */ + 0x00 /* SOUND_MIXER_RECLEV */ +}; +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sequencer.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sequencer.c new file mode 100644 index 000000000..9024922a5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sequencer.c @@ -0,0 +1,1152 @@ +/* + * sound/sequencer.c + * + * The sequencer personality manager. + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#define SEQUENCER_C +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#ifndef EXCLUDE_SEQUENCER + +static int sequencer_ok = 0; + +DEFINE_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); +/* DEFINE_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); */ +#define midi_sleeper seq_sleeper +#define midi_sleep_flag seq_sleep_flag + +static int midi_opened[MAX_MIDI_DEV] = +{0}; /* 1 if the process has opened MIDI */ +static int midi_written[MAX_MIDI_DEV] = +{0}; + +long seq_time = 0; /* Reference point for the timer */ + +#include "tuning.h" + +#define EV_SZ 8 +#define IEV_SZ 4 +static unsigned char *queue = NULL; /* SEQ_MAX_QUEUE * EV_SZ bytes */ +static unsigned char *iqueue = NULL; /* SEQ_MAX_QUEUE * IEV_SZ bytes */ + +static volatile int qhead = 0, qtail = 0, qlen = 0; +static volatile int iqhead = 0, iqtail = 0, iqlen = 0; +static volatile int seq_playing = 0; +static int sequencer_busy = 0; +static int output_treshold; +static unsigned synth_open_mask; + +static int seq_queue (unsigned char *note); +static void seq_startplay (void); +static int seq_sync (void); +static void seq_reset (void); +static int pmgr_present[MAX_SYNTH_DEV] = +{0}; + +#if MAX_SYNTH_DEV > 15 +#error Too many synthesizer devices +#endif + +int +sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + int c = count, p = 0; + + dev = dev >> 4; + + if (dev) /* Patch manager device */ + return pmgr_read (dev - 1, file, buf, count); + + while (c > 3) + { + if (!iqlen) + { + DO_SLEEP (midi_sleeper, midi_sleep_flag, 0); + + if (!iqlen) + return count - c; + } + + COPY_TO_USER (buf, p, &iqueue[iqhead * IEV_SZ], IEV_SZ); + p += 4; + c -= 4; + + iqhead = (iqhead + 1) % SEQ_MAX_QUEUE; + iqlen--; + } + + return count - c; +} + +static void +sequencer_midi_output (int dev) +{ + /* Currently NOP */ +} + +static void +copy_to_input (unsigned char *event) +{ + unsigned long flags; + + if (iqlen >= (SEQ_MAX_QUEUE - 1)) + return; /* Overflow */ + + memcpy (&iqueue[iqtail * IEV_SZ], event, IEV_SZ); + iqlen++; + iqtail = (iqtail + 1) % SEQ_MAX_QUEUE; + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (midi_sleeper, midi_sleep_flag)) + { + WAKE_UP (midi_sleeper, midi_sleep_flag); + } + RESTORE_INTR (flags); +} + +static void +sequencer_midi_input (int dev, unsigned char data) +{ + int tstamp; + unsigned char event[4]; + + if (data == 0xfe) /* Active sensing */ + return; /* Ignore */ + + tstamp = GET_TIME () - seq_time; /* Time since open() */ + tstamp = (tstamp << 8) | SEQ_WAIT; + + copy_to_input ((unsigned char *) &tstamp); + + event[0] = SEQ_MIDIPUTC; + event[1] = data; + event[2] = dev; + event[3] = 0; + + copy_to_input (event); +} + +int +sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + unsigned char event[EV_SZ], ev_code; + int p = 0, c, ev_size; + int err; + int mode = file->mode & O_ACCMODE; + + dev = dev >> 4; + + DEB (printk ("sequencer_write(dev=%d, count=%d)\n", dev, count)); + + if (mode == OPEN_READ) + return RET_ERROR (EIO); + + if (dev) /* Patch manager device */ + return pmgr_write (dev - 1, file, buf, count); + + c = count; + + while (c >= 4) + { + COPY_FROM_USER (event, buf, p, 4); + ev_code = event[0]; + + if (ev_code == SEQ_FULLSIZE) + { + int err; + + dev = *(unsigned short *) &event[2]; + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (!(synth_open_mask & (1 << dev))) + return RET_ERROR (ENXIO); + + err = synth_devs[dev]->load_patch (dev, *(short *) &event[0], buf, p + 4, c, 0); + if (err < 0) + return err; + + return err; + } + + if (ev_code == SEQ_EXTENDED || ev_code == SEQ_PRIVATE) + { + + ev_size = 8; + + if (c < ev_size) + { + if (!seq_playing) + seq_startplay (); + return count - c; + } + + COPY_FROM_USER (&event[4], buf, p + 4, 4); + + } + else + ev_size = 4; + + if (event[0] == SEQ_MIDIPUTC) + { + + if (!midi_opened[event[2]]) + { + int mode; + int dev = event[2]; + + if (dev >= num_midis) + { + printk ("Sequencer Error: Nonexistent MIDI device %d\n", dev); + return RET_ERROR (ENXIO); + } + + mode = file->mode & O_ACCMODE; + + if ((err = midi_devs[dev]->open (dev, mode, + sequencer_midi_input, sequencer_midi_output)) < 0) + { + seq_reset (); + printk ("Sequencer Error: Unable to open Midi #%d\n", dev); + return err; + } + + midi_opened[dev] = 1; + } + + } + + if (!seq_queue (event)) + { + + if (!seq_playing) + seq_startplay (); + return count - c; + } + + p += ev_size; + c -= ev_size; + } + + if (!seq_playing) + seq_startplay (); + + return count; +} + +static int +seq_queue (unsigned char *note) +{ + + /* Test if there is space in the queue */ + + if (qlen >= SEQ_MAX_QUEUE) + if (!seq_playing) + seq_startplay (); /* Give chance to drain the queue */ + + if (qlen >= SEQ_MAX_QUEUE && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + { + /* Sleep until there is enough space on the queue */ + DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); + } + + if (qlen >= SEQ_MAX_QUEUE) + return 0; /* To be sure */ + + memcpy (&queue[qtail * EV_SZ], note, EV_SZ); + + qtail = (qtail + 1) % SEQ_MAX_QUEUE; + qlen++; + + return 1; +} + +static int +extended_event (unsigned char *q) +{ + int dev = q[2]; + + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (!(synth_open_mask & (1 << dev))) + return RET_ERROR (ENXIO); + + switch (q[1]) + { + case SEQ_NOTEOFF: + synth_devs[dev]->kill_note (dev, q[3], q[5]); + break; + + case SEQ_NOTEON: + if (q[4] > 127 && q[4] != 255) + return 0; + + synth_devs[dev]->start_note (dev, q[3], q[4], q[5]); + break; + + case SEQ_PGMCHANGE: + synth_devs[dev]->set_instr (dev, q[3], q[4]); + break; + + case SEQ_AFTERTOUCH: + synth_devs[dev]->aftertouch (dev, q[3], q[4]); + break; + + case SEQ_BALANCE: + synth_devs[dev]->panning (dev, q[3], (char) q[4]); + break; + + case SEQ_CONTROLLER: + synth_devs[dev]->controller (dev, q[3], q[4], *(short *) &q[5]); + break; + + default: + return RET_ERROR (EINVAL); + } + + return 0; +} + +static void +seq_startplay (void) +{ + int this_one; + unsigned long *delay; + unsigned char *q; + + while (qlen > 0) + { + qhead = ((this_one = qhead) + 1) % SEQ_MAX_QUEUE; + qlen--; + + q = &queue[this_one*EV_SZ]; + + switch (q[0]) + { + case SEQ_NOTEOFF: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->kill_note (0, q[1], q[3]); + break; + + case SEQ_NOTEON: + if (q[4] < 128 || q[4] == 255) + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->start_note (0, q[1], q[2], q[3]); + break; + + case SEQ_WAIT: + delay = (unsigned long *) q; /* Bytes 1 to 3 are containing the + * delay in GET_TIME() */ + *delay = (*delay >> 8) & 0xffffff; + + if (*delay > 0) + { + long time; + + seq_playing = 1; + time = *delay; + + request_sound_timer (time); + + if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + { + unsigned long flags; + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + { + WAKE_UP (seq_sleeper, seq_sleep_flag); + } + RESTORE_INTR (flags); + } + return; /* Stop here. Timer routine will continue + * playing after the delay */ + } + break; + + case SEQ_PGMCHANGE: + if (synth_open_mask & (1 << 0)) + if (synth_devs[0]) + synth_devs[0]->set_instr (0, q[1], q[2]); + break; + + case SEQ_SYNCTIMER: /* Reset timer */ + seq_time = GET_TIME (); + break; + + case SEQ_MIDIPUTC: /* Put a midi character */ + if (midi_opened[q[2]]) + { + int dev; + + dev = q[2]; + + if (!midi_devs[dev]->putc (dev, q[1])) + { + /* + * Output FIFO is full. Wait one timer cycle and try again. + */ + + qlen++; + qhead = this_one; /* Restore queue */ + seq_playing = 1; + request_sound_timer (-1); + return; + } + else + midi_written[dev] = 1; + } + break; + + case SEQ_ECHO: + copy_to_input (q); /* Echo back to the process */ + break; + + case SEQ_PRIVATE: + if (q[1] < num_synths) + synth_devs[q[1]]->hw_control (q[1], q); + break; + + case SEQ_EXTENDED: + extended_event (q); + break; + + default:; + } + + } + + seq_playing = 0; + + if ((SEQ_MAX_QUEUE - qlen) >= output_treshold) + { + unsigned long flags; + + DISABLE_INTR (flags); + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + { + WAKE_UP (seq_sleeper, seq_sleep_flag); + } + RESTORE_INTR (flags); + } + +} + +int +sequencer_open (int dev, struct fileinfo *file) + { + int retval, mode, i; + + dev = dev >> 4; + mode = file->mode & O_ACCMODE; + + DEB (printk ("sequencer_open(dev=%d)\n", dev)); + + if (!sequencer_ok) + { + printk ("Soundcard: Sequencer not initialized\n"); + return RET_ERROR (ENXIO); + } + + if (dev) /* Patch manager device */ + { + int err; + + dev--; + if (pmgr_present[dev]) + return RET_ERROR (EBUSY); + if ((err = pmgr_open (dev)) < 0) + return err; /* Failed */ + + pmgr_present[dev] = 1; + return err; + } + + if (sequencer_busy) + { + printk ("Sequencer busy\n"); + return RET_ERROR (EBUSY); + } + + if (!(num_synths + num_midis)) + return RET_ERROR (ENXIO); + + synth_open_mask = 0; + + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + for (i = 0; i < num_synths; i++) /* Open synth devices */ + if (synth_devs[i]->open (i, mode) < 0) + printk ("Sequencer: Warning! Cannot open synth device #%d\n", i); + else + synth_open_mask |= (1 << i); + + seq_time = GET_TIME (); + + for (i = 0; i < num_midis; i++) + { + midi_opened[i] = 0; + midi_written[i] = 0; + } + + if (mode == OPEN_READ || mode == OPEN_READWRITE) + { /* Initialize midi input devices */ + if (!num_midis) + { + printk ("Sequencer: No Midi devices. Input not possible\n"); + return RET_ERROR (ENXIO); + } + + for (i = 0; i < num_midis; i++) + { + if ((retval = midi_devs[i]->open (i, mode, + sequencer_midi_input, sequencer_midi_output)) >= 0) + midi_opened[i] = 1; + } + } + + sequencer_busy = 1; + RESET_WAIT_QUEUE (seq_sleeper, seq_sleep_flag); + RESET_WAIT_QUEUE (midi_sleeper, midi_sleep_flag); + output_treshold = SEQ_MAX_QUEUE / 2; + + for (i = 0; i < num_synths; i++) + if (pmgr_present[i]) + pmgr_inform (i, PM_E_OPENED, 0, 0, 0, 0); + + return 0; + } + +void +seq_drain_midi_queues (void) +{ + int i, n; + + /* + * Give the Midi drivers time to drain their output queues + */ + + n = 1; + + while (!PROCESS_ABORTING (midi_sleeper, midi_sleep_flag) && n) + { + n = 0; + + for (i = 0; i < num_midis; i++) + if (midi_opened[i] && midi_written[i]) + if (midi_devs[i]->buffer_status != NULL) + if (midi_devs[i]->buffer_status (i)) + n++; + + /* + * Let's have a delay + */ + if (n) + { + DO_SLEEP (seq_sleeper, seq_sleep_flag, HZ / 10); + } + } +} + +void +sequencer_release (int dev, struct fileinfo *file) + { + int i; + int mode = file->mode & O_ACCMODE; + + dev = dev >> 4; + + DEB (printk ("sequencer_release(dev=%d)\n", dev)); + + if (dev) /* Patch manager device */ + { + dev--; + pmgr_release (dev); + pmgr_present[dev] = 0; + return; + } + + /* + * Wait until the queue is empty + */ + + while (!PROCESS_ABORTING (seq_sleeper, seq_sleep_flag) && qlen) + { + seq_sync (); + } + + if (mode != OPEN_READ) + seq_drain_midi_queues (); /* Ensure the output queues are empty */ + seq_reset (); + if (mode != OPEN_READ) + seq_drain_midi_queues (); /* Flush the all notes off messages */ + + for (i = 0; i < num_midis; i++) + if (midi_opened[i]) + midi_devs[i]->close (i); + + if (mode == OPEN_WRITE || mode == OPEN_READWRITE) + for (i = 0; i < num_synths; i++) + if (synth_open_mask & (1 << i)) /* Actually opened */ + if (synth_devs[i]) + synth_devs[i]->close (i); + + for (i = 0; i < num_synths; i++) + if (pmgr_present[i]) + pmgr_inform (i, PM_E_CLOSED, 0, 0, 0, 0); + + sequencer_busy = 0; + } + +static int +seq_sync (void) +{ + if (qlen && !seq_playing && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) + seq_startplay (); + + if (qlen && !SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) /* Queue not empty */ + { + DO_SLEEP (seq_sleeper, seq_sleep_flag, 0); + } + + return qlen; +} + +static void +midi_outc (int dev, unsigned char data) +{ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ + + int n; + + /* This routine sends one byte to the Midi channel. */ + /* If the output Fifo is full, it waits until there */ + /* is space in the queue */ + + n = 300; /* Timeout in jiffies */ + + while (n && !midi_devs[dev]->putc (dev, data)) + { + DO_SLEEP (seq_sleeper, seq_sleep_flag, 4); + n--; + } +} + +static void +seq_reset (void) +{ + /* + * NOTE! Calls sleep(). Don't call this from interrupt. + */ + + int i, chn; + + sound_stop_timer (); + + qlen = qhead = qtail = 0; + iqlen = iqhead = iqtail = 0; + + for (i = 0; i < num_synths; i++) + if (synth_open_mask & (1 << i)) + if (synth_devs[i]) + synth_devs[i]->reset (i); + + for (i = 0; i < num_midis; i++) + if (midi_written[i]) /* Midi used. Some notes may still be playing */ + { + for (chn = 0; chn < 16; chn++) + { + midi_outc (i, + (unsigned char)(0xb0 + (chn & 0xff))); /* Channel msg */ + midi_outc (i, 0x7b);/* All notes off */ + midi_outc (i, 0); /* Dummy parameter */ + } + + midi_devs[i]->close (i); + + midi_written[i] = 0; + midi_opened[i] = 0; + } + + seq_playing = 0; + + if (SOMEONE_WAITING (seq_sleeper, seq_sleep_flag)) + printk ("Sequencer Warning: Unexpected sleeping process\n"); + +} + +int +sequencer_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg) +{ + int midi_dev, orig_dev; + int mode = file->mode & O_ACCMODE; + + orig_dev = dev = dev >> 4; + + switch (cmd) + { + + case SNDCTL_SEQ_SYNC: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + if (mode == OPEN_READ) + return 0; + while (qlen && !PROCESS_ABORTING (seq_sleeper, seq_sleep_flag)) + seq_sync (); + return 0; + break; + + case SNDCTL_SEQ_RESET: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + seq_reset (); + return 0; + break; + + case SNDCTL_SEQ_TESTMIDI: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + midi_dev = IOCTL_IN (arg); + if (midi_dev >= num_midis) + return RET_ERROR (ENXIO); + + if (!midi_opened[midi_dev]) + { + int err, mode; + + mode = file->mode & O_ACCMODE; + if ((err = midi_devs[midi_dev]->open (midi_dev, mode, + sequencer_midi_input, + sequencer_midi_output)) < 0) + return err; + } + + midi_opened[midi_dev] = 1; + + return 0; + break; + + case SNDCTL_SEQ_GETINCOUNT: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + if (mode == OPEN_WRITE) + return 0; + return IOCTL_OUT (arg, iqlen); + break; + + case SNDCTL_SEQ_GETOUTCOUNT: + + if (mode == OPEN_READ) + return 0; + return IOCTL_OUT (arg, SEQ_MAX_QUEUE - qlen); + break; + + case SNDCTL_SEQ_CTRLRATE: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + /* If *arg == 0, just return the current rate */ + return IOCTL_OUT (arg, HZ); + break; + + case SNDCTL_SEQ_RESETSAMPLES: + dev = IOCTL_IN (arg); + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return RET_ERROR (EBUSY); + + if (!orig_dev && pmgr_present[dev]) + pmgr_inform (dev, PM_E_PATCH_RESET, 0, 0, 0, 0); + + return synth_devs[dev]->ioctl (dev, cmd, arg); + break; + + case SNDCTL_SEQ_NRSYNTHS: + return IOCTL_OUT (arg, num_synths); + break; + + case SNDCTL_SEQ_NRMIDIS: + return IOCTL_OUT (arg, num_midis); + break; + + case SNDCTL_SYNTH_MEMAVL: + { + int dev = IOCTL_IN (arg); + + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return RET_ERROR (EBUSY); + + return IOCTL_OUT (arg, synth_devs[dev]->ioctl (dev, cmd, arg)); + } + break; + + case SNDCTL_FM_4OP_ENABLE: + { + int dev = IOCTL_IN (arg); + + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (!(synth_open_mask & (1 << dev))) + return RET_ERROR (ENXIO); + + synth_devs[dev]->ioctl (dev, cmd, arg); + return 0; + } + break; + + case SNDCTL_SYNTH_INFO: + { + struct synth_info inf; + int dev; + + IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf)); + dev = inf.device; + + if (dev < 0 || dev >= num_synths) + return RET_ERROR (ENXIO); + + if (!(synth_open_mask & (1 << dev)) && !orig_dev) + return RET_ERROR (EBUSY); + + return synth_devs[dev]->ioctl (dev, cmd, arg); + } + break; + + case SNDCTL_MIDI_INFO: + { + struct midi_info inf; + int dev; + + IOCTL_FROM_USER ((char *) &inf, (char *) arg, 0, sizeof (inf)); + dev = inf.device; + + if (dev < 0 || dev >= num_midis) + return RET_ERROR (ENXIO); + + IOCTL_TO_USER ((char *) arg, 0, (char *) &(midi_devs[dev]->info), sizeof (inf)); + return 0; + } + break; + + case SNDCTL_PMGR_IFACE: + { + struct patmgr_info *inf; + int dev, err; + + inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); + + IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); + dev = inf->device; + + if (dev < 0 || dev >= num_synths) + { + KERNEL_FREE (inf); + return RET_ERROR (ENXIO); + } + + if (!synth_devs[dev]->pmgr_interface) + { + KERNEL_FREE (inf); + return RET_ERROR (ENXIO); + } + + if ((err = synth_devs[dev]->pmgr_interface (dev, inf)) == -1) + { + KERNEL_FREE (inf); + return err; + } + + IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf)); + KERNEL_FREE (inf); + return 0; + } + break; + + case SNDCTL_PMGR_ACCESS: + { + struct patmgr_info *inf; + int dev, err; + + inf = (struct patmgr_info *) KERNEL_MALLOC (sizeof (*inf)); + + IOCTL_FROM_USER ((char *) inf, (char *) arg, 0, sizeof (*inf)); + dev = inf->device; + + if (dev < 0 || dev >= num_synths) + { + KERNEL_FREE (inf); + return RET_ERROR (ENXIO); + } + + if (!pmgr_present[dev]) + { + KERNEL_FREE (inf); + return RET_ERROR (ESRCH); + } + + if ((err = pmgr_access (dev, inf)) < 0) + { + KERNEL_FREE (inf); + return err; + } + + IOCTL_TO_USER ((char *) arg, 0, (char *) inf, sizeof (*inf)); + KERNEL_FREE (inf); + return 0; + } + break; + + case SNDCTL_SEQ_TRESHOLD: + { + int tmp = IOCTL_IN (arg); + + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + if (tmp < 1) + tmp = 1; + if (tmp >= SEQ_MAX_QUEUE) + tmp = SEQ_MAX_QUEUE - 1; + output_treshold = tmp; + return 0; + } + break; + + default: + if (dev) /* Patch manager */ + return RET_ERROR (EIO); + + if (mode == OPEN_READ) + return RET_ERROR (EIO); + + if (!synth_devs[0]) + return RET_ERROR (ENXIO); + if (!(synth_open_mask & (1 << 0))) + return RET_ERROR (ENXIO); + return synth_devs[0]->ioctl (0, cmd, arg); + break; + } + + return RET_ERROR (EINVAL); +} + +#ifdef ALLOW_SELECT +int +sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +{ + dev = dev >> 4; + + switch (sel_type) + { + case SEL_IN: + if (!iqlen) + { + select_wait (&midi_sleeper, wait); + return 0; + } + return 1; + + break; + + case SEL_OUT: + if (qlen >= SEQ_MAX_QUEUE) + { + select_wait (&seq_sleeper, wait); + return 0; + } + return 1; + break; + + case SEL_EX: + return 0; + } + + return 0; +} + +#endif + +void +sequencer_timer (void) +{ + seq_startplay (); +} + +int +note_to_freq (int note_num) +{ + + /* + * This routine converts a midi note to a frequency (multiplied by 1000) + */ + + int note, octave, note_freq; + int notes[] = + { + 261632, 277189, 293671, 311132, 329632, 349232, + 369998, 391998, 415306, 440000, 466162, 493880 + }; /* Note freq*1000 for octave 5 */ + +#define BASE_OCTAVE 5 + + octave = note_num / 12; + note = note_num % 12; + + note_freq = notes[note]; + + if (octave < BASE_OCTAVE) + note_freq >>= (BASE_OCTAVE - octave); + else if (octave > BASE_OCTAVE) + note_freq <<= (octave - BASE_OCTAVE); + + /* note_freq >>= 1; */ + + return note_freq; +} + +unsigned long +compute_finetune (unsigned long base_freq, int bend, int range) +{ + unsigned long amount; + int negative, semitones, cents; + + if (!bend) + return base_freq; + if (!range) + return base_freq; + + if (!base_freq) + return base_freq; + + if (range >= 8192) + range = 8191; + + bend = bend * range / 8192; + if (!bend) + return base_freq; + + negative = bend < 0 ? 1 : 0; + + if (bend < 0) + bend *= -1; + if (bend > range) + bend = range; + + if (bend > 2399) + bend = 2399; + + semitones = bend / 100; + cents = bend % 100; + + amount = semitone_tuning[semitones] * cent_tuning[cents] / 10000; + + if (negative) + return (base_freq * 10000) / amount; /* Bend down */ + else + return (base_freq * amount) / 10000; /* Bend up */ +} + + +long +sequencer_init (long mem_start) +{ + + sequencer_ok = 1; + PERMANENT_MALLOC(unsigned char*, queue, SEQ_MAX_QUEUE*EV_SZ, mem_start); + PERMANENT_MALLOC(unsigned char*, iqueue, SEQ_MAX_QUEUE*IEV_SZ, mem_start); + return mem_start; +} + +#else +/* Stub version */ +int +sequencer_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + return RET_ERROR (EIO); +} + +int +sequencer_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count) +{ + return RET_ERROR (EIO); +} + +int +sequencer_open (int dev, struct fileinfo *file) + { + return RET_ERROR (ENXIO); + } + +void +sequencer_release (int dev, struct fileinfo *file) + { + } +int +sequencer_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg) +{ + return RET_ERROR (EIO); +} + +int +sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig) +{ + return RET_ERROR (EIO); +} + +long +sequencer_init (long mem_start) +{ + return mem_start; +} + +int +sequencer_select (int dev, struct fileinfo *file, int sel_type, select_table * wait) +{ + return RET_ERROR (EIO); +} + +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_calls.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_calls.h new file mode 100644 index 000000000..97fb76996 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_calls.h @@ -0,0 +1,203 @@ +/* + * DMA buffer calls + */ + +int DMAbuf_open(int dev, int mode); +int DMAbuf_release(int dev, int mode); +int DMAbuf_read (int dev, snd_rw_buf *user_buf, int count); +int DMAbuf_getwrbuffer(int dev, char **buf, int *size); +int DMAbuf_getrdbuffer(int dev, char **buf, int *len); +int DMAbuf_rmchars(int dev, int buff_no, int c); +int DMAbuf_start_output(int dev, int buff_no, int l); +int DMAbuf_ioctl(int dev, unsigned int cmd, unsigned int arg, int local); +long DMAbuf_init(long mem_start); +int DMAbuf_start_dma (int dev, unsigned long physaddr, int count, int dma_mode); +int DMAbuf_open_dma (int chan); +void DMAbuf_close_dma (int chan); +void DMAbuf_reset_dma (int chan); +void DMAbuf_inputintr(int dev); +void DMAbuf_outputintr(int dev, int underflow_flag); + +/* + * System calls for /dev/dsp and /dev/audio + */ + +int audio_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int audio_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int audio_open (int dev, struct fileinfo *file); +void audio_release (int dev, struct fileinfo *file); +int audio_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg); +int audio_lseek (int dev, struct fileinfo *file, off_t offset, int orig); +long audio_init (long mem_start); + +/* + * System calls for the /dev/sequencer + */ + +int sequencer_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int sequencer_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int sequencer_open (int dev, struct fileinfo *file); +void sequencer_release (int dev, struct fileinfo *file); +int sequencer_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg); +int sequencer_lseek (int dev, struct fileinfo *file, off_t offset, int orig); +long sequencer_init (long mem_start); +void sequencer_timer(void); +int note_to_freq(int note_num); +unsigned long compute_finetune(unsigned long base_freq, int bend, int range); + +#ifdef ALLOW_SELECT +int sequencer_select(int dev, struct fileinfo *file, int sel_type, select_table * wait); +#endif + +/* + * System calls for the /dev/midi + */ + +int MIDIbuf_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int MIDIbuf_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int MIDIbuf_open (int dev, struct fileinfo *file); +void MIDIbuf_release (int dev, struct fileinfo *file); +int MIDIbuf_ioctl (int dev, struct fileinfo *file, + unsigned int cmd, unsigned int arg); +int MIDIbuf_lseek (int dev, struct fileinfo *file, off_t offset, int orig); +void MIDIbuf_bytes_received(int dev, unsigned char *buf, int count); +long MIDIbuf_init(long mem_start); + +/* + * System calls for the generic midi interface. + * + */ + +long CMIDI_init (long mem_start); +int CMIDI_open (int dev, struct fileinfo *file); +int CMIDI_write (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int CMIDI_read (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int CMIDI_close (int dev, struct fileinfo *file); + +/* + * + * Misc calls from various sources + */ + +/* From pro_midi.c */ + +long pro_midi_attach(long mem_start); +int pro_midi_open(int dev, int mode); +void pro_midi_close(int dev); +int pro_midi_write(int dev, snd_rw_buf *uio); +int pro_midi_read(int dev, snd_rw_buf *uio); + +/* From soundcard.c */ +long soundcard_init(long mem_start); +void tenmicrosec(void); +void request_sound_timer (int count); +void sound_stop_timer(void); +int snd_ioctl_return(int *addr, int value); +int snd_set_irq_handler (int interrupt_level, void(*hndlr)(int)); +void snd_release_irq(int vect); +void sound_dma_malloc(int dev); +void sound_dma_free(int dev); + +/* From sound_switch.c */ +int sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count); +int sound_open_sw (int dev, struct fileinfo *file); +void sound_release_sw (int dev, struct fileinfo *file); +int sound_ioctl_sw (int dev, struct fileinfo *file, + unsigned int cmd, unsigned long arg); + +/* From sb_dsp.c */ +int sb_dsp_detect (struct address_info *hw_config); +long sb_dsp_init (long mem_start, struct address_info *hw_config); +void sb_dsp_disable_midi(void); +int sb_get_irq(void); +void sb_free_irq(void); +int sb_dsp_command (unsigned char val); +int sb_reset_dsp (void); + +/* From sb16_dsp.c */ +void sb16_dsp_interrupt (int unused); +long sb16_dsp_init(long mem_start, struct address_info *hw_config); +int sb16_dsp_detect(struct address_info *hw_config); + +/* From sb16_midi.c */ +void sb16midiintr (int unit); +long attach_sb16midi(long mem_start, struct address_info * hw_config); +int probe_sb16midi(struct address_info *hw_config); + +/* From sb_midi.c */ +void sb_midi_init(int model); + +/* From sb_mixer.c */ +void sb_setmixer (unsigned int port, unsigned int value); +int sb_getmixer (unsigned int port); +void sb_mixer_set_stereo(int mode); +void sb_mixer_init(int major_model); + +/* From opl3.c */ +int opl3_detect (int ioaddr); +long opl3_init(long mem_start); + +/* From sb_card.c */ +long attach_sb_card(long mem_start, struct address_info *hw_config); +int probe_sb(struct address_info *hw_config); + +/* From adlib_card.c */ +long attach_adlib_card(long mem_start, struct address_info *hw_config); +int probe_adlib(struct address_info *hw_config); + +/* From pas_card.c */ +long attach_pas_card(long mem_start, struct address_info *hw_config); +int probe_pas(struct address_info *hw_config); +int pas_set_intr(int mask); +int pas_remove_intr(int mask); +unsigned char pas_read(int ioaddr); +void pas_write(unsigned char data, int ioaddr); + +/* From pas_audio.c */ +void pas_pcm_interrupt(unsigned char status, int cause); +long pas_pcm_init(long mem_start, struct address_info *hw_config); + +/* From pas_mixer.c */ +int pas_init_mixer(void); + +/* From pas_midi.c */ +long pas_midi_init(long mem_start); +void pas_midi_interrupt(void); + +/* From gus_card.c */ +long attach_gus_card(long mem_start, struct address_info * hw_config); +int probe_gus(struct address_info *hw_config); +int gus_set_midi_irq(int num); +void gusintr(int); + +/* From gus_wave.c */ +int gus_wave_detect(int baseaddr); +long gus_wave_init(long mem_start, int irq, int dma); +void gus_voice_irq(void); +unsigned char gus_read8 (int reg); +void gus_write8(int reg, unsigned int data); +void guswave_dma_irq(void); +void gus_delay(void); + +/* From gus_midi.c */ +long gus_midi_init(long mem_start); +void gus_midi_interrupt(int dummy); + +/* From mpu401.c */ +long attach_mpu401(long mem_start, struct address_info * hw_config); +int probe_mpu401(struct address_info *hw_config); + +/* From opl3.c */ +void enable_opl3_mode(int left, int right, int both); + +/* From patmgr.c */ +int pmgr_open(int dev); +void pmgr_release(int dev); +int pmgr_read (int dev, struct fileinfo *file, snd_rw_buf * buf, int count); +int pmgr_write (int dev, struct fileinfo *file, snd_rw_buf * buf, int count); +int pmgr_access(int dev, struct patmgr_info *rec); +int pmgr_inform(int dev, int event, unsigned long parm1, unsigned long parm2, + unsigned long parm3, unsigned long parm4); diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_config.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_config.h new file mode 100644 index 000000000..1cad333c9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_config.h @@ -0,0 +1,233 @@ +/* sound_config.h + * + * A driver for Soundcards, misc configuration parameters. + * + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "local.h" + + +#undef CONFIGURE_SOUNDCARD +#undef DYNAMIC_BUFFER + +#ifdef KERNEL_SOUNDCARD +#define CONFIGURE_SOUNDCARD +#define DYNAMIC_BUFFER +#undef LOADABLE_SOUNDCARD +#endif + +#ifdef EXCLUDE_SEQUENCER +#define EXCLUDE_MIDI +#define EXCLUDE_YM3812 +#define EXCLUDE_OPL3 +#endif + +#ifndef SND_DEFAULT_ENABLE +#define SND_DEFAULT_ENABLE 1 +#endif + +/** UWM - new MIDI stuff **/ + +#ifdef EXCLUDE_CHIP_MIDI +#define EXCLUDE_PRO_MIDI +#endif + +/** UWM - stuff **/ + +#if defined(EXCLUDE_SEQUENCER) && defined(EXCLUDE_AUDIO) +#undef CONFIGURE_SOUNDCARD +#endif + +#ifdef CONFIGURE_SOUNDCARD + +/* ****** IO-address, DMA and IRQ settings **** + +If your card has nonstandard I/O address or IRQ number, change defines + for the following settings in your kernel Makefile */ + +#ifndef SBC_BASE +#define SBC_BASE 0x220 /* 0x220 is the factory default. */ +#endif + +#ifndef SBC_IRQ +#define SBC_IRQ 7 /* IQR7 is the factory default. */ +#endif + +#ifndef SBC_DMA +#define SBC_DMA 1 +#endif + +#ifndef SB16_DMA +#define SB16_DMA 6 +#endif + +#ifndef SB16MIDI_BASE +#define SB16MIDI_BASE 0x300 +#endif + +#ifndef PAS_BASE +#define PAS_BASE 0x388 +#endif + +#ifndef PAS_IRQ +#define PAS_IRQ 5 +#endif + +#ifndef PAS_DMA +#define PAS_DMA 3 +#endif + +#ifndef GUS_BASE +#define GUS_BASE 0x220 +#endif + +#ifndef GUS_IRQ +#define GUS_IRQ 15 +#endif + +#ifndef GUS_MIDI_IRQ +#define GUS_MIDI_IRQ GUS_IRQ +#endif + +#ifndef GUS_DMA +#define GUS_DMA 6 +#endif + +#ifndef MPU_BASE +#define MPU_BASE 0x330 +#endif + +#ifndef MPU_IRQ +#define MPU_IRQ 6 +#endif + +#ifndef MAX_REALTIME_FACTOR +#define MAX_REALTIME_FACTOR 4 +#endif + +/************* PCM DMA buffer sizes *******************/ + +/* If you are using high playback or recording speeds, the default buffersize + is too small. DSP_BUFFSIZE must be 64k or less. + + A rule of thumb is 64k for PAS16, 32k for PAS+, 16k for SB Pro and + 4k for SB. + + If you change the DSP_BUFFSIZE, don't modify this file. + Use the make config command instead. */ + +#ifndef DSP_BUFFSIZE +#define DSP_BUFFSIZE (4096) +#endif + +#ifndef DSP_BUFFCOUNT +#define DSP_BUFFCOUNT 2 /* 2 is recommended. */ +#endif + +#define DMA_AUTOINIT 0x10 + +#define FM_MONO 0x388 /* This is the I/O address used by AdLib */ + +/* SEQ_MAX_QUEUE is the maximum number of sequencer events buffered by the + driver. (There is no need to alter this) */ +#define SEQ_MAX_QUEUE 1024 + +#define SBFM_MAXINSTR (256) /* Size of the FM Instrument + bank */ +/* 128 instruments for general MIDI setup and 16 unassigned */ + +#define SND_NDEVS 50 /* Number of supported devices */ +#define SND_DEV_CTL 0 /* Control port /dev/mixer */ +#define SND_DEV_SEQ 1 /* Sequencer output /dev/sequencer (FM + synthesizer and MIDI output) */ +#define SND_DEV_MIDIN 2 /* MIDI input /dev/midin (not implemented + yet) */ +#define SND_DEV_DSP 3 /* Digitized voice /dev/dsp */ +#define SND_DEV_AUDIO 4 /* Sparc compatible /dev/audio */ +#define SND_DEV_DSP16 5 /* Like /dev/dsp but 16 bits/sample */ +#define SND_DEV_STATUS 6 /* /dev/sndstatus */ + +/* UWM ... note add new MIDI devices here.. + * Also do not forget to add table midi_supported[] + * Minor numbers for on-chip midi devices start from 15.. and + * should be contiguous.. viz. 15,16,17.... + * ERROR!!!!!!!!! NO NO. Minor numbers above 15 are reserved!!!!!! Hannu + * Also note the max # of midi devices as MAX_MIDI_DEV + */ + +#define CMIDI_DEV_PRO 15 /* Chip midi device == /dev/pro_midi */ + +/* + * Add other midis here... + . + . + . + . + */ + +#define DSP_DEFAULT_SPEED 8000 + +#define ON 1 +#define OFF 0 + +#define MAX_DSP_DEV 4 +#define MAX_MIXER_DEV 2 +#define MAX_SYNTH_DEV 3 +#define MAX_MIDI_DEV 4 + +struct fileinfo { + int mode; /* Open mode */ + }; + +struct address_info { + int io_base; + int irq; + int dma; +}; + +/* + * Process wakeup reasons + */ +#define WK_NONE 0x00 +#define WK_WAKEUP 0x01 +#define WK_TIMEOUT 0x02 +#define WK_SIGNAL 0x04 +#define WK_SLEEP 0x08 + +#define OPEN_READ 1 +#define OPEN_WRITE 2 +#define OPEN_READWRITE 3 + +#include "os.h" +#include "sound_calls.h" +#include "dev_table.h" + +#ifndef DEB +#define DEB(x) +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_switch.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_switch.c new file mode 100644 index 000000000..0cc81508d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/sound_switch.c @@ -0,0 +1,417 @@ +/* + * sound/sound_switch.c + * + * The system call switch + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +struct sbc_device +{ + int usecount; +}; + +static struct sbc_device sbc_devices[SND_NDEVS] = {{0}}; + +static int in_use = 0; /* Total # of open device files (excluding + * minor 0) */ + +/* + * /dev/sndstatus -device + */ +static char *status_buf = NULL; +static int status_len, status_ptr; +static int status_busy = 0; + +static int +put_status (char *s) +{ + int l; + + for (l=0;l<256,s[l];l++); /* l=strlen(s); */ + + if (status_len + l >= 4000) + return 0; + + memcpy (&status_buf[status_len], s, l); + status_len += l; + + return 1; +} + +static int +put_status_int (unsigned int val, int radix) +{ + int l, v; + + static char hx[] = "0123456789abcdef"; + char buf[11]; + + if (!val) return put_status("0"); + + l = 0; + buf[10]=0; + + while (val) + { + v = val % radix; + val = val / radix; + + buf[9-l] = hx[v]; + l++; + } + + if (status_len + l >= 4000) + return 0; + + memcpy (&status_buf[status_len], &buf[10-l], l); + status_len += l; + + return 1; +} + +static void +init_status (void) +{ + /* + * Write the status information to the status_buf and update status_len. + * There is a limit of 4000 bytes for the data. + */ + + int i; + + status_ptr = 0; + + put_status ("Sound Driver:" SOUND_VERSION_STRING + " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@" + SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")" + "\n"); + + if (!put_status ("Config options: ")) + return; + if (!put_status_int(SELECTED_SOUND_OPTIONS, 16)) + return; + + if (!put_status ("\n\nHW config: \n")) + return; + + for (i = 0; i < (num_sound_drivers - 1); i++) + { + if (!supported_drivers[i].enabled) + if (!put_status ("(")) + return; + + if (!put_status ("Type ")) return; + if (!put_status_int(supported_drivers[i].card_type, 10)) return; + if (!put_status (": ")) return; + if (!put_status (supported_drivers[i].name)) return; + if (!put_status (" at 0x")) return; + if (!put_status_int(supported_drivers[i].config.io_base, 16)) return; + if (!put_status (" irq ")) return; + if (!put_status_int(supported_drivers[i].config.irq, 10)) return; + if (!put_status (" drq ")) return; + if (!put_status_int(supported_drivers[i].config.dma, 10)) return; + + if (!supported_drivers[i].enabled) + if (!put_status (")")) + return; + + if (!put_status ("\n")) + return; + } + + if (!put_status ("\nPCM devices:\n")) + return; + + for (i = 0; i < num_dspdevs; i++) + { + if (!put_status_int(i, 10)) return; + if (!put_status(": "))return; + if (!put_status(dsp_devs[i]->name))return; + if (!put_status("\n"))return; + } + + if (!put_status ("\nSynth devices:\n")) + return; + + for (i = 0; i < num_synths; i++) + { + if (!put_status_int(i, 10)) return; + if (!put_status(": "))return; + if (!put_status(synth_devs[i]->info->name))return; + if (!put_status("\n"))return; + } + + if (!put_status ("\nMidi devices:\n")) + return; + + for (i = 0; i < num_midis; i++) + { + if (!put_status_int(i, 10)) return; + if (!put_status(": "))return; + if (!put_status(midi_devs[i]->info.name))return; + if (!put_status("\n"))return; + } + + if (num_mixers) + { + if (!put_status ("\nMixer(s) installed\n")) + return; + } + else + { + if (!put_status ("\nNo mixers installed\n")) + return; + } +} + +static int +read_status (snd_rw_buf *buf, int count) +{ + /* + * Return at most 'count' bytes from the status_buf. + */ + int l, c; + + l = count; + c = status_len - status_ptr; + + if (l > c) + l = c; + if (l <= 0) + return 0; + + COPY_TO_USER(buf, 0, &status_buf[status_ptr], l); + status_ptr += l; + + return l; +} + +int +sound_read_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count) +{ + DEB (printk ("sound_read_sw(dev=%d, count=%d)\n", dev, count)); + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + return read_status (buf, count); + break; + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_read (dev, file, buf, count); + break; + + case SND_DEV_SEQ: + return sequencer_read (dev, file, buf, count); + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + return MIDIbuf_read (dev, file, buf, count); +#endif + + default: + printk ("Sound: Undefined minor device %d\n", dev); + } + + return RET_ERROR (EPERM); +} + +int +sound_write_sw (int dev, struct fileinfo *file, snd_rw_buf *buf, int count) +{ + + DEB (printk ("sound_write_sw(dev=%d, count=%d)\n", dev, count)); + + switch (dev & 0x0f) + { + + case SND_DEV_SEQ: + return sequencer_write (dev, file, buf, count); + break; + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_write (dev, file, buf, count); + break; + + default: + return RET_ERROR (EPERM); + } + + return count; +} + +int +sound_open_sw (int dev, struct fileinfo *file) +{ + int retval; + DEB (printk ("sound_open_sw(dev=%d) : usecount=%d\n", dev, sbc_devices[dev].usecount)); + + if ((dev >= SND_NDEVS) || (dev < 0)) + { + printk ("Invalid minor device %d\n", dev); + return RET_ERROR (ENXIO); + } + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_busy) + return RET_ERROR (EBUSY); + status_busy = 1; + if ((status_buf = (char *) KERNEL_MALLOC (4000)) == NULL) + return RET_ERROR (EIO); + status_len = status_ptr = 0; + init_status (); + break; + + case SND_DEV_CTL: + return 0; + break; + + case SND_DEV_SEQ: + if ((retval = sequencer_open (dev, file)) < 0) + return retval; + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + if ((retval = MIDIbuf_open (dev, file)) < 0) + return retval; + break; +#endif + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + if ((retval = audio_open (dev, file)) < 0) + return retval; + break; + + default: + printk ("Invalid minor device %d\n", dev); + return RET_ERROR (ENXIO); + } + + sbc_devices[dev].usecount++; + in_use++; + + return 0; +} + +void +sound_release_sw (int dev, struct fileinfo *file) +{ + + DEB (printk ("sound_release_sw(dev=%d)\n", dev)); + + switch (dev & 0x0f) + { + case SND_DEV_STATUS: + if (status_buf) + KERNEL_FREE (status_buf); + status_buf = NULL; + status_busy = 0; + break; + + case SND_DEV_CTL: + break; + + case SND_DEV_SEQ: + sequencer_release (dev, file); + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + MIDIbuf_release (dev, file); + break; +#endif + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + audio_release (dev, file); + break; + + default: + printk ("Sound error: Releasing unknown device 0x%02x\n", dev); + } + + sbc_devices[dev].usecount--; + in_use--; +} + +int +sound_ioctl_sw (int dev, struct fileinfo *file, + unsigned int cmd, unsigned long arg) +{ + DEB (printk ("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg)); + + switch (dev & 0x0f) + { + + case SND_DEV_CTL: + + if (!num_mixers) + return RET_ERROR (ENXIO); + + if ((dev >> 4) >= num_mixers) + return RET_ERROR (ENXIO); + + return mixer_devs[dev >> 4]->ioctl (dev >> 4, cmd, arg); + break; + + case SND_DEV_SEQ: + return sequencer_ioctl (dev, file, cmd, arg); + break; + + case SND_DEV_DSP: + case SND_DEV_DSP16: + case SND_DEV_AUDIO: + return audio_ioctl (dev, file, cmd, arg); + break; + +#ifndef EXCLUDE_MPU401 + case SND_DEV_MIDIN: + return MIDIbuf_ioctl (dev, file, cmd, arg); + break; +#endif + + default: + return RET_ERROR (EPERM); + break; + } + + return RET_ERROR (EPERM); +} +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/soundcard.c b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/soundcard.c new file mode 100644 index 000000000..ddf718016 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/soundcard.c @@ -0,0 +1,355 @@ + +/* + * linux/kernel/chr_drv/sound/soundcard.c + * + * Soundcard driver for Linux + * + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. 2. + * Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +#include "sound_config.h" + +#ifdef CONFIGURE_SOUNDCARD + +#include + +extern long seq_time; + +static int soundcards_installed = 0; /* Number of installed + * soundcards */ +static int soundcard_configured = 0; + +static struct fileinfo files[SND_NDEVS]; + +extern char *snd_raw_buf[MAX_DSP_DEV][DSP_BUFFCOUNT]; +extern unsigned long snd_raw_buf_phys[MAX_DSP_DEV][DSP_BUFFCOUNT]; +extern int snd_raw_count[MAX_DSP_DEV]; + +int +snd_ioctl_return (int *addr, int value) +{ + if (value < 0) + return value; + + PUT_WORD_TO_USER (addr, 0, value); + return 0; +} + +static int +sound_read (struct inode *inode, struct file *file, char *buf, int count) +{ + int dev; + + dev = inode->i_rdev; + dev = MINOR (dev); + + return sound_read_sw (dev, &files[dev], buf, count); +} + +static int +sound_write (struct inode *inode, struct file *file, char *buf, int count) +{ + int dev; + + dev = inode->i_rdev; + dev = MINOR (dev); + + return sound_write_sw (dev, &files[dev], buf, count); +} + +static int +sound_lseek (struct inode *inode, struct file *file, off_t offset, int orig) +{ + return RET_ERROR (EPERM); +} + +static int +sound_open (struct inode *inode, struct file *file) +{ + int dev; + + dev = inode->i_rdev; + dev = MINOR (dev); + + if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) + { + printk ("SoundCard Error: The soundcard system has not been configured\n"); + return RET_ERROR (ENXIO); + } + + files[dev].mode = 0; + + if ((file->f_flags & O_ACCMODE) == O_RDWR) + files[dev].mode = OPEN_READWRITE; + if ((file->f_flags & O_ACCMODE) == O_RDONLY) + files[dev].mode = OPEN_READ; + if ((file->f_flags & O_ACCMODE) == O_WRONLY) + files[dev].mode = OPEN_WRITE; + + return sound_open_sw (dev, &files[dev]); +} + +static void +sound_release (struct inode *inode, struct file *file) +{ + int dev; + + dev = inode->i_rdev; + dev = MINOR (dev); + + sound_release_sw (dev, &files[dev]); +} + +static int +sound_ioctl (struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int dev; + + dev = inode->i_rdev; + dev = MINOR (dev); + + return sound_ioctl_sw (dev, &files[dev], cmd, arg); +} + +static int +sound_select (struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + int dev; + + dev = inode->i_rdev; + dev = MINOR (dev); + + DEB (printk ("sound_select(dev=%d, type=0x%x)\n", dev, sel_type)); + + switch (dev & 0x0f) + { + case SND_DEV_SEQ: + return sequencer_select (dev, &files[dev], sel_type, wait); + break; + + default: + return 0; + } + + return 0; +} + +static struct file_operations sound_fops = +{ + sound_lseek, + sound_read, + sound_write, + NULL, /* sound_readdir */ + sound_select, + sound_ioctl, + NULL, + sound_open, + sound_release +}; + +long +soundcard_init (long mem_start) +{ + register_chrdev (SOUND_MAJOR, "sound", &sound_fops); + + soundcard_configured = 1; + + mem_start = sndtable_init (mem_start); /* Initialize call tables and + * detect cards */ + + if (!(soundcards_installed = sndtable_get_cardcount ())) + return mem_start; /* No cards detected */ + + if (num_dspdevs) /* Audio devices present */ + { + mem_start = DMAbuf_init (mem_start); + mem_start = audio_init (mem_start); + } + +#ifndef EXCLUDE_MPU401 + if (num_midis) + mem_start = MIDIbuf_init (mem_start); +#endif + + if (num_midis + num_synths) + mem_start = sequencer_init (mem_start); + + return mem_start; +} + +void +tenmicrosec (void) +{ + int i; + + for (i = 0; i < 16; i++) + inb (0x80); +} + +int +snd_set_irq_handler (int interrupt_level, void(*hndlr)(int)) +{ + int retcode; + + struct sigaction sa; + + sa.sa_handler = hndlr; + +#ifdef SND_SA_INTERRUPT + sa.sa_flags = SA_INTERRUPT; +#else + sa.sa_flags = 0; +#endif + + sa.sa_mask = 0; + sa.sa_restorer = NULL; + + retcode = irqaction (interrupt_level, &sa); + + if (retcode < 0) + { + printk ("Sound: IRQ%d already in use\n", interrupt_level); + } + + return retcode; +} + +void +snd_release_irq(int vect) +{ + free_irq(vect); +} + +void +request_sound_timer (int count) +{ +#ifndef EXCLUDE_SEQUENCER + if (count < 0) + count = jiffies + (-count); + else + count += seq_time; + timer_table[SOUND_TIMER].fn = sequencer_timer; + timer_table[SOUND_TIMER].expires = count; + timer_active |= 1 << SOUND_TIMER; +#endif +} + +void +sound_stop_timer (void) +{ +#ifndef EXCLUDE_SEQUENCER + timer_table[SOUND_TIMER].expires = 0; + timer_active &= ~(1 << SOUND_TIMER); +#endif +} + +#ifndef EXCLUDE_AUDIO +static int +valid_dma_page (unsigned long addr, unsigned long dev_buffsize, unsigned long dma_pagesize) +{ + if (((addr & (dma_pagesize - 1)) + dev_buffsize) <= dma_pagesize) + return 1; + else + return 0; +} + +void +sound_mem_init (void) +{ + int i, dev; + unsigned long start_addr, end_addr, mem_ptr, dma_pagesize; + + mem_ptr = high_memory; + + /* Some sanity checks */ + + if (mem_ptr > (16 * 1024 * 1024)) + mem_ptr = 16 * 1024 * 1024; /* Limit to 16M */ + + for (dev = 0; dev < num_dspdevs; dev++) /* Enumerate devices */ + if (sound_buffcounts[dev] > 0 && sound_dsp_dmachan[dev] > 0) + { + if (sound_dma_automode[dev]) + sound_buffcounts[dev] = 1; + + if (sound_dsp_dmachan[dev] > 3 && sound_buffsizes[dev] > 65536) + dma_pagesize = 131072;/* 128k */ + else + dma_pagesize = 65536; + + /* More sanity checks */ + + if (sound_buffsizes[dev] > dma_pagesize) + sound_buffsizes[dev] = dma_pagesize; + sound_buffsizes[dev] &= 0xfffff000; /* Truncate to n*4k */ + if (sound_buffsizes[dev] < 4096) + sound_buffsizes[dev] = 4096; + + /* Now allocate the buffers */ + + for (snd_raw_count[dev] = 0; snd_raw_count[dev] < sound_buffcounts[dev]; snd_raw_count[dev]++) + { + start_addr = mem_ptr - sound_buffsizes[dev]; + if (!valid_dma_page (start_addr, sound_buffsizes[dev], dma_pagesize)) + start_addr &= ~(dma_pagesize - 1); /* Align address to + * dma_pagesize */ + + end_addr = start_addr + sound_buffsizes[dev] - 1; + + snd_raw_buf[dev][snd_raw_count[dev]] = (char *) start_addr; + snd_raw_buf_phys[dev][snd_raw_count[dev]] = start_addr; + mem_ptr = start_addr; + + for (i = MAP_NR (start_addr); i <= MAP_NR (end_addr); i++) + { + if (mem_map[i]) + panic ("sound_mem_init: Page not free (driver incompatible with kernel).\n"); + + mem_map[i] = MAP_PAGE_RESERVED; + } + } + } /* for dev */ +} + +#endif + +#else + +long +soundcard_init (long mem_start) /* Dummy version */ +{ + return mem_start; +} + +#endif + +#if !defined(CONFIGURE_SOUNDCARD) || defined(EXCLUDE_AUDIO) +void +sound_mem_init (void) +{ + /* Dummy version */ +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/tuning.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/tuning.h new file mode 100644 index 000000000..858e1fe6c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/tuning.h @@ -0,0 +1,29 @@ +#ifdef SEQUENCER_C + +unsigned short semitone_tuning[24] = +{ +/* 0 */ 10000, 10595, 11225, 11892, 12599, 13348, 14142, 14983, +/* 8 */ 15874, 16818, 17818, 18877, 20000, 21189, 22449, 23784, +/* 16 */ 25198, 26697, 28284, 29966, 31748, 33636, 35636, 37755 +}; + +unsigned short cent_tuning[100] = +{ +/* 0 */ 10000, 10006, 10012, 10017, 10023, 10029, 10035, 10041, +/* 8 */ 10046, 10052, 10058, 10064, 10070, 10075, 10081, 10087, +/* 16 */ 10093, 10099, 10105, 10110, 10116, 10122, 10128, 10134, +/* 24 */ 10140, 10145, 10151, 10157, 10163, 10169, 10175, 10181, +/* 32 */ 10187, 10192, 10198, 10204, 10210, 10216, 10222, 10228, +/* 40 */ 10234, 10240, 10246, 10251, 10257, 10263, 10269, 10275, +/* 48 */ 10281, 10287, 10293, 10299, 10305, 10311, 10317, 10323, +/* 56 */ 10329, 10335, 10341, 10347, 10353, 10359, 10365, 10371, +/* 64 */ 10377, 10383, 10389, 10395, 10401, 10407, 10413, 10419, +/* 72 */ 10425, 10431, 10437, 10443, 10449, 10455, 10461, 10467, +/* 80 */ 10473, 10479, 10485, 10491, 10497, 10503, 10509, 10515, +/* 88 */ 10521, 10528, 10534, 10540, 10546, 10552, 10558, 10564, +/* 96 */ 10570, 10576, 10582, 10589 +}; +#else +extern unsigned short semitone_tuning[24]; +extern unsigned short cent_tuning[100]; +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/ulaw.h b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/ulaw.h new file mode 100644 index 000000000..be9f92d99 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/drivers/sound/ulaw.h @@ -0,0 +1,69 @@ +static unsigned char ulaw_dsp[] = { + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 2, + 5, 9, 13, 17, 21, 25, 29, 33, + 37, 41, 45, 49, 53, 57, 61, 65, + 68, 70, 72, 74, 76, 78, 80, 82, + 84, 86, 88, 90, 92, 94, 96, 98, + 100, 101, 102, 103, 104, 105, 106, 107, + 108, 109, 110, 111, 112, 113, 114, 115, + 115, 116, 116, 117, 117, 118, 118, 119, + 119, 120, 120, 121, 121, 122, 122, 123, + 123, 123, 124, 124, 124, 124, 125, 125, + 125, 125, 126, 126, 126, 126, 127, 127, + 127, 127, 127, 127, 128, 128, 128, 128, + 128, 128, 128, 128, 128, 128, 128, 128, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, + 252, 248, 244, 240, 236, 232, 228, 224, + 220, 216, 212, 208, 204, 200, 196, 192, + 189, 187, 185, 183, 181, 179, 177, 175, + 173, 171, 169, 167, 165, 163, 161, 159, + 157, 156, 155, 154, 153, 152, 151, 150, + 149, 148, 147, 146, 145, 144, 143, 142, + 142, 141, 141, 140, 140, 139, 139, 138, + 138, 137, 137, 136, 136, 135, 135, 134, + 134, 134, 133, 133, 133, 133, 132, 132, + 132, 132, 131, 131, 131, 131, 130, 130, + 130, 130, 130, 130, 129, 129, 129, 129, + 129, 129, 129, 129, 128, 128, 128, 128, +}; + +static unsigned char dsp_ulaw[] = { + 31, 31, 31, 32, 32, 32, 32, 33, + 33, 33, 33, 34, 34, 34, 34, 35, + 35, 35, 35, 36, 36, 36, 36, 37, + 37, 37, 37, 38, 38, 38, 38, 39, + 39, 39, 39, 40, 40, 40, 40, 41, + 41, 41, 41, 42, 42, 42, 42, 43, + 43, 43, 43, 44, 44, 44, 44, 45, + 45, 45, 45, 46, 46, 46, 46, 47, + 47, 47, 47, 48, 48, 49, 49, 50, + 50, 51, 51, 52, 52, 53, 53, 54, + 54, 55, 55, 56, 56, 57, 57, 58, + 58, 59, 59, 60, 60, 61, 61, 62, + 62, 63, 63, 64, 65, 66, 67, 68, + 69, 70, 71, 72, 73, 74, 75, 76, + 77, 78, 79, 81, 83, 85, 87, 89, + 91, 93, 95, 99, 103, 107, 111, 119, + 255, 247, 239, 235, 231, 227, 223, 221, + 219, 217, 215, 213, 211, 209, 207, 206, + 205, 204, 203, 202, 201, 200, 199, 198, + 197, 196, 195, 194, 193, 192, 191, 191, + 190, 190, 189, 189, 188, 188, 187, 187, + 186, 186, 185, 185, 184, 184, 183, 183, + 182, 182, 181, 181, 180, 180, 179, 179, + 178, 178, 177, 177, 176, 176, 175, 175, + 175, 175, 174, 174, 174, 174, 173, 173, + 173, 173, 172, 172, 172, 172, 171, 171, + 171, 171, 170, 170, 170, 170, 169, 169, + 169, 169, 168, 168, 168, 168, 167, 167, + 167, 167, 166, 166, 166, 166, 165, 165, + 165, 165, 164, 164, 164, 164, 163, 163, + 163, 163, 162, 162, 162, 162, 161, 161, + 161, 161, 160, 160, 160, 160, 159, 159, +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/Makefile new file mode 100644 index 000000000..d008403c1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/Makefile @@ -0,0 +1,84 @@ +# +# Makefile for the linux filesystem. +# +# 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... + +SUBDIRS = minix ext ext2 msdos proc isofs nfs xiafs hpfs sysv + +ifdef CONFIG_MINIX_FS +FS_SUBDIRS := $(FS_SUBDIRS) minix +endif +ifdef CONFIG_EXT_FS +FS_SUBDIRS := $(FS_SUBDIRS) ext +endif +ifdef CONFIG_EXT2_FS +FS_SUBDIRS := $(FS_SUBDIRS) ext2 +endif +ifdef CONFIG_MSDOS_FS +FS_SUBDIRS := $(FS_SUBDIRS) msdos +endif +ifdef CONFIG_PROC_FS +FS_SUBDIRS := $(FS_SUBDIRS) proc +endif +ifdef CONFIG_ISO9660_FS +FS_SUBDIRS := $(FS_SUBDIRS) isofs +endif +ifdef CONFIG_NFS_FS +FS_SUBDIRS := $(FS_SUBDIRS) nfs +endif +ifdef CONFIG_XIA_FS +FS_SUBDIRS := $(FS_SUBDIRS) xiafs +endif +ifdef CONFIG_SYSV_FS +FS_SUBDIRS := $(FS_SUBDIRS) sysv +endif +ifdef CONFIG_HPFS_FS +FS_SUBDIRS := $(FS_SUBDIRS) hpfs +endif + +ifdef CONFIG_BINFMT_ELF +BINFMTS := $(BINFMTS) binfmt_elf.o +endif +ifdef CONFIG_BINFMT_COFF +BINFMTS := $(BINFMTS) binfmt_coff.o +endif + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= open.o read_write.o inode.o devices.o file_table.o buffer.o super.o \ + block_dev.o stat.o exec.o pipe.o namei.o fcntl.o ioctl.o \ + select.o fifo.o locks.o filesystems.o $(BINFMTS) + +all: fs.o filesystems.a + +fs.o: $(OBJS) + $(LD) -r -o fs.o $(OBJS) + +filesystems.a: dummy + rm -f filesystems.a + set -e; for i in $(FS_SUBDIRS); do \ + test ! -d $$i || \ + { $(MAKE) -C $$i; $(AR) rcs filesystems.a $$i/$$i.o; }; done + +depend dep: + $(CPP) -M *.c > .depend + set -e; for i in $(SUBDIRS); do \ + test ! -d $$i || $(MAKE) -C $$i dep; done + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_coff.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_coff.c new file mode 100644 index 000000000..bf5701648 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_coff.c @@ -0,0 +1,782 @@ +/* + * These are the functions used to load COFF IBSC style executables. + * Information on COFF format may be obtained in either the Intel Binary + * Compatibility Specification 2 or O'Rilley's book on COFF. The shared + * libraries are defined only the in the Intel book. + * + * This file is based upon code written by Eric Youndale for the ELF object + * file format. + * + * Revision information: + * 28 August 1993 + * Al Longyear (longyear@sii.com) + * initial release to alpha level testing. This version does not load + * shared libraries, but will identify them and log the file names. + * + * 4 September 1993 + * Al Longyear (longyear@sii.com) + * Added support for shared libraries. + * + * 9 September 1993 + * Al Longyear (longyear@sii.com) + * Load the FS register with the proper value prior to the call to + * sys_uselib(). + * + * Built the parameter and envionment strings before destroying the + * current executable. + * + * 10 September 1993 + * Al Longyear (longyear@sii.com) + * Added new parameter to the create_tables() function to allow the + * proper creation of the IBCS environment stack when the process is + * started. + * + * Added code to create_tables() which I mistakenly deleted in the + * last patch. + * + * 13 September 1993 + * Al Longyear (longyear@sii.com) + * Removed erroneous code which mistakenly folded .data with .bss for + * a shared library. + * + * 8 Janurary 1994 + * Al Longyear (longyear@sii.com) + * Corrected problem with read of library section returning the byte + * count rather than zero. This was a change between the pl12 and + * pl14 kernels which slipped by me. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +asmlinkage int sys_exit (int exit_code); +asmlinkage int sys_close (unsigned fd); +asmlinkage int sys_open (const char *, int, int); +asmlinkage int sys_uselib(const char * library); + +static int preload_library (struct linux_binprm *exe_bprm, + COFF_SCNHDR * sect, + struct file *fp); + +static int load_object (struct linux_binprm *bprm, + struct pt_regs *regs, + int lib_ok); + +/* + * Small procedure to test for the proper file alignment. + */ + +static inline int +is_properly_aligned (COFF_SCNHDR *sect) +{ + long scnptr = COFF_LONG (sect->s_scnptr); + long vaddr = COFF_LONG (sect->s_vaddr); +/* + * Print the section information if needed + */ + +#ifdef COFF_DEBUG + printk ("%s, scnptr = %d, vaddr = %d\n", + sect->s_name, + scnptr, vaddr); +#endif + +/* + * Return the error code if the section is not properly aligned. + */ + +#ifdef COFF_DEBUG + if (((vaddr - scnptr) & ~PAGE_MASK) != 0) + printk ("bad alignment in %s\n", sect->s_name); +#endif + return ((((vaddr - scnptr) & ~PAGE_MASK) != 0) ? -ENOEXEC : 0); +} + +/* + * Helper function to process the load operation. + */ + +static int +load_object (struct linux_binprm * bprm, struct pt_regs *regs, int lib_ok) +{ + COFF_FILHDR *coff_hdr = (COFF_FILHDR *) bprm->buf; /* COFF Header */ + COFF_SCNHDR *sect_bufr; /* Pointer to section table */ + COFF_SCNHDR *text_sect; /* Pointer to the text section */ + COFF_SCNHDR *data_sect; /* Pointer to the data section */ + COFF_SCNHDR *bss_sect; /* Pointer to the bss section */ + int text_count; /* Number of text sections */ + int data_count; /* Number of data sections */ + int bss_count; /* Number of bss sections */ + int lib_count; /* Number of lib sections */ + unsigned int start_addr = 0;/* Starting location for program */ + int status = 0; /* Result status register */ + int fd = -1; /* Open file descriptor */ + struct file *fp = NULL; /* Pointer to the file at "fd" */ + short int sections = 0; /* Number of sections in the file */ + short int aout_size = 0; /* Size of the a.out header area */ + short int flags; /* Flag bits from the COFF header */ + +#ifdef COFF_DEBUG + printk ("binfmt_coff entry: %s\n", bprm->filename); +#endif + +/* + * Validate the magic value for the object file. + */ + do { + if (COFF_I386BADMAG (*coff_hdr)) { +#ifdef COFF_DEBUG + printk ("bad filehdr magic\n"); +#endif + status = -ENOEXEC; + break; + } +/* + * The object file should have 32 BIT little endian format. Do not allow + * it to have the 16 bit object file flag set as Linux is not able to run + * on the 80286/80186/8086. + */ + flags = COFF_SHORT (coff_hdr->f_flags); + if ((flags & (COFF_F_AR32WR | COFF_F_AR16WR)) != COFF_F_AR32WR) { +#ifdef COFF_DEBUG + printk ("invalid f_flags bits\n"); +#endif + status = -ENOEXEC; + break; + } +/* + * Extract the header information which we need. + */ + sections = COFF_SHORT (coff_hdr->f_nscns); /* Number of sections */ + aout_size = COFF_SHORT (coff_hdr->f_opthdr); /* Size of opt. headr */ +/* + * If the file is not executable then reject the exectution. This means + * that there must not be external references. + */ + if ((flags & COFF_F_EXEC) == 0) { +#ifdef COFF_DEBUG + printk ("not executable bit\n"); +#endif + status = -ENOEXEC; + break; + } +/* + * There must be atleast one section. + */ + if (sections == 0) { +#ifdef COFF_DEBUG + printk ("no sections\n"); +#endif + status = -ENOEXEC; + break; + } +/* + * Do some additional consistency checks. + * The system requires mapping for this loader. If you try + * to use a file system with no mapping, the format is not valid. + */ + if (!bprm->inode->i_op || + !bprm->inode->i_op->default_file_ops->mmap) { +#ifdef COFF_DEBUG + printk ("no mmap in fs\n"); +#endif + status = -ENOEXEC; + } + } + while (0); +/* + * Allocate a buffer to hold the entire coff section list. + */ + if (status >= 0) { + int nbytes = sections * COFF_SCNHSZ; + + sect_bufr = (COFF_SCNHDR *) kmalloc (nbytes, GFP_KERNEL); + if (0 == sect_bufr) { +#ifdef COFF_DEBUG + printk ("kmalloc failed\n"); +#endif + status = -ENOEXEC; + } +/* + * Read the section list from the disk file. + */ + else { + int old_fs = get_fs (); + set_fs (get_ds ()); /* Make it point to the proper location */ + status = read_exec (bprm->inode, /* INODE for file */ + aout_size + COFF_FILHSZ, /* Offset in the file */ + (char *) sect_bufr, /* Buffer for read */ + nbytes); /* Byte count reqd. */ + set_fs (old_fs); /* Restore the selector */ +#ifdef COFF_DEBUG + if (status < 0) + printk ("read aout hdr, status = %d\n", status); +#endif + } + } + else + sect_bufr = NULL; /* Errors do not have a section buffer */ +/* + * Count the number of sections for the required types and store the location + * of the last section for the three primary types. + */ + text_count = 0; + data_count = 0; + bss_count = 0; + lib_count = 0; + + text_sect = NULL; + data_sect = NULL; + bss_sect = NULL; +/* + * Loop through the sections and find the various types + */ + if (status >= 0) { + int nIndex; + COFF_SCNHDR *sect_ptr = sect_bufr; + + for (nIndex = 0; nIndex < sections; ++nIndex) { + long int sect_flags = COFF_LONG (sect_ptr->s_flags); + + switch (sect_flags) { + case COFF_STYP_TEXT: + text_sect = sect_ptr; + ++text_count; + status = is_properly_aligned (sect_ptr); + break; + + case COFF_STYP_DATA: + data_sect = sect_ptr; + ++data_count; + status = is_properly_aligned (sect_ptr); + break; + + case COFF_STYP_BSS: + bss_sect = sect_ptr; + ++bss_count; + break; + + case COFF_STYP_LIB: +#ifdef COFF_DEBUG + printk (".lib section found\n"); +#endif + ++lib_count; + break; + + default: + break; + } + sect_ptr = (COFF_SCNHDR *) & ((char *) sect_ptr)[COFF_SCNHSZ]; + } +/* + * Ensure that there are the required sections. There must be one text + * sections and one each of the data and bss sections for an executable. + * A library may or may not have a data / bss section. + */ + if (text_count != 1) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("no text sections\n"); +#endif + } + else { + if (lib_ok) { + if (data_count != 1 || bss_count != 1) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("no .data nor .bss sections\n"); +#endif + } + } + } + } +/* + * If there is no additional header then assume the file starts at + * the first byte of the text section. This may not be the proper place, + * so the best solution is to include the optional header. A shared library + * __MUST__ have an optional header to indicate that it is a shared library. + */ + if (status >= 0) { + if (aout_size == 0) { + if (!lib_ok) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("no header in library\n"); +#endif + } + start_addr = COFF_LONG (text_sect->s_vaddr); + } +/* + * There is some header. Ensure that it is sufficient. + */ + else { + if (aout_size < COFF_AOUTSZ) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("header too small\n"); +#endif + } + else { + COFF_AOUTHDR *aout_hdr = /* Pointer to a.out header */ + (COFF_AOUTHDR *) & ((char *) coff_hdr)[COFF_FILHSZ]; + short int aout_magic = COFF_SHORT (aout_hdr->magic); /* id */ +/* + * Validate the magic number in the a.out header. If it is valid then + * update the starting symbol location. Do not accept these file formats + * when loading a shared library. + */ + switch (aout_magic) { + case COFF_OMAGIC: + case COFF_ZMAGIC: + case COFF_STMAGIC: + if (!lib_ok) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("wrong a.out header magic\n"); +#endif + } + start_addr = (unsigned int) COFF_LONG (aout_hdr->entry); + break; +/* + * Magic value for a shared library. This is valid only when loading a + * shared library. (There is no need for a start_addr. It won't be used.) + */ + case COFF_SHMAGIC: + if (lib_ok) { +#ifdef COFF_DEBUG + printk ("wrong a.out header magic\n"); +#endif + status = -ENOEXEC; + } + break; + + default: +#ifdef COFF_DEBUG + printk ("wrong a.out header magic\n"); +#endif + status = -ENOEXEC; + break; + } + } + } + } +/* + * Fetch a file pointer to the executable. + */ + if (status >= 0) { + fd = open_inode (bprm->inode, O_RDONLY); + if (fd < 0) { +#ifdef COFF_DEBUG + printk ("can not open inode, result = %d\n", fd); +#endif + status = fd; + } + else + fp = current->filp[fd]; + } + else + fd = -1; /* Invalidate the open file descriptor */ +/* + * Generate the proper values for the text fields + * + * THIS IS THE POINT OF NO RETURN. THE NEW PROCESS WILL TRAP OUT SHOULD + * SOMETHING FAIL IN THE LOAD SEQUENCE FROM THIS POINT ONWARD. + */ + if (status >= 0) { + long text_scnptr = COFF_LONG (text_sect->s_scnptr); + long text_size = COFF_LONG (text_sect->s_size); + long text_vaddr = COFF_LONG (text_sect->s_vaddr); + + long data_scnptr; + long data_size; + long data_vaddr; + + long bss_size; + long bss_vaddr; +/* + * Generate the proper values for the data fields + */ + if (data_sect != NULL) { + data_scnptr = COFF_LONG (data_sect->s_scnptr); + data_size = COFF_LONG (data_sect->s_size); + data_vaddr = COFF_LONG (data_sect->s_vaddr); + } + else { + data_scnptr = 0; + data_size = 0; + data_vaddr = 0; + } +/* + * Generate the proper values for the bss fields + */ + if (bss_sect != NULL) { + bss_size = COFF_LONG (bss_sect->s_size); + bss_vaddr = COFF_LONG (bss_sect->s_vaddr); + } + else { + bss_size = 0; + bss_vaddr = 0; + } +/* + * Flush the executable from memory. At this point the executable is + * committed to being defined or a segmentation violation will occur. + */ + if (lib_ok) { +#ifdef COFF_DEBUG + printk ("flushing executable\n"); +#endif + flush_old_exec (bprm); +/* + * Define the initial locations for the various items in the new process + */ + current->mmap = NULL; + current->rss = 0; +/* + * Construct the parameter and environment string table entries. + */ + bprm->p += change_ldt (0, bprm->page); + bprm->p -= MAX_ARG_PAGES*PAGE_SIZE; + bprm->p = (unsigned long) create_tables ((char *) bprm->p, + bprm->argc, + bprm->envc, + 1); +/* + * Do the end processing once the stack has been constructed + */ + current->start_code = text_vaddr & PAGE_MASK; + current->end_code = text_vaddr + text_size; + current->end_data = data_vaddr + data_size; + current->start_brk = + current->brk = bss_vaddr + bss_size; + current->suid = + current->euid = bprm->e_uid; + current->sgid = + current->egid = bprm->e_gid; + current->executable = bprm->inode; /* Store inode for file */ + ++bprm->inode->i_count; /* Count the open inode */ + regs->eip = start_addr; /* Current EIP register */ + regs->esp = + current->start_stack = bprm->p; + } +/* + * Map the text pages + */ + +#ifdef COFF_DEBUG + printk (".text: vaddr = %d, size = %d, scnptr = %d\n", + text_vaddr, + text_size, + text_scnptr); +#endif + status = do_mmap (fp, + text_vaddr & PAGE_MASK, + text_size + (text_vaddr & ~PAGE_MASK), + PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_SHARED, + text_scnptr & PAGE_MASK); + + status = (status == (text_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC; +/* + * Map the data pages + */ + if (status >= 0 && data_size != 0) { +#ifdef COFF_DEBUG + printk (".data: vaddr = %d, size = %d, scnptr = %d\n", + data_vaddr, + data_size, + data_scnptr); +#endif + status = do_mmap (fp, + data_vaddr & PAGE_MASK, + data_size + (data_vaddr & ~PAGE_MASK), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, + data_scnptr & PAGE_MASK); + + status = (status == (data_vaddr & PAGE_MASK)) ? 0 : -ENOEXEC; + } +/* + * Construct the bss data for the process. The bss ranges from the + * end of the data (which may not be on a page boundry) to the end + * of the bss section. Allocate any necessary pages for the data. + */ + if (status >= 0 && bss_size != 0) { +#ifdef COFF_DEBUG + printk (".bss: vaddr = %d, size = %d\n", + bss_vaddr, + bss_size); +#endif + zeromap_page_range (PAGE_ALIGN (bss_vaddr), + PAGE_ALIGN (bss_size), + PAGE_COPY); + } +/* + * Load any shared library for the executable. + */ + if (lib_ok && lib_count != 0) { + int nIndex; + COFF_SCNHDR *sect_ptr = sect_bufr; +/* + * Find the library sections. (There should be atleast one. It was counted + * earlier.) This will evenutally recurse to our code and load the shared + * library with our own procedures. + */ + for (nIndex = 0; nIndex < sections; ++nIndex) { + long int sect_flags = COFF_LONG (sect_ptr->s_flags); + if (sect_flags == COFF_STYP_LIB) { + status = preload_library (bprm, sect_ptr, fp); + if (status != 0) + break; + } + sect_ptr = (COFF_SCNHDR *) &((char *) sect_ptr) [COFF_SCNHSZ]; + } + } +/* + * Generate any needed trap for this process. If an error occured then + * generate a segmentation violation. If the process is being debugged + * then generate the load trap. (Note: If this is a library load then + * do not generate the trap here. Pass the error to the caller who + * will do it for the process in the outer lay of this procedure call.) + */ + if (lib_ok) { + if (status < 0) + send_sig (SIGSEGV, current, 0); /* Generate the error trap */ + else { + if (current->flags & PF_PTRACED) + send_sig (SIGTRAP, current, 0); + } + status = 0; /* We are committed. It can't fail */ + } + } +/* + * Do any cleanup processing + */ + if (fd >= 0) + sys_close (fd); /* Close unused code file */ + + if (sect_bufr != NULL) + kfree (sect_bufr); /* Release section list buffer */ +/* + * Return the completion status. + */ +#ifdef COFF_DEBUG + printk ("binfmt_coff: result = %d\n", status); +#endif + return (status); +} + +/* + * This procedure will load the library listed in the file name given + * as the paramter. The result will be non-zero should something fail + * to load. + */ + +static int +preload_this_library (struct linux_binprm *exe_bprm, char *lib_name) +{ + int status; + int old_fs = get_fs(); +/* + * If debugging then print "we have arrived" + */ +#ifdef COFF_DEBUG + printk ("%s loading shared library %s\n", + exe_bprm->filename, + lib_name); +#endif +/* + * Change the FS register to the proper kernel address space and attempt + * to load the library. The library name is allocated from the kernel + * pool. + */ + set_fs (get_ds ()); + status = sys_uselib (lib_name); + set_fs (old_fs); +/* + * Return the success/failure to the caller. + */ + return (status); +} + +/* + * This procedure is called to load a library section. The various + * libraries are loaded from the list given in the section data. + */ + +static int +preload_library (struct linux_binprm *exe_bprm, + COFF_SCNHDR * sect, struct file *fp) +{ + int status = 0; /* Completion status */ + long nbytes; /* Count of bytes in the header area */ +/* + * Fetch the size of the section. There must be enough room for atleast + * one entry. + */ + nbytes = COFF_LONG (sect->s_size); + if (nbytes < COFF_SLIBSZ) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("library section too small\n"); +#endif + } +/* + * Allocate a buffer to hold the section data + */ + else { + COFF_SLIBHD *phdr; + char *buffer = (char *) kmalloc (nbytes, GFP_KERNEL); + + if (0 == buffer) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("kmalloc failed\n"); +#endif + } + else { + int old_fs = get_fs (); +/* + * Read the section data from the disk file. + */ + set_fs (get_ds ()); /* Make it point to the proper location */ + status = read_exec (exe_bprm->inode, /* INODE for file */ + COFF_LONG (sect->s_scnptr), /* Disk location */ + buffer, /* Buffer for read */ + nbytes); /* Byte count reqd. */ + set_fs (old_fs); /* Restore the selector */ +/* + * Check the result. The value returned is the byte count actaully read. + */ + if (status >= 0 && status != nbytes) { +#ifdef COFF_DEBUG + printk ("read of lib section was short\n"); +#endif + status = -ENOEXEC; + } + } +/* + * At this point, go through the list of libraries in the data area. + */ + phdr = (COFF_SLIBHD *) buffer; + while (status >= 0 && nbytes > COFF_SLIBSZ) { + int entry_size = COFF_LONG (phdr->sl_entsz) * sizeof (long); + int header_size = COFF_LONG (phdr->sl_pathndx) * sizeof (long); +/* + * Validate the sizes of the various items. I don't trust the linker!! + */ + if ((unsigned) header_size >= (unsigned) nbytes || + entry_size <= 0 || + (unsigned) entry_size <= (unsigned) header_size) { + status = -ENOEXEC; +#ifdef COFF_DEBUG + printk ("header count is invalid\n"); +#endif + } +/* + * Load the library. Stop the load process on the first error. + */ + else { + status = preload_this_library (exe_bprm, + &((char *) phdr)[header_size]); +#ifdef COFF_DEBUG + printk ("preload_this_library result = %d\n", status); +#endif + } +/* + * Point to the next library in the section data. + */ + nbytes -= entry_size; + phdr = (COFF_SLIBHD *) &((char *) phdr)[entry_size]; + } +/* + * Release the space for the library list. + */ + if (buffer != NULL) + kfree (buffer); + } +/* + * Return the resulting status to the caller. + */ + return (status); +} + +/* + * This procedure is called by the main load sequence. It will load + * the executable and prepare it for execution. It provides the additional + * parameters used by the recursive coff loader and tells the loader that + * this is the main executable. How simple it is . . . . + */ + +int +load_coff_binary (struct linux_binprm *bprm, struct pt_regs *regs) +{ + return (load_object (bprm, regs, 1)); +} + +/* + * Load the image for any shared library. + * + * This is called when we need to load a library based upon a file name. + */ + +int +load_coff_library (int fd) +{ + struct linux_binprm *bprm; /* Parameters for the load operation */ + int status; /* Status of the request */ +/* + * Read the first portion of the file. + */ + bprm = (struct linux_binprm *) kmalloc (sizeof (struct linux_binprm), + GFP_KERNEL); + if (0 == bprm) { +#ifdef COFF_DEBUG + printk ("kmalloc failed\n"); +#endif + status = -ENOEXEC; + } + else { + struct file *file; /* Pointer to the file table */ + struct pt_regs regs; /* Register work area */ + int old_fs = get_fs (); /* Previous FS register value */ + + memset (bprm, '\0', sizeof (struct linux_binprm)); + + file = current->filp[fd]; + bprm->inode = file->f_inode; /* The only item _really_ needed */ + bprm->filename = ""; /* Make it a legal string */ +/* + * Read the section list from the disk file. + */ + set_fs (get_ds ()); /* Make it point to the proper location */ + status = read_exec (bprm->inode, /* INODE for file */ + 0L, /* Offset in the file */ + bprm->buf, /* Buffer for read */ + sizeof (bprm->buf)); /* Size of the buffer */ + set_fs (old_fs); /* Restore the selector */ +/* + * Try to load the library. + */ + status = load_object (bprm, ®s, 0); +/* + * Release the work buffer and return the result. + */ + kfree (bprm); /* Release the buffer area */ + } +/* + * Return the result of the load operation + */ + return (status); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_elf.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_elf.c new file mode 100644 index 000000000..23d9abe7c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/binfmt_elf.c @@ -0,0 +1,425 @@ +/* + * linux/fs/binfmt_elf.c + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +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 + +/* 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. + */ + +int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs) +{ + struct elfhdr elf_ex; + struct file * file; + struct exec ex; + struct inode *interpreter_inode; + int i; + int old_fs; + int error; + struct elf_phdr * elf_ppnt, *elf_phdata; + int elf_exec_fileno; + unsigned int elf_bss, k, elf_brk; + int retval; + char * elf_interpreter; + unsigned int elf_entry; + int status; + unsigned int start_code, end_code, end_data; + unsigned int elf_stack; + char passed_fileno[6]; + + status = 0; + elf_ex = *((struct elfhdr *) bprm->buf); /* exec-header */ + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) + return -ENOEXEC; + + + /* First of all, some simple consistency checks */ + if(elf_ex.e_type != ET_EXEC || + (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) || + (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || + !bprm->inode->i_op->default_file_ops->mmap)){ + return -ENOEXEC; + }; + + /* Now read in all of the header information */ + + elf_phdata = (struct elf_phdr *) kmalloc(elf_ex.e_phentsize * + elf_ex.e_phnum, GFP_KERNEL); + + old_fs = get_fs(); + set_fs(get_ds()); + retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, + elf_ex.e_phentsize * elf_ex.e_phnum); + set_fs(old_fs); + if (retval < 0) { + kfree (elf_phdata); + return retval; + } + + elf_ppnt = elf_phdata; + + elf_bss = 0; + elf_brk = 0; + + elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); + + if (elf_exec_fileno < 0) { + kfree (elf_phdata); + return elf_exec_fileno; + } + + file = current->filp[elf_exec_fileno]; + + elf_stack = 0xffffffff; + elf_interpreter = NULL; + start_code = 0; + end_code = 0; + end_data = 0; + + old_fs = get_fs(); + set_fs(get_ds()); + + for(i=0;i < elf_ex.e_phnum; i++){ + if(elf_ppnt->p_type == PT_INTERP) { + /* This is the program interpreter used for shared libraries - + for now assume that this is an a.out format binary */ + + elf_interpreter = (char *) kmalloc(elf_ppnt->p_filesz, + GFP_KERNEL); + + 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) + retval = read_exec(interpreter_inode,0,bprm->buf,128); + + if(retval >= 0){ + ex = *((struct exec *) bprm->buf); /* exec-header */ + +#if 0 + printk("Interpreter: %x %x %x\n",N_MAGIC(ex), ex.a_text,ex.a_data); +#endif + }; + }; + elf_ppnt++; + }; + + set_fs(old_fs); + + /* Some simple consistency checks for the interpreter */ + if(elf_interpreter){ + if(retval < 0) { + kfree(elf_interpreter); + kfree(elf_phdata); + return -ELIBACC; + }; + if((N_MAGIC(ex) != OMAGIC) && (N_MAGIC(ex) != ZMAGIC)) { + kfree(elf_interpreter); + kfree(elf_phdata); + return -ELIBBAD; + }; + } + + /* OK, we are done with that, now set up the arg stuff, + and then start this sucker up */ + + if (!bprm->sh_bang) { + char * passed_p; + + sprintf(passed_fileno, "%d", elf_exec_fileno); + passed_p = passed_fileno; + + if(elf_interpreter) { + bprm->p = copy_strings(1,&passed_p,bprm->page,bprm->p,2); + bprm->argc++; + }; + if (!bprm->p) { + if(elf_interpreter) { + kfree(elf_interpreter); + } + kfree (elf_phdata); + return -E2BIG; + } + } + + /* OK, This is the point of no return */ + flush_old_exec(bprm); + + current->end_data = 0; + current->end_code = 0; + current->start_mmap = ELF_START_MMAP; + current->mmap = NULL; + elf_entry = (unsigned int) elf_ex.e_entry; + + /* Do this so that we can load the interpreter, if need be. We will + change some of these later */ + current->rss = 0; + bprm->p += change_ldt(0, bprm->page); + current->start_stack = bprm->p; + + /* Now we do a little grungy work by mmaping the ELF image into + the correct location in memory. At this point, we assume that + the image should be loaded at fixed address, not at a variable + address. */ + + old_fs = get_fs(); + set_fs(get_ds()); + + elf_ppnt = elf_phdata; + for(i=0;i < elf_ex.e_phnum; i++){ + + if(elf_ppnt->p_type == PT_INTERP) { + /* Set these up so that we are able to load the interpreter */ + current->brk = ex.a_bss + + (current->end_data = ex.a_data + + (current->end_code = ex.a_text)); + elf_entry = ex.a_entry; + + /* Now load the interpreter into user address space */ + set_fs(old_fs); + + 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); + 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) { + 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; + + old_fs = get_fs(); + set_fs(get_ds()); + + if(retval >= 0) + 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) { + kfree(elf_phdata); + send_sig(SIGSEGV, current, 0); + return 0; + }; + }; + + + if(elf_ppnt->p_type == PT_LOAD) { + error = do_mmap(file, + elf_ppnt->p_vaddr & 0xfffff000, + elf_ppnt->p_filesz + (elf_ppnt->p_vaddr & 0xfff), + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, + elf_ppnt->p_offset & 0xfffff000); + +#ifdef LOW_ELF_STACK + if(elf_ppnt->p_vaddr & 0xfffff000 < elf_stack) + elf_stack = elf_ppnt->p_vaddr & 0xfffff000; +#endif + + k = elf_ppnt->p_vaddr; + if(k > start_code) start_code = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_filesz; + if(k > elf_bss) elf_bss = k; + if((elf_ppnt->p_flags | PROT_WRITE) && end_code < k) + end_code = k; + if(end_data < k) end_data = k; + k = elf_ppnt->p_vaddr + elf_ppnt->p_memsz; + if(k > elf_brk) elf_brk = k; + + if(status == 0xffffffff) { + set_fs(old_fs); + kfree(elf_phdata); + send_sig(SIGSEGV, current, 0); + return 0; + }; + }; + elf_ppnt++; + }; + set_fs(old_fs); + + kfree(elf_phdata); + + if(!elf_interpreter) sys_close(elf_exec_fileno); + current->elf_executable = 1; + current->executable = bprm->inode; + bprm->inode->i_count++; +#ifdef LOW_ELF_STACK + current->start_stack = p = elf_stack - 4; +#endif + bprm->p -= MAX_ARG_PAGES*PAGE_SIZE; + bprm->p = (unsigned long) create_tables((char *)bprm->p,bprm->argc,bprm->envc,0); + if(elf_interpreter) current->arg_start += strlen(passed_fileno) + 1; + 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; + + /* 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 */ + 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, 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)) { + sys_close(fd); + return -EACCES; + } + set_fs(USER_DS); + + if (elf_ex.e_ident[0] != 0x7f || + strncmp(&elf_ex.e_ident[1], "ELF",3) != 0) + return -ENOEXEC; + + /* First of all, some simple consistency checks */ + if(elf_ex.e_type != ET_EXEC || elf_ex.e_phnum > 2 || + (elf_ex.e_machine != EM_386 && elf_ex.e_machine != EM_486) || + (!inode->i_op || !inode->i_op->bmap || + !inode->i_op->default_file_ops->mmap)){ + return -ENOEXEC; + }; + + /* Now read in all of the header information */ + + if(sizeof(struct elf_phdr) * elf_ex.e_phnum > PAGE_SIZE) + return -ENOEXEC; + + elf_phdata = (struct elf_phdr *) + kmalloc(sizeof(struct elf_phdr) * elf_ex.e_phnum, GFP_KERNEL); + + old_fs = get_fs(); + set_fs(get_ds()); + retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, + sizeof(struct elf_phdr) * elf_ex.e_phnum); + set_fs(old_fs); + + j = 0; + for(i=0; ip_type == PT_LOAD) j++; + + if(j != 1) { + kfree(elf_phdata); + return -ENOEXEC; + }; + + while(elf_phdata->p_type != PT_LOAD) elf_phdata++; + + /* Now use mmap to map the library into memory. */ + error = do_mmap(file, + elf_phdata->p_vaddr & 0xfffff000, + elf_phdata->p_filesz + (elf_phdata->p_vaddr & 0xfff), + 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) + 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/gems-kernel.git/source/THIRDPARTY/linux-old/fs/block_dev.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/block_dev.c new file mode 100644 index 000000000..22ffc2154 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/block_dev.c @@ -0,0 +1,215 @@ +/* + * linux/fs/block_dev.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +extern int *blk_size[]; +extern int *blksize_size[]; + +int block_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + int blocksize, blocksize_bits, i; + int block; + int offset; + int chars; + int written = 0; + unsigned int size; + unsigned int dev; + struct buffer_head * bh; + register char * p; + + dev = inode->i_rdev; + blocksize = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) + blocksize = blksize_size[MAJOR(dev)][MINOR(dev)]; + + i = blocksize; + blocksize_bits = 0; + while(i != 1) { + blocksize_bits++; + i >>= 1; + } + + block = filp->f_pos >> blocksize_bits; + offset = filp->f_pos & (blocksize-1); + + if (blk_size[MAJOR(dev)]) + size = (blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS) >> blocksize_bits; + else + size = INT_MAX; + while (count>0) { + if (block >= size) + return written; + chars = blocksize - offset; + if (chars > count) + chars=count; + if (chars == blocksize) + bh = getblk(dev, block, blocksize); + else + bh = breada(dev,block,block+1,block+2,-1); + block++; + if (!bh) + return written?written:-EIO; + p = offset + bh->b_data; + offset = 0; + filp->f_pos += chars; + written += chars; + count -= chars; + memcpy_fromfs(p,buf,chars); + p += chars; + buf += chars; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + } + return written; +} + +#define NBUF 32 + +int block_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + unsigned int block; + unsigned int offset; + int blocksize; + int blocksize_bits, i; + unsigned int left; + unsigned int blocks; + int bhrequest, uptodate; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * buflist[NBUF]; + struct buffer_head * bhreq[NBUF]; + unsigned int chars; + unsigned int size; + unsigned int dev; + int read; + + dev = inode->i_rdev; + blocksize = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) + blocksize = blksize_size[MAJOR(dev)][MINOR(dev)]; + i = blocksize; + blocksize_bits = 0; + while (i != 1) { + blocksize_bits++; + i >>= 1; + } + + offset = filp->f_pos; + if (blk_size[MAJOR(dev)]) + size = blk_size[MAJOR(dev)][MINOR(dev)] << BLOCK_SIZE_BITS; + else + size = INT_MAX; + + if (offset > size) + left = 0; + else + left = size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = offset >> blocksize_bits; + offset &= blocksize-1; + size >>= blocksize_bits; + blocks = (left + offset + blocksize - 1) >> blocksize_bits; + bhb = bhe = buflist; + if (filp->f_reada) { + blocks += read_ahead[MAJOR(dev)] / (blocksize >> 9); + if (block + blocks > size) + blocks = size - block; + } + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk. + + This routine is optimized to make maximum use of the various + buffers and caches. */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + *bhb = getblk(dev, block++, blocksize); + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing. */ + if (uptodate) + break; + if (bhb == bhe) + break; + } + + /* Now request them all */ + if (bhrequest) + ll_rw_block(READ, bhrequest, bhreq); + + do { /* Finish off all I/O that has actually completed */ + if (*bhe) { + wait_on_buffer(*bhe); + if (!(*bhe)->b_uptodate) { /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < blocksize - offset) + chars = left; + else + chars = blocksize - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs(buf,offset+(*bhe)->b_data,chars); + brelse(*bhe); + buf += chars; + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); + } while (left > 0); + +/* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + }; + if (!read) + return -EIO; + filp->f_reada = 1; + return read; +} + +int block_fsync(struct inode *inode, struct file *filp) +{ + return fsync_dev (inode->i_rdev); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/buffer.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/buffer.c new file mode 100644 index 000000000..1d0086852 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/buffer.c @@ -0,0 +1,1000 @@ +/* + * linux/fs/buffer.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'buffer.c' implements the buffer-cache functions. Race-conditions have + * been avoided by NEVER letting an interrupt change a buffer (except for the + * data, of course), but instead letting the caller do it. + */ + +/* + * NOTE! There is one discordant note here: checking floppies for + * disk change. This is where it fits best, I think, as it should + * invalidate changed floppy-disk-caches. + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#ifdef CONFIG_SCSI +#ifdef CONFIG_BLK_DEV_SR +extern int check_cdrom_media_change(int, int); +#endif +#ifdef CONFIG_BLK_DEV_SD +extern int check_scsidisk_media_change(int, int); +extern int revalidate_scsidisk(int, int); +#endif +#endif +#ifdef CONFIG_CDU31A +extern int check_cdu31a_media_change(int, int); +#endif +#ifdef CONFIG_MCD +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; +static struct wait_queue * buffer_wait = NULL; + +int nr_buffers = 0; +int buffermem = 0; +int nr_buffer_heads = 0; +static int min_free_pages = 20; /* nr free pages needed before buffer grows */ +extern int *blksize_size[]; + +/* + * Rewrote the wait-routines to use the "new" wait-queue functionality, + * and getting rid of the cli-sti pairs. The wait-queue routines still + * need cli-sti, but now it's just a couple of 386 instructions or so. + * + * Note that the real wait_on_buffer() is an inline function that checks + * if 'b_wait' is set before calling this, so that the queues aren't set + * up unnecessarily. + */ +void __wait_on_buffer(struct buffer_head * bh) +{ + struct wait_queue wait = { current, NULL }; + + bh->b_count++; + add_wait_queue(&bh->b_wait, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (bh->b_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&bh->b_wait, &wait); + bh->b_count--; + current->state = TASK_RUNNING; +} + +/* Call sync_buffers with wait!=0 to ensure that the call does not + return until all buffer writes have completed. Sync() may return + before the writes have finished; fsync() may not. */ + +static int sync_buffers(dev_t dev, int wait) +{ + int i, retry, pass = 0, err = 0; + struct buffer_head * bh; + + /* One pass for no-wait, three for wait: + 0) write out all dirty, unlocked buffers; + 1) write out all dirty buffers, waiting if locked; + 2) wait for completion by waiting for all buffers to unlock. + */ +repeat: + retry = 0; + bh = free_list; + for (i = nr_buffers*2 ; i-- > 0 ; bh = bh->b_next_free) { + if (dev && bh->b_dev != dev) + continue; +#ifdef 0 /* Disable bad-block debugging code */ + if (bh->b_req && !bh->b_lock && + !bh->b_dirt && !bh->b_uptodate) + printk ("Warning (IO error) - orphaned block %08x on %04x\n", + bh->b_blocknr, bh->b_dev); +#endif + if (bh->b_lock) + { + /* Buffer is locked; skip it unless wait is + requested AND pass > 0. */ + if (!wait || !pass) { + retry = 1; + continue; + } + wait_on_buffer (bh); + } + /* If an unlocked buffer is not uptodate, there has been + an IO error. Skip it. */ + if (wait && bh->b_req && !bh->b_lock && + !bh->b_dirt && !bh->b_uptodate) + { + err = 1; + continue; + } + /* Don't write clean buffers. Don't write ANY buffers + on the third pass. */ + if (!bh->b_dirt || pass>=2) + continue; + bh->b_count++; + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + retry = 1; + } + /* If we are waiting for the sync to succeed, and if any dirty + blocks were written, then repeat; on the second pass, only + wait for buffers being written (do not pass to write any + more buffers on the second pass). */ + if (wait && retry && ++pass<=2) + goto repeat; + return err; +} + +void sync_dev(dev_t dev) +{ + sync_buffers(dev, 0); + sync_supers(dev); + sync_inodes(dev); + sync_buffers(dev, 0); +} + +int fsync_dev(dev_t dev) +{ + sync_buffers(dev, 0); + sync_supers(dev); + sync_inodes(dev); + return sync_buffers(dev, 1); +} + +asmlinkage int sys_sync(void) +{ + sync_dev(0); + return 0; +} + +int file_fsync (struct inode *inode, struct file *filp) +{ + return fsync_dev(inode->i_dev); +} + +asmlinkage int sys_fsync(unsigned int fd) +{ + struct file * file; + struct inode * inode; + + if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode)) + return -EBADF; + if (!file->f_op || !file->f_op->fsync) + return -EINVAL; + if (file->f_op->fsync(inode,file)) + return -EIO; + return 0; +} + +void invalidate_buffers(dev_t dev) +{ + int i; + struct buffer_head * bh; + + bh = free_list; + for (i = nr_buffers*2 ; --i > 0 ; bh = bh->b_next_free) { + if (bh->b_dev != dev) + continue; + wait_on_buffer(bh); + if (bh->b_dev == dev) + bh->b_uptodate = bh->b_dirt = bh->b_req = 0; + } +} + +/* + * This routine checks whether a floppy has been changed, and + * invalidates all buffer-cache-entries in that case. This + * is a relatively slow routine, so we have to try to minimize using + * it. Thus it is called only upon a 'mount' or 'open'. This + * is the best way of combining speed and utility, I think. + * People changing diskettes in the middle of an operation deserve + * to loose :-) + * + * NOTE! Although currently this is only for floppies, the idea is + * that any additional removable block-device will use this routine, + * and that mount/open needn't know that floppies/whatever are + * special. + */ +void check_disk_change(dev_t dev) +{ + int i; + struct buffer_head * bh; + + switch(MAJOR(dev)){ + case FLOPPY_MAJOR: + if (!(bh = getblk(dev,0,1024))) + return; + i = floppy_change(bh); + brelse(bh); + break; + +#if defined(CONFIG_BLK_DEV_SD) && defined(CONFIG_SCSI) + case SCSI_DISK_MAJOR: + i = check_scsidisk_media_change(dev, 0); + break; +#endif + +#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) + case SCSI_CDROM_MAJOR: + i = check_cdrom_media_change(dev, 0); + break; +#endif + +#if defined(CONFIG_CDU31A) + case CDU31A_CDROM_MAJOR: + i = check_cdu31a_media_change(dev, 0); + break; +#endif + +#if defined(CONFIG_MCD) + case MITSUMI_CDROM_MAJOR: + i = check_mcd_media_change(dev, 0); + break; +#endif + + default: + return; + }; + + if (!i) return; + + printk("VFS: Disk change detected on device %d/%d\n", + MAJOR(dev), MINOR(dev)); + for (i=0 ; ib_next) + bh->b_next->b_prev = bh->b_prev; + if (bh->b_prev) + bh->b_prev->b_next = bh->b_next; + if (hash(bh->b_dev,bh->b_blocknr) == bh) + hash(bh->b_dev,bh->b_blocknr) = bh->b_next; + bh->b_next = bh->b_prev = NULL; +} + +static inline void remove_from_free_list(struct buffer_head * bh) +{ + if (!(bh->b_prev_free) || !(bh->b_next_free)) + panic("VFS: Free block list corrupted"); + bh->b_prev_free->b_next_free = bh->b_next_free; + bh->b_next_free->b_prev_free = bh->b_prev_free; + if (free_list == bh) + free_list = bh->b_next_free; + bh->b_next_free = bh->b_prev_free = NULL; +} + +static inline void remove_from_queues(struct buffer_head * bh) +{ + remove_from_hash_queue(bh); + remove_from_free_list(bh); +} + +static inline void put_first_free(struct buffer_head * bh) +{ + if (!bh || (bh == free_list)) + return; + remove_from_free_list(bh); +/* add to front of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; + free_list = bh; +} + +static inline void put_last_free(struct buffer_head * bh) +{ + if (!bh) + return; + if (bh == free_list) { + free_list = bh->b_next_free; + return; + } + remove_from_free_list(bh); +/* add to back of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; +} + +static inline void insert_into_queues(struct buffer_head * bh) +{ +/* put at end of free list */ + bh->b_next_free = free_list; + bh->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = bh; + free_list->b_prev_free = bh; +/* put the buffer in new hash-queue if it has a device */ + bh->b_prev = NULL; + bh->b_next = NULL; + if (!bh->b_dev) + return; + bh->b_next = hash(bh->b_dev,bh->b_blocknr); + hash(bh->b_dev,bh->b_blocknr) = bh; + if (bh->b_next) + bh->b_next->b_prev = bh; +} + +static struct buffer_head * find_buffer(dev_t dev, int block, int size) +{ + struct buffer_head * tmp; + + for (tmp = hash(dev,block) ; tmp != NULL ; tmp = tmp->b_next) + if (tmp->b_dev==dev && tmp->b_blocknr==block) + if (tmp->b_size == size) + return tmp; + else { + printk("VFS: Wrong blocksize on device %d/%d\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + return NULL; +} + +/* + * Why like this, I hear you say... The reason is race-conditions. + * As we don't lock buffers (unless we are readint them, that is), + * something might happen to it while we sleep (ie a read-error + * will force it bad). This shouldn't really happen currently, but + * the code is ready. + */ +struct buffer_head * get_hash_table(dev_t dev, int block, int size) +{ + struct buffer_head * bh; + + for (;;) { + if (!(bh=find_buffer(dev,block,size))) + return NULL; + bh->b_count++; + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_blocknr == block && bh->b_size == size) + return bh; + bh->b_count--; + } +} + +void set_blocksize(dev_t dev, int size) +{ + int i; + struct buffer_head * bh, *bhnext; + + if (!blksize_size[MAJOR(dev)]) + return; + + switch(size) { + default: panic("Invalid blocksize passed to set_blocksize"); + case 512: case 1024: case 2048: case 4096:; + } + + if (blksize_size[MAJOR(dev)][MINOR(dev)] == 0 && size == BLOCK_SIZE) { + blksize_size[MAJOR(dev)][MINOR(dev)] = size; + return; + } + if (blksize_size[MAJOR(dev)][MINOR(dev)] == size) + return; + sync_buffers(dev, 2); + blksize_size[MAJOR(dev)][MINOR(dev)] = size; + + /* We need to be quite careful how we do this - we are moving entries + around on the free list, and we can get in a loop if we are not careful.*/ + + bh = free_list; + for (i = nr_buffers*2 ; --i > 0 ; bh = bhnext) { + bhnext = bh->b_next_free; + if (bh->b_dev != dev) + continue; + if (bh->b_size == size) + continue; + + wait_on_buffer(bh); + if (bh->b_dev == dev && bh->b_size != size) + bh->b_uptodate = bh->b_dirt = 0; + remove_from_hash_queue(bh); +/* put_first_free(bh); */ + } +} + +/* + * Ok, this is getblk, and it isn't very clear, again to hinder + * race-conditions. Most of the code is seldom used, (ie repeating), + * so it should be much more efficient than it looks. + * + * The algoritm is changed: hopefully better, and an elusive bug removed. + * + * 14.02.92: changed it to sync dirty buffers a bit: better performance + * when the filesystem starts to get full of dirty blocks (I hope). + */ +#define BADNESS(bh) (((bh)->b_dirt<<1)+(bh)->b_lock) +struct buffer_head * getblk(dev_t dev, int block, int size) +{ + struct buffer_head * bh, * tmp; + int buffers; + static int grow_size = 0; + +repeat: + bh = get_hash_table(dev, block, size); + if (bh) { + if (bh->b_uptodate && !bh->b_dirt) + put_last_free(bh); + return bh; + } + grow_size -= size; + if (nr_free_pages > min_free_pages && grow_size <= 0) { + if (grow_buffers(GFP_BUFFER, size)) + grow_size = PAGE_SIZE; + } + buffers = nr_buffers; + bh = NULL; + + for (tmp = free_list; buffers-- > 0 ; tmp = tmp->b_next_free) { + if (tmp->b_count || tmp->b_size != size) + continue; + if (mem_map[MAP_NR((unsigned long) tmp->b_data)] != 1) + continue; + if (!bh || BADNESS(tmp)b_dirt) { + tmp->b_count++; + ll_rw_block(WRITEA, 1, &tmp); + tmp->b_count--; + } +#endif + } + + if (!bh && nr_free_pages > 5) { + if (grow_buffers(GFP_BUFFER, size)) + goto repeat; + } + +/* and repeat until we find something good */ + if (!bh) { + if (!grow_buffers(GFP_ATOMIC, size)) + sleep_on(&buffer_wait); + goto repeat; + } + wait_on_buffer(bh); + if (bh->b_count || bh->b_size != size) + goto repeat; + if (bh->b_dirt) { + sync_buffers(0,0); + goto repeat; + } +/* NOTE!! While we slept waiting for this block, somebody else might */ +/* already have added "this" block to the cache. check it */ + if (find_buffer(dev,block,size)) + goto repeat; +/* OK, FINALLY we know that this buffer is the only one of its kind, */ +/* and that it's unused (b_count=0), unlocked (b_lock=0), and clean */ + bh->b_count=1; + bh->b_dirt=0; + bh->b_uptodate=0; + bh->b_req=0; + remove_from_queues(bh); + bh->b_dev=dev; + bh->b_blocknr=block; + insert_into_queues(bh); + return bh; +} + +void brelse(struct buffer_head * buf) +{ + if (!buf) + return; + wait_on_buffer(buf); + if (buf->b_count) { + if (--buf->b_count) + return; + wake_up(&buffer_wait); + return; + } + printk("VFS: brelse: Trying to free free buffer\n"); +} + +/* + * bread() reads a specified block and returns the buffer that contains + * it. It returns NULL if the block was unreadable. + */ +struct buffer_head * bread(dev_t dev, int block, int size) +{ + struct buffer_head * bh; + + if (!(bh = getblk(dev, block, size))) { + printk("VFS: bread: READ error on device %d/%d\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + if (bh->b_uptodate) + return bh; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +/* + * Ok, breada can be used as bread, but additionally to mark other + * blocks for reading as well. End the argument list with a negative + * number. + */ +struct buffer_head * breada(dev_t dev,int first, ...) +{ + va_list args; + unsigned int blocksize; + struct buffer_head * bh, *tmp; + + va_start(args,first); + + blocksize = BLOCK_SIZE; + if (blksize_size[MAJOR(dev)] && blksize_size[MAJOR(dev)][MINOR(dev)]) + blocksize = blksize_size[MAJOR(dev)][MINOR(dev)]; + + if (!(bh = getblk(dev, first, blocksize))) { + printk("VFS: breada: READ error on device %d/%d\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + if (!bh->b_uptodate) + ll_rw_block(READ, 1, &bh); + while ((first=va_arg(args,int))>=0) { + tmp = getblk(dev, first, blocksize); + if (tmp) { + if (!tmp->b_uptodate) + ll_rw_block(READA, 1, &tmp); + tmp->b_count--; + } + } + va_end(args); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return (NULL); +} + +/* + * See fs/inode.c for the weird use of volatile.. + */ +static void put_unused_buffer_head(struct buffer_head * bh) +{ + struct wait_queue * wait; + + wait = ((volatile struct buffer_head *) bh)->b_wait; + memset((void *) bh,0,sizeof(*bh)); + ((volatile struct buffer_head *) bh)->b_wait = wait; + bh->b_next_free = unused_list; + unused_list = bh; +} + +static void get_more_buffer_heads(void) +{ + int i; + struct buffer_head * bh; + + if (unused_list) + return; + + if(! (bh = (struct buffer_head*) get_free_page(GFP_BUFFER))) + return; + + for (nr_buffer_heads+=i=PAGE_SIZE/sizeof*bh ; i>0; i--) { + bh->b_next_free = unused_list; /* only make link */ + unused_list = bh++; + } +} + +static struct buffer_head * get_unused_buffer_head(void) +{ + struct buffer_head * bh; + + get_more_buffer_heads(); + if (!unused_list) + return NULL; + bh = unused_list; + unused_list = bh->b_next_free; + bh->b_next_free = NULL; + bh->b_data = NULL; + bh->b_size = 0; + bh->b_req = 0; + return bh; +} + +/* + * Create the appropriate buffers when given a page for data area and + * the size of each buffer.. Use the bh->b_this_page linked list to + * follow the buffers created. Return NULL if unable to create more + * buffers. + */ +static struct buffer_head * create_buffers(unsigned long page, unsigned long size) +{ + struct buffer_head *bh, *head; + unsigned long offset; + + head = NULL; + offset = PAGE_SIZE; + while ((offset -= size) < PAGE_SIZE) { + bh = get_unused_buffer_head(); + if (!bh) + goto no_grow; + bh->b_this_page = head; + head = bh; + bh->b_data = (char *) (page+offset); + bh->b_size = size; + } + return head; +/* + * In case anything failed, we just free everything we got. + */ +no_grow: + bh = head; + while (bh) { + head = bh; + bh = bh->b_this_page; + put_unused_buffer_head(head); + } + return NULL; +} + +static void read_buffers(struct buffer_head * bh[], int nrbuf) +{ + int i; + int bhnum = 0; + struct buffer_head * bhr[8]; + + for (i = 0 ; i < nrbuf ; i++) { + if (bh[i] && !bh[i]->b_uptodate) + bhr[bhnum++] = bh[i]; + } + if (bhnum) + ll_rw_block(READ, bhnum, bhr); + for (i = 0 ; i < nrbuf ; i++) { + if (bh[i]) { + wait_on_buffer(bh[i]); + } + } +} + +static unsigned long check_aligned(struct buffer_head * first, unsigned long address, + dev_t dev, int *b, int size) +{ + struct buffer_head * bh[8]; + unsigned long page; + unsigned long offset; + int block; + int nrbuf; + + page = (unsigned long) first->b_data; + if (page & ~PAGE_MASK) { + brelse(first); + return 0; + } + mem_map[MAP_NR(page)]++; + bh[0] = first; + nrbuf = 1; + for (offset = size ; offset < PAGE_SIZE ; offset += size) { + block = *++b; + if (!block) + goto no_go; + first = get_hash_table(dev, block, size); + if (!first) + goto no_go; + bh[nrbuf++] = first; + if (page+offset != (unsigned long) first->b_data) + goto no_go; + } + read_buffers(bh,nrbuf); /* make sure they are actually read correctly */ + while (nrbuf-- > 0) + brelse(bh[nrbuf]); + free_page(address); + ++current->min_flt; + return page; +no_go: + while (nrbuf-- > 0) + brelse(bh[nrbuf]); + free_page(page); + return 0; +} + +static unsigned long try_to_load_aligned(unsigned long address, + dev_t dev, int b[], int size) +{ + struct buffer_head * bh, * tmp, * arr[8]; + unsigned long offset; + int * p; + int block; + + bh = create_buffers(address, size); + if (!bh) + return 0; + p = b; + for (offset = 0 ; offset < PAGE_SIZE ; offset += size) { + block = *(p++); + if (!block) + goto not_aligned; + tmp = get_hash_table(dev, block, size); + if (tmp) { + brelse(tmp); + goto not_aligned; + } + } + tmp = bh; + p = b; + block = 0; + while (1) { + arr[block++] = bh; + bh->b_count = 1; + bh->b_dirt = 0; + bh->b_uptodate = 0; + bh->b_dev = dev; + bh->b_blocknr = *(p++); + nr_buffers++; + insert_into_queues(bh); + if (bh->b_this_page) + bh = bh->b_this_page; + else + break; + } + buffermem += PAGE_SIZE; + bh->b_this_page = tmp; + mem_map[MAP_NR(address)]++; + read_buffers(arr,block); + while (block-- > 0) + brelse(arr[block]); + ++current->maj_flt; + return address; +not_aligned: + while ((tmp = bh) != NULL) { + bh = bh->b_this_page; + put_unused_buffer_head(tmp); + } + return 0; +} + +/* + * Try-to-share-buffers tries to minimize memory use by trying to keep + * both code pages and the buffer area in the same page. This is done by + * (a) checking if the buffers are already aligned correctly in memory and + * (b) if none of the buffer heads are in memory at all, trying to load + * them into memory the way we want them. + * + * This doesn't guarantee that the memory is shared, but should under most + * circumstances work very well indeed (ie >90% sharing of code pages on + * demand-loadable executables). + */ +static inline unsigned long try_to_share_buffers(unsigned long address, + dev_t dev, int *b, int size) +{ + struct buffer_head * bh; + int block; + + block = b[0]; + if (!block) + return 0; + bh = get_hash_table(dev, block, size); + if (bh) + return check_aligned(bh, address, dev, b, size); + return try_to_load_aligned(address, dev, b, size); +} + +#define COPYBLK(size,from,to) \ +__asm__ __volatile__("rep ; movsl": \ + :"c" (((unsigned long) size) >> 2),"S" (from),"D" (to) \ + :"cx","di","si") + +/* + * bread_page reads four buffers into memory at the desired address. It's + * a function of its own, as there is some speed to be got by reading them + * all at the same time, not waiting for one to be read, and then another + * etc. This also allows us to optimize memory usage by sharing code pages + * and filesystem buffers.. + */ +unsigned long bread_page(unsigned long address, dev_t dev, int b[], int size, int prot) +{ + struct buffer_head * bh[8]; + unsigned long where; + int i, j; + + if (!(prot & PAGE_RW)) { + where = try_to_share_buffers(address,dev,b,size); + if (where) + return where; + } + ++current->maj_flt; + for (i=0, j=0; jb_uptodate) + COPYBLK(size, (unsigned long) bh[i]->b_data,address); + brelse(bh[i]); + } + } + return where; +} + +/* + * Try to increase the number of buffers available: the size argument + * is used to determine what kind of buffers we want. + */ +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 0; + } + if(!(page = __get_free_page(pri))) + return 0; + bh = create_buffers(page, size); + if (!bh) { + free_page(page); + return 0; + } + tmp = bh; + while (1) { + if (free_list) { + tmp->b_next_free = free_list; + tmp->b_prev_free = free_list->b_prev_free; + free_list->b_prev_free->b_next_free = tmp; + free_list->b_prev_free = tmp; + } else { + tmp->b_prev_free = tmp; + tmp->b_next_free = tmp; + } + free_list = tmp; + ++nr_buffers; + if (tmp->b_this_page) + tmp = tmp->b_this_page; + else + break; + } + tmp->b_this_page = bh; + buffermem += PAGE_SIZE; + return 1; +} + +/* + * try_to_free() checks if all the buffers on this particular page + * are unused, and free's the page if so. + */ +static int try_to_free(struct buffer_head * bh, struct buffer_head ** bhp) +{ + unsigned long page; + struct buffer_head * tmp, * p; + + *bhp = bh; + page = (unsigned long) bh->b_data; + page &= PAGE_MASK; + tmp = bh; + do { + if (!tmp) + return 0; + if (tmp->b_count || tmp->b_dirt || tmp->b_lock) + return 0; + tmp = tmp->b_this_page; + } while (tmp != bh); + tmp = bh; + do { + p = tmp; + tmp = tmp->b_this_page; + nr_buffers--; + if (p == *bhp) + *bhp = p->b_prev_free; + remove_from_queues(p); + put_unused_buffer_head(p); + } while (tmp != bh); + buffermem -= PAGE_SIZE; + free_page(page); + return !mem_map[MAP_NR(page)]; +} + +/* + * Try to free up some pages by shrinking the buffer-cache + * + * Priority tells the routine how hard to try to shrink the + * buffers: 3 means "don't bother too much", while a value + * of 0 means "we'd better get some free pages now". + */ +int shrink_buffers(unsigned int priority) +{ + struct buffer_head *bh; + int i; + + if (priority < 2) + sync_buffers(0,0); + bh = free_list; + i = nr_buffers >> priority; + for ( ; i-- > 0 ; bh = bh->b_next_free) { + if (bh->b_count || !bh->b_this_page) + continue; + if (bh->b_lock) + if (priority) + continue; + else + wait_on_buffer(bh); + if (bh->b_dirt) { + bh->b_count++; + ll_rw_block(WRITEA, 1, &bh); + bh->b_count--; + continue; + } + if (try_to_free(bh, &bh)) + return 1; + } + return 0; +} + +/* + * This initializes the initial buffer free list. nr_buffers is set + * to one less the actual number of buffers, as a sop to backwards + * compatibility --- the old code did this (I think unintentionally, + * but I'm not sure), and programs in the ps package expect it. + * - TYT 8/30/92 + */ +void buffer_init(void) +{ + int i; + + if (high_memory >= 4*1024*1024) + min_free_pages = 200; + else + min_free_pages = 20; + for (i = 0 ; i < NR_HASH ; i++) + hash_table[i] = NULL; + free_list = 0; + grow_buffers(GFP_KERNEL, BLOCK_SIZE); + if (!free_list) + panic("VFS: Unable to initialize buffer free list!"); + return; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/devices.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/devices.c new file mode 100644 index 000000000..fb6e2c7b4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/devices.c @@ -0,0 +1,193 @@ +/* + * linux/fs/devices.c + * + * (C) 1993 Matthias Urlichs -- collected common code and tables. + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +struct device_struct { + const char * name; + struct file_operations * fops; +}; + +static struct device_struct chrdevs[MAX_CHRDEV] = { + { NULL, NULL }, +}; + +static struct device_struct blkdevs[MAX_BLKDEV] = { + { NULL, NULL }, +}; + +struct file_operations * get_blkfops(unsigned int major) +{ + if (major >= MAX_BLKDEV) + return NULL; + return blkdevs[major].fops; +} + +struct file_operations * get_chrfops(unsigned int major) +{ + if (major >= MAX_CHRDEV) + return NULL; + return chrdevs[major].fops; +} + +int register_chrdev(unsigned int major, const char * name, struct file_operations *fops) +{ + if (major >= MAX_CHRDEV) + return -EINVAL; + if (chrdevs[major].fops) + return -EBUSY; + chrdevs[major].name = name; + chrdevs[major].fops = fops; + return 0; +} + +int register_blkdev(unsigned int major, const char * name, struct file_operations *fops) +{ + if (major >= MAX_BLKDEV) + return -EINVAL; + if (blkdevs[major].fops) + return -EBUSY; + blkdevs[major].name = name; + blkdevs[major].fops = fops; + return 0; +} + +int unregister_chrdev(unsigned int major, const char * name) +{ + if (major >= MAX_CHRDEV) + return -EINVAL; + if (!chrdevs[major].fops) + return -EINVAL; + if (strcmp(chrdevs[major].name, name)) + return -EINVAL; + chrdevs[major].name = NULL; + chrdevs[major].fops = NULL; + return 0; +} + +int unregister_blkdev(unsigned int major, const char * name) +{ + if (major >= MAX_BLKDEV) + return -EINVAL; + if (!blkdevs[major].fops) + return -EINVAL; + if (strcmp(blkdevs[major].name, name)) + return -EINVAL; + blkdevs[major].name = NULL; + blkdevs[major].fops = NULL; + return 0; +} + +/* + * Called every time a block special file is opened + */ +int blkdev_open(struct inode * inode, struct file * filp) +{ + int i; + + i = MAJOR(inode->i_rdev); + if (i >= MAX_BLKDEV || !blkdevs[i].fops) + return -ENODEV; + filp->f_op = blkdevs[i].fops; + if (filp->f_op->open) + return filp->f_op->open(inode,filp); + return 0; +} + +/* + * Dummy default file-operations: the only thing this does + * is contain the open that then fills in the correct operations + * depending on the special file... + */ +struct file_operations def_blk_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + blkdev_open, /* open */ + NULL, /* release */ +}; + +struct inode_operations blkdev_inode_operations = { + &def_blk_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/* + * Called every time a character special file is opened + */ +int chrdev_open(struct inode * inode, struct file * filp) +{ + int i; + + i = MAJOR(inode->i_rdev); + if (i >= MAX_CHRDEV || !chrdevs[i].fops) + return -ENODEV; + filp->f_op = chrdevs[i].fops; + if (filp->f_op->open) + return filp->f_op->open(inode,filp); + return 0; +} + +/* + * Dummy default file-operations: the only thing this does + * is contain the open that then fills in the correct operations + * depending on the special file... + */ +struct file_operations def_chr_fops = { + NULL, /* lseek */ + NULL, /* read */ + NULL, /* write */ + NULL, /* readdir */ + NULL, /* select */ + NULL, /* ioctl */ + NULL, /* mmap */ + chrdev_open, /* open */ + NULL, /* release */ +}; + +struct inode_operations chrdev_inode_operations = { + &def_chr_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/exec.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/exec.c new file mode 100644 index 000000000..4f744f1e4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/exec.c @@ -0,0 +1,905 @@ +/* + * linux/fs/exec.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * #!-checking implemented by tytso. + */ + +/* + * Demand-loading implemented 01.12.91 - no need to read anything but + * the header into memory. The inode of the executable is put into + * "current->executable", and page faults do the actual loading. Clean. + * + * Once more I can proudly say that linux stood up to being changed: it + * was less than 2 hours work to get demand-loading completely implemented. + * + * Demand loading changed July 1993 by Eric Youngdale. Use mmap instead, + * current->executable is only used by the procfs. This allows a dispatch + * table to check for several different types of binary formats. We keep + * trying until we recognize the file or we run out of supported binary + * formats. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +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); + +int open_inode(struct inode * inode, int mode) +{ + int error, fd; + struct file *f, **fpp; + + if (!inode->i_op || !inode->i_op->default_file_ops) + return -EINVAL; + f = get_empty_filp(); + if (!f) + return -EMFILE; + fd = 0; + fpp = current->filp; + for (;;) { + if (!*fpp) + break; + if (++fd > NR_OPEN) + return -ENFILE; + fpp++; + } + *fpp = f; + f->f_flags = mode; + f->f_mode = (mode+1) & O_ACCMODE; + f->f_inode = inode; + f->f_pos = 0; + f->f_reada = 0; + f->f_op = inode->i_op->default_file_ops; + if (f->f_op->open) { + error = f->f_op->open(inode,f); + if (error) { + *fpp = NULL; + f->f_count--; + return error; + } + } + inode->i_count++; + return fd; +} + +/* + * These are the only things you should do on a core-file: use only these + * macros to write out all the necessary info. + */ +#define DUMP_WRITE(addr,nr) \ +while (file.f_op->write(inode,&file,(char *)(addr),(nr)) != (nr)) goto close_coredump + +#define DUMP_SEEK(offset) \ +if (file.f_op->lseek) { \ + if (file.f_op->lseek(inode,&file,(offset),0) != (offset)) \ + goto close_coredump; \ +} else file.f_pos = (offset) + +/* + * Routine writes a core dump image in the current directory. + * Currently only a stub-function. + * + * Note that setuid/setgid files won't make a core-dump if the uid/gid + * changed due to the set[u|g]id. It's enforced by the "current->dumpable" + * field, which also makes sure the core-dumps won't be recursive if the + * dumping of the process results in another error.. + */ +int core_dump(long signr, struct pt_regs * regs) +{ + struct inode * inode = NULL; + struct file file; + unsigned short fs; + int has_dumped = 0; + char corefile[6+sizeof(current->comm)]; + int i; + register int dump_start, dump_size; + struct user dump; + + if (!current->dumpable) + return 0; + current->dumpable = 0; + +/* See if we have enough room to write the upage. */ + if (current->rlim[RLIMIT_CORE].rlim_cur < PAGE_SIZE) + return 0; + fs = get_fs(); + set_fs(KERNEL_DS); + memcpy(corefile,"core.",5); + memcpy(corefile+5,current->comm,sizeof(current->comm)); + if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { + inode = NULL; + goto end_coredump; + } + if (!S_ISREG(inode->i_mode)) + goto end_coredump; + if (!inode->i_op || !inode->i_op->default_file_ops) + goto end_coredump; + file.f_mode = 3; + file.f_flags = 0; + file.f_count = 1; + file.f_inode = inode; + file.f_pos = 0; + file.f_reada = 0; + file.f_op = inode->i_op->default_file_ops; + if (file.f_op->open) + if (file.f_op->open(inode,&file)) + goto end_coredump; + if (!file.f_op->write) + goto close_coredump; + has_dumped = 1; +/* changed the size calculations - should hopefully work better. lbt */ + dump.magic = CMAGIC; + dump.start_code = 0; + dump.start_stack = regs->esp & ~(PAGE_SIZE - 1); + dump.u_tsize = ((unsigned long) current->end_code) >> 12; + 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 + if we wrote the stack, but not the data area. */ + if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > + current->rlim[RLIMIT_CORE].rlim_cur) + dump.u_dsize = 0; +/* Make sure we have enough room to write the stack and data areas. */ + if ((dump.u_ssize+1) * PAGE_SIZE > + current->rlim[RLIMIT_CORE].rlim_cur) + dump.u_ssize = 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; +/* Flag indicating the math stuff is valid. We don't support this for the + soft-float routines yet */ + if (hard_math) { + if ((dump.u_fpvalid = current->used_math) != 0) { + if (last_task_used_math == current) + __asm__("clts ; fnsave %0": :"m" (dump.i387)); + else + memcpy(&dump.i387,¤t->tss.i387.hard,sizeof(dump.i387)); + } + } else { + /* we should dump the emulator state here, but we need to + convert it into standard 387 format first.. */ + dump.u_fpvalid = 0; + } + set_fs(KERNEL_DS); +/* struct user */ + DUMP_WRITE(&dump,sizeof(dump)); +/* 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 */ + set_fs(USER_DS); +/* Dump the data area */ + if (dump.u_dsize != 0) { + dump_start = dump.u_tsize << 12; + dump_size = dump.u_dsize << 12; + DUMP_WRITE(dump_start,dump_size); + }; +/* Now prepare to dump the stack area */ + if (dump.u_ssize != 0) { + dump_start = dump.start_stack; + dump_size = dump.u_ssize << 12; + DUMP_WRITE(dump_start,dump_size); + }; +/* Finally dump the task struct. Not be used by gdb, but could be useful */ + set_fs(KERNEL_DS); + DUMP_WRITE(current,sizeof(*current)); +close_coredump: + if (file.f_op->release) + file.f_op->release(inode,&file); +end_coredump: + set_fs(fs); + iput(inode); + return has_dumped; +} + +/* + * Note that a shared library must be both readable and executable due to + * security reasons. + * + * Also note that we take the address to load from from the file itself. + */ +asmlinkage int sys_uselib(const char * library) +{ + int fd, retval; + struct file * file; + struct linux_binfmt * fmt; + + fd = sys_open(library, 0, 0); + if (fd < 0) + return fd; + file = current->filp[fd]; + retval = -ENOEXEC; + if (file && file->f_inode && file->f_op && file->f_op->read) { + fmt = formats; + do { + int (*fn)(int) = fmt->load_shlib; + if (!fn) + break; + retval = fn(fd); + fmt++; + } while (retval == -ENOEXEC); + } + sys_close(fd); + return retval; +} + +/* + * create_tables() parses the env- and arg-strings in new user + * memory and creates the pointer tables from them, and puts their + * addresses on the "stack", returning the new stack pointer value. + */ +unsigned long * create_tables(char * p,int argc,int envc,int ibcs) +{ + unsigned long *argv,*envp; + unsigned long * sp; + struct vm_area_struct *mpnt; + + mpnt = (struct vm_area_struct *)kmalloc(sizeof(*mpnt), GFP_KERNEL); + if (mpnt) { + mpnt->vm_task = current; + mpnt->vm_start = PAGE_MASK & (unsigned long) p; + 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; + } + sp = (unsigned long *) (0xfffffffc & (unsigned long) p); + sp -= envc+1; + envp = sp; + sp -= argc+1; + argv = sp; + if (!ibcs) { + put_fs_long((unsigned long)envp,--sp); + put_fs_long((unsigned long)argv,--sp); + } + put_fs_long((unsigned long)argc,--sp); + current->arg_start = (unsigned long) p; + while (argc-->0) { + put_fs_long((unsigned long) p,argv++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,argv); + current->arg_end = current->env_start = (unsigned long) p; + while (envc-->0) { + put_fs_long((unsigned long) p,envp++); + while (get_fs_byte(p++)) /* nothing */ ; + } + put_fs_long(0,envp); + current->env_end = (unsigned long) p; + return sp; +} + +/* + * count() counts the number of arguments/envelopes + */ +static int count(char ** argv) +{ + int i=0; + char ** tmp; + + if ((tmp = argv) != 0) + while (get_fs_long((unsigned long *) (tmp++))) + i++; + + return i; +} + +/* + * 'copy_string()' copies argument/envelope strings from user + * memory to free pages in kernel mem. These are in a format ready + * to be put directly into the top of new user memory. + * + * Modified by TYT, 11/24/91 to add the from_kmem argument, which specifies + * whether the string and the string array are from user or kernel segments: + * + * from_kmem argv * argv ** + * 0 user space user space + * 1 kernel space user space + * 2 kernel space kernel space + * + * We do this by playing games with the fs segment register. Since it + * it is expensive to load a segment register, we try to avoid calling + * set_fs() unless we absolutely have to. + */ +unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem) +{ + char *tmp, *pag = NULL; + int len, offset = 0; + unsigned long old_fs, new_fs; + + if (!p) + return 0; /* bullet-proofing */ + new_fs = get_ds(); + old_fs = get_fs(); + if (from_kmem==2) + set_fs(new_fs); + while (argc-- > 0) { + if (from_kmem == 1) + set_fs(new_fs); + if (!(tmp = (char *)get_fs_long(((unsigned long *)argv)+argc))) + panic("VFS: argc is wrong"); + if (from_kmem == 1) + set_fs(old_fs); + len=0; /* remember zero-padding */ + do { + len++; + } while (get_fs_byte(tmp++)); + if (p < len) { /* this shouldn't happen - 128kB */ + set_fs(old_fs); + return 0; + } + while (len) { + --p; --tmp; --len; + if (--offset < 0) { + offset = p % PAGE_SIZE; + if (from_kmem==2) + set_fs(old_fs); + if (!(pag = (char *) page[p/PAGE_SIZE]) && + !(pag = (char *) page[p/PAGE_SIZE] = + (unsigned long *) get_free_page(GFP_USER))) + return 0; + if (from_kmem==2) + set_fs(new_fs); + + } + *(pag + offset) = get_fs_byte(tmp); + } + } + if (from_kmem==2) + set_fs(old_fs); + return p; +} + +unsigned long change_ldt(unsigned long text_size,unsigned long * page) +{ + unsigned long code_limit,data_limit,code_base,data_base; + int i; + + code_limit = TASK_SIZE; + data_limit = TASK_SIZE; + code_base = data_base = 0; + current->start_code = code_base; + data_base += data_limit; + for (i=MAX_ARG_PAGES-1 ; i>=0 ; i--) { + data_base -= PAGE_SIZE; + if (page[i]) { + current->rss++; + put_dirty_page(current,page[i],data_base); + } + } + return data_limit; +} + +/* + * Read in the complete executable. This is used for "-N" files + * that aren't on a block boundary, and for files on filesystems + * without bmap support. + */ +int read_exec(struct inode *inode, unsigned long offset, + char * addr, unsigned long count) +{ + struct file file; + int result = -ENOEXEC; + + if (!inode->i_op || !inode->i_op->default_file_ops) + goto end_readexec; + file.f_mode = 1; + file.f_flags = 0; + file.f_count = 1; + file.f_inode = inode; + file.f_pos = 0; + file.f_reada = 0; + file.f_op = inode->i_op->default_file_ops; + if (file.f_op->open) + if (file.f_op->open(inode,&file)) + goto end_readexec; + if (!file.f_op || !file.f_op->read) + goto close_readexec; + if (file.f_op->lseek) { + if (file.f_op->lseek(inode,&file,offset,0) != offset) + goto close_readexec; + } else + file.f_pos = offset; + if (get_fs() == USER_DS) { + result = verify_area(VERIFY_WRITE, addr, count); + if (result) + goto close_readexec; + } + result = file.f_op->read(inode, &file, addr, count); +close_readexec: + if (file.f_op->release) + file.f_op->release(inode,&file); +end_readexec: + return result; +} + + +/* + * This function flushes out all traces of the currently running executable so + * that a new one can be started + */ + +void flush_old_exec(struct linux_binprm * bprm) +{ + int i; + int ch; + char * name; + struct vm_area_struct * mpnt, *mpnt1; + + current->dumpable = 1; + name = bprm->filename; + for (i=0; (ch = *(name++)) != '\0';) { + if (ch == '/') + i = 0; + else + if (i < 15) + current->comm[i++] = ch; + } + current->comm[i] = '\0'; + if (current->shm) + shm_exit(); + if (current->executable) { + iput(current->executable); + current->executable = NULL; + } + /* Release all of the old mmap stuff. */ + + mpnt = current->mmap; + current->mmap = NULL; + current->stk_vma = NULL; + while (mpnt) { + mpnt1 = mpnt->vm_next; + if (mpnt->vm_ops && mpnt->vm_ops->close) + mpnt->vm_ops->close(mpnt); + kfree(mpnt); + mpnt = mpnt1; + } + + /* Flush the old ldt stuff... */ + if (current->ldt) { + free_page((unsigned long) current->ldt); + current->ldt = NULL; + for (i=1 ; idebugreg[i] = 0; + + if (bprm->e_uid != current->euid || bprm->e_gid != current->egid || + !permission(bprm->inode,MAY_READ)) + current->dumpable = 0; + current->signal = 0; + for (i=0 ; i<32 ; i++) { + current->sigaction[i].sa_mask = 0; + current->sigaction[i].sa_flags = 0; + if (current->sigaction[i].sa_handler != SIG_IGN) + current->sigaction[i].sa_handler = NULL; + } + for (i=0 ; iclose_on_exec)) + sys_close(i); + FD_ZERO(¤t->close_on_exec); + clear_page_tables(current); + if (last_task_used_math == current) + last_task_used_math = NULL; + current->used_math = 0; + current->elf_executable = 0; +} + +/* + * sys_execve() executes a new program. + */ +static int do_execve(char * filename, char ** argv, char ** envp, struct pt_regs * regs) +{ + struct linux_binprm bprm; + struct linux_binfmt * fmt; + unsigned long old_fs; + int i; + int retval; + int sh_bang = 0; + + if (regs->cs != USER_CS) + return -EINVAL; + bprm.p = PAGE_SIZE*MAX_ARG_PAGES-4; + for (i=0 ; ii_mode)) { /* must be regular file */ + retval = -EACCES; + goto exec_error2; + } + if (IS_NOEXEC(bprm.inode)) { /* FS mustn't be mounted noexec */ + retval = -EPERM; + goto exec_error2; + } + if (!bprm.inode->i_sb) { + retval = -EACCES; + goto exec_error2; + } + i = bprm.inode->i_mode; + if (IS_NOSUID(bprm.inode) && (((i & S_ISUID) && bprm.inode->i_uid != current-> + euid) || ((i & S_ISGID) && !in_group_p(bprm.inode->i_gid))) && + !suser()) { + retval = -EPERM; + goto exec_error2; + } + /* make sure we don't let suid, sgid files be ptraced. */ + if (current->flags & PF_PTRACED) { + bprm.e_uid = current->euid; + bprm.e_gid = current->egid; + } else { + bprm.e_uid = (i & S_ISUID) ? bprm.inode->i_uid : current->euid; + bprm.e_gid = (i & S_ISGID) ? bprm.inode->i_gid : current->egid; + } + if (current->euid == bprm.inode->i_uid) + i >>= 6; + else if (in_group_p(bprm.inode->i_gid)) + i >>= 3; + if (!(i & 1) && + !((bprm.inode->i_mode & 0111) && suser())) { + retval = -EACCES; + goto exec_error2; + } + memset(bprm.buf,0,sizeof(bprm.buf)); + old_fs = get_fs(); + set_fs(get_ds()); + retval = read_exec(bprm.inode,0,bprm.buf,128); + set_fs(old_fs); + if (retval < 0) + goto exec_error2; + if ((bprm.buf[0] == '#') && (bprm.buf[1] == '!') && (!sh_bang)) { + /* + * This section does the #! interpretation. + * Sorta complicated, but hopefully it will work. -TYT + */ + + char *cp, *interp, *i_name, *i_arg; + + iput(bprm.inode); + bprm.buf[127] = '\0'; + if ((cp = strchr(bprm.buf, '\n')) == NULL) + cp = bprm.buf+127; + *cp = '\0'; + while (cp > bprm.buf) { + cp--; + if ((*cp == ' ') || (*cp == '\t')) + *cp = '\0'; + else + break; + } + for (cp = bprm.buf+2; (*cp == ' ') || (*cp == '\t'); cp++); + if (!cp || *cp == '\0') { + retval = -ENOEXEC; /* No interpreter name found */ + goto exec_error1; + } + interp = i_name = cp; + i_arg = 0; + for ( ; *cp && (*cp != ' ') && (*cp != '\t'); cp++) { + if (*cp == '/') + i_name = cp+1; + } + while ((*cp == ' ') || (*cp == '\t')) + *cp++ = '\0'; + if (*cp) + i_arg = cp; + /* + * OK, we've parsed out the interpreter name and + * (optional) argument. + */ + if (sh_bang++ == 0) { + bprm.p = copy_strings(bprm.envc, envp, bprm.page, bprm.p, 0); + bprm.p = copy_strings(--bprm.argc, argv+1, bprm.page, bprm.p, 0); + } + /* + * Splice in (1) the interpreter's name for argv[0] + * (2) (optional) argument to interpreter + * (3) filename of shell script + * + * This is done in reverse order, because of how the + * user environment and arguments are stored. + */ + bprm.p = copy_strings(1, &bprm.filename, bprm.page, bprm.p, 2); + bprm.argc++; + if (i_arg) { + bprm.p = copy_strings(1, &i_arg, bprm.page, bprm.p, 2); + bprm.argc++; + } + bprm.p = copy_strings(1, &i_name, bprm.page, bprm.p, 2); + bprm.argc++; + if (!bprm.p) { + retval = -E2BIG; + goto exec_error1; + } + /* + * OK, now restart the process with the interpreter's inode. + * Note that we use open_namei() as the name is now in kernel + * space, and we don't need to copy it. + */ + retval = open_namei(interp, 0, 0, &bprm.inode, NULL); + if (retval) + goto exec_error1; + goto restart_interp; + } + if (!sh_bang) { + bprm.p = copy_strings(bprm.envc,envp,bprm.page,bprm.p,0); + bprm.p = copy_strings(bprm.argc,argv,bprm.page,bprm.p,0); + if (!bprm.p) { + retval = -E2BIG; + goto exec_error2; + } + } + + bprm.sh_bang = sh_bang; + fmt = formats; + do { + int (*fn)(struct linux_binprm *, struct pt_regs *) = fmt->load_binary; + if (!fn) + break; + retval = fn(&bprm, regs); + if (retval == 0) { + iput(bprm.inode); + return 0; + } + fmt++; + } while (retval == -ENOEXEC); +exec_error2: + iput(bprm.inode); +exec_error1: + for (i=0 ; ip; + + ex = *((struct exec *) bprm->buf); /* exec-header */ + if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && + N_MAGIC(ex) != QMAGIC) || + ex.a_trsize || ex.a_drsize || + bprm->inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + return -ENOEXEC; + } + + if (N_MAGIC(ex) == ZMAGIC && + (N_TXTOFF(ex) < bprm->inode->i_sb->s_blocksize)) { + printk("N_TXTOFF < BLOCK_SIZE. Please convert binary."); + return -ENOEXEC; + } + + if (N_TXTOFF(ex) != BLOCK_SIZE && N_MAGIC(ex) == ZMAGIC) { + printk("N_TXTOFF != BLOCK_SIZE. See a.out.h."); + return -ENOEXEC; + } + + /* OK, This is the point of no return */ + flush_old_exec(bprm); + + 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) + printk("%s: executable not page aligned\n", current->comm); + + fd = open_inode(bprm->inode, O_RDONLY); + + if (fd < 0) + return fd; + file = current->filp[fd]; + if (!file->f_op || !file->f_op->mmap) { + sys_close(fd); + 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; + } + error = do_mmap(file, N_TXTADDR(ex), ex.a_text, + PROT_READ | PROT_EXEC, + MAP_FIXED | MAP_SHARED, N_TXTOFF(ex)); + + if (error != N_TXTADDR(ex)) { + sys_close(fd); + send_sig(SIGSEGV, current, 0); + return 0; + }; + + error = do_mmap(file, N_TXTADDR(ex) + ex.a_text, ex.a_data, + PROT_READ | PROT_WRITE | PROT_EXEC, + MAP_FIXED | MAP_PRIVATE, N_TXTOFF(ex) + ex.a_text); + sys_close(fd); + if (error != N_TXTADDR(ex) + ex.a_text) { + send_sig(SIGSEGV, current, 0); + return 0; + }; + current->executable = bprm->inode; + bprm->inode->i_count++; + } +beyond_if: + 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,0); + current->start_stack = p; + regs->eip = ex.a_entry; /* eip, magic happens :-) */ + regs->esp = p; /* stack pointer */ + if (current->flags & PF_PTRACED) + send_sig(SIGTRAP, current, 0); + return 0; +} + + +int load_aout_library(int fd) +{ + struct file * file; + struct exec ex; + struct inode * inode; + unsigned int len; + unsigned int bss; + unsigned int start_addr; + int error; + + file = current->filp[fd]; + inode = file->f_inode; + + set_fs(KERNEL_DS); + if (file->f_op->read(inode, file, (char *) &ex, sizeof(ex)) != sizeof(ex)) { + return -EACCES; + } + set_fs(USER_DS); + + /* We come in here for the regular a.out style of shared libraries */ + if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != QMAGIC) || ex.a_trsize || + ex.a_drsize || ((ex.a_entry & 0xfff) && N_MAGIC(ex) == ZMAGIC) || + inode->i_size < ex.a_text+ex.a_data+ex.a_syms+N_TXTOFF(ex)) { + return -ENOEXEC; + } + if (N_MAGIC(ex) == ZMAGIC && N_TXTOFF(ex) && + (N_TXTOFF(ex) < inode->i_sb->s_blocksize)) { + printk("N_TXTOFF < BLOCK_SIZE. Please convert library\n"); + return -ENOEXEC; + } + + if (N_FLAGS(ex)) return -ENOEXEC; + + /* For QMAGIC, the starting address is 0x20 into the page. We mask + this off to get the starting address for the page */ + + start_addr = ex.a_entry & 0xfffff000; + + /* Now use mmap to map the library into memory. */ + error = do_mmap(file, start_addr, ex.a_text + ex.a_data, + PROT_READ | PROT_WRITE | PROT_EXEC, MAP_FIXED | MAP_PRIVATE, + N_TXTOFF(ex)); + if (error != start_addr) + return error; + len = PAGE_ALIGN(ex.a_text + ex.a_data); + bss = ex.a_text + ex.a_data + ex.a_bss; + if (bss > len) + do_mmap(NULL, start_addr + len, bss-len, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_PRIVATE|MAP_FIXED, 0); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/Makefile new file mode 100644 index 000000000..5e23319c8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for the linux ext-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= freelists.o truncate.o namei.o inode.o \ + file.o dir.o symlink.o fsync.o + +ext.o: $(OBJS) + $(LD) -r -o ext.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/dir.c new file mode 100644 index 000000000..a7667a3c1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/dir.c @@ -0,0 +1,118 @@ +/* + * linux/fs/ext/dir.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext directory handling functions + */ + +#include + +#include +#include +#include +#include +#include + +static int ext_dir_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + return -EISDIR; +} + +static int ext_readdir(struct inode *, struct file *, struct dirent *, int); + +static struct file_operations ext_dir_operations = { + NULL, /* lseek - default */ + ext_dir_read, /* read */ + NULL, /* write - bad */ + ext_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations ext_dir_inode_operations = { + &ext_dir_operations, /* default directory file-ops */ + ext_create, /* create */ + ext_lookup, /* lookup */ + ext_link, /* link */ + ext_unlink, /* unlink */ + ext_symlink, /* symlink */ + ext_mkdir, /* mkdir */ + ext_rmdir, /* rmdir */ + ext_mknod, /* mknod */ + ext_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + ext_truncate, /* truncate */ + NULL /* permission */ +}; + +static int ext_readdir(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + unsigned int offset,i; + char c; + struct buffer_head * bh; + struct ext_dir_entry * de; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + if (filp->f_pos % 8 != 0) + return -EBADF; + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & 1023; + bh = ext_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0); + if (!bh) { + filp->f_pos += 1024-offset; + continue; + } + de = (struct ext_dir_entry *) (offset + bh->b_data); + while (offset < 1024 && filp->f_pos < inode->i_size) { + if (de->rec_len < 8 || de->rec_len % 8 != 0 || + de->rec_len < de->name_len + 8 || + (de->rec_len + filp->f_pos - 1) / 1024 > (filp->f_pos / 1024)) { + printk ("ext_readdir: bad dir entry, skipping\n"); + printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n", + inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len); + filp->f_pos += 1024-offset; + if (filp->f_pos > inode->i_size) + filp->f_pos = inode->i_size; + continue; + } + offset += de->rec_len; + filp->f_pos += de->rec_len; + if (de->inode) { + for (i = 0; i < de->name_len; i++) + if ((c = de->name[i]) != 0) + put_fs_byte(c,i+dirent->d_name); + else + break; + if (i) { + put_fs_long(de->inode,&dirent->d_ino); + put_fs_byte(0,i+dirent->d_name); + put_fs_word(i,&dirent->d_reclen); + brelse(bh); + return i; + } + } + de = (struct ext_dir_entry *) ((char *) de + + de->rec_len); + } + brelse(bh); + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/file.c new file mode 100644 index 000000000..d8caabd2c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/file.c @@ -0,0 +1,257 @@ +/* + * linux/fs/ext/file.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +static int ext_file_read(struct inode *, struct file *, char *, int); +static int ext_file_write(struct inode *, struct file *, char *, int); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the ext filesystem. + */ +static struct file_operations ext_file_operations = { + NULL, /* lseek - default */ + ext_file_read, /* read */ + ext_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + ext_sync_file /* fsync */ +}; + +struct inode_operations ext_file_inode_operations = { + &ext_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + ext_bmap, /* bmap */ + ext_truncate, /* truncate */ + NULL /* permission */ +}; + +static int ext_file_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int read,left,chars; + int block, blocks, offset; + int bhrequest, uptodate; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + unsigned int size; + + if (!inode) { + printk("ext_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("ext_file_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + offset = filp->f_pos; + size = inode->i_size; + if (offset > size) + left = 0; + else + left = size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = offset >> BLOCK_SIZE_BITS; + offset &= BLOCK_SIZE-1; + size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS; + blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; + bhb = bhe = buflist; + if (filp->f_reada) { + blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9); + if (block + blocks > size) + blocks = size - block; + } + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk. + + This routine is optimized to make maximum use of the various + buffers and caches. */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + *bhb = ext_getblk(inode, block++, 0); + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing. */ + if (uptodate) + break; + if (bhb == bhe) + break; + } + + /* Now request them all */ + if (bhrequest) + ll_rw_block(READ, bhrequest, bhreq); + + do { /* Finish off all I/O that has actually completed */ + if (*bhe) { + wait_on_buffer(*bhe); + if (!(*bhe)->b_uptodate) { /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < BLOCK_SIZE - offset) + chars = left; + else + chars = BLOCK_SIZE - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs(buf,offset+(*bhe)->b_data,chars); + brelse(*bhe); + buf += chars; + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); + } while (left > 0); + +/* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + }; + if (!read) + return -EIO; + filp->f_reada = 1; + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return read; +} + +static int ext_file_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int written,c; + struct buffer_head * bh; + char * p; + + if (!inode) { + printk("ext_file_write: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("ext_file_write: mode = %07o\n",inode->i_mode); + return -EINVAL; + } +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written count-written) + c = count-written; + if (c != BLOCK_SIZE && !bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + if (!written) + written = -EIO; + break; + } + } + p = (pos % BLOCK_SIZE) + bh->b_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs(p,buf,c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + return written; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/freelists.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/freelists.c new file mode 100644 index 000000000..6462da1c9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/freelists.c @@ -0,0 +1,348 @@ +/* + * linux/fs/ext/freelists.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + */ + +/* freelists.c contains the code that handles the inode and block free lists */ + + +/* + + The free blocks are managed by a linked list. The super block contains the + number of the first free block. This block contains 254 numbers of other + free blocks and the number of the next block in the list. + + When an ext fs is mounted, the number of the first free block is stored + in s->u.ext_sb.s_firstfreeblocknumber and the block header is stored in + s->u.ext_sb.s_firstfreeblock. u.ext_sb.s_freeblockscount contains the count + of free blocks. + + The free inodes are also managed by a linked list in a similar way. The + super block contains the number of the first free inode. This inode contains + 14 numbers of other free inodes and the number of the next inode in the list. + + The number of the first free inode is stored in + s->u.ext_sb.s_firstfreeinodenumber and the header of the block containing + the inode is stored in s->u.ext_sb.s_firstfreeinodeblock. + u.ext_sb.s_freeinodescount contains the count of free inodes. + +*/ + +#include +#include +#include +#include +#include +#include + +#define clear_block(addr) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di") + +void ext_free_block(struct super_block * sb, int block) +{ + struct buffer_head * bh; + struct ext_free_block * efb; + + if (!sb) { + printk("trying to free block on non-existent device\n"); + return; + } + lock_super (sb); + if (block < sb->u.ext_sb.s_firstdatazone || + block >= sb->u.ext_sb.s_nzones) { + printk("trying to free block not in datazone\n"); + return; + } + bh = get_hash_table(sb->s_dev, block, sb->s_blocksize); + if (bh) + bh->b_dirt=0; + brelse(bh); + if (sb->u.ext_sb.s_firstfreeblock) + efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data; + if (!sb->u.ext_sb.s_firstfreeblock || efb->count == 254) { +#ifdef EXTFS_DEBUG +printk("ext_free_block: block full, skipping to %d\n", block); +#endif + if (sb->u.ext_sb.s_firstfreeblock) + brelse (sb->u.ext_sb.s_firstfreeblock); + if (!(sb->u.ext_sb.s_firstfreeblock = bread (sb->s_dev, + block, sb->s_blocksize))) + panic ("ext_free_block: unable to read block to free\n"); + efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data; + efb->next = sb->u.ext_sb.s_firstfreeblocknumber; + efb->count = 0; + sb->u.ext_sb.s_firstfreeblocknumber = block; + } else { + efb->free[efb->count++] = block; + } + sb->u.ext_sb.s_freeblockscount ++; + sb->s_dirt = 1; + sb->u.ext_sb.s_firstfreeblock->b_dirt = 1; + unlock_super (sb); + return; +} + +int ext_new_block(struct super_block * sb) +{ + struct buffer_head * bh; + struct ext_free_block * efb; + int j; + + if (!sb) { + printk("trying to get new block from non-existent device\n"); + return 0; + } + if (!sb->u.ext_sb.s_firstfreeblock) + return 0; + lock_super (sb); + efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data; + if (efb->count) { + j = efb->free[--efb->count]; + sb->u.ext_sb.s_firstfreeblock->b_dirt = 1; + } else { +#ifdef EXTFS_DEBUG +printk("ext_new_block: block empty, skipping to %d\n", efb->next); +#endif + j = sb->u.ext_sb.s_firstfreeblocknumber; + sb->u.ext_sb.s_firstfreeblocknumber = efb->next; + brelse (sb->u.ext_sb.s_firstfreeblock); + if (!sb->u.ext_sb.s_firstfreeblocknumber) { + sb->u.ext_sb.s_firstfreeblock = NULL; + } else { + if (!(sb->u.ext_sb.s_firstfreeblock = bread (sb->s_dev, + sb->u.ext_sb.s_firstfreeblocknumber, + sb->s_blocksize))) + panic ("ext_new_block: unable to read next free block\n"); + } + } + if (j < sb->u.ext_sb.s_firstdatazone || j > sb->u.ext_sb.s_nzones) { + printk ("ext_new_block: blk = %d\n", j); + printk("allocating block not in data zone\n"); + return 0; + } + sb->u.ext_sb.s_freeblockscount --; + sb->s_dirt = 1; + + if (!(bh=getblk(sb->s_dev, j, sb->s_blocksize))) { + printk("new_block: cannot get block"); + return 0; + } + clear_block(bh->b_data); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); +#ifdef EXTFS_DEBUG +printk("ext_new_block: allocating block %d\n", j); +#endif + unlock_super (sb); + return j; +} + +unsigned long ext_count_free_blocks(struct super_block *sb) +{ +#ifdef EXTFS_DEBUG + struct buffer_head * bh; + struct ext_free_block * efb; + unsigned long count, block; + + lock_super (sb); + if (!sb->u.ext_sb.s_firstfreeblock) + count = 0; + else { + efb = (struct ext_free_block *) sb->u.ext_sb.s_firstfreeblock->b_data; + count = efb->count + 1; + block = efb->next; + while (block) { + if (!(bh = bread (sb->s_dev, block, sb->s_blocksize))) { + printk ("ext_count_free: error while reading free blocks list\n"); + block = 0; + } else { + efb = (struct ext_free_block *) bh->b_data; + count += efb->count + 1; + block = efb->next; + brelse (bh); + } + } + } +printk("ext_count_free_blocks: stored = %d, computed = %d\n", + sb->u.ext_sb.s_freeblockscount, count); + unlock_super (sb); + return count; +#else + return sb->u.ext_sb.s_freeblockscount; +#endif +} + +void ext_free_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct ext_free_inode * efi; + struct super_block * sb; + unsigned long block; + unsigned long ino; + dev_t dev; + + if (!inode) + return; + if (!inode->i_dev) { + printk("free_inode: inode has no device\n"); + return; + } + if (inode->i_count != 1) { + printk("free_inode: inode has count=%d\n",inode->i_count); + return; + } + if (inode->i_nlink) { + printk("free_inode: inode has nlink=%d\n",inode->i_nlink); + return; + } + if (!inode->i_sb) { + printk("free_inode: inode on non-existent device\n"); + return; + } + sb = inode->i_sb; + ino = inode->i_ino; + dev = inode->i_dev; + clear_inode(inode); + lock_super (sb); + if (ino < 1 || ino > sb->u.ext_sb.s_ninodes) { + printk("free_inode: inode 0 or non-existent inode\n"); + unlock_super (sb); + return; + } + if (sb->u.ext_sb.s_firstfreeinodeblock) + efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) + + (sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK; + if (!sb->u.ext_sb.s_firstfreeinodeblock || efi->count == 14) { +#ifdef EXTFS_DEBUG +printk("ext_free_inode: inode full, skipping to %d\n", ino); +#endif + if (sb->u.ext_sb.s_firstfreeinodeblock) + brelse (sb->u.ext_sb.s_firstfreeinodeblock); + block = 2 + (ino - 1) / EXT_INODES_PER_BLOCK; + if (!(bh = bread(dev, block, sb->s_blocksize))) + panic("ext_free_inode: unable to read inode block\n"); + efi = ((struct ext_free_inode *) bh->b_data) + + (ino - 1) % EXT_INODES_PER_BLOCK; + efi->next = sb->u.ext_sb.s_firstfreeinodenumber; + efi->count = 0; + sb->u.ext_sb.s_firstfreeinodenumber = ino; + sb->u.ext_sb.s_firstfreeinodeblock = bh; + } else { + efi->free[efi->count++] = ino; + } + sb->u.ext_sb.s_freeinodescount ++; + sb->s_dirt = 1; + sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1; + unlock_super (sb); +} + +struct inode * ext_new_inode(const struct inode * dir) +{ + struct super_block * sb; + struct inode * inode; + struct ext_free_inode * efi; + unsigned long block; + int j; + + if (!dir || !(inode=get_empty_inode())) + return NULL; + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + if (!sb->u.ext_sb.s_firstfreeinodeblock) + return 0; + lock_super (sb); + efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) + + (sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK; + if (efi->count) { + j = efi->free[--efi->count]; + sb->u.ext_sb.s_firstfreeinodeblock->b_dirt = 1; + } else { +#ifdef EXTFS_DEBUG +printk("ext_free_inode: inode empty, skipping to %d\n", efi->next); +#endif + j = sb->u.ext_sb.s_firstfreeinodenumber; + if (efi->next > sb->u.ext_sb.s_ninodes) { + printk ("efi->next = %d\n", efi->next); + panic ("ext_new_inode: bad inode number in free list\n"); + } + sb->u.ext_sb.s_firstfreeinodenumber = efi->next; + block = 2 + (((unsigned long) efi->next) - 1) / EXT_INODES_PER_BLOCK; + brelse (sb->u.ext_sb.s_firstfreeinodeblock); + if (!sb->u.ext_sb.s_firstfreeinodenumber) { + sb->u.ext_sb.s_firstfreeinodeblock = NULL; + } else { + if (!(sb->u.ext_sb.s_firstfreeinodeblock = + bread(sb->s_dev, block, sb->s_blocksize))) + panic ("ext_new_inode: unable to read next free inode block\n"); + } + } + sb->u.ext_sb.s_freeinodescount --; + sb->s_dirt = 1; + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->euid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid; + inode->i_dirt = 1; + inode->i_ino = j; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = NULL; + inode->i_blocks = inode->i_blksize = 0; + insert_inode_hash(inode); +#ifdef EXTFS_DEBUG +printk("ext_new_inode : allocating inode %d\n", inode->i_ino); +#endif + unlock_super (sb); + return inode; +} + +unsigned long ext_count_free_inodes(struct super_block *sb) +{ +#ifdef EXTFS_DEBUG + struct buffer_head * bh; + struct ext_free_inode * efi; + unsigned long count, block, ino; + + lock_super (sb); + if (!sb->u.ext_sb.s_firstfreeinodeblock) + count = 0; + else { + efi = ((struct ext_free_inode *) sb->u.ext_sb.s_firstfreeinodeblock->b_data) + + ((sb->u.ext_sb.s_firstfreeinodenumber-1)%EXT_INODES_PER_BLOCK); + count = efi->count + 1; + ino = efi->next; + while (ino) { + if (ino < 1 || ino > sb->u.ext_sb.s_ninodes) { + printk ("u.ext_sb.s_firstfreeinodenumber = %d, ino = %d\n", + (int) sb->u.ext_sb.s_firstfreeinodenumber,ino); + panic ("ext_count_fre_inodes: bad inode number in free list\n"); + } + block = 2 + ((ino - 1) / EXT_INODES_PER_BLOCK); + if (!(bh = bread (sb->s_dev, block, sb->s_blocksize))) { + printk ("ext_count_free_inodes: error while reading free inodes list\n"); + block = 0; + } else { + efi = ((struct ext_free_inode *) bh->b_data) + + ((ino - 1) % EXT_INODES_PER_BLOCK); + count += efi->count + 1; + ino = efi->next; + brelse (bh); + } + } + } +printk("ext_count_free_inodes: stored = %d, computed = %d\n", + sb->u.ext_sb.s_freeinodescount, count); + unlock_super (sb); + return count; +#else + return sb->u.ext_sb.s_freeinodescount; +#endif +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/fsync.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/fsync.c new file mode 100644 index 000000000..bb20383cc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/fsync.c @@ -0,0 +1,185 @@ + +/* + * linux/fs/ext/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * from + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * from + * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds + * + * extfs fsync primitive + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +#define blocksize BLOCK_SIZE +#define addr_per_block 256 + +static int sync_block (struct inode * inode, unsigned long * block, int wait) +{ + struct buffer_head * bh; + int tmp; + + if (!*block) + return 0; + tmp = *block; + bh = get_hash_table(inode->i_dev, *block, blocksize); + if (!bh) + return 0; + if (*block != tmp) { + brelse (bh); + return 1; + } + if (wait && bh->b_req && !bh->b_uptodate) { + brelse(bh); + return -1; + } + if (wait || !bh->b_uptodate || !bh->b_dirt) + { + brelse(bh); + return 0; + } + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + return 0; +} + +static int sync_iblock (struct inode * inode, unsigned long * iblock, + struct buffer_head **bh, int wait) +{ + int rc, tmp; + + *bh = NULL; + tmp = *iblock; + if (!tmp) + return 0; + rc = sync_block (inode, iblock, wait); + if (rc) + return rc; + *bh = bread(inode->i_dev, tmp, blocksize); + if (tmp != *iblock) { + brelse(*bh); + *bh = NULL; + return 1; + } + if (!*bh) + return -1; + return 0; +} + + +static int sync_direct(struct inode *inode, int wait) +{ + int i; + int rc, err = 0; + + for (i = 0; i < 9; i++) { + rc = sync_block (inode, inode->u.ext_i.i_data + i, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + return err; +} + +static int sync_indirect(struct inode *inode, unsigned long *iblock, int wait) +{ + int i; + struct buffer_head * ind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, iblock, &ind_bh, wait); + if (rc || !ind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_block (inode, + ((unsigned long *) ind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(ind_bh); + return err; +} + +static int sync_dindirect(struct inode *inode, unsigned long *diblock, + int wait) +{ + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect (inode, + ((unsigned long *) dind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(dind_bh); + return err; +} + +static int sync_tindirect(struct inode *inode, unsigned long *tiblock, + int wait) +{ + int i; + struct buffer_head * tind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, tiblock, &tind_bh, wait); + if (rc || !tind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_dindirect (inode, + ((unsigned long *) tind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(tind_bh); + return err; +} + +int ext_sync_file(struct inode * inode, struct file *file) +{ + int wait, err = 0; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + for (wait=0; wait<=1; wait++) + { + err |= sync_direct(inode, wait); + err |= sync_indirect(inode, inode->u.ext_i.i_data+9, wait); + err |= sync_dindirect(inode, inode->u.ext_i.i_data+10, wait); + err |= sync_tindirect(inode, inode->u.ext_i.i_data+11, wait); + } + err |= ext_sync_inode (inode); + return (err < 0) ? -EIO : 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/inode.c new file mode 100644 index 000000000..910ab5891 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/inode.c @@ -0,0 +1,444 @@ +/* + * linux/fs/ext/inode.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void ext_put_inode(struct inode *inode) +{ + if (inode->i_nlink) + return; + inode->i_size = 0; + ext_truncate(inode); + ext_free_inode(inode); +} + +void ext_put_super(struct super_block *sb) +{ + + lock_super(sb); + sb->s_dev = 0; + if (sb->u.ext_sb.s_firstfreeinodeblock) + brelse (sb->u.ext_sb.s_firstfreeinodeblock); + if (sb->u.ext_sb.s_firstfreeblock) + brelse (sb->u.ext_sb.s_firstfreeblock); + unlock_super(sb); + return; +} + +static struct super_operations ext_sops = { + ext_read_inode, + NULL, + ext_write_inode, + ext_put_inode, + ext_put_super, + ext_write_super, + ext_statfs, + NULL +}; + +struct super_block *ext_read_super(struct super_block *s,void *data, + int silent) +{ + struct buffer_head *bh; + struct ext_super_block *es; + int dev = s->s_dev,block; + + lock_super(s); + set_blocksize(dev, BLOCK_SIZE); + if (!(bh = bread(dev, 1, BLOCK_SIZE))) { + s->s_dev=0; + unlock_super(s); + printk("EXT-fs: unable to read superblock\n"); + return NULL; + } + es = (struct ext_super_block *) bh->b_data; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->u.ext_sb.s_ninodes = es->s_ninodes; + s->u.ext_sb.s_nzones = es->s_nzones; + s->u.ext_sb.s_firstdatazone = es->s_firstdatazone; + s->u.ext_sb.s_log_zone_size = es->s_log_zone_size; + s->u.ext_sb.s_max_size = es->s_max_size; + s->s_magic = es->s_magic; + s->u.ext_sb.s_firstfreeblocknumber = es->s_firstfreeblock; + s->u.ext_sb.s_freeblockscount = es->s_freeblockscount; + s->u.ext_sb.s_firstfreeinodenumber = es->s_firstfreeinode; + s->u.ext_sb.s_freeinodescount = es->s_freeinodescount; + brelse(bh); + if (s->s_magic != EXT_SUPER_MAGIC) { + s->s_dev = 0; + unlock_super(s); + if (!silent) + printk("VFS: Can't find an extfs filesystem on dev 0x%04x.\n", + dev); + return NULL; + } + if (!s->u.ext_sb.s_firstfreeblocknumber) + s->u.ext_sb.s_firstfreeblock = NULL; + else + if (!(s->u.ext_sb.s_firstfreeblock = bread(dev, + s->u.ext_sb.s_firstfreeblocknumber, BLOCK_SIZE))) { + printk("ext_read_super: unable to read first free block\n"); + s->s_dev = 0; + unlock_super(s); + return NULL; + } + if (!s->u.ext_sb.s_firstfreeinodenumber) + s->u.ext_sb.s_firstfreeinodeblock = NULL; + else { + block = 2 + (s->u.ext_sb.s_firstfreeinodenumber - 1) / EXT_INODES_PER_BLOCK; + if (!(s->u.ext_sb.s_firstfreeinodeblock = bread(dev, block, BLOCK_SIZE))) { + printk("ext_read_super: unable to read first free inode block\n"); + brelse(s->u.ext_sb.s_firstfreeblock); + s->s_dev = 0; + unlock_super (s); + return NULL; + } + } + unlock_super(s); + /* set up enough so that it can read an inode */ + s->s_dev = dev; + s->s_op = &ext_sops; + if (!(s->s_mounted = iget(s,EXT_ROOT_INO))) { + s->s_dev=0; + printk("EXT-fs: get root inode failed\n"); + return NULL; + } + return s; +} + +void ext_write_super (struct super_block *sb) +{ + struct buffer_head * bh; + struct ext_super_block * es; + + if (!(bh = bread(sb->s_dev, 1, BLOCK_SIZE))) { + printk ("ext_write_super: bread failed\n"); + return; + } + es = (struct ext_super_block *) bh->b_data; + es->s_firstfreeblock = sb->u.ext_sb.s_firstfreeblocknumber; + es->s_freeblockscount = sb->u.ext_sb.s_freeblockscount; + es->s_firstfreeinode = sb->u.ext_sb.s_firstfreeinodenumber; + es->s_freeinodescount = sb->u.ext_sb.s_freeinodescount; + bh->b_dirt = 1; + brelse (bh); + sb->s_dirt = 0; +} + +void ext_statfs (struct super_block *sb, struct statfs *buf) +{ + long tmp; + + put_fs_long(EXT_SUPER_MAGIC, &buf->f_type); + put_fs_long(1024, &buf->f_bsize); + put_fs_long(sb->u.ext_sb.s_nzones << sb->u.ext_sb.s_log_zone_size, + &buf->f_blocks); + tmp = ext_count_free_blocks(sb); + put_fs_long(tmp, &buf->f_bfree); + put_fs_long(tmp, &buf->f_bavail); + put_fs_long(sb->u.ext_sb.s_ninodes, &buf->f_files); + put_fs_long(ext_count_free_inodes(sb), &buf->f_ffree); + put_fs_long(EXT_NAME_LEN, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ +} + +#define inode_bmap(inode,nr) ((inode)->u.ext_i.i_data[(nr)]) + +static int block_bmap(struct buffer_head * bh, int nr) +{ + int tmp; + + if (!bh) + return 0; + tmp = ((unsigned long *) bh->b_data)[nr]; + brelse(bh); + return tmp; +} + +int ext_bmap(struct inode * inode,int block) +{ + int i; + + if (block<0) { + printk("ext_bmap: block<0"); + return 0; + } + if (block >= 9+256+256*256+256*256*256) { + printk("ext_bmap: block>big"); + return 0; + } + if (block<9) + return inode_bmap(inode,block); + block -= 9; + if (block<256) { + i = inode_bmap(inode,9); + if (!i) + return 0; + return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block); + } + block -= 256; + if (block<256*256) { + i = inode_bmap(inode,10); + if (!i) + return 0; + i = block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>8); + if (!i) + return 0; + return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255); + } + block -= 256*256; + i = inode_bmap(inode,11); + if (!i) + return 0; + i = block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>16); + if (!i) + return 0; + i = block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),(block>>8) & 255); + if (!i) + return 0; + return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 255); +} + +static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create) +{ + int tmp; + unsigned long * p; + struct buffer_head * result; + + p = inode->u.ext_i.i_data + nr; +repeat: + tmp = *p; + if (tmp) { + result = getblk(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp == *p) + return result; + brelse(result); + goto repeat; + } + if (!create) + return NULL; + tmp = ext_new_block(inode->i_sb); + if (!tmp) + return NULL; + result = getblk(inode->i_dev, tmp, BLOCK_SIZE); + if (*p) { + ext_free_block(inode->i_sb,tmp); + brelse(result); + goto repeat; + } + *p = tmp; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return result; +} + +static struct buffer_head * block_getblk(struct inode * inode, + struct buffer_head * bh, int nr, int create) +{ + int tmp; + unsigned long * p; + struct buffer_head * result; + + if (!bh) + return NULL; + if (!bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + return NULL; + } + } + p = nr + (unsigned long *) bh->b_data; +repeat: + tmp = *p; + if (tmp) { + result = getblk(bh->b_dev, tmp, BLOCK_SIZE); + if (tmp == *p) { + brelse(bh); + return result; + } + brelse(result); + goto repeat; + } + if (!create) { + brelse(bh); + return NULL; + } + tmp = ext_new_block(inode->i_sb); + if (!tmp) { + brelse(bh); + return NULL; + } + result = getblk(bh->b_dev, tmp, BLOCK_SIZE); + if (*p) { + ext_free_block(inode->i_sb,tmp); + brelse(result); + goto repeat; + } + *p = tmp; + bh->b_dirt = 1; + brelse(bh); + return result; +} + +struct buffer_head * ext_getblk(struct inode * inode, int block, int create) +{ + struct buffer_head * bh; + + if (block<0) { + printk("ext_getblk: block<0\n"); + return NULL; + } + if (block >= 9+256+256*256+256*256*256) { + printk("ext_getblk: block>big\n"); + return NULL; + } + if (block<9) + return inode_getblk(inode,block,create); + block -= 9; + if (block<256) { + bh = inode_getblk(inode,9,create); + return block_getblk(inode,bh,block,create); + } + block -= 256; + if (block<256*256) { + bh = inode_getblk(inode,10,create); + bh = block_getblk(inode,bh,block>>8,create); + return block_getblk(inode,bh,block & 255,create); + } + block -= 256*256; + bh = inode_getblk(inode,11,create); + bh = block_getblk(inode,bh,block>>16,create); + bh = block_getblk(inode,bh,(block>>8) & 255,create); + return block_getblk(inode,bh,block & 255,create); +} + +struct buffer_head * ext_bread(struct inode * inode, int block, int create) +{ + struct buffer_head * bh; + + bh = ext_getblk(inode,block,create); + if (!bh || bh->b_uptodate) + return bh; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +void ext_read_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct ext_inode * raw_inode; + int block; + + block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) + panic("unable to read i-node block"); + raw_inode = ((struct ext_inode *) bh->b_data) + + (inode->i_ino-1)%EXT_INODES_PER_BLOCK; + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_nlinks; + inode->i_size = raw_inode->i_size; + inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time; + inode->i_blocks = inode->i_blksize = 0; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = raw_inode->i_zone[0]; + else for (block = 0; block < 12; block++) + inode->u.ext_i.i_data[block] = raw_inode->i_zone[block]; + brelse(bh); + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &ext_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &ext_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ext_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); +} + +static struct buffer_head * ext_update_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct ext_inode * raw_inode; + int block; + + block = 2 + (inode->i_ino-1)/EXT_INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) + panic("unable to read i-node block"); + raw_inode = ((struct ext_inode *)bh->b_data) + + (inode->i_ino-1)%EXT_INODES_PER_BLOCK; + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_nlinks = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_time = inode->i_mtime; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_zone[0] = inode->i_rdev; + else for (block = 0; block < 12; block++) + raw_inode->i_zone[block] = inode->u.ext_i.i_data[block]; + bh->b_dirt=1; + inode->i_dirt=0; + return bh; +} + +void ext_write_inode(struct inode * inode) +{ + struct buffer_head *bh; + bh = ext_update_inode (inode); + brelse(bh); +} + +int ext_sync_inode (struct inode *inode) +{ + int err = 0; + struct buffer_head *bh; + + bh = ext_update_inode(inode); + if (bh && bh->b_dirt) + { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + if (bh->b_req && !bh->b_uptodate) + { + printk ("IO error syncing ext inode [%04x:%08x]\n", + inode->i_dev, inode->i_ino); + err = -1; + } + } + else if (!bh) + err = -1; + brelse (bh); + return err; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/namei.c new file mode 100644 index 000000000..a8bc1cb31 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/namei.c @@ -0,0 +1,900 @@ +/* + * linux/fs/ext/namei.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * comment out this line if you want names > EXT_NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +/* + * EXT_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a power of 2 and must be greater or equal than 8 + * because a directory entry needs 8 bytes for its fixed part + * (4 bytes for the inode, 2 bytes for the entry length and 2 bytes + * for the name length) + */ +#define EXT_DIR_PAD 8 + +/* + * + * EXT_DIR_MIN_SIZE is the minimal size of a directory entry + * + * During allocations, a directory entry is split into 2 ones + * *ONLY* if the size of the unused part is greater than or + * equal to EXT_DIR_MIN_SIZE + */ +#define EXT_DIR_MIN_SIZE 12 + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use ext_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, ext_match returns 1 for success, 0 for failure. + */ +static int ext_match(int len,const char * name,struct ext_dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->inode || len > EXT_NAME_LEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + if (len < EXT_NAME_LEN && len != de->name_len) + return 0; + __asm__("cld\n\t" + "repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) + :"cx","di","si"); + return same; +} + +/* + * ext_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + * + * addition for the ext file system : this function returns the previous + * and next directory entries in the parameters prev_dir and next_dir + */ +static struct buffer_head * ext_find_entry(struct inode * dir, + const char * name, int namelen, struct ext_dir_entry ** res_dir, + struct ext_dir_entry ** prev_dir, struct ext_dir_entry ** next_dir) +{ + long offset; + struct buffer_head * bh; + struct ext_dir_entry * de; + + *res_dir = NULL; + if (!dir) + return NULL; +#ifdef NO_TRUNCATE + if (namelen > EXT_NAME_LEN) + return NULL; +#else + if (namelen > EXT_NAME_LEN) + namelen = EXT_NAME_LEN; +#endif + bh = ext_bread(dir,0,0); + if (!bh) + return NULL; + if (prev_dir) + *prev_dir = NULL; + if (next_dir) + *next_dir = NULL; + offset = 0; + de = (struct ext_dir_entry *) bh->b_data; + while (offset < dir->i_size) { + if ((char *)de >= BLOCK_SIZE+bh->b_data) { + brelse(bh); + bh = NULL; + bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0); + if (!bh) + continue; + de = (struct ext_dir_entry *) bh->b_data; + if (prev_dir) + *prev_dir = NULL; + } + if (de->rec_len < 8 || de->rec_len % 8 != 0 || + de->rec_len < de->name_len + 8 || + (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) { + printk ("ext_find_entry: bad dir entry\n"); + printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n", + dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len); + de = (struct ext_dir_entry *) (bh->b_data+BLOCK_SIZE); + offset = ((offset / BLOCK_SIZE) + 1) * BLOCK_SIZE; + continue; +/* brelse (bh); + return NULL; */ + } + if (ext_match(namelen,name,de)) { + *res_dir = de; + if (next_dir) + if (offset + de->rec_len < dir->i_size && + ((char *)de) + de->rec_len < BLOCK_SIZE+bh->b_data) + *next_dir = (struct ext_dir_entry *) + ((char *) de + de->rec_len); + else + *next_dir = NULL; + return bh; + } + offset += de->rec_len; + if (prev_dir) + *prev_dir = de; + de = (struct ext_dir_entry *) ((char *) de + de->rec_len); + } + brelse(bh); + return NULL; +} + +int ext_lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + int ino; + struct ext_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!(bh = ext_find_entry(dir,name,len,&de,NULL,NULL))) { + iput(dir); + return -ENOENT; + } + ino = de->inode; + brelse(bh); + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -EACCES; + } + iput(dir); + return 0; +} + +/* + * ext_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as ext_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * ext_add_entry(struct inode * dir, + const char * name, int namelen, struct ext_dir_entry ** res_dir) +{ + int i; + long offset; + unsigned short rec_len; + struct buffer_head * bh; + struct ext_dir_entry * de, * de1; + + *res_dir = NULL; + if (!dir) + return NULL; +#ifdef NO_TRUNCATE + if (namelen > EXT_NAME_LEN) + return NULL; +#else + if (namelen > EXT_NAME_LEN) + namelen = EXT_NAME_LEN; +#endif + if (!namelen) + return NULL; + bh = ext_bread(dir,0,0); + if (!bh) + return NULL; + rec_len = ((8 + namelen + EXT_DIR_PAD - 1) / EXT_DIR_PAD) * EXT_DIR_PAD; + offset = 0; + de = (struct ext_dir_entry *) bh->b_data; + while (1) { + if ((char *)de >= BLOCK_SIZE+bh->b_data && offset < dir->i_size) { +#ifdef EXTFS_DEBUG +printk ("ext_add_entry: skipping to next block\n"); +#endif + brelse(bh); + bh = NULL; + bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,0); + if (!bh) + return NULL; + de = (struct ext_dir_entry *) bh->b_data; + } + if (offset >= dir->i_size) { + /* Check that the directory entry fits in the block */ + if (offset % BLOCK_SIZE == 0 || + (BLOCK_SIZE - (offset % BLOCK_SIZE)) < rec_len) { + if ((offset % BLOCK_SIZE) != 0) { + /* If the entry does not fit in the + block, the remainder of the block + becomes an unused entry */ + de->inode = 0; + de->rec_len = BLOCK_SIZE + - (offset & (BLOCK_SIZE - 1)); + de->name_len = 0; + offset += de->rec_len; + dir->i_size += de->rec_len; + dir->i_dirt = 1; +#if 0 + dir->i_ctime = CURRENT_TIME; +#endif + bh->b_dirt = 1; + } + brelse (bh); + bh = NULL; +#ifdef EXTFS_DEBUG +printk ("ext_add_entry : creating next block\n"); +#endif + bh = ext_bread(dir,offset>>BLOCK_SIZE_BITS,1); + if (!bh) + return NULL; /* Other thing to do ??? */ + de = (struct ext_dir_entry *) bh->b_data; + } + /* Allocate the entry */ + de->inode=0; + de->rec_len = rec_len; + dir->i_size += de->rec_len; + dir->i_dirt = 1; +#if 0 + dir->i_ctime = CURRENT_TIME; +#endif + } + if (de->rec_len < 8 || de->rec_len % 4 != 0 || + de->rec_len < de->name_len + 8 || + (((char *) de) + de->rec_len-1 >= BLOCK_SIZE+bh->b_data)) { + printk ("ext_addr_entry: bad dir entry\n"); + printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n", + dir->i_dev, dir->i_ino, offset, de->rec_len, de->name_len); + brelse (bh); + return NULL; + } + if (!de->inode && de->rec_len >= rec_len) { + if (de->rec_len > rec_len + && de->rec_len - rec_len >= EXT_DIR_MIN_SIZE) { + /* The found entry is too big : it is split + into 2 ones : + - the 1st one will be used to hold the name, + - the 2nd one is unused */ + de1 = (struct ext_dir_entry *) ((char *) de + rec_len); + de1->inode = 0; + de1->rec_len = de->rec_len - rec_len; + de1->name_len = 0; + de->rec_len = rec_len; + } + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + de->name_len = namelen; + for (i=0; i < namelen ; i++) + de->name[i] = name[i]; + bh->b_dirt = 1; + *res_dir = de; + return bh; + } + offset += de->rec_len; + de = (struct ext_dir_entry *) ((char *) de + de->rec_len); + } + brelse(bh); + return NULL; +} + +int ext_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result) +{ + struct inode * inode; + struct buffer_head * bh; + struct ext_dir_entry * de; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = ext_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &ext_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = ext_add_entry(dir,name,len,&de); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *result = inode; + return 0; +} + +int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +{ + struct inode * inode; + struct buffer_head * bh; + struct ext_dir_entry * de; + + if (!dir) + return -ENOENT; + bh = ext_find_entry(dir,name,len,&de,NULL,NULL); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = ext_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &ext_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ext_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ext_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; +#if 0 + inode->i_mtime = inode->i_atime = CURRENT_TIME; +#endif + inode->i_dirt = 1; + bh = ext_add_entry(dir,name,len,&de); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int ext_mkdir(struct inode * dir, const char * name, int len, int mode) +{ + struct inode * inode; + struct buffer_head * bh, *dir_block; + struct ext_dir_entry * de; + + bh = ext_find_entry(dir,name,len,&de,NULL,NULL); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = ext_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &ext_dir_inode_operations; + inode->i_size = 2 * 16; /* Each entry is coded on 16 bytes for "." and ".." + - 4 bytes for the inode number, + - 2 bytes for the record length + - 2 bytes for the name length + - 8 bytes for the name */ +#if 0 + inode->i_mtime = inode->i_atime = CURRENT_TIME; +#endif + dir_block = ext_bread(inode,0,1); + if (!dir_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + de = (struct ext_dir_entry *) dir_block->b_data; + de->inode=inode->i_ino; + de->rec_len=16; + de->name_len=1; + strcpy(de->name,"."); + de = (struct ext_dir_entry *) ((char *) de + de->rec_len); + de->inode = dir->i_ino; + de->rec_len=16; + de->name_len=2; + strcpy(de->name,".."); + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + inode->i_dirt = 1; + bh = ext_add_entry(dir,name,len,&de); + if (!bh) { + iput(dir); + inode->i_nlink=0; + iput(inode); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + dir->i_nlink++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct inode * inode) +{ + unsigned long offset; + struct buffer_head * bh; + struct ext_dir_entry * de, * de1; + + if (inode->i_size < 2 * 12 || !(bh = ext_bread(inode,0,0))) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 1; + } + de = (struct ext_dir_entry *) bh->b_data; + de1 = (struct ext_dir_entry *) ((char *) de + de->rec_len); + if (de->inode != inode->i_ino || !de1->inode || + strcmp(".",de->name) || strcmp("..",de1->name)) { + printk("warning - bad directory on dev %04x\n",inode->i_dev); + return 1; + } + offset = de->rec_len + de1->rec_len; + de = (struct ext_dir_entry *) ((char *) de1 + de1->rec_len); + while (offset < inode->i_size ) { + if ((void *) de >= (void *) (bh->b_data+BLOCK_SIZE)) { + brelse(bh); + bh = ext_bread(inode, offset >> BLOCK_SIZE_BITS,1); + if (!bh) { + offset += BLOCK_SIZE; + continue; + } + de = (struct ext_dir_entry *) bh->b_data; + } + if (de->rec_len < 8 || de->rec_len %4 != 0 || + de->rec_len < de->name_len + 8) { + printk ("empty_dir: bad dir entry\n"); + printk ("dev=%d, dir=%d, offset=%d, rec_len=%d, name_len=%d\n", + inode->i_dev, inode->i_ino, offset, de->rec_len, de->name_len); + brelse (bh); + return 1; + } + if (de->inode) { + brelse(bh); + return 0; + } + offset += de->rec_len; + de = (struct ext_dir_entry *) ((char *) de + de->rec_len); + } + brelse(bh); + return 1; +} + +static inline void ext_merge_entries (struct ext_dir_entry * de, + struct ext_dir_entry * pde, struct ext_dir_entry * nde) +{ + if (nde && !nde->inode) + de->rec_len += nde->rec_len; + if (pde && !pde->inode) + pde->rec_len += de->rec_len; +} + +int ext_rmdir(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext_dir_entry * de, * pde, * nde; + + inode = NULL; + bh = ext_find_entry(dir,name,len,&de,&pde,&nde); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget(dir->i_sb, de->inode))) + goto end_rmdir; + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir(inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto end_rmdir; + } + if (inode->i_nlink != 2) + printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); + de->inode = 0; + de->name_len = 0; + ext_merge_entries (de, pde, nde); + bh->b_dirt = 1; + inode->i_nlink=0; + inode->i_dirt=1; + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + retval = 0; +end_rmdir: + iput(dir); + iput(inode); + brelse(bh); + return retval; +} + +int ext_unlink(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext_dir_entry * de, * pde, * nde; + + retval = -ENOENT; + inode = NULL; + bh = ext_find_entry(dir,name,len,&de,&pde,&nde); + if (!bh) + goto end_unlink; + if (!(inode = iget(dir->i_sb, de->inode))) + goto end_unlink; + retval = -EPERM; + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (!inode->i_nlink) { + printk("Deleting nonexistent file (%04x:%d), %d\n", + inode->i_dev,inode->i_ino,inode->i_nlink); + inode->i_nlink=1; + } + de->inode = 0; + de->name_len = 0; + ext_merge_entries (de, pde, nde); + bh->b_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + inode->i_ctime = CURRENT_TIME; + dir->i_ctime = dir->i_mtime = inode->i_ctime; + dir->i_dirt = 1; + retval = 0; +end_unlink: + brelse(bh); + iput(inode); + iput(dir); + return retval; +} + +int ext_symlink(struct inode * dir, const char * name, int len, const char * symname) +{ + struct ext_dir_entry * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + int i; + char c; + + if (!(inode = ext_new_inode(dir))) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | 0777; + inode->i_op = &ext_symlink_inode_operations; + name_block = ext_bread(inode,0,1); + if (!name_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + i = 0; + while (i < 1023 && (c = *(symname++))) + name_block->b_data[i++] = c; + name_block->b_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = ext_find_entry(dir,name,len,&de,NULL,NULL); + if (bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + brelse(bh); + iput(dir); + return -EEXIST; + } + bh = ext_add_entry(dir,name,len,&de); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +{ + struct ext_dir_entry * de; + struct buffer_head * bh; + + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (oldinode->i_nlink > 32000) { + iput(oldinode); + iput(dir); + return -EMLINK; + } + bh = ext_find_entry(dir,name,len,&de,NULL,NULL); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + bh = ext_add_entry(dir,name,len,&de); + if (!bh) { + iput(dir); + iput(oldinode); + return -ENOSPC; + } + de->inode = oldinode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} + +static int subdir(struct inode * new_inode, struct inode * old_inode) +{ + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (ext_lookup(new_inode,"..",2,&new_inode)) + break; + if (new_inode->i_ino == ino) + break; + } + iput(new_inode); + return result; +} + +#define PARENT_INO(buffer) \ +((struct ext_dir_entry *) ((char *) buffer + \ +((struct ext_dir_entry *) buffer)->rec_len))->inode + +#define PARENT_NAME(buffer) \ +((struct ext_dir_entry *) ((char *) buffer + \ +((struct ext_dir_entry *) buffer)->rec_len))->name + +/* + * rename uses retrying to avoid race-conditions: at least they should be minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_ext_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ext_dir_entry * old_de, * new_de, * pde, * nde; + int retval; + + goto start_up; +try_again: + brelse(old_bh); + brelse(new_bh); + brelse(dir_bh); + iput(old_inode); + iput(new_inode); + current->counter = 0; + schedule(); +start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + old_bh = ext_find_entry(old_dir,old_name,old_len,&old_de,&pde,&nde); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ + if (!old_inode) + goto end_rename; + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = ext_find_entry(new_dir,new_name,new_len,&new_de,NULL,NULL); + if (new_bh) { + new_inode = __iget(new_dir->i_sb, new_de->inode,0); /* don't cross mnt-points */ + if (!new_inode) { + brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EEXIST; + goto end_rename; + } + retval = -EPERM; + if (new_inode && (new_dir->i_mode & S_ISVTX) && + current->euid != new_inode->i_uid && + current->euid != new_dir->i_uid && !suser()) + goto end_rename; + if (S_ISDIR(old_inode->i_mode)) { + retval = -EEXIST; + if (new_bh) + goto end_rename; + retval = -EACCES; + if (!permission(old_inode, MAY_WRITE)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -EIO; + dir_bh = ext_bread(old_inode,0,0); + if (!dir_bh) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + } + if (!new_bh) + new_bh = ext_add_entry(new_dir,new_name,new_len,&new_de); + retval = -ENOSPC; + if (!new_bh) + goto end_rename; +/* sanity checking before doing the rename - avoid races */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; +/* ok, that's it */ + old_de->inode = 0; + old_de->name_len = 0; + new_de->inode = old_inode->i_ino; + ext_merge_entries (old_de, pde, nde); + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } + old_bh->b_dirt = 1; + new_bh->b_dirt = 1; + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + new_dir->i_nlink++; + old_dir->i_dirt = 1; + new_dir->i_dirt = 1; + } + retval = 0; +end_rename: + brelse(dir_bh); + brelse(old_bh); + brelse(new_bh); + iput(old_inode); + iput(new_inode); + iput(old_dir); + iput(new_dir); + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + */ +int ext_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + + while (lock) + sleep_on(&wait); + lock = 1; + result = do_ext_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len); + lock = 0; + wake_up(&wait); + return result; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/symlink.c new file mode 100644 index 000000000..94d148e19 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/symlink.c @@ -0,0 +1,108 @@ +/* + * linux/fs/ext/symlink.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext symlink handling code + */ + +#include + +#include +#include +#include +#include +#include + +static int ext_readlink(struct inode *, char *, int); +static int ext_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations ext_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + ext_readlink, /* readlink */ + ext_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int ext_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + struct buffer_head * bh; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput(dir); + iput(inode); + return -ELOOP; + } + if (!(bh = ext_bread(inode, 0, 0))) { + iput(inode); + iput(dir); + return -EIO; + } + iput(inode); + current->link_count++; + error = open_namei(bh->b_data,flag,mode,res_inode,dir); + current->link_count--; + brelse(bh); + return error; +} + +static int ext_readlink(struct inode * inode, char * buffer, int buflen) +{ + struct buffer_head * bh; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + if (buflen > 1023) + buflen = 1023; + bh = ext_bread(inode, 0, 0); + iput(inode); + if (!bh) + return 0; + i = 0; + while (ib_data[i])) { + i++; + put_fs_byte(c,buffer++); + } + brelse(bh); + return i; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/truncate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/truncate.c new file mode 100644 index 000000000..d14dc6cb3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext/truncate.c @@ -0,0 +1,252 @@ +/* + * linux/fs/ext/truncate.c + * + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * from + * + * linux/fs/minix/truncate.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include + +/* + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + +static int trunc_direct(struct inode * inode) +{ + int i, tmp; + unsigned long * p; + struct buffer_head * bh; + int retry = 0; +#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10) + +repeat: + for (i = DIRECT_BLOCK ; i < 9 ; i++) { + p = inode->u.ext_i.i_data+i; + if (!(tmp = *p)) + continue; + bh = getblk(inode->i_dev,tmp,BLOCK_SIZE); + if (i < DIRECT_BLOCK) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *p) { + retry = 1; + brelse(bh); + continue; + } + *p = 0; + inode->i_dirt = 1; + brelse(bh); + ext_free_block(inode->i_sb,tmp); + } + return retry; +} + +static int trunc_indirect(struct inode * inode, int offset, unsigned long * p) +{ + int i, tmp; + struct buffer_head * bh; + struct buffer_head * ind_bh; + unsigned long * ind; + int retry = 0; +#define INDIRECT_BLOCK (DIRECT_BLOCK-offset) + + tmp = *p; + if (!tmp) + return 0; + ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp != *p) { + brelse(ind_bh); + return 1; + } + if (!ind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = INDIRECT_BLOCK ; i < 256 ; i++) { + if (i < 0) + i = 0; + if (i < INDIRECT_BLOCK) + goto repeat; + ind = i+(unsigned long *) ind_bh->b_data; + tmp = *ind; + if (!tmp) + continue; + bh = getblk(inode->i_dev,tmp,BLOCK_SIZE); + if (i < INDIRECT_BLOCK) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *ind) { + retry = 1; + brelse(bh); + continue; + } + *ind = 0; + ind_bh->b_dirt = 1; + brelse(bh); + ext_free_block(inode->i_sb,tmp); + } + ind = (unsigned long *) ind_bh->b_data; + for (i = 0; i < 256; i++) + if (*(ind++)) + break; + if (i >= 256) + if (ind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_dirt = 1; + ext_free_block(inode->i_sb,tmp); + } + brelse(ind_bh); + return retry; +} + +static int trunc_dindirect(struct inode * inode, int offset, unsigned long * p) +{ + int i,tmp; + struct buffer_head * dind_bh; + unsigned long * dind; + int retry = 0; +#define DINDIRECT_BLOCK ((DIRECT_BLOCK-offset)>>8) + + tmp = *p; + if (!tmp) + return 0; + dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp != *p) { + brelse(dind_bh); + return 1; + } + if (!dind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = DINDIRECT_BLOCK ; i < 256 ; i ++) { + if (i < 0) + i = 0; + if (i < DINDIRECT_BLOCK) + goto repeat; + dind = i+(unsigned long *) dind_bh->b_data; + tmp = *dind; + if (!tmp) + continue; + retry |= trunc_indirect(inode,offset+(i<<8),dind); + dind_bh->b_dirt = 1; + } + dind = (unsigned long *) dind_bh->b_data; + for (i = 0; i < 256; i++) + if (*(dind++)) + break; + if (i >= 256) + if (dind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_dirt = 1; + ext_free_block(inode->i_sb,tmp); + } + brelse(dind_bh); + return retry; +} + +static int trunc_tindirect(struct inode * inode) +{ + int i,tmp; + struct buffer_head * tind_bh; + unsigned long * tind, * p; + int retry = 0; +#define TINDIRECT_BLOCK ((DIRECT_BLOCK-(256*256+256+9))>>16) + + p = inode->u.ext_i.i_data+11; + if (!(tmp = *p)) + return 0; + tind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp != *p) { + brelse(tind_bh); + return 1; + } + if (!tind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = TINDIRECT_BLOCK ; i < 256 ; i ++) { + if (i < 0) + i = 0; + if (i < TINDIRECT_BLOCK) + goto repeat; + tind = i+(unsigned long *) tind_bh->b_data; + retry |= trunc_dindirect(inode,9+256+256*256+(i<<16),tind); + tind_bh->b_dirt = 1; + } + tind = (unsigned long *) tind_bh->b_data; + for (i = 0; i < 256; i++) + if (*(tind++)) + break; + if (i >= 256) + if (tind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_dirt = 1; + ext_free_block(inode->i_sb,tmp); + } + brelse(tind_bh); + return retry; +} + +void ext_truncate(struct inode * inode) +{ + int retry; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + while (1) { + retry = trunc_direct(inode); + retry |= trunc_indirect(inode,9,inode->u.ext_i.i_data+9); + retry |= trunc_dindirect(inode,9+256,inode->u.ext_i.i_data+10); + retry |= trunc_tindirect(inode); + if (!retry) + break; + current->counter = 0; + schedule(); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; +} + +/* + * Called when a inode is released. Note that this is different + * from ext_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +void ext_release(struct inode * inode, struct file * filp) +{ + printk("ext_release not implemented\n"); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/CHANGES b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/CHANGES new file mode 100644 index 000000000..08b7b6437 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/CHANGES @@ -0,0 +1,91 @@ +Changes from version 0.4a to version 0.4b +========================================= + - Copyrights changed to include the name of my laboratory. + - Clean up of balloc.c and ialloc.c. + - More consistency checks. + - Block preallocation added by Stephen Tweedie. + - Direct reads of directories disallowed. + - Readahead implemented in readdir by Stephen Tweedie. + - Bugs in block and inodes allocation fixed. + - Readahead implemented in ext2_find_entry by Chip Salzenberg. + - New mount options: + `check=none|normal|strict' + `debug' + `errors=continue|remount-ro|panic' + `grpid', `bsdgroups' + `nocheck' + `nogrpid', `sysvgroups' + - truncate() now tries to deallocate contigous blocks in a single call + to ext2_free_blocks(). + - lots of cosmetic changes. + +Changes from version 0.4 to version 0.4a +======================================== + - the `sync' option support is now complete. Version 0.4 was not + supporting it when truncating a file. I have tested the synchronous + writes and they work but they make the system very slow :-( I have + to work again on this to make it faster. + - when detecting an error on a mounted filesystem, version 0.4 used + to try to write a flag in the super block even if the filesystem had + been mounted read-only. This is fixed. + - the `sb=#' option now causes the kernel code to use the filesystem + descriptors located at block #+1. Version 0.4 used the superblock + backup located at block # but used the main copy of the descriptors. + - a new file attribute `S' is supported. This attribute causes + synchronous writes but is applied to a file not to the entire file + system (thanks to Michael Kraehe for + suggesting it). + - the directory cache is inhibited by default. The cache management + code seems to be buggy and I have to look at it carefully before + using it again. + - deleting a file with the `s' attribute (secure deletion) causes its + blocks to be overwritten with random values not with zeros (thanks to + Michael A. Griffith for suggesting it). + - lots of cosmetic changes have been made. + +Changes from version 0.3 to version 0.4 +======================================= + - Three new mount options are supported: `check', `sync' and `sb=#'. + `check' tells the kernel code to make more consistency checks + when the file system is mounted. Currently, the kernel code checks + that the blocks and inodes bitmaps are consistent with the free + blocks and inodes counts. More checks will be added in future + releases. + `sync' tells the kernel code to use synchronous writes when updating + an inode, a bitmap, a directory entry or an indirect block. This + can make the file system much slower but can be a big win for files + recovery in case of a crash (and we can now say to the BSD folks + that Linux also supports synchronous updates :-). + `sb=#' tells the kernel code to use an alternate super block instead + of its master copy. `#' is the number of the block (counted in + 1024 bytes blocks) which contains the alternate super block. + An ext2 file system typically contains backups of the super block + at blocks 8193, 16385, and so on. + - I have change the meaning of the valid flag used by e2fsck. it + now contains the state of the file system. If the kernel code + detects an inconsistency while the file system is mounted, it flags + it as erroneous and e2fsck will detect that on next run. + - The super block now contains a mount counter. This counter is + incremented each time the file system is mounted read/write. When + this counter becomes bigger than a maximal mount counts (also stored + in the super block), e2fsck checks the file system, even if it had + been unmounted cleany, and resets this counter to 0. + - File attributes are now supported. One can associate a set of + attributes to a file. Three attributes are defined: + `c': the file is marked for automatic compression, + `s': the file is marked for secure deletion: when the file is + deleted, its blocks are zeroed and written back to the disk, + `u': the file is marked for undeletion: when the file is deleted, + its contents are saved to allow a future undeletion. + Currently, only the `s' attribute is implemented in the kernel + code. Support for the other attributes will be added in a future + release. + - a few bugs related to times updates have been fixed by Bruce + Evans and me. + - a bug related to the links count of deleted inodes has been fixed. + Previous versions used to keep the links count set to 1 when a file + was deleted. The new version now sets links_count to 0 when deleting + the last link. + - a race condition when deallocating an inode has been fixed by + Stephen Tweedie. + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/Makefile new file mode 100644 index 000000000..f8f8e9523 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for the linux ext2-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= acl.o balloc.o bitmap.o dcache.o dir.o file.o fsync.o \ + ialloc.o inode.o ioctl.o namei.o super.o symlink.o truncate.o + +ext2.o: $(OBJS) + $(LD) -r -o ext2.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/acl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/acl.c new file mode 100644 index 000000000..421fc11fc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/acl.c @@ -0,0 +1,45 @@ +/* + * linux/fs/ext2/acl.c + * + * Copyright (C) 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +/* + * This file will contain the Access Control Lists management for the + * second extended file system. + */ + +#include +#include +#include +#include +#include + +/* + * ext2_permission () + * + * Check for access rights + */ +int ext2_permission (struct inode * inode, int mask) +{ + unsigned short mode = inode->i_mode; + + /* + * Special case, access is always granted for root + */ + if (suser ()) + return 1; + /* + * If no ACL, checks using the file mode + */ + else if (current->euid == inode->i_uid) + mode >>= 6; + else if (in_group_p (inode->i_gid)) + mode >>= 3; + if (((mode & mask & S_IRWXO) == mask)) + return 1; + else + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/balloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/balloc.c new file mode 100644 index 000000000..b6559894b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/balloc.c @@ -0,0 +1,656 @@ +/* + * linux/fs/ext2/balloc.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * Enhanced block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + */ + +/* + * balloc.c contains the blocks allocation and deallocation routines + */ + +/* + * The free blocks are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see ext2_read_super). + */ + +#include +#include +#include +#include +#include +#include + +#include + +#define clear_block(addr,size) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (0), "c" (size / 4), "D" ((long) (addr)) \ + :"cx", "di") + +#define in_range(b, first, len) ((b) >= (first) && (b) <= (first) + (len) - 1) + +static inline int find_first_zero_bit (unsigned long * addr, unsigned size) +{ + int res; + + if (!size) + return 0; + __asm__(" + cld + movl $-1,%%eax + repe; scasl + je 1f + subl $4,%%edi + movl (%%edi),%%eax + notl %%eax + bsfl %%eax,%%edx + jmp 2f +1: xorl %%edx,%%edx +2: subl %%ebx,%%edi + shll $3,%%edi + addl %%edi,%%edx" + :"=d" (res) + :"c" ((size + 31) >> 5), "D" (addr), "b" (addr) + :"ax", "bx", "cx", "di"); + return res; +} + +static inline int find_next_zero_bit (unsigned long * addr, int size, + int offset) +{ + unsigned long * p = ((unsigned long *) addr) + (offset >> 5); + int set = 0, bit = offset & 31, res; + + if (bit) { + /* + * Look for zero in first byte + */ + __asm__(" + bsfl %1,%0 + jne 1f + movl $32, %0 +1: " + : "=r" (set) + : "r" (~(*p >> bit))); + if (set < (32 - bit)) + return set + offset; + set = 32 - bit; + p++; + } + /* + * No zero yet, search remaining full bytes for a zero + */ + res = find_first_zero_bit (p, size - 32 * (p - addr)); + return (offset + set + res); +} + +static inline char * find_first_zero_byte (char * addr, int size) +{ + char *res; + + if (!size) + return 0; + __asm__(" + cld + mov $0,%%eax + repnz; scasb + jnz 1f + dec %%edi +1: " + : "=D" (res) + : "0" (addr), "c" (size) + : "ax"); + return res; +} + +static struct ext2_group_desc * get_group_desc (struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) +{ + unsigned long group_desc; + unsigned long desc; + struct ext2_group_desc * gdp; + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "get_group_desc", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + if (!sb->u.ext2_sb.s_group_desc[group_desc]) + ext2_panic (sb, "get_group_desc", + "Group descriptor not loaded\n" + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.ext2_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +static void read_block_bitmap (struct super_block * sb, + unsigned int block_group, + unsigned long bitmap_nr) +{ + struct ext2_group_desc * gdp; + struct buffer_head * bh; + + gdp = get_group_desc (sb, block_group, NULL); + bh = bread (sb->s_dev, gdp->bg_block_bitmap, sb->s_blocksize); + if (!bh) + ext2_panic (sb, "read_block_bitmap", + "Cannot read block bitmap\n" + "block_group = %d, block_bitmap = %lu", + block_group, gdp->bg_block_bitmap); + sb->u.ext2_sb.s_block_bitmap_number[bitmap_nr] = block_group; + sb->u.ext2_sb.s_block_bitmap[bitmap_nr] = bh; +} + +/* + * load_block_bitmap loads the block bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + */ +static int load__block_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int i, j; + unsigned long block_bitmap_number; + struct buffer_head * block_bitmap; + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "load_block_bitmap", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { + if (sb->u.ext2_sb.s_block_bitmap[block_group]) { + if (sb->u.ext2_sb.s_block_bitmap_number[block_group] != + block_group) + ext2_panic (sb, "load_block_bitmap", + "block_group != block_bitmap_number"); + else + return block_group; + } else { + read_block_bitmap (sb, block_group, block_group); + return block_group; + } + } + + for (i = 0; i < sb->u.ext2_sb.s_loaded_block_bitmaps && + sb->u.ext2_sb.s_block_bitmap_number[i] != block_group; i++) + ; + if (i < sb->u.ext2_sb.s_loaded_block_bitmaps && + sb->u.ext2_sb.s_block_bitmap_number[i] == block_group) { + block_bitmap_number = sb->u.ext2_sb.s_block_bitmap_number[i]; + block_bitmap = sb->u.ext2_sb.s_block_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.ext2_sb.s_block_bitmap_number[j] = + sb->u.ext2_sb.s_block_bitmap_number[j - 1]; + sb->u.ext2_sb.s_block_bitmap[j] = + sb->u.ext2_sb.s_block_bitmap[j - 1]; + } + sb->u.ext2_sb.s_block_bitmap_number[0] = block_bitmap_number; + sb->u.ext2_sb.s_block_bitmap[0] = block_bitmap; + } else { + if (sb->u.ext2_sb.s_loaded_block_bitmaps < EXT2_MAX_GROUP_LOADED) + sb->u.ext2_sb.s_loaded_block_bitmaps++; + else + brelse (sb->u.ext2_sb.s_block_bitmap[EXT2_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext2_sb.s_loaded_block_bitmaps - 1; j > 0; j--) { + sb->u.ext2_sb.s_block_bitmap_number[j] = + sb->u.ext2_sb.s_block_bitmap_number[j - 1]; + sb->u.ext2_sb.s_block_bitmap[j] = + sb->u.ext2_sb.s_block_bitmap[j - 1]; + } + read_block_bitmap (sb, block_group, 0); + } + return 0; +} + +static inline int load_block_bitmap (struct super_block * sb, + unsigned int block_group) +{ + if (sb->u.ext2_sb.s_loaded_block_bitmaps > 0 && + sb->u.ext2_sb.s_block_bitmap_number[0] == block_group) + return 0; + + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED && + sb->u.ext2_sb.s_block_bitmap_number[block_group] == block_group && + sb->u.ext2_sb.s_block_bitmap[block_group]) + return block_group; + + return load__block_bitmap (sb, block_group); +} + +void ext2_free_blocks (struct super_block * sb, unsigned long block, + unsigned long count) +{ + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + unsigned long i; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + + if (!sb) { + printk ("ext2_free_blocks: nonexistent device"); + return; + } + lock_super (sb); + es = sb->u.ext2_sb.s_es; + if (block < es->s_first_data_block || + (block + count) > es->s_blocks_count) { + ext2_error (sb, "ext2_free_blocks", + "Freeing blocks not in datazone\n" + "block = %lu, count = %lu", block, count); + unlock_super (sb); + return; + } + + ext2_debug ("freeing block %lu\n", block); + + block_group = (block - es->s_first_data_block) / + EXT2_BLOCKS_PER_GROUP(sb); + bit = (block - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb); + if (bit + count > EXT2_BLOCKS_PER_GROUP(sb)) + ext2_panic (sb, "ext2_free_blocks", + "Freeing blocks across group boundary\n" + "Block = %lu, count = %lu", + block, count); + bitmap_nr = load_block_bitmap (sb, block_group); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + gdp = get_group_desc (sb, block_group, &bh2); + + if (test_opt (sb, CHECK_STRICT) && + (in_range (gdp->bg_block_bitmap, block, count) || + in_range (gdp->bg_inode_bitmap, block, count) || + in_range (block, gdp->bg_inode_table, + sb->u.ext2_sb.s_itb_per_group) || + in_range (block + count - 1, gdp->bg_inode_table, + sb->u.ext2_sb.s_itb_per_group))) + ext2_panic (sb, "ext2_free_blocks", + "Freeing blocks in system zones\n" + "Block = %lu, count = %lu", + block, count); + + for (i = 0; i < count; i++) { + if (!clear_bit (bit + i, bh->b_data)) + ext2_warning (sb, "ext2_free_blocks", + "bit already cleared for block %lu", + block); + else { + gdp->bg_free_blocks_count++; + es->s_free_blocks_count++; + } + } + + bh2->b_dirt = 1; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + sb->s_dirt = 1; + unlock_super (sb); + return; +} + +/* + * ext2_new_block uses a goal block to assist allocation. If the goal is + * free, or there is a free block within 32 blocks of the goal, that block + * is allocated. Otherwise a forward search is made for a free block; within + * each block group the search first looks for an entire free byte in the block + * bitmap, and then for any free bit if that fails. + */ +int ext2_new_block (struct super_block * sb, unsigned long goal, + unsigned long * prealloc_count, + unsigned long * prealloc_block) +{ + struct buffer_head * bh; + struct buffer_head * bh2; + char * p, * r; + int i, j, k, tmp; + unsigned long lmap; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + +#ifdef EXT2FS_DEBUG + static int goal_hits = 0, goal_attempts = 0; +#endif + if (!sb) { + printk ("ext2_new_block: nonexistent device"); + return 0; + } + lock_super (sb); + es = sb->u.ext2_sb.s_es; + if (es->s_free_blocks_count <= es->s_r_blocks_count && !suser()) { + unlock_super (sb); + return 0; + } + + ext2_debug ("goal=%lu.\n", goal); + + if (goal < es->s_first_data_block || goal >= es->s_blocks_count) { + ext2_warning (sb, "ext2_new_block", + "Goal out of bounds: %lu", goal); + goal = es->s_first_data_block; + } +repeat: + /* + * First, test whether the goal block is free. + */ + i = ((goal - es->s_first_data_block) / EXT2_BLOCKS_PER_GROUP(sb)); + gdp = get_group_desc (sb, i, &bh2); + if (gdp->bg_free_blocks_count > 0) { + j = ((goal - es->s_first_data_block) % EXT2_BLOCKS_PER_GROUP(sb)); +#ifdef EXT2FS_DEBUG + if (j) + goal_attempts++; +#endif + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + + ext2_debug ("goal is at %d:%d.\n", i, j); + + if (!test_bit(j, bh->b_data)) { +#ifdef EXT2FS_DEBUG + goal_hits++; + ext2_debug ("goal bit allocated.\n"); +#endif + goto got_block; + } + if (j) { + /* + * The goal was occupied; search forward for a free + * block within the next 32 blocks + */ + lmap = ((((unsigned long *) bh->b_data)[j >> 5]) >> + ((j & 31) + 1)); + if (j < EXT2_BLOCKS_PER_GROUP(sb) - 32) + lmap |= (((unsigned long *) bh->b_data)[(j >> 5) + 1]) << + (31 - (j & 31)); + else + lmap |= 0xffffffff << (31 - (j & 31)); + if (lmap != 0xffffffffl) { + __asm__ ("bsfl %1,%0" + : "=r" (k) + : "r" (~lmap)); + k++; + if ((j + k) < EXT2_BLOCKS_PER_GROUP(sb)) { + j += k; + goto got_block; + } + } + } + + ext2_debug ("Bit not found near goal\n"); + + /* + * There has been no free block found in the near vicinity + * of the goal: do a search forward through the block groups, + * searching in each group first for an entire free byte in + * the bitmap and then for any free bit. + * + * Search first in the remainder of the current group; then, + * cyclicly search throught the rest of the groups. + */ + p = ((char *) bh->b_data) + (j >> 3); + r = find_first_zero_byte (p, + (EXT2_BLOCKS_PER_GROUP(sb) - j + 7) >> 3); + k = (r - ((char *) bh->b_data)) << 3; + if (k < EXT2_BLOCKS_PER_GROUP(sb)) { + j = k; + goto search_back; + } + k = find_next_zero_bit ((unsigned long *) bh->b_data, + EXT2_BLOCKS_PER_GROUP(sb), + j); + if (k < EXT2_BLOCKS_PER_GROUP(sb)) { + j = k; + goto got_block; + } + } + + ext2_debug ("Bit not found in block group %d.\n", i); + + /* + * Now search the rest of the groups. We assume that + * i and gdp correctly point to the last group visited. + */ + for (k = 0; k < sb->u.ext2_sb.s_groups_count; k++) { + i++; + if (i >= sb->u.ext2_sb.s_groups_count) + i = 0; + gdp = get_group_desc (sb, i, &bh2); + if (gdp->bg_free_blocks_count > 0) + break; + } + if (k >= sb->u.ext2_sb.s_groups_count) { + unlock_super (sb); + return 0; + } + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + r = find_first_zero_byte (bh->b_data, + EXT2_BLOCKS_PER_GROUP(sb) >> 3); + j = (r - bh->b_data) << 3; + if (j < EXT2_BLOCKS_PER_GROUP(sb)) + goto search_back; + else + j = find_first_zero_bit ((unsigned long *) bh->b_data, + EXT2_BLOCKS_PER_GROUP(sb)); + if (j >= EXT2_BLOCKS_PER_GROUP(sb)) { + ext2_error (sb, "ext2_new_block", + "Free blocks count corrupted for block group %d", i); + unlock_super (sb); + return 0; + } + +search_back: + /* + * We have succeeded in finding a free byte in the block + * bitmap. Now search backwards up to 7 bits to find the + * start of this group of free blocks. + */ + for (k = 0; k < 7 && j > 0 && !test_bit (j - 1, bh->b_data); k++, j--); + +got_block: + + ext2_debug ("using block group %d(%d)\n", i, gdp->bg_free_blocks_count); + + tmp = j + i * EXT2_BLOCKS_PER_GROUP(sb) + es->s_first_data_block; + + if (test_opt (sb, CHECK_STRICT) && + (tmp == gdp->bg_block_bitmap || + tmp == gdp->bg_inode_bitmap || + in_range (tmp, gdp->bg_inode_table, sb->u.ext2_sb.s_itb_per_group))) + ext2_panic (sb, "ext2_new_block", + "Allocating block in system zone\n" + "block = %u", tmp); + + if (set_bit (j, bh->b_data)) { + ext2_warning (sb, "ext2_new_block", + "bit already set for block %d", j); + goto repeat; + } + + ext2_debug ("found bit %d\n", j); + + /* + * Do block preallocation now if required. + */ +#ifdef EXT2_PREALLOCATE + if (prealloc_block) { + *prealloc_count = 0; + *prealloc_block = tmp + 1; + for (k = 1; + k < 8 && (j + k) < EXT2_BLOCKS_PER_GROUP(sb); k++) { + if (set_bit (j + k, bh->b_data)) + break; + (*prealloc_count)++; + } + gdp->bg_free_blocks_count -= *prealloc_count; + es->s_free_blocks_count -= *prealloc_count; + ext2_debug ("Preallocated a further %lu bits.\n", + *prealloc_count); + } +#endif + + j = tmp; + + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + + if (j >= es->s_blocks_count) { + ext2_error (sb, "ext2_new_block", + "block >= blocks count\n" + "block_group = %d, block=%d", i, j); + unlock_super (sb); + return 0; + } + if (!(bh = getblk (sb->s_dev, j, sb->s_blocksize))) { + ext2_error (sb, "ext2_new_block", "cannot get block %d", j); + unlock_super (sb); + return 0; + } + clear_block (bh->b_data, sb->s_blocksize); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse (bh); + + ext2_debug ("allocating block %d. " + "Goal hits %d of %d.\n", j, goal_hits, goal_attempts); + + gdp->bg_free_blocks_count--; + bh2->b_dirt = 1; + es->s_free_blocks_count--; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + unlock_super (sb); + return j; +} + +unsigned long ext2_count_free_blocks (struct super_block * sb) +{ +#ifdef EXT2FS_DEBUG + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); + desc_count += gdp->bg_free_blocks_count; + bitmap_nr = load_block_bitmap (sb, i); + x = ext2_count_free (sb->u.ext2_sb.s_block_bitmap[bitmap_nr], + sb->s_blocksize); + printk ("group %d: stored = %d, counted = %lu\n", + i, gdp->bg_free_blocks_count, x); + bitmap_count += x; + } + printk("ext2_count_free_blocks: stored = %lu, computed = %lu, %lu\n", + es->s_free_blocks_count, desc_count, bitmap_count); + unlock_super (sb); + return bitmap_count; +#else + return sb->u.ext2_sb.s_es->s_free_blocks_count; +#endif +} + +static inline int block_in_use (unsigned long block, + struct super_block * sb, + unsigned char * map) +{ + return test_bit ((block - sb->u.ext2_sb.s_es->s_first_data_block) % + EXT2_BLOCKS_PER_GROUP(sb), map); +} + +void ext2_check_blocks_bitmap (struct super_block * sb) +{ + struct buffer_head * bh; + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i, j; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); + desc_count += gdp->bg_free_blocks_count; + bitmap_nr = load_block_bitmap (sb, i); + bh = sb->u.ext2_sb.s_block_bitmap[bitmap_nr]; + + if (!block_in_use (gdp->bg_block_bitmap, sb, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Block bitmap for group %d is marked free", + i); + + if (!block_in_use (gdp->bg_inode_bitmap, sb, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Inode bitmap for group %d is marked free", + i); + + for (j = 0; j < sb->u.ext2_sb.s_itb_per_group; j++) + if (!block_in_use (gdp->bg_inode_table + j, sb, bh->b_data)) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Block #%d of the inode table in group %d " + "is marked free", j, i); + + x = ext2_count_free (bh, sb->s_blocksize); + if (gdp->bg_free_blocks_count != x) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Wrong free blocks count for group %d, " + "stored = %d, counted = %lu", i, + gdp->bg_free_blocks_count, x); + bitmap_count += x; + } + if (es->s_free_blocks_count != bitmap_count) + ext2_error (sb, "ext2_check_blocks_bitmap", + "Wrong free blocks count in super block, " + "stored = %lu, counted = %lu", + es->s_free_blocks_count, bitmap_count); + unlock_super (sb); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/bitmap.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/bitmap.c new file mode 100644 index 000000000..1084da16d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/bitmap.c @@ -0,0 +1,25 @@ +/* + * linux/fs/ext2/bitmap.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include +#include + +static int nibblemap[] = {4, 3, 3, 2, 3, 2, 2, 1, 3, 2, 2, 1, 2, 1, 1, 0}; + +unsigned long ext2_count_free (struct buffer_head * map, unsigned int numchars) +{ + unsigned int i; + unsigned long sum = 0; + + if (!map) + return (0); + for (i = 0; i < numchars; i++) + sum += nibblemap[map->b_data[i] & 0xf] + + nibblemap[(map->b_data[i] >> 4) & 0xf]; + return (sum); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dcache.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dcache.c new file mode 100644 index 000000000..324ddaee4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dcache.c @@ -0,0 +1,338 @@ +/* + * linux/fs/ext2/dcache.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + */ + +/* + * dcache.c contains the code that handles the directory cache used by + * lookup() and readdir() + */ + +#include + +#include +#include +#include + +#ifndef DONT_USE_DCACHE + +#define DCACHE_NAME_LEN 32 + +struct dir_cache_entry { + unsigned short dev; + unsigned long dir; + unsigned long ino; + char name[DCACHE_NAME_LEN + 1]; + int len; + struct dir_cache_entry * queue_prev; + struct dir_cache_entry * queue_next; + struct dir_cache_entry * prev; + struct dir_cache_entry * next; +}; + +static struct dir_cache_entry * first = NULL; +static struct dir_cache_entry * last = NULL; +static struct dir_cache_entry * first_free = NULL; +static int cache_initialized = 0; +#ifdef EXT2FS_DEBUG_CACHE +static int hits = 0; +static int misses = 0; +#endif + +#define CACHE_SIZE 128 + +static struct dir_cache_entry dcache[CACHE_SIZE]; + +#define HASH_QUEUES 16 + +static struct dir_cache_entry * queue_head[HASH_QUEUES]; +static struct dir_cache_entry * queue_tail[HASH_QUEUES]; + +#define hash(dev,dir) ((dev ^ dir) % HASH_QUEUES) + +/* + * Initialize the cache + */ +static void init_cache (void) +{ + int i; + + dcache[0].prev = NULL; + dcache[0].next = &dcache[1]; + dcache[0].queue_next = dcache[0].queue_prev = NULL; + for (i = 1; i < CACHE_SIZE - 1; i++) { + dcache[i].prev = &dcache[i - 1]; + dcache[i].next = &dcache[i + 1]; + dcache[i].queue_next = dcache[i].queue_prev = NULL; + } + dcache[i].prev = &dcache[i - 1]; + dcache[i].next = NULL; + dcache[i].queue_next = dcache[i].queue_prev = NULL; + first_free = &dcache[0]; + for (i = 0; i < HASH_QUEUES; i++) + queue_tail[i] = queue_head[i] = NULL; + cache_initialized = 1; +} + +/* + * Find a name in the cache + */ +static struct dir_cache_entry * find_name (int queue, unsigned short dev, + unsigned long dir, + const char * name, int len) +{ + struct dir_cache_entry * p; + + for (p = queue_head[queue]; p != NULL && (p->dev != dev || + p->dir != dir || p->len != len || + strncmp (name, p->name, p->len) != 0); + p = p->queue_next) + ; + return p; +} + +#ifdef EXT2FS_DEBUG_CACHE +/* + * List the cache entries for debugging + */ +static void show_cache (const char * func_name) +{ + struct dir_cache_entry * p; + + printk ("%s: cache status\n", func_name); + for (p = first; p != NULL; p = p->next) + printk ("dev:%04x, dir=%4lu, name=%s\n", + p->dev, p->dir, p->name); +} +#endif + +/* + * Add an entry at the beginning of the cache + */ +static void add_to_cache (struct dir_cache_entry * p) +{ + p->prev = NULL; + p->next = first; + if (first) + first->prev = p; + if (!last) + last = p; + first = p; +} + +/* + * Add an entry at the beginning of a queue + */ +static void add_to_queue (int queue, struct dir_cache_entry * p) +{ + p->queue_prev = NULL; + p->queue_next = queue_head[queue]; + if (queue_head[queue]) + queue_head[queue]->queue_prev = p; + if (!queue_tail[queue]) + queue_tail[queue] = p; + queue_head[queue] = p; +} + +/* + * Remove an entry from the cache + */ +static void remove_from_cache (struct dir_cache_entry * p) +{ + if (p->prev) + p->prev->next = p->next; + else + first = p->next; + if (p->next) + p->next->prev = p->prev; + else + last = p->prev; + p->prev = NULL; + p->next = NULL; +} + +/* + * Remove an entry from a queue + */ +static void remove_from_queue (int queue, struct dir_cache_entry * p) +{ + if (p->queue_prev) + p->queue_prev->queue_next = p->queue_next; + else + queue_head[queue] = p->queue_next; + if (p->queue_next) + p->queue_next->queue_prev = p->queue_prev; + else + queue_tail[queue] = p->queue_prev; + p->queue_prev = NULL; + p->queue_next = NULL; +} + +/* + * Invalidate all cache entries on a device (called by put_super() when + * a file system is unmounted) + */ +void ext2_dcache_invalidate (unsigned short dev) +{ + struct dir_cache_entry * p; + struct dir_cache_entry * p2; + + if (!cache_initialized) + init_cache (); + for (p = first; p != NULL; p = p2) { + p2 = p->next; + if (p->dev == dev) { + remove_from_cache (p); + remove_from_queue (hash (p->dev, p->dir), p); + p->next = first_free; + first_free = p; + } + } +#ifdef EXT2FS_DEBUG_CACHE + show_cache ("dcache_invalidate"); +#endif +} + +/* + * Lookup a directory entry in the cache + */ +unsigned long ext2_dcache_lookup (unsigned short dev, unsigned long dir, + const char * name, int len) +{ + char our_name[EXT2_NAME_LEN]; + int queue; + struct dir_cache_entry * p; + + if (!cache_initialized) + init_cache (); + if (len > DCACHE_NAME_LEN) + return 0; + memcpy (our_name, (char *) name, len); + our_name[len] = '\0'; +#ifdef EXT2FS_DEBUG_CACHE + printk ("dcache_lookup (%04x, %lu, %s, %d)\n", dev, dir, our_name, len); +#endif + queue = hash (dev, dir); + if ((p = find_name (queue, dev, dir, our_name, len))) { + if (p != first) { + remove_from_cache (p); + add_to_cache (p); + } + if (p != queue_head[queue]) { + remove_from_queue (queue, p); + add_to_queue (queue, p); + } +#ifdef EXT2FS_DEBUG_CACHE + hits++; + printk ("dcache_lookup: %s,hit,inode=%lu,hits=%d,misses=%d\n", + our_name, p->ino, hits, misses); + show_cache ("dcache_lookup"); +#endif + return p->ino; + } else { +#ifdef EXT2FS_DEBUG_CACHE + misses++; + printk ("dcache_lookup: %s,miss,hits=%d,misses=%d\n", + our_name, hits, misses); + show_cache ("dcache_lookup"); +#endif + return 0; + } +} + +/* + * Add a directory entry to the cache + * + * This function is called by ext2_lookup(), ext2_readdir() + * and the functions which create directory entries + */ +void ext2_dcache_add (unsigned short dev, unsigned long dir, const char * name, + int len, unsigned long ino) +{ + struct dir_cache_entry * p; + int queue; + + if (!cache_initialized) + init_cache (); +#ifdef EXT2FS_DEBUG_CACHE + printk ("dcache_add (%04x, %lu, %s, %d, %lu)\n", + dev, dir, name, len, ino); +#endif + if (len > DCACHE_NAME_LEN) + return; + queue = hash (dev, dir); + if ((p = find_name (queue, dev, dir, name, len))) { + p->dir = dir; + p->ino = ino; + if (p != first) { + remove_from_cache (p); + add_to_cache (p); + } + if (p != queue_head[queue]) { + remove_from_queue (queue, p); + add_to_queue (queue, p); + } + } else { + if (first_free) { + p = first_free; + first_free = p->next; + } else { + if (!last) + panic ("dcache_add: last == NULL\n"); + else { + p = last; + last = p->prev; + if (last) + last->next = NULL; + remove_from_queue (hash (p->dev, p->dir), p); + } + } + p->dev = dev; + p->dir = dir; + p->ino = ino; + strncpy (p->name, name, len); + p->len = len; + p->name[len] = '\0'; + add_to_cache (p); + add_to_queue (queue, p); + } +#ifdef EXT2FS_DEBUG_CACHE + show_cache ("dcache_add"); +#endif +} + +/* + * Remove a directory from the cache + * + * This function is called by the functions which remove directory entries + */ +void ext2_dcache_remove (unsigned short dev, unsigned long dir, + const char * name, int len) +{ + struct dir_cache_entry * p; + int queue; + + if (!cache_initialized) + init_cache (); +#ifdef EXT2FS_DEBUG_CACHE + printk ("dcache_remove (%04x, %lu, %s, %d)\n", dev, dir, name, len); +#endif + if (len > DCACHE_NAME_LEN) + return; + queue = hash (dev, dir); + if ((p = find_name (queue, dev, dir, name, len))) { + remove_from_cache (p); + remove_from_queue (queue, p); + p->next = first_free; + first_free = p; + } +#ifdef EXT2FS_DEBUG_CACHE + show_cache ("dcache_remove"); +#endif +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dir.c new file mode 100644 index 000000000..84830b8a5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/dir.c @@ -0,0 +1,170 @@ +/* + * linux/fs/ext2/dir.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 directory handling functions + */ + +#include + +#include +#include +#include +#include +#include + +static int ext2_dir_read (struct inode * inode, struct file * filp, + char * buf, int count) +{ + return -EISDIR; +} + +static int ext2_readdir (struct inode *, struct file *, struct dirent *, int); + +static struct file_operations ext2_dir_operations = { + NULL, /* lseek - default */ + ext2_dir_read, /* read */ + NULL, /* write - bad */ + ext2_readdir, /* readdir */ + NULL, /* select - default */ + ext2_ioctl, /* ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations ext2_dir_inode_operations = { + &ext2_dir_operations, /* default directory file-ops */ + ext2_create, /* create */ + ext2_lookup, /* lookup */ + ext2_link, /* link */ + ext2_unlink, /* unlink */ + ext2_symlink, /* symlink */ + ext2_mkdir, /* mkdir */ + ext2_rmdir, /* rmdir */ + ext2_mknod, /* mknod */ + ext2_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + ext2_truncate, /* truncate */ + ext2_permission /* permission */ +}; + +int ext2_check_dir_entry (char * function, struct inode * dir, + struct ext2_dir_entry * de, struct buffer_head * bh, + unsigned long offset) +{ + char * error_msg = NULL; + + if (de->rec_len < EXT2_DIR_REC_LEN(1)) + error_msg = "rec_len is smaller than minimal"; + else if (de->rec_len % 4 != 0) + error_msg = "rec_len % 4 != 0"; + else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len)) + error_msg = "rec_len is too small for name_len"; + else if (dir && ((char *) de - bh->b_data) + de->rec_len > + dir->i_sb->s_blocksize) + error_msg = "directory entry across blocks"; + + if (error_msg != NULL) + ext2_error (dir->i_sb, function, "bad directory entry: %s\n" + "offset=%lu, inode=%lu, rec_len=%d, name_len=%d", + error_msg, offset, de->inode, de->rec_len, + de->name_len); + return error_msg == NULL ? 1 : 0; +} + +static int ext2_readdir (struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + unsigned long offset, blk; + int i, num; + struct buffer_head * bh, * tmp, * bha[16]; + struct ext2_dir_entry * de; + struct super_block * sb; + int err; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + sb = inode->i_sb; + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & (sb->s_blocksize - 1); + blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb); + bh = ext2_bread (inode, blk, 0, &err); + if (!bh) { + filp->f_pos += sb->s_blocksize - offset; + continue; + } + + /* + * Do the readahead + */ + if (!offset) { + for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0; + i > 0; i--) { + tmp = ext2_getblk (inode, ++blk, 0, &err); + if (tmp && !tmp->b_uptodate && !tmp->b_lock) + bha[num++] = tmp; + else + brelse (tmp); + } + if (num) { + ll_rw_block (READA, num, bha); + for (i = 0; i < num; i++) + brelse (bha[i]); + } + } + + de = (struct ext2_dir_entry *) (offset + bh->b_data); + while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) { + if (!ext2_check_dir_entry ("ext2_readdir", inode, de, + bh, offset)) { + brelse (bh); + return 0; + } + offset += de->rec_len; + filp->f_pos += de->rec_len; + if (de->inode) { + memcpy_tofs (dirent->d_name, de->name, + de->name_len); + put_fs_long (de->inode, &dirent->d_ino); + put_fs_byte (0, de->name_len + dirent->d_name); + put_fs_word (de->name_len, &dirent->d_reclen); +#ifndef DONT_USE_DCACHE + ext2_dcache_add (inode->i_dev, inode->i_ino, + de->name, de->name_len, + de->inode); +#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 + + de->rec_len); + } + brelse (bh); + } + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/file.c new file mode 100644 index 000000000..4f7fa7b4b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/file.c @@ -0,0 +1,301 @@ +/* + * linux/fs/ext2/file.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 fs regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +static int ext2_file_read (struct inode *, struct file *, char *, int); +static int ext2_file_write (struct inode *, struct file *, char *, int); +static void ext2_release_file (struct inode *, struct file *); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the ext2 filesystem. + */ +static struct file_operations ext2_file_operations = { + NULL, /* lseek - default */ + ext2_file_read, /* read */ + ext2_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + ext2_ioctl, /* ioctl */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + ext2_release_file, /* release */ + ext2_sync_file /* fsync */ +}; + +struct inode_operations ext2_file_inode_operations = { + &ext2_file_operations,/* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + ext2_bmap, /* bmap */ + ext2_truncate, /* truncate */ + ext2_permission /* permission */ +}; + +static int ext2_file_read (struct inode * inode, struct file * filp, + char * buf, int count) +{ + int read, left, chars; + int block, blocks, offset; + int bhrequest, uptodate; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + struct super_block * sb; + unsigned int size; + int err; + + if (!inode) { + printk ("ext2_file_read: inode = NULL\n"); + return -EINVAL; + } + sb = inode->i_sb; + if (!S_ISREG(inode->i_mode)) { + ext2_warning (sb, "ext2_file_read", "mode = %07o", + inode->i_mode); + return -EINVAL; + } + offset = filp->f_pos; + size = inode->i_size; + if (offset > size) + left = 0; + else + left = size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = offset >> EXT2_BLOCK_SIZE_BITS(sb); + offset &= (sb->s_blocksize - 1); + size = (size + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); + blocks = (left + offset + sb->s_blocksize - 1) >> EXT2_BLOCK_SIZE_BITS(sb); + bhb = bhe = buflist; + if (filp->f_reada) { + blocks += read_ahead[MAJOR(inode->i_dev)] >> + (EXT2_BLOCK_SIZE_BITS(sb) - 9); + if (block + blocks > size) + blocks = size - block; + } + + /* + * We do this in a two stage process. We first try and request + * as many blocks as we can, then we wait for the first one to + * complete, and then we try and wrap up as many as are actually + * done. This routine is rather generic, in that it can be used + * in a filesystem by substituting the appropriate function in + * for getblk + * + * This routine is optimized to make maximum use of the various + * buffers and caches. + */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + *bhb = ext2_getblk (inode, block++, 0, &err); + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* + * If the block we have on hand is uptodate, go ahead + * and complete processing + */ + if (uptodate) + break; + + if (bhb == bhe) + break; + } + + /* + * Now request them all + */ + if (bhrequest) + ll_rw_block (READ, bhrequest, bhreq); + + do { + /* + * Finish off all I/O that has actually completed + */ + if (*bhe) { + wait_on_buffer (*bhe); + if (!(*bhe)->b_uptodate) { /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < sb->s_blocksize - offset) + chars = left; + else + chars = sb->s_blocksize - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs (buf, offset + (*bhe)->b_data, + chars); + brelse (*bhe); + buf += chars; + } else { + while (chars-- > 0) + put_fs_byte (0, buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); + } while (left > 0); + + /* + * Release the read-ahead blocks + */ + while (bhe != bhb) { + brelse (*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } + if (!read) + return -EIO; + filp->f_reada = 1; + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return read; +} + +static int ext2_file_write (struct inode * inode, struct file * filp, + char * buf, int count) +{ + off_t pos; + int written, c; + struct buffer_head * bh; + char * p; + struct super_block * sb; + int err; + + if (!inode) { + printk("ext2_file_write: inode = NULL\n"); + return -EINVAL; + } + sb = inode->i_sb; + if (sb->s_flags & MS_RDONLY) + /* + * This fs has been automatically remounted ro because of errors + */ + return -ENOSPC; + + if (!S_ISREG(inode->i_mode)) { + ext2_warning (sb, "ext2_file_write", "mode = %07o\n", + inode->i_mode); + return -EINVAL; + } +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written < count) { + bh = ext2_getblk (inode, pos / sb->s_blocksize, 1, &err); + if (!bh) { + if (!written) + written = err; + break; + } + c = sb->s_blocksize - (pos % sb->s_blocksize); + if (c > count-written) + c = count - written; + if (c != sb->s_blocksize && !bh->b_uptodate) { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!bh->b_uptodate) { + brelse (bh); + if (!written) + written = -EIO; + break; + } + } + p = (pos % sb->s_blocksize) + bh->b_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs (p, buf, c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse (bh); + } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + return written; +} + +/* + * Called when a inode is released. Note that this is different + * from ext2_open: open gets called at every open, but release + * gets called only when /all/ the files are closed. + */ +static void ext2_release_file (struct inode * inode, struct file * filp) +{ + if (filp->f_mode & 2) + ext2_discard_prealloc (inode); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/fsync.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/fsync.c new file mode 100644 index 000000000..2f79c4749 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/fsync.c @@ -0,0 +1,198 @@ +/* + * linux/fs/ext2/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * from + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * from + * linux/fs/minix/truncate.c Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2fs fsync primitive + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define blocksize (EXT2_BLOCK_SIZE(inode->i_sb)) +#define addr_per_block (EXT2_ADDR_PER_BLOCK(inode->i_sb)) + +static int sync_block (struct inode * inode, unsigned long * block, int wait) +{ + struct buffer_head * bh; + int tmp; + + if (!*block) + return 0; + tmp = *block; + bh = get_hash_table (inode->i_dev, *block, blocksize); + if (!bh) + return 0; + if (*block != tmp) { + brelse (bh); + return 1; + } + if (wait && bh->b_req && !bh->b_uptodate) { + brelse (bh); + return -1; + } + if (wait || !bh->b_uptodate || !bh->b_dirt) { + brelse (bh); + return 0; + } + ll_rw_block (WRITE, 1, &bh); + bh->b_count--; + return 0; +} + +static int sync_iblock (struct inode * inode, unsigned long * iblock, + struct buffer_head ** bh, int wait) +{ + int rc, tmp; + + *bh = NULL; + tmp = *iblock; + if (!tmp) + return 0; + rc = sync_block (inode, iblock, wait); + if (rc) + return rc; + *bh = bread (inode->i_dev, tmp, blocksize); + if (tmp != *iblock) { + brelse (*bh); + *bh = NULL; + return 1; + } + if (!*bh) + return -1; + return 0; +} + + +static int sync_direct (struct inode * inode, int wait) +{ + int i; + int rc, err = 0; + + for (i = 0; i < EXT2_NDIR_BLOCKS; i++) { + rc = sync_block (inode, inode->u.ext2_i.i_data + i, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + return err; +} + +static int sync_indirect (struct inode * inode, unsigned long * iblock, + int wait) +{ + int i; + struct buffer_head * ind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, iblock, &ind_bh, wait); + if (rc || !ind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_block (inode, + ((unsigned long *) ind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (ind_bh); + return err; +} + +static int sync_dindirect (struct inode * inode, unsigned long * diblock, + int wait) +{ + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect (inode, + ((unsigned long *) dind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (dind_bh); + return err; +} + +static int sync_tindirect (struct inode * inode, unsigned long * tiblock, + int wait) +{ + int i; + struct buffer_head * tind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, tiblock, &tind_bh, wait); + if (rc || !tind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_dindirect (inode, + ((unsigned long *) tind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse (tind_bh); + return err; +} + +int ext2_sync_file (struct inode * inode, struct file * file) +{ + int wait, err = 0; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + if (S_ISLNK(inode->i_mode) && !(inode->i_blocks)) + /* + * Don't sync fast links! + */ + goto skip; + + for (wait=0; wait<=1; wait++) + { + err |= sync_direct (inode, wait); + err |= sync_indirect (inode, + inode->u.ext2_i.i_data+EXT2_IND_BLOCK, + wait); + err |= sync_dindirect (inode, + inode->u.ext2_i.i_data+EXT2_DIND_BLOCK, + wait); + err |= sync_tindirect (inode, + inode->u.ext2_i.i_data+EXT2_TIND_BLOCK, + wait); + } +skip: + err |= ext2_sync_inode (inode); + return (err < 0) ? -EIO : 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ialloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ialloc.c new file mode 100644 index 000000000..de2144aa1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ialloc.c @@ -0,0 +1,577 @@ +/* + * linux/fs/ext2/ialloc.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * BSD ufs-inspired inode and directory allocation by + * Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + */ + +/* + * ialloc.c contains the inodes allocation and deallocation routines + */ + +/* + * The free inodes are managed by bitmaps. A file system contains several + * blocks groups. Each group contains 1 bitmap block for blocks, 1 bitmap + * block for inodes, N blocks for the inode table and data blocks. + * + * The file system contains group descriptors which are located after the + * super block. Each descriptor contains the number of the bitmap block and + * the free blocks count in the block. The descriptors are loaded in memory + * when a file system is mounted (see ext2_read_super). + */ + +#include +#include +#include +#include +#include +#include + +#include + +static inline int find_first_zero_bit (unsigned long * addr, unsigned size) +{ + int res; + + if (!size) + return 0; + __asm__(" + cld + movl $-1,%%eax + repe; scasl + je 1f + subl $4,%%edi + movl (%%edi),%%eax + notl %%eax + bsfl %%eax,%%edx + jmp 2f +1: xorl %%edx,%%edx +2: subl %%ebx,%%edi + shll $3,%%edi + addl %%edi,%%edx" + : "=d" (res) + : "c" ((size + 31) >> 5), "D" (addr), "b" (addr) + : "ax", "bx", "cx", "di"); + return res; +} + +static struct ext2_group_desc * get_group_desc (struct super_block * sb, + unsigned int block_group, + struct buffer_head ** bh) +{ + unsigned long group_desc; + unsigned long desc; + struct ext2_group_desc * gdp; + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "get_group_desc", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + + group_desc = block_group / EXT2_DESC_PER_BLOCK(sb); + desc = block_group % EXT2_DESC_PER_BLOCK(sb); + if (!sb->u.ext2_sb.s_group_desc[group_desc]) + ext2_panic (sb, "get_group_desc", + "Group descriptor not loaded\n" + "block_group = %d, group_desc = %lu, desc = %lu", + block_group, group_desc, desc); + gdp = (struct ext2_group_desc *) + sb->u.ext2_sb.s_group_desc[group_desc]->b_data; + if (bh) + *bh = sb->u.ext2_sb.s_group_desc[group_desc]; + return gdp + desc; +} + +static void read_inode_bitmap (struct super_block * sb, + unsigned long block_group, + unsigned int bitmap_nr) +{ + struct ext2_group_desc * gdp; + struct buffer_head * bh; + + gdp = get_group_desc (sb, block_group, NULL); + bh = bread (sb->s_dev, gdp->bg_inode_bitmap, sb->s_blocksize); + if (!bh) + ext2_panic (sb, "read_inode_bitmap", "Cannot read inode bitmap\n" + "block_group = %lu, inode_bitmap = %lu", + block_group, gdp->bg_inode_bitmap); + sb->u.ext2_sb.s_inode_bitmap_number[bitmap_nr] = block_group; + sb->u.ext2_sb.s_inode_bitmap[bitmap_nr] = bh; +} + +/* + * load_inode_bitmap loads the inode bitmap for a blocks group + * + * It maintains a cache for the last bitmaps loaded. This cache is managed + * with a LRU algorithm. + * + * Notes: + * 1/ There is one cache per mounted file system. + * 2/ If the file system contains less than EXT2_MAX_GROUP_LOADED groups, + * this function reads the bitmap without maintaining a LRU cache. + */ +static int load_inode_bitmap (struct super_block * sb, + unsigned int block_group) +{ + int i, j; + unsigned long inode_bitmap_number; + struct buffer_head * inode_bitmap; + + if (block_group >= sb->u.ext2_sb.s_groups_count) + ext2_panic (sb, "load_inode_bitmap", + "block_group >= groups_count\n" + "block_group = %d, groups_count = %lu", + block_group, sb->u.ext2_sb.s_groups_count); + if (sb->u.ext2_sb.s_loaded_inode_bitmaps > 0 && + sb->u.ext2_sb.s_inode_bitmap_number[0] == block_group) + return 0; + if (sb->u.ext2_sb.s_groups_count <= EXT2_MAX_GROUP_LOADED) { + if (sb->u.ext2_sb.s_inode_bitmap[block_group]) { + if (sb->u.ext2_sb.s_inode_bitmap_number[block_group] != block_group) + ext2_panic (sb, "load_inode_bitmap", + "block_group != inode_bitmap_number"); + else + return block_group; + } else { + read_inode_bitmap (sb, block_group, block_group); + return block_group; + } + } + + for (i = 0; i < sb->u.ext2_sb.s_loaded_inode_bitmaps && + sb->u.ext2_sb.s_inode_bitmap_number[i] != block_group; + i++) + ; + if (i < sb->u.ext2_sb.s_loaded_inode_bitmaps && + sb->u.ext2_sb.s_inode_bitmap_number[i] == block_group) { + inode_bitmap_number = sb->u.ext2_sb.s_inode_bitmap_number[i]; + inode_bitmap = sb->u.ext2_sb.s_inode_bitmap[i]; + for (j = i; j > 0; j--) { + sb->u.ext2_sb.s_inode_bitmap_number[j] = + sb->u.ext2_sb.s_inode_bitmap_number[j - 1]; + sb->u.ext2_sb.s_inode_bitmap[j] = + sb->u.ext2_sb.s_inode_bitmap[j - 1]; + } + sb->u.ext2_sb.s_inode_bitmap_number[0] = inode_bitmap_number; + sb->u.ext2_sb.s_inode_bitmap[0] = inode_bitmap; + } else { + if (sb->u.ext2_sb.s_loaded_inode_bitmaps < EXT2_MAX_GROUP_LOADED) + sb->u.ext2_sb.s_loaded_inode_bitmaps++; + else + brelse (sb->u.ext2_sb.s_inode_bitmap[EXT2_MAX_GROUP_LOADED - 1]); + for (j = sb->u.ext2_sb.s_loaded_inode_bitmaps - 1; j > 0; j--) { + sb->u.ext2_sb.s_inode_bitmap_number[j] = + sb->u.ext2_sb.s_inode_bitmap_number[j - 1]; + sb->u.ext2_sb.s_inode_bitmap[j] = + sb->u.ext2_sb.s_inode_bitmap[j - 1]; + } + read_inode_bitmap (sb, block_group, 0); + } + return 0; +} + +/* + * This function sets the deletion time for the inode + * + * This may be used one day by an 'undelete' program + */ +static void set_inode_dtime (struct inode * inode, + struct ext2_group_desc * gdp) +{ + unsigned long inode_block; + struct buffer_head * bh; + struct ext2_inode * raw_inode; + + inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) / + EXT2_INODES_PER_BLOCK(inode->i_sb)); + bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); + if (!bh) + ext2_panic (inode->i_sb, "set_inode_dtime", + "Cannot load inode table block\n" + "inode=%lu, inode_block=%lu", + inode->i_ino, inode_block); + raw_inode = ((struct ext2_inode *) bh->b_data) + + (((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; + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); +} + +void ext2_free_inode (struct inode * inode) +{ + struct super_block * sb; + struct buffer_head * bh; + struct buffer_head * bh2; + unsigned long block_group; + unsigned long bit; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_super_block * es; + + if (!inode) + return; + if (!inode->i_dev) { + printk ("ext2_free_inode: inode has no device\n"); + return; + } + if (inode->i_count > 1) { + printk ("ext2_free_inode: inode has count=%d\n", + inode->i_count); + return; + } + if (inode->i_nlink) { + printk ("ext2_free_inode: inode has nlink=%d\n", + inode->i_nlink); + return; + } + if (!inode->i_sb) { + printk("ext2_free_inode: inode on nonexistent device\n"); + return; + } + + ext2_debug ("freeing inode %lu\n", inode->i_ino); + + sb = inode->i_sb; + lock_super (sb); + if (inode->i_ino < EXT2_FIRST_INO || + inode->i_ino > sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (sb, "free_inode", + "reserved inode or nonexistent inode"); + unlock_super (sb); + return; + } + es = sb->u.ext2_sb.s_es; + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(sb); + bit = (inode->i_ino - 1) % EXT2_INODES_PER_GROUP(sb); + bitmap_nr = load_inode_bitmap (sb, block_group); + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + if (!clear_bit (bit, bh->b_data)) + ext2_warning (sb, "ext2_free_inode", + "bit already cleared for inode %lu", inode->i_ino); + else { + gdp = get_group_desc (sb, block_group, &bh2); + gdp->bg_free_inodes_count++; + if (S_ISDIR(inode->i_mode)) + gdp->bg_used_dirs_count--; + bh2->b_dirt = 1; + es->s_free_inodes_count++; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + set_inode_dtime (inode, gdp); + } + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + + sb->s_dirt = 1; + clear_inode (inode); + unlock_super (sb); +} + +/* + * This function increments the inode version number + * + * This may be used one day by the NFS server + */ +static void inc_inode_version (struct inode * inode, + struct ext2_group_desc *gdp, + int mode) +{ + unsigned long inode_block; + struct buffer_head * bh; + struct ext2_inode * raw_inode; + + inode_block = gdp->bg_inode_table + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) / + EXT2_INODES_PER_BLOCK(inode->i_sb)); + bh = bread (inode->i_sb->s_dev, inode_block, inode->i_sb->s_blocksize); + if (!bh) { + ext2_error (inode->i_sb, "inc_inode_version", + "Cannot load inode table block" + "inode=%lu, inode_block=%lu\n", + inode->i_ino, inode_block); + inode->u.ext2_i.i_version = 1; + return; + } + raw_inode = ((struct ext2_inode *) bh->b_data) + + (((inode->i_ino - 1) % + EXT2_INODES_PER_GROUP(inode->i_sb)) % + EXT2_INODES_PER_BLOCK(inode->i_sb)); + raw_inode->i_version++; + inode->u.ext2_i.i_version = raw_inode->i_version; + bh->b_dirt = 1; + brelse (bh); +} + +/* + * There are two policies for allocating an inode. If the new inode is + * a directory, then a forward search is made for a block group with both + * free space and a low directory-to-inode ratio; if that fails, then of + * the groups with above-average free space, that group with the fewest + * directories already is chosen. + * + * For other inodes, search forward from the parent directory\'s block + * group to find a free inode. + */ +struct inode * ext2_new_inode (const struct inode * dir, int mode) +{ + struct super_block * sb; + struct buffer_head * bh; + struct buffer_head * bh2; + int i, j, avefreei; + struct inode * inode; + int bitmap_nr; + struct ext2_group_desc * gdp; + struct ext2_group_desc * tmp; + struct ext2_super_block * es; + + if (!dir || !(inode = get_empty_inode ())) + return NULL; + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = sb->s_flags; + lock_super (sb); + es = sb->u.ext2_sb.s_es; +repeat: + gdp = NULL; i=0; + + if (S_ISDIR(mode)) { + avefreei = es->s_free_inodes_count / + sb->u.ext2_sb.s_groups_count; +/* I am not yet convinced that this next bit is necessary. + i = dir->u.ext2_i.i_block_group; + for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { + tmp = get_group_desc (sb, i, &bh2); + if ((tmp->bg_used_dirs_count << 8) < + tmp->bg_free_inodes_count) { + gdp = tmp; + break; + } + else + i = ++i % sb->u.ext2_sb.s_groups_count; + } +*/ + if (!gdp) { + for (j = 0; j < sb->u.ext2_sb.s_groups_count; j++) { + tmp = get_group_desc (sb, j, &bh2); + if (tmp->bg_free_inodes_count && + tmp->bg_free_inodes_count >= avefreei) { + if (!gdp || + (tmp->bg_free_blocks_count > + gdp->bg_free_blocks_count)) { + i = j; + gdp = tmp; + } + } + } + } + } + else + { + /* + * Try to place the inode in it's parent directory + */ + i = dir->u.ext2_i.i_block_group; + tmp = get_group_desc (sb, i, &bh2); + if (tmp->bg_free_inodes_count) + gdp = tmp; + else + { + /* + * Use a quadratic hash to find a group with a + * free inode + */ + for (j = 1; j < sb->u.ext2_sb.s_groups_count; j <<= 1) { + i += j; + if (i >= sb->u.ext2_sb.s_groups_count) + i -= sb->u.ext2_sb.s_groups_count; + tmp = get_group_desc (sb, i, &bh2); + if (tmp->bg_free_inodes_count) { + gdp = tmp; + break; + } + } + } + if (!gdp) { + /* + * That failed: try linear search for a free inode + */ + i = dir->u.ext2_i.i_block_group + 1; + for (j = 2; j < sb->u.ext2_sb.s_groups_count; j++) { + if (++i >= sb->u.ext2_sb.s_groups_count) + i = 0; + tmp = get_group_desc (sb, i, &bh2); + if (tmp->bg_free_inodes_count) { + gdp = tmp; + break; + } + } + } + } + + if (!gdp) { + unlock_super (sb); + iput(inode); + return NULL; + } + bitmap_nr = load_inode_bitmap (sb, i); + bh = sb->u.ext2_sb.s_inode_bitmap[bitmap_nr]; + if ((j = find_first_zero_bit ((unsigned long *) bh->b_data, + EXT2_INODES_PER_GROUP(sb))) < + EXT2_INODES_PER_GROUP(sb)) { + if (set_bit (j, bh->b_data)) { + ext2_warning (sb, "ext2_new_inode", + "bit already set for inode %d", j); + goto repeat; + } + bh->b_dirt = 1; + if (sb->s_flags & MS_SYNC) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + } else { + if (gdp->bg_free_inodes_count != 0) { + ext2_error (sb, "ext2_new_inode", + "Free inodes count corrupted in group %d", + i); + unlock_super (sb); + iput (inode); + return NULL; + } + goto repeat; + } + j += i * EXT2_INODES_PER_GROUP(sb) + 1; + if (j < EXT2_FIRST_INO || j > es->s_inodes_count) { + ext2_error (sb, "ext2_new_inode", + "reserved inode or inode > inodes count\n" + "block_group = %d,inode=%d", i, j); + unlock_super (sb); + iput (inode); + return NULL; + } + gdp->bg_free_inodes_count--; + if (S_ISDIR(mode)) + gdp->bg_used_dirs_count++; + bh2->b_dirt = 1; + es->s_free_inodes_count--; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + inode->i_mode = mode; + inode->i_sb = sb; + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->euid; + if (test_opt (sb, GRPID)) + inode->i_gid = dir->i_gid; + else if (dir->i_mode & S_ISGID) { + inode->i_gid = dir->i_gid; + if (S_ISDIR(mode)) + mode |= S_ISGID; + } else + inode->i_gid = current->egid; + inode->i_dirt = 1; + inode->i_ino = j; + inode->i_blksize = sb->s_blocksize; + inode->i_blocks = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->u.ext2_i.i_flags = dir->u.ext2_i.i_flags; + inode->u.ext2_i.i_faddr = 0; + inode->u.ext2_i.i_frag = 0; + inode->u.ext2_i.i_fsize = 0; + inode->u.ext2_i.i_file_acl = 0; + inode->u.ext2_i.i_dir_acl = 0; + inode->u.ext2_i.i_dtime = 0; + inode->u.ext2_i.i_block_group = i; + inode->i_op = NULL; + if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) + inode->i_flags |= MS_SYNC; + insert_inode_hash(inode); + inc_inode_version (inode, gdp, mode); + + ext2_debug ("allocating inode %lu\n", inode->i_ino); + + unlock_super (sb); + return inode; +} + +unsigned long ext2_count_free_inodes (struct super_block * sb) +{ +#ifdef EXT2FS_DEBUG + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); + desc_count += gdp->bg_free_inodes_count; + bitmap_nr = load_inode_bitmap (sb, i); + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], + EXT2_INODES_PER_GROUP(sb) / 8); + printk ("group %d: stored = %d, counted = %lu\n", + i, gdp->bg_free_inodes_count, x); + bitmap_count += x; + } + printk("ext2_count_free_inodes: stored = %lu, computed = %lu, %lu\n", + es->s_free_inodes_count, desc_count, bitmap_count); + unlock_super (sb); + return desc_count; +#else + return sb->u.ext2_sb.s_es->s_free_inodes_count; +#endif +} + +void ext2_check_inodes_bitmap (struct super_block * sb) +{ + struct ext2_super_block * es; + unsigned long desc_count, bitmap_count, x; + int bitmap_nr; + struct ext2_group_desc * gdp; + int i; + + lock_super (sb); + es = sb->u.ext2_sb.s_es; + desc_count = 0; + bitmap_count = 0; + gdp = NULL; + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) { + gdp = get_group_desc (sb, i, NULL); + desc_count += gdp->bg_free_inodes_count; + bitmap_nr = load_inode_bitmap (sb, i); + x = ext2_count_free (sb->u.ext2_sb.s_inode_bitmap[bitmap_nr], + EXT2_INODES_PER_GROUP(sb) / 8); + if (gdp->bg_free_inodes_count != x) + ext2_error (sb, "ext2_check_inodes_bitmap", + "Wrong free inodes count in group %d, " + "stored = %d, counted = %lu", i, + gdp->bg_free_inodes_count, x); + bitmap_count += x; + } + if (es->s_free_inodes_count != bitmap_count) + ext2_error (sb, "ext2_check_inodes_bitmap", + "Wrong free inodes count in super block, " + "stored = %lu, counted = %lu", + es->s_free_inodes_count, bitmap_count); + unlock_super (sb); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/inode.c new file mode 100644 index 000000000..3f0230e63 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/inode.c @@ -0,0 +1,584 @@ +/* + * linux/fs/ext2/inode.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Goal-directed block allocation by Stephen Tweedie (sct@dcs.ed.ac.uk), 1993 + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define clear_block(addr,size) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (0), "c" (size / 4), "D" ((long) (addr)) \ + :"cx", "di") + +void ext2_put_inode (struct inode * inode) +{ + ext2_discard_prealloc (inode); + if (inode->i_nlink || inode->i_ino == EXT2_ACL_IDX_INO || + inode->i_ino == EXT2_ACL_DATA_INO) + return; + inode->i_size = 0; + if (inode->i_blocks) + ext2_truncate (inode); + ext2_free_inode (inode); +} + +#define inode_bmap(inode, nr) ((inode)->u.ext2_i.i_data[(nr)]) + +static int block_bmap (struct buffer_head * bh, int nr) +{ + int tmp; + + if (!bh) + return 0; + tmp = ((unsigned long *) bh->b_data)[nr]; + brelse (bh); + return tmp; +} + +/* + * ext2_discard_prealloc and ext2_alloc_block are atomic wrt. the + * superblock in the same manner as are ext2_free_blocks and + * ext2_new_block. We just wait on the super rather than locking it + * here, since ext2_new_block will do the necessary locking and we + * can't block until then. + */ +void ext2_discard_prealloc (struct inode * inode) +{ +#ifdef EXT2_PREALLOCATE + if (inode->u.ext2_i.i_prealloc_count) { + ext2_free_blocks (inode->i_sb, + inode->u.ext2_i.i_prealloc_block, + inode->u.ext2_i.i_prealloc_count); + inode->u.ext2_i.i_prealloc_count = 0; + } +#endif +} + +static int ext2_alloc_block (struct inode * inode, unsigned long goal) +{ +#ifdef EXT2FS_DEBUG + static unsigned long alloc_hits = 0, alloc_attempts = 0; +#endif + unsigned long result; + struct buffer_head * bh; + + wait_on_super (inode->i_sb); + +#ifdef EXT2_PREALLOCATE + if (inode->u.ext2_i.i_prealloc_count && + (goal == inode->u.ext2_i.i_prealloc_block || + goal + 1 == inode->u.ext2_i.i_prealloc_block)) + { + result = inode->u.ext2_i.i_prealloc_block++; + inode->u.ext2_i.i_prealloc_count--; + ext2_debug ("preallocation hit (%lu/%lu).\n", + ++alloc_hits, ++alloc_attempts); + + /* It doesn't matter if we block in getblk() since + we have already atomically allocated the block, and + are only clearing it now. */ + if (!(bh = getblk (inode->i_sb->s_dev, result, + inode->i_sb->s_blocksize))) { + ext2_error (inode->i_sb, "ext2_alloc_block", + "cannot get block %lu", result); + return 0; + } + clear_block (bh->b_data, inode->i_sb->s_blocksize); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse (bh); + } else { + ext2_discard_prealloc (inode); + ext2_debug ("preallocation miss (%lu/%lu).\n", + alloc_hits, ++alloc_attempts); + if (S_ISREG(inode->i_mode)) + result = ext2_new_block + (inode->i_sb, goal, + &inode->u.ext2_i.i_prealloc_count, + &inode->u.ext2_i.i_prealloc_block); + else + result = ext2_new_block (inode->i_sb, goal, 0, 0); + } +#else + result = ext2_new_block (inode->i_sb, goal, 0, 0); +#endif + + return result; +} + + +int ext2_bmap (struct inode * inode, int block) +{ + int i; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + + if (block < 0) { + ext2_warning (inode->i_sb, "ext2_bmap", "block < 0"); + return 0; + } + if (block >= EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) { + ext2_warning (inode->i_sb, "ext2_bmap", "block > big"); + return 0; + } + if (block < EXT2_NDIR_BLOCKS) + return inode_bmap (inode, block); + block -= EXT2_NDIR_BLOCKS; + if (block < addr_per_block) { + i = inode_bmap (inode, EXT2_IND_BLOCK); + if (!i) + return 0; + return block_bmap (bread (inode->i_dev, i, + inode->i_sb->s_blocksize), block); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + i = inode_bmap (inode, EXT2_DIND_BLOCK); + if (!i) + return 0; + i = block_bmap (bread (inode->i_dev, i, + inode->i_sb->s_blocksize), + block / addr_per_block); + if (!i) + return 0; + return block_bmap (bread (inode->i_dev, i, + inode->i_sb->s_blocksize), + block & (addr_per_block - 1)); + } + block -= addr_per_block * addr_per_block; + i = inode_bmap (inode, EXT2_TIND_BLOCK); + if (!i) + return 0; + i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), + block / (addr_per_block * addr_per_block)); + if (!i) + return 0; + i = block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), + (block / addr_per_block) & (addr_per_block - 1)); + if (!i) + return 0; + return block_bmap (bread (inode->i_dev, i, inode->i_sb->s_blocksize), + block & (addr_per_block - 1)); +} + +static struct buffer_head * inode_getblk (struct inode * inode, int nr, + int create, int new_block, int * err) +{ + int tmp, goal = 0; + unsigned long * p; + struct buffer_head * result; + int blocks = inode->i_sb->s_blocksize / 512; + + p = inode->u.ext2_i.i_data + nr; +repeat: + tmp = *p; + if (tmp) { + result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp == *p) + return result; + brelse (result); + goto repeat; + } + if (!create || new_block >= + (current->rlim[RLIMIT_FSIZE].rlim_cur >> + EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { + *err = -EFBIG; + return NULL; + } + if (inode->u.ext2_i.i_next_alloc_block == new_block) + goal = inode->u.ext2_i.i_next_alloc_goal; + + ext2_debug ("hint = %d,", goal); + + if (!goal) { + for (tmp = nr - 1; tmp >= 0; tmp--) { + if (inode->u.ext2_i.i_data[tmp]) { + goal = inode->u.ext2_i.i_data[tmp]; + break; + } + } + if (!goal) + goal = (inode->u.ext2_i.i_block_group * + EXT2_BLOCKS_PER_GROUP(inode->i_sb)) + + inode->i_sb->u.ext2_sb.s_es->s_first_data_block; + } + + ext2_debug ("goal = %d.\n", goal); + + tmp = ext2_alloc_block (inode, goal); + if (!tmp) + return NULL; + result = getblk (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (*p) { + ext2_free_blocks (inode->i_sb, tmp, 1); + brelse (result); + goto repeat; + } + *p = tmp; + inode->u.ext2_i.i_next_alloc_block = new_block; + inode->u.ext2_i.i_next_alloc_goal = tmp; + inode->i_ctime = CURRENT_TIME; + inode->i_blocks += blocks; + if (IS_SYNC(inode)) + ext2_sync_inode (inode); + else + inode->i_dirt = 1; + return result; +} + +static struct buffer_head * block_getblk (struct inode * inode, + struct buffer_head * bh, int nr, + int create, int blocksize, + int new_block, int * err) +{ + int tmp, goal = 0; + unsigned long * p; + struct buffer_head * result; + int blocks = inode->i_sb->s_blocksize / 512; + + if (!bh) + return NULL; + if (!bh->b_uptodate) { + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (!bh->b_uptodate) { + brelse (bh); + return NULL; + } + } + p = (unsigned long *) bh->b_data + nr; +repeat: + tmp = *p; + if (tmp) { + result = getblk (bh->b_dev, tmp, blocksize); + if (tmp == *p) { + brelse (bh); + return result; + } + brelse (result); + goto repeat; + } + if (!create || new_block >= + (current->rlim[RLIMIT_FSIZE].rlim_cur >> + EXT2_BLOCK_SIZE_BITS(inode->i_sb))) { + brelse (bh); + *err = -EFBIG; + return NULL; + } + if (inode->u.ext2_i.i_next_alloc_block == new_block) + goal = inode->u.ext2_i.i_next_alloc_goal; + if (!goal) { + for (tmp = nr - 1; tmp >= 0; tmp--) { + if (((unsigned long *) bh->b_data)[tmp]) { + goal = ((unsigned long *)bh->b_data)[tmp]; + break; + } + } + if (!goal) + goal = bh->b_blocknr; + } + tmp = ext2_alloc_block (inode, goal); + if (!tmp) { + brelse (bh); + return NULL; + } + result = getblk (bh->b_dev, tmp, blocksize); + if (*p) { + ext2_free_blocks (inode->i_sb, tmp, 1); + brelse (result); + goto repeat; + } + *p = tmp; + bh->b_dirt = 1; + if (IS_SYNC(inode)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + inode->i_ctime = CURRENT_TIME; + inode->i_blocks += blocks; + inode->i_dirt = 1; + inode->u.ext2_i.i_next_alloc_block = new_block; + inode->u.ext2_i.i_next_alloc_goal = tmp; + brelse (bh); + return result; +} + +struct buffer_head * ext2_getblk (struct inode * inode, long block, + int create, int * err) +{ + struct buffer_head * bh; + unsigned long b; + unsigned long addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + + *err = -EIO; + if (block < 0) { + ext2_warning (inode->i_sb, "ext2_getblk", "block < 0"); + return NULL; + } + if (block > EXT2_NDIR_BLOCKS + addr_per_block + + addr_per_block * addr_per_block + + addr_per_block * addr_per_block * addr_per_block) { + ext2_warning (inode->i_sb, "ext2_getblk", "block > big"); + return NULL; + } + /* + * If this is a sequential block allocation, set the next_alloc_block + * to this block now so that all the indblock and data block + * allocations use the same goal zone + */ + + ext2_debug ("block %lu, next %lu, goal %lu.\n", block, + inode->u.ext2_i.i_next_alloc_block, + inode->u.ext2_i.i_next_alloc_goal); + + if (block == inode->u.ext2_i.i_next_alloc_block + 1) { + inode->u.ext2_i.i_next_alloc_block++; + inode->u.ext2_i.i_next_alloc_goal++; + } + + *err = -ENOSPC; + b = block; + if (block < EXT2_NDIR_BLOCKS) + return inode_getblk (inode, block, create, b, err); + block -= EXT2_NDIR_BLOCKS; + if (block < addr_per_block) { + bh = inode_getblk (inode, EXT2_IND_BLOCK, create, b, err); + return block_getblk (inode, bh, block, create, + inode->i_sb->s_blocksize, b, err); + } + block -= addr_per_block; + if (block < addr_per_block * addr_per_block) { + bh = inode_getblk (inode, EXT2_DIND_BLOCK, create, b, err); + bh = block_getblk (inode, bh, block / addr_per_block, create, + inode->i_sb->s_blocksize, b, err); + return block_getblk (inode, bh, block & (addr_per_block - 1), + create, inode->i_sb->s_blocksize, b, err); + } + block -= addr_per_block * addr_per_block; + bh = inode_getblk (inode, EXT2_TIND_BLOCK, create, b, err); + bh = block_getblk (inode, bh, block/(addr_per_block * addr_per_block), + create, inode->i_sb->s_blocksize, b, err); + bh = block_getblk (inode, bh, (block/addr_per_block) & (addr_per_block - 1), + create, inode->i_sb->s_blocksize, b, err); + return block_getblk (inode, bh, block & (addr_per_block - 1), create, + inode->i_sb->s_blocksize, b, err); +} + +struct buffer_head * ext2_bread (struct inode * inode, int block, + int create, int *err) +{ + struct buffer_head * bh; + + bh = ext2_getblk (inode, block, create, err); + if (!bh || bh->b_uptodate) + return bh; + ll_rw_block (READ, 1, &bh); + wait_on_buffer (bh); + if (bh->b_uptodate) + return bh; + brelse (bh); + *err = -EIO; + return NULL; +} + +void ext2_read_inode (struct inode * inode) +{ + struct buffer_head * bh; + struct ext2_inode * raw_inode; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long block; + struct ext2_group_desc * gdp; + + if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino != EXT2_ACL_IDX_INO && + inode->i_ino != EXT2_ACL_DATA_INO && inode->i_ino < EXT2_FIRST_INO) || + inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (inode->i_sb, "ext2_read_inode", + "bad inode number: %lu", inode->i_ino); + return; + } + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) + ext2_panic (inode->i_sb, "ext2_read_inode", + "group >= groups count"); + group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb); + desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb); + bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; + if (!bh) + ext2_panic (inode->i_sb, "ext2_read_inode", + "Descriptor not loaded"); + gdp = (struct ext2_group_desc *) bh->b_data; + block = gdp[desc].bg_inode_table + + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) + / EXT2_INODES_PER_BLOCK(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) + ext2_panic (inode->i_sb, "ext2_read_inode", + "unable to read i-node block\n" + "inode=%lu, block=%lu", inode->i_ino, block); + raw_inode = ((struct ext2_inode *) bh->b_data) + + (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb); + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_links_count; + inode->i_size = raw_inode->i_size; + inode->i_atime = raw_inode->i_atime; + inode->i_ctime = raw_inode->i_ctime; + inode->i_mtime = raw_inode->i_mtime; + inode->u.ext2_i.i_dtime = raw_inode->i_dtime; + inode->i_blksize = inode->i_sb->s_blocksize; + inode->i_blocks = raw_inode->i_blocks; + inode->u.ext2_i.i_flags = raw_inode->i_flags; + inode->u.ext2_i.i_faddr = raw_inode->i_faddr; + inode->u.ext2_i.i_frag = raw_inode->i_frag; + inode->u.ext2_i.i_fsize = raw_inode->i_fsize; + inode->u.ext2_i.i_file_acl = raw_inode->i_file_acl; + inode->u.ext2_i.i_dir_acl = raw_inode->i_dir_acl; + inode->u.ext2_i.i_version = raw_inode->i_version; + inode->u.ext2_i.i_block_group = block_group; + inode->u.ext2_i.i_next_alloc_block = 0; + inode->u.ext2_i.i_next_alloc_goal = 0; + if (inode->u.ext2_i.i_prealloc_count) + ext2_error (inode->i_sb, "ext2_read_inode", + "New inode has non-zero prealloc count!"); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = raw_inode->i_block[0]; + else for (block = 0; block < EXT2_N_BLOCKS; block++) + inode->u.ext2_i.i_data[block] = raw_inode->i_block[block]; + brelse (bh); + inode->i_op = NULL; + if (inode->i_ino == EXT2_ACL_IDX_INO || + inode->i_ino == EXT2_ACL_DATA_INO) + /* Nothing to do */ ; + else if (S_ISREG(inode->i_mode)) + inode->i_op = &ext2_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &ext2_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ext2_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (inode->u.ext2_i.i_flags & EXT2_SYNC_FL) + inode->i_flags |= MS_SYNC; +} + +static struct buffer_head * ext2_update_inode (struct inode * inode) +{ + struct buffer_head * bh; + struct ext2_inode * raw_inode; + unsigned long block_group; + unsigned long group_desc; + unsigned long desc; + unsigned long block; + struct ext2_group_desc * gdp; + + if ((inode->i_ino != EXT2_ROOT_INO && inode->i_ino < EXT2_FIRST_INO) || + inode->i_ino > inode->i_sb->u.ext2_sb.s_es->s_inodes_count) { + ext2_error (inode->i_sb, "ext2_write_inode", + "bad inode number: %lu", inode->i_ino); + return 0; + } + block_group = (inode->i_ino - 1) / EXT2_INODES_PER_GROUP(inode->i_sb); + if (block_group >= inode->i_sb->u.ext2_sb.s_groups_count) + ext2_panic (inode->i_sb, "ext2_write_inode", + "group >= groups count"); + group_desc = block_group / EXT2_DESC_PER_BLOCK(inode->i_sb); + desc = block_group % EXT2_DESC_PER_BLOCK(inode->i_sb); + bh = inode->i_sb->u.ext2_sb.s_group_desc[group_desc]; + if (!bh) + ext2_panic (inode->i_sb, "ext2_write_inode", + "Descriptor not loaded"); + gdp = (struct ext2_group_desc *) bh->b_data; + block = gdp[desc].bg_inode_table + + (((inode->i_ino - 1) % EXT2_INODES_PER_GROUP(inode->i_sb)) + / EXT2_INODES_PER_BLOCK(inode->i_sb)); + if (!(bh = bread (inode->i_dev, block, inode->i_sb->s_blocksize))) + ext2_panic (inode->i_sb, "ext2_write_inode", + "unable to read i-node block\n" + "inode=%lu, block=%lu", inode->i_ino, block); + raw_inode = ((struct ext2_inode *)bh->b_data) + + (inode->i_ino - 1) % EXT2_INODES_PER_BLOCK(inode->i_sb); + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_links_count = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_atime = inode->i_atime; + raw_inode->i_ctime = inode->i_ctime; + raw_inode->i_mtime = inode->i_mtime; + raw_inode->i_blocks = inode->i_blocks; + raw_inode->i_dtime = inode->u.ext2_i.i_dtime; + raw_inode->i_flags = inode->u.ext2_i.i_flags; + raw_inode->i_faddr = inode->u.ext2_i.i_faddr; + raw_inode->i_frag = inode->u.ext2_i.i_frag; + raw_inode->i_fsize = inode->u.ext2_i.i_fsize; + raw_inode->i_file_acl = inode->u.ext2_i.i_file_acl; + raw_inode->i_dir_acl = inode->u.ext2_i.i_dir_acl; + raw_inode->i_version = inode->u.ext2_i.i_version; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_block[0] = inode->i_rdev; + else for (block = 0; block < EXT2_N_BLOCKS; block++) + raw_inode->i_block[block] = inode->u.ext2_i.i_data[block]; + bh->b_dirt = 1; + inode->i_dirt = 0; + return bh; +} + +void ext2_write_inode (struct inode * inode) +{ + struct buffer_head * bh; + bh = ext2_update_inode (inode); + brelse (bh); +} + +int ext2_sync_inode (struct inode *inode) +{ + int err = 0; + struct buffer_head *bh; + + bh = ext2_update_inode (inode); + if (bh && bh->b_dirt) + { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + if (bh->b_req && !bh->b_uptodate) + { + printk ("IO error syncing ext2 inode [%04x:%08lx]\n", + inode->i_dev, inode->i_ino); + err = -1; + } + } + else if (!bh) + err = -1; + brelse (bh); + return err; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ioctl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ioctl.c new file mode 100644 index 000000000..8c103ae4c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/ioctl.c @@ -0,0 +1,51 @@ +/* + * linux/fs/ext2/ioctl.c + * + * Copyright (C) 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + */ + +#include + +#include +#include +#include +#include +#include + +int ext2_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, + unsigned long arg) +{ + + ext2_debug ("cmd = %u, arg = %lu\n", cmd, arg); + + switch (cmd) { + case EXT2_IOC_GETFLAGS: + put_fs_long (inode->u.ext2_i.i_flags, (long *) arg); + return 0; + case EXT2_IOC_SETFLAGS: + if ((current->euid != inode->i_uid) && !suser()) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + inode->u.ext2_i.i_flags = get_fs_long ((long *) arg); + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return 0; + case EXT2_IOC_GETVERSION: + put_fs_long (inode->u.ext2_i.i_version, (long *) arg); + return 0; + case EXT2_IOC_SETVERSION: + if ((current->euid != inode->i_uid) && !suser()) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + inode->u.ext2_i.i_version = get_fs_long ((long *) arg); + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return 0; + default: + return -EINVAL; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/namei.c new file mode 100644 index 000000000..d5a47b2a9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/namei.c @@ -0,0 +1,1120 @@ +/* + * linux/fs/ext2/namei.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * comment out this line if you want names > EXT2_NAME_LEN chars to be + * truncated. Else they will be disallowed. + */ +/* #define NO_TRUNCATE */ + +/* + * define how far ahead to read directories while searching them. + */ +#define NAMEI_RA_CHUNKS 2 +#define NAMEI_RA_BLOCKS 4 +#define NAMEI_RA_SIZE (NAMEI_RA_CHUNKS * NAMEI_RA_BLOCKS) +#define NAMEI_RA_INDEX(c,b) (((c) * NAMEI_RA_BLOCKS) + (b)) + +/* + * NOTE! unlike strncmp, ext2_match returns 1 for success, 0 for failure. + */ +static int ext2_match (int len, const char * const name, + struct ext2_dir_entry * de) +{ + unsigned char same; + + if (!de || !de->inode || len > EXT2_NAME_LEN) + return 0; + /* + * "" means "." ---> so paths like "/usr/lib//libc.a" work + */ + if (!len && de->name_len == 1 && (de->name[0] == '.') && + (de->name[1] == '\0')) + return 1; + if (len != de->name_len) + return 0; + __asm__("cld\n\t" + "repe ; cmpsb\n\t" + "setz %0" + :"=q" (same) + :"S" ((long) name), "D" ((long) de->name), "c" (len) + :"cx", "di", "si"); + return (int) same; +} + +/* + * ext2_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * ext2_find_entry (struct inode * dir, + const char * const name, int namelen, + struct ext2_dir_entry ** res_dir) +{ + struct super_block * sb; + struct buffer_head * bh_use[NAMEI_RA_SIZE]; + struct buffer_head * bh_read[NAMEI_RA_SIZE]; + unsigned long offset; + int block, toread, i, err; + + *res_dir = NULL; + if (!dir) + return NULL; + sb = dir->i_sb; + +#ifdef NO_TRUNCATE + if (namelen > EXT2_NAME_LEN) + return NULL; +#else + if (namelen > EXT2_NAME_LEN) + namelen = EXT2_NAME_LEN; +#endif + + memset (bh_use, 0, sizeof (bh_use)); + toread = 0; + for (block = 0; block < NAMEI_RA_SIZE; ++block) { + struct buffer_head * bh; + + if ((block << EXT2_BLOCK_SIZE_BITS (sb)) >= dir->i_size) + break; + bh = ext2_getblk (dir, block, 0, &err); + bh_use[block] = bh; + if (bh && !bh->b_uptodate) + bh_read[toread++] = bh; + } + + block = 0; + offset = 0; + while (offset < dir->i_size) { + struct buffer_head * bh; + struct ext2_dir_entry * de; + char * dlimit; + + if ((block % NAMEI_RA_BLOCKS) == 0 && toread) { + ll_rw_block (READ, toread, bh_read); + toread = 0; + } + bh = bh_use[block % NAMEI_RA_SIZE]; + if (!bh) + ext2_panic (sb, "ext2_find_entry", + "buffer head pointer is NULL"); + wait_on_buffer (bh); + if (!bh->b_uptodate) { + /* + * read error: all bets are off + */ + break; + } + + de = (struct ext2_dir_entry *) bh->b_data; + dlimit = bh->b_data + sb->s_blocksize; + while ((char *) de < dlimit) { + if (!ext2_check_dir_entry ("ext2_find_entry", dir, + de, bh, offset)) + goto failure; + if (de->inode != 0 && ext2_match (namelen, name, de)) { + for (i = 0; i < NAMEI_RA_SIZE; ++i) { + if (bh_use[i] != bh) + brelse (bh_use[i]); + } + *res_dir = de; + return bh; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) + ((char *) de + de->rec_len); + } + + brelse (bh); + if (((block + NAMEI_RA_SIZE) << EXT2_BLOCK_SIZE_BITS (sb)) >= + dir->i_size) + bh = NULL; + else + bh = ext2_getblk (dir, block + NAMEI_RA_SIZE, 0, &err); + bh_use[block++ % NAMEI_RA_SIZE] = bh; + if (bh && !bh->b_uptodate) + bh_read[toread++] = bh; + } + +failure: + for (i = 0; i < NAMEI_RA_SIZE; ++i) + brelse (bh_use[i]); + return NULL; +} + +int ext2_lookup (struct inode * dir, const char * name, int len, + struct inode ** result) +{ + unsigned long ino; + struct ext2_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput (dir); + return -ENOENT; + } +#ifndef DONT_USE_DCACHE + if (!(ino = ext2_dcache_lookup (dir->i_dev, dir->i_ino, name, len))) { +#endif + if (!(bh = ext2_find_entry (dir, name, len, &de))) { + iput (dir); + return -ENOENT; + } + ino = de->inode; +#ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, + de->name_len, ino); +#endif + brelse (bh); +#ifndef DONT_USE_DCACHE + } +#endif + if (!(*result = iget (dir->i_sb, ino))) { + iput (dir); + return -EACCES; + } + iput (dir); + return 0; +} + +/* + * ext2_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as ext2_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * ext2_add_entry (struct inode * dir, + const char * name, int namelen, + struct ext2_dir_entry ** res_dir, + int *err) +{ + unsigned long offset; + unsigned short rec_len; + struct buffer_head * bh; + struct ext2_dir_entry * de, * de1; + struct super_block * sb; + + *err = -EINVAL; + *res_dir = NULL; + if (!dir) + return NULL; + sb = dir->i_sb; +#ifdef NO_TRUNCATE + if (namelen > EXT2_NAME_LEN) + return NULL; +#else + if (namelen > EXT2_NAME_LEN) + namelen = EXT2_NAME_LEN; +#endif + if (!namelen) + return NULL; + /* + * Is this a busy deleted directory? Can't create new files if so + */ + if (dir->i_size == 0) + { + *err = -ENOENT; + return NULL; + } + bh = ext2_bread (dir, 0, 0, err); + if (!bh) + return NULL; + rec_len = EXT2_DIR_REC_LEN(namelen); + offset = 0; + de = (struct ext2_dir_entry *) bh->b_data; + *err = -ENOSPC; + while (1) { + if ((char *)de >= sb->s_blocksize + bh->b_data) { + brelse (bh); + bh = NULL; + bh = ext2_bread (dir, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, err); + if (!bh) + return NULL; + if (dir->i_size <= offset) { + if (dir->i_size == 0) { + *err = -ENOENT; + return NULL; + } + + ext2_debug ("creating next block\n"); + + de = (struct ext2_dir_entry *) bh->b_data; + de->inode = 0; + de->rec_len = sb->s_blocksize; + dir->i_size = offset + sb->s_blocksize; + dir->i_dirt = 1; +#if 0 /* XXX don't update any times until successful completion of syscall */ + dir->i_ctime = CURRENT_TIME; +#endif + } else { + + ext2_debug ("skipping to next block\n"); + + de = (struct ext2_dir_entry *) bh->b_data; + } + } + if (!ext2_check_dir_entry ("ext2_add_entry", dir, de, bh, + offset)) { + *err = -ENOENT; + brelse (bh); + return NULL; + } + if (de->inode != 0 && ext2_match (namelen, name, de)) { + *err = -EEXIST; + brelse (bh); + return NULL; + } + if ((de->inode == 0 && de->rec_len >= rec_len) || + (de->rec_len >= EXT2_DIR_REC_LEN(de->name_len) + rec_len)) { + offset += de->rec_len; + if (de->inode) { + de1 = (struct ext2_dir_entry *) ((char *) de + + EXT2_DIR_REC_LEN(de->name_len)); + de1->rec_len = de->rec_len - + EXT2_DIR_REC_LEN(de->name_len); + de->rec_len = EXT2_DIR_REC_LEN(de->name_len); + de = de1; + } + de->inode = 0; + de->name_len = namelen; + memcpy (de->name, name, namelen); + /* + * XXX shouldn't update any times until successful + * completion of syscall, but too many callers depend + * on this. + * + * XXX similarly, too many callers depend on + * ext2_new_inode() setting the times, but error + * recovery deletes the inode, so the worst that can + * happen is that the times are slightly out of date + * and/or different from the directory change time. + */ + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + dir->i_dirt = 1; + bh->b_dirt = 1; + *res_dir = de; + *err = 0; + return bh; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + brelse (bh); + return NULL; +} + +/* + * ext2_delete_entry deletes a directory entry by merging it with the + * previous entry + */ +static int ext2_delete_entry (struct ext2_dir_entry * dir, + struct buffer_head * bh) +{ + struct ext2_dir_entry * de, * pde; + int i; + + i = 0; + pde = NULL; + de = (struct ext2_dir_entry *) bh->b_data; + while (i < bh->b_size) { + if (!ext2_check_dir_entry ("ext2_delete_entry", NULL, + de, bh, i)) + return -EIO; + if (de == dir) { + if (pde) + pde->rec_len += dir->rec_len; + dir->inode = 0; + return 0; + } + i += de->rec_len; + pde = de; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + return -ENOENT; +} + +int ext2_create (struct inode * dir,const char * name, int len, int mode, + struct inode ** result) +{ + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + int err; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = ext2_new_inode (dir, mode); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_op = &ext2_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + iput (dir); + return err; + } + de->inode = inode->i_ino; +#ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); +#endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + *result = inode; + return 0; +} + +int ext2_mknod (struct inode * dir, const char * name, int len, int mode, + int rdev) +{ + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + int err; + + if (!dir) + return -ENOENT; + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + brelse (bh); + iput (dir); + return -EEXIST; + } + inode = ext2_new_inode (dir, mode); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &ext2_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &ext2_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &ext2_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; +#if 0 + /* + * XXX we may as well use the times set by ext2_new_inode(). The + * following usually does nothing, but sometimes it invalidates + * inode->i_ctime. + */ + inode->i_mtime = inode->i_atime = CURRENT_TIME; +#endif + inode->i_dirt = 1; + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + iput (dir); + return err; + } + de->inode = inode->i_ino; +#ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); +#endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + iput (inode); + return 0; +} + +int ext2_mkdir (struct inode * dir, const char * name, int len, int mode) +{ + struct inode * inode; + struct buffer_head * bh, * dir_block; + struct ext2_dir_entry * de; + int err; + + if (!dir) + return -ENOENT; + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + brelse (bh); + iput (dir); + return -EEXIST; + } + if (dir->i_nlink >= EXT2_LINK_MAX) { + iput (dir); + return -EMLINK; + } + inode = ext2_new_inode (dir, S_IFDIR); + if (!inode) { + iput (dir); + return -ENOSPC; + } + inode->i_op = &ext2_dir_inode_operations; + inode->i_size = inode->i_sb->s_blocksize; +#if 0 /* XXX as above */ + inode->i_mtime = inode->i_atime = CURRENT_TIME; +#endif + dir_block = ext2_bread (inode, 0, 1, &err); + if (!dir_block) { + iput (dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + return err; + } + inode->i_blocks = inode->i_sb->s_blocksize / 512; + de = (struct ext2_dir_entry *) dir_block->b_data; + de->inode = inode->i_ino; + de->name_len = 1; + de->rec_len = EXT2_DIR_REC_LEN(de->name_len); + strcpy (de->name, "."); + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + de->inode = dir->i_ino; + de->rec_len = inode->i_sb->s_blocksize - EXT2_DIR_REC_LEN(1); + de->name_len = 2; + strcpy (de->name, ".."); + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse (dir_block); + inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + inode->i_dirt = 1; + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + iput (dir); + inode->i_nlink = 0; + inode->i_dirt = 1; + iput (inode); + return err; + } + de->inode = inode->i_ino; +#ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); +#endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + dir->i_nlink++; + dir->i_dirt = 1; + iput (dir); + iput (inode); + brelse (bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir (struct inode * inode) +{ + unsigned long offset; + struct buffer_head * bh; + struct ext2_dir_entry * de, * de1; + struct super_block * sb; + int err; + + sb = inode->i_sb; + if (inode->i_size < EXT2_DIR_REC_LEN(1) + EXT2_DIR_REC_LEN(2) || + !(bh = ext2_bread (inode, 0, 0, &err))) { + ext2_warning (inode->i_sb, "empty_dir", + "bad directory (dir %lu)", inode->i_ino); + return 1; + } + de = (struct ext2_dir_entry *) bh->b_data; + de1 = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + if (de->inode != inode->i_ino || !de1->inode || + strcmp (".", de->name) || strcmp ("..", de1->name)) { + ext2_warning (inode->i_sb, "empty_dir", + "bad directory (dir %lu)", inode->i_ino); + return 1; + } + offset = de->rec_len + de1->rec_len; + de = (struct ext2_dir_entry *) ((char *) de1 + de1->rec_len); + while (offset < inode->i_size ) { + if ((void *) de >= (void *) (bh->b_data + sb->s_blocksize)) { + brelse (bh); + bh = ext2_bread (inode, offset >> EXT2_BLOCK_SIZE_BITS(sb), 1, &err); + if (!bh) { + offset += sb->s_blocksize; + continue; + } + de = (struct ext2_dir_entry *) bh->b_data; + } + if (!ext2_check_dir_entry ("empty_dir", inode, de, bh, + offset)) { + brelse (bh); + return 1; + } + if (de->inode) { + brelse (bh); + return 0; + } + offset += de->rec_len; + de = (struct ext2_dir_entry *) ((char *) de + de->rec_len); + } + brelse (bh); + return 1; +} + +int ext2_rmdir (struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + +repeat: + if (!dir) + return -ENOENT; + inode = NULL; + bh = ext2_find_entry (dir, name, len, &de); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget (dir->i_sb, de->inode))) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir (inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (de->inode != inode->i_ino) { + retval = -ENOENT; + goto end_rmdir; + } + if (inode->i_count > 1) { + /* + * Are we deleting the last instance of a busy directory? + * Better clean up if so. + * + * Make directory empty (it will be truncated when finally + * dereferenced). This also inhibits ext2_add_entry. + */ + inode->i_size = 0; + } + retval = ext2_delete_entry (de, bh); + if (retval) + goto end_rmdir; + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } +#ifndef DONT_USE_DCACHE + ext2_dcache_remove(inode->i_dev, inode->i_ino, ".", 1); + ext2_dcache_remove(inode->i_dev, inode->i_ino, "..", 2); +#endif + if (inode->i_nlink != 2) + ext2_warning (inode->i_sb, "ext2_rmdir", + "empty directory has nlink!=2 (%d)", + inode->i_nlink); +#ifndef DONT_USE_DCACHE + ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len); +#endif + inode->i_nlink = 0; + inode->i_dirt = 1; + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; +end_rmdir: + iput (dir); + iput (inode); + brelse (bh); + return retval; +} + +int ext2_unlink (struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct ext2_dir_entry * de; + +repeat: + if (!dir) + return -ENOENT; + retval = -ENOENT; + inode = NULL; + bh = ext2_find_entry (dir, name, len, &de); + if (!bh) + goto end_unlink; + if (!(inode = iget (dir->i_sb, de->inode))) + goto end_unlink; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (!inode->i_nlink) { + ext2_warning (inode->i_sb, "ext2_unlink", + "Deleting nonexistent file (%lu), %d", + inode->i_ino, inode->i_nlink); + inode->i_nlink = 1; + } + retval = ext2_delete_entry (de, bh); + if (retval) + goto end_unlink; + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } +#ifndef DONT_USE_DCACHE + ext2_dcache_remove (dir->i_dev, dir->i_ino, de->name, de->name_len); +#endif + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + inode->i_ctime = dir->i_ctime; + retval = 0; +end_unlink: + brelse (bh); + iput (inode); + iput (dir); + return retval; +} + +int ext2_symlink (struct inode * dir, const char * name, int len, + const char * symname) +{ + struct ext2_dir_entry * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + char * link; + int i, err; + int l; + char c; + + if (!(inode = ext2_new_inode (dir, S_IFLNK))) { + iput (dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_op = &ext2_symlink_inode_operations; + for (l = 0; l < inode->i_sb->s_blocksize - 1 && + symname [l]; l++) + ; + if (l >= EXT2_N_BLOCKS * sizeof (unsigned long)) { + + ext2_debug ("l=%d, normal symlink\n", l); + + name_block = ext2_bread (inode, 0, 1, &err); + if (!name_block) { + iput (dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + return err; + } + link = name_block->b_data; + } else { + link = (char *) inode->u.ext2_i.i_data; + + ext2_debug ("l=%d, fast symlink\n", l); + + } + i = 0; + while (i < inode->i_sb->s_blocksize - 1 && (c = *(symname++))) + link[i++] = c; + link[i] = 0; + if (name_block) { + name_block->b_dirt = 1; + brelse (name_block); + } + inode->i_size = i; + inode->i_dirt = 1; + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + brelse (bh); + iput (dir); + return -EEXIST; + } + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput (inode); + iput (dir); + return err; + } + de->inode = inode->i_ino; +#ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); +#endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + iput (inode); + return 0; +} + +int ext2_link (struct inode * oldinode, struct inode * dir, + const char * name, int len) +{ + struct ext2_dir_entry * de; + struct buffer_head * bh; + int err; + + if (S_ISDIR(oldinode->i_mode)) { + iput (oldinode); + iput (dir); + return -EPERM; + } + if (oldinode->i_nlink >= EXT2_LINK_MAX) { + iput (oldinode); + iput (dir); + return -EMLINK; + } + bh = ext2_find_entry (dir, name, len, &de); + if (bh) { + brelse (bh); + iput (dir); + iput (oldinode); + return -EEXIST; + } + bh = ext2_add_entry (dir, name, len, &de, &err); + if (!bh) { + iput (dir); + iput (oldinode); + return err; + } + de->inode = oldinode->i_ino; +#ifndef DONT_USE_DCACHE + ext2_dcache_add (dir->i_dev, dir->i_ino, de->name, de->name_len, + de->inode); +#endif + bh->b_dirt = 1; + if (IS_SYNC(dir)) { + ll_rw_block (WRITE, 1, &bh); + wait_on_buffer (bh); + } + brelse (bh); + iput (dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput (oldinode); + return 0; +} + +static int subdir (struct inode * new_inode, struct inode * old_inode) +{ + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (ext2_lookup (new_inode, "..", 2, &new_inode)) + break; + if (new_inode->i_ino == ino) + break; + } + iput (new_inode); + return result; +} + +#define PARENT_INO(buffer) \ + ((struct ext2_dir_entry *) ((char *) buffer + \ + ((struct ext2_dir_entry *) buffer)->rec_len))->inode + +#define PARENT_NAME(buffer) \ + ((struct ext2_dir_entry *) ((char *) buffer + \ + ((struct ext2_dir_entry *) buffer)->rec_len))->name + +/* + * rename uses retrying to avoid race-conditions: at least they should be + * minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_ext2_rename (struct inode * old_dir, const char * old_name, + int old_len, struct inode * new_dir, + const char * new_name, int new_len) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct ext2_dir_entry * old_de, * new_de; + int retval; + + goto start_up; +try_again: + if (new_bh && new_de) + ext2_delete_entry(new_de, new_bh); + brelse (old_bh); + brelse (new_bh); + brelse (dir_bh); + iput (old_inode); + iput (new_inode); + current->counter = 0; + schedule (); +start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + new_de = NULL; + old_bh = ext2_find_entry (old_dir, old_name, old_len, &old_de); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = __iget (old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ + if (!old_inode) + goto end_rename; + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = ext2_find_entry (new_dir, new_name, new_len, &new_de); + if (new_bh) { + new_inode = __iget (new_dir->i_sb, new_de->inode, 0); /* no mntp cross */ + if (!new_inode) { + brelse (new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir (new_dir, old_inode)) + goto end_rename; + retval = -ENOTEMPTY; + if (!empty_dir (new_inode)) + goto end_rename; + retval = -EBUSY; + if (new_inode->i_count > 1) + goto end_rename; + } + retval = -EPERM; + if (new_inode && (new_dir->i_mode & S_ISVTX) && + current->euid != new_inode->i_uid && + current->euid != new_dir->i_uid && !suser()) + goto end_rename; + if (S_ISDIR(old_inode->i_mode)) { + retval = -ENOTDIR; + if (new_inode && !S_ISDIR(new_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir (new_dir, old_inode)) + goto end_rename; + dir_bh = ext2_bread (old_inode, 0, 0, &retval); + if (!dir_bh) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= EXT2_LINK_MAX) + goto end_rename; + } + if (!new_bh) + new_bh = ext2_add_entry (new_dir, new_name, new_len, &new_de, + &retval); + if (!new_bh) + goto end_rename; + /* + * sanity checking before doing the rename - avoid races + */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; + /* + * ok, that's it + */ + new_de->inode = old_inode->i_ino; +#ifndef DONT_USE_DCACHE + ext2_dcache_remove (old_dir->i_dev, old_dir->i_ino, old_de->name, + old_de->name_len); + ext2_dcache_add (new_dir->i_dev, new_dir->i_ino, new_de->name, + new_de->name_len, new_de->inode); +#endif + retval = ext2_delete_entry (old_de, old_bh); + if (retval == -ENOENT) + goto try_again; + if (retval) + 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; + old_dir->i_dirt = 1; + old_bh->b_dirt = 1; + if (IS_SYNC(old_dir)) { + ll_rw_block (WRITE, 1, &old_bh); + wait_on_buffer (old_bh); + } + new_bh->b_dirt = 1; + if (IS_SYNC(new_dir)) { + ll_rw_block (WRITE, 1, &new_bh); + wait_on_buffer (new_bh); + } + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + old_dir->i_dirt = 1; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } else { + new_dir->i_nlink++; + new_dir->i_dirt = 1; + } + } + retval = 0; +end_rename: + brelse (dir_bh); + brelse (old_bh); + brelse (new_bh); + iput (old_inode); + iput (new_inode); + iput (old_dir); + iput (new_dir); + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + * + * In the second extended file system, we use a lock flag stored in the memory + * super-block. This way, we really lock other renames only if they occur + * on the same file system + */ +int ext2_rename (struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + int result; + + while (old_dir->i_sb->u.ext2_sb.s_rename_lock) + sleep_on (&old_dir->i_sb->u.ext2_sb.s_rename_wait); + old_dir->i_sb->u.ext2_sb.s_rename_lock = 1; + result = do_ext2_rename (old_dir, old_name, old_len, new_dir, + new_name, new_len); + old_dir->i_sb->u.ext2_sb.s_rename_lock = 0; + wake_up (&old_dir->i_sb->u.ext2_sb.s_rename_wait); + return result; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/super.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/super.c new file mode 100644 index 000000000..6c7e7d204 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/super.c @@ -0,0 +1,673 @@ +/* + * linux/fs/ext2/super.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +extern int vsprintf (char *, const char *, va_list); + +void ext2_error (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + char buf[1024]; + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + if (test_opt (sb, ERRORS_PANIC) || + (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_PANIC && + !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_RO))) + panic ("EXT2-fs panic (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); + printk (KERN_CRIT "EXT2-fs error (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); + if (test_opt (sb, ERRORS_RO) || + (sb->u.ext2_sb.s_es->s_errors == EXT2_ERRORS_RO && + !test_opt (sb, ERRORS_CONT) && !test_opt (sb, ERRORS_PANIC))) { + printk ("Remounting filesystem read-only\n"); + sb->s_flags |= MS_RDONLY; + } +} + +NORET_TYPE void ext2_panic (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + char buf[1024]; + va_list args; + + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_mount_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_es->s_state |= EXT2_ERROR_FS; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + } + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + panic ("EXT2-fs panic (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); +} + +void ext2_warning (struct super_block * sb, const char * function, + const char * fmt, ...) +{ + char buf[1024]; + va_list args; + + va_start (args, fmt); + vsprintf (buf, fmt, args); + va_end (args); + printk (KERN_WARNING "EXT2-fs warning (device %d/%d): %s: %s\n", + MAJOR(sb->s_dev), MINOR(sb->s_dev), function, buf); +} + +void ext2_put_super (struct super_block * sb) +{ + int i; + + lock_super (sb); + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.ext2_sb.s_es->s_state = sb->u.ext2_sb.s_mount_state; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + } +#ifndef DONT_USE_DCACHE + ext2_dcache_invalidate (sb->s_dev); +#endif + sb->s_dev = 0; + for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) + if (sb->u.ext2_sb.s_group_desc[i]) + brelse (sb->u.ext2_sb.s_group_desc[i]); + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) + if (sb->u.ext2_sb.s_inode_bitmap[i]) + brelse (sb->u.ext2_sb.s_inode_bitmap[i]); + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) + if (sb->u.ext2_sb.s_block_bitmap[i]) + brelse (sb->u.ext2_sb.s_block_bitmap[i]); + brelse (sb->u.ext2_sb.s_sbh); + unlock_super (sb); + return; +} + +static struct super_operations ext2_sops = { + ext2_read_inode, + NULL, + ext2_write_inode, + ext2_put_inode, + ext2_put_super, + ext2_write_super, + ext2_statfs, + ext2_remount +}; + +#ifdef EXT2FS_PRE_02B_COMPAT + +static int convert_pre_02b_fs (struct super_block * sb, + struct buffer_head * bh) +{ + struct ext2_super_block * es; + struct ext2_old_group_desc old_group_desc [BLOCK_SIZE / sizeof (struct ext2_old_group_desc)]; + struct ext2_group_desc * gdp; + struct buffer_head * bh2; + int groups_count; + int i; + + es = (struct ext2_super_block *) bh->b_data; + bh2 = bread (sb->s_dev, 2, BLOCK_SIZE); + if (!bh2) { + printk ("Cannot read descriptor blocks while converting !\n"); + return 0; + } + memcpy (old_group_desc, bh2->b_data, BLOCK_SIZE); + groups_count = (sb->u.ext2_sb.s_blocks_count - + sb->u.ext2_sb.s_first_data_block + + (EXT2_BLOCK_SIZE(sb) * 8) - 1) / + (EXT2_BLOCK_SIZE(sb) * 8); + memset (bh2->b_data, 0, BLOCK_SIZE); + gdp = (struct ext2_group_desc *) bh2->b_data; + for (i = 0; i < groups_count; i++) { + gdp[i].bg_block_bitmap = old_group_desc[i].bg_block_bitmap; + gdp[i].bg_inode_bitmap = old_group_desc[i].bg_inode_bitmap; + gdp[i].bg_inode_table = old_group_desc[i].bg_inode_table; + gdp[i].bg_free_blocks_count = old_group_desc[i].bg_free_blocks_count; + gdp[i].bg_free_inodes_count = old_group_desc[i].bg_free_inodes_count; + } + bh2->b_dirt = 1; + brelse (bh2); + es->s_magic = EXT2_SUPER_MAGIC; + bh->b_dirt = 1; + sb->s_magic = EXT2_SUPER_MAGIC; + return 1; +} + +#endif + +/* + * This function has been shamelessly adapted from the msdos fs + */ +static int parse_options (char * options, unsigned long * sb_block, + unsigned long * mount_options) +{ + char * this_char; + char * value; + + if (!options) + return 1; + for (this_char = strtok (options, ","); + this_char != NULL; + this_char = strtok (NULL, ",")) { + if ((value = strchr (this_char, '=')) != NULL) + *value++ = 0; + if (!strcmp (this_char, "check")) { + if (!value || !*value) + set_opt (*mount_options, CHECK_NORMAL); + else if (!strcmp (value, "none")) { + clear_opt (*mount_options, CHECK_NORMAL); + clear_opt (*mount_options, CHECK_STRICT); + } + else if (strcmp (value, "normal")) + set_opt (*mount_options, CHECK_NORMAL); + else if (strcmp (value, "strict")) { + set_opt (*mount_options, CHECK_NORMAL); + set_opt (*mount_options, CHECK_STRICT); + } + else { + printk ("EXT2-fs: Invalid check option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "debug")) + set_opt (*mount_options, DEBUG); + else if (!strcmp (this_char, "errors")) { + if (!value || !*value) { + printk ("EXT2-fs: the errors option requires " + "an argument"); + return 0; + } + if (!strcmp (value, "continue")) { + clear_opt (*mount_options, ERRORS_RO); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_CONT); + } + else if (!strcmp (value, "remount-ro")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_PANIC); + set_opt (*mount_options, ERRORS_RO); + } + else if (!strcmp (value, "panic")) { + clear_opt (*mount_options, ERRORS_CONT); + clear_opt (*mount_options, ERRORS_RO); + set_opt (*mount_options, ERRORS_PANIC); + } + else { + printk ("EXT2-fs: Invalid errors option: %s\n", + value); + return 0; + } + } + else if (!strcmp (this_char, "grpid") || + !strcmp (this_char, "bsdgroups")) + set_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "nocheck")) { + clear_opt (*mount_options, CHECK_NORMAL); + clear_opt (*mount_options, CHECK_STRICT); + } + else if (!strcmp (this_char, "nogrpid") || + !strcmp (this_char, "sysvgroups")) + clear_opt (*mount_options, GRPID); + else if (!strcmp (this_char, "sb")) { + if (!value || !*value) { + printk ("EXT2-fs: the sb option requires " + "an argument"); + return 0; + } + *sb_block = simple_strtoul (value, &value, 0); + if (*value) { + printk ("EXT2-fs: Invalid sb option: %s\n", + value); + return 0; + } + } + else { + printk ("EXT2-fs: Unrecognized mount option %s\n", this_char); + return 0; + } + } + return 1; +} + +static void ext2_setup_super (struct super_block * sb, + struct ext2_super_block * es) +{ + if (!(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + printk ("EXT2-fs warning: mounting unchecked fs, " + "running e2fsck is recommended\n"); + else if ((sb->u.ext2_sb.s_mount_state & EXT2_ERROR_FS)) + printk ("EXT2-fs warning: mounting fs with errors, " + "running e2fsck is recommended\n"); + else if (es->s_max_mnt_count >= 0 && + es->s_mnt_count >= (unsigned short) es->s_max_mnt_count) + printk ("EXT2-fs warning: maximal mount count reached, " + "running e2fsck is recommended\n"); + if (!(sb->s_flags & MS_RDONLY)) { + es->s_state &= ~EXT2_VALID_FS; + if (!es->s_max_mnt_count) + es->s_max_mnt_count = EXT2_DFL_MAX_MNT_COUNT; + es->s_mnt_count++; + es->s_mtime = CURRENT_TIME; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + if (test_opt (sb, DEBUG)) + printk ("[EXT II FS %s, %s, bs=%lu, fs=%lu, gc=%lu, " + "bpg=%lu, ipg=%lu, mo=%04lx]\n", + EXT2FS_VERSION, EXT2FS_DATE, sb->s_blocksize, + sb->u.ext2_sb.s_frag_size, + sb->u.ext2_sb.s_groups_count, + EXT2_BLOCKS_PER_GROUP(sb), + EXT2_INODES_PER_GROUP(sb), + sb->u.ext2_sb.s_mount_opt); + if (test_opt (sb, CHECK)) { + ext2_check_blocks_bitmap (sb); + ext2_check_inodes_bitmap (sb); + } + } +} + +static int ext2_check_descriptors (struct super_block * sb) +{ + int i; + int desc_block = 0; + unsigned long block = sb->u.ext2_sb.s_es->s_first_data_block; + struct ext2_group_desc * gdp = NULL; + + ext2_debug ("Checking group descriptors"); + + for (i = 0; i < sb->u.ext2_sb.s_groups_count; i++) + { + if ((i % EXT2_DESC_PER_BLOCK(sb)) == 0) + gdp = (struct ext2_group_desc *) sb->u.ext2_sb.s_group_desc[desc_block++]->b_data; + if (gdp->bg_block_bitmap < block || + gdp->bg_block_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) + { + ext2_error (sb, "ext2_check_desciptors", + "Block bitmap for group %d" + " not in group (block %lu)!", + i, gdp->bg_block_bitmap); + return 0; + } + if (gdp->bg_inode_bitmap < block || + gdp->bg_inode_bitmap >= block + EXT2_BLOCKS_PER_GROUP(sb)) + { + ext2_error (sb, "ext2_check_desciptors", + "Inode bitmap for group %d" + " not in group (block %lu)!", + i, gdp->bg_inode_bitmap); + return 0; + } + if (gdp->bg_inode_table < block || + gdp->bg_inode_table + sb->u.ext2_sb.s_itb_per_group >= + block + EXT2_BLOCKS_PER_GROUP(sb)) + { + ext2_error (sb, "ext2_check_desciptors", + "Inode table for group %d" + " not in group (block %lu)!", + i, gdp->bg_inode_table); + return 0; + } + block += EXT2_BLOCKS_PER_GROUP(sb); + gdp++; + } + return 1; +} + +struct super_block * ext2_read_super (struct super_block * sb, void * data, + int silent) +{ + struct buffer_head * bh; + struct ext2_super_block * es; + unsigned long sb_block = 1; + unsigned long logic_sb_block = 1; + int dev = sb->s_dev; + int bh_count; + int i, j; +#ifdef EXT2FS_PRE_02B_COMPAT + int fs_converted = 0; +#endif + + set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); + if (!parse_options ((char *) data, &sb_block, + &sb->u.ext2_sb.s_mount_opt)) { + sb->s_dev = 0; + return NULL; + } + + lock_super (sb); + set_blocksize (dev, BLOCK_SIZE); + if (!(bh = bread (dev, sb_block, BLOCK_SIZE))) { + sb->s_dev = 0; + unlock_super (sb); + printk ("EXT2-fs: unable to read superblock\n"); + return NULL; + } + /* + * Note: s_es must be initialized s_es as soon as possible because + * some ext2 macro-instructions depend on its value + */ + es = (struct ext2_super_block *) bh->b_data; + sb->u.ext2_sb.s_es = es; + sb->s_magic = es->s_magic; + if (sb->s_magic != EXT2_SUPER_MAGIC +#ifdef EXT2FS_PRE_02B_COMPAT + && sb->s_magic != EXT2_PRE_02B_MAGIC +#endif + ) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + if (!silent) + printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + sb->s_blocksize = EXT2_MIN_BLOCK_SIZE << es->s_log_block_size; + sb->s_blocksize_bits = EXT2_BLOCK_SIZE_BITS(sb); + if (sb->s_blocksize != BLOCK_SIZE && + (sb->s_blocksize == 1024 || sb->s_blocksize == 2048 || + sb->s_blocksize == 4096)) { + unsigned long offset; + + brelse (bh); + set_blocksize (dev, sb->s_blocksize); + logic_sb_block = sb_block / sb->s_blocksize; + offset = sb_block % sb->s_blocksize; + bh = bread (dev, logic_sb_block, sb->s_blocksize); + if(!bh) + return NULL; + es = (struct ext2_super_block *) (((char *)bh->b_data) + offset); + sb->u.ext2_sb.s_es = es; + if (es->s_magic != EXT2_SUPER_MAGIC) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: Magic mismatch, very weird !\n"); + return NULL; + } + } + sb->u.ext2_sb.s_frag_size = EXT2_MIN_FRAG_SIZE << + es->s_log_frag_size; + if (sb->u.ext2_sb.s_frag_size) + sb->u.ext2_sb.s_frags_per_block = sb->s_blocksize / + sb->u.ext2_sb.s_frag_size; + else + sb->s_magic = 0; + sb->u.ext2_sb.s_blocks_per_group = es->s_blocks_per_group; + sb->u.ext2_sb.s_frags_per_group = es->s_frags_per_group; + sb->u.ext2_sb.s_inodes_per_group = es->s_inodes_per_group; + sb->u.ext2_sb.s_inodes_per_block = sb->s_blocksize / + sizeof (struct ext2_inode); + sb->u.ext2_sb.s_itb_per_group = sb->u.ext2_sb.s_inodes_per_group / + sb->u.ext2_sb.s_inodes_per_block; + sb->u.ext2_sb.s_desc_per_block = sb->s_blocksize / + sizeof (struct ext2_group_desc); + sb->u.ext2_sb.s_sbh = bh; + sb->u.ext2_sb.s_es = es; + sb->u.ext2_sb.s_mount_state = es->s_state; + sb->u.ext2_sb.s_rename_lock = 0; + sb->u.ext2_sb.s_rename_wait = NULL; +#ifdef EXT2FS_PRE_02B_COMPAT + if (sb->s_magic == EXT2_PRE_02B_MAGIC) { + if (es->s_blocks_count > 262144) { + /* + * fs > 256 MB can't be converted + */ + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: trying to mount a pre-0.2b file" + "system which cannot be converted\n"); + return NULL; + } + printk ("EXT2-fs: mounting a pre 0.2b file system, " + "will try to convert the structure\n"); + if (!(sb->s_flags & MS_RDONLY)) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: cannot convert a read-only fs\n"); + return NULL; + } + if (!convert_pre_02b_fs (sb, bh)) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: conversion failed !!!\n"); + return NULL; + } + printk ("EXT2-fs: conversion succeeded !!!\n"); + fs_converted = 1; + } +#endif + if (sb->s_magic != EXT2_SUPER_MAGIC) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + if (!silent) + printk ("VFS: Can't find an ext2 filesystem on dev %d/%d.\n", + MAJOR(dev), MINOR(dev)); + return NULL; + } + if (sb->s_blocksize != bh->b_size) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + if (!silent) + printk ("VFS: Unsupported blocksize on dev 0x%04x.\n", + dev); + return NULL; + } + + if (sb->s_blocksize != sb->u.ext2_sb.s_frag_size) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: fragsize %lu != blocksize %lu (not supported yet)\n", + sb->u.ext2_sb.s_frag_size, sb->s_blocksize); + return NULL; + } + + sb->u.ext2_sb.s_groups_count = (es->s_blocks_count - + es->s_first_data_block + + EXT2_BLOCKS_PER_GROUP(sb) - 1) / + EXT2_BLOCKS_PER_GROUP(sb); + for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) + sb->u.ext2_sb.s_group_desc[i] = NULL; + bh_count = (sb->u.ext2_sb.s_groups_count + EXT2_DESC_PER_BLOCK(sb) - 1) / + EXT2_DESC_PER_BLOCK(sb); + if (bh_count > EXT2_MAX_GROUP_DESC) { + sb->s_dev = 0; + unlock_super (sb); + brelse (bh); + printk ("EXT2-fs: file system is too big\n"); + return NULL; + } + for (i = 0; i < bh_count; i++) { + sb->u.ext2_sb.s_group_desc[i] = bread (dev, logic_sb_block + i + 1, + sb->s_blocksize); + if (!sb->u.ext2_sb.s_group_desc[i]) { + sb->s_dev = 0; + unlock_super (sb); + for (j = 0; j < i; j++) + brelse (sb->u.ext2_sb.s_group_desc[j]); + brelse (bh); + printk ("EXT2-fs: unable to read group descriptors\n"); + return NULL; + } + } + if (!ext2_check_descriptors (sb)) { + sb->s_dev = 0; + unlock_super (sb); + for (j = 0; j < i; j++) + brelse (sb->u.ext2_sb.s_group_desc[j]); + brelse (bh); + printk ("EXT2-fs: group descriptors corrupted !\n"); + return NULL; + } + for (i = 0; i < EXT2_MAX_GROUP_LOADED; i++) { + sb->u.ext2_sb.s_inode_bitmap_number[i] = 0; + sb->u.ext2_sb.s_inode_bitmap[i] = NULL; + sb->u.ext2_sb.s_block_bitmap_number[i] = 0; + sb->u.ext2_sb.s_block_bitmap[i] = NULL; + } + sb->u.ext2_sb.s_loaded_inode_bitmaps = 0; + sb->u.ext2_sb.s_loaded_block_bitmaps = 0; + unlock_super (sb); + /* + * set up enough so that it can read an inode + */ + sb->s_dev = dev; + sb->s_op = &ext2_sops; + if (!(sb->s_mounted = iget (sb, EXT2_ROOT_INO))) { + sb->s_dev = 0; + for (i = 0; i < EXT2_MAX_GROUP_DESC; i++) + if (sb->u.ext2_sb.s_group_desc[i]) + brelse (sb->u.ext2_sb.s_group_desc[i]); + brelse (bh); + printk ("EXT2-fs: get root inode failed\n"); + return NULL; + } +#ifdef EXT2FS_PRE_02B_COMPAT + if (fs_converted) { + for (i = 0; i < bh_count; i++) + sb->u.ext2_sb.s_group_desc[i]->b_dirt = 1; + sb->s_dirt = 1; + } +#endif + ext2_setup_super (sb, es); + return sb; +} + +static void ext2_commit_super (struct super_block * sb, + struct ext2_super_block * es) +{ + es->s_wtime = CURRENT_TIME; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 0; +} + +/* + * In the second extended file system, it is not necessary to + * write the super block since we use a mapping of the + * disk super block in a buffer. + * + * However, this function is still used to set the fs valid + * flags to 0. We need to set this flag to 0 since the fs + * may have been checked while mounted and e2fsck may have + * set s_state to EXT2_VALID_FS after some corrections. + */ + +void ext2_write_super (struct super_block * sb) +{ + struct ext2_super_block * es; + + if (!(sb->s_flags & MS_RDONLY)) { + es = sb->u.ext2_sb.s_es; + + ext2_debug ("setting valid to 0\n"); + + if (es->s_state & EXT2_VALID_FS) { + es->s_state &= ~EXT2_VALID_FS; + es->s_mtime = CURRENT_TIME; + } + ext2_commit_super (sb, es); + } + sb->s_dirt = 0; +} + +int ext2_remount (struct super_block * sb, int * flags, char * data) +{ + struct ext2_super_block * es; + unsigned long tmp; + + /* + * Allow the "check" option to be passed as a remount option. + */ + set_opt (sb->u.ext2_sb.s_mount_opt, CHECK_NORMAL); + parse_options (data, &tmp, &sb->u.ext2_sb.s_mount_opt); + + es = sb->u.ext2_sb.s_es; + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + if (es->s_state & EXT2_VALID_FS || + !(sb->u.ext2_sb.s_mount_state & EXT2_VALID_FS)) + return 0; + /* + * OK, we are remounting a valid rw partition rdonly, so set + * the rdonly flag and then mark the partition as valid again. + */ + es->s_state = sb->u.ext2_sb.s_mount_state; + es->s_mtime = CURRENT_TIME; + sb->u.ext2_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + ext2_commit_super (sb, es); + } + else { + /* + * Mounting a RDONLY partition read-write, so reread and + * store the current valid flag. (It may have been changed + * by e2fsck since we originally mounted the partition.) + */ + sb->u.ext2_sb.s_mount_state = es->s_state; + sb->s_flags &= ~MS_RDONLY; + ext2_setup_super (sb, es); + } + return 0; +} + +void ext2_statfs (struct super_block * sb, struct statfs * buf) +{ + long tmp; + + put_fs_long (EXT2_SUPER_MAGIC, &buf->f_type); + put_fs_long (sb->s_blocksize, &buf->f_bsize); + put_fs_long (sb->u.ext2_sb.s_es->s_blocks_count, &buf->f_blocks); + tmp = ext2_count_free_blocks (sb); + put_fs_long (tmp, &buf->f_bfree); + if (tmp >= sb->u.ext2_sb.s_es->s_r_blocks_count) + put_fs_long (tmp - sb->u.ext2_sb.s_es->s_r_blocks_count, + &buf->f_bavail); + else + put_fs_long (0, &buf->f_bavail); + put_fs_long (sb->u.ext2_sb.s_es->s_inodes_count, &buf->f_files); + put_fs_long (ext2_count_free_inodes (sb), &buf->f_ffree); + put_fs_long (EXT2_NAME_LEN, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/symlink.c new file mode 100644 index 000000000..a98ed66bb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/symlink.c @@ -0,0 +1,126 @@ +/* + * linux/fs/ext2/symlink.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext2 symlink handling code + */ + +#include + +#include +#include +#include +#include +#include + +static int ext2_readlink (struct inode *, char *, int); +static int ext2_follow_link (struct inode *, struct inode *, int, int, + struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations ext2_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + ext2_readlink, /* readlink */ + ext2_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int ext2_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + struct buffer_head * bh = NULL; + char * link; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput (dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput (dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput (dir); + iput (inode); + return -ELOOP; + } + if (inode->i_blocks) { + if (!(bh = ext2_bread (inode, 0, 0, &error))) { + iput (dir); + iput (inode); + return -EIO; + } + link = bh->b_data; + } else + link = (char *) inode->u.ext2_i.i_data; + current->link_count++; + error = open_namei (link, flag, mode, res_inode, dir); + current->link_count--; + iput (inode); + if (bh) + brelse (bh); + return error; +} + +static int ext2_readlink (struct inode * inode, char * buffer, int buflen) +{ + struct buffer_head * bh = NULL; + char * link; + int i, err; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput (inode); + return -EINVAL; + } + if (buflen > inode->i_sb->s_blocksize - 1) + buflen = inode->i_sb->s_blocksize - 1; + if (inode->i_blocks) { + bh = ext2_bread (inode, 0, 0, &err); + if (!bh) { + iput (inode); + return 0; + } + link = bh->b_data; + } + else + link = (char *) inode->u.ext2_i.i_data; + i = 0; + while (i < buflen && (c = link[i])) { + i++; + put_fs_byte (c, buffer++); + } + iput (inode); + if (bh) + brelse (bh); + return i; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/truncate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/truncate.c new file mode 100644 index 000000000..cc2849681 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ext2/truncate.c @@ -0,0 +1,345 @@ +/* + * linux/fs/ext2/truncate.c + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/fs/minix/truncate.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +#define clear_block(addr,size,value) \ + __asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (value), "c" (size / 4), "D" ((long) (addr)) \ + :"cx", "di") + +/* + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + +static int trunc_direct (struct inode * inode) +{ + int i, tmp; + unsigned long * p; + struct buffer_head * bh; + unsigned long block_to_free = 0; + unsigned long free_count = 0; + int retry = 0; + int blocks = inode->i_sb->s_blocksize / 512; +#define DIRECT_BLOCK ((inode->i_size + inode->i_sb->s_blocksize - 1) / \ + inode->i_sb->s_blocksize) + int direct_block = DIRECT_BLOCK; + +repeat: + for (i = direct_block ; i < EXT2_NDIR_BLOCKS ; i++) { + p = inode->u.ext2_i.i_data + i; + tmp = *p; + if (!tmp) + continue; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) + bh = getblk (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + else + bh = get_hash_table (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + if (i < direct_block) { + brelse (bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *p) { + retry = 1; + brelse (bh); + continue; + } + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { + clear_block (bh->b_data, inode->i_sb->s_blocksize, + CURRENT_TIME); + bh->b_dirt = 1; + } + brelse (bh); + if (free_count == 0) { + block_to_free = tmp; + free_count++; + } else if (free_count > 0 && block_to_free == tmp - free_count) + free_count++; + else { + ext2_free_blocks (inode->i_sb, block_to_free, free_count); + block_to_free = tmp; + free_count = 1; + } +/* ext2_free_blocks (inode->i_sb, tmp, 1); */ + } + if (free_count > 0) + ext2_free_blocks (inode->i_sb, block_to_free, free_count); + return retry; +} + +static int trunc_indirect (struct inode * inode, int offset, unsigned long * p) +{ + int i, tmp; + struct buffer_head * bh; + struct buffer_head * ind_bh; + unsigned long * ind; + unsigned long block_to_free = 0; + unsigned long free_count = 0; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; +#define INDIRECT_BLOCK ((int)DIRECT_BLOCK - offset) + int indirect_block = INDIRECT_BLOCK; + + tmp = *p; + if (!tmp) + return 0; + ind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != *p) { + brelse (ind_bh); + return 1; + } + if (!ind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = indirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < indirect_block) + goto repeat; + ind = i + (unsigned long *) ind_bh->b_data; + tmp = *ind; + if (!tmp) + continue; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) + bh = getblk (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + else + bh = get_hash_table (inode->i_dev, tmp, + inode->i_sb->s_blocksize); + if (i < indirect_block) { + brelse (bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *ind) { + retry = 1; + brelse (bh); + continue; + } + *ind = 0; + ind_bh->b_dirt = 1; + if (inode->u.ext2_i.i_flags & EXT2_SECRM_FL) { + clear_block (bh->b_data, inode->i_sb->s_blocksize, + CURRENT_TIME); + bh->b_dirt = 1; + } + brelse (bh); + if (free_count == 0) { + block_to_free = tmp; + free_count++; + } else if (free_count > 0 && block_to_free == tmp - free_count) + free_count++; + else { + ext2_free_blocks (inode->i_sb, block_to_free, free_count); + block_to_free = tmp; + free_count = 1; + } +/* ext2_free_blocks (inode->i_sb, tmp, 1); */ + inode->i_blocks -= blocks; + inode->i_dirt = 1; + } + if (free_count > 0) + ext2_free_blocks (inode->i_sb, block_to_free, free_count); + ind = (unsigned long *) ind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (*(ind++)) + break; + if (i >= addr_per_block) + if (ind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_blocks (inode->i_sb, tmp, 1); + } + if (IS_SYNC(inode) && ind_bh->b_dirt) { + ll_rw_block (WRITE, 1, &ind_bh); + wait_on_buffer (ind_bh); + } + brelse (ind_bh); + return retry; +} + +static int trunc_dindirect (struct inode * inode, int offset, + unsigned long * p) +{ + int i, tmp; + struct buffer_head * dind_bh; + unsigned long * dind; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; +#define DINDIRECT_BLOCK (((int)DIRECT_BLOCK - offset) / addr_per_block) + int dindirect_block = DINDIRECT_BLOCK; + + tmp = *p; + if (!tmp) + return 0; + dind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != *p) { + brelse (dind_bh); + return 1; + } + if (!dind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = dindirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < dindirect_block) + goto repeat; + dind = i + (unsigned long *) dind_bh->b_data; + tmp = *dind; + if (!tmp) + continue; + retry |= trunc_indirect (inode, offset + (i * addr_per_block), + dind); + dind_bh->b_dirt = 1; + } + dind = (unsigned long *) dind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (*(dind++)) + break; + if (i >= addr_per_block) + if (dind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_blocks (inode->i_sb, tmp, 1); + } + if (IS_SYNC(inode) && dind_bh->b_dirt) { + ll_rw_block (WRITE, 1, &dind_bh); + wait_on_buffer (dind_bh); + } + brelse (dind_bh); + return retry; +} + +static int trunc_tindirect (struct inode * inode) +{ + int i, tmp; + struct buffer_head * tind_bh; + unsigned long * tind, * p; + int retry = 0; + int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); + int blocks = inode->i_sb->s_blocksize / 512; +#define TINDIRECT_BLOCK (((int)DIRECT_BLOCK - (addr_per_block * addr_per_block + \ + addr_per_block + EXT2_NDIR_BLOCKS)) / \ + (addr_per_block * addr_per_block)) + int tindirect_block = TINDIRECT_BLOCK; + + p = inode->u.ext2_i.i_data + EXT2_TIND_BLOCK; + if (!(tmp = *p)) + return 0; + tind_bh = bread (inode->i_dev, tmp, inode->i_sb->s_blocksize); + if (tmp != *p) { + brelse (tind_bh); + return 1; + } + if (!tind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = tindirect_block ; i < addr_per_block ; i++) { + if (i < 0) + i = 0; + if (i < tindirect_block) + goto repeat; + tind = i + (unsigned long *) tind_bh->b_data; + retry |= trunc_dindirect(inode, EXT2_NDIR_BLOCKS + + addr_per_block + (i + 1) * addr_per_block * addr_per_block, + tind); + tind_bh->b_dirt = 1; + } + tind = (unsigned long *) tind_bh->b_data; + for (i = 0; i < addr_per_block; i++) + if (*(tind++)) + break; + if (i >= addr_per_block) + if (tind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_blocks -= blocks; + inode->i_dirt = 1; + ext2_free_blocks (inode->i_sb, tmp, 1); + } + if (IS_SYNC(inode) && tind_bh->b_dirt) { + ll_rw_block (WRITE, 1, &tind_bh); + wait_on_buffer (tind_bh); + } + brelse (tind_bh); + return retry; +} + +void ext2_truncate (struct inode * inode) +{ + int retry; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + ext2_discard_prealloc(inode); + while (1) { + retry = trunc_direct(inode); + retry |= trunc_indirect (inode, EXT2_IND_BLOCK, + (unsigned long *) &inode->u.ext2_i.i_data[EXT2_IND_BLOCK]); + retry |= trunc_dindirect (inode, EXT2_IND_BLOCK + + EXT2_ADDR_PER_BLOCK(inode->i_sb), + (unsigned long *) &inode->u.ext2_i.i_data[EXT2_DIND_BLOCK]); + retry |= trunc_tindirect (inode); + if (!retry) + break; + if (IS_SYNC(inode) && inode->i_dirt) + ext2_sync_inode (inode); + current->counter = 0; + schedule (); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/fcntl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/fcntl.c new file mode 100644 index 000000000..5a7fe10df --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/fcntl.c @@ -0,0 +1,103 @@ +/* + * linux/fs/fcntl.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include + +extern int fcntl_getlk(unsigned int, struct flock *); +extern int fcntl_setlk(unsigned int, unsigned int, struct flock *); +extern int sock_fcntl (struct file *, unsigned int cmd, unsigned long arg); + +static int dupfd(unsigned int fd, unsigned int arg) +{ + if (fd >= NR_OPEN || !current->filp[fd]) + return -EBADF; + if (arg >= NR_OPEN) + return -EINVAL; + while (arg < NR_OPEN) + if (current->filp[arg]) + arg++; + else + break; + if (arg >= NR_OPEN) + return -EMFILE; + FD_CLR(arg, ¤t->close_on_exec); + (current->filp[arg] = current->filp[fd])->f_count++; + return arg; +} + +asmlinkage int sys_dup2(unsigned int oldfd, unsigned int newfd) +{ + if (oldfd >= NR_OPEN || !current->filp[oldfd]) + return -EBADF; + if (newfd == oldfd) + return newfd; + /* + * errno's for dup2() are slightly different than for fcntl(F_DUPFD) + * for historical reasons. + */ + if (newfd > NR_OPEN) /* historical botch - should have been >= */ + return -EBADF; /* dupfd() would return -EINVAL */ +#if 1 + if (newfd == NR_OPEN) + return -EBADF; /* dupfd() does return -EINVAL and that may + * even be the standard! But that is too + * weird for now. + */ +#endif + sys_close(newfd); + return dupfd(oldfd,newfd); +} + +asmlinkage int sys_dup(unsigned int fildes) +{ + return dupfd(fildes,0); +} + +asmlinkage int sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case F_DUPFD: + return dupfd(fd,arg); + case F_GETFD: + return FD_ISSET(fd, ¤t->close_on_exec); + case F_SETFD: + if (arg&1) + FD_SET(fd, ¤t->close_on_exec); + else + FD_CLR(fd, ¤t->close_on_exec); + return 0; + case F_GETFL: + return filp->f_flags; + case F_SETFL: + filp->f_flags &= ~(O_APPEND | O_NONBLOCK); + filp->f_flags |= arg & (O_APPEND | O_NONBLOCK); + return 0; + case F_GETLK: + return fcntl_getlk(fd, (struct flock *) arg); + case F_SETLK: + return fcntl_setlk(fd, cmd, (struct flock *) arg); + case F_SETLKW: + return fcntl_setlk(fd, cmd, (struct flock *) arg); + default: + /* sockets need a few special fcntls. */ + if (S_ISSOCK (filp->f_inode->i_mode)) + { + return (sock_fcntl (filp, cmd, arg)); + } + return -EINVAL; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/fifo.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/fifo.c new file mode 100644 index 000000000..ecd9bc232 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/fifo.c @@ -0,0 +1,161 @@ +/* + * linux/fs/fifo.c + * + * written by Paul H. Hargrove + */ + +#include +#include +#include +#include + +static int fifo_open(struct inode * inode,struct file * filp) +{ + int retval = 0; + unsigned long page; + + switch( filp->f_mode ) { + + case 1: + /* + * O_RDONLY + * POSIX.1 says that O_NONBLOCK means return with the FIFO + * opened, even when there is no process writing the FIFO. + */ + filp->f_op = &connecting_fifo_fops; + if (!PIPE_READERS(*inode)++) + wake_up_interruptible(&PIPE_WAIT(*inode)); + if (!(filp->f_flags & O_NONBLOCK) && !PIPE_WRITERS(*inode)) { + PIPE_RD_OPENERS(*inode)++; + while (!PIPE_WRITERS(*inode)) { + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&PIPE_WAIT(*inode)); + } + if (!--PIPE_RD_OPENERS(*inode)) + wake_up_interruptible(&PIPE_WAIT(*inode)); + } + while (PIPE_WR_OPENERS(*inode)) + interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (PIPE_WRITERS(*inode)) + filp->f_op = &read_fifo_fops; + if (retval && !--PIPE_READERS(*inode)) + wake_up_interruptible(&PIPE_WAIT(*inode)); + break; + + case 2: + /* + * O_WRONLY + * POSIX.1 says that O_NONBLOCK means return -1 with + * errno=ENXIO when there is no process reading the FIFO. + */ + if ((filp->f_flags & O_NONBLOCK) && !PIPE_READERS(*inode)) { + retval = -ENXIO; + break; + } + filp->f_op = &write_fifo_fops; + if (!PIPE_WRITERS(*inode)++) + wake_up_interruptible(&PIPE_WAIT(*inode)); + if (!PIPE_READERS(*inode)) { + PIPE_WR_OPENERS(*inode)++; + while (!PIPE_READERS(*inode)) { + if (current->signal & ~current->blocked) { + retval = -ERESTARTSYS; + break; + } + interruptible_sleep_on(&PIPE_WAIT(*inode)); + } + if (!--PIPE_WR_OPENERS(*inode)) + wake_up_interruptible(&PIPE_WAIT(*inode)); + } + while (PIPE_RD_OPENERS(*inode)) + interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (retval && !--PIPE_WRITERS(*inode)) + wake_up_interruptible(&PIPE_WAIT(*inode)); + break; + + case 3: + /* + * O_RDWR + * POSIX.1 leaves this case "undefined" when O_NONBLOCK is set. + * This implementation will NEVER block on a O_RDWR open, since + * the process can at least talk to itself. + */ + filp->f_op = &rdwr_fifo_fops; + if (!PIPE_READERS(*inode)++) + wake_up_interruptible(&PIPE_WAIT(*inode)); + while (PIPE_WR_OPENERS(*inode)) + interruptible_sleep_on(&PIPE_WAIT(*inode)); + if (!PIPE_WRITERS(*inode)++) + wake_up_interruptible(&PIPE_WAIT(*inode)); + while (PIPE_RD_OPENERS(*inode)) + interruptible_sleep_on(&PIPE_WAIT(*inode)); + break; + + default: + retval = -EINVAL; + } + if (retval || PIPE_BASE(*inode)) + return retval; + page = __get_free_page(GFP_KERNEL); + if (PIPE_BASE(*inode)) { + free_page(page); + return 0; + } + if (!page) + return -ENOMEM; + PIPE_LOCK(*inode) = 0; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_BASE(*inode) = (char *) page; + return 0; +} + +/* + * Dummy default file-operations: the only thing this does + * is contain the open that then fills in the correct operations + * depending on the access mode of the file... + */ +static struct file_operations def_fifo_fops = { + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + fifo_open, /* will set read or write pipe_fops */ + NULL, + NULL +}; + +static struct inode_operations fifo_inode_operations = { + &def_fifo_fops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +void init_fifo(struct inode * inode) +{ + inode->i_op = &fifo_inode_operations; + inode->i_pipe = 1; + PIPE_LOCK(*inode) = 0; + PIPE_BASE(*inode) = NULL; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; + PIPE_WAIT(*inode) = NULL; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/file_table.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/file_table.c new file mode 100644 index 000000000..df0ae4ae6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/file_table.c @@ -0,0 +1,89 @@ +/* + * linux/fs/file_table.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include + +struct file * first_file; +int nr_files = 0; + +static void insert_file_free(struct file *file) +{ + file->f_next = first_file; + file->f_prev = first_file->f_prev; + file->f_next->f_prev = file; + file->f_prev->f_next = file; + first_file = file; +} + +static void remove_file_free(struct file *file) +{ + if (first_file == file) + first_file = first_file->f_next; + if (file->f_next) + file->f_next->f_prev = file->f_prev; + if (file->f_prev) + file->f_prev->f_next = file->f_next; + file->f_next = file->f_prev = NULL; +} + +static void put_last_free(struct file *file) +{ + remove_file_free(file); + file->f_prev = first_file->f_prev; + file->f_prev->f_next = file; + file->f_next = first_file; + file->f_next->f_prev = file; +} + +void grow_files(void) +{ + struct file * file; + int i; + + file = (struct file *) get_free_page(GFP_KERNEL); + + if (!file) + return; + + nr_files+=i= PAGE_SIZE/sizeof(struct file); + + if (!first_file) + file->f_next = file->f_prev = first_file = file++, i--; + + for (; i ; i--) + insert_file_free(file++); +} + +unsigned long file_table_init(unsigned long start, unsigned long end) +{ + first_file = NULL; + return start; +} + +struct file * get_empty_filp(void) +{ + int i; + struct file * f; + + if (!first_file) + grow_files(); +repeat: + for (f = first_file, i=0; i < nr_files; i++, f = f->f_next) + if (!f->f_count) { + remove_file_free(f); + memset(f,0,sizeof(*f)); + put_last_free(f); + f->f_count = 1; + return f; + } + if (nr_files < NR_FILE) { + grow_files(); + goto repeat; + } + return NULL; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/filesystems.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/filesystems.c new file mode 100644 index 000000000..4d59fb7c1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/filesystems.c @@ -0,0 +1,76 @@ +/* + * linux/fs/filesystems.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * table of configured filesystems + */ + +#include +#include +#ifdef CONFIG_MINIX_FS +#include +#endif +#ifdef CONFIG_XIA_FS +#include +#endif +#ifdef CONFIG_PROC_FS +#include +#endif +#ifdef CONFIG_EXT2_FS +#include +#endif +#ifdef CONFIG_EXT_FS +#include +#endif +#ifdef CONFIG_MSDOS_FS +#include +#endif +#ifdef CONFIG_NFS_FS +#include +#endif +#ifdef CONFIG_ISO9660_FS +#include +#endif +#ifdef CONFIG_HPFS_FS +#include +#endif +#ifdef CONFIG_SYSV_FS +#include +#endif + +struct file_system_type file_systems[] = { +#ifdef CONFIG_MINIX_FS + {minix_read_super, "minix", 1}, +#endif +#ifdef CONFIG_EXT_FS + {ext_read_super, "ext", 1}, +#endif +#ifdef CONFIG_EXT2_FS + {ext2_read_super, "ext2", 1}, +#endif +#ifdef CONFIG_XIA_FS + {xiafs_read_super, "xiafs", 1}, +#endif +#ifdef CONFIG_MSDOS_FS + {msdos_read_super, "msdos", 1}, +#endif +#ifdef CONFIG_PROC_FS + {proc_read_super, "proc", 0}, +#endif +#ifdef CONFIG_NFS_FS + {nfs_read_super, "nfs", 0}, +#endif +#ifdef CONFIG_ISO9660_FS + {isofs_read_super, "iso9660", 1}, +#endif +#ifdef CONFIG_SYSV_FS + {sysv_read_super, "xenix", 1}, + {sysv_read_super, "sysv", 1}, + {sysv_read_super, "coherent", 1}, +#endif +#ifdef CONFIG_HPFS_FS + {hpfs_read_super, "hpfs", 1}, +#endif + {NULL, NULL, 0} +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/Makefile new file mode 100644 index 000000000..94ab74d5d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux HPFS filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= hpfs_fs.o + +hpfs.o: $(OBJS) + ln -f hpfs_fs.o hpfs.o + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs.h new file mode 100644 index 000000000..b01e8d7d2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs.h @@ -0,0 +1,494 @@ +/* The paper + + Duncan, Roy + Design goals and implementation of the new High Performance File System + Microsoft Systems Journal Sept 1989 v4 n5 p1(13) + + describes what HPFS looked like when it was new, and it is the source + of most of the information given here. The rest is conjecture. + + For definitive information on the Duncan paper, see it, not this file. + For definitive information on HPFS, ask somebody else -- this is guesswork. + There are certain to be many mistakes. */ + +/* Notation */ + +typedef unsigned secno; /* sector number, partition relative */ + +typedef secno dnode_secno; /* sector number of a dnode */ +typedef secno fnode_secno; /* sector number of an fnode */ +typedef secno anode_secno; /* sector number of an anode */ + +/* sector 0 */ + +/* The boot block is very like a FAT boot block, except that the + 29h signature byte is 28h instead, and the ID string is "HPFS". */ + +struct hpfs_boot_block +{ + unsigned char jmp[3]; + unsigned char oem_id[8]; + unsigned char bytes_per_sector[2]; /* 512 */ + unsigned char sectors_per_cluster; + unsigned char n_reserved_sectors[2]; + unsigned char n_fats; + unsigned char n_rootdir_entries[2]; + unsigned char n_sectors_s[2]; + unsigned char media_byte; + unsigned short sectors_per_fat; + unsigned short sectors_per_track; + unsigned short heads_per_cyl; + unsigned int n_hidden_sectors; + unsigned int n_sectors_l; /* size of partition */ + unsigned char drive_number; + unsigned char mbz; + unsigned char sig_28h; /* 28h */ + unsigned char vol_serno[4]; + unsigned char vol_label[11]; + unsigned char sig_hpfs[8]; /* "HPFS " */ + unsigned char pad[448]; + unsigned short magic; /* aa55 */ +}; + + +/* sector 16 */ + +/* The super block has the pointer to the root directory. */ + +#define SB_MAGIC 0xf995e849 + +struct hpfs_super_block +{ + unsigned magic; /* f995 e849 */ + unsigned magic1; /* fa53 e9c5, more magic? */ + unsigned huh202; /* ?? 202 = N. of B. in 1.00390625 S.*/ + fnode_secno root; /* fnode of root directory */ + secno n_sectors; /* size of filesystem */ + unsigned n_badblocks; /* number of bad blocks */ + secno bitmaps; /* pointers to free space bit maps */ + unsigned zero1; /* 0 */ + secno badblocks; /* bad block list */ + unsigned zero3; /* 0 */ + time_t last_chkdsk; /* date last checked, 0 if never */ + unsigned zero4; /* 0 */ + secno n_dir_band; /* number of sectors in dir band */ + secno dir_band_start; /* first sector in dir band */ + secno dir_band_end; /* last sector in dir band */ + secno dir_band_bitmap; /* free space map, 1 dnode per bit */ + unsigned zero5[8]; /* 0 */ + secno scratch_dnodes; /* ?? 8 preallocated sectors near dir + band, 4-aligned. */ + unsigned zero6[103]; /* 0 */ +}; + + +/* sector 17 */ + +/* The spare block has pointers to spare sectors. */ + +#define SP_MAGIC 0xf9911849 + +struct hpfs_spare_block +{ + unsigned magic; /* f991 1849 */ + unsigned magic1; /* fa52 29c5, more magic? */ + unsigned dirty; /* 0 clean, 1 "improperly stopped" */ + + secno hotfix_map; /* info about remapped bad sectors */ + unsigned n_spares_used; /* number of hotfixes */ + unsigned n_spares; /* number of spares in hotfix map */ + unsigned n_dnode_spares_free; /* spare dnodes unused */ + unsigned n_dnode_spares; /* length of spare_dnodes[] list, + follows in this block*/ + secno code_page_dir; /* code page directory block */ + unsigned n_code_pages; /* number of code pages */ + unsigned large_numbers[2]; /* ?? */ + unsigned zero1[15]; + dnode_secno spare_dnodes[20]; /* emergency free dnode list */ + unsigned zero2[81]; /* room for more? */ +}; + +/* The bad block list is 4 sectors long. The first word must be zero, + the remaining words give n_badblocks bad block numbers. + I bet you can see it coming... */ + +#define BAD_MAGIC 0 + +/* The hotfix map is 4 sectors long. It looks like + + secno from[n_spares]; + secno to[n_spares]; + + The to[] list is initalized to point to n_spares preallocated empty + sectors. The from[] list contains the sector numbers of bad blocks + which have been remapped to corresponding sectors in the to[] list. + n_spares_used gives the length of the from[] list. */ + + +/* Sectors 18 and 19 are preallocated and unused. + Maybe they're spares for 16 and 17, but simple substitution fails. */ + + +/* The code page info pointed to by the spare block consists of an index + block and blocks containing character maps. The following is pretty + sketchy, but Linux is Latin-1 so it doesn't matter. */ + +/* block pointed to by spareblock->code_page_dir */ + +#define CP_DIR_MAGIC 0x494521f7 + +struct code_page_directory +{ + unsigned magic; /* 4945 21f7 */ + unsigned n_code_pages; /* number of pointers following */ + unsigned zero1[2]; + struct { + unsigned short ix; /* index */ + unsigned short code_page_number; /* code page number */ + unsigned bounds; /* matches corresponding word + in data block */ + secno code_page_data; /* sector number of a code_page_data + containing c.p. array */ + unsigned index; /* index in c.p. array in that sector*/ + } array[31]; /* unknown length */ +}; + +/* blocks pointed to by code_page_directory */ + +#define CP_DATA_MAGIC 0x894521f7 + +struct code_page_data +{ + unsigned magic; /* 8945 21f7 */ + unsigned n_used; /* # elements used in c_p_data[] */ + unsigned bounds[3]; /* looks a bit like + (beg1,end1), (beg2,end2) + one byte each */ + unsigned short offs[3]; /* offsets from start of sector + to start of c_p_data[ix] */ + struct { + unsigned short ix; /* index */ + unsigned short code_page_number; /* code page number */ + unsigned short zero1; + unsigned char map[128]; /* map for chars 80..ff */ + unsigned short zero2; + } code_page[3]; + unsigned char incognita[78]; +}; + + +/* Free space bitmaps are 4 sectors long, which is 16384 bits. + 16384 sectors is 8 meg, and each 8 meg band has a 4-sector bitmap. + Bit order in the maps is little-endian. 0 means taken, 1 means free. + + Bit map sectors are marked allocated in the bit maps, and so are sectors + off the end of the partition. + + Band 0 is sectors 0-3fff, its map is in sectors 18-1b. + Band 1 is 4000-7fff, its map is in 7ffc-7fff. + Band 2 is 8000-ffff, its map is in 8000-8003. + The remaining bands have maps in their first (even) or last (odd) 4 sectors + -- if the last, partial, band is odd its map is in its last 4 sectors. + + The bitmap locations are given in a table pointed to by the super block. + No doubt they aren't constrained to be at 18, 7ffc, 8000, ...; that is + just where they usually are. + + The "directory band" is a bunch of sectors preallocated for dnodes. + It has a 4-sector free space bitmap of its own. Each bit in the map + corresponds to one 4-sector dnode, bit 0 of the map corresponding to + the first 4 sectors of the directory band. The entire band is marked + allocated in the main bitmap. The super block gives the locations + of the directory band and its bitmap. ("band" doesn't mean it is + 8 meg long; it isn't.) */ + + +/* dnode: directory. 4 sectors long */ + +/* A directory is a tree of dnodes. The fnode for a directory + contains one pointer, to the root dnode of the tree. The fnode + never moves, the dnodes do the B-tree thing, splitting and merging + as files are added and removed. */ + +#define DNODE_MAGIC 0x77e40aae + +struct dnode { + unsigned magic; /* 77e4 0aae */ + unsigned first_free; /* offset from start of dnode to + first free dir entry */ + unsigned increment_me; /* some kind of activity counter? + Neither HPFS.IFS nor CHKDSK cares + if you change this word */ + secno up; /* (root dnode) directory's fnode + (nonroot) parent dnode */ + dnode_secno self; /* pointer to this dnode */ + unsigned char dirent[2028]; /* one or more dirents */ +}; + +struct hpfs_dirent { + unsigned short length; /* offset to next dirent */ + unsigned first: 1; /* set on phony ^A^A (".") entry */ + unsigned flag1: 1; + unsigned down: 1; /* down pointer present (after name) */ + unsigned last: 1; /* set on phony \377 entry */ + unsigned flag4: 1; + unsigned flag5: 1; + unsigned flag6: 1; + unsigned has_needea: 1; /* ?? some EA has NEEDEA set + I have no idea why this is + interesting in a dir entry */ + unsigned read_only: 1; /* dos attrib */ + unsigned hidden: 1; /* dos attrib */ + unsigned system: 1; /* dos attrib */ + unsigned flag11: 1; /* would be volume label dos attrib */ + unsigned directory: 1; /* dos attrib */ + unsigned archive: 1; /* dos attrib */ + unsigned not_8x3: 1; /* name is not 8.3 */ + unsigned flag15: 1; + fnode_secno fnode; /* fnode giving allocation info */ + time_t write_date; /* mtime */ + unsigned file_size; /* file length, bytes */ + time_t read_date; /* atime */ + time_t creation_date; /* ctime */ + unsigned ea_size; /* total EA length, bytes */ + unsigned char zero1; + unsigned char locality; /* 0=unk 1=seq 2=random 3=both */ + unsigned char namelen, name[1]; /* file name */ + /* dnode_secno down; btree down pointer, if present, + follows name on next word boundary, or maybe it's + precedes next dirent, which is on a word boundary. */ +}; + +/* The b-tree down pointer from a dir entry */ + +static inline dnode_secno de_down_pointer (struct hpfs_dirent *de) +{ + return *(dnode_secno *) ((void *) de + de->length - 4); +} + +/* The first dir entry in a dnode */ + +static inline struct hpfs_dirent *dnode_first_de (struct dnode *dnode) +{ + return (void *) dnode->dirent; +} + +/* The end+1 of the dir entries */ + +static inline struct hpfs_dirent *dnode_end_de (struct dnode *dnode) +{ + return (void *) dnode + dnode->first_free; +} + +/* The dir entry after dir entry de */ + +static inline struct hpfs_dirent *de_next_de (struct hpfs_dirent *de) +{ + return (void *) de + de->length; +} + + +/* B+ tree: allocation info in fnodes and anodes */ + +/* dnodes point to fnodes which are responsible for listing the sectors + assigned to the file. This is done with trees of (length,address) + pairs. (Actually triples, of (length, file-address, disk-address) + which can represent holes. Find out if HPFS does that.) + At any rate, fnodes contain a small tree; if subtrees are needed + they occupy essentially a full block in anodes. A leaf-level tree node + has 3-word entries giving sector runs, a non-leaf node has 2-word + entries giving subtree pointers. A flag in the header says which. */ + +struct bplus_leaf_node +{ + unsigned file_secno; /* first file sector in extent */ + unsigned length; /* length, sectors */ + secno disk_secno; /* first corresponding disk sector */ +}; + +struct bplus_internal_node +{ + unsigned file_secno; /* subtree maps sectors < this */ + anode_secno down; /* pointer to subtree */ +}; + +struct bplus_header +{ + unsigned flag0: 1; + unsigned flag1: 1; + unsigned flag2: 1; + unsigned flag3: 1; + unsigned flag4: 1; + unsigned fnode_parent: 1; /* ? we're pointed to by an fnode, + the data btree or some ea or the + main ea bootage pointer ea_secno */ + /* also can get set in fnodes, which + may be a chkdsk glitch or may mean + this bit is irrelevant in fnodes, + or this interpretation is all wet */ + unsigned flag6: 1; + unsigned internal: 1; /* 1 -> (internal) tree of anodes + 0 -> (leaf) list of extents */ + unsigned char fill[3]; + unsigned char n_free_nodes; /* free nodes in following array */ + unsigned char n_used_nodes; /* used nodes in following array */ + unsigned short first_free; /* offset from start of header to + first free node in array */ + union { + struct bplus_internal_node internal[0]; /* (internal) 2-word entries giving + subtree pointers */ + struct bplus_leaf_node external[0]; /* (external) 3-word entries giving + sector runs */ + } u; +}; + +/* fnode: root of allocation b+ tree, and EA's */ + +/* Every file and every directory has one fnode, pointed to by the directory + entry and pointing to the file's sectors or directory's root dnode. EA's + are also stored here, and there are said to be ACL's somewhere here too. */ + +#define FNODE_MAGIC 0xf7e40aae + +struct fnode +{ + unsigned magic; /* f7e4 0aae */ + unsigned zero1[2]; + unsigned char len, name[15]; /* true length, truncated name */ + fnode_secno up; /* pointer to file's directory fnode */ + unsigned zero2[3]; + unsigned ea_size_l; /* length of disk-resident ea's */ + secno ea_secno; /* first sector of disk-resident ea's*/ + unsigned short ea_size_s; /* length of fnode-resident ea's */ + + unsigned flag0: 1; + unsigned ea_anode: 1; /* 1 -> ea_secno is an anode */ + unsigned flag2: 1; + unsigned flag3: 1; + unsigned flag4: 1; + unsigned flag5: 1; + unsigned flag6: 1; + unsigned flag7: 1; + unsigned dirflag: 1; /* 1 -> directory. first & only extent + points to dnode. */ + unsigned flag9: 1; + unsigned flag10: 1; + unsigned flag11: 1; + unsigned flag12: 1; + unsigned flag13: 1; + unsigned flag14: 1; + unsigned flag15: 1; + + struct bplus_header btree; /* b+ tree, 8 extents or 12 subtrees */ + union { + struct bplus_leaf_node external[8]; + struct bplus_internal_node internal[12]; + } u; + + unsigned file_size; /* file length, bytes */ + unsigned n_needea; /* number of EA's with NEEDEA set */ + unsigned zero4[4]; + unsigned ea_offs; /* offset from start of fnode + to first fnode-resident ea */ + unsigned zero5[2]; + unsigned char ea[316]; /* zero or more EA's, packed together + with no alignment padding. + (Do not use this name, get here + via fnode + ea_offs. I think.) */ +}; + + +/* anode: 99.44% pure allocation tree */ + +#define ANODE_MAGIC 0x37e40aae + +struct anode +{ + unsigned magic; /* 37e4 0aae */ + anode_secno self; /* pointer to this anode */ + secno up; /* parent anode or fnode */ + + struct bplus_header btree; /* b+tree, 40 extents or 60 subtrees */ + union { + struct bplus_leaf_node external[40]; + struct bplus_internal_node internal[60]; + } u; + + unsigned fill[3]; /* unused */ +}; + + +/* extended attributes. + + A file's EA info is stored as a list of (name,value) pairs. It is + usually in the fnode, but (if it's large) it is moved to a single + sector run outside the fnode, or to multiple runs with an anode tree + that points to them. + + The value of a single EA is stored along with the name, or (if large) + it is moved to a single sector run, or multiple runs pointed to by an + anode tree, pointed to by the value field of the (name,value) pair. + + Flags in the EA tell whether the value is immediate, in a single sector + run, or in multiple runs. Flags in the fnode tell whether the EA list + is immediate, in a single run, or in multiple runs. */ + +struct extended_attribute +{ + unsigned indirect: 1; /* 1 -> value gives sector number + where real value starts */ + unsigned anode: 1; /* 1 -> sector is an anode + that points to fragmented value */ + unsigned flag2: 1; + unsigned flag3: 1; + unsigned flag4: 1; + unsigned flag5: 1; + unsigned flag6: 1; + unsigned needea: 1; /* required ea */ + unsigned char namelen; /* length of name, bytes */ + unsigned short valuelen; /* length of value, bytes */ + /* + unsigned char name[namelen]; ascii attrib name + unsigned char nul; terminating '\0', not counted + unsigned char value[valuelen]; value, arbitrary + if this.indirect, valuelen is 8 and the value is + unsigned length; real length of value, bytes + secno secno; sector address where it starts + if this.anode, the above sector number is the root of an anode tree + which points to the value. + */ +}; + +static inline unsigned char *ea_name (struct extended_attribute *ea) +{ + return (void *) ea + sizeof *ea; +} + +static inline unsigned char *ea_value (struct extended_attribute *ea) +{ + return (void *) ea + sizeof *ea + ea->namelen + 1; +} + +static inline struct extended_attribute * + ea_next_ea (struct extended_attribute *ea) +{ + return (void *) ea + sizeof *ea + ea->namelen + 1 + ea->valuelen; +} + +static inline unsigned ea_indirect_length (struct extended_attribute *ea) +{ + unsigned *v = (void *) ea_value (ea); + return v[0]; +} + +static inline secno ea_indirect_secno (struct extended_attribute *ea) +{ + unsigned *v = (void *) ea_value (ea); + return v[1]; +} + +/* + Local Variables: + comment-column: 40 + End: +*/ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs_fs.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs_fs.c new file mode 100644 index 000000000..0bd09f2cf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/hpfs/hpfs_fs.c @@ -0,0 +1,1724 @@ +/* + * linux/fs/hpfs/hpfs_fs.c + * read-only HPFS + * version 1.0 + * + * Chris Smith 1993 + * + * Sources & references: + * Duncan, _Design ... of HPFS_, MSSJ 4(5) (C) 1989 Microsoft Corp + * linux/fs/minix Copyright (C) 1991, 1992, 1993 Linus Torvalds + * linux/fs/msdos Written 1992, 1993 by Werner Almesberger + * linux/fs/isofs Copyright (C) 1991 Eric Youngdale + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hpfs.h" + +/* + * HPFS is a mixture of 512-byte blocks and 2048-byte blocks. The 2k blocks + * are used for directories and bitmaps. For bmap to work, we must run the + * file system with 512-byte blocks. The 2k blocks are assembled in buffers + * obtained from kmalloc. + * + * For a file's i-number we use the sector number of its fnode, coded. + * (Directory ino's are even, file ino's are odd, and ino >> 1 is the + * sector address of the fnode. This is a hack to allow lookup() to + * tell read_inode() whether it is necessary to read the fnode.) + * + * The map_xxx routines all read something into a buffer and return a + * pointer somewhere in the buffer. The caller must do the brelse. + * The other routines are balanced. + * + * For details on the data structures see hpfs.h and the Duncan paper. + * + * Overview + * + * [ The names of these data structures, except fnode, are not Microsoft's + * or IBM's. I don't know what names they use. The semantics described + * here are those of this implementation, and any coincidence between it + * and real HPFS is to be hoped for but not guaranteed by me, and + * certainly not guaranteed by MS or IBM. Who know nothing about this. ] + * + * [ Also, the following will make little sense if you haven't read the + * Duncan paper, which is excellent. ] + * + * HPFS is a tree. There are 3 kinds of nodes. A directory is a tree + * of dnodes, and a file's allocation info is a tree of sector runs + * stored in fnodes and anodes. + * + * The top pointer is in the super block, it points to the fnode of the + * root directory. + * + * The root directory -- all directories -- gives file names, dates &c, + * and fnode addresses. If the directory fits in one dnode, that's it, + * otherwise the top dnode points to other dnodes, forming a tree. A + * dnode tree (one directory) might look like + * + * ((a b c) d (e f g) h (i j) k l (m n o p)) + * + * The subtrees appear between the files. Each dir entry contains, along + * with the name and fnode, a dnode pointer to the subtree that precedes it + * (if there is one; a flag tells that). The first entry in every directory + * is ^A^A, the "." entry for the directory itself. The last entry in every + * dnode is \377, a fake entry whose only valid fields are the bit marking + * it last and the down pointer to the subtree preceding it, if any. + * + * The "value" field of directory entries is an fnode address. The fnode + * tells where the sectors of the file are. The fnode for a subdirectory + * contains one pointer, to the root dnode of the subdirectory. The fnode + * for a data file contains, in effect, a tiny anode. (Most of the space + * in fnodes is for extended attributes.) + * + * anodes and the anode part of fnodes are trees of extents. An extent + * is a (length, disk address) pair, labeled with the file address being + * mapped. E.g., + * + * (0: 3@1000 3: 1@2000 4: 2@10) + * + * means the file:disk sector map (0:1000 1:1001 2:1002 3:2000 4:10 5:11). + * + * There is space for 8 file:len@disk triples in an fnode, or for 40 in an + * anode. If this is insufficient, subtrees are used, as in + * + * (6: (0: 3@1000 3: 1@2000 4: 2@10) 12: (6: 3@8000 9: 1@9000 10: 2@20)) + * + * The label on a subtree is the first address *after* that tree. The + * subtrees are always anodes. The label:subtree pairs require only + * two words each, so non-leaf subtrees have a different format; there + * is room for 12 label:subtree pairs in an fnode, or 60 in an anode. + * + * Within a directory, each dnode contains a pointer up to its parent + * dnode. The root dnode points up to the directory's fnode. + * + * Each fnode contains a pointer to the directory that contains it + * (to the fnode of the directory). So this pointer in a directory + * fnode is "..". + * + * On the disk, dnodes are all together in the center of the partition, + * and HPFS even manages to put all the dnodes for a single directory + * together, generally. fnodes are out with the data. anodes are seldom + * seen -- in fact noncontiguous files are seldom seen. I think this is + * partly the open() call that lets programs specify the length of an + * output file when they know it, and partly because HPFS.IFS really is + * very good at resisting fragmentation. + */ + +/* notation */ + +#define little_ushort(x) (*(unsigned short *) &(x)) +typedef void nonconst; + +/* super block ops */ + +static void hpfs_read_inode(struct inode *); +static void hpfs_put_super(struct super_block *); +static void hpfs_statfs(struct super_block *, struct statfs *); +static int hpfs_remount_fs(struct super_block *, int *); + +static const struct super_operations hpfs_sops = +{ + hpfs_read_inode, /* read_inode */ + NULL, /* notify_change */ + NULL, /* write_inode */ + NULL, /* put_inode */ + hpfs_put_super, /* put_super */ + NULL, /* write_super */ + hpfs_statfs, /* statfs */ + hpfs_remount_fs, /* remount_fs */ +}; + +/* file ops */ + +static int hpfs_file_read(struct inode *, struct file *, char *, int); +static secno hpfs_bmap(struct inode *, unsigned); + +static const struct file_operations hpfs_file_ops = +{ + NULL, /* lseek - default */ + hpfs_file_read, /* read */ + NULL, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync, /* fsync */ +}; + +static const struct inode_operations hpfs_file_iops = +{ + (nonconst *) & hpfs_file_ops, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + (int (*)(struct inode *, int)) + &hpfs_bmap, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ +}; + +/* directory ops */ + +static int hpfs_dir_read(struct inode *inode, struct file *filp, + char *buf, int count); +static int hpfs_readdir(struct inode *inode, struct file *filp, + struct dirent *dirent, int count); +static int hpfs_lookup(struct inode *, const char *, int, struct inode **); + +static const struct file_operations hpfs_dir_ops = +{ + NULL, /* lseek - default */ + hpfs_dir_read, /* read */ + NULL, /* write - bad */ + hpfs_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync, /* fsync */ +}; + +static const struct inode_operations hpfs_dir_iops = +{ + (nonconst *) & hpfs_dir_ops, /* default directory file ops */ + NULL, /* create */ + hpfs_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL, /* permission */ +}; + +/* Four 512-byte buffers and the 2k block obtained by concatenating them */ + +struct quad_buffer_head { + struct buffer_head *bh[4]; + void *data; +}; + +/* forwards */ + +static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, + int *lowercase, int *conv); +static int check_warn(int not_ok, + const char *p1, const char *p2, const char *p3); +static int zerop(void *addr, unsigned len); +static void count_dnodes(struct inode *inode, dnode_secno dno, + unsigned *n_dnodes, unsigned *n_subdirs); +static unsigned count_bitmap(struct super_block *s); +static unsigned count_one_bitmap(dev_t dev, secno secno); +static secno bplus_lookup(struct inode *inode, struct bplus_header *b, + secno file_secno, struct buffer_head **bhp); +static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, + const unsigned char *name, unsigned len, + struct quad_buffer_head *qbh); +static struct hpfs_dirent *map_pos_dirent(struct inode *inode, off_t *posp, + struct quad_buffer_head *qbh); +static void write_one_dirent(struct dirent *dirent, const unsigned char *name, + unsigned namelen, ino_t ino, int lowercase); +static dnode_secno dir_subdno(struct inode *inode, unsigned pos); +static struct hpfs_dirent *map_nth_dirent(dev_t dev, dnode_secno dno, + int n, + struct quad_buffer_head *qbh); +static unsigned choose_conv(unsigned char *p, unsigned len); +static unsigned convcpy_tofs(unsigned char *out, unsigned char *in, + unsigned len); +static dnode_secno fnode_dno(dev_t dev, ino_t ino); +static struct fnode *map_fnode(dev_t dev, ino_t ino, + struct buffer_head **bhp); +static struct anode *map_anode(dev_t dev, unsigned secno, + struct buffer_head **bhp); +static struct dnode *map_dnode(dev_t dev, unsigned secno, + struct quad_buffer_head *qbh); +static void *map_sector(dev_t dev, unsigned secno, struct buffer_head **bhp); +static void *map_4sectors(dev_t dev, unsigned secno, + struct quad_buffer_head *qbh); +static void brelse4(struct quad_buffer_head *qbh); + +/* + * make inode number for a file + */ + +static inline ino_t file_ino(fnode_secno secno) +{ + return secno << 1 | 1; +} + +/* + * make inode number for a directory + */ + +static inline ino_t dir_ino(fnode_secno secno) +{ + return secno << 1; +} + +/* + * get fnode address from an inode number + */ + +static inline fnode_secno ino_secno(ino_t ino) +{ + return ino >> 1; +} + +/* + * test for directory's inode number + */ + +static inline int ino_is_dir(ino_t ino) +{ + return (ino & 1) == 0; +} + +/* + * conv= options + */ + +#define CONV_BINARY 0 /* no conversion */ +#define CONV_TEXT 1 /* crlf->newline */ +#define CONV_AUTO 2 /* decide based on file contents */ + +/* + * local time (HPFS) to GMT (Unix) + */ + +static inline time_t local_to_gmt(time_t t) +{ + extern struct timezone sys_tz; + return t + sys_tz.tz_minuteswest * 60; +} + +/* super block ops */ + +/* + * mount. This gets one thing, the root directory inode. It does a + * bunch of guessed-at consistency checks. + */ + +struct super_block *hpfs_read_super(struct super_block *s, + void *options, int silent) +{ + struct hpfs_boot_block *bootblock; + struct hpfs_super_block *superblock; + struct hpfs_spare_block *spareblock; + struct hpfs_dirent *de; + struct buffer_head *bh0, *bh1, *bh2; + struct quad_buffer_head qbh; + dnode_secno root_dno; + dev_t dev; + uid_t uid; + gid_t gid; + umode_t umask; + int lowercase; + int conv; + int dubious; + + /* + * Get the mount options + */ + + if (!parse_opts(options, &uid, &gid, &umask, &lowercase, &conv)) { + printk("HPFS: syntax error in mount options. Not mounted.\n"); + s->s_dev = 0; + return 0; + } + + /* + * Fill in the super block struct + */ + + lock_super(s); + dev = s->s_dev; + set_blocksize(dev, 512); + + /* + * fetch sectors 0, 16, 17 + */ + + bootblock = map_sector(dev, 0, &bh0); + if (!bootblock) + goto bail; + + superblock = map_sector(dev, 16, &bh1); + if (!superblock) + goto bail0; + + spareblock = map_sector(dev, 17, &bh2); + if (!spareblock) + goto bail1; + + /* + * Check that this fs looks enough like a known one that we can find + * and read the root directory. + */ + + if (bootblock->magic != 0xaa55 + || superblock->magic != SB_MAGIC + || spareblock->magic != SP_MAGIC + || bootblock->sig_28h != 0x28 + || memcmp(&bootblock->sig_hpfs, "HPFS ", 8) + || little_ushort(bootblock->bytes_per_sector) != 512) { + printk("HPFS: hpfs_read_super: Not HPFS\n"); + goto bail2; + } + + /* + * Check for inconsistencies -- possibly wrong guesses here, possibly + * filesystem problems. + */ + + dubious = 0; + + dubious |= check_warn(spareblock->dirty != 0, + "`Improperly stopped'", "flag is set", "run CHKDSK"); + dubious |= check_warn(spareblock->n_spares_used != 0, + "Spare blocks", "may be in use", "run CHKDSK"); + + /* + * Above errors mean we could get wrong answers if we proceed, + * so don't + */ + + if (dubious) + goto bail2; + + dubious |= check_warn((spareblock->n_dnode_spares != + spareblock->n_dnode_spares_free), + "Spare dnodes", "may be in use", "run CHKDSK"); + dubious |= check_warn(superblock->zero1 != 0, + "#1", "unknown word nonzero", "investigate"); + dubious |= check_warn(superblock->zero3 != 0, + "#3", "unknown word nonzero", "investigate"); + dubious |= check_warn(superblock->zero4 != 0, + "#4", "unknown word nonzero", "investigate"); + dubious |= check_warn(!zerop(superblock->zero5, + sizeof superblock->zero5), + "#5", "unknown word nonzero", "investigate"); + dubious |= check_warn(!zerop(superblock->zero6, + sizeof superblock->zero6), + "#6", "unknown word nonzero", "investigate"); + + if (dubious) + printk("HPFS: Proceeding, but operation may be unreliable\n"); + + /* + * set fs read only + */ + + s->s_flags |= MS_RDONLY; + + /* + * fill in standard stuff + */ + + s->s_magic = HPFS_SUPER_MAGIC; + s->s_blocksize = 512; + s->s_blocksize_bits = 9; + s->s_op = (struct super_operations *) &hpfs_sops; + + /* + * fill in hpfs stuff + */ + + s->s_hpfs_root = dir_ino(superblock->root); + s->s_hpfs_fs_size = superblock->n_sectors; + s->s_hpfs_dirband_size = superblock->n_dir_band / 4; + s->s_hpfs_dmap = superblock->dir_band_bitmap; + s->s_hpfs_bitmaps = superblock->bitmaps; + s->s_hpfs_uid = uid; + s->s_hpfs_gid = gid; + s->s_hpfs_mode = 0777 & ~umask; + s->s_hpfs_n_free = -1; + s->s_hpfs_n_free_dnodes = -1; + s->s_hpfs_lowercase = lowercase; + s->s_hpfs_conv = conv; + + /* + * done with the low blocks + */ + + brelse(bh2); + brelse(bh1); + brelse(bh0); + + /* + * all set. try it out. + */ + + s->s_mounted = iget(s, s->s_hpfs_root); + unlock_super(s); + + if (!s->s_mounted) { + printk("HPFS: hpfs_read_super: inode get failed\n"); + s->s_dev = 0; + return 0; + } + + /* + * find the root directory's . pointer & finish filling in the inode + */ + + root_dno = fnode_dno(dev, s->s_hpfs_root); + if (root_dno) + de = map_dirent(s->s_mounted, root_dno, "\001\001", 2, &qbh); + if (!root_dno || !de) { + printk("HPFS: " + "hpfs_read_super: root dir isn't in the root dir\n"); + s->s_dev = 0; + return 0; + } + + s->s_mounted->i_atime = local_to_gmt(de->read_date); + s->s_mounted->i_mtime = local_to_gmt(de->write_date); + s->s_mounted->i_ctime = local_to_gmt(de->creation_date); + + brelse4(&qbh); + return s; + + bail2: + brelse(bh2); + bail1: + brelse(bh1); + bail0: + brelse(bh0); + bail: + s->s_dev = 0; + unlock_super(s); + return 0; +} + +static int check_warn(int not_ok, + const char *p1, const char *p2, const char *p3) +{ + if (not_ok) + printk("HPFS: %s %s. Please %s\n", p1, p2, p3); + return not_ok; +} + +static int zerop(void *addr, unsigned len) +{ + unsigned char *p = addr; + return p[0] == 0 && memcmp(p, p + 1, len - 1) == 0; +} + +/* + * A tiny parser for option strings, stolen from dosfs. + */ + +static int parse_opts(char *opts, uid_t *uid, gid_t *gid, umode_t *umask, + int *lowercase, int *conv) +{ + char *p, *rhs; + + *uid = current->uid; + *gid = current->gid; + *umask = current->umask; + *lowercase = 1; + *conv = CONV_BINARY; + + if (!opts) + return 1; + + for (p = strtok(opts, ","); p != 0; p = strtok(0, ",")) { + if ((rhs = strchr(p, '=')) != 0) + *rhs++ = '\0'; + if (!strcmp(p, "uid")) { + if (!rhs || !*rhs) + return 0; + *uid = simple_strtoul(rhs, &rhs, 0); + if (*rhs) + return 0; + } + else if (!strcmp(p, "gid")) { + if (!rhs || !*rhs) + return 0; + *gid = simple_strtoul(rhs, &rhs, 0); + if (*rhs) + return 0; + } + else if (!strcmp(p, "umask")) { + if (!rhs || !*rhs) + return 0; + *umask = simple_strtoul(rhs, &rhs, 8); + if (*rhs) + return 0; + } + else if (!strcmp(p, "case")) { + if (!strcmp(rhs, "lower")) + *lowercase = 1; + else if (!strcmp(rhs, "asis")) + *lowercase = 0; + else + return 0; + } + else if (!strcmp(p, "conv")) { + if (!strcmp(rhs, "binary")) + *conv = CONV_BINARY; + else if (!strcmp(rhs, "text")) + *conv = CONV_TEXT; + else if (!strcmp(rhs, "auto")) + *conv = CONV_AUTO; + else + return 0; + } + else + return 0; + } + + return 1; +} + +/* + * read_inode. This is called with exclusive access to a new inode that + * has only (i_dev,i_ino) set. It is responsible for filling in the rest. + * We leave the dates blank, to be filled in from the dir entry. + * + * NOTE that there must be no sleeping from the return in this routine + * until lookup() finishes filling in the inode, otherwise the partly + * completed inode would be visible during the sleep. + * + * It is done in this strange and sinful way because the alternative + * is to read the fnode, find the dir pointer in it, read that fnode + * to get the dnode pointer, search through that whole directory for + * the ino we're reading, and get the dates. It works that way, but + * ls sounds like fsck. + */ + +static void hpfs_read_inode(struct inode *inode) +{ + struct super_block *s = inode->i_sb; + + /* be ready to bail out */ + + inode->i_op = 0; + inode->i_mode = 0; + + if (inode->i_ino == 0 + || ino_secno(inode->i_ino) >= inode->i_sb->s_hpfs_fs_size) { + printk("HPFS: read_inode: bad ino\n"); + return; + } + + /* + * canned stuff + */ + + inode->i_uid = s->s_hpfs_uid; + inode->i_gid = s->s_hpfs_gid; + inode->i_mode = s->s_hpfs_mode; + inode->i_hpfs_conv = s->s_hpfs_conv; + + inode->i_hpfs_dno = 0; + inode->i_hpfs_n_secs = 0; + inode->i_hpfs_file_sec = 0; + inode->i_hpfs_disk_sec = 0; + inode->i_hpfs_dpos = 0; + inode->i_hpfs_dsubdno = 0; + + /* + * figure out whether we are looking at a directory or a file + */ + + if (ino_is_dir(inode->i_ino)) + inode->i_mode |= S_IFDIR; + else { + inode->i_mode |= S_IFREG; + inode->i_mode &= ~0111; + } + + /* + * these fields must be filled in from the dir entry, which we don't + * have but lookup does. It will fill them in before letting the + * inode out of its grasp. + */ + + inode->i_atime = 0; + inode->i_mtime = 0; + inode->i_ctime = 0; + inode->i_size = 0; + + /* + * fill in the rest + */ + + if (S_ISREG(inode->i_mode)) { + + inode->i_op = (struct inode_operations *) &hpfs_file_iops; + inode->i_nlink = 1; + inode->i_blksize = 512; + + } + else { + unsigned n_dnodes, n_subdirs; + struct buffer_head *bh0; + struct fnode *fnode = map_fnode(inode->i_dev, + inode->i_ino, &bh0); + + if (!fnode) { + printk("HPFS: read_inode: no fnode\n"); + inode->i_mode = 0; + return; + } + + inode->i_hpfs_parent_dir = dir_ino(fnode->up); + inode->i_hpfs_dno = fnode->u.external[0].disk_secno; + + brelse(bh0); + + n_dnodes = n_subdirs = 0; + count_dnodes(inode, inode->i_hpfs_dno, &n_dnodes, &n_subdirs); + + inode->i_op = (struct inode_operations *) &hpfs_dir_iops; + inode->i_blksize = 512; /* 2048 here confuses ls & du & ... */ + inode->i_blocks = 4 * n_dnodes; + inode->i_size = 512 * inode->i_blocks; + inode->i_nlink = 2 + n_subdirs; + } +} + +/* + * unmount. + */ + +static void hpfs_put_super(struct super_block *s) +{ + lock_super(s); + s->s_dev = 0; + unlock_super(s); +} + +/* + * statfs. For free inode counts we report the count of dnodes in the + * directory band -- not exactly right but pretty analagous. + */ + +static void hpfs_statfs(struct super_block *s, struct statfs *buf) +{ + /* + * count the bits in the bitmaps, unless we already have + */ + + if (s->s_hpfs_n_free == -1) { + s->s_hpfs_n_free = count_bitmap(s); + s->s_hpfs_n_free_dnodes = + count_one_bitmap(s->s_dev, s->s_hpfs_dmap); + } + + /* + * fill in the user statfs struct + */ + + put_fs_long(s->s_magic, &buf->f_type); + put_fs_long(512, &buf->f_bsize); + put_fs_long(s->s_hpfs_fs_size, &buf->f_blocks); + put_fs_long(s->s_hpfs_n_free, &buf->f_bfree); + put_fs_long(s->s_hpfs_n_free, &buf->f_bavail); + put_fs_long(s->s_hpfs_dirband_size, &buf->f_files); + put_fs_long(s->s_hpfs_n_free_dnodes, &buf->f_ffree); + put_fs_long(254, &buf->f_namelen); +} + +/* + * remount. Don't let read only be turned off. + */ + +static int hpfs_remount_fs(struct super_block *s, int *flags) +{ + if (!(*flags & MS_RDONLY)) + return -EINVAL; + return 0; +} + +/* + * count the dnodes in a directory, and the subdirs. + */ + +static void count_dnodes(struct inode *inode, dnode_secno dno, + unsigned *n_dnodes, unsigned *n_subdirs) +{ + struct quad_buffer_head qbh; + struct dnode *dnode; + struct hpfs_dirent *de; + struct hpfs_dirent *de_end; + + dnode = map_dnode(inode->i_dev, dno, &qbh); + if (!dnode) + return; + de = dnode_first_de(dnode); + de_end = dnode_end_de(dnode); + + (*n_dnodes)++; + + for (; de < de_end; de = de_next_de(de)) { + if (de->down) + count_dnodes(inode, de_down_pointer(de), + n_dnodes, n_subdirs); + if (de->directory && !de->first) + (*n_subdirs)++; + if (de->last || de->length == 0) + break; + } + + brelse4(&qbh); +} + +/* + * count the bits in the free space bit maps + */ + +static unsigned count_bitmap(struct super_block *s) +{ + unsigned n, count, n_bands; + secno *bitmaps; + struct quad_buffer_head qbh; + + /* + * there is one bit map for each 16384 sectors + */ + n_bands = (s->s_hpfs_fs_size + 0x3fff) >> 14; + + /* + * their locations are given in an array pointed to by the super + * block + */ + bitmaps = map_4sectors(s->s_dev, s->s_hpfs_bitmaps, &qbh); + if (!bitmaps) + return 0; + + count = 0; + + /* + * map each one and count the free sectors + */ + for (n = 0; n < n_bands; n++) + if (bitmaps[n] == 0) + printk("HPFS: bit map pointer missing\n"); + else + count += count_one_bitmap(s->s_dev, bitmaps[n]); + + brelse4(&qbh); + return count; +} + +/* + * Read in one bit map, count the bits, return the count. + */ + +static unsigned count_one_bitmap(dev_t dev, secno secno) +{ + struct quad_buffer_head qbh; + char *bits; + unsigned i, count; + + bits = map_4sectors(dev, secno, &qbh); + if (!bits) + return 0; + + count = 0; + + for (i = 0; i < 8 * 2048; i++) + count += (test_bit(i, bits) != 0); + brelse4(&qbh); + + return count; +} + +/* file ops */ + +/* + * read. Read the bytes, put them in buf, return the count. + */ + +static int hpfs_file_read(struct inode *inode, struct file *filp, + char *buf, int count) +{ + unsigned q, r, n, n0; + struct buffer_head *bh; + char *block; + char *start; + + if (inode == 0 || !S_ISREG(inode->i_mode)) + return -EINVAL; + + /* + * truncate count at EOF + */ + if (count > inode->i_size - filp->f_pos) + count = inode->i_size - filp->f_pos; + + start = buf; + while (count > 0) { + /* + * get file sector number, offset in sector, length to end of + * sector + */ + q = filp->f_pos >> 9; + r = filp->f_pos & 511; + n = 512 - r; + + /* + * get length to copy to user buffer + */ + if (n > count) + n = count; + + /* + * read the sector, copy to user + */ + block = map_sector(inode->i_dev, hpfs_bmap(inode, q), &bh); + if (!block) + return -EIO; + + /* + * but first decide if it has \r\n, if the mount option said + * to do that + */ + if (inode->i_hpfs_conv == CONV_AUTO) + inode->i_hpfs_conv = choose_conv(block + r, n); + + if (inode->i_hpfs_conv == CONV_BINARY) { + /* + * regular copy, output length is same as input + * length + */ + memcpy_tofs(buf, block + r, n); + n0 = n; + } + else { + /* + * squeeze out \r, output length varies + */ + n0 = convcpy_tofs(buf, block + r, n); + if (count > inode->i_size - filp->f_pos - n + n0) + count = inode->i_size - filp->f_pos - n + n0; + } + + brelse(bh); + + /* + * advance input n bytes, output n0 bytes + */ + filp->f_pos += n; + buf += n0; + count -= n0; + } + + return buf - start; +} + +/* + * This routine implements conv=auto. Return CONV_BINARY or CONV_TEXT. + */ + +static unsigned choose_conv(unsigned char *p, unsigned len) +{ + unsigned tvote, bvote; + unsigned c; + + tvote = bvote = 0; + + while (len--) { + c = *p++; + if (c < ' ') + if (c == '\r' && len && *p == '\n') + tvote += 10; + else if (c == '\t' || c == '\n'); + else + bvote += 5; + else if (c < '\177') + tvote++; + else + bvote += 5; + } + + if (tvote > bvote) + return CONV_TEXT; + else + return CONV_BINARY; +} + +/* + * This routine implements conv=text. :s/crlf/nl/ + */ + +static unsigned convcpy_tofs(unsigned char *out, unsigned char *in, + unsigned len) +{ + unsigned char *start = out; + + while (len--) { + unsigned c = *in++; + if (c == '\r' && (len == 0 || *in == '\n')); + else + put_fs_byte(c, out++); + } + + return out - start; +} + +/* + * Return the disk sector number containing a file sector. + */ + +static secno hpfs_bmap(struct inode *inode, unsigned file_secno) +{ + unsigned n, disk_secno; + struct fnode *fnode; + struct buffer_head *bh; + + /* + * There is one sector run cached in the inode. See if the sector is + * in it. + */ + + n = file_secno - inode->i_hpfs_file_sec; + if (n < inode->i_hpfs_n_secs) + return inode->i_hpfs_disk_sec + n; + + /* + * No, read the fnode and go find the sector. + */ + + else { + fnode = map_fnode(inode->i_dev, inode->i_ino, &bh); + if (!fnode) + return 0; + disk_secno = bplus_lookup(inode, &fnode->btree, + file_secno, &bh); + brelse(bh); + return disk_secno; + } +} + +/* + * Search allocation tree *b for the given file sector number and return + * the disk sector number. Buffer *bhp has the tree in it, and can be + * reused for subtrees when access to *b is no longer needed. + * *bhp is busy on entry and exit. + */ + +static secno bplus_lookup(struct inode *inode, struct bplus_header *b, + secno file_secno, struct buffer_head **bhp) +{ + int i; + + /* + * A leaf-level tree gives a list of sector runs. Find the one + * containing the file sector we want, cache the map info in the + * inode for later, and return the corresponding disk sector. + */ + + if (!b->internal) { + struct bplus_leaf_node *n = b->u.external; + for (i = 0; i < b->n_used_nodes; i++) { + unsigned t = file_secno - n[i].file_secno; + if (t < n[i].length) { + inode->i_hpfs_file_sec = n[i].file_secno; + inode->i_hpfs_disk_sec = n[i].disk_secno; + inode->i_hpfs_n_secs = n[i].length; + return n[i].disk_secno + t; + } + } + } + + /* + * A non-leaf tree gives a list of subtrees. Find the one containing + * the file sector we want, read it in, and recurse to search it. + */ + + else { + struct bplus_internal_node *n = b->u.internal; + for (i = 0; i < b->n_used_nodes; i++) { + if (file_secno < n[i].file_secno) { + struct anode *anode; + anode_secno ano = n[i].down; + brelse(*bhp); + anode = map_anode(inode->i_dev, ano, bhp); + if (!anode) + break; + return bplus_lookup(inode, &anode->btree, + file_secno, bhp); + } + } + } + + /* + * If we get here there was a hole in the file. As far as I know we + * never do get here, but falling off the end would be indelicate. So + * return a pointer to a handy all-zero sector. This is not a + * reasonable way to handle files with holes if they really do + * happen. + */ + + printk("HPFS: bplus_lookup: sector not found\n"); + return 15; +} + +/* directory ops */ + +/* + * lookup. Search the specified directory for the specified name, set + * *result to the corresponding inode. + * + * lookup uses the inode number to tell read_inode whether it is reading + * the inode of a directory or a file -- file ino's are odd, directory + * ino's are even. read_inode avoids i/o for file inodes; everything + * needed is up here in the directory. (And file fnodes are out in + * the boondocks.) + */ + +static int hpfs_lookup(struct inode *dir, const char *name, int len, + struct inode **result) +{ + struct quad_buffer_head qbh; + struct hpfs_dirent *de; + struct inode *inode; + ino_t ino; + + /* In case of madness */ + + *result = 0; + if (dir == 0) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) + goto bail; + + /* + * Read in the directory entry. "." is there under the name ^A^A . + * Always read the dir even for . and .. in case we need the dates. + */ + + if (name[0] == '.' && len == 1) + de = map_dirent(dir, dir->i_hpfs_dno, "\001\001", 2, &qbh); + else if (name[0] == '.' && name[1] == '.' && len == 2) + de = map_dirent(dir, + fnode_dno(dir->i_dev, dir->i_hpfs_parent_dir), + "\001\001", 2, &qbh); + else + de = map_dirent(dir, dir->i_hpfs_dno, name, len, &qbh); + + /* + * This is not really a bailout, just means file not found. + */ + + if (!de) + goto bail; + + /* + * Get inode number, what we're after. + */ + + if (de->directory) + ino = dir_ino(de->fnode); + else + ino = file_ino(de->fnode); + + /* + * Go find or make an inode. + */ + + if (!(inode = iget(dir->i_sb, ino))) + goto bail1; + + /* + * Fill in the info from the directory if this is a newly created + * inode. + */ + + if (!inode->i_atime) { + inode->i_atime = local_to_gmt(de->read_date); + inode->i_mtime = local_to_gmt(de->write_date); + inode->i_ctime = local_to_gmt(de->creation_date); + if (de->read_only) + inode->i_mode &= ~0222; + if (!de->directory) { + inode->i_size = de->file_size; + /* + * i_blocks should count the fnode and any anodes. + * We count 1 for the fnode and don't bother about + * anodes -- the disk heads are on the directory band + * and we want them to stay there. + */ + inode->i_blocks = 1 + ((inode->i_size + 511) >> 9); + } + } + + brelse4(&qbh); + + /* + * Made it. + */ + + *result = inode; + iput(dir); + return 0; + + /* + * Didn't. + */ + bail1: + brelse4(&qbh); + bail: + iput(dir); + return -ENOENT; +} + +/* + * Compare two counted strings ignoring case. + * HPFS directory order sorts letters as if they're upper case. + */ + +static inline int memcasecmp(const unsigned char *s1, const unsigned char *s2, + unsigned n) +{ + int t; + + if (n != 0) + do { + unsigned c1 = *s1++; + unsigned c2 = *s2++; + if (c1 - 'a' < 26) + c1 -= 040; + if (c2 - 'a' < 26) + c2 -= 040; + if ((t = c1 - c2) != 0) + return t; + } while (--n != 0); + + return 0; +} + +/* + * Search a directory for the given name, return a pointer to its dir entry + * and a pointer to the buffer containing it. + */ + +static struct hpfs_dirent *map_dirent(struct inode *inode, dnode_secno dno, + const unsigned char *name, unsigned len, + struct quad_buffer_head *qbh) +{ + struct dnode *dnode; + struct hpfs_dirent *de; + struct hpfs_dirent *de_end; + int t, l; + + /* + * read the dnode at the root of our subtree + */ + dnode = map_dnode(inode->i_dev, dno, qbh); + if (!dnode) + return 0; + + /* + * get pointers to start and end+1 of dir entries + */ + de = dnode_first_de(dnode); + de_end = dnode_end_de(dnode); + + /* + * look through the entries for the name we're after + */ + for ( ; de < de_end; de = de_next_de(de)) { + + /* + * compare names + */ + l = len < de->namelen ? len : de->namelen; + t = memcasecmp(name, de->name, l); + + /* + * initial substring matches, compare lengths + */ + if (t == 0) { + t = len - de->namelen; + /* bingo */ + if (t == 0) + return de; + } + + /* + * wanted name .lt. dir name => not present. + */ + if (t < 0) { + /* + * if there is a subtree, search it. + */ + if (de->down) { + dnode_secno sub_dno = de_down_pointer(de); + brelse4(qbh); + return map_dirent(inode, sub_dno, + name, len, qbh); + } + else + break; + } + + /* + * de->last is set on the last name in the dnode (it's always + * a "\377" pseudo entry). de->length == 0 means we're about + * to infinite loop. This test does nothing in a well-formed + * dnode. + */ + if (de->last || de->length == 0) + break; + } + + /* + * name not found. + */ + + return 0; +} + +/* + * readdir. Return exactly 1 dirent. (I tried and tried, but currently + * the interface with libc just does not permit more than 1. If it gets + * fixed, throw this out and just walk the tree and write records into + * the user buffer.) + * + * We keep track of our position in the dnode tree with a sort of + * dewey-decimal record of subtree locations. Like so: + * + * (1 (1.1 1.2 1.3) 2 3 (3.1 (3.1.1 3.1.2) 3.2 3.3 (3.3.1)) 4) + * + * Subtrees appear after their file, out of lexical order, + * which would be before their file. It's easier. + * + * A directory can't hold more than 56 files, so 6 bits are used for + * position numbers. If the tree is so deep that the position encoding + * doesn't fit, I'm sure something absolutely fascinating happens. + * + * The actual sequence of f_pos values is + * 0 => . -1 => .. 1 1.1 ... 8.9 9 => files -2 => eof + * + * The directory inode caches one position-to-dnode correspondence so + * we won't have to repeatedly scan the top levels of the tree. + */ + +static int hpfs_readdir(struct inode *inode, struct file *filp, + struct dirent *dirent, int likely_story) +{ + struct quad_buffer_head qbh; + struct hpfs_dirent *de; + int namelen, lc; + ino_t ino; + + if (inode == 0 + || inode->i_sb == 0 + || !S_ISDIR(inode->i_mode)) + return -EBADF; + + lc = inode->i_sb->s_hpfs_lowercase; + + switch (filp->f_pos) { + case 0: + write_one_dirent(dirent, ".", 1, inode->i_ino, lc); + filp->f_pos = -1; + return 1; + + case -1: + write_one_dirent(dirent, "..", 2, + inode->i_hpfs_parent_dir, lc); + filp->f_pos = 1; + return 2; + + case -2: + return 0; + + default: + de = map_pos_dirent(inode, &filp->f_pos, &qbh); + if (!de) { + filp->f_pos = -2; + return 0; + } + + namelen = de->namelen; + if (de->directory) + ino = dir_ino(de->fnode); + else + ino = file_ino(de->fnode); + write_one_dirent(dirent, de->name, namelen, ino, lc); + brelse4(&qbh); + + return namelen; + } +} + +/* + * Send the given name and ino off to the user dirent struct at *dirent. + * Blam it to lowercase if the mount option said to. + * + * Note that Linux d_reclen is the length of the file name, and has nothing + * to do with the length of the dirent record. + */ + +static void write_one_dirent(struct dirent *dirent, const unsigned char *name, + unsigned namelen, ino_t ino, int lowercase) +{ + unsigned n; + + put_fs_long(ino, &dirent->d_ino); + put_fs_word(namelen, &dirent->d_reclen); + + if (lowercase) + for (n = namelen; n != 0;) { + unsigned t = name[--n]; + if (t - 'A' < 26) + t += 040; + put_fs_byte(t, &dirent->d_name[n]); + } + else + memcpy_tofs(dirent->d_name, name, namelen); + + put_fs_byte(0, &dirent->d_name[namelen]); +} + +/* + * Map the dir entry at subtree coordinates given by *posp, and + * increment *posp to point to the following dir entry. + */ + +static struct hpfs_dirent *map_pos_dirent(struct inode *inode, off_t *posp, + struct quad_buffer_head *qbh) +{ + unsigned pos, q, r; + dnode_secno dno; + struct hpfs_dirent *de; + + /* + * Get the position code and split off the rightmost index r + */ + + pos = *posp; + q = pos >> 6; + r = pos & 077; + + /* + * Get the sector address of the dnode + * pointed to by the leading part q + */ + + dno = dir_subdno(inode, q); + if (!dno) + return 0; + + /* + * Get the entry at index r in dnode q + */ + + de = map_nth_dirent(inode->i_dev, dno, r, qbh); + + /* + * If none, we're out of files in this dnode. Ascend. + */ + + if (!de) { + if (q == 0) + return 0; + *posp = q + 1; + return map_pos_dirent(inode, posp, qbh); + } + + /* + * If a subtree is here, descend. + */ + + if (de->down) + *posp = pos << 6 | 1; + else + *posp = pos + 1; + + /* + * Don't return the ^A^A and \377 entries. + */ + + if (de->first || de->last) { + brelse4(qbh); + return map_pos_dirent(inode, posp, qbh); + } + else + return de; +} + +/* + * Return the address of the dnode with subtree coordinates given by pos. + */ + +static dnode_secno dir_subdno(struct inode *inode, unsigned pos) +{ + struct hpfs_dirent *de; + struct quad_buffer_head qbh; + + /* + * 0 is the root dnode + */ + + if (pos == 0) + return inode->i_hpfs_dno; + + /* + * we have one pos->dnode translation cached in the inode + */ + + else if (pos == inode->i_hpfs_dpos) + return inode->i_hpfs_dsubdno; + + /* + * otherwise go look + */ + + else { + unsigned q = pos >> 6; + unsigned r = pos & 077; + dnode_secno dno; + + /* + * dnode at position q + */ + dno = dir_subdno(inode, q); + if (dno == 0) + return 0; + + /* + * entry at index r + */ + de = map_nth_dirent(inode->i_dev, dno, r, &qbh); + if (!de || !de->down) + return 0; + + /* + * get the dnode down pointer + */ + dno = de_down_pointer(de); + brelse4(&qbh); + + /* + * cache it for next time + */ + inode->i_hpfs_dpos = pos; + inode->i_hpfs_dsubdno = dno; + return dno; + } +} + +/* + * Return the dir entry at index n in dnode dno, or 0 if there isn't one + */ + +static struct hpfs_dirent *map_nth_dirent(dev_t dev, dnode_secno dno, + int n, + struct quad_buffer_head *qbh) +{ + int i; + struct hpfs_dirent *de, *de_end; + struct dnode *dnode = map_dnode(dev, dno, qbh); + + de = dnode_first_de(dnode); + de_end = dnode_end_de(dnode); + + for (i = 1; de < de_end; i++, de = de_next_de(de)) { + if (i == n) + return de; + if (de->last || de->length == 0) + break; + } + + brelse4(qbh); + return 0; +} + +static int hpfs_dir_read(struct inode *inode, struct file *filp, + char *buf, int count) +{ + return -EISDIR; +} + +/* Return the dnode pointer in a directory fnode */ + +static dnode_secno fnode_dno(dev_t dev, ino_t ino) +{ + struct buffer_head *bh; + struct fnode *fnode; + dnode_secno dno; + + fnode = map_fnode(dev, ino, &bh); + if (!fnode) + return 0; + + dno = fnode->u.external[0].disk_secno; + brelse(bh); + return dno; +} + +/* Map an fnode into a buffer and return pointers to it and to the buffer. */ + +static struct fnode *map_fnode(dev_t dev, ino_t ino, struct buffer_head **bhp) +{ + struct fnode *fnode; + + if (ino == 0) { + printk("HPFS: missing fnode\n"); + return 0; + } + + fnode = map_sector(dev, ino_secno(ino), bhp); + if (fnode) + if (fnode->magic != FNODE_MAGIC) { + printk("HPFS: map_fnode: bad fnode pointer\n"); + brelse(*bhp); + return 0; + } + return fnode; +} + +/* Map an anode into a buffer and return pointers to it and to the buffer. */ + +static struct anode *map_anode(dev_t dev, unsigned secno, + struct buffer_head **bhp) +{ + struct anode *anode; + + if (secno == 0) { + printk("HPFS: missing anode\n"); + return 0; + } + + anode = map_sector(dev, secno, bhp); + if (anode) + if (anode->magic != ANODE_MAGIC || anode->self != secno) { + printk("HPFS: map_anode: bad anode pointer\n"); + brelse(*bhp); + return 0; + } + return anode; +} + +/* Map a dnode into a buffer and return pointers to it and to the buffer. */ + +static struct dnode *map_dnode(dev_t dev, unsigned secno, + struct quad_buffer_head *qbh) +{ + struct dnode *dnode; + + if (secno == 0) { + printk("HPFS: missing dnode\n"); + return 0; + } + + dnode = map_4sectors(dev, secno, qbh); + if (dnode) + if (dnode->magic != DNODE_MAGIC || dnode->self != secno) { + printk("HPFS: map_dnode: bad dnode pointer\n"); + brelse4(qbh); + return 0; + } + return dnode; +} + +/* Map a sector into a buffer and return pointers to it and to the buffer. */ + +static void *map_sector(dev_t dev, unsigned secno, struct buffer_head **bhp) +{ + struct buffer_head *bh; + + if ((*bhp = bh = bread(dev, secno, 512)) != 0) + return bh->b_data; + else { + printk("HPFS: map_sector: read error\n"); + return 0; + } +} + +/* Map 4 sectors into a 4buffer and return pointers to it and to the buffer. */ + +static void *map_4sectors(dev_t dev, unsigned secno, + struct quad_buffer_head *qbh) +{ + struct buffer_head *bh; + char *data; + + if (secno & 3) { + printk("HPFS: map_4sectors: unaligned read\n"); + return 0; + } + + qbh->data = data = kmalloc(2048, GFP_KERNEL); + if (!data) + goto bail; + + qbh->bh[0] = bh = breada(dev, + secno, secno + 1, secno + 2, secno + 3, -1); + if (!bh) + goto bail0; + memcpy(data, bh->b_data, 512); + + qbh->bh[1] = bh = bread(dev, secno + 1, 512); + if (!bh) + goto bail1; + memcpy(data + 512, bh->b_data, 512); + + qbh->bh[2] = bh = bread(dev, secno + 2, 512); + if (!bh) + goto bail2; + memcpy(data + 2 * 512, bh->b_data, 512); + + qbh->bh[3] = bh = bread(dev, secno + 3, 512); + if (!bh) + goto bail3; + memcpy(data + 3 * 512, bh->b_data, 512); + + return data; + + bail3: + brelse(qbh->bh[2]); + bail2: + brelse(qbh->bh[1]); + bail1: + brelse(qbh->bh[0]); + bail0: + kfree_s(data, 2048); + bail: + printk("HPFS: map_4sectors: read error\n"); + return 0; +} + +/* Deallocate a 4-buffer block */ + +static void brelse4(struct quad_buffer_head *qbh) +{ + brelse(qbh->bh[3]); + brelse(qbh->bh[2]); + brelse(qbh->bh[1]); + brelse(qbh->bh[0]); + kfree_s(qbh->data, 2048); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/inode.c new file mode 100644 index 000000000..0db43c984 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/inode.c @@ -0,0 +1,504 @@ +/* + * linux/fs/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include + +#include + +static struct inode_hash_entry { + struct inode * inode; + int updating; +} hash_table[NR_IHASH]; + +static struct inode * first_inode; +static struct wait_queue * inode_wait = NULL; +static int nr_inodes = 0, nr_free_inodes = 0; + +static inline int const hashfn(dev_t dev, unsigned int i) +{ + return (dev ^ i) % NR_IHASH; +} + +static inline struct inode_hash_entry * const hash(dev_t dev, int i) +{ + return hash_table + hashfn(dev, i); +} + +static void insert_inode_free(struct inode *inode) +{ + inode->i_next = first_inode; + inode->i_prev = first_inode->i_prev; + inode->i_next->i_prev = inode; + inode->i_prev->i_next = inode; + first_inode = inode; +} + +static void remove_inode_free(struct inode *inode) +{ + if (first_inode == inode) + first_inode = first_inode->i_next; + if (inode->i_next) + inode->i_next->i_prev = inode->i_prev; + if (inode->i_prev) + inode->i_prev->i_next = inode->i_next; + inode->i_next = inode->i_prev = NULL; +} + +void insert_inode_hash(struct inode *inode) +{ + struct inode_hash_entry *h; + h = hash(inode->i_dev, inode->i_ino); + + inode->i_hash_next = h->inode; + inode->i_hash_prev = NULL; + if (inode->i_hash_next) + inode->i_hash_next->i_hash_prev = inode; + h->inode = inode; +} + +static void remove_inode_hash(struct inode *inode) +{ + struct inode_hash_entry *h; + h = hash(inode->i_dev, inode->i_ino); + + if (h->inode == inode) + h->inode = inode->i_hash_next; + if (inode->i_hash_next) + inode->i_hash_next->i_hash_prev = inode->i_hash_prev; + if (inode->i_hash_prev) + inode->i_hash_prev->i_hash_next = inode->i_hash_next; + inode->i_hash_prev = inode->i_hash_next = NULL; +} + +static void put_last_free(struct inode *inode) +{ + remove_inode_free(inode); + inode->i_prev = first_inode->i_prev; + inode->i_prev->i_next = inode; + inode->i_next = first_inode; + inode->i_next->i_prev = inode; +} + +void grow_inodes(void) +{ + struct inode * inode; + int i; + + if (!(inode = (struct inode*) get_free_page(GFP_KERNEL))) + return; + + i=PAGE_SIZE / sizeof(struct inode); + nr_inodes += i; + nr_free_inodes += i; + + if (!first_inode) + inode->i_next = inode->i_prev = first_inode = inode++, i--; + + for ( ; i ; i-- ) + insert_inode_free(inode++); +} + +unsigned long inode_init(unsigned long start, unsigned long end) +{ + memset(hash_table, 0, sizeof(hash_table)); + first_inode = NULL; + return start; +} + +static void __wait_on_inode(struct inode *); + +static inline void wait_on_inode(struct inode * inode) +{ + if (inode->i_lock) + __wait_on_inode(inode); +} + +static inline void lock_inode(struct inode * inode) +{ + wait_on_inode(inode); + inode->i_lock = 1; +} + +static inline void unlock_inode(struct inode * inode) +{ + inode->i_lock = 0; + wake_up(&inode->i_wait); +} + +/* + * Note that we don't want to disturb any wait-queues when we discard + * an inode. + * + * Argghh. Got bitten by a gcc problem with inlining: no way to tell + * the compiler that the inline asm function 'memset' changes 'inode'. + * I've been searching for the bug for days, and was getting desperate. + * Finally looked at the assembler output... Grrr. + * + * The solution is the weird use of 'volatile'. Ho humm. Have to report + * it to the gcc lists, and hope we can do this more cleanly some day.. + */ +void clear_inode(struct inode * inode) +{ + struct wait_queue * wait; + + wait_on_inode(inode); + remove_inode_hash(inode); + remove_inode_free(inode); + wait = ((volatile struct inode *) inode)->i_wait; + if (inode->i_count) + nr_free_inodes++; + memset(inode,0,sizeof(*inode)); + ((volatile struct inode *) inode)->i_wait = wait; + insert_inode_free(inode); +} + +int fs_may_mount(dev_t dev) +{ + struct inode * inode, * next; + int i; + + next = first_inode; + for (i = nr_inodes ; i > 0 ; i--) { + inode = next; + next = inode->i_next; /* clear_inode() changes the queues.. */ + if (inode->i_dev != dev) + continue; + if (inode->i_count || inode->i_dirt || inode->i_lock) + return 0; + clear_inode(inode); + } + return 1; +} + +int fs_may_umount(dev_t dev, struct inode * mount_root) +{ + struct inode * inode; + int i; + + inode = first_inode; + for (i=0 ; i < nr_inodes ; i++, inode = inode->i_next) { + if (inode->i_dev != dev || !inode->i_count) + continue; + if (inode == mount_root && inode->i_count == 1) + continue; + return 0; + } + return 1; +} + +int fs_may_remount_ro(dev_t dev) +{ + struct file * file; + int i; + + /* Check that no files are currently opened for writing. */ + for (file = first_file, i=0; if_next) { + if (!file->f_count || !file->f_inode || + file->f_inode->i_dev != dev) + continue; + if (S_ISREG(file->f_inode->i_mode) && (file->f_mode & 2)) + return 0; + } + return 1; +} + +static void write_inode(struct inode * inode) +{ + if (!inode->i_dirt) + return; + wait_on_inode(inode); + if (!inode->i_dirt) + return; + if (!inode->i_sb || !inode->i_sb->s_op || !inode->i_sb->s_op->write_inode) { + inode->i_dirt = 0; + return; + } + inode->i_lock = 1; + inode->i_sb->s_op->write_inode(inode); + unlock_inode(inode); +} + +static void read_inode(struct inode * inode) +{ + lock_inode(inode); + if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->read_inode) + inode->i_sb->s_op->read_inode(inode); + unlock_inode(inode); +} + +/* + * notify_change is called for inode-changing operations such as + * chown, chmod, utime, and truncate. It is guaranteed (unlike + * write_inode) to be called from the context of the user requesting + * the change. It is not called for ordinary access-time updates. + * NFS uses this to get the authentication correct. -- jrs + */ + +int notify_change(int flags, struct inode * inode) +{ + if (inode->i_sb && inode->i_sb->s_op && + inode->i_sb->s_op->notify_change) + return inode->i_sb->s_op->notify_change(flags, inode); + return 0; +} + +/* + * bmap is needed for demand-loading and paging: if this function + * doesn't exist for a filesystem, then those things are impossible: + * executables cannot be run from the filesystem etc... + * + * This isn't as bad as it sounds: the read-routines might still work, + * so the filesystem would be otherwise ok (for example, you might have + * a DOS filesystem, which doesn't lend itself to bmap very well, but + * you could still transfer files to/from the filesystem) + */ +int bmap(struct inode * inode, int block) +{ + if (inode->i_op && inode->i_op->bmap) + return inode->i_op->bmap(inode,block); + return 0; +} + +void invalidate_inodes(dev_t dev) +{ + struct inode * inode, * next; + int i; + + next = first_inode; + for(i = nr_inodes ; i > 0 ; i--) { + inode = next; + next = inode->i_next; /* clear_inode() changes the queues.. */ + if (inode->i_dev != dev) + continue; + if (inode->i_count || inode->i_dirt || inode->i_lock) { + printk("VFS: inode busy on removed device %d/%d\n", MAJOR(dev), MINOR(dev)); + continue; + } + clear_inode(inode); + } +} + +void sync_inodes(dev_t dev) +{ + int i; + struct inode * inode; + + inode = first_inode; + for(i = 0; i < nr_inodes*2; i++, inode = inode->i_next) { + if (dev && inode->i_dev != dev) + continue; + wait_on_inode(inode); + if (inode->i_dirt) + write_inode(inode); + } +} + +void iput(struct inode * inode) +{ + if (!inode) + return; + wait_on_inode(inode); + if (!inode->i_count) { + printk("VFS: iput: trying to free free inode\n"); + printk("VFS: device %d/%d, inode %lu, mode=0%07o\n", + MAJOR(inode->i_rdev), MINOR(inode->i_rdev), + inode->i_ino, inode->i_mode); + return; + } + if (inode->i_pipe) + wake_up_interruptible(&PIPE_WAIT(*inode)); +repeat: + if (inode->i_count>1) { + inode->i_count--; + return; + } + wake_up(&inode_wait); + if (inode->i_pipe) { + unsigned long page = (unsigned long) PIPE_BASE(*inode); + PIPE_BASE(*inode) = NULL; + free_page(page); + } + if (inode->i_sb && inode->i_sb->s_op && inode->i_sb->s_op->put_inode) { + inode->i_sb->s_op->put_inode(inode); + if (!inode->i_nlink) + return; + } + if (inode->i_dirt) { + write_inode(inode); /* we can sleep - so do again */ + wait_on_inode(inode); + goto repeat; + } + inode->i_count--; + nr_free_inodes++; + return; +} + +struct inode * get_empty_inode(void) +{ + struct inode * inode, * best; + int i; + + if (nr_inodes < NR_INODE && nr_free_inodes < (nr_inodes >> 2)) + grow_inodes(); +repeat: + inode = first_inode; + best = NULL; + for (i = 0; ii_next, i++) { + if (!inode->i_count) { + if (!best) + best = inode; + if (!inode->i_dirt && !inode->i_lock) { + best = inode; + break; + } + } + } + if (!best || best->i_dirt || best->i_lock) + if (nr_inodes < NR_INODE) { + grow_inodes(); + goto repeat; + } + inode = best; + if (!inode) { + printk("VFS: No free inodes - contact Linus\n"); + sleep_on(&inode_wait); + goto repeat; + } + if (inode->i_lock) { + wait_on_inode(inode); + goto repeat; + } + if (inode->i_dirt) { + write_inode(inode); + goto repeat; + } + if (inode->i_count) + goto repeat; + clear_inode(inode); + inode->i_count = 1; + inode->i_nlink = 1; + nr_free_inodes--; + if (nr_free_inodes < 0) { + printk ("VFS: get_empty_inode: bad free inode count.\n"); + nr_free_inodes = 0; + } + return inode; +} + +struct inode * get_pipe_inode(void) +{ + struct inode * inode; + extern struct inode_operations pipe_inode_operations; + + if (!(inode = get_empty_inode())) + return NULL; + if (!(PIPE_BASE(*inode) = (char*) __get_free_page(GFP_USER))) { + iput(inode); + return NULL; + } + inode->i_op = &pipe_inode_operations; + inode->i_count = 2; /* sum of readers/writers */ + PIPE_WAIT(*inode) = NULL; + PIPE_START(*inode) = PIPE_LEN(*inode) = 0; + PIPE_RD_OPENERS(*inode) = PIPE_WR_OPENERS(*inode) = 0; + PIPE_READERS(*inode) = PIPE_WRITERS(*inode) = 1; + PIPE_LOCK(*inode) = 0; + inode->i_pipe = 1; + inode->i_mode |= S_IFIFO | S_IRUSR | S_IWUSR; + inode->i_uid = current->euid; + inode->i_gid = current->egid; + inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; + return inode; +} + +struct inode * iget(struct super_block * sb,int nr) +{ + return __iget(sb,nr,1); +} + +struct inode * __iget(struct super_block * sb, int nr, int crossmntp) +{ + static struct wait_queue * update_wait = NULL; + struct inode_hash_entry * h; + struct inode * inode; + struct inode * empty = NULL; + + if (!sb) + panic("VFS: iget with sb==NULL"); + h = hash(sb->s_dev, nr); +repeat: + for (inode = h->inode; inode ; inode = inode->i_hash_next) + if (inode->i_dev == sb->s_dev && inode->i_ino == nr) + goto found_it; + if (!empty) { + h->updating++; + empty = get_empty_inode(); + if (!--h->updating) + wake_up(&update_wait); + if (empty) + goto repeat; + return (NULL); + } + inode = empty; + inode->i_sb = sb; + inode->i_dev = sb->s_dev; + inode->i_ino = nr; + inode->i_flags = sb->s_flags; + put_last_free(inode); + insert_inode_hash(inode); + read_inode(inode); + goto return_it; + +found_it: + if (!inode->i_count) + nr_free_inodes--; + inode->i_count++; + wait_on_inode(inode); + if (inode->i_dev != sb->s_dev || inode->i_ino != nr) { + printk("Whee.. inode changed from under us. Tell Linus\n"); + iput(inode); + goto repeat; + } + if (crossmntp && inode->i_mount) { + struct inode * tmp = inode->i_mount; + tmp->i_count++; + iput(inode); + inode = tmp; + wait_on_inode(inode); + } + if (empty) + iput(empty); + +return_it: + while (h->updating) + sleep_on(&update_wait); + return inode; +} + +/* + * The "new" scheduling primitives (new as of 0.97 or so) allow this to + * be done without disabling interrupts (other than in the actual queue + * updating things: only a couple of 386 instructions). This should be + * much better for interrupt latency. + */ +static void __wait_on_inode(struct inode * inode) +{ + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&inode->i_wait, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (inode->i_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&inode->i_wait, &wait); + current->state = TASK_RUNNING; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ioctl.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ioctl.c new file mode 100644 index 000000000..515203f73 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/ioctl.c @@ -0,0 +1,99 @@ +/* + * linux/fs/ioctl.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include /* for f_flags values */ + +static int file_ioctl(struct file *filp,unsigned int cmd,unsigned long arg) +{ + int error; + int block; + + switch (cmd) { + case FIBMAP: + if (filp->f_inode->i_op == NULL) + return -EBADF; + if (filp->f_inode->i_op->bmap == NULL) + return -EINVAL; + error = verify_area(VERIFY_WRITE,(void *) arg,4); + if (error) + return error; + block = get_fs_long((long *) arg); + block = filp->f_inode->i_op->bmap(filp->f_inode,block); + put_fs_long(block,(long *) arg); + return 0; + case FIGETBSZ: + if (filp->f_inode->i_sb == NULL) + return -EBADF; + error = verify_area(VERIFY_WRITE,(void *) arg,4); + if (error) + return error; + put_fs_long(filp->f_inode->i_sb->s_blocksize, + (long *) arg); + return 0; + case FIONREAD: + error = verify_area(VERIFY_WRITE,(void *) arg,4); + if (error) + return error; + put_fs_long(filp->f_inode->i_size - filp->f_pos, + (long *) arg); + return 0; + } + if (filp->f_op && filp->f_op->ioctl) + return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg); + return -EINVAL; +} + + +asmlinkage int sys_ioctl(unsigned int fd, unsigned int cmd, unsigned long arg) +{ + struct file * filp; + int on; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + switch (cmd) { + case FIOCLEX: + FD_SET(fd, ¤t->close_on_exec); + return 0; + + case FIONCLEX: + FD_CLR(fd, ¤t->close_on_exec); + return 0; + + case FIONBIO: + on = get_fs_long((unsigned long *) arg); + if (on) + filp->f_flags |= O_NONBLOCK; + else + filp->f_flags &= ~O_NONBLOCK; + return 0; + + case FIOASYNC: /* O_SYNC is not yet implemented, + but it's here for completeness. */ + on = get_fs_long ((unsigned long *) arg); + if (on) + filp->f_flags |= O_SYNC; + else + filp->f_flags &= ~O_SYNC; + return 0; + + default: + if (filp->f_inode && S_ISREG(filp->f_inode->i_mode)) + return file_ioctl(filp,cmd,arg); + + if (filp->f_op && filp->f_op->ioctl) + return filp->f_op->ioctl(filp->f_inode, filp, cmd,arg); + + return -EINVAL; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/Makefile new file mode 100644 index 000000000..a780af479 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux isofs-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= namei.o inode.o file.o dir.o util.o rock.o symlink.o + +isofs.o: $(OBJS) + $(LD) -r -o isofs.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/dir.c new file mode 100644 index 000000000..ed5884ab5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/dir.c @@ -0,0 +1,239 @@ +/* + * linux/fs/isofs/dir.c + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + * + * isofs directory handling functions + */ + +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +static int isofs_readdir(struct inode *, struct file *, struct dirent *, int); + +static struct file_operations isofs_dir_operations = { + NULL, /* lseek - default */ + NULL, /* read */ + NULL, /* write - bad */ + isofs_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations isofs_dir_inode_operations = { + &isofs_dir_operations, /* default directory file-ops */ + NULL, /* create */ + isofs_lookup, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + isofs_bmap, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/* This is used to speed up lookup. Without this we would need to +make a linear search of the directory to find the file that the +directory read just returned. This is a single element cache. */ + +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; + struct buffer_head * bh; + void * cpnt = NULL; + unsigned int old_offset; + int dlen, rrflag; + char * dpnt; + struct iso_directory_record * de; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + + 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); +#endif + 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 (*((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)>>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 */ + + old_offset = offset; + offset += *((unsigned char *) de); + filp->f_pos += *((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 = filp->f_pos & (bufsize - 1); + block = isofs_bmap(inode,(filp->f_pos)>> bufbits); + if (!block + || !(bh = bread(inode->i_dev,block,bufsize))) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + return 0; + }; + memcpy((char *)cpnt+bufsize, bh->b_data, bufsize); + } + + /* Handle the case of the '.' directory */ + + rrflag = 0; + i = 1; + if (de->name_len[0] == 1 && de->name[0] == 0) { + put_fs_byte('.',dirent->d_name); + inode_number = inode->i_ino; + dpnt = "."; + } + + /* Handle the case of the '..' directory */ + + else if (de->name_len[0] == 1 && de->name[0] == 1) { + put_fs_byte('.',dirent->d_name); + put_fs_byte('.',dirent->d_name+1); + i = 2; + dpnt = ".."; + 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; + + /* This should never happen, but who knows. Try to be forgiving */ + if(inode_number == -1) { + inode_number = + isofs_lookup_grandparent(inode, + find_rock_ridge_relocation(de, inode)); + if(inode_number == -1){ /* Should never happen */ + printk("Backlink not properly set.\n"); + goto out; + }; + } + } + + /* Handle everything else. Do name translation if there + is no Rock Ridge NM field. */ + + else { + dlen = de->name_len[0]; + dpnt = de->name; + i = dlen; + rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, inode); + if (rrflag) { + if (rrflag == -1) { /* This is a rock ridge reloc dir */ + if (cpnt) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + cpnt = NULL; + }; + continue; + }; + i = dlen; + } + else + if(inode->i_sb->u.isofs_sb.s_mapping == 'n') + for (i = 0; i < dlen && i < NAME_MAX; i++) { + if (!(c = dpnt[i])) break; + if (c >= 'A' && c <= 'Z') c |= 0x20; /* lower case */ + if (c == ';' && i == dlen-2 && de->name[i+1] == '1') + break; /* Drop trailing ';1' */ + if (c == ';') c = '.'; /* Convert remaining ';' to '.' */ + dpnt[i] = c; + }; + + for(j=0; jd_name); /* And save it */ + }; +#if 0 + printk("Nchar: %d\n",i); +#endif + + if (i && i+1 < sizeof(cache.filename)) { + cache.ino = inode_number; + cache.dir = inode->i_ino; + cache.dev = inode->i_dev; + strncpy(cache.filename, dpnt, i); + cache.dlen = dlen; + }; + + if (rrflag) kfree(dpnt); + if (cpnt) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + cpnt = NULL; + }; + + if (i) { + put_fs_long(inode_number, &dirent->d_ino); + put_fs_byte(0,i+dirent->d_name); + put_fs_word(i,&dirent->d_reclen); + brelse(bh); + return i; + } + } + /* 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); + brelse(bh); + return 0; +} + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/file.c new file mode 100644 index 000000000..35d501a29 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/file.c @@ -0,0 +1,265 @@ +/* + * linux/fs/isofs/file.c + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + * + * isofs regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +static int isofs_file_read(struct inode *, struct file *, char *, int); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the isofs filesystem. + */ +static struct file_operations isofs_file_operations = { + NULL, /* lseek - default */ + isofs_file_read, /* read */ + NULL, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + NULL /* fsync */ +}; + +struct inode_operations isofs_file_inode_operations = { + &isofs_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + isofs_bmap, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +/* This is a heuristic to determine if a file is text of binary. If it + * is text, then we translate all 0x0d characters to spaces. If the 0x0d + * character is not preceeded or followed by a 0x0a, then we turn it into + * a 0x0a. A control-Z is also turned into a linefeed. + */ + +static inline void unixify_text_buffer(char * buffer, int chars, int mode) +{ + while(chars--){ + if(*buffer == 0x1a) *buffer = 0x0a; + if(*buffer == 0x0d){ + if(mode == ISOFS_FILE_TEXT_M) *buffer = 0x0a; + if(mode == ISOFS_FILE_TEXT) *buffer = ' '; + } + buffer++; + } +} + +/*This function determines if a given file has a DOS-like text format or not*/ + +static void isofs_determine_filetype(struct inode * inode) +{ + int block; + int result, i; + struct buffer_head * bh; + unsigned char * pnt; + + block = isofs_bmap(inode,0); + if (block && (bh = bread(inode->i_dev,block, ISOFS_BUFFER_SIZE(inode)))) { + pnt = (unsigned char *) bh->b_data; + result = ISOFS_FILE_TEXT_M; + for(i=0;i<(inode->i_size < ISOFS_BUFFER_SIZE(inode) ? inode->i_size : ISOFS_BUFFER_SIZE(inode)); + i++,pnt++){ + if(*pnt & 0x80) {result = ISOFS_FILE_BINARY; break;}; + if(*pnt >= 0x20 || *pnt == 0x1a) continue; + if(*pnt == 0x0a) {result = ISOFS_FILE_TEXT; continue;}; + if(*pnt >= 0x9 && *pnt <= 0x0d) continue; + result = ISOFS_FILE_BINARY; + break; + } + brelse(bh); + inode->u.isofs_i.i_file_format = result; + } +} + +static int isofs_file_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int read,left,chars; + int block, blocks, offset; + int bhrequest; + int ra_blocks, max_block, nextblock; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + + if (!inode) { + printk("isofs_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) { + printk("isofs_file_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + if (inode->u.isofs_i.i_file_format == ISOFS_FILE_UNKNOWN) + isofs_determine_filetype(inode); + if (filp->f_pos > inode->i_size) + left = 0; + else + left = inode->i_size - filp->f_pos; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = filp->f_pos >> ISOFS_BUFFER_BITS(inode); + offset = filp->f_pos & (ISOFS_BUFFER_SIZE(inode)-1); + blocks = (left + offset + ISOFS_BUFFER_SIZE(inode) - 1) / ISOFS_BUFFER_SIZE(inode); + bhb = bhe = buflist; + + ra_blocks = read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9); + max_block = (inode->i_size + BLOCK_SIZE - 1)/BLOCK_SIZE; + nextblock = -1; + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk. + + This routine is optimized to make maximum use of the various + buffers and caches. */ + + do { + bhrequest = 0; + while (blocks) { + int uptodate; + --blocks; + *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode)); + uptodate = 1; + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + nextblock = (*bhb)->b_blocknr + 1; + }; + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing. */ + if(bhrequest == 0 && uptodate) break; + + if (bhb == bhe) + break; + } + + if(blocks == 0 && bhrequest && filp->f_reada && bhb != bhe) { + /* If we are going to read something anyways, add in the + read-ahead blocks */ + while(ra_blocks){ + if (block >= max_block) break; + if(bhrequest == NBUF) break; /* Block full */ + --ra_blocks; + *bhb = getblk(inode->i_dev,isofs_bmap(inode, block++), ISOFS_BUFFER_SIZE(inode)); + + if (*bhb && !(*bhb)->b_uptodate) { + if((*bhb)->b_blocknr != nextblock) { + brelse(*bhb); + break; + }; + nextblock = (*bhb)->b_blocknr + 1; + bhreq[bhrequest++] = *bhb; + }; + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + if (bhb == bhe) + break; + }; + }; + /* Now request them all */ + if (bhrequest) + ll_rw_block(READ, bhrequest, bhreq); + + do{ /* Finish off all I/O that has actually completed */ + if (*bhe) {/* test for valid buffer */ + wait_on_buffer(*bhe); + if (!(*bhe)->b_uptodate) { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + + if (left < ISOFS_BUFFER_SIZE(inode) - offset) + chars = left; + else + chars = ISOFS_BUFFER_SIZE(inode) - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + if (inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT || + inode->u.isofs_i.i_file_format == ISOFS_FILE_TEXT_M) + unixify_text_buffer(offset+(*bhe)->b_data, + chars, inode->u.isofs_i.i_file_format); + memcpy_tofs(buf,offset+(*bhe)->b_data,chars); + brelse(*bhe); + buf += chars; + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while( bhe != bhb && (*bhe == 0 || !(*bhe)->b_lock) && + (left > 0)); + } while (left > 0); + +/* Release the read-ahead blocks */ + while (bhe != bhb) { + if (*bhe) brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + }; + + filp->f_reada = 1; + + if (!read) + return -EIO; + return read; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/inode.c new file mode 100644 index 000000000..d800d59ff --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/inode.c @@ -0,0 +1,685 @@ +/* + * linux/fs/isofs/inode.c + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#if defined(CONFIG_BLK_DEV_SR) +extern int check_cdrom_media_change(int, int); +#endif +#if defined(CONFIG_CDU31A) +extern int check_cdu31a_media_change(int, int); +#endif +#if defined(CONFIG_MCD) +extern int check_mcd_media_change(int, int); +#endif +#if defined (CONFIG_SBPCD) +extern int check_sbpcd_media_change(int, int); +#endif CONFIG_SBPCD + +#ifdef LEAK_CHECK +static int check_malloc = 0; +static int check_bread = 0; +#endif + +void isofs_put_super(struct super_block *sb) +{ + lock_super(sb); + +#ifdef LEAK_CHECK + printk("Outstanding mallocs:%d, outstanding buffers: %d\n", + check_malloc, check_bread); +#endif + sb->s_dev = 0; + unlock_super(sb); + return; +} + +static struct super_operations isofs_sops = { + isofs_read_inode, + NULL, /* notify_change */ + NULL, /* write_inode */ + NULL, /* put_inode */ + isofs_put_super, + NULL, /* write_super */ + isofs_statfs, + NULL +}; + + + +static int parse_options(char *options,char *map,char *conversion, char * rock, char * cruft, unsigned int * blocksize) +{ + char *this_char,*value; + + *map = 'n'; + *rock = 'y'; + *cruft = 'n'; + *conversion = 'a'; + *blocksize = 1024; + if (!options) return 1; + for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { + if (strncmp(this_char,"norock",6) == 0) { + *rock = 'n'; + continue; + }; + if (strncmp(this_char,"cruft",5) == 0) { + *cruft = 'y'; + continue; + }; + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"map") && value) { + if (value[0] && !value[1] && strchr("on",*value)) + *map = *value; + else if (!strcmp(value,"off")) *map = 'o'; + else if (!strcmp(value,"normal")) *map = 'n'; + else return 0; + } + else if (!strcmp(this_char,"conv") && value) { + if (value[0] && !value[1] && strchr("bta",*value)) + *conversion = *value; + else if (!strcmp(value,"binary")) *conversion = 'b'; + else if (!strcmp(value,"text")) *conversion = 't'; + else if (!strcmp(value,"mtext")) *conversion = 'm'; + else if (!strcmp(value,"auto")) *conversion = 'a'; + else return 0; + } + else if (!strcmp(this_char,"block") && value) { + char * vpnt = value; + unsigned int ivalue; + ivalue = 0; + while(*vpnt){ + if(*vpnt < '0' || *vpnt > '9') break; + ivalue = ivalue * 10 + (*vpnt - '0'); + vpnt++; + }; + if (*vpnt) return 0; + if (ivalue != 1024 && ivalue != 2048) return 0; + *blocksize = ivalue; + } + else return 0; + } + return 1; +} + +struct super_block *isofs_read_super(struct super_block *s,void *data, + int silent) +{ + struct buffer_head *bh; + int iso_blknum; + unsigned int blocksize, blocksize_bits; + int high_sierra; + int dev=s->s_dev; + struct iso_volume_descriptor *vdp; + struct hs_volume_descriptor *hdp; + + struct iso_primary_descriptor *pri = NULL; + struct hs_primary_descriptor *h_pri = NULL; + + struct iso_directory_record *rootp; + + char map, conversion, rock, cruft; + + if (!parse_options((char *) data,&map,&conversion, &rock, &cruft, &blocksize)) { + s->s_dev = 0; + return NULL; + } + + blocksize_bits = 0; + { + int i = blocksize; + while (i != 1){ + blocksize_bits++; + i >>=1; + }; + }; + set_blocksize(dev, blocksize); + + lock_super(s); + + s->u.isofs_sb.s_high_sierra = high_sierra = 0; /* default is iso9660 */ + + for (iso_blknum = 16; iso_blknum < 100; iso_blknum++) { + if (!(bh = bread(dev, iso_blknum << (ISOFS_BLOCK_BITS-blocksize_bits), blocksize))) { + s->s_dev=0; + printk("isofs_read_super: bread failed, dev 0x%x iso_blknum %d\n", + dev, iso_blknum); + unlock_super(s); + return NULL; + } + + vdp = (struct iso_volume_descriptor *)bh->b_data; + hdp = (struct hs_volume_descriptor *)bh->b_data; + + + if (strncmp (hdp->id, HS_STANDARD_ID, sizeof hdp->id) == 0) { + if (isonum_711 (hdp->type) != ISO_VD_PRIMARY) + goto out; + if (isonum_711 (hdp->type) == ISO_VD_END) + goto out; + + s->u.isofs_sb.s_high_sierra = 1; + high_sierra = 1; + rock = 'n'; + h_pri = (struct hs_primary_descriptor *)vdp; + break; + }; + + if (strncmp (vdp->id, ISO_STANDARD_ID, sizeof vdp->id) == 0) { + if (isonum_711 (vdp->type) != ISO_VD_PRIMARY) + goto out; + if (isonum_711 (vdp->type) == ISO_VD_END) + goto out; + + pri = (struct iso_primary_descriptor *)vdp; + break; + }; + + brelse(bh); + } + if(iso_blknum == 100) { + if (!silent) + printk("Unable to identify CD-ROM format.\n"); + s->s_dev = 0; + unlock_super(s); + return NULL; + }; + + + if(high_sierra){ + rootp = (struct iso_directory_record *) h_pri->root_directory_record; + if (isonum_723 (h_pri->volume_set_size) != 1) { + printk("Multi-volume disks not (yet) supported.\n"); + goto out; + }; + s->u.isofs_sb.s_nzones = isonum_733 (h_pri->volume_space_size); + s->u.isofs_sb.s_log_zone_size = isonum_723 (h_pri->logical_block_size); + s->u.isofs_sb.s_max_size = isonum_733(h_pri->volume_space_size); + } else { + rootp = (struct iso_directory_record *) pri->root_directory_record; + if (isonum_723 (pri->volume_set_size) != 1) { + printk("Multi-volume disks not (yet) supported.\n"); + goto out; + }; + s->u.isofs_sb.s_nzones = isonum_733 (pri->volume_space_size); + s->u.isofs_sb.s_log_zone_size = isonum_723 (pri->logical_block_size); + s->u.isofs_sb.s_max_size = isonum_733(pri->volume_space_size); + } + + s->u.isofs_sb.s_ninodes = 0; /* No way to figure this out easily */ + + s->u.isofs_sb.s_firstdatazone = isonum_733( rootp->extent) << + (ISOFS_BLOCK_BITS - blocksize_bits); + s->s_magic = ISOFS_SUPER_MAGIC; + + /* The CDROM is read-only, has no nodes (devices) on it, and since + all of the files appear to be owned by root, we really do not want + to allow suid. (suid or devices will not show up unless we have + Rock Ridge extensions) */ + + s->s_flags = MS_RDONLY /* | MS_NODEV | MS_NOSUID */; + + if(s->u.isofs_sb.s_log_zone_size != (1 << ISOFS_BLOCK_BITS)) { + printk("1 <u.isofs_sb.s_max_size, + s->u.isofs_sb.s_log_zone_size); + printk("First datazone:%ld Root inode number %d\n", + s->u.isofs_sb.s_firstdatazone, + isonum_733 (rootp->extent) << ISOFS_BLOCK_BITS); + if(high_sierra) printk("Disc in High Sierra format.\n"); + unlock_super(s); + /* set up enough so that it can read an inode */ + + s->s_dev = dev; + s->s_op = &isofs_sops; + s->u.isofs_sb.s_mapping = map; + s->u.isofs_sb.s_rock = (rock == 'y' ? 1 : 0); + s->u.isofs_sb.s_conversion = conversion; + s->u.isofs_sb.s_cruft = cruft; + s->s_blocksize = blocksize; + s->s_blocksize_bits = blocksize_bits; + s->s_mounted = iget(s, isonum_733 (rootp->extent) << ISOFS_BLOCK_BITS); + unlock_super(s); + + if (!(s->s_mounted)) { + s->s_dev=0; + printk("get root inode failed\n"); + return NULL; + } +#if defined(CONFIG_BLK_DEV_SR) && defined(CONFIG_SCSI) + if (MAJOR(s->s_dev) == SCSI_CDROM_MAJOR) { + /* Check this one more time. */ + if(check_cdrom_media_change(s->s_dev, 0)) + goto out; + } +#endif +#if defined(CONFIG_CDU31A) + if (MAJOR(s->s_dev) == CDU31A_CDROM_MAJOR) { + /* Check this one more time. */ + if(check_cdu31a_media_change(s->s_dev, 0)) + goto out; + } +#endif +#if defined(CONFIG_MCD) + if (MAJOR(s->s_dev) == MITSUMI_CDROM_MAJOR) { + /* Check this one more time. */ + if(check_mcd_media_change(s->s_dev, 0)) + goto out; + } +#endif +#if defined(CONFIG_SBPCD) + if (MAJOR(s->s_dev) == MATSUSHITA_CDROM_MAJOR) { + if (check_sbpcd_media_change(s->s_dev,0)) + goto out; + }; +#endif CONFIG_SBPCD + + return s; + out: /* Kick out for various error conditions */ + brelse(bh); + s->s_dev = 0; + unlock_super(s); + return NULL; +} + +void isofs_statfs (struct super_block *sb, struct statfs *buf) +{ + put_fs_long(ISOFS_SUPER_MAGIC, &buf->f_type); + put_fs_long(1 << ISOFS_BLOCK_BITS, &buf->f_bsize); + put_fs_long(sb->u.isofs_sb.s_nzones, &buf->f_blocks); + put_fs_long(0, &buf->f_bfree); + put_fs_long(0, &buf->f_bavail); + put_fs_long(sb->u.isofs_sb.s_ninodes, &buf->f_files); + put_fs_long(0, &buf->f_ffree); + put_fs_long(NAME_MAX, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ +} + +int isofs_bmap(struct inode * inode,int block) +{ + + if (block<0) { + printk("_isofs_bmap: block<0"); + return 0; + } + return inode->u.isofs_i.i_first_extent + 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; + int high_sierra; + int block; + int i; + + block = inode->i_ino >> ISOFS_BUFFER_BITS(inode); + if (!(bh=bread(inode->i_dev,block, bufsize))) { + printk("unable to read i-node block"); + goto fail; + }; + + 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 & (bufsize - 1)) + *pnt > bufsize){ + cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL); + memcpy(cpnt, bh->b_data, bufsize); + brelse(bh); + if (!(bh = bread(inode->i_dev,++block, bufsize))) { + kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS); + printk("unable to read i-node block"); + goto fail; + }; + memcpy((char *)cpnt + bufsize, bh->b_data, bufsize); + pnt = ((unsigned char *) cpnt + + (inode->i_ino & (bufsize - 1))); + raw_inode = ((struct iso_directory_record *) pnt); + }; + + inode->i_mode = S_IRUGO; /* Everybody gets to read the file. */ + inode->i_nlink = 1; + + if (raw_inode->flags[-high_sierra] & 2) { + inode->i_mode = S_IRUGO | S_IXUGO | S_IFDIR; + inode->i_nlink = 2; /* There are always at least 2. It is + hard to figure out what is correct*/ + } else { + inode->i_mode = S_IRUGO; /* Everybody gets to read the file. */ + inode->i_nlink = 1; + inode->i_mode |= S_IFREG; +/* If there are no periods in the name, then set the execute permission bit */ + for(i=0; i< raw_inode->name_len[0]; i++) + if(raw_inode->name[i]=='.' || raw_inode->name[i]==';') + break; + if(i == raw_inode->name_len[0] || raw_inode->name[i] == ';') + inode->i_mode |= S_IXUGO; /* execute permission */ + }; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_size = isonum_733 (raw_inode->size); + + /* There are defective discs out there - we do this to protect + ourselves. A cdrom will never contain more than 700Mb */ + if((inode->i_size < 0 || inode->i_size > 700000000) && + inode->i_sb->u.isofs_sb.s_cruft == 'n') { + printk("Warning: defective cdrom. Enabling \"cruft\" mount option.\n"); + inode->i_sb->u.isofs_sb.s_cruft = 'y'; + }; + +/* Some dipshit decided to store some other bit of information in the high + byte of the file length. Catch this and holler. WARNING: this will make + it impossible for a file to be > 16Mb on the CDROM!!!*/ + + if(inode->i_sb->u.isofs_sb.s_cruft == 'y' && + inode->i_size & 0xff000000){ +/* printk("Illegal format on cdrom. Pester manufacturer.\n"); */ + inode->i_size &= 0x00ffffff; + }; + + if (raw_inode->interleave[0]) { + printk("Interleaved files not (yet) supported.\n"); + inode->i_size = 0; + }; + +#ifdef DEBUG + /* I have no idea what extended attributes are used for, so + we will flag it for now */ + if(raw_inode->ext_attr_length[0] != 0){ + printk("Extended attributes present for ISO file (%ld).\n", + inode->i_ino); + } +#endif + + /* I have no idea what file_unit_size is used for, so + we will flag it for now */ + if(raw_inode->file_unit_size[0] != 0){ + printk("File unit size != 0 for ISO file (%ld).\n",inode->i_ino); + } + + /* I have no idea what other flag bits are used for, so + we will flag it for now */ + if((raw_inode->flags[-high_sierra] & ~2)!= 0){ + printk("Unusual flag settings for ISO file (%ld %x).\n", + inode->i_ino, raw_inode->flags[-high_sierra]); + } + +#ifdef DEBUG + printk("Get inode %d: %d %d: %d\n",inode->i_ino, block, + ((int)pnt) & 0x3ff, inode->i_size); +#endif + + inode->i_mtime = inode->i_atime = inode->i_ctime = + iso_date(raw_inode->date, high_sierra); + + inode->u.isofs_i.i_first_extent = isonum_733 (raw_inode->extent) << + (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(inode)); + + inode->u.isofs_i.i_backlink = 0xffffffff; /* Will be used for previous directory */ + switch (inode->i_sb->u.isofs_sb.s_conversion){ + case 'a': + inode->u.isofs_i.i_file_format = ISOFS_FILE_UNKNOWN; /* File type */ + break; + case 'b': + inode->u.isofs_i.i_file_format = ISOFS_FILE_BINARY; /* File type */ + break; + case 't': + inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT; /* File type */ + break; + case 'm': + inode->u.isofs_i.i_file_format = ISOFS_FILE_TEXT_M; /* File type */ + break; + }; + + +/* Now test for possible Rock Ridge extensions which will override some of + these numbers in the inode structure. */ + + if (!high_sierra) + parse_rock_ridge_inode(raw_inode, inode); + +#ifdef DEBUG + printk("Inode: %x extent: %x\n",inode->i_ino, inode->u.isofs_i.i_first_extent); +#endif + brelse(bh); + + if (cpnt) { + kfree_s (cpnt, 1 << ISOFS_BLOCK_BITS); + cpnt = NULL; + }; + + inode->i_op = NULL; + if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && + isonum_723 (raw_inode->volume_sequence_number) != 1) { + printk("Multi volume CD somehow got mounted.\n"); + } else { + if (S_ISREG(inode->i_mode)) + inode->i_op = &isofs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &isofs_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &isofs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + } + return; + fail: + /* With a data error we return this information */ + inode->i_mtime = inode->i_atime = inode->i_ctime = 0; + inode->u.isofs_i.i_first_extent = 0; + inode->u.isofs_i.i_backlink = 0xffffffff; + inode->i_size = 0; + inode->i_nlink = 1; + inode->i_uid = inode->i_gid = 0; + inode->i_mode = S_IFREG; /*Regular file, noone gets to read*/ + inode->i_op = NULL; + return; +} + +/* There are times when we need to know the inode number of a parent of + a particular directory. When control passes through a routine that + has access to the parent information, it fills it into the inode structure, + but sometimes the inode gets flushed out of the queue, and someone + remmembers the number. When they try to open up again, we have lost + the information. The '..' entry on the disc points to the data area + for a particular inode, so we can follow these links back up, but since + we do not know the inode number, we do not actually know how large the + directory is. The disc is almost always correct, and there is + enough error checking on the drive itself, but an open ended search + makes me a little nervous. + + The bsd iso filesystem uses the extent number for an inode, and this + would work really nicely for us except that the read_inode function + would not have any clean way of finding the actual directory record + that goes with the file. If we had such info, then it would pay + to change the inode numbers and eliminate this function. +*/ + +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; + void * cpnt = NULL; + int result; + struct buffer_head * bh; + struct iso_directory_record * de; + + offset = 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 *) (bh->b_data + offset); + if (*((unsigned char *) de) == 0) + { + 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; + } + } +#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. */ + + result = -1; + + offset = 0; + block = parent_dir << (ISOFS_BLOCK_BITS - bufbits); + if (!block || !(bh = bread(parent->i_dev,block, bufsize))) + return -1; + + for(;;) + { + 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 (*((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 >= bufsize) + { + if((block & 1) != 0) return -1; + cpnt = kmalloc(1<b_data, bufsize); + de = (struct iso_directory_record *) + ((char *)cpnt + old_offset); + brelse(bh); + offset -= bufsize; + block++; + if (!(bh = bread(parent->i_dev,block,bufsize))) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + 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. */ + + out: + if (cpnt) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + cpnt = NULL; + } + brelse(bh); +#ifdef DEBUG + printk("Resultant Inode %d\n",result); +#endif + return result; +} + +#ifdef LEAK_CHECK +#undef malloc +#undef free_s +#undef bread +#undef brelse + +void * leak_check_malloc(unsigned int size){ + void * tmp; + check_malloc++; + tmp = kmalloc(size, GFP_KERNEL); + return tmp; +} + +void leak_check_free_s(void * obj, int size){ + check_malloc--; + return kfree_s(obj, size); +} + +struct buffer_head * leak_check_bread(int dev, int block, int size){ + check_bread++; + return bread(dev, block, size); +} + +void leak_check_brelse(struct buffer_head * bh){ + check_bread--; + return brelse(bh); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/namei.c new file mode 100644 index 000000000..a2713779b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/namei.c @@ -0,0 +1,268 @@ +/* + * linux/fs/isofs/namei.c + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * (C) 1991 Linus Torvalds - minix filesystem + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use isofs_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, isofs_match returns 1 for success, 0 for failure. + */ +static int isofs_match(int len,const char * name, char * compare, int dlen) +{ + register int same __asm__("ax"); + + if (!compare) return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (compare[0]==0) && (dlen==1)) + return 1; + + if (compare[0]==0 && dlen==1 && len == 1) + compare = "."; + if (compare[0]==1 && dlen==1 && len == 2) { + compare = ".."; + dlen = 2; + }; +#if 0 + if (len <= 2) printk("Match: %d %d %s %d %d \n",len,dlen,compare,de->name[0], dlen); +#endif + + if (dlen != len) + return 0; + __asm__("cld\n\t" + "repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) compare),"c" (len) + :"cx","di","si"); + return same; +} + +/* + * isofs_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as an inode number). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * isofs_find_entry(struct inode * dir, + const char * name, int namelen, int * ino, int * ino_back) +{ + 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; + unsigned int backlink; + int dlen, rrflag, match; + char * dpnt; + struct iso_directory_record * de; + char c; + + *ino = 0; + if (!dir) return NULL; + + if (!(block = dir->u.isofs_i.i_first_extent)) return NULL; + + f_pos = 0; + + 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 *) (bh->b_data + offset); + backlink = dir->i_ino; + 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) { + brelse(bh); + offset = 0; + 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 >= 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 = f_pos & (bufsize - 1); + block = isofs_bmap(dir,f_pos>>bufbits); + if (!block || !(bh = bread(dir->i_dev,block,bufsize))) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + return 0; + }; + memcpy((char *)cpnt+bufsize,bh->b_data,bufsize); + } + + /* Handle the '.' case */ + + if (de->name[0]==0 && de->name_len[0]==1) { + inode_number = dir->i_ino; + backlink = 0; + } + + /* Handle the '..' case */ + + if (de->name[0]==1 && de->name_len[0]==1) { +#if 0 + printk("Doing .. (%d %d)", + dir->i_sb->s_firstdatazone << bufbits, + dir->i_ino); +#endif + 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; + backlink = 0; + } + + dlen = de->name_len[0]; + dpnt = de->name; + /* Now convert the filename in the buffer to lower case */ + rrflag = get_rock_ridge_filename(de, &dpnt, &dlen, dir); + if (rrflag) { + if (rrflag == -1) goto out; /* Relocated deep directory */ + } 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); + if (cpnt) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + cpnt = NULL; + } + + if(rrflag) kfree(dpnt); + if (match) { + 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 */ + 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); + brelse(bh); + return NULL; +} + +int isofs_lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + int ino, ino_back; + struct buffer_head * bh; + +#ifdef DEBUG + printk("lookup: %x %d\n",dir->i_ino, len); +#endif + *result = NULL; + if (!dir) + return -ENOENT; + + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + + ino = 0; + if (dir->i_dev == cache.dev && + dir->i_ino == cache.dir && + len == cache.dlen && + isofs_match(len, name, cache.filename, cache.dlen)) + { + ino = cache.ino; + ino_back = dir->i_ino; + /* These two cases are special, but since they are at the start + of the directory, we can just as easily search there */ + if (cache.dlen == 1 && cache.filename[0] == '.') ino = 0; + if (cache.dlen == 2 && cache.filename[0] == '.' && + cache.filename[1] == '.') ino = 0; + }; + + if (!ino) { + if (!(bh = isofs_find_entry(dir,name,len, &ino, &ino_back))) { + iput(dir); + return -ENOENT; + } + brelse(bh); + }; + + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -EACCES; + } + + /* 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 && (*result)->i_sb == dir->i_sb) { + (*result)->u.isofs_i.i_backlink = ino_back; + } + + iput(dir); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.c new file mode 100644 index 000000000..ebbb44962 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.c @@ -0,0 +1,508 @@ +/* + * linux/fs/isofs/rock.c + * + * (C) 1992 Eric Youngdale + * + * Rock Ridge Extensions to iso9660 + */ +#include +#include +#include +#include +#include +#include +#include + +#include "rock.h" + +/* These functions are designed to read the system areas of a directory record + * and extract relevant information. There are different functions provided + * depending upon what information we need at the time. One function fills + * out an inode structure, a second one extracts a filename, a third one + * returns a symbolic link name, and a fourth one returns the extent number + * for the file. */ + +#define SIG(A,B) ((A << 8) | B) + + +/* This is a way of ensuring that we have something in the system + use fields that is compatible with Rock Ridge */ +#define CHECK_SP(FAIL) \ + if(rr->u.SP.magic[0] != 0xbe) FAIL; \ + if(rr->u.SP.magic[1] != 0xef) FAIL; + +/* We define a series of macros because each function must do exactly the + same thing in certain places. We use the macros to ensure that everyting + is done correctly */ + +#define CONTINUE_DECLS \ + int cont_extent = 0, cont_offset = 0, cont_size = 0; \ + void * buffer = 0 + +#define CHECK_CE \ + {cont_extent = isonum_733(rr->u.CE.extent); \ + cont_offset = isonum_733(rr->u.CE.offset); \ + cont_size = isonum_733(rr->u.CE.size);} + +#define SETUP_ROCK_RIDGE(DE,CHR,LEN) \ + {LEN= sizeof(struct iso_directory_record) + DE->name_len[0]; \ + if(LEN & 1) LEN++; \ + CHR = ((unsigned char *) DE) + LEN; \ + LEN = *((unsigned char *) DE) - LEN;} + +#define MAYBE_CONTINUE(LABEL,DEV) \ + {if (buffer) kfree(buffer); \ + if (cont_extent){ \ + int block, offset, offset1; \ + struct buffer_head * bh; \ + buffer = kmalloc(cont_size,GFP_KERNEL); \ + block = cont_extent; \ + offset = cont_offset; \ + offset1 = 0; \ + if(ISOFS_BUFFER_SIZE(DEV) == 1024) { \ + block <<= 1; \ + if (offset >= 1024) block++; \ + offset &= 1023; \ + if(offset + cont_size >= 1024) { \ + bh = bread(DEV->i_dev, block++, ISOFS_BUFFER_SIZE(DEV)); \ + memcpy(buffer, bh->b_data + offset, 1024 - offset); \ + brelse(bh); \ + offset1 = 1024 - offset; \ + offset = 0; \ + } \ + }; \ + bh = bread(DEV->i_dev, block, ISOFS_BUFFER_SIZE(DEV)); \ + if(bh){ \ + memcpy(buffer + offset1, bh->b_data + offset, cont_size - offset1); \ + brelse(bh); \ + chr = (unsigned char *) buffer; \ + len = cont_size; \ + cont_extent = 0; \ + cont_size = 0; \ + cont_offset = 0; \ + goto LABEL; \ + }; \ + printk("Unable to read rock-ridge attributes\n"); \ + }} + +/* This is the inner layer of the get filename routine, and is called + for each system area and continuation record related to the file */ + +int find_rock_ridge_relocation(struct iso_directory_record * de, + struct inode * inode) { + int flag; + int len; + int retval; + unsigned char * chr; + CONTINUE_DECLS; + flag = 0; + + /* If this is a '..' then we are looking for the parent, otherwise we + are looking for the child */ + + if (de->name[0]==1 && de->name_len[0]==1) flag = 1; + /* Return value if we do not find appropriate record. */ + retval = isonum_733 (de->extent); + + if (!inode->i_sb->u.isofs_sb.s_rock) return retval; + + SETUP_ROCK_RIDGE(de, chr, len); + repeat: + { + int rrflag, sig; + struct rock_ridge * rr; + + while (len > 1){ /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *) chr; + if (rr->len == 0) goto out; /* Something got screwed up here */ + sig = (chr[0] << 8) + chr[1]; + chr += rr->len; + len -= rr->len; + + switch(sig){ + case SIG('R','R'): + rrflag = rr->u.RR.flags[0]; + if (flag && !(rrflag & RR_PL)) goto out; + if (!flag && !(rrflag & RR_CL)) goto out; + break; + case SIG('S','P'): + CHECK_SP(goto out); + break; + case SIG('C','L'): +#ifdef DEBUG + printk("RR: CL\n"); +#endif + if (flag == 0) { + retval = isonum_733(rr->u.CL.location); + goto out; + }; + break; + case SIG('P','L'): +#ifdef DEBUG + printk("RR: PL\n"); +#endif + if (flag != 0) { + retval = isonum_733(rr->u.PL.location); + goto out; + }; + break; + case SIG('C','E'): + CHECK_CE; /* This tells is if there is a continuation record */ + break; + default: + break; + } + }; + }; + MAYBE_CONTINUE(repeat, inode); + return retval; + out: + if(buffer) kfree(buffer); + return retval; +} + +int get_rock_ridge_filename(struct iso_directory_record * de, + char ** name, int * namlen, struct inode * inode) +{ + int len; + unsigned char * chr; + CONTINUE_DECLS; + char * retname = NULL; + int retnamlen = 0, truncate=0; + + if (!inode->i_sb->u.isofs_sb.s_rock) return 0; + + SETUP_ROCK_RIDGE(de, chr, len); + repeat: + { + struct rock_ridge * rr; + int sig; + + while (len > 1){ /* There may be one byte for padding somewhere */ + rr = (struct rock_ridge *) chr; + if (rr->len == 0) goto out; /* Something got screwed up here */ + sig = (chr[0] << 8) + chr[1]; + chr += rr->len; + len -= rr->len; + + switch(sig){ + case SIG('R','R'): + if((rr->u.RR.flags[0] & RR_NM) == 0) goto out; + break; + case SIG('S','P'): + CHECK_SP(goto out); + break; + case SIG('C','E'): + CHECK_CE; + break; + case SIG('N','M'): + if (truncate) break; + if (rr->u.NM.flags & ~1) { + printk("Unsupported NM flag settings (%d)\n",rr->u.NM.flags); + break; + }; + if (!retname){ + retname = (char *) kmalloc (255,GFP_KERNEL); + /* This may be a waste, but we only + need this for a moment. The layers + that call this function should + deallocate the mem fairly soon + after control is returned */ + + *retname = 0; /* Zero length string */ + retnamlen = 0; + }; + if((strlen(retname) + rr->len - 5) >= 254) { + truncate = 1; + break; + }; + strncat(retname, rr->u.NM.name, rr->len - 5); + retnamlen += rr->len - 5; + break; + case SIG('R','E'): +#ifdef DEBUG + printk("RR: RE (%x)\n", inode->i_ino); +#endif + if (buffer) kfree(buffer); + if (retname) kfree(retname); + return -1; + default: + break; + } + }; + } + MAYBE_CONTINUE(repeat,inode); + if(retname){ + *name = retname; + *namlen = retnamlen; + return 1; + }; + return 0; /* This file did not have a NM field */ + out: + if(buffer) kfree(buffer); + if (retname) kfree(retname); + return 0; +} + +int parse_rock_ridge_inode(struct iso_directory_record * de, + struct inode * inode){ + int len; + unsigned char * chr; + CONTINUE_DECLS; + + if (!inode->i_sb->u.isofs_sb.s_rock) return 0; + + SETUP_ROCK_RIDGE(de, chr, len); + repeat: + { + 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; + if (rr->len == 0) goto out; /* Something got screwed up here */ + sig = (chr[0] << 8) + chr[1]; + chr += rr->len; + len -= rr->len; + + switch(sig){ + case SIG('R','R'): + if((rr->u.RR.flags[0] & + (RR_PX | RR_TF | RR_SL | RR_CL)) == 0) goto out; + break; + case SIG('S','P'): + CHECK_SP(goto out); + break; + case SIG('C','E'): + CHECK_CE; + break; + case SIG('E','R'): + printk("ISO9660 Extensions: "); + { int p; + for(p=0;pu.ER.len_id;p++) printk("%c",rr->u.ER.data[p]); + }; + printk("\n"); + break; + case SIG('P','X'): + inode->i_mode = isonum_733(rr->u.PX.mode); + inode->i_nlink = isonum_733(rr->u.PX.n_links); + inode->i_uid = isonum_733(rr->u.PX.uid); + inode->i_gid = isonum_733(rr->u.PX.gid); + break; + case SIG('P','N'): + { int high, low; + high = isonum_733(rr->u.PN.dev_high); + low = isonum_733(rr->u.PN.dev_low); + inode->i_rdev = ((high << 8) | (low & 0xff)) & 0xffff; + }; + break; + case SIG('T','F'): + /* Some RRIP writers incorrectly place ctime in the TF_CREATE field. + Try and handle this correctly for either case. */ + cnt = 0; /* Rock ridge never appears on a High Sierra disk */ + if(rr->u.TF.flags & TF_CREATE) + inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0); + if(rr->u.TF.flags & TF_MODIFY) + inode->i_mtime = iso_date(rr->u.TF.times[cnt++].time, 0); + if(rr->u.TF.flags & TF_ACCESS) + inode->i_atime = iso_date(rr->u.TF.times[cnt++].time, 0); + if(rr->u.TF.flags & TF_ATTRIBUTES) + inode->i_ctime = iso_date(rr->u.TF.times[cnt++].time, 0); + break; + case SIG('S','L'): + {int slen; + struct SL_component * slp; + 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; + break; + case 2: + inode->i_size += 1; + break; + case 4: + inode->i_size += 2; + break; + case 8: + rootflag = 1; + inode->i_size += 1; + break; + default: + printk("Symlink component flag not implemented\n"); + }; + slen -= slp->len + 2; + slp = (struct SL_component *) (((char *) slp) + slp->len + 2); + + if(slen < 2) break; + if(!rootflag) inode->i_size += 1; + }; + }; + break; + case SIG('R','E'): + printk("Attempt to read inode for relocated directory\n"); + goto out; + case SIG('C','L'): +#ifdef DEBUG + printk("RR CL (%x)\n",inode->i_ino); +#endif + inode->u.isofs_i.i_first_extent = isonum_733(rr->u.CL.location) << + (ISOFS_BLOCK_BITS - ISOFS_BUFFER_BITS(inode)); + reloc = iget(inode->i_sb, inode->u.isofs_i.i_first_extent << ISOFS_BUFFER_BITS(inode)); + inode->i_mode = reloc->i_mode; + inode->i_nlink = reloc->i_nlink; + inode->i_uid = reloc->i_uid; + inode->i_gid = reloc->i_gid; + inode->i_rdev = reloc->i_rdev; + inode->i_size = reloc->i_size; + inode->i_atime = reloc->i_atime; + inode->i_ctime = reloc->i_ctime; + inode->i_mtime = reloc->i_mtime; + iput(reloc); + break; + default: + break; + } + }; + } + MAYBE_CONTINUE(repeat,inode); + return 0; + out: + if(buffer) kfree(buffer); + return 0; +} + + +/* Returns the name of the file that this inode is symlinked to. This is + in malloc'd memory, so it needs to be freed, once we are through with it */ + +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; + char * rpnt; + struct iso_directory_record * raw_inode; + CONTINUE_DECLS; + int block; + int sig; + int rootflag; + int len; + unsigned char * chr; + struct rock_ridge * rr; + + if (!inode->i_sb->u.isofs_sb.s_rock) + panic("Cannot have symlink with high sierra variant of iso filesystem\n"); + + rpnt = 0; + + block = inode->i_ino >> bufbits; + if (!(bh=bread(inode->i_dev,block, bufsize))) { + printk("unable to read i-node block"); + return NULL; + }; + + pnt = ((unsigned char *) bh->b_data) + (inode->i_ino & (bufsize - 1)); + + raw_inode = ((struct iso_directory_record *) pnt); + + if ((inode->i_ino & (bufsize - 1)) + *pnt > bufsize){ + cpnt = kmalloc(1 << ISOFS_BLOCK_BITS, GFP_KERNEL); + memcpy(cpnt, bh->b_data, bufsize); + brelse(bh); + if (!(bh = bread(inode->i_dev,++block, bufsize))) { + kfree_s(cpnt, 1 << ISOFS_BLOCK_BITS); + printk("unable to read i-node block"); + return NULL; + }; + memcpy((char *)cpnt+bufsize, bh->b_data, bufsize); + pnt = ((unsigned char *) cpnt) + (inode->i_ino & (bufsize - 1)); + raw_inode = ((struct iso_directory_record *) pnt); + }; + + /* Now test for possible Rock Ridge extensions which will override some of + these numbers in the inode structure. */ + + SETUP_ROCK_RIDGE(raw_inode, chr, len); + + repeat: + while (len > 1){ /* There may be one byte for padding somewhere */ + if (rpnt) break; + rr = (struct rock_ridge *) chr; + if (rr->len == 0) goto out; /* Something got screwed up here */ + sig = (chr[0] << 8) + chr[1]; + chr += rr->len; + len -= rr->len; + + switch(sig){ + case SIG('R','R'): + if((rr->u.RR.flags[0] & RR_SL) == 0) goto out; + break; + case SIG('S','P'): + CHECK_SP(goto out); + break; + case SIG('S','L'): + {int slen; + struct SL_component * slp; + slen = rr->len - 5; + slp = &rr->u.SL.link; + while (slen > 1){ + if (!rpnt){ + 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); + break; + case 2: + strcat(rpnt,"."); + break; + case 4: + strcat(rpnt,".."); + break; + case 8: + rootflag = 1; + strcat(rpnt,"/"); + break; + default: + printk("Symlink component flag not implemented (%d)\n",slen); + }; + slen -= slp->len + 2; + slp = (struct SL_component *) (((char *) slp) + slp->len + 2); + + if(slen < 2) break; + if(!rootflag) strcat(rpnt,"/"); + }; + break; + default: + break; + } + }; + }; + MAYBE_CONTINUE(repeat,inode); + brelse(bh); + + if (cpnt) { + kfree(cpnt); + cpnt = NULL; + }; + + return rpnt; + out: + if(buffer) kfree(buffer); + return 0; +} + + + + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.h b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.h new file mode 100644 index 000000000..5f1d28e98 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/rock.h @@ -0,0 +1,111 @@ +/* These structs are used by the system-use-sharing protocol, in which the + Rock Ridge extensions are imbedded. It is quite possible that other + extensions are present on the disk, and this is fine as long as they + all use SUSP */ + +struct SU_SP{ + unsigned char magic[2]; + unsigned char skip; +}; + +struct SU_CE{ + char extent[8]; + char offset[8]; + char size[8]; +}; + +struct SU_ER{ + unsigned char len_id; + unsigned char len_des; + unsigned char len_src; + unsigned char ext_ver; + char data[0]; +}; + +struct RR_RR{ + char flags[1]; +}; + +struct RR_PX{ + char mode[8]; + char n_links[8]; + char uid[8]; + char gid[8]; +}; + +struct RR_PN{ + char dev_high[8]; + char dev_low[8]; +}; + + +struct SL_component{ + unsigned char flags; + unsigned char len; + char text[0]; +}; + +struct RR_SL{ + unsigned char flags; + struct SL_component link; +}; + +struct RR_NM{ + unsigned char flags; + char name[0]; +}; + +struct RR_CL{ + char location[8]; +}; + +struct RR_PL{ + char location[8]; +}; + +struct stamp{ + char time[7]; +}; + +struct RR_TF{ + char flags; + struct stamp times[0]; /* Variable number of these beasts */ +}; + +/* These are the bits and their meanings for flags in the TF structure. */ +#define TF_CREATE 1 +#define TF_MODIFY 2 +#define TF_ACCESS 4 +#define TF_ATTRIBUTES 8 +#define TF_BACKUP 16 +#define TF_EXPIRATION 32 +#define TF_EFFECTIVE 64 +#define TF_LONG_FORM 128 + +struct rock_ridge{ + char signature[2]; + unsigned char len; + unsigned char version; + union{ + struct SU_SP SP; + struct SU_CE CE; + struct SU_ER ER; + struct RR_RR RR; + struct RR_PX PX; + struct RR_PN PN; + struct RR_SL SL; + struct RR_NM NM; + struct RR_CL CL; + struct RR_PL PL; + struct RR_TF TF; + } u; +}; + +#define RR_PX 1 /* POSIX attributes */ +#define RR_PN 2 /* POSIX devices */ +#define RR_SL 4 /* Symbolic link */ +#define RR_NM 8 /* Alternate Name */ +#define RR_CL 16 /* Child link */ +#define RR_PL 32 /* Parent link */ +#define RR_RE 64 /* Relocation directory */ +#define RR_TF 128 /* Timestamps */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/symlink.c new file mode 100644 index 000000000..7b25a8fa0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/isofs/symlink.c @@ -0,0 +1,106 @@ +/* + * linux/fs/isofs/symlink.c + * + * (C) 1992 Eric Youngdale Modified for ISO9660 filesystem. + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * isofs symlink handling code. This is only used with the Rock Ridge + * extensions to iso9660 + */ + +#include + +#include +#include +#include +#include +#include +#include + +static int isofs_readlink(struct inode *, char *, int); +static int isofs_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations isofs_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + isofs_readlink, /* readlink */ + isofs_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int isofs_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + char * pnt; + + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + *res_inode = NULL; + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if ((current->link_count > 5) || + !(pnt = get_rock_ridge_symlink(inode))) { + iput(dir); + iput(inode); + *res_inode = NULL; + return -ELOOP; + } + iput(inode); + current->link_count++; + error = open_namei(pnt,flag,mode,res_inode,dir); + current->link_count--; + kfree(pnt); + return error; +} + +static int isofs_readlink(struct inode * inode, char * buffer, int buflen) +{ + char * pnt; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + + if (buflen > 1023) + buflen = 1023; + pnt = get_rock_ridge_symlink(inode); + + iput(inode); + if (!pnt) + return 0; + i = 0; + + while (i 2) + days += (year+1) / 4; + for (i = 1; i < month; i++) + days += monlen[i-1]; + if (((year+2) % 4) == 0 && month > 2) + days++; + days += day - 1; + crtime = ((((days * 24) + hour) * 60 + minute) * 60) + + second; + + /* sign extend */ + if (tz & 0x80) + tz |= (-1 << 8); + + /* timezone offset is unreliable on some disks */ + if (-48 <= tz && tz <= 52) + crtime += tz * 15 * 60; + } + return crtime; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/locks.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/locks.c new file mode 100644 index 000000000..80c45972f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/locks.c @@ -0,0 +1,454 @@ +/* + * linux/fs/locks.c + * + * Provide support for fcntl()'s F_GETLK, F_SETLK, and F_SETLKW calls. + * Doug Evans, 92Aug07, dje@sspiff.uucp. + * + * FIXME: two things aren't handled yet: + * - deadlock detection/avoidance (of dubious merit, but since it's in + * the definition, I guess it should be provided eventually) + * - mandatory locks (requires lots of changes elsewhere) + * + * Edited by Kai Petzke, wpp@marie.physik.tu-berlin.de + */ + +#include + +#include +#include +#include +#include +#include + +#define OFFSET_MAX ((off_t)0x7fffffff) /* FIXME: move elsewhere? */ + +static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, + unsigned int fd); +static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl); +static int overlap(struct file_lock *fl1, struct file_lock *fl2); +static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd); +static struct file_lock *alloc_lock(struct file_lock **pos, struct file_lock *fl, + unsigned int fd); +static void free_lock(struct file_lock **fl); + +static struct file_lock file_lock_table[NR_FILE_LOCKS]; +static struct file_lock *file_lock_free_list; + +/* + * Called at boot time to initialize the lock table ... + */ + +void fcntl_init_locks(void) +{ + struct file_lock *fl; + + for (fl = &file_lock_table[0]; fl < file_lock_table + NR_FILE_LOCKS - 1; fl++) { + fl->fl_next = fl + 1; + fl->fl_owner = NULL; + } + file_lock_table[NR_FILE_LOCKS - 1].fl_next = NULL; + file_lock_table[NR_FILE_LOCKS - 1].fl_owner = NULL; + file_lock_free_list = &file_lock_table[0]; +} + +int fcntl_getlk(unsigned int fd, struct flock *l) +{ + int error; + struct flock flock; + struct file *filp; + struct file_lock *fl,file_lock; + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + error = verify_area(VERIFY_WRITE,l, sizeof(*l)); + if (error) + return error; + memcpy_fromfs(&flock, l, sizeof(flock)); + if (flock.l_type == F_UNLCK) + return -EINVAL; + if (!copy_flock(filp, &file_lock, &flock, fd)) + return -EINVAL; + + for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) { + if (conflict(&file_lock, fl)) { + flock.l_pid = fl->fl_owner->pid; + flock.l_start = fl->fl_start; + flock.l_len = fl->fl_end == OFFSET_MAX ? 0 : + fl->fl_end - fl->fl_start + 1; + flock.l_whence = fl->fl_whence; + flock.l_type = fl->fl_type; + memcpy_tofs(l, &flock, sizeof(flock)); + return 0; + } + } + + flock.l_type = F_UNLCK; /* no conflict found */ + memcpy_tofs(l, &flock, sizeof(flock)); + return 0; +} + +/* + * This function implements both F_SETLK and F_SETLKW. + */ + +int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) +{ + int error; + struct file *filp; + struct file_lock *fl,file_lock; + struct flock flock; + + /* + * Get arguments and validate them ... + */ + + if (fd >= NR_OPEN || !(filp = current->filp[fd])) + return -EBADF; + error = verify_area(VERIFY_WRITE, l, sizeof(*l)); + if (error) + return error; + memcpy_fromfs(&flock, l, sizeof(flock)); + if (!copy_flock(filp, &file_lock, &flock, fd)) + return -EINVAL; + switch (file_lock.fl_type) { + case F_RDLCK : + if (!(filp->f_mode & 1)) + return -EBADF; + break; + case F_WRLCK : + if (!(filp->f_mode & 2)) + return -EBADF; + break; + case F_SHLCK : + if (!(filp->f_mode & 3)) + return -EBADF; + file_lock.fl_type = F_RDLCK; + break; + case F_EXLCK : + if (!(filp->f_mode & 3)) + return -EBADF; + file_lock.fl_type = F_WRLCK; + break; + case F_UNLCK : + break; + } + + /* + * Scan for a conflicting lock ... + */ + + if (file_lock.fl_type != F_UNLCK) { +repeat: + for (fl = filp->f_inode->i_flock; fl != NULL; fl = fl->fl_next) { + if (!conflict(&file_lock, fl)) + continue; + /* + * File is locked by another process. If this is + * F_SETLKW wait for the lock to be released. + * FIXME: We need to check for deadlocks here. + */ + if (cmd == F_SETLKW) { + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + interruptible_sleep_on(&fl->fl_wait); + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + goto repeat; + } + return -EAGAIN; + } + } + + /* + * Lock doesn't conflict with any other lock ... + */ + + return lock_it(filp, &file_lock, fd); +} + +/* + * This function is called when the file is closed. + */ + +void fcntl_remove_locks(struct task_struct *task, struct file *filp, + unsigned int fd) +{ + struct file_lock *fl; + struct file_lock **before; + + /* Find first lock owned by caller ... */ + + before = &filp->f_inode->i_flock; + while ((fl = *before) && (task != fl->fl_owner || fd != fl->fl_fd)) + before = &fl->fl_next; + + /* The list is sorted by owner and fd ... */ + + while ((fl = *before) && task == fl->fl_owner && fd == fl->fl_fd) + free_lock(before); +} + +/* + * Verify a "struct flock" and copy it to a "struct file_lock" ... + * Result is a boolean indicating success. + */ + +static int copy_flock(struct file *filp, struct file_lock *fl, struct flock *l, + unsigned int fd) +{ + off_t start; + + if (!filp->f_inode) /* just in case */ + return 0; + if (!S_ISREG(filp->f_inode->i_mode)) + return 0; + if (l->l_type != F_UNLCK && l->l_type != F_RDLCK && l->l_type != F_WRLCK + && l->l_type != F_SHLCK && l->l_type != F_EXLCK) + return 0; + switch (l->l_whence) { + case 0 /*SEEK_SET*/ : start = 0; break; + case 1 /*SEEK_CUR*/ : start = filp->f_pos; break; + case 2 /*SEEK_END*/ : start = filp->f_inode->i_size; break; + default : return 0; + } + if ((start += l->l_start) < 0 || l->l_len < 0) + return 0; + fl->fl_type = l->l_type; + fl->fl_start = start; /* we record the absolute position */ + fl->fl_whence = 0; /* FIXME: do we record {l_start} as passed? */ + if (l->l_len == 0 || (fl->fl_end = start + l->l_len - 1) < 0) + fl->fl_end = OFFSET_MAX; + fl->fl_owner = current; + fl->fl_fd = fd; + fl->fl_wait = NULL; /* just for cleanliness */ + return 1; +} + +/* + * Determine if lock {sys_fl} blocks lock {caller_fl} ... + */ + +static int conflict(struct file_lock *caller_fl, struct file_lock *sys_fl) +{ + if ( caller_fl->fl_owner == sys_fl->fl_owner + && caller_fl->fl_fd == sys_fl->fl_fd) + return 0; + if (!overlap(caller_fl, sys_fl)) + return 0; + switch (caller_fl->fl_type) { + case F_RDLCK : + return sys_fl->fl_type != F_RDLCK; + case F_WRLCK : + return 1; /* overlapping region not owned by caller */ + } + return 0; /* shouldn't get here, but just in case */ +} + +static int overlap(struct file_lock *fl1, struct file_lock *fl2) +{ + return fl1->fl_end >= fl2->fl_start && fl2->fl_end >= fl1->fl_start; +} + +/* + * Add a lock to a file ... + * Result is 0 for success or -ENOLCK. + * + * We merge adjacent locks whenever possible. + * + * WARNING: We assume the lock doesn't conflict with any other lock. + */ + +/* + * Rewritten by Kai Petzke: + * We sort the lock list first by owner, then by the starting address. + * + * To make freeing a lock much faster, we keep a pointer to the lock before the + * actual one. But the real gain of the new coding was, that lock_it() and + * unlock_it() became one function. + * + * To all purists: Yes, I use a few goto's. Just pass on to the next function. + */ + +static int lock_it(struct file *filp, struct file_lock *caller, unsigned int fd) +{ + struct file_lock *fl; + struct file_lock *left = 0; + struct file_lock *right = 0; + struct file_lock **before; + int added = 0; + + /* + * Find the first old lock with the same owner as the new lock. + */ + + before = &filp->f_inode->i_flock; + while ((fl = *before) && + (caller->fl_owner != fl->fl_owner || + caller->fl_fd != fl->fl_fd)) + before = &fl->fl_next; + + /* + * Look up all locks of this owner. + */ + + while ( (fl = *before) + && caller->fl_owner == fl->fl_owner + && caller->fl_fd == fl->fl_fd) { + /* + * Detect adjacent or overlapping regions (if same lock type) + */ + if (caller->fl_type == fl->fl_type) { + if (fl->fl_end < caller->fl_start - 1) + goto next_lock; + /* + * If the next lock in the list has entirely bigger + * addresses than the new one, insert the lock here. + */ + if (fl->fl_start > caller->fl_end + 1) + break; + + /* + * If we come here, the new and old lock are of the + * same type and adjacent or overlapping. Make one + * lock yielding from the lower start address of both + * locks to the higher end address. + */ + if (fl->fl_start > caller->fl_start) + fl->fl_start = caller->fl_start; + else + caller->fl_start = fl->fl_start; + if (fl->fl_end < caller->fl_end) + fl->fl_end = caller->fl_end; + else + caller->fl_end = fl->fl_end; + if (added) { + free_lock(before); + continue; + } + caller = fl; + added = 1; + goto next_lock; + } + /* + * Processing for different lock types is a bit more complex. + */ + if (fl->fl_end < caller->fl_start) + goto next_lock; + if (fl->fl_start > caller->fl_end) + break; + if (caller->fl_type == F_UNLCK) + added = 1; + if (fl->fl_start < caller->fl_start) + left = fl; + /* + * If the next lock in the list has a higher end address than + * the new one, insert the new one here. + */ + if (fl->fl_end > caller->fl_end) { + right = fl; + break; + } + if (fl->fl_start >= caller->fl_start) { + /* + * The new lock completely replaces an old one (This may + * happen several times). + */ + if (added) { + free_lock(before); + continue; + } + /* + * Replace the old lock with the new one. Wake up + * anybody waiting for the old one, as the change in + * lock type migth satisfy his needs. + */ + wake_up(&fl->fl_wait); + fl->fl_start = caller->fl_start; + fl->fl_end = caller->fl_end; + fl->fl_type = caller->fl_type; + caller = fl; + added = 1; + } + /* + * Go on to next lock. + */ +next_lock: + before = &(*before)->fl_next; + } + + if (! added) { + if (caller->fl_type == F_UNLCK) + return -EINVAL; + if (! (caller = alloc_lock(before, caller, fd))) + return -ENOLCK; + } + if (right) { + if (left == right) { + /* + * The new lock breaks the old one in two pieces, so we + * have to allocate one more lock (in this case, even + * F_UNLCK may fail!). + */ + if (! (left = alloc_lock(before, right, fd))) { + if (! added) + free_lock(before); + return -ENOLCK; + } + } + right->fl_start = caller->fl_end + 1; + } + if (left) + left->fl_end = caller->fl_start - 1; + return 0; +} + +/* + * File_lock() inserts a lock at the position pos of the linked list. + */ + +static struct file_lock *alloc_lock(struct file_lock **pos, + struct file_lock *fl, + unsigned int fd) +{ + struct file_lock *tmp; + + tmp = file_lock_free_list; + if (tmp == NULL) + return NULL; /* no available entry */ + if (tmp->fl_owner != NULL) + panic("alloc_lock: broken free list\n"); + + /* remove from free list */ + file_lock_free_list = tmp->fl_next; + + *tmp = *fl; + + tmp->fl_next = *pos; /* insert into file's list */ + *pos = tmp; + + tmp->fl_owner = current; /* FIXME: needed? */ + tmp->fl_fd = fd; /* FIXME: needed? */ + tmp->fl_wait = NULL; + return tmp; +} + +/* + * Add a lock to the free list ... + */ + +static void free_lock(struct file_lock **fl_p) +{ + struct file_lock *fl; + + fl = *fl_p; + if (fl->fl_owner == NULL) /* sanity check */ + panic("free_lock: broken lock list\n"); + + *fl_p = (*fl_p)->fl_next; + + fl->fl_next = file_lock_free_list; /* add to free list */ + file_lock_free_list = fl; + fl->fl_owner = NULL; /* for sanity checks */ + + wake_up(&fl->fl_wait); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/Makefile new file mode 100644 index 000000000..20e7f3dae --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for the linux minix-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= bitmap.o truncate.o namei.o inode.o \ + file.o dir.o symlink.o fsync.o + +minix.o: $(OBJS) + $(LD) -r -o minix.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/bitmap.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/bitmap.c new file mode 100644 index 000000000..8f4d1c8e3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/bitmap.c @@ -0,0 +1,230 @@ +/* + * linux/fs/minix/bitmap.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ + +#include +#include +#include +#include +#include + +#include + +#define clear_block(addr) \ +__asm__("cld\n\t" \ + "rep\n\t" \ + "stosl" \ + : \ + :"a" (0),"c" (BLOCK_SIZE/4),"D" ((long) (addr)):"cx","di") + +#define find_first_zero(addr) ({ \ +int __res; \ +__asm__("cld\n" \ + "1:\tlodsl\n\t" \ + "notl %%eax\n\t" \ + "bsfl %%eax,%%edx\n\t" \ + "jne 2f\n\t" \ + "addl $32,%%ecx\n\t" \ + "cmpl $8192,%%ecx\n\t" \ + "jl 1b\n\t" \ + "xorl %%edx,%%edx\n" \ + "2:\taddl %%edx,%%ecx" \ + :"=c" (__res):"0" (0),"S" (addr):"ax","dx","si"); \ +__res;}) + +static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; + +static unsigned long count_used(struct buffer_head *map[], unsigned numblocks, + unsigned numbits) +{ + unsigned i, j, end, sum = 0; + struct buffer_head *bh; + + for (i=0; (i= (8*BLOCK_SIZE)) { + end = BLOCK_SIZE; + numbits -= 8*BLOCK_SIZE; + } else { + int tmp; + end = numbits >> 3; + numbits &= 0x7; + tmp = bh->b_data[end] & ((1<>4)&0xf]; + numbits = 0; + } + for (j=0; jb_data[j] & 0xf] + + nibblemap[(bh->b_data[j]>>4)&0xf]; + } + return(sum); +} + +void minix_free_block(struct super_block * sb, int block) +{ + struct buffer_head * bh; + unsigned int bit,zone; + + if (!sb) { + printk("trying to free block on nonexistent device\n"); + return; + } + if (block < sb->u.minix_sb.s_firstdatazone || + block >= sb->u.minix_sb.s_nzones) { + printk("trying to free block not in datazone\n"); + return; + } + bh = get_hash_table(sb->s_dev,block,BLOCK_SIZE); + if (bh) + bh->b_dirt=0; + brelse(bh); + zone = block - sb->u.minix_sb.s_firstdatazone + 1; + bit = zone & 8191; + zone >>= 13; + bh = sb->u.minix_sb.s_zmap[zone]; + if (!bh) { + printk("minix_free_block: nonexistent bitmap buffer\n"); + return; + } + if (!clear_bit(bit,bh->b_data)) + printk("free_block (%04x:%d): bit already cleared\n",sb->s_dev,block); + bh->b_dirt = 1; + return; +} + +int minix_new_block(struct super_block * sb) +{ + struct buffer_head * bh; + int i,j; + + if (!sb) { + printk("trying to get new block from nonexistent device\n"); + return 0; + } +repeat: + j = 8192; + for (i=0 ; i<8 ; i++) + if ((bh=sb->u.minix_sb.s_zmap[i]) != NULL) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (i>=8 || !bh || j>=8192) + return 0; + if (set_bit(j,bh->b_data)) { + printk("new_block: bit already set"); + goto repeat; + } + bh->b_dirt = 1; + j += i*8192 + sb->u.minix_sb.s_firstdatazone-1; + if (j < sb->u.minix_sb.s_firstdatazone || + j >= sb->u.minix_sb.s_nzones) + return 0; + if (!(bh = getblk(sb->s_dev,j,BLOCK_SIZE))) { + printk("new_block: cannot get block"); + return 0; + } + clear_block(bh->b_data); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + return j; +} + +unsigned long minix_count_free_blocks(struct super_block *sb) +{ + return (sb->u.minix_sb.s_nzones - count_used(sb->u.minix_sb.s_zmap,sb->u.minix_sb.s_zmap_blocks,sb->u.minix_sb.s_nzones)) + << sb->u.minix_sb.s_log_zone_size; +} + +void minix_free_inode(struct inode * inode) +{ + struct buffer_head * bh; + unsigned long ino; + + if (!inode) + return; + if (!inode->i_dev) { + printk("free_inode: inode has no device\n"); + return; + } + if (inode->i_count != 1) { + printk("free_inode: inode has count=%d\n",inode->i_count); + return; + } + if (inode->i_nlink) { + printk("free_inode: inode has nlink=%d\n",inode->i_nlink); + return; + } + if (!inode->i_sb) { + printk("free_inode: inode on nonexistent device\n"); + return; + } + if (inode->i_ino < 1 || inode->i_ino >= inode->i_sb->u.minix_sb.s_ninodes) { + printk("free_inode: inode 0 or nonexistent inode\n"); + return; + } + ino = inode->i_ino; + if (!(bh=inode->i_sb->u.minix_sb.s_imap[ino >> 13])) { + printk("free_inode: nonexistent imap in superblock\n"); + return; + } + clear_inode(inode); + if (!clear_bit(ino & 8191, bh->b_data)) + printk("free_inode: bit %lu already cleared.\n",ino); + bh->b_dirt = 1; +} + +struct inode * minix_new_inode(const struct inode * dir) +{ + struct super_block * sb; + struct inode * inode; + struct buffer_head * bh; + int i,j; + + if (!dir || !(inode = get_empty_inode())) + return NULL; + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = inode->i_sb->s_flags; + j = 8192; + for (i=0 ; i<8 ; i++) + if ((bh = inode->i_sb->u.minix_sb.s_imap[i]) != NULL) + if ((j=find_first_zero(bh->b_data))<8192) + break; + if (!bh || j >= 8192) { + iput(inode); + return NULL; + } + if (set_bit(j,bh->b_data)) { /* shouldn't happen */ + printk("new_inode: bit already set"); + iput(inode); + return NULL; + } + bh->b_dirt = 1; + j += i*8192; + if (!j || j >= inode->i_sb->u.minix_sb.s_ninodes) { + iput(inode); + return NULL; + } + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->euid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid; + inode->i_dirt = 1; + inode->i_ino = j; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = NULL; + inode->i_blocks = inode->i_blksize = 0; + insert_inode_hash(inode); + return inode; +} + +unsigned long minix_count_free_inodes(struct super_block *sb) +{ + return sb->u.minix_sb.s_ninodes - count_used(sb->u.minix_sb.s_imap,sb->u.minix_sb.s_imap_blocks,sb->u.minix_sb.s_ninodes); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/dir.c new file mode 100644 index 000000000..f32a6837a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/dir.c @@ -0,0 +1,100 @@ +/* + * linux/fs/minix/dir.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * minix directory handling functions + */ + +#include + +#include +#include +#include +#include + +static int minix_dir_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + return -EISDIR; +} + +static int minix_readdir(struct inode *, struct file *, struct dirent *, int); + +static struct file_operations minix_dir_operations = { + NULL, /* lseek - default */ + minix_dir_read, /* read */ + NULL, /* write - bad */ + minix_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* default fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations minix_dir_inode_operations = { + &minix_dir_operations, /* default directory file-ops */ + minix_create, /* create */ + minix_lookup, /* lookup */ + minix_link, /* link */ + minix_unlink, /* unlink */ + minix_symlink, /* symlink */ + minix_mkdir, /* mkdir */ + minix_rmdir, /* rmdir */ + minix_mknod, /* mknod */ + minix_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + minix_truncate, /* truncate */ + NULL /* permission */ +}; + +static int minix_readdir(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + unsigned int offset,i; + char c; + struct buffer_head * bh; + struct minix_dir_entry * de; + struct minix_sb_info * info; + + if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) + return -EBADF; + info = &inode->i_sb->u.minix_sb; + if (filp->f_pos & (info->s_dirsize - 1)) + return -EBADF; + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & 1023; + bh = minix_bread(inode,(filp->f_pos)>>BLOCK_SIZE_BITS,0); + if (!bh) { + filp->f_pos += 1024-offset; + continue; + } + while (offset < 1024 && filp->f_pos < inode->i_size) { + de = (struct minix_dir_entry *) (offset + bh->b_data); + offset += info->s_dirsize; + filp->f_pos += info->s_dirsize; + if (de->inode) { + for (i = 0; i < info->s_namelen; i++) + if ((c = de->name[i]) != 0) + put_fs_byte(c,i+dirent->d_name); + else + break; + if (i) { + put_fs_long(de->inode,&dirent->d_ino); + put_fs_byte(0,i+dirent->d_name); + put_fs_word(i,&dirent->d_reclen); + brelse(bh); + return i; + } + } + } + brelse(bh); + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/file.c new file mode 100644 index 000000000..8329a48d7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/file.c @@ -0,0 +1,249 @@ +/* + * linux/fs/minix/file.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * minix regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +static int minix_file_read(struct inode *, struct file *, char *, int); +static int minix_file_write(struct inode *, struct file *, char *, int); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the minix filesystem. + */ +static struct file_operations minix_file_operations = { + NULL, /* lseek - default */ + minix_file_read, /* read */ + minix_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + minix_sync_file /* fsync */ +}; + +struct inode_operations minix_file_inode_operations = { + &minix_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + minix_bmap, /* bmap */ + minix_truncate, /* truncate */ + NULL /* permission */ +}; + +static int minix_file_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int read,left,chars; + int block, blocks, offset; + int bhrequest, uptodate; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + unsigned int size; + + if (!inode) { + printk("minix_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("minix_file_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + offset = filp->f_pos; + size = inode->i_size; + if (offset > size) + left = 0; + else + left = size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = offset >> BLOCK_SIZE_BITS; + offset &= BLOCK_SIZE-1; + size = (size + (BLOCK_SIZE-1)) >> BLOCK_SIZE_BITS; + blocks = (left + offset + BLOCK_SIZE - 1) >> BLOCK_SIZE_BITS; + bhb = bhe = buflist; + if (filp->f_reada) { + blocks += read_ahead[MAJOR(inode->i_dev)] / (BLOCK_SIZE >> 9); + if (block + blocks > size) + blocks = size - block; + } + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk. + + This routine is optimized to make maximum use of the various + buffers and caches. */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + *bhb = minix_getblk(inode, block++, 0); + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing. */ + if (uptodate) + break; + if (bhb == bhe) + break; + } + + /* Now request them all */ + if (bhrequest) + ll_rw_block(READ, bhrequest, bhreq); + + do { /* Finish off all I/O that has actually completed */ + if (*bhe) { + wait_on_buffer(*bhe); + if (!(*bhe)->b_uptodate) { /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < BLOCK_SIZE - offset) + chars = left; + else + chars = BLOCK_SIZE - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs(buf,offset+(*bhe)->b_data,chars); + brelse(*bhe); + buf += chars; + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); + } while (left > 0); + +/* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + }; + if (!read) + return -EIO; + filp->f_reada = 1; + if (!IS_RDONLY(inode)) + inode->i_atime = CURRENT_TIME; + return read; +} + +static int minix_file_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int written,c; + struct buffer_head * bh; + char * p; + + if (!inode) { + printk("minix_file_write: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("minix_file_write: mode = %07o\n",inode->i_mode); + return -EINVAL; + } +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written count-written) + c = count-written; + if (c != BLOCK_SIZE && !bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + if (!written) + written = -EIO; + break; + } + } + p = (pos % BLOCK_SIZE) + bh->b_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs(p,buf,c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + return written; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/fsync.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/fsync.c new file mode 100644 index 000000000..737a5bfcd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/fsync.c @@ -0,0 +1,159 @@ +/* + * linux/fs/minix/fsync.c + * + * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * from + * Copyright (C) 1991, 1992 Linus Torvalds + * + * minix fsync primitive + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + + +#define blocksize BLOCK_SIZE +#define addr_per_block 512 + +static int sync_block (struct inode * inode, unsigned short * block, int wait) +{ + struct buffer_head * bh; + unsigned short tmp; + + if (!*block) + return 0; + tmp = *block; + bh = get_hash_table(inode->i_dev, *block, blocksize); + if (!bh) + return 0; + if (*block != tmp) { + brelse (bh); + return 1; + } + if (wait && bh->b_req && !bh->b_uptodate) { + brelse(bh); + return -1; + } + if (wait || !bh->b_uptodate || !bh->b_dirt) + { + brelse(bh); + return 0; + } + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + return 0; +} + +static int sync_iblock (struct inode * inode, unsigned short * iblock, + struct buffer_head **bh, int wait) +{ + int rc; + unsigned short tmp; + + *bh = NULL; + tmp = *iblock; + if (!tmp) + return 0; + rc = sync_block (inode, iblock, wait); + if (rc) + return rc; + *bh = bread(inode->i_dev, tmp, blocksize); + if (tmp != *iblock) { + brelse(*bh); + *bh = NULL; + return 1; + } + if (!*bh) + return -1; + return 0; +} + + +static int sync_direct(struct inode *inode, int wait) +{ + int i; + int rc, err = 0; + + for (i = 0; i < 7; i++) { + rc = sync_block (inode, inode->u.minix_i.i_data + i, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + return err; +} + +static int sync_indirect(struct inode *inode, unsigned short *iblock, int wait) +{ + int i; + struct buffer_head * ind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, iblock, &ind_bh, wait); + if (rc || !ind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_block (inode, + ((unsigned short *) ind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(ind_bh); + return err; +} + +static int sync_dindirect(struct inode *inode, unsigned short *diblock, + int wait) +{ + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect (inode, + ((unsigned short *) dind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(dind_bh); + return err; +} + +int minix_sync_file(struct inode * inode, struct file * file) +{ + int wait, err = 0; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + + for (wait=0; wait<=1; wait++) + { + err |= sync_direct(inode, wait); + err |= sync_indirect(inode, inode->u.minix_i.i_data+7, wait); + err |= sync_dindirect(inode, inode->u.minix_i.i_data+8, wait); + } + err |= minix_sync_inode (inode); + return (err < 0) ? -EIO : 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/inode.c new file mode 100644 index 000000000..bc4b16c5b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/inode.c @@ -0,0 +1,512 @@ +/* + * linux/fs/minix/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +void minix_put_inode(struct inode *inode) +{ + if (inode->i_nlink) + return; + inode->i_size = 0; + minix_truncate(inode); + minix_free_inode(inode); +} + +static void minix_commit_super (struct super_block * sb, + struct minix_super_block * ms) +{ + sb->u.minix_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 0; +} + +void minix_write_super (struct super_block * sb) +{ + struct minix_super_block * ms; + + if (!(sb->s_flags & MS_RDONLY)) { + ms = sb->u.minix_sb.s_ms; + + if (ms->s_state & MINIX_VALID_FS) + ms->s_state &= ~MINIX_VALID_FS; + minix_commit_super (sb, ms); + } + sb->s_dirt = 0; +} + + +void minix_put_super(struct super_block *sb) +{ + int i; + + lock_super(sb); + if (!(sb->s_flags & MS_RDONLY)) { + sb->u.minix_sb.s_ms->s_state = sb->u.minix_sb.s_mount_state; + sb->u.minix_sb.s_sbh->b_dirt = 1; + } + sb->s_dev = 0; + for(i = 0 ; i < MINIX_I_MAP_SLOTS ; i++) + brelse(sb->u.minix_sb.s_imap[i]); + for(i = 0 ; i < MINIX_Z_MAP_SLOTS ; i++) + brelse(sb->u.minix_sb.s_zmap[i]); + brelse (sb->u.minix_sb.s_sbh); + unlock_super(sb); + return; +} + +static struct super_operations minix_sops = { + minix_read_inode, + NULL, + minix_write_inode, + minix_put_inode, + minix_put_super, + minix_write_super, + minix_statfs, + minix_remount +}; + +int minix_remount (struct super_block * sb, int * flags, char * data) +{ + struct minix_super_block * ms; + + ms = sb->u.minix_sb.s_ms; + if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY)) + return 0; + if (*flags & MS_RDONLY) { + if (ms->s_state & MINIX_VALID_FS || + !(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + return 0; + /* Mounting a rw partition read-only. */ + ms->s_state = sb->u.minix_sb.s_mount_state; + sb->u.minix_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + minix_commit_super (sb, ms); + } + else { + /* Mount a partition which is read-only, read-write. */ + sb->u.minix_sb.s_mount_state = ms->s_state; + ms->s_state &= ~MINIX_VALID_FS; + sb->u.minix_sb.s_sbh->b_dirt = 1; + sb->s_dirt = 1; + + if (!(sb->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + printk ("MINIX-fs warning: remounting unchecked fs, " + "running fsck is recommended.\n"); + else if ((sb->u.minix_sb.s_mount_state & MINIX_ERROR_FS)) + printk ("MINIX-fs warning: remounting fs with errors, " + "running fsck is recommended.\n"); + } + return 0; +} + + +struct super_block *minix_read_super(struct super_block *s,void *data, + int silent) +{ + struct buffer_head *bh; + struct minix_super_block *ms; + int i,dev=s->s_dev,block; + + if (32 != sizeof (struct minix_inode)) + panic("bad i-node size"); + lock_super(s); + if (!(bh = bread(dev,1,BLOCK_SIZE))) { + s->s_dev=0; + unlock_super(s); + printk("MINIX-fs: unable to read superblock\n"); + return NULL; + } + ms = (struct minix_super_block *) bh->b_data; + s->u.minix_sb.s_ms = ms; + s->u.minix_sb.s_sbh = bh; + s->u.minix_sb.s_mount_state = ms->s_state; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->u.minix_sb.s_ninodes = ms->s_ninodes; + s->u.minix_sb.s_nzones = ms->s_nzones; + s->u.minix_sb.s_imap_blocks = ms->s_imap_blocks; + s->u.minix_sb.s_zmap_blocks = ms->s_zmap_blocks; + s->u.minix_sb.s_firstdatazone = ms->s_firstdatazone; + s->u.minix_sb.s_log_zone_size = ms->s_log_zone_size; + s->u.minix_sb.s_max_size = ms->s_max_size; + s->s_magic = ms->s_magic; + if (s->s_magic == MINIX_SUPER_MAGIC) { + s->u.minix_sb.s_dirsize = 16; + s->u.minix_sb.s_namelen = 14; + } else if (s->s_magic == MINIX_SUPER_MAGIC2) { + s->u.minix_sb.s_dirsize = 32; + s->u.minix_sb.s_namelen = 30; + } else { + s->s_dev = 0; + unlock_super(s); + brelse(bh); + if (!silent) + printk("VFS: Can't find a minix filesystem on dev 0x%04x.\n", dev); + return NULL; + } + for (i=0;i < MINIX_I_MAP_SLOTS;i++) + s->u.minix_sb.s_imap[i] = NULL; + for (i=0;i < MINIX_Z_MAP_SLOTS;i++) + s->u.minix_sb.s_zmap[i] = NULL; + block=2; + for (i=0 ; i < s->u.minix_sb.s_imap_blocks ; i++) + if ((s->u.minix_sb.s_imap[i]=bread(dev,block,BLOCK_SIZE)) != NULL) + block++; + else + break; + for (i=0 ; i < s->u.minix_sb.s_zmap_blocks ; i++) + if ((s->u.minix_sb.s_zmap[i]=bread(dev,block,BLOCK_SIZE)) != NULL) + block++; + else + break; + if (block != 2+s->u.minix_sb.s_imap_blocks+s->u.minix_sb.s_zmap_blocks) { + for(i=0;iu.minix_sb.s_imap[i]); + for(i=0;iu.minix_sb.s_zmap[i]); + s->s_dev=0; + unlock_super(s); + brelse(bh); + printk("MINIX-fs: bad superblock or unable to read bitmaps\n"); + return NULL; + } + set_bit(0,s->u.minix_sb.s_imap[0]->b_data); + set_bit(0,s->u.minix_sb.s_zmap[0]->b_data); + unlock_super(s); + /* set up enough so that it can read an inode */ + s->s_dev = dev; + s->s_op = &minix_sops; + s->s_mounted = iget(s,MINIX_ROOT_INO); + if (!s->s_mounted) { + s->s_dev = 0; + brelse(bh); + printk("MINIX-fs: get root inode failed\n"); + return NULL; + } + if (!(s->s_flags & MS_RDONLY)) { + ms->s_state &= ~MINIX_VALID_FS; + bh->b_dirt = 1; + s->s_dirt = 1; + } + if (!(s->u.minix_sb.s_mount_state & MINIX_VALID_FS)) + printk ("MINIX-fs: mounting unchecked file system, " + "running fsck is recommended.\n"); + else if (s->u.minix_sb.s_mount_state & MINIX_ERROR_FS) + printk ("MINIX-fs: mounting file system with errors, " + "running fsck is recommended.\n"); + return s; +} + +void minix_statfs(struct super_block *sb, struct statfs *buf) +{ + long tmp; + + put_fs_long(MINIX_SUPER_MAGIC, &buf->f_type); + put_fs_long(1024, &buf->f_bsize); + tmp = sb->u.minix_sb.s_nzones - sb->u.minix_sb.s_firstdatazone; + tmp <<= sb->u.minix_sb.s_log_zone_size; + put_fs_long(tmp, &buf->f_blocks); + tmp = minix_count_free_blocks(sb); + put_fs_long(tmp, &buf->f_bfree); + put_fs_long(tmp, &buf->f_bavail); + put_fs_long(sb->u.minix_sb.s_ninodes, &buf->f_files); + put_fs_long(minix_count_free_inodes(sb), &buf->f_ffree); + put_fs_long(sb->u.minix_sb.s_namelen, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ +} + +#define inode_bmap(inode,nr) ((inode)->u.minix_i.i_data[(nr)]) + +static int block_bmap(struct buffer_head * bh, int nr) +{ + int tmp; + + if (!bh) + return 0; + tmp = ((unsigned short *) bh->b_data)[nr]; + brelse(bh); + return tmp; +} + +int minix_bmap(struct inode * inode,int block) +{ + int i; + + if (block<0) { + printk("minix_bmap: block<0"); + return 0; + } + if (block >= 7+512+512*512) { + printk("minix_bmap: block>big"); + return 0; + } + if (block < 7) + return inode_bmap(inode,block); + block -= 7; + if (block < 512) { + i = inode_bmap(inode,7); + if (!i) + return 0; + return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block); + } + block -= 512; + i = inode_bmap(inode,8); + if (!i) + return 0; + i = block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block>>9); + if (!i) + return 0; + return block_bmap(bread(inode->i_dev,i,BLOCK_SIZE),block & 511); +} + +static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create) +{ + int tmp; + unsigned short *p; + struct buffer_head * result; + + p = inode->u.minix_i.i_data + nr; +repeat: + tmp = *p; + if (tmp) { + result = getblk(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp == *p) + return result; + brelse(result); + goto repeat; + } + if (!create) + return NULL; + tmp = minix_new_block(inode->i_sb); + if (!tmp) + return NULL; + result = getblk(inode->i_dev, tmp, BLOCK_SIZE); + if (*p) { + minix_free_block(inode->i_sb,tmp); + brelse(result); + goto repeat; + } + *p = tmp; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return result; +} + +static struct buffer_head * block_getblk(struct inode * inode, + struct buffer_head * bh, int nr, int create) +{ + int tmp; + unsigned short *p; + struct buffer_head * result; + + if (!bh) + return NULL; + if (!bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + return NULL; + } + } + p = nr + (unsigned short *) bh->b_data; +repeat: + tmp = *p; + if (tmp) { + result = getblk(bh->b_dev, tmp, BLOCK_SIZE); + if (tmp == *p) { + brelse(bh); + return result; + } + brelse(result); + goto repeat; + } + if (!create) { + brelse(bh); + return NULL; + } + tmp = minix_new_block(inode->i_sb); + if (!tmp) { + brelse(bh); + return NULL; + } + result = getblk(bh->b_dev, tmp, BLOCK_SIZE); + if (*p) { + minix_free_block(inode->i_sb,tmp); + brelse(result); + goto repeat; + } + *p = tmp; + bh->b_dirt = 1; + brelse(bh); + return result; +} + +struct buffer_head * minix_getblk(struct inode * inode, int block, int create) +{ + struct buffer_head * bh; + + if (block<0) { + printk("minix_getblk: block<0"); + return NULL; + } + if (block >= 7+512+512*512) { + printk("minix_getblk: block>big"); + return NULL; + } + if (block < 7) + return inode_getblk(inode,block,create); + block -= 7; + if (block < 512) { + bh = inode_getblk(inode,7,create); + return block_getblk(inode, bh, block, create); + } + block -= 512; + bh = inode_getblk(inode,8,create); + bh = block_getblk(inode, bh, block>>9, create); + return block_getblk(inode, bh, block & 511, create); +} + +struct buffer_head * minix_bread(struct inode * inode, int block, int create) +{ + struct buffer_head * bh; + + bh = minix_getblk(inode,block,create); + if (!bh || bh->b_uptodate) + return bh; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +void minix_read_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct minix_inode * raw_inode; + int block, ino; + + ino = inode->i_ino; + inode->i_op = NULL; + inode->i_mode = 0; + if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) { + printk("Bad inode number on dev 0x%04x: %d is out of range\n", + inode->i_dev, ino); + return; + } + block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + + inode->i_sb->u.minix_sb.s_zmap_blocks + + (ino-1)/MINIX_INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev,block, BLOCK_SIZE))) { + printk("Major problem: unable to read inode from dev 0x%04x\n", + inode->i_dev); + return; + } + raw_inode = ((struct minix_inode *) bh->b_data) + + (ino-1)%MINIX_INODES_PER_BLOCK; + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_nlinks; + inode->i_size = raw_inode->i_size; + inode->i_mtime = inode->i_atime = inode->i_ctime = raw_inode->i_time; + inode->i_blocks = inode->i_blksize = 0; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = raw_inode->i_zone[0]; + else for (block = 0; block < 9; block++) + inode->u.minix_i.i_data[block] = raw_inode->i_zone[block]; + brelse(bh); + if (S_ISREG(inode->i_mode)) + inode->i_op = &minix_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &minix_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &minix_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); +} + +static struct buffer_head * minix_update_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct minix_inode * raw_inode; + int ino, block; + + ino = inode->i_ino; + if (!ino || ino >= inode->i_sb->u.minix_sb.s_ninodes) { + printk("Bad inode number on dev 0x%04x: %d is out of range\n", + inode->i_dev, ino); + inode->i_dirt = 0; + return 0; + } + block = 2 + inode->i_sb->u.minix_sb.s_imap_blocks + inode->i_sb->u.minix_sb.s_zmap_blocks + + (ino-1)/MINIX_INODES_PER_BLOCK; + if (!(bh=bread(inode->i_dev, block, BLOCK_SIZE))) { + printk("unable to read i-node block\n"); + inode->i_dirt = 0; + return 0; + } + raw_inode = ((struct minix_inode *)bh->b_data) + + (ino-1)%MINIX_INODES_PER_BLOCK; + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_nlinks = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_time = inode->i_mtime; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_zone[0] = inode->i_rdev; + else for (block = 0; block < 9; block++) + raw_inode->i_zone[block] = inode->u.minix_i.i_data[block]; + inode->i_dirt=0; + bh->b_dirt=1; + return bh; +} + +void minix_write_inode(struct inode * inode) +{ + struct buffer_head *bh; + bh = minix_update_inode(inode); + brelse(bh); +} + +int minix_sync_inode(struct inode * inode) +{ + int err = 0; + struct buffer_head *bh; + + bh = minix_update_inode(inode); + if (bh && bh->b_dirt) + { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + if (bh->b_req && !bh->b_uptodate) + { + printk ("IO error syncing minix inode [%04x:%08lx]\n", + inode->i_dev, inode->i_ino); + err = -1; + } + } + else if (!bh) + err = -1; + brelse (bh); + return err; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/namei.c new file mode 100644 index 000000000..f4814ee70 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/namei.c @@ -0,0 +1,828 @@ +/* + * linux/fs/minix/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +/* + * comment out this line if you want names > info->s_namelen chars to be + * truncated. Else they will be disallowed (ENAMETOOLONG). + */ +/* #define NO_TRUNCATE */ + +static inline int namecompare(int len, int maxlen, + const char * name, const char * buffer) +{ + if (len >= maxlen || !buffer[len]) { + unsigned char same; + __asm__("repe ; cmpsb ; setz %0" + :"=q" (same) + :"S" ((long) name),"D" ((long) buffer),"c" (len) + :"cx","di","si"); + return same; + } + return 0; +} + +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use minix_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, minix_match returns 1 for success, 0 for failure. + */ +static int minix_match(int len, const char * name, + struct buffer_head * bh, unsigned long * offset, + struct minix_sb_info * info) +{ + struct minix_dir_entry * de; + + de = (struct minix_dir_entry *) (bh->b_data + *offset); + *offset += info->s_dirsize; + if (!de->inode || len > info->s_namelen) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + return namecompare(len,info->s_namelen,name,de->name); +} + +/* + * minix_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * minix_find_entry(struct inode * dir, + const char * name, int namelen, struct minix_dir_entry ** res_dir) +{ + unsigned long block, offset; + struct buffer_head * bh; + struct minix_sb_info * info; + + *res_dir = NULL; + if (!dir || !dir->i_sb) + return NULL; + info = &dir->i_sb->u.minix_sb; + if (namelen > info->s_namelen) { +#ifdef NO_TRUNCATE + return NULL; +#else + namelen = info->s_namelen; +#endif + } + bh = NULL; + block = offset = 0; + while (block*BLOCK_SIZE+offset < dir->i_size) { + if (!bh) { + bh = minix_bread(dir,block,0); + if (!bh) { + block++; + continue; + } + } + *res_dir = (struct minix_dir_entry *) (bh->b_data + offset); + if (minix_match(namelen,name,bh,&offset,info)) + return bh; + if (offset < bh->b_size) + continue; + brelse(bh); + bh = NULL; + offset = 0; + block++; + } + brelse(bh); + *res_dir = NULL; + return NULL; +} + +int minix_lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + int ino; + struct minix_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!(bh = minix_find_entry(dir,name,len,&de))) { + iput(dir); + return -ENOENT; + } + ino = de->inode; + brelse(bh); + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -EACCES; + } + iput(dir); + return 0; +} + +/* + * minix_add_entry() + * + * adds a file entry to the specified directory, returning a possible + * error value if it fails. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static int minix_add_entry(struct inode * dir, + const char * name, int namelen, + struct buffer_head ** res_buf, + struct minix_dir_entry ** res_dir) +{ + int i; + unsigned long block, offset; + struct buffer_head * bh; + struct minix_dir_entry * de; + struct minix_sb_info * info; + + *res_buf = NULL; + *res_dir = NULL; + if (!dir || !dir->i_sb) + return -ENOENT; + info = &dir->i_sb->u.minix_sb; + if (namelen > info->s_namelen) { +#ifdef NO_TRUNCATE + return -ENAMETOOLONG; +#else + namelen = info->s_namelen; +#endif + } + if (!namelen) + return -ENOENT; + bh = NULL; + block = offset = 0; + while (1) { + if (!bh) { + bh = minix_bread(dir,block,1); + if (!bh) + return -ENOSPC; + } + de = (struct minix_dir_entry *) (bh->b_data + offset); + offset += info->s_dirsize; + if (block*bh->b_size + offset > dir->i_size) { + de->inode = 0; + dir->i_size = block*bh->b_size + offset; + dir->i_dirt = 1; + } + if (de->inode) { + if (namecompare(namelen, info->s_namelen, name, de->name)) { + brelse(bh); + return -EEXIST; + } + } else { + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + for (i = 0; i < info->s_namelen ; i++) + de->name[i] = (i < namelen) ? name[i] : 0; + bh->b_dirt = 1; + *res_dir = de; + break; + } + if (offset < bh->b_size) + continue; + brelse(bh); + bh = NULL; + offset = 0; + block++; + } + *res_buf = bh; + return 0; +} + +int minix_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result) +{ + int error; + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = minix_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &minix_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + error = minix_add_entry(dir,name,len, &bh ,&de); + if (error) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return error; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *result = inode; + return 0; +} + +int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +{ + int error; + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + if (!dir) + return -ENOENT; + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = minix_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &minix_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &minix_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &minix_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; + inode->i_dirt = 1; + error = minix_add_entry(dir, name, len, &bh, &de); + if (error) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return error; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int minix_mkdir(struct inode * dir, const char * name, int len, int mode) +{ + int error; + struct inode * inode; + struct buffer_head * bh, *dir_block; + struct minix_dir_entry * de; + struct minix_sb_info * info; + + if (!dir || !dir->i_sb) { + iput(dir); + return -EINVAL; + } + info = &dir->i_sb->u.minix_sb; + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + if (dir->i_nlink >= MINIX_LINK_MAX) { + iput(dir); + return -EMLINK; + } + inode = minix_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &minix_dir_inode_operations; + inode->i_size = 2 * info->s_dirsize; + dir_block = minix_bread(inode,0,1); + if (!dir_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + de = (struct minix_dir_entry *) dir_block->b_data; + de->inode=inode->i_ino; + strcpy(de->name,"."); + de = (struct minix_dir_entry *) (dir_block->b_data + info->s_dirsize); + de->inode = dir->i_ino; + strcpy(de->name,".."); + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + inode->i_dirt = 1; + error = minix_add_entry(dir, name, len, &bh, &de); + if (error) { + iput(dir); + inode->i_nlink=0; + iput(inode); + return error; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + dir->i_nlink++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct inode * inode) +{ + unsigned int block, offset; + struct buffer_head * bh; + struct minix_dir_entry * de; + struct minix_sb_info * info; + + if (!inode || !inode->i_sb) + return 1; + info = &inode->i_sb->u.minix_sb; + block = 0; + bh = NULL; + offset = 2*info->s_dirsize; + if (inode->i_size & (info->s_dirsize-1)) + goto bad_dir; + if (inode->i_size < offset) + goto bad_dir; + bh = minix_bread(inode,0,0); + if (!bh) + goto bad_dir; + de = (struct minix_dir_entry *) bh->b_data; + if (!de->inode || strcmp(de->name,".")) + goto bad_dir; + de = (struct minix_dir_entry *) (bh->b_data + info->s_dirsize); + if (!de->inode || strcmp(de->name,"..")) + goto bad_dir; + while (block*BLOCK_SIZE+offset < inode->i_size) { + if (!bh) { + bh = minix_bread(inode,block,0); + if (!bh) { + block++; + continue; + } + } + de = (struct minix_dir_entry *) (bh->b_data + offset); + offset += info->s_dirsize; + if (de->inode) { + brelse(bh); + return 0; + } + if (offset < bh->b_size) + continue; + brelse(bh); + bh = NULL; + offset = 0; + block++; + } + brelse(bh); + return 1; +bad_dir: + brelse(bh); + printk("Bad directory on device %04x\n",inode->i_dev); + return 1; +} + +int minix_rmdir(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + + inode = NULL; + bh = minix_find_entry(dir,name,len,&de); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget(dir->i_sb, de->inode))) + goto end_rmdir; + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir(inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (de->inode != inode->i_ino) { + retval = -ENOENT; + goto end_rmdir; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto end_rmdir; + } + if (inode->i_nlink != 2) + printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); + de->inode = 0; + bh->b_dirt = 1; + inode->i_nlink=0; + inode->i_dirt=1; + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + retval = 0; +end_rmdir: + iput(dir); + iput(inode); + brelse(bh); + return retval; +} + +int minix_unlink(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct minix_dir_entry * de; + +repeat: + retval = -ENOENT; + inode = NULL; + bh = minix_find_entry(dir,name,len,&de); + if (!bh) + goto end_unlink; + if (!(inode = iget(dir->i_sb, de->inode))) + goto end_unlink; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (de->inode != inode->i_ino) { + retval = -ENOENT; + goto end_unlink; + } + if (!inode->i_nlink) { + printk("Deleting nonexistent file (%04x:%lu), %d\n", + inode->i_dev,inode->i_ino,inode->i_nlink); + inode->i_nlink=1; + } + de->inode = 0; + bh->b_dirt = 1; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + inode->i_nlink--; + inode->i_ctime = dir->i_ctime; + inode->i_dirt = 1; + retval = 0; +end_unlink: + brelse(bh); + iput(inode); + iput(dir); + return retval; +} + +int minix_symlink(struct inode * dir, const char * name, int len, const char * symname) +{ + struct minix_dir_entry * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + int i; + char c; + + if (!(inode = minix_new_inode(dir))) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | 0777; + inode->i_op = &minix_symlink_inode_operations; + name_block = minix_bread(inode,0,1); + if (!name_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + i = 0; + while (i < 1023 && (c=*(symname++))) + name_block->b_data[i++] = c; + name_block->b_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + brelse(bh); + iput(dir); + return -EEXIST; + } + i = minix_add_entry(dir, name, len, &bh, &de); + if (i) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return i; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +{ + int error; + struct minix_dir_entry * de; + struct buffer_head * bh; + + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (oldinode->i_nlink >= MINIX_LINK_MAX) { + iput(oldinode); + iput(dir); + return -EMLINK; + } + bh = minix_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + error = minix_add_entry(dir, name, len, &bh, &de); + if (error) { + iput(dir); + iput(oldinode); + return error; + } + de->inode = oldinode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} + +static int subdir(struct inode * new_inode, struct inode * old_inode) +{ + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (minix_lookup(new_inode,"..",2,&new_inode)) + break; + if (new_inode->i_ino == ino) + break; + } + iput(new_inode); + return result; +} + +#define PARENT_INO(buffer) \ +(((struct minix_dir_entry *) ((buffer)+info->s_dirsize))->inode) + +/* + * rename uses retrying to avoid race-conditions: at least they should be minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct minix_dir_entry * old_de, * new_de; + struct minix_sb_info * info; + int retval; + + info = &old_dir->i_sb->u.minix_sb; + goto start_up; +try_again: + brelse(old_bh); + brelse(new_bh); + brelse(dir_bh); + iput(old_inode); + iput(new_inode); + current->counter = 0; + schedule(); +start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + old_bh = minix_find_entry(old_dir,old_name,old_len,&old_de); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = __iget(old_dir->i_sb, old_de->inode,0); /* don't cross mnt-points */ + if (!old_inode) + goto end_rename; + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = minix_find_entry(new_dir,new_name,new_len,&new_de); + if (new_bh) { + new_inode = __iget(new_dir->i_sb, new_de->inode, 0); + if (!new_inode) { + brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -ENOTEMPTY; + if (!empty_dir(new_inode)) + goto end_rename; + retval = -EBUSY; + if (new_inode->i_count > 1) + goto end_rename; + } + retval = -EPERM; + if (new_inode && (new_dir->i_mode & S_ISVTX) && + current->euid != new_inode->i_uid && + current->euid != new_dir->i_uid && !suser()) + goto end_rename; + if (S_ISDIR(old_inode->i_mode)) { + retval = -ENOTDIR; + if (new_inode && !S_ISDIR(new_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -EIO; + dir_bh = minix_bread(old_inode,0,0); + if (!dir_bh) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= MINIX_LINK_MAX) + goto end_rename; + } + if (!new_bh) { + retval = minix_add_entry(new_dir,new_name,new_len,&new_bh,&new_de); + if (retval) + goto end_rename; + } +/* sanity checking before doing the rename - avoid races */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; +/* ok, that's it */ + old_de->inode = 0; + 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; + new_bh->b_dirt = 1; + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + old_dir->i_dirt = 1; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } else { + new_dir->i_nlink++; + new_dir->i_dirt = 1; + } + } + retval = 0; +end_rename: + brelse(dir_bh); + brelse(old_bh); + brelse(new_bh); + iput(old_inode); + iput(new_inode); + iput(old_dir); + iput(new_dir); + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + */ +int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + + while (lock) + sleep_on(&wait); + lock = 1; + result = do_minix_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len); + lock = 0; + wake_up(&wait); + return result; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/symlink.c new file mode 100644 index 000000000..a3310aecb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/symlink.c @@ -0,0 +1,102 @@ +/* + * linux/fs/minix/symlink.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * minix symlink handling code + */ + +#include + +#include +#include +#include +#include +#include + +static int minix_readlink(struct inode *, char *, int); +static int minix_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations minix_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + minix_readlink, /* readlink */ + minix_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int minix_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + struct buffer_head * bh; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput(inode); + iput(dir); + return -ELOOP; + } + if (!(bh = minix_bread(inode, 0, 0))) { + iput(inode); + iput(dir); + return -EIO; + } + iput(inode); + current->link_count++; + error = open_namei(bh->b_data,flag,mode,res_inode,dir); + current->link_count--; + brelse(bh); + return error; +} + +static int minix_readlink(struct inode * inode, char * buffer, int buflen) +{ + struct buffer_head * bh; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + if (buflen > 1023) + buflen = 1023; + bh = minix_bread(inode, 0, 0); + iput(inode); + if (!bh) + return 0; + i = 0; + while (ib_data[i])) { + i++; + put_fs_byte(c,buffer++); + } + brelse(bh); + return i; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/truncate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/truncate.c new file mode 100644 index 000000000..bef81a302 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/minix/truncate.c @@ -0,0 +1,184 @@ +/* + * linux/fs/truncate.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include + +/* + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + +static int trunc_direct(struct inode * inode) +{ + unsigned short * p; + struct buffer_head * bh; + int i, tmp; + int retry = 0; +#define DIRECT_BLOCK ((inode->i_size + 1023) >> 10) + +repeat: + for (i = DIRECT_BLOCK ; i < 7 ; i++) { + p = i + inode->u.minix_i.i_data; + if (!(tmp = *p)) + continue; + bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE); + if (i < DIRECT_BLOCK) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *p) { + retry = 1; + brelse(bh); + continue; + } + *p = 0; + inode->i_dirt = 1; + brelse(bh); + minix_free_block(inode->i_sb,tmp); + } + return retry; +} + +static int trunc_indirect(struct inode * inode, int offset, unsigned short * p) +{ + struct buffer_head * bh; + int i, tmp; + struct buffer_head * ind_bh; + unsigned short * ind; + int retry = 0; +#define INDIRECT_BLOCK (DIRECT_BLOCK-offset) + + tmp = *p; + if (!tmp) + return 0; + ind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp != *p) { + brelse(ind_bh); + return 1; + } + if (!ind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = INDIRECT_BLOCK ; i < 512 ; i++) { + if (i < 0) + i = 0; + if (i < INDIRECT_BLOCK) + goto repeat; + ind = i+(unsigned short *) ind_bh->b_data; + tmp = *ind; + if (!tmp) + continue; + bh = get_hash_table(inode->i_dev,tmp,BLOCK_SIZE); + if (i < INDIRECT_BLOCK) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *ind) { + retry = 1; + brelse(bh); + continue; + } + *ind = 0; + ind_bh->b_dirt = 1; + brelse(bh); + minix_free_block(inode->i_sb,tmp); + } + ind = (unsigned short *) ind_bh->b_data; + for (i = 0; i < 512; i++) + if (*(ind++)) + break; + if (i >= 512) + if (ind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + minix_free_block(inode->i_sb,tmp); + } + brelse(ind_bh); + return retry; +} + +static int trunc_dindirect(struct inode * inode) +{ + int i, tmp; + struct buffer_head * dind_bh; + unsigned short * dind, * p; + int retry = 0; +#define DINDIRECT_BLOCK ((DIRECT_BLOCK-(512+7))>>9) + + p = 8 + inode->u.minix_i.i_data; + if (!(tmp = *p)) + return 0; + dind_bh = bread(inode->i_dev, tmp, BLOCK_SIZE); + if (tmp != *p) { + brelse(dind_bh); + return 1; + } + if (!dind_bh) { + *p = 0; + return 0; + } +repeat: + for (i = DINDIRECT_BLOCK ; i < 512 ; i ++) { + if (i < 0) + i = 0; + if (i < DINDIRECT_BLOCK) + goto repeat; + dind = i+(unsigned short *) dind_bh->b_data; + retry |= trunc_indirect(inode,7+512+(i<<9),dind); + dind_bh->b_dirt = 1; + } + dind = (unsigned short *) dind_bh->b_data; + for (i = 0; i < 512; i++) + if (*(dind++)) + break; + if (i >= 512) + if (dind_bh->b_count != 1) + retry = 1; + else { + tmp = *p; + *p = 0; + inode->i_dirt = 1; + minix_free_block(inode->i_sb,tmp); + } + brelse(dind_bh); + return retry; +} + +void minix_truncate(struct inode * inode) +{ + int retry; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + while (1) { + retry = trunc_direct(inode); + retry |= trunc_indirect(inode,7,inode->u.minix_i.i_data+7); + retry |= trunc_dindirect(inode); + if (!retry) + break; + current->counter = 0; + schedule(); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/Makefile new file mode 100644 index 000000000..820ec4356 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux MS-DOS-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= namei.o inode.o file.o dir.o misc.o fat.o + +msdos.o: $(OBJS) + $(LD) -r -o msdos.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/dir.c new file mode 100644 index 000000000..e42cc5c63 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/dir.c @@ -0,0 +1,114 @@ +/* + * linux/fs/msdos/dir.c + * + * Written 1992,1993 by Werner Almesberger + * + * MS-DOS directory handling functions + */ + +#include + +#include +#include +#include +#include + + +static int msdos_dir_read(struct inode * inode,struct file * filp, char * buf,int count) +{ + return -EISDIR; +} + +static int msdos_readdir(struct inode *inode,struct file *filp, + struct dirent *dirent,int count); + + +static struct file_operations msdos_dir_operations = { + NULL, /* lseek - default */ + msdos_dir_read, /* read */ + NULL, /* write - bad */ + msdos_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* fsync */ +}; + +struct inode_operations msdos_dir_inode_operations = { + &msdos_dir_operations, /* default directory file-ops */ + msdos_create, /* create */ + msdos_lookup, /* lookup */ + NULL, /* link */ + msdos_unlink, /* unlink */ + NULL, /* symlink */ + msdos_mkdir, /* mkdir */ + msdos_rmdir, /* rmdir */ + NULL, /* mknod */ + msdos_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + msdos_bmap, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int msdos_readdir(struct inode *inode,struct file *filp, + struct dirent *dirent,int count) +{ + int ino,i,i2,last; + char c,*walk; + struct buffer_head *bh; + struct msdos_dir_entry *de; + + if (!inode || !S_ISDIR(inode->i_mode)) return -EBADF; + if (inode->i_ino == MSDOS_ROOT_INO) { +/* Fake . and .. for the root directory. */ + if (filp->f_pos == 2) filp->f_pos = 0; + else if (filp->f_pos < 2) { + walk = filp->f_pos++ ? ".." : "."; + for (i = 0; *walk; walk++) + put_fs_byte(*walk,dirent->d_name+i++); + put_fs_long(MSDOS_ROOT_INO,&dirent->d_ino); + put_fs_byte(0,dirent->d_name+i); + put_fs_word(i,&dirent->d_reclen); + return i; + } + } + if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1)) return -ENOENT; + bh = NULL; + while ((ino = msdos_get_entry(inode,&filp->f_pos,&bh,&de)) > -1) { + if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) { + for (i = last = 0; i < 8; i++) { + if (!(c = de->name[i])) break; + if (c >= 'A' && c <= 'Z') c += 32; + if (c != ' ') last = i+1; + put_fs_byte(c,i+dirent->d_name); + } + i = last; + put_fs_byte('.',i+dirent->d_name); + i++; + for (i2 = 0; i2 < 3; i2++) { + if (!(c = de->ext[i2])) break; + if (c >= 'A' && c <= 'Z') c += 32; + if (c != ' ') last = i+1; + put_fs_byte(c,i+dirent->d_name); + i++; + } + if ((i = last) != 0) { + if (!strcmp(de->name,MSDOS_DOT)) + ino = inode->i_ino; + else if (!strcmp(de->name,MSDOS_DOTDOT)) + ino = msdos_parent_ino(inode,0); + put_fs_long(ino,&dirent->d_ino); + put_fs_byte(0,i+dirent->d_name); + put_fs_word(i,&dirent->d_reclen); + brelse(bh); + return i; + } + } + } + if (bh) brelse(bh); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/fat.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/fat.c new file mode 100644 index 000000000..b4ec8d7b0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/fat.c @@ -0,0 +1,293 @@ +/* + * linux/fs/msdos/fat.c + * + * Written 1992,1993 by Werner Almesberger + */ + +#include +#include +#include +#include + + +static struct fat_cache *fat_cache,cache[FAT_CACHE]; + +/* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If + new_value is != -1, that FAT entry is replaced by it. */ + +int fat_access(struct super_block *sb,int nr,int new_value) +{ + struct buffer_head *bh,*bh2,*c_bh,*c_bh2; + unsigned char *p_first,*p_last; + void *data,*data2,*c_data,*c_data2; + int first,last,next,copy; + + if ((unsigned) (nr-2) >= MSDOS_SB(sb)->clusters) return 0; + if (MSDOS_SB(sb)->fat_bits == 16) first = last = nr*2; + else { + first = nr*3/2; + last = first+1; + } + if (!(bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >> + SECTOR_BITS),&data))) { + printk("bread in fat_access failed\n"); + return 0; + } + if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) { + bh2 = bh; + data2 = data; + } + else { + if (!(bh2 = msdos_sread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last + >> SECTOR_BITS),&data2))) { + brelse(bh); + printk("bread in fat_access failed\n"); + return 0; + } + } + if (MSDOS_SB(sb)->fat_bits == 16) { + p_first = p_last = NULL; /* GCC needs that stuff */ + next = CF_LE_W(((unsigned short *) data)[(first & + (SECTOR_SIZE-1)) >> 1]); + if (next >= 0xfff7) next = -1; + } + else { + p_first = &((unsigned char *) data)[first & (SECTOR_SIZE-1)]; + p_last = &((unsigned char *) data2)[(first+1) & + (SECTOR_SIZE-1)]; + if (nr & 1) next = ((*p_first >> 4) | (*p_last << 4)) & 0xfff; + else next = (*p_first+(*p_last << 8)) & 0xfff; + if (next >= 0xff7) next = -1; + } + if (new_value != -1) { + if (MSDOS_SB(sb)->fat_bits == 16) + ((unsigned short *) data)[(first & (SECTOR_SIZE-1)) >> + 1] = CT_LE_W(new_value); + else { + if (nr & 1) { + *p_first = (*p_first & 0xf) | (new_value << 4); + *p_last = new_value >> 4; + } + else { + *p_first = new_value & 0xff; + *p_last = (*p_last & 0xf0) | (new_value >> 8); + } + bh2->b_dirt = 1; + } + bh->b_dirt = 1; + for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { + if (!(c_bh = msdos_sread(sb->s_dev,MSDOS_SB(sb)-> + fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> + fat_length*copy,&c_data))) break; + memcpy(c_data,data,SECTOR_SIZE); + c_bh->b_dirt = 1; + if (data != data2 || bh != bh2) { + if (!(c_bh2 = msdos_sread(sb->s_dev, + MSDOS_SB(sb)->fat_start+(first >> + SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy + +1,&c_data2))) { + brelse(c_bh); + break; + } + memcpy(c_data2,data2,SECTOR_SIZE); + brelse(c_bh2); + } + brelse(c_bh); + } + } + brelse(bh); + if (data != data2) brelse(bh2); + return next; +} + + +void cache_init(void) +{ + static int initialized = 0; + int count; + + if (initialized) return; + fat_cache = &cache[0]; + for (count = 0; count < FAT_CACHE; count++) { + cache[count].device = 0; + cache[count].next = count == FAT_CACHE-1 ? NULL : + &cache[count+1]; + } + initialized = 1; +} + + +void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu) +{ + struct fat_cache *walk; + +#ifdef DEBUG +printk("cache lookup: <%d,%d> %d (%d,%d) -> ",inode->i_dev,inode->i_ino,cluster, + *f_clu,*d_clu); +#endif + for (walk = fat_cache; walk; walk = walk->next) + if (inode->i_dev == walk->device && walk->ino == inode->i_ino && + walk->file_cluster <= cluster && walk->file_cluster > + *f_clu) { + *d_clu = walk->disk_cluster; +#ifdef DEBUG +printk("cache hit: %d (%d)\n",walk->file_cluster,*d_clu); +#endif + if ((*f_clu = walk->file_cluster) == cluster) return; + } +#ifdef DEBUG +printk("cache miss\n"); +#endif +} + + +#ifdef DEBUG +static void list_cache(void) +{ + struct fat_cache *walk; + + for (walk = fat_cache; walk; walk = walk->next) { + if (walk->device) + printk("<%d,%d>(%d,%d) ",walk->device,walk->ino, + walk->file_cluster,walk->disk_cluster); + else printk("-- "); + } + printk("\n"); +} +#endif + + +void cache_add(struct inode *inode,int f_clu,int d_clu) +{ + struct fat_cache *walk,*last; + +#ifdef DEBUG +printk("cache add: <%d,%d> %d (%d)\n",inode->i_dev,inode->i_ino,f_clu,d_clu); +#endif + last = NULL; + for (walk = fat_cache; walk->next; walk = (last = walk)->next) + if (inode->i_dev == walk->device && walk->ino == inode->i_ino && + walk->file_cluster == f_clu) { + if (walk->disk_cluster != d_clu) { + printk("FAT cache corruption"); + cache_inval_inode(inode); + return; + } + /* update LRU */ + if (last == NULL) return; + last->next = walk->next; + walk->next = fat_cache; + fat_cache = walk; +#ifdef DEBUG +list_cache(); +#endif + return; + } + walk->device = inode->i_dev; + walk->ino = inode->i_ino; + walk->file_cluster = f_clu; + walk->disk_cluster = d_clu; + last->next = NULL; + walk->next = fat_cache; + fat_cache = walk; +#ifdef DEBUG +list_cache(); +#endif +} + + +/* Cache invalidation occurs rarely, thus the LRU chain is not updated. It + fixes itself after a while. */ + +void cache_inval_inode(struct inode *inode) +{ + struct fat_cache *walk; + + for (walk = fat_cache; walk; walk = walk->next) + if (walk->device == inode->i_dev && walk->ino == inode->i_ino) + walk->device = 0; +} + + +void cache_inval_dev(int device) +{ + struct fat_cache *walk; + + for (walk = fat_cache; walk; walk = walk->next) + if (walk->device == device) walk->device = 0; +} + + +int get_cluster(struct inode *inode,int cluster) +{ + int nr,count; + + if (!(nr = MSDOS_I(inode)->i_start)) return 0; + if (!cluster) return nr; + count = 0; + for (cache_lookup(inode,cluster,&count,&nr); count < cluster; + count++) { + if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0; + if (!nr) return 0; + } + cache_add(inode,cluster,nr); + return nr; +} + + +int msdos_smap(struct inode *inode,int sector) +{ + struct msdos_sb_info *sb; + int cluster,offset; + + sb = MSDOS_SB(inode->i_sb); + if (inode->i_ino == MSDOS_ROOT_INO || (S_ISDIR(inode->i_mode) && + !MSDOS_I(inode)->i_start)) { + if (sector >= sb->dir_entries >> MSDOS_DPS_BITS) return 0; + return sector+sb->dir_start; + } + cluster = sector/sb->cluster_size; + offset = sector % sb->cluster_size; + if (!(cluster = get_cluster(inode,cluster))) return 0; + return (cluster-2)*sb->cluster_size+sb->data_start+offset; +} + + +/* Free all clusters after the skip'th cluster. Doesn't use the cache, + because this way we get an additional sanity check. */ + +int fat_free(struct inode *inode,int skip) +{ + int nr,last; + + if (!(nr = MSDOS_I(inode)->i_start)) return 0; + last = 0; + while (skip--) { + last = nr; + if ((nr = fat_access(inode->i_sb,nr,-1)) == -1) return 0; + if (!nr) { + printk("fat_free: skipped EOF\n"); + return -EIO; + } + } + if (last) + fat_access(inode->i_sb,last,MSDOS_SB(inode->i_sb)->fat_bits == + 12 ? 0xff8 : 0xfff8); + else { + MSDOS_I(inode)->i_start = 0; + inode->i_dirt = 1; + } + lock_fat(inode->i_sb); + while (nr != -1) { + if (!(nr = fat_access(inode->i_sb,nr,0))) { + fs_panic(inode->i_sb,"fat_free: deleting beyond EOF"); + break; + } + if (MSDOS_SB(inode->i_sb)->free_clusters != -1) + MSDOS_SB(inode->i_sb)->free_clusters++; + inode->i_blocks -= MSDOS_SB(inode->i_sb)->cluster_size; + } + unlock_fat(inode->i_sb); + cache_inval_inode(inode); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/file.c new file mode 100644 index 000000000..fc5463dbf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/file.c @@ -0,0 +1,223 @@ +/* + * linux/fs/msdos/file.c + * + * Written 1992,1993 by Werner Almesberger + * + * MS-DOS regular file handling primitives + */ + +#include +#include + +#include +#include +#include +#include +#include +#include + +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +static int msdos_file_read(struct inode *inode,struct file *filp,char *buf, + int count); +static int msdos_file_write(struct inode *inode,struct file *filp,char *buf, + int count); + + +static struct file_operations msdos_file_operations = { + NULL, /* lseek - default */ + msdos_file_read, /* read */ + msdos_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + file_fsync /* fsync */ +}; + +struct inode_operations msdos_file_inode_operations = { + &msdos_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + msdos_bmap, /* bmap */ + msdos_truncate, /* truncate */ + NULL /* permission */ +}; + +/* No bmap for MS-DOS FS' that don't align data at kByte boundaries. */ + +struct inode_operations msdos_file_inode_operations_no_bmap = { + &msdos_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + msdos_truncate, /* truncate */ + NULL /* permission */ +}; + + +static int msdos_file_read(struct inode *inode,struct file *filp,char *buf, + int count) +{ + char *start; + int left,offset,size,sector,cnt; + char ch; + struct buffer_head *bh; + void *data; + +/* printk("msdos_file_read\n"); */ + if (!inode) { + printk("msdos_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("msdos_file_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + if (filp->f_pos >= inode->i_size || count <= 0) return 0; + start = buf; + while ((left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) > 0){ + if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) + break; + offset = filp->f_pos & (SECTOR_SIZE-1); + if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break; + filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left)); + if (MSDOS_I(inode)->i_binary) { + memcpy_tofs(buf,data+offset,size); + buf += size; + } + else for (cnt = size; cnt; cnt--) { + if ((ch = *((char *) data+offset++)) == '\r') + size--; + else { + if (ch != 26) put_fs_byte(ch,buf++); + else { + filp->f_pos = inode->i_size; + brelse(bh); + if (start != buf + && !IS_RDONLY(inode)) + inode->i_atime + = CURRENT_TIME; + return buf-start; + } + } + } + brelse(bh); + } + if (start == buf) return -EIO; + if (!IS_RDONLY(inode)) + inode->i_atime = CURRENT_TIME; + return buf-start; +} + + +static int msdos_file_write(struct inode *inode,struct file *filp,char *buf, + int count) +{ + int sector,offset,size,left,written; + int error,carry; + char *start,*to,ch; + struct buffer_head *bh; + void *data; + + if (!inode) { + printk("msdos_file_write: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("msdos_file_write: mode = %07o\n",inode->i_mode); + return -EINVAL; + } +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size; + if (count <= 0) return 0; + error = carry = 0; + for (start = buf; count || carry; count -= size) { + while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS))) + if ((error = msdos_add_cluster(inode)) < 0) break; + if (error) { + msdos_truncate(inode); + break; + } + offset = filp->f_pos & (SECTOR_SIZE-1); + size = MIN(SECTOR_SIZE-offset,MAX(carry,count)); + if (!(bh = msdos_sread(inode->i_dev,sector,&data))) { + error = -EIO; + break; + } + if (MSDOS_I(inode)->i_binary) { + memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)), + buf,written = size); + buf += size; + } + else { + written = left = SECTOR_SIZE-offset; + to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1)); + if (carry) { + *to++ = '\n'; + left--; + carry = 0; + } + for (size = 0; size < count && left; size++) { + if ((ch = get_fs_byte(buf++)) == '\n') { + *to++ = '\r'; + left--; + } + if (!left) carry = 1; + else { + *to++ = ch; + left--; + } + } + written -= left; + } + filp->f_pos += written; + if (filp->f_pos > inode->i_size) { + inode->i_size = filp->f_pos; + inode->i_dirt = 1; + } + bh->b_dirt = 1; + brelse(bh); + } + if (start == buf) + return error; + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + MSDOS_I(inode)->i_attrs |= ATTR_ARCH; + inode->i_dirt = 1; + return buf-start; +} + + +void msdos_truncate(struct inode *inode) +{ + int cluster; + + cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size; + (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster); + MSDOS_I(inode)->i_attrs |= ATTR_ARCH; + inode->i_dirt = 1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/inode.c new file mode 100644 index 000000000..cf333623d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/inode.c @@ -0,0 +1,447 @@ +/* + * linux/fs/msdos/inode.c + * + * Written 1992,1993 by Werner Almesberger + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +void msdos_put_inode(struct inode *inode) +{ + struct inode *depend; + struct super_block *sb; + + if (inode->i_nlink) { + if (MSDOS_I(inode)->i_busy) cache_inval_inode(inode); + return; + } + inode->i_size = 0; + msdos_truncate(inode); + depend = MSDOS_I(inode)->i_depend; + sb = inode->i_sb; + clear_inode(inode); + if (depend) { + if (MSDOS_I(depend)->i_old != inode) { + printk("Invalid link (0x%X): expected 0x%X, got 0x%X\n", + (int) depend,(int) inode,(int) MSDOS_I(depend)-> + i_old); + fs_panic(sb,"..."); + return; + } + MSDOS_I(depend)->i_old = NULL; + iput(depend); + } +} + + +void msdos_put_super(struct super_block *sb) +{ + cache_inval_dev(sb->s_dev); + lock_super(sb); + sb->s_dev = 0; + unlock_super(sb); + return; +} + + +static struct super_operations msdos_sops = { + msdos_read_inode, + msdos_notify_change, + msdos_write_inode, + msdos_put_inode, + msdos_put_super, + NULL, /* added in 0.96c */ + msdos_statfs, + NULL +}; + + +static int parse_options(char *options,char *check,char *conversion,uid_t *uid, + gid_t *gid,int *umask,int *debug,int *fat,int *quiet) +{ + char *this_char,*value; + + *check = 'n'; + *conversion = 'b'; + *uid = current->uid; + *gid = current->gid; + *umask = current->umask; + *debug = *fat = *quiet = 0; + if (!options) return 1; + for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"check") && value) { + if (value[0] && !value[1] && strchr("rns",*value)) + *check = *value; + else if (!strcmp(value,"relaxed")) *check = 'r'; + else if (!strcmp(value,"normal")) *check = 'n'; + else if (!strcmp(value,"strict")) *check = 's'; + else return 0; + } + else if (!strcmp(this_char,"conv") && value) { + if (value[0] && !value[1] && strchr("bta",*value)) + *conversion = *value; + else if (!strcmp(value,"binary")) *conversion = 'b'; + else if (!strcmp(value,"text")) *conversion = 't'; + else if (!strcmp(value,"auto")) *conversion = 'a'; + else return 0; + } + else if (!strcmp(this_char,"uid")) { + if (!value || !*value) + return 0; + *uid = simple_strtoul(value,&value,0); + if (*value) + return 0; + } + else if (!strcmp(this_char,"gid")) { + if (!value || !*value) + return 0; + *gid = simple_strtoul(value,&value,0); + if (*value) + return 0; + } + else if (!strcmp(this_char,"umask")) { + if (!value || !*value) + return 0; + *umask = simple_strtoul(value,&value,8); + if (*value) + return 0; + } + else if (!strcmp(this_char,"debug")) { + if (value) return 0; + *debug = 1; + } + else if (!strcmp(this_char,"fat")) { + if (!value || !*value) + return 0; + *fat = simple_strtoul(value,&value,0); + if (*value || (*fat != 12 && *fat != 16)) + return 0; + } + else if (!strcmp(this_char,"quiet")) { + if (value) return 0; + *quiet = 1; + } + else return 0; + } + return 1; +} + + +/* Read the super block of an MS-DOS FS. */ + +struct super_block *msdos_read_super(struct super_block *s,void *data, + int silent) +{ + struct buffer_head *bh; + struct msdos_boot_sector *b; + int data_sectors,logical_sector_size,sector_mult; + int debug,error,fat,quiet; + char check,conversion; + uid_t uid; + gid_t gid; + int umask; + + if (!parse_options((char *) data,&check,&conversion,&uid,&gid,&umask, + &debug,&fat,&quiet)) { + s->s_dev = 0; + return NULL; + } + cache_init(); + lock_super(s); + bh = bread(s->s_dev, 0, BLOCK_SIZE); + unlock_super(s); + if (bh == NULL) { + s->s_dev = 0; + printk("MSDOS bread failed\n"); + return NULL; + } + b = (struct msdos_boot_sector *) bh->b_data; + s->s_blocksize = 1024; /* we cannot handle anything else yet */ + s->s_blocksize_bits = 10; /* we cannot handle anything else yet */ + +/* + * The DOS3 partition size limit is *not* 32M as many people think. + * Instead, it is 64K sectors (with the usual sector size being + * 512 bytes, leading to a 32M limit). + * + * DOS 3 partition managers got around this problem by faking a + * larger sector size, ie treating multiple physical sectors as + * a single logical sector. + * + * We can accommodate this scheme by adjusting our cluster size, + * fat_start, and data_start by an appropriate value. + * + * (by Drew Eckhardt) + */ + +#define ROUND_TO_MULTIPLE(n,m) ((n) && (m) ? (n)+(m)-1-((n)-1)%(m) : 0) + /* don't divide by zero */ + + logical_sector_size = CF_LE_W(*(unsigned short *) &b->sector_size); + sector_mult = logical_sector_size >> SECTOR_BITS; + MSDOS_SB(s)->cluster_size = b->cluster_size*sector_mult; + MSDOS_SB(s)->fats = b->fats; + MSDOS_SB(s)->fat_start = CF_LE_W(b->reserved)*sector_mult; + MSDOS_SB(s)->fat_length = CF_LE_W(b->fat_length)*sector_mult; + MSDOS_SB(s)->dir_start = (CF_LE_W(b->reserved)+b->fats*CF_LE_W( + b->fat_length))*sector_mult; + MSDOS_SB(s)->dir_entries = CF_LE_W(*((unsigned short *) &b->dir_entries + )); + MSDOS_SB(s)->data_start = MSDOS_SB(s)->dir_start+ROUND_TO_MULTIPLE(( + MSDOS_SB(s)->dir_entries << MSDOS_DIR_BITS) >> SECTOR_BITS, + sector_mult); + data_sectors = (CF_LE_W(*((unsigned short *) &b->sectors)) ? + CF_LE_W(*((unsigned short *) &b->sectors)) : + CF_LE_L(b->total_sect))*sector_mult-MSDOS_SB(s)->data_start; + error = !b->cluster_size || !sector_mult; + if (!error) { + MSDOS_SB(s)->clusters = b->cluster_size ? data_sectors/ + b->cluster_size/sector_mult : 0; + MSDOS_SB(s)->fat_bits = fat ? fat : MSDOS_SB(s)->clusters > + MSDOS_FAT12 ? 16 : 12; + error = !MSDOS_SB(s)->fats || (MSDOS_SB(s)->dir_entries & + (MSDOS_DPS-1)) || MSDOS_SB(s)->clusters+2 > MSDOS_SB(s)-> + fat_length*SECTOR_SIZE*8/MSDOS_SB(s)->fat_bits || + (logical_sector_size & (SECTOR_SIZE-1)) || !b->secs_track || + !b->heads; + } + brelse(bh); + if (error || debug) { + printk("[MS-DOS FS Rel. 12,FAT %d,check=%c,conv=%c," + "uid=%d,gid=%d,umask=%03o%s]\n",MSDOS_SB(s)->fat_bits,check, + conversion,uid,gid,umask,MSDOS_CAN_BMAP(MSDOS_SB(s)) ? + ",bmap" : ""); + printk("[me=0x%x,cs=%d,#f=%d,fs=%d,fl=%d,ds=%d,de=%d,data=%d," + "se=%d,ts=%ld,ls=%d]\n",b->media,MSDOS_SB(s)->cluster_size, + MSDOS_SB(s)->fats,MSDOS_SB(s)->fat_start,MSDOS_SB(s)-> + fat_length,MSDOS_SB(s)->dir_start,MSDOS_SB(s)->dir_entries, + MSDOS_SB(s)->data_start,CF_LE_W(*(unsigned short *) &b-> + sectors),b->total_sect,logical_sector_size); + } + if (error) { + if (!silent) + printk("VFS: Can't find a valid MSDOS filesystem on dev 0x%04x.\n", + s->s_dev); + s->s_dev = 0; + return NULL; + } + s->s_magic = MSDOS_SUPER_MAGIC; + MSDOS_SB(s)->name_check = check; + MSDOS_SB(s)->conversion = conversion; + /* set up enough so that it can read an inode */ + s->s_op = &msdos_sops; + MSDOS_SB(s)->fs_uid = uid; + MSDOS_SB(s)->fs_gid = gid; + MSDOS_SB(s)->fs_umask = umask; + MSDOS_SB(s)->quiet = quiet; + MSDOS_SB(s)->free_clusters = -1; /* don't know yet */ + MSDOS_SB(s)->fat_wait = NULL; + MSDOS_SB(s)->fat_lock = 0; + MSDOS_SB(s)->prev_free = 0; + if (!(s->s_mounted = iget(s,MSDOS_ROOT_INO))) { + s->s_dev = 0; + printk("get root inode failed\n"); + return NULL; + } + return s; +} + + +void msdos_statfs(struct super_block *sb,struct statfs *buf) +{ + int free,nr; + + put_fs_long(sb->s_magic,&buf->f_type); + put_fs_long(MSDOS_SB(sb)->cluster_size*SECTOR_SIZE,&buf->f_bsize); + put_fs_long(MSDOS_SB(sb)->clusters,&buf->f_blocks); + lock_fat(sb); + if (MSDOS_SB(sb)->free_clusters != -1) + free = MSDOS_SB(sb)->free_clusters; + else { + free = 0; + for (nr = 2; nr < MSDOS_SB(sb)->clusters+2; nr++) + if (!fat_access(sb,nr,-1)) free++; + MSDOS_SB(sb)->free_clusters = free; + } + unlock_fat(sb); + put_fs_long(free,&buf->f_bfree); + put_fs_long(free,&buf->f_bavail); + put_fs_long(0,&buf->f_files); + put_fs_long(0,&buf->f_ffree); + put_fs_long(12,&buf->f_namelen); +} + + +int msdos_bmap(struct inode *inode,int block) +{ + struct msdos_sb_info *sb; + int cluster,offset; + + sb = MSDOS_SB(inode->i_sb); + if ((sb->cluster_size & 1) || (sb->data_start & 1)) return 0; + if (inode->i_ino == MSDOS_ROOT_INO) { + if (sb->dir_start & 1) return 0; + return (sb->dir_start >> 1)+block; + } + cluster = (block*2)/sb->cluster_size; + offset = (block*2) % sb->cluster_size; + if (!(cluster = get_cluster(inode,cluster))) return 0; + return ((cluster-2)*sb->cluster_size+sb->data_start+offset) >> 1; +} + + +void msdos_read_inode(struct inode *inode) +{ + struct buffer_head *bh; + struct msdos_dir_entry *raw_entry; + int nr; + +/* printk("read inode %d\n",inode->i_ino); */ + MSDOS_I(inode)->i_busy = 0; + MSDOS_I(inode)->i_depend = MSDOS_I(inode)->i_old = NULL; + MSDOS_I(inode)->i_binary = 1; + inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid; + inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid; + if (inode->i_ino == MSDOS_ROOT_INO) { + inode->i_mode = (S_IRWXUGO & ~MSDOS_SB(inode->i_sb)->fs_umask) | + S_IFDIR; + inode->i_op = &msdos_dir_inode_operations; + inode->i_nlink = msdos_subdirs(inode)+2; + /* subdirs (neither . nor ..) plus . and "self" */ + inode->i_size = MSDOS_SB(inode->i_sb)->dir_entries* + sizeof(struct msdos_dir_entry); + inode->i_blksize = MSDOS_SB(inode->i_sb)->cluster_size* + SECTOR_SIZE; + inode->i_blocks = (inode->i_size+inode->i_blksize-1)/ + inode->i_blksize*MSDOS_SB(inode->i_sb)->cluster_size; + MSDOS_I(inode)->i_start = 0; + MSDOS_I(inode)->i_attrs = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = 0; + return; + } + if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS, + BLOCK_SIZE))) { + printk("dev = 0x%04X, ino = %ld\n",inode->i_dev,inode->i_ino); + panic("msdos_read_inode: unable to read i-node block"); + } + raw_entry = &((struct msdos_dir_entry *) (bh->b_data)) + [inode->i_ino & (MSDOS_DPB-1)]; + if ((raw_entry->attr & ATTR_DIR) && !IS_FREE(raw_entry->name)) { + inode->i_mode = MSDOS_MKMODE(raw_entry->attr,S_IRWXUGO & + ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IFDIR; + inode->i_op = &msdos_dir_inode_operations; + MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start); + inode->i_nlink = msdos_subdirs(inode); + /* includes .., compensating for "self" */ +#ifdef DEBUG + if (!inode->i_nlink) { + printk("directory %d: i_nlink == 0\n",inode->i_ino); + inode->i_nlink = 1; + } +#endif + inode->i_size = 0; + if ((nr = CF_LE_W(raw_entry->start)) != 0) + while (nr != -1) { + inode->i_size += SECTOR_SIZE*MSDOS_SB(inode-> + i_sb)->cluster_size; + if (!(nr = fat_access(inode->i_sb,nr,-1))) { + printk("Directory %ld: bad FAT\n", + inode->i_ino); + break; + } + } + } + else { + inode->i_mode = MSDOS_MKMODE(raw_entry->attr,(IS_NOEXEC(inode) + ? S_IRUGO|S_IWUGO : S_IRWXUGO) & ~MSDOS_SB(inode->i_sb)->fs_umask) | + S_IFREG; + inode->i_op = MSDOS_CAN_BMAP(MSDOS_SB(inode->i_sb)) ? + &msdos_file_inode_operations : + &msdos_file_inode_operations_no_bmap; + MSDOS_I(inode)->i_start = CF_LE_W(raw_entry->start); + inode->i_nlink = 1; + inode->i_size = CF_LE_L(raw_entry->size); + } + MSDOS_I(inode)->i_binary = is_binary(MSDOS_SB(inode->i_sb)->conversion, + raw_entry->ext); + MSDOS_I(inode)->i_attrs = raw_entry->attr & ATTR_UNUSED; + /* this is as close to the truth as we can get ... */ + inode->i_blksize = MSDOS_SB(inode->i_sb)->cluster_size*SECTOR_SIZE; + inode->i_blocks = (inode->i_size+inode->i_blksize-1)/ + inode->i_blksize*MSDOS_SB(inode->i_sb)->cluster_size; + inode->i_mtime = inode->i_atime = inode->i_ctime = + date_dos2unix(CF_LE_W(raw_entry->time),CF_LE_W(raw_entry->date)); + brelse(bh); +} + + +void msdos_write_inode(struct inode *inode) +{ + struct buffer_head *bh; + struct msdos_dir_entry *raw_entry; + + inode->i_dirt = 0; + if (inode->i_ino == MSDOS_ROOT_INO || !inode->i_nlink) return; + if (!(bh = bread(inode->i_dev,inode->i_ino >> MSDOS_DPB_BITS, + BLOCK_SIZE))) { + printk("dev = 0x%04X, ino = %ld\n",inode->i_dev,inode->i_ino); + panic("msdos_write_inode: unable to read i-node block"); + } + raw_entry = &((struct msdos_dir_entry *) (bh->b_data)) + [inode->i_ino & (MSDOS_DPB-1)]; + if (S_ISDIR(inode->i_mode)) { + raw_entry->attr = ATTR_DIR; + raw_entry->size = 0; + } + else { + raw_entry->attr = ATTR_NONE; + raw_entry->size = CT_LE_L(inode->i_size); + } + raw_entry->attr |= MSDOS_MKATTR(inode->i_mode) | + MSDOS_I(inode)->i_attrs; + raw_entry->start = CT_LE_L(MSDOS_I(inode)->i_start); + date_unix2dos(inode->i_mtime,&raw_entry->time,&raw_entry->date); + raw_entry->time = CT_LE_W(raw_entry->time); + raw_entry->date = CT_LE_W(raw_entry->date); + bh->b_dirt = 1; + brelse(bh); +} + + +int msdos_notify_change(int flags,struct inode *inode) +{ + int error; + + error = 0; + if ((flags & NOTIFY_UIDGID) && (inode->i_uid != MSDOS_SB(inode->i_sb)-> + fs_uid || inode->i_gid != MSDOS_SB(inode->i_sb)->fs_gid)) { + inode->i_uid = MSDOS_SB(inode->i_sb)->fs_uid; + inode->i_gid = MSDOS_SB(inode->i_sb)->fs_gid; + error = -EPERM; + } + if (!(flags & NOTIFY_MODE)) + return MSDOS_SB(inode->i_sb)->quiet ? 0 : error; + if (inode->i_mode & ~MSDOS_VALID_MODE) { + inode->i_mode &= MSDOS_VALID_MODE; + error = -EPERM; + } + if (IS_NOEXEC(inode) && !S_ISDIR(inode->i_mode)) + inode->i_mode &= S_IFMT | S_IRUGO | S_IWUGO; + else inode->i_mode |= S_IXUGO; + inode->i_mode = ((inode->i_mode & S_IFMT) | ((((inode->i_mode & S_IRWXU + & ~MSDOS_SB(inode->i_sb)->fs_umask) | S_IRUSR) >> 6)*S_IXUGO)) & + ~MSDOS_SB(inode->i_sb)->fs_umask; + return MSDOS_SB(inode->i_sb)->quiet ? 0 : error; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/misc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/misc.c new file mode 100644 index 000000000..49b7215c8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/misc.c @@ -0,0 +1,523 @@ +/* + * linux/fs/msdos/misc.c + * + * Written 1992,1993 by Werner Almesberger + */ + +#include +#include +#include +#include +#include +#include +#include + +/* Well-known binary file extensions */ + +static char bin_extensions[] = + "EXECOMBINAPPSYSDRVOVLOVROBJLIBDLLPIF" /* program code */ + "ARCZIPLHALZHZOOTARZ ARJ" /* common archivers */ + "TZ TAZTZPTPZ" /* abbreviations of tar.Z and tar.zip */ + "GIFBMPTIFGL JPGPCX" /* graphics */ + "TFMVF GF PK PXLDVI"; /* TeX */ + + +/* + * fs_panic reports a severe file system problem and sets the file system + * read-only. The file system can be made writable again by remounting it. + */ + +void fs_panic(struct super_block *s,char *msg) +{ + int not_ro; + + not_ro = !(s->s_flags & MS_RDONLY); + if (not_ro) s->s_flags |= MS_RDONLY; + printk("Filesystem panic (dev 0x%04X, mounted on 0x%04X:%ld)\n %s\n", + s->s_dev,s->s_covered->i_dev,s->s_covered->i_ino,msg); + if (not_ro) + printk(" File system has been set read-only\n"); +} + + +/* + * is_binary selects optional text conversion based on the conversion mode and + * the extension part of the file name. + */ + +int is_binary(char conversion,char *extension) +{ + char *walk; + + switch (conversion) { + case 'b': + return 1; + case 't': + return 0; + case 'a': + for (walk = bin_extensions; *walk; walk += 3) + if (!strncmp(extension,walk,3)) return 1; + return 0; + default: + printk("Invalid conversion mode - defaulting to " + "binary.\n"); + return 1; + } +} + + +/* File creation lock. This is system-wide to avoid deadlocks in rename. */ +/* (rename might deadlock before detecting cross-FS moves.) */ + +static struct wait_queue *creation_wait = NULL; +static creation_lock = 0; + + +void lock_creation(void) +{ + while (creation_lock) sleep_on(&creation_wait); + creation_lock = 1; +} + + +void unlock_creation(void) +{ + creation_lock = 0; + wake_up(&creation_wait); +} + + +void lock_fat(struct super_block *sb) +{ + while (MSDOS_SB(sb)->fat_lock) sleep_on(&MSDOS_SB(sb)->fat_wait); + MSDOS_SB(sb)->fat_lock = 1; +} + + +void unlock_fat(struct super_block *sb) +{ + MSDOS_SB(sb)->fat_lock = 0; + wake_up(&MSDOS_SB(sb)->fat_wait); +} + + +/* + * msdos_add_cluster tries to allocate a new cluster and adds it to the file + * represented by inode. The cluster is zero-initialized. + */ + +int msdos_add_cluster(struct inode *inode) +{ + int count,nr,limit,last,current,sector; + void *data; + struct buffer_head *bh; + + if (inode->i_ino == MSDOS_ROOT_INO) return -ENOSPC; + if (!MSDOS_SB(inode->i_sb)->free_clusters) return -ENOSPC; + lock_fat(inode->i_sb); + limit = MSDOS_SB(inode->i_sb)->clusters; + nr = limit; /* to keep GCC happy */ + for (count = 0; count < limit; count++) { + nr = ((count+MSDOS_SB(inode->i_sb)->prev_free) % limit)+2; + if (fat_access(inode->i_sb,nr,-1) == 0) break; + } +#ifdef DEBUG +printk("free cluster: %d\n",nr); +#endif + MSDOS_SB(inode->i_sb)->prev_free = (count+MSDOS_SB(inode->i_sb)-> + prev_free+1) % limit; + if (count >= limit) { + MSDOS_SB(inode->i_sb)->free_clusters = 0; + unlock_fat(inode->i_sb); + return -ENOSPC; + } + fat_access(inode->i_sb,nr,MSDOS_SB(inode->i_sb)->fat_bits == 12 ? + 0xff8 : 0xfff8); + if (MSDOS_SB(inode->i_sb)->free_clusters != -1) + MSDOS_SB(inode->i_sb)->free_clusters--; + unlock_fat(inode->i_sb); +#ifdef DEBUG +printk("set to %x\n",fat_access(inode->i_sb,nr,-1)); +#endif + last = 0; + if ((current = MSDOS_I(inode)->i_start) != 0) { + cache_lookup(inode,INT_MAX,&last,¤t); + while (current && current != -1) + if (!(current = fat_access(inode->i_sb, + last = current,-1))) { + fs_panic(inode->i_sb,"File without EOF"); + return -ENOSPC; + } + } +#ifdef DEBUG +printk("last = %d\n",last); +#endif + if (last) fat_access(inode->i_sb,last,nr); + else { + MSDOS_I(inode)->i_start = nr; + inode->i_dirt = 1; + } +#ifdef DEBUG +if (last) printk("next set to %d\n",fat_access(inode->i_sb,last,-1)); +#endif + for (current = 0; current < MSDOS_SB(inode->i_sb)->cluster_size; + current++) { + sector = MSDOS_SB(inode->i_sb)->data_start+(nr-2)* + MSDOS_SB(inode->i_sb)->cluster_size+current; +#ifdef DEBUG +printk("zeroing sector %d\n",sector); +#endif + if (current < MSDOS_SB(inode->i_sb)->cluster_size-1 && + !(sector & 1)) { + if (!(bh = getblk(inode->i_dev,sector >> 1, + BLOCK_SIZE))) + printk("getblk failed\n"); + else { + memset(bh->b_data,0,BLOCK_SIZE); + bh->b_uptodate = 1; + } + current++; + } + else { + if (!(bh = msdos_sread(inode->i_dev,sector, + &data))) + printk("msdos_sread failed\n"); + else memset(data,0,SECTOR_SIZE); + } + if (bh) { + bh->b_dirt = 1; + brelse(bh); + } + } + inode->i_blocks += MSDOS_SB(inode->i_sb)->cluster_size; + if (S_ISDIR(inode->i_mode)) { + if (inode->i_size & (SECTOR_SIZE-1)) { + fs_panic(inode->i_sb,"Odd directory size"); + inode->i_size = (inode->i_size+SECTOR_SIZE) & + ~(SECTOR_SIZE-1); + } + inode->i_size += SECTOR_SIZE*MSDOS_SB(inode->i_sb)-> + cluster_size; +#ifdef DEBUG +printk("size is %d now (%x)\n",inode->i_size,inode); +#endif + inode->i_dirt = 1; + } + return 0; +} + + +/* Linear day numbers of the respective 1sts in non-leap years. */ + +static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 }; + /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */ + + +extern struct timezone sys_tz; + + +/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ + +int date_dos2unix(unsigned short time,unsigned short date) +{ + int month,year,secs; + + month = ((date >> 5) & 15)-1; + year = date >> 9; + secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400* + ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 && + month < 2 ? 1 : 0)+3653); + /* days since 1.1.70 plus 80's leap day */ + secs += sys_tz.tz_minuteswest*60; + return secs; +} + + +/* Convert linear UNIX date to a MS-DOS time/date pair. */ + +void date_unix2dos(int unix_date,unsigned short *time, + unsigned short *date) +{ + int day,year,nl_day,month; + + unix_date -= sys_tz.tz_minuteswest*60; + *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+ + (((unix_date/3600) % 24) << 11); + day = unix_date/86400-3652; + year = day/365; + if ((year+3)/4+365*year > day) year--; + day -= (year+3)/4+365*year; + if (day == 59 && !(year & 3)) { + nl_day = day; + month = 2; + } + else { + nl_day = (year & 3) || day <= 59 ? day : day-1; + for (month = 0; month < 12; month++) + if (day_n[month] > nl_day) break; + } + *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9); +} + + +/* Returns the inode number of the directory entry at offset pos. If bh is + non-NULL, it is brelse'd before. Pos is incremented. The buffer header is + returned in bh. */ + +int msdos_get_entry(struct inode *dir, off_t *pos,struct buffer_head **bh, + struct msdos_dir_entry **de) +{ + int sector,offset; + void *data; + + while (1) { + offset = *pos; + if ((sector = msdos_smap(dir,offset >> SECTOR_BITS)) == -1) + return -1; + if (!sector) + return -1; /* beyond EOF */ + *pos += sizeof(struct msdos_dir_entry); + if (*bh) + brelse(*bh); + if (!(*bh = msdos_sread(dir->i_dev,sector,&data))) { + printk("Directory sread (sector %d) failed\n",sector); + continue; + } + *de = (struct msdos_dir_entry *) (data+(offset & + (SECTOR_SIZE-1))); + return (sector << MSDOS_DPS_BITS)+((offset & (SECTOR_SIZE-1)) >> + MSDOS_DIR_BITS); + } +} + + +/* + * Now an ugly part: this set of directory scan routines works on clusters + * rather than on inodes and sectors. They are necessary to locate the '..' + * directory "inode". raw_scan_sector operates in four modes: + * + * name number ino action + * -------- -------- -------- ------------------------------------------------- + * non-NULL - X Find an entry with that name + * NULL non-NULL non-NULL Find an entry whose data starts at *number + * NULL non-NULL NULL Count subdirectories in *number. (*) + * NULL NULL non-NULL Find an empty entry + * + * (*) The return code should be ignored. It DOES NOT indicate success or + * failure. *number has to be initialized to zero. + * + * - = not used, X = a value is returned unless NULL + * + * If res_bh is non-NULL, the buffer is not deallocated but returned to the + * caller on success. res_de is set accordingly. + * + * If cont is non-zero, raw_found continues with the entry after the one + * res_bh/res_de point to. + */ + + +#define RSS_NAME /* search for name */ \ + done = !strncmp(data[entry].name,name,MSDOS_NAME) && \ + !(data[entry].attr & ATTR_VOLUME); + +#define RSS_START /* search for start cluster */ \ + done = !IS_FREE(data[entry].name) && CF_LE_W(data[entry].start) == *number; + +#define RSS_FREE /* search for free entry */ \ + { \ + done = IS_FREE(data[entry].name); \ + if (done) { \ + inode = iget(sb,sector*MSDOS_DPS+entry); \ + if (inode) { \ + /* Directory slots of busy deleted files aren't available yet. */ \ + done = !MSDOS_I(inode)->i_busy; \ + iput(inode); \ + } \ + } \ + } + +#define RSS_COUNT /* count subdirectories */ \ + { \ + done = 0; \ + if (!IS_FREE(data[entry].name) && (data[entry].attr & ATTR_DIR)) \ + (*number)++; \ + } + +static int raw_scan_sector(struct super_block *sb,int sector,char *name, + int *number,int *ino,struct buffer_head **res_bh, + struct msdos_dir_entry **res_de) +{ + struct buffer_head *bh; + struct msdos_dir_entry *data; + struct inode *inode; + int entry,start,done; + + if (!(bh = msdos_sread(sb->s_dev,sector,(void **) &data))) return -EIO; + for (entry = 0; entry < MSDOS_DPS; entry++) { + if (name) RSS_NAME + else { + if (!ino) RSS_COUNT + else { + if (number) RSS_START + else RSS_FREE + } + } + if (done) { + if (ino) *ino = sector*MSDOS_DPS+entry; + start = CF_LE_W(data[entry].start); + if (!res_bh) brelse(bh); + else { + *res_bh = bh; + *res_de = &data[entry]; + } + return start; + } + } + brelse(bh); + return -ENOENT; +} + + +/* + * raw_scan_root performs raw_scan_sector on the root directory until the + * requested entry is found or the end of the directory is reached. + */ + +static int raw_scan_root(struct super_block *sb,char *name,int *number,int *ino, + struct buffer_head **res_bh,struct msdos_dir_entry **res_de) +{ + int count,cluster; + + for (count = 0; count < MSDOS_SB(sb)->dir_entries/MSDOS_DPS; count++) { + if ((cluster = raw_scan_sector(sb,MSDOS_SB(sb)->dir_start+count, + name,number,ino,res_bh,res_de)) >= 0) return cluster; + } + return -ENOENT; +} + + +/* + * raw_scan_nonroot performs raw_scan_sector on a non-root directory until the + * requested entry is found or the end of the directory is reached. + */ + +static int raw_scan_nonroot(struct super_block *sb,int start,char *name, + int *number,int *ino,struct buffer_head **res_bh,struct msdos_dir_entry + **res_de) +{ + int count,cluster; + +#ifdef DEBUG + printk("raw_scan_nonroot: start=%d\n",start); +#endif + do { + for (count = 0; count < MSDOS_SB(sb)->cluster_size; count++) { + if ((cluster = raw_scan_sector(sb,(start-2)* + MSDOS_SB(sb)->cluster_size+MSDOS_SB(sb)->data_start+ + count,name,number,ino,res_bh,res_de)) >= 0) + return cluster; + } + if (!(start = fat_access(sb,start,-1))) { + fs_panic(sb,"FAT error"); + break; + } +#ifdef DEBUG + printk("next start: %d\n",start); +#endif + } + while (start != -1); + return -ENOENT; +} + + +/* + * raw_scan performs raw_scan_sector on any sector. + * + * NOTE: raw_scan must not be used on a directory that is is the process of + * being created. + */ + +static int raw_scan(struct super_block *sb,int start,char *name,int *number, + int *ino,struct buffer_head **res_bh,struct msdos_dir_entry **res_de) +{ + if (start) + return raw_scan_nonroot(sb,start,name,number,ino,res_bh,res_de); + else return raw_scan_root(sb,name,number,ino,res_bh,res_de); +} + + +/* + * msdos_parent_ino returns the inode number of the parent directory of dir. + * File creation has to be deferred while msdos_parent_ino is running to + * prevent renames. + */ + +int msdos_parent_ino(struct inode *dir,int locked) +{ + static int zero = 0; + int error,current,prev,nr; + + if (!S_ISDIR(dir->i_mode)) panic("Non-directory fed to m_p_i"); + if (dir->i_ino == MSDOS_ROOT_INO) return dir->i_ino; + if (!locked) lock_creation(); /* prevent renames */ + if ((current = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,MSDOS_DOTDOT, + &zero,NULL,NULL,NULL)) < 0) { + if (!locked) unlock_creation(); + return current; + } + if (!current) nr = MSDOS_ROOT_INO; + else { + if ((prev = raw_scan(dir->i_sb,current,MSDOS_DOTDOT,&zero,NULL, + NULL,NULL)) < 0) { + if (!locked) unlock_creation(); + return prev; + } + if ((error = raw_scan(dir->i_sb,prev,NULL,¤t,&nr,NULL, + NULL)) < 0) { + if (!locked) unlock_creation(); + return error; + } + } + if (!locked) unlock_creation(); + return nr; +} + + +/* + * msdos_subdirs counts the number of sub-directories of dir. It can be run + * on directories being created. + */ + +int msdos_subdirs(struct inode *dir) +{ + int count; + + count = 0; + if (dir->i_ino == MSDOS_ROOT_INO) + (void) raw_scan_root(dir->i_sb,NULL,&count,NULL,NULL,NULL); + else { + if (!MSDOS_I(dir)->i_start) return 0; /* in mkdir */ + else (void) raw_scan_nonroot(dir->i_sb,MSDOS_I(dir)->i_start, + NULL,&count,NULL,NULL,NULL); + } + return count; +} + + +/* + * Scans a directory for a given file (name points to its formatted name) or + * for an empty directory slot (name is NULL). Returns an error code or zero. + */ + +int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh, + struct msdos_dir_entry **res_de,int *ino) +{ + int res; + + if (name) + res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,name,NULL,ino, + res_bh,res_de); + else res = raw_scan(dir->i_sb,MSDOS_I(dir)->i_start,NULL,NULL,ino, + res_bh,res_de); + return res < 0 ? res : 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/namei.c new file mode 100644 index 000000000..cf64067c9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/msdos/namei.c @@ -0,0 +1,592 @@ +/* + * linux/fs/msdos/namei.c + * + * Written 1992,1993 by Werner Almesberger + */ + +#include + +#include +#include +#include +#include +#include +#include + +/* MS-DOS "device special files" */ + +static char *reserved_names[] = { + "CON ","PRN ","NUL ","AUX ", + "LPT1 ","LPT2 ","LPT3 ","LPT4 ", + "COM1 ","COM2 ","COM3 ","COM4 ", + NULL }; + + +/* Characters that are undesirable in an MS-DOS file name */ + +static char bad_chars[] = "*?<>|\""; +static char bad_if_strict[] = "+=,; "; + + +/* Formats an MS-DOS file name. Rejects invalid names. */ + +static int msdos_format_name(char conv,const char *name,int len,char *res, + int dot_dirs) +{ + char *walk,**reserved; + unsigned char c; + int space; + + if (IS_FREE(name)) return -EINVAL; + if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) { + if (!dot_dirs) return -EEXIST; + memset(res+1,' ',10); + while (len--) *res++ = '.'; + return 0; + } + space = 1; /* disallow names starting with a dot */ + c = 0; + for (walk = res; len && walk-res < 8; walk++) { + c = *name++; + len--; + if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; + if (conv == 's' && strchr(bad_if_strict,c)) return -EINVAL; + if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL; + if (c < ' ' || c == ':' || c == '\\') return -EINVAL; + if (c == '.') break; + space = c == ' '; + *walk = c >= 'a' && c <= 'z' ? c-32 : c; + } + if (space) return -EINVAL; + if (conv == 's' && len && c != '.') { + c = *name++; + len--; + if (c != '.') return -EINVAL; + } + while (c != '.' && len--) c = *name++; + if (c == '.') { + while (walk-res < 8) *walk++ = ' '; + while (len > 0 && walk-res < MSDOS_NAME) { + c = *name++; + len--; + if (conv != 'r' && strchr(bad_chars,c)) return -EINVAL; + if (conv == 's' && strchr(bad_if_strict,c)) + return -EINVAL; + if (c < ' ' || c == ':' || c == '\\' || c == '.') + return -EINVAL; + if (c >= 'A' && c <= 'Z' && conv == 's') return -EINVAL; + space = c == ' '; + *walk++ = c >= 'a' && c <= 'z' ? c-32 : c; + } + if (space) return -EINVAL; + if (conv == 's' && len) return -EINVAL; + } + while (walk-res < MSDOS_NAME) *walk++ = ' '; + for (reserved = reserved_names; *reserved; reserved++) + if (!strncmp(res,*reserved,8)) return -EINVAL; + return 0; +} + + +/* Locates a directory entry. */ + +static int msdos_find(struct inode *dir,const char *name,int len, + struct buffer_head **bh,struct msdos_dir_entry **de,int *ino) +{ + char msdos_name[MSDOS_NAME]; + int res; + + if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, + msdos_name,1)) < 0) return res; + return msdos_scan(dir,msdos_name,bh,de,ino); +} + + +int msdos_lookup(struct inode *dir,const char *name,int len, + struct inode **result) +{ + int ino,res; + struct msdos_dir_entry *de; + struct buffer_head *bh; + struct inode *next; + + *result = NULL; + if (!dir) return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (len == 1 && name[0] == '.') { + *result = dir; + return 0; + } + if (len == 2 && name[0] == '.' && name[1] == '.') { + ino = msdos_parent_ino(dir,0); + iput(dir); + if (ino < 0) return ino; + if (!(*result = iget(dir->i_sb,ino))) return -EACCES; + return 0; + } + if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) { + iput(dir); + return res; + } + if (bh) brelse(bh); +/* printk("lookup: ino=%d\n",ino); */ + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -EACCES; + } + if (MSDOS_I(*result)->i_busy) { /* mkdir in progress */ + iput(*result); + iput(dir); + return -ENOENT; + } + while (MSDOS_I(*result)->i_old) { + next = MSDOS_I(*result)->i_old; + iput(*result); + if (!(*result = iget(next->i_sb,next->i_ino))) { + fs_panic(dir->i_sb,"msdos_lookup: Can't happen"); + iput(dir); + return -ENOENT; + } + } + iput(dir); + return 0; +} + + +/* Creates a directory entry (name is already formatted). */ + +static int msdos_create_entry(struct inode *dir,char *name,int is_dir, + struct inode **result) +{ + struct buffer_head *bh; + struct msdos_dir_entry *de; + int res,ino; + + if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) { + if (res != -ENOENT) return res; + if (dir->i_ino == MSDOS_ROOT_INO) return -ENOSPC; + if ((res = msdos_add_cluster(dir)) < 0) return res; + if ((res = msdos_scan(dir,NULL,&bh,&de,&ino)) < 0) return res; + } + /* + * XXX all times should be set by caller upon successful completion. + */ + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + memcpy(de->name,name,MSDOS_NAME); + de->attr = is_dir ? ATTR_DIR : ATTR_ARCH; + de->start = 0; + date_unix2dos(dir->i_mtime,&de->time,&de->date); + de->size = 0; + bh->b_dirt = 1; + if ((*result = iget(dir->i_sb,ino)) != NULL) + msdos_read_inode(*result); + brelse(bh); + if (!*result) return -EIO; + (*result)->i_mtime = (*result)->i_atime = (*result)->i_ctime = + CURRENT_TIME; + (*result)->i_dirt = 1; + return 0; +} + + +int msdos_create(struct inode *dir,const char *name,int len,int mode, + struct inode **result) +{ + struct buffer_head *bh; + struct msdos_dir_entry *de; + char msdos_name[MSDOS_NAME]; + int ino,res; + + if (!dir) return -ENOENT; + if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, + msdos_name,0)) < 0) { + iput(dir); + return res; + } + lock_creation(); + if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { + unlock_creation(); + brelse(bh); + iput(dir); + return -EEXIST; + } + res = msdos_create_entry(dir,msdos_name,S_ISDIR(mode),result); + unlock_creation(); + iput(dir); + return res; +} + + +#ifdef DEBUG + +static void dump_fat(struct super_block *sb,int start) +{ + printk("["); + while (start) { + printk("%d ",start); + start = fat_access(sb,start,-1); + if (!start) { + printk("ERROR"); + break; + } + if (start == -1) break; + } + printk("]\n"); +} + +#endif + + +int msdos_mkdir(struct inode *dir,const char *name,int len,int mode) +{ + struct buffer_head *bh; + struct msdos_dir_entry *de; + struct inode *inode,*dot; + char msdos_name[MSDOS_NAME]; + int ino,res; + + if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->name_check,name,len, + msdos_name,0)) < 0) { + iput(dir); + return res; + } + lock_creation(); + if (msdos_scan(dir,msdos_name,&bh,&de,&ino) >= 0) { + unlock_creation(); + brelse(bh); + iput(dir); + return -EEXIST; + } + if ((res = msdos_create_entry(dir,msdos_name,1,&inode)) < 0) { + unlock_creation(); + iput(dir); + return res; + } + dir->i_nlink++; + inode->i_nlink = 2; /* no need to mark them dirty */ + MSDOS_I(inode)->i_busy = 1; /* prevent lookups */ + if ((res = msdos_add_cluster(inode)) < 0) goto mkdir_error; + if ((res = msdos_create_entry(inode,MSDOS_DOT,1,&dot)) < 0) + goto mkdir_error; + dot->i_size = inode->i_size; /* doesn't grow in the 2nd create_entry */ + MSDOS_I(dot)->i_start = MSDOS_I(inode)->i_start; + dot->i_nlink = inode->i_nlink; + dot->i_dirt = 1; + iput(dot); + if ((res = msdos_create_entry(inode,MSDOS_DOTDOT,1,&dot)) < 0) + goto mkdir_error; + unlock_creation(); + dot->i_size = dir->i_size; + MSDOS_I(dot)->i_start = MSDOS_I(dir)->i_start; + dot->i_nlink = dir->i_nlink; + dot->i_dirt = 1; + MSDOS_I(inode)->i_busy = 0; + iput(dot); + iput(inode); + iput(dir); + return 0; +mkdir_error: + iput(inode); + if (msdos_rmdir(dir,name,len) < 0) + fs_panic(dir->i_sb,"rmdir in mkdir failed"); + unlock_creation(); + return res; +} + + +static int msdos_empty(struct inode *dir) +{ + off_t pos; + struct buffer_head *bh; + struct msdos_dir_entry *de; + + if (dir->i_count > 1) + return -EBUSY; + if (MSDOS_I(dir)->i_start) { /* may be zero in mkdir */ + pos = 0; + bh = NULL; + while (msdos_get_entry(dir,&pos,&bh,&de) > -1) + if (!IS_FREE(de->name) && strncmp(de->name,MSDOS_DOT, + MSDOS_NAME) && strncmp(de->name,MSDOS_DOTDOT, + MSDOS_NAME)) { + brelse(bh); + return -ENOTEMPTY; + } + if (bh) + brelse(bh); + } + return 0; +} + + +int msdos_rmdir(struct inode *dir,const char *name,int len) +{ + int res,ino; + struct buffer_head *bh; + struct msdos_dir_entry *de; + struct inode *inode; + + bh = NULL; + inode = NULL; + res = -EPERM; + if (name[0] == '.' && (len == 1 || (len == 2 && name[1] == '.'))) + goto rmdir_done; + if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) goto rmdir_done; + res = -ENOENT; + if (!(inode = iget(dir->i_sb,ino))) goto rmdir_done; + res = -ENOTDIR; + if (!S_ISDIR(inode->i_mode)) goto rmdir_done; + res = -EBUSY; + if (dir->i_dev != inode->i_dev || dir == inode) goto rmdir_done; + res = msdos_empty(inode); + if (res) + goto rmdir_done; + inode->i_nlink = 0; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_nlink--; + inode->i_dirt = dir->i_dirt = 1; + de->name[0] = DELETED_FLAG; + bh->b_dirt = 1; + res = 0; +rmdir_done: + brelse(bh); + iput(dir); + iput(inode); + return res; +} + + +int msdos_unlink(struct inode *dir,const char *name,int len) +{ + int res,ino; + struct buffer_head *bh; + struct msdos_dir_entry *de; + struct inode *inode; + + bh = NULL; + inode = NULL; + if ((res = msdos_find(dir,name,len,&bh,&de,&ino)) < 0) + goto unlink_done; + if (!(inode = iget(dir->i_sb,ino))) { + res = -ENOENT; + goto unlink_done; + } + if (!S_ISREG(inode->i_mode)) { + res = -EPERM; + goto unlink_done; + } + inode->i_nlink = 0; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + MSDOS_I(inode)->i_busy = 1; + inode->i_dirt = dir->i_dirt = 1; + de->name[0] = DELETED_FLAG; + bh->b_dirt = 1; +unlink_done: + brelse(bh); + iput(inode); + iput(dir); + return res; +} + + +static int rename_same_dir(struct inode *old_dir,char *old_name, + struct inode *new_dir,char *new_name,struct buffer_head *old_bh, + struct msdos_dir_entry *old_de,int old_ino) +{ + struct buffer_head *new_bh; + struct msdos_dir_entry *new_de; + struct inode *new_inode,*old_inode; + int new_ino,exists,error; + + if (!strncmp(old_name,new_name,MSDOS_NAME)) return 0; + exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0; + if (*(unsigned char *) old_de->name == DELETED_FLAG) { + if (exists) brelse(new_bh); + return -ENOENT; + } + if (exists) { + if (!(new_inode = iget(new_dir->i_sb,new_ino))) { + brelse(new_bh); + return -EIO; + } + error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ? + msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR) + ? -EPERM : 0; + if (error) { + iput(new_inode); + brelse(new_bh); + return error; + } + if (S_ISDIR(new_inode->i_mode)) { + new_dir->i_nlink--; + new_dir->i_dirt = 1; + } + new_inode->i_nlink = 0; + MSDOS_I(new_inode)->i_busy = 1; + new_inode->i_dirt = 1; + new_de->name[0] = DELETED_FLAG; + new_bh->b_dirt = 1; + iput(new_inode); + brelse(new_bh); + } + memcpy(old_de->name,new_name,MSDOS_NAME); + old_bh->b_dirt = 1; + if (MSDOS_SB(old_dir->i_sb)->conversion == 'a') /* update binary info */ + if ((old_inode = iget(old_dir->i_sb,old_ino)) != NULL) { + msdos_read_inode(old_inode); + iput(old_inode); + } + return 0; +} + + +static int rename_diff_dir(struct inode *old_dir,char *old_name, + struct inode *new_dir,char *new_name,struct buffer_head *old_bh, + struct msdos_dir_entry *old_de,int old_ino) +{ + struct buffer_head *new_bh,*free_bh,*dotdot_bh; + struct msdos_dir_entry *new_de,*free_de,*dotdot_de; + struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode,*walk; + int new_ino,free_ino,dotdot_ino; + int error,exists,ino; + + if (old_dir->i_dev != new_dir->i_dev) return -EINVAL; + if (old_ino == new_dir->i_ino) return -EINVAL; + if (!(walk = iget(new_dir->i_sb,new_dir->i_ino))) return -EIO; + while (walk->i_ino != MSDOS_ROOT_INO) { + ino = msdos_parent_ino(walk,1); + iput(walk); + if (ino < 0) return ino; + if (ino == old_ino) return -EINVAL; + if (!(walk = iget(new_dir->i_sb,ino))) return -EIO; + } + iput(walk); + while ((error = msdos_scan(new_dir,NULL,&free_bh,&free_de,&free_ino)) < + 0) { + if (error != -ENOENT) return error; + error = msdos_add_cluster(new_dir); + if (error) return error; + } + exists = msdos_scan(new_dir,new_name,&new_bh,&new_de,&new_ino) >= 0; + if (!(old_inode = iget(old_dir->i_sb,old_ino))) { + brelse(free_bh); + if (exists) brelse(new_bh); + return -EIO; + } + if (*(unsigned char *) old_de->name == DELETED_FLAG) { + iput(old_inode); + brelse(free_bh); + if (exists) brelse(new_bh); + return -ENOENT; + } + new_inode = NULL; /* to make GCC happy */ + if (exists) { + if (!(new_inode = iget(new_dir->i_sb,new_ino))) { + iput(old_inode); + brelse(new_bh); + return -EIO; + } + error = S_ISDIR(new_inode->i_mode) ? (old_de->attr & ATTR_DIR) ? + msdos_empty(new_inode) : -EPERM : (old_de->attr & ATTR_DIR) + ? -EPERM : 0; + if (error) { + iput(new_inode); + iput(old_inode); + brelse(new_bh); + return error; + } + new_inode->i_nlink = 0; + MSDOS_I(new_inode)->i_busy = 1; + new_inode->i_dirt = 1; + new_de->name[0] = DELETED_FLAG; + new_bh->b_dirt = 1; + } + memcpy(free_de,old_de,sizeof(struct msdos_dir_entry)); + memcpy(free_de->name,new_name,MSDOS_NAME); + if (!(free_inode = iget(new_dir->i_sb,free_ino))) { + free_de->name[0] = DELETED_FLAG; +/* Don't mark free_bh as dirty. Both states are supposed to be equivalent. */ + brelse(free_bh); + if (exists) { + iput(new_inode); + brelse(new_bh); + } + return -EIO; + } + if (exists && S_ISDIR(new_inode->i_mode)) { + new_dir->i_nlink--; + new_dir->i_dirt = 1; + } + msdos_read_inode(free_inode); + MSDOS_I(old_inode)->i_busy = 1; + cache_inval_inode(old_inode); + old_inode->i_dirt = 1; + old_de->name[0] = DELETED_FLAG; + old_bh->b_dirt = 1; + free_bh->b_dirt = 1; + if (!exists) iput(free_inode); + else { + MSDOS_I(new_inode)->i_depend = free_inode; + MSDOS_I(free_inode)->i_old = new_inode; + /* free_inode is put when putting new_inode */ + iput(new_inode); + brelse(new_bh); + } + if (S_ISDIR(old_inode->i_mode)) { + if ((error = msdos_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh, + &dotdot_de,&dotdot_ino)) < 0) goto rename_done; + if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) { + brelse(dotdot_bh); + error = -EIO; + goto rename_done; + } + dotdot_de->start = MSDOS_I(dotdot_inode)->i_start = + MSDOS_I(new_dir)->i_start; + dotdot_inode->i_dirt = 1; + dotdot_bh->b_dirt = 1; + old_dir->i_nlink--; + new_dir->i_nlink++; + /* no need to mark them dirty */ + dotdot_inode->i_nlink = new_dir->i_nlink; + iput(dotdot_inode); + brelse(dotdot_bh); + } + error = 0; +rename_done: + brelse(free_bh); + iput(old_inode); + return error; +} + + +int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, + struct inode *new_dir,const char *new_name,int new_len) +{ + char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME]; + struct buffer_head *old_bh; + struct msdos_dir_entry *old_de; + int old_ino,error; + + if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->name_check, + old_name,old_len,old_msdos_name,1)) < 0) goto rename_done; + if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->name_check, + new_name,new_len,new_msdos_name,0)) < 0) goto rename_done; + if ((error = msdos_scan(old_dir,old_msdos_name,&old_bh,&old_de, + &old_ino)) < 0) goto rename_done; + lock_creation(); + if (old_dir == new_dir) + error = rename_same_dir(old_dir,old_msdos_name,new_dir, + new_msdos_name,old_bh,old_de,old_ino); + else error = rename_diff_dir(old_dir,old_msdos_name,new_dir, + new_msdos_name,old_bh,old_de,old_ino); + unlock_creation(); + brelse(old_bh); +rename_done: + iput(old_dir); + iput(new_dir); + return error; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/namei.c new file mode 100644 index 000000000..92736274b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/namei.c @@ -0,0 +1,741 @@ +/* + * linux/fs/namei.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * Some corrections by tytso. + */ + +#include + +#include +#include +#include +#include +#include +#include + +#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) + +/* + * In order to reduce some races, while at the same time doing additional + * checking and hopefully speeding things up, we copy filenames to the + * kernel data space before using them.. + * + * POSIX.1 2.4: an empty pathname is invalid (ENOENT). + */ +int getname(const char * filename, char **result) +{ + int error; + unsigned long i, page; + char * tmp, c; + + i = (unsigned long) filename; + if (!i || i >= TASK_SIZE) + return -EFAULT; + i = TASK_SIZE - i; + error = -EFAULT; + if (i > PAGE_SIZE) { + i = PAGE_SIZE; + error = -ENAMETOOLONG; + } + c = get_fs_byte(filename++); + if (!c) + return -ENOENT; + if(!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + *result = tmp = (char *) page; + while (--i) { + *(tmp++) = c; + c = get_fs_byte(filename++); + if (!c) { + *tmp = '\0'; + return 0; + } + } + free_page(page); + return error; +} + +void putname(char * name) +{ + free_page((unsigned long) name); +} + +/* + * permission() + * + * is used to check for read/write/execute permissions on a file. + * I don't know if we should look at just the euid or both euid and + * uid, but that should be easily changed. + */ +int permission(struct inode * inode,int mask) +{ + int mode = inode->i_mode; + + if (inode->i_op && inode->i_op->permission) + return inode->i_op->permission(inode, mask); + else if (current->euid == inode->i_uid) + mode >>= 6; + else if (in_group_p(inode->i_gid)) + mode >>= 3; + if (((mode & mask & 0007) == mask) || suser()) + return 1; + return 0; +} + +/* + * lookup() looks up one part of a pathname, using the fs-dependent + * routines (currently minix_lookup) for it. It also checks for + * fathers (pseudo-roots, mount-points) + */ +int lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + struct super_block * sb; + int perm; + + *result = NULL; + if (!dir) + return -ENOENT; +/* check permissions before traversing mount-points */ + perm = permission(dir,MAY_EXEC); + if (len==2 && name[0] == '.' && name[1] == '.') { + if (dir == current->root) { + *result = dir; + return 0; + } else if ((sb = dir->i_sb) && (dir == sb->s_mounted)) { + sb = dir->i_sb; + iput(dir); + dir = sb->s_covered; + if (!dir) + return -ENOENT; + dir->i_count++; + } + } + if (!dir->i_op || !dir->i_op->lookup) { + iput(dir); + return -ENOTDIR; + } + if (!perm) { + iput(dir); + return -EACCES; + } + if (!len) { + *result = dir; + return 0; + } + return dir->i_op->lookup(dir,name,len,result); +} + +int follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + if (!dir || !inode) { + iput(dir); + iput(inode); + *res_inode = NULL; + return -ENOENT; + } + if (!inode->i_op || !inode->i_op->follow_link) { + iput(dir); + *res_inode = inode; + return 0; + } + return inode->i_op->follow_link(dir,inode,flag,mode,res_inode); +} + +/* + * dir_namei() + * + * dir_namei() returns the inode of the directory of the + * specified name, and the name within that directory. + */ +static int dir_namei(const char * pathname, int * namelen, const char ** name, + struct inode * base, struct inode ** res_inode) +{ + char c; + const char * thisname; + int len,error; + struct inode * inode; + + *res_inode = NULL; + if (!base) { + base = current->pwd; + base->i_count++; + } + if ((c = *pathname) == '/') { + iput(base); + base = current->root; + pathname++; + base->i_count++; + } + while (1) { + thisname = pathname; + for(len=0;(c = *(pathname++))&&(c != '/');len++) + /* nothing */ ; + if (!c) + break; + base->i_count++; + error = lookup(base,thisname,len,&inode); + if (error) { + iput(base); + return error; + } + error = follow_link(base,inode,0,0,&base); + if (error) + return error; + } + if (!base->i_op || !base->i_op->lookup) { + iput(base); + return -ENOTDIR; + } + *name = thisname; + *namelen = len; + *res_inode = base; + return 0; +} + +static int _namei(const char * pathname, struct inode * base, + int follow_links, struct inode ** res_inode) +{ + const char * basename; + int namelen,error; + struct inode * inode; + + *res_inode = NULL; + error = dir_namei(pathname,&namelen,&basename,base,&base); + if (error) + return error; + base->i_count++; /* lookup uses up base */ + error = lookup(base,basename,namelen,&inode); + if (error) { + iput(base); + return error; + } + if (follow_links) { + error = follow_link(base,inode,0,0,&inode); + if (error) + return error; + } else + iput(base); + *res_inode = inode; + return 0; +} + +int lnamei(const char * pathname, struct inode ** res_inode) +{ + int error; + char * tmp; + + error = getname(pathname,&tmp); + if (!error) { + error = _namei(tmp,NULL,0,res_inode); + putname(tmp); + } + return error; +} + +/* + * namei() + * + * is used by most simple commands to get the inode of a specified name. + * Open, link etc use their own routines, but this is enough for things + * like 'chmod' etc. + */ +int namei(const char * pathname, struct inode ** res_inode) +{ + int error; + char * tmp; + + error = getname(pathname,&tmp); + if (!error) { + error = _namei(tmp,NULL,1,res_inode); + putname(tmp); + } + return error; +} + +/* + * open_namei() + * + * namei for open - this is in fact almost the whole open-routine. + * + * Note that the low bits of "flag" aren't the same as in the open + * system call - they are 00 - no permissions needed + * 01 - read permission needed + * 10 - write permission needed + * 11 - read/write permissions needed + * which is a lot more logical, and also allows the "no perm" needed + * for symlinks (where the permissions are checked later). + */ +int open_namei(const char * pathname, int flag, int mode, + struct inode ** res_inode, struct inode * base) +{ + const char * basename; + int namelen,error,i; + struct inode * dir, *inode; + struct task_struct ** p; + + mode &= S_IALLUGO & ~current->umask; + mode |= S_IFREG; + error = dir_namei(pathname,&namelen,&basename,base,&dir); + if (error) + return error; + if (!namelen) { /* special case: '/usr/' etc */ + if (flag & 2) { + iput(dir); + return -EISDIR; + } + /* thanks to Paul Pluzhnikov for noticing this was missing.. */ + if (!permission(dir,ACC_MODE(flag))) { + iput(dir); + return -EACCES; + } + *res_inode=dir; + return 0; + } + for (i = 0; i < 5; i++) { /* races... */ + dir->i_count++; /* lookup eats the dir */ + error = lookup(dir,basename,namelen,&inode); + if (!error) + break; + if (!(flag & O_CREAT)) { + iput(dir); + return error; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->create) { + iput(dir); + return -EACCES; + } + if (IS_RDONLY(dir)) { + iput(dir); + return -EROFS; + } + dir->i_count++; /* create eats the dir */ + error = dir->i_op->create(dir,basename,namelen,mode,res_inode); + if (error != -EEXIST) { + iput(dir); + return error; + } + } + if (error) { + iput(dir); + return error; + } + if ((flag & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL)) { + iput(dir); + iput(inode); + return -EEXIST; + } + error = follow_link(dir,inode,flag,mode,&inode); + if (error) + return error; + if (S_ISDIR(inode->i_mode) && (flag & 2)) { + iput(inode); + return -EISDIR; + } + if (!permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EACCES; + } + if (S_ISBLK(inode->i_mode) || S_ISCHR(inode->i_mode)) { + if (IS_NODEV(inode)) { + iput(inode); + return -EACCES; + } + } else { + if (IS_RDONLY(inode) && (flag & 2)) { + iput(inode); + return -EROFS; + } + } + if ((inode->i_count > 1) && (flag & 2)) { + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + struct vm_area_struct * mpnt; + if (!*p) + continue; + if (inode == (*p)->executable) { + iput(inode); + return -ETXTBSY; + } + for(mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next) { + if (mpnt->vm_page_prot & PAGE_RW) + continue; + if (inode == mpnt->vm_inode) { + iput(inode); + return -ETXTBSY; + } + } + } + } + if (flag & O_TRUNC) { + inode->i_size = 0; + if (inode->i_op && inode->i_op->truncate) + inode->i_op->truncate(inode); + if ((error = notify_change(NOTIFY_SIZE, inode))) { + iput(inode); + return error; + } + inode->i_dirt = 1; + } + *res_inode = inode; + return 0; +} + +int do_mknod(const char * filename, int mode, dev_t dev) +{ + const char * basename; + int namelen, error; + struct inode * dir; + + mode &= ~current->umask; + error = dir_namei(filename,&namelen,&basename, NULL, &dir); + if (error) + return error; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (IS_RDONLY(dir)) { + iput(dir); + return -EROFS; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->mknod) { + iput(dir); + return -EPERM; + } + return dir->i_op->mknod(dir,basename,namelen,mode,dev); +} + +asmlinkage int sys_mknod(const char * filename, int mode, dev_t dev) +{ + int error; + char * tmp; + + 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); + putname(tmp); + } + return error; +} + +static int do_mkdir(const char * pathname, int mode) +{ + const char * basename; + int namelen, error; + struct inode * dir; + + error = dir_namei(pathname,&namelen,&basename,NULL,&dir); + if (error) + return error; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (IS_RDONLY(dir)) { + iput(dir); + return -EROFS; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->mkdir) { + iput(dir); + return -EPERM; + } + return dir->i_op->mkdir(dir,basename,namelen,mode); +} + +asmlinkage int sys_mkdir(const char * pathname, int mode) +{ + int error; + char * tmp; + + error = getname(pathname,&tmp); + if (!error) { + error = do_mkdir(tmp,mode); + putname(tmp); + } + return error; +} + +static int do_rmdir(const char * name) +{ + const char * basename; + int namelen, error; + struct inode * dir; + + error = dir_namei(name,&namelen,&basename,NULL,&dir); + if (error) + return error; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (IS_RDONLY(dir)) { + iput(dir); + return -EROFS; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->rmdir) { + iput(dir); + return -EPERM; + } + return dir->i_op->rmdir(dir,basename,namelen); +} + +asmlinkage int sys_rmdir(const char * pathname) +{ + int error; + char * tmp; + + error = getname(pathname,&tmp); + if (!error) { + error = do_rmdir(tmp); + putname(tmp); + } + return error; +} + +static int do_unlink(const char * name) +{ + const char * basename; + int namelen, error; + struct inode * dir; + + error = dir_namei(name,&namelen,&basename,NULL,&dir); + if (error) + return error; + if (!namelen) { + iput(dir); + return -EPERM; + } + if (IS_RDONLY(dir)) { + iput(dir); + return -EROFS; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->unlink) { + iput(dir); + return -EPERM; + } + return dir->i_op->unlink(dir,basename,namelen); +} + +asmlinkage int sys_unlink(const char * pathname) +{ + int error; + char * tmp; + + error = getname(pathname,&tmp); + if (!error) { + error = do_unlink(tmp); + putname(tmp); + } + return error; +} + +static int do_symlink(const char * oldname, const char * newname) +{ + struct inode * dir; + const char * basename; + int namelen, error; + + error = dir_namei(newname,&namelen,&basename,NULL,&dir); + if (error) + return error; + if (!namelen) { + iput(dir); + return -ENOENT; + } + if (IS_RDONLY(dir)) { + iput(dir); + return -EROFS; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->symlink) { + iput(dir); + return -EPERM; + } + return dir->i_op->symlink(dir,basename,namelen,oldname); +} + +asmlinkage int sys_symlink(const char * oldname, const char * newname) +{ + int error; + char * from, * to; + + error = getname(oldname,&from); + if (!error) { + error = getname(newname,&to); + if (!error) { + error = do_symlink(from,to); + putname(to); + } + putname(from); + } + return error; +} + +static int do_link(struct inode * oldinode, const char * newname) +{ + struct inode * dir; + const char * basename; + int namelen, error; + + error = dir_namei(newname,&namelen,&basename,NULL,&dir); + if (error) { + iput(oldinode); + return error; + } + if (!namelen) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (IS_RDONLY(dir)) { + iput(oldinode); + iput(dir); + return -EROFS; + } + if (dir->i_dev != oldinode->i_dev) { + iput(dir); + iput(oldinode); + return -EXDEV; + } + if (!permission(dir,MAY_WRITE | MAY_EXEC)) { + iput(dir); + iput(oldinode); + return -EACCES; + } + if (!dir->i_op || !dir->i_op->link) { + iput(dir); + iput(oldinode); + return -EPERM; + } + return dir->i_op->link(oldinode, dir, basename, namelen); +} + +asmlinkage int sys_link(const char * oldname, const char * newname) +{ + int error; + char * to; + struct inode * oldinode; + + error = namei(oldname, &oldinode); + if (error) + return error; + error = getname(newname,&to); + if (error) { + iput(oldinode); + return error; + } + error = do_link(oldinode,to); + putname(to); + return error; +} + +static int do_rename(const char * oldname, const char * newname) +{ + struct inode * old_dir, * new_dir; + const char * old_base, * new_base; + int old_len, new_len, error; + + error = dir_namei(oldname,&old_len,&old_base,NULL,&old_dir); + if (error) + return error; + if (!permission(old_dir,MAY_WRITE | MAY_EXEC)) { + iput(old_dir); + return -EACCES; + } + if (!old_len || (old_base[0] == '.' && + (old_len == 1 || (old_base[1] == '.' && + old_len == 2)))) { + iput(old_dir); + return -EPERM; + } + error = dir_namei(newname,&new_len,&new_base,NULL,&new_dir); + if (error) { + iput(old_dir); + return error; + } + if (!permission(new_dir,MAY_WRITE | MAY_EXEC)) { + iput(old_dir); + iput(new_dir); + return -EACCES; + } + if (!new_len || (new_base[0] == '.' && + (new_len == 1 || (new_base[1] == '.' && + new_len == 2)))) { + iput(old_dir); + iput(new_dir); + return -EPERM; + } + if (new_dir->i_dev != old_dir->i_dev) { + iput(old_dir); + iput(new_dir); + return -EXDEV; + } + if (IS_RDONLY(new_dir) || IS_RDONLY(old_dir)) { + iput(old_dir); + iput(new_dir); + return -EROFS; + } + if (!old_dir->i_op || !old_dir->i_op->rename) { + iput(old_dir); + iput(new_dir); + return -EPERM; + } + return old_dir->i_op->rename(old_dir, old_base, old_len, + new_dir, new_base, new_len); +} + +asmlinkage int sys_rename(const char * oldname, const char * newname) +{ + int error; + char * from, * to; + + error = getname(oldname,&from); + if (!error) { + error = getname(newname,&to); + if (!error) { + error = do_rename(from,to); + putname(to); + } + putname(from); + } + return error; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/Makefile new file mode 100644 index 000000000..8610c95b1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for the linux nfs-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= proc.o sock.o inode.o file.o dir.o \ + symlink.o mmap.o + +nfs.o: $(OBJS) + $(LD) -r -o nfs.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/dir.c new file mode 100644 index 000000000..d8aa88141 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/dir.c @@ -0,0 +1,606 @@ +/* + * linux/fs/nfs/dir.c + * + * Copyright (C) 1992 Rick Sladkey + * + * nfs directory handling functions + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for fs functions */ + +static int nfs_dir_read(struct inode *, struct file *filp, char *buf, + int count); +static int nfs_readdir(struct inode *, struct file *, struct dirent *, int); +static int nfs_lookup(struct inode *dir, const char *name, int len, + struct inode **result); +static int nfs_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result); +static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode); +static int nfs_rmdir(struct inode *dir, const char *name, int len); +static int nfs_unlink(struct inode *dir, const char *name, int len); +static int nfs_symlink(struct inode *inode, const char *name, int len, + const char *symname); +static int nfs_link(struct inode *oldinode, struct inode *dir, + const char *name, int len); +static int nfs_mknod(struct inode *dir, const char *name, int len, int mode, + int rdev); +static int nfs_rename(struct inode *old_dir, const char *old_name, + int old_len, struct inode *new_dir, const char *new_name, + int new_len); + +static struct file_operations nfs_dir_operations = { + NULL, /* lseek - default */ + nfs_dir_read, /* read - bad */ + NULL, /* write - bad */ + nfs_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* fsync */ +}; + +struct inode_operations nfs_dir_inode_operations = { + &nfs_dir_operations, /* default directory file-ops */ + nfs_create, /* create */ + nfs_lookup, /* lookup */ + nfs_link, /* link */ + nfs_unlink, /* unlink */ + nfs_symlink, /* symlink */ + nfs_mkdir, /* mkdir */ + nfs_rmdir, /* rmdir */ + nfs_mknod, /* mknod */ + nfs_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf, + int count) +{ + return -EISDIR; +} + +/* + * We need to do caching of directory entries to prevent an + * incredible amount of RPC traffic. Only the most recent open + * directory is cached. This seems sufficient for most purposes. + * Technically, we ought to flush the cache on close but this is + * not a problem in practice. + */ + +static int nfs_readdir(struct inode *inode, struct file *filp, + struct dirent *dirent, int count) +{ + static int c_dev = 0; + static int c_ino; + static int c_size; + static struct nfs_entry *c_entry = NULL; + + int result; + int i; + struct nfs_entry *entry; + + if (!inode || !S_ISDIR(inode->i_mode)) { + printk("nfs_readdir: inode is NULL or not a directory\n"); + return -EBADF; + } + + /* initialize cache memory if it hasn't been used before */ + + if (c_entry == NULL) { + i = sizeof (struct nfs_entry)*NFS_READDIR_CACHE_SIZE; + c_entry = (struct nfs_entry *) kmalloc(i, GFP_KERNEL); + for (i = 0; i < NFS_READDIR_CACHE_SIZE; i++) { + c_entry[i].name = (char *) kmalloc(NFS_MAXNAMLEN + 1, + GFP_KERNEL); + } + } + entry = NULL; + + /* try to find it in the cache */ + + if (inode->i_dev == c_dev && inode->i_ino == c_ino) { + for (i = 0; i < c_size; i++) { + if (filp->f_pos == c_entry[i].cookie) { + if (i == c_size - 1) { + if (c_entry[i].eof) + return 0; + } + else + entry = c_entry + i + 1; + break; + } + } + } + + /* if we didn't find it in the cache, revert to an nfs call */ + + if (!entry) { + result = nfs_proc_readdir(NFS_SERVER(inode), NFS_FH(inode), + filp->f_pos, NFS_READDIR_CACHE_SIZE, c_entry); + if (result < 0) { + c_dev = 0; + return result; + } + if (result > 0) { + c_dev = inode->i_dev; + c_ino = inode->i_ino; + c_size = result; + entry = c_entry + 0; + } + } + + /* if we found it in the cache or from an nfs call, return results */ + + if (entry) { + i = strlen(entry->name); + memcpy_tofs(dirent->d_name, entry->name, i + 1); + put_fs_long(entry->fileid, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + filp->f_pos = entry->cookie; + return i; + } + return 0; +} + +/* + * Lookup caching is a big win for performance but this is just + * a trial to see how well it works on a small scale. + * For example, bash does a lookup on ".." 13 times for each path + * element when running pwd. Yes, hard to believe but true. + * Try pwd in a filesystem mounted with noac. + * + * It trades a little cpu time and memory for a lot of network bandwidth. + * Since the cache is not hashed yet, it is a good idea not to make it too + * large because every lookup looks through the entire cache even + * though most of them will fail. + */ + +static struct nfs_lookup_cache_entry { + int dev; + int inode; + char filename[NFS_MAXNAMLEN + 1]; + struct nfs_fh fhandle; + struct nfs_fattr fattr; + int expiration_date; +} nfs_lookup_cache[NFS_LOOKUP_CACHE_SIZE]; + +static struct nfs_lookup_cache_entry *nfs_lookup_cache_index(struct inode *dir, + const char *filename) +{ + struct nfs_lookup_cache_entry *entry; + int i; + + for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) { + entry = nfs_lookup_cache + i; + if (entry->dev == dir->i_dev && entry->inode == dir->i_ino + && !strncmp(filename, entry->filename, NFS_MAXNAMLEN)) + return entry; + } + return NULL; +} + +static int nfs_lookup_cache_lookup(struct inode *dir, const char *filename, + struct nfs_fh *fhandle, + struct nfs_fattr *fattr) +{ + static int nfs_lookup_cache_in_use = 0; + + struct nfs_lookup_cache_entry *entry; + + if (!nfs_lookup_cache_in_use) { + memset(nfs_lookup_cache, 0, sizeof(nfs_lookup_cache)); + nfs_lookup_cache_in_use = 1; + } + if ((entry = nfs_lookup_cache_index(dir, filename))) { + if (jiffies > entry->expiration_date) { + entry->dev = 0; + return 0; + } + *fhandle = entry->fhandle; + *fattr = entry->fattr; + return 1; + } + return 0; +} + +static void nfs_lookup_cache_add(struct inode *dir, const char *filename, + struct nfs_fh *fhandle, + struct nfs_fattr *fattr) +{ + static int nfs_lookup_cache_pos = 0; + struct nfs_lookup_cache_entry *entry; + + /* compensate for bug in SGI NFS server */ + if (fattr->size == -1 || fattr->uid == -1 || fattr->gid == -1 + || fattr->atime.seconds == -1 || fattr->mtime.seconds == -1) + return; + if (!(entry = nfs_lookup_cache_index(dir, filename))) { + entry = nfs_lookup_cache + nfs_lookup_cache_pos++; + if (nfs_lookup_cache_pos == NFS_LOOKUP_CACHE_SIZE) + nfs_lookup_cache_pos = 0; + } + entry->dev = dir->i_dev; + entry->inode = dir->i_ino; + strcpy(entry->filename, filename); + entry->fhandle = *fhandle; + entry->fattr = *fattr; + entry->expiration_date = jiffies + (S_ISDIR(fattr->mode) + ? NFS_SERVER(dir)->acdirmax : NFS_SERVER(dir)->acregmax); +} + +static void nfs_lookup_cache_remove(struct inode *dir, struct inode *inode, + const char *filename) +{ + struct nfs_lookup_cache_entry *entry; + int dev; + int fileid; + int i; + + if (inode) { + dev = inode->i_dev; + fileid = inode->i_ino; + } + else if ((entry = nfs_lookup_cache_index(dir, filename))) { + dev = entry->dev; + fileid = entry->fattr.fileid; + } + else + return; + for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) { + entry = nfs_lookup_cache + i; + if (entry->dev == dev && entry->fattr.fileid == fileid) + entry->dev = 0; + } +} + +static void nfs_lookup_cache_refresh(struct inode *file, + struct nfs_fattr *fattr) +{ + struct nfs_lookup_cache_entry *entry; + int dev = file->i_dev; + int fileid = file->i_ino; + int i; + + for (i = 0; i < NFS_LOOKUP_CACHE_SIZE; i++) { + entry = nfs_lookup_cache + i; + if (entry->dev == dev && entry->fattr.fileid == fileid) + entry->fattr = *fattr; + } +} + +static int nfs_lookup(struct inode *dir, const char *__name, int len, + struct inode **result) +{ + struct nfs_fh fhandle; + struct nfs_fattr fattr; + char name[len > NFS_MAXNAMLEN? 1 : len+1]; + int error; + + *result = NULL; + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_lookup: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + memcpy(name,__name,len); + name[len] = '\0'; + if (len == 1 && name[0] == '.') { /* cheat for "." */ + *result = dir; + return 0; + } + if ((NFS_SERVER(dir)->flags & NFS_MOUNT_NOAC) + || !nfs_lookup_cache_lookup(dir, name, &fhandle, &fattr)) { + if ((error = nfs_proc_lookup(NFS_SERVER(dir), NFS_FH(dir), + name, &fhandle, &fattr))) { + iput(dir); + return error; + } + nfs_lookup_cache_add(dir, name, &fhandle, &fattr); + } + if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) { + iput(dir); + return -EACCES; + } + iput(dir); + return 0; +} + +static int nfs_create(struct inode *dir, const char *name, int len, int mode, + struct inode **result) +{ + struct nfs_sattr sattr; + struct nfs_fattr fattr; + struct nfs_fh fhandle; + int error; + + *result = NULL; + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_create: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + sattr.mode = mode; + sattr.uid = sattr.gid = sattr.size = (unsigned) -1; + sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + if ((error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), + name, &sattr, &fhandle, &fattr))) { + iput(dir); + return error; + } + if (!(*result = nfs_fhget(dir->i_sb, &fhandle, &fattr))) { + iput(dir); + return -EACCES; + } + nfs_lookup_cache_add(dir, name, &fhandle, &fattr); + iput(dir); + return 0; +} + +static int nfs_mknod(struct inode *dir, const char *name, int len, + int mode, int rdev) +{ + struct nfs_sattr sattr; + struct nfs_fattr fattr; + struct nfs_fh fhandle; + int error; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_mknod: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + sattr.mode = mode; + sattr.uid = sattr.gid = (unsigned) -1; + if (S_ISCHR(mode) || S_ISBLK(mode)) + sattr.size = rdev; /* get out your barf bag */ + else + sattr.size = (unsigned) -1; + sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + error = nfs_proc_create(NFS_SERVER(dir), NFS_FH(dir), + name, &sattr, &fhandle, &fattr); + if (!error) + nfs_lookup_cache_add(dir, name, &fhandle, &fattr); + iput(dir); + return error; +} + +static int nfs_mkdir(struct inode *dir, const char *name, int len, int mode) +{ + struct nfs_sattr sattr; + struct nfs_fattr fattr; + struct nfs_fh fhandle; + int error; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_mkdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + sattr.mode = mode; + sattr.uid = sattr.gid = sattr.size = (unsigned) -1; + sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir), + name, &sattr, &fhandle, &fattr); + if (!error) + nfs_lookup_cache_add(dir, name, &fhandle, &fattr); + iput(dir); + return error; +} + +static int nfs_rmdir(struct inode *dir, const char *name, int len) +{ + int error; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_rmdir: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + error = nfs_proc_rmdir(NFS_SERVER(dir), NFS_FH(dir), name); + if (!error) + nfs_lookup_cache_remove(dir, NULL, name); + iput(dir); + return error; +} + +static int nfs_unlink(struct inode *dir, const char *name, int len) +{ + int error; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_unlink: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + error = nfs_proc_remove(NFS_SERVER(dir), NFS_FH(dir), name); + if (!error) + nfs_lookup_cache_remove(dir, NULL, name); + iput(dir); + return error; +} + +static int nfs_symlink(struct inode *dir, const char *name, int len, + const char *symname) +{ + struct nfs_sattr sattr; + int error; + + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_symlink: inode is NULL or not a directory\n"); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(dir); + return -ENAMETOOLONG; + } + if (strlen(symname) > NFS_MAXPATHLEN) { + iput(dir); + return -ENAMETOOLONG; + } + sattr.mode = S_IFLNK | S_IRWXUGO; /* SunOS 4.1.2 crashes without this! */ + sattr.uid = sattr.gid = sattr.size = (unsigned) -1; + sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1; + error = nfs_proc_symlink(NFS_SERVER(dir), NFS_FH(dir), + name, symname, &sattr); + iput(dir); + return error; +} + +static int nfs_link(struct inode *oldinode, struct inode *dir, + const char *name, int len) +{ + int error; + + if (!oldinode) { + printk("nfs_link: old inode is NULL\n"); + iput(oldinode); + iput(dir); + return -ENOENT; + } + if (!dir || !S_ISDIR(dir->i_mode)) { + printk("nfs_link: dir is NULL or not a directory\n"); + iput(oldinode); + iput(dir); + return -ENOENT; + } + if (len > NFS_MAXNAMLEN) { + iput(oldinode); + iput(dir); + return -ENAMETOOLONG; + } + error = nfs_proc_link(NFS_SERVER(oldinode), NFS_FH(oldinode), + NFS_FH(dir), name); + if (!error) + nfs_lookup_cache_remove(dir, oldinode, NULL); + iput(oldinode); + iput(dir); + return error; +} + +static int nfs_rename(struct inode *old_dir, const char *old_name, int old_len, + struct inode *new_dir, const char *new_name, int new_len) +{ + int error; + + if (!old_dir || !S_ISDIR(old_dir->i_mode)) { + printk("nfs_rename: old inode is NULL or not a directory\n"); + iput(old_dir); + iput(new_dir); + return -ENOENT; + } + if (!new_dir || !S_ISDIR(new_dir->i_mode)) { + printk("nfs_rename: new inode is NULL or not a directory\n"); + iput(old_dir); + iput(new_dir); + return -ENOENT; + } + if (old_len > NFS_MAXNAMLEN || new_len > NFS_MAXNAMLEN) { + iput(old_dir); + iput(new_dir); + return -ENAMETOOLONG; + } + error = nfs_proc_rename(NFS_SERVER(old_dir), + NFS_FH(old_dir), old_name, + NFS_FH(new_dir), new_name); + if (!error) { + nfs_lookup_cache_remove(old_dir, NULL, old_name); + nfs_lookup_cache_remove(new_dir, NULL, new_name); + } + iput(old_dir); + iput(new_dir); + return error; +} + +/* + * Many nfs protocol calls return the new file attributes after + * an operation. Here we update the inode to reflect the state + * of the server's inode. + */ + +void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr) +{ + int was_empty; + + if (!inode || !fattr) { + printk("nfs_refresh_inode: inode or fattr is NULL\n"); + return; + } + if (inode->i_ino != fattr->fileid) { + printk("nfs_refresh_inode: inode number mismatch\n"); + return; + } + was_empty = inode->i_mode == 0; + inode->i_mode = fattr->mode; + inode->i_nlink = fattr->nlink; + inode->i_uid = fattr->uid; + inode->i_gid = fattr->gid; + inode->i_size = fattr->size; + inode->i_blksize = fattr->blocksize; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = fattr->rdev; + else + inode->i_rdev = 0; + inode->i_blocks = fattr->blocks; + inode->i_atime = fattr->atime.seconds; + inode->i_mtime = fattr->mtime.seconds; + inode->i_ctime = fattr->ctime.seconds; + if (was_empty) { + if (S_ISREG(inode->i_mode)) + inode->i_op = &nfs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &nfs_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &nfs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + else + inode->i_op = NULL; + } + nfs_lookup_cache_refresh(inode, fattr); +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/file.c new file mode 100644 index 000000000..b6a269f9a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/file.c @@ -0,0 +1,163 @@ +/* + * linux/fs/nfs/file.c + * + * Copyright (C) 1992 Rick Sladkey + * + * nfs regular file handling functions + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +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); + +static struct file_operations nfs_file_operations = { + NULL, /* lseek - default */ + nfs_file_read, /* read */ + nfs_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + nfs_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + nfs_fsync, /* fsync */ +}; + +struct inode_operations nfs_file_inode_operations = { + &nfs_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + 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) +{ + int result; + int hunk; + int i; + int n; + struct nfs_fattr fattr; + char *data; + off_t pos; + + if (!inode) { + printk("nfs_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("nfs_file_read: read from non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; + } + pos = file->f_pos; + if (file->f_pos + count > inode->i_size) + count = inode->i_size - pos; + if (count <= 0) + return 0; + n = NFS_SERVER(inode)->rsize; + data = (char *) kmalloc(n, GFP_KERNEL); + for (i = 0; i < count; i += n) { + hunk = count - i; + if (hunk > n) + hunk = n; + result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), + pos, hunk, data, &fattr); + if (result < 0) { + kfree_s(data, n); + return result; + } + memcpy_tofs(buf, data, result); + pos += result; + buf += result; + if (result < n) { + i += result; + break; + } + } + file->f_pos = pos; + kfree_s(data, n); + nfs_refresh_inode(inode, &fattr); + return i; +} + +static int nfs_file_write(struct inode *inode, struct file *file, char *buf, + int count) +{ + int result; + int hunk; + int i; + int n; + struct nfs_fattr fattr; + char *data; + int pos; + + if (!inode) { + printk("nfs_file_write: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("nfs_file_write: write to non-file, mode %07o\n", + inode->i_mode); + return -EINVAL; + } + if (count <= 0) + return 0; + pos = file->f_pos; + if (file->f_flags & O_APPEND) + pos = inode->i_size; + n = NFS_SERVER(inode)->wsize; + data = (char *) kmalloc(n, GFP_KERNEL); + for (i = 0; i < count; i += n) { + hunk = count - i; + if (hunk >= n) + hunk = n; + memcpy_fromfs(data, buf, hunk); + result = nfs_proc_write(NFS_SERVER(inode), NFS_FH(inode), + pos, hunk, data, &fattr); + if (result < 0) { + kfree_s(data, n); + return result; + } + pos += hunk; + buf += hunk; + if (hunk < n) { + i += hunk; + break; + } + } + file->f_pos = pos; + kfree_s(data, n); + nfs_refresh_inode(inode, &fattr); + return i; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/inode.c new file mode 100644 index 000000000..b4c81fa59 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/inode.c @@ -0,0 +1,233 @@ +/* + * linux/fs/nfs/inode.c + * + * Copyright (C) 1992 Rick Sladkey + * + * nfs inode and superblock handling functions + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +extern int close_fp(struct file *filp, unsigned int fd); + +static int nfs_notify_change(int, struct inode *); +static void nfs_put_inode(struct inode *); +static void nfs_put_super(struct super_block *); +static void nfs_statfs(struct super_block *, struct statfs *); + +static struct super_operations nfs_sops = { + NULL, /* read inode */ + nfs_notify_change, /* notify change */ + NULL, /* write inode */ + nfs_put_inode, /* put inode */ + nfs_put_super, /* put superblock */ + NULL, /* write superblock */ + nfs_statfs, /* stat filesystem */ + NULL +}; + +static void nfs_put_inode(struct inode * inode) +{ + clear_inode(inode); +} + +void nfs_put_super(struct super_block *sb) +{ + /* No locks should be open on this, so 0 should be safe as a fd. */ + close_fp(sb->u.nfs_sb.s_server.file, 0); + lock_super(sb); + sb->s_dev = 0; + unlock_super(sb); +} + +/* + * The way this works is that the mount process passes a structure + * in the data argument which contains an open socket to the NFS + * server and the root file handle obtained from the server's mount + * daemon. We stash theses away in the private superblock fields. + * Later we can add other mount parameters like caching values. + */ + +struct super_block *nfs_read_super(struct super_block *sb, void *raw_data, + int silent) +{ + struct nfs_mount_data *data = (struct nfs_mount_data *) raw_data; + struct nfs_server *server; + unsigned int fd; + struct file *filp; + dev_t dev = sb->s_dev; + + if (!data) { + printk("nfs_read_super: missing data argument\n"); + sb->s_dev = 0; + return NULL; + } + fd = data->fd; + if (data->version != NFS_MOUNT_VERSION) { + printk("nfs warning: mount version %s than kernel\n", + data->version < NFS_MOUNT_VERSION ? "older" : "newer"); + } + if (fd >= NR_OPEN || !(filp = current->filp[fd])) { + printk("nfs_read_super: invalid file descriptor\n"); + sb->s_dev = 0; + return NULL; + } + if (!S_ISSOCK(filp->f_inode->i_mode)) { + printk("nfs_read_super: not a socket\n"); + sb->s_dev = 0; + return NULL; + } + filp->f_count++; + lock_super(sb); + sb->s_blocksize = 1024; /* XXX */ + sb->s_blocksize_bits = 10; + sb->s_magic = NFS_SUPER_MAGIC; + sb->s_dev = dev; + sb->s_op = &nfs_sops; + server = &sb->u.nfs_sb.s_server; + server->file = filp; + server->lock = 0; + server->wait = NULL; + server->flags = data->flags; + server->rsize = data->rsize; + if (server->rsize <= 0) + server->rsize = NFS_DEF_FILE_IO_BUFFER_SIZE; + else if (server->rsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) + server->rsize = NFS_MAX_FILE_IO_BUFFER_SIZE; + server->wsize = data->wsize; + if (server->wsize <= 0) + server->wsize = NFS_DEF_FILE_IO_BUFFER_SIZE; + else if (server->wsize >= NFS_MAX_FILE_IO_BUFFER_SIZE) + server->wsize = NFS_MAX_FILE_IO_BUFFER_SIZE; + server->timeo = data->timeo*HZ/10; + server->retrans = data->retrans; + server->acregmin = data->acregmin*HZ; + server->acregmax = data->acregmax*HZ; + server->acdirmin = data->acdirmin*HZ; + server->acdirmax = data->acdirmax*HZ; + strcpy(server->hostname, data->hostname); + sb->u.nfs_sb.s_root = data->root; + unlock_super(sb); + if (!(sb->s_mounted = nfs_fhget(sb, &data->root, NULL))) { + sb->s_dev = 0; + printk("nfs_read_super: get root inode failed\n"); + return NULL; + } + return sb; +} + +void nfs_statfs(struct super_block *sb, struct statfs *buf) +{ + int error; + struct nfs_fsinfo res; + + put_fs_long(NFS_SUPER_MAGIC, &buf->f_type); + error = nfs_proc_statfs(&sb->u.nfs_sb.s_server, &sb->u.nfs_sb.s_root, + &res); + if (error) { + printk("nfs_statfs: statfs error = %d\n", -error); + res.bsize = res.blocks = res.bfree = res.bavail = 0; + } + put_fs_long(res.bsize, &buf->f_bsize); + put_fs_long(res.blocks, &buf->f_blocks); + put_fs_long(res.bfree, &buf->f_bfree); + put_fs_long(res.bavail, &buf->f_bavail); + put_fs_long(0, &buf->f_files); + put_fs_long(0, &buf->f_ffree); + /* We should really try to interrogate the remote server to find + it's maximum name length here */ + put_fs_long(NAME_MAX, &buf->f_namelen); +} + +/* + * This is our own version of iget that looks up inodes by file handle + * instead of inode number. We use this technique instead of using + * the vfs read_inode function because there is no way to pass the + * file handle or current attributes into the read_inode function. + * We just have to be careful not to subvert iget's special handling + * of mount points. + */ + +struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) +{ + struct nfs_fattr newfattr; + int error; + struct inode *inode; + + if (!sb) { + printk("nfs_fhget: super block is NULL\n"); + return NULL; + } + if (!fattr) { + error = nfs_proc_getattr(&sb->u.nfs_sb.s_server, fhandle, + &newfattr); + if (error) { + printk("nfs_fhget: getattr error = %d\n", -error); + return NULL; + } + fattr = &newfattr; + } + if (!(inode = iget(sb, fattr->fileid))) { + printk("nfs_fhget: iget failed\n"); + return NULL; + } + if (inode->i_dev == sb->s_dev) { + if (inode->i_ino != fattr->fileid) { + printk("nfs_fhget: unexpected inode from iget\n"); + return inode; + } + *NFS_FH(inode) = *fhandle; + nfs_refresh_inode(inode, fattr); + } + return inode; +} + +int nfs_notify_change(int flags, struct inode *inode) +{ + struct nfs_sattr sattr; + struct nfs_fattr fattr; + int error; + + if (flags & NOTIFY_MODE) + sattr.mode = inode->i_mode; + else + sattr.mode = (unsigned) -1; + if (flags & NOTIFY_UIDGID) { + sattr.uid = inode->i_uid; + sattr.gid = inode->i_gid; + } + else + sattr.uid = sattr.gid = (unsigned) -1; + if (flags & NOTIFY_SIZE) + sattr.size = S_ISREG(inode->i_mode) ? inode->i_size : -1; + else + sattr.size = (unsigned) -1; + if (flags & NOTIFY_TIME) { + sattr.mtime.seconds = inode->i_mtime; + sattr.mtime.useconds = 0; + sattr.atime.seconds = inode->i_atime; + sattr.atime.useconds = 0; + } + else { + sattr.mtime.seconds = sattr.mtime.useconds = (unsigned) -1; + sattr.atime.seconds = sattr.atime.useconds = (unsigned) -1; + } + error = nfs_proc_setattr(NFS_SERVER(inode), NFS_FH(inode), + &sattr, &fattr); + if (!error) + nfs_refresh_inode(inode, &fattr); + inode->i_dirt = 0; + return error; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/mmap.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/mmap.c new file mode 100644 index 000000000..2ae370cf2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/mmap.c @@ -0,0 +1,156 @@ +/* + * fs/nfs/mmap.c by Jon Tombs 15 Aug 1993 + * + * This code is from + * linux/mm/mmap.c which was written by obz, Linus and Eric + * and + * linux/mm/memory.c by Linus Torvalds and others + * + * Copyright (C) 1993 + * + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +extern int share_page(struct vm_area_struct * area, struct task_struct * tsk, + struct inode * inode, unsigned long address, unsigned long error_code, + unsigned long newpage); + +extern unsigned long put_page(struct task_struct * tsk,unsigned long page, + unsigned long address,int prot); + +static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area, + unsigned long address); + +extern void file_mmap_free(struct vm_area_struct * area); +extern int file_mmap_share(struct vm_area_struct * from, struct vm_area_struct * to, + unsigned long address); + +struct vm_operations_struct nfs_file_mmap = { + NULL, /* open */ + file_mmap_free, /* close */ + nfs_file_mmap_nopage, /* nopage */ + NULL, /* wppage */ + file_mmap_share, /* share */ + NULL, /* unmap */ +}; + + +/* This is used for a general mmap of a nfs file */ +int nfs_mmap(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) /* only PAGE_COW or read-only supported now */ + return -EINVAL; + if (off & (inode->i_sb->s_blocksize - 1)) + return -EINVAL; + if (!inode->i_sb || !S_ISREG(inode->i_mode)) + return -EACCES; + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + + mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + if (!mpnt) + return -ENOMEM; + + unmap_page_range(addr, len); + 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 = &nfs_file_mmap; + insert_vm_struct(current, mpnt); + merge_segments(current->mmap, NULL, NULL); + return 0; +} + + +static void nfs_file_mmap_nopage(int error_code, struct vm_area_struct * area, + unsigned long address) +{ + struct inode * inode = area->vm_inode; + unsigned int clear; + unsigned long page; + unsigned long tmp; + int n; + int i; + int pos; + struct nfs_fattr fattr; + + address &= PAGE_MASK; + pos = address - area->vm_start + area->vm_offset; + + page = get_free_page(GFP_KERNEL); + if (share_page(area, area->vm_task, inode, address, error_code, page)) { + ++area->vm_task->min_flt; + return; + } + + ++area->vm_task->maj_flt; + if (!page) { + oom(current); + put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE); + return; + } + + clear = 0; + if (address + PAGE_SIZE > area->vm_end) { + clear = address + PAGE_SIZE - area->vm_end; + } + + n = NFS_SERVER(inode)->rsize; /* what we can read in one go */ + + for (i = 0; i < (PAGE_SIZE - clear); i += n) { + int hunk, result; + + hunk = PAGE_SIZE - i; + if (hunk > n) + hunk = n; + result = nfs_proc_read(NFS_SERVER(inode), NFS_FH(inode), + pos, hunk, (char *) (page + i), &fattr); + if (result < 0) + break; + pos += result; + if (result < n) { + i += result; + break; + } + } + +#ifdef doweneedthishere + nfs_refresh_inode(inode, &fattr); +#endif + + if (!(error_code & 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)) + return; + free_page(page); + oom(current); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/proc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/proc.c new file mode 100644 index 000000000..59cb05070 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/proc.c @@ -0,0 +1,768 @@ +/* + * linux/fs/nfs/proc.c + * + * Copyright (C) 1992 Rick Sladkey + * + * OS-independent nfs remote procedure call functions + */ + +/* + * Defining NFS_PROC_DEBUG causes a lookup of a file named + * "xyzzy" to toggle debugging. Just cd to an NFS-mounted + * filesystem and type 'ls xyzzy' to turn on debugging. + */ + +#if 0 +#define NFS_PROC_DEBUG +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef NFS_PROC_DEBUG + +static int proc_debug = 0; +#define PRINTK(format, args...) \ + do { \ + if (proc_debug) \ + printk(format , ## args); \ + } while (0) + +#else /* !NFS_PROC_DEBUG */ + +#define PRINTK(format, args...) do ; while (0) + +#endif /* !NFS_PROC_DEBUG */ + +static int *nfs_rpc_header(int *p, int procedure); +static int *nfs_rpc_verify(int *p); +static int nfs_stat_to_errno(int stat); + +/* + * Our memory allocation and release functions. + */ + +static inline int *nfs_rpc_alloc(void) +{ + return (int *) __get_free_page(GFP_KERNEL); +} + +static inline void nfs_rpc_free(int *p) +{ + free_page((long) p); +} + +/* + * Here are a bunch of xdr encode/decode functions that convert + * between machine dependent and xdr data formats. + */ + +static inline int *xdr_encode_fhandle(int *p, struct nfs_fh *fhandle) +{ + *((struct nfs_fh *) p) = *fhandle; + p += (sizeof (*fhandle) + 3) >> 2; + return p; +} + +static inline int *xdr_decode_fhandle(int *p, struct nfs_fh *fhandle) +{ + *fhandle = *((struct nfs_fh *) p); + p += (sizeof (*fhandle) + 3) >> 2; + return p; +} + +static inline int *xdr_encode_string(int *p, const char *string) +{ + int len, quadlen; + + len = strlen(string); + quadlen = (len + 3) >> 2; + *p++ = htonl(len); + memcpy((char *) p, string, len); + memset(((char *) p) + len, '\0', (quadlen << 2) - len); + p += quadlen; + return p; +} + +static inline int *xdr_decode_string(int *p, char *string, int maxlen) +{ + unsigned int len; + + len = ntohl(*p++); + if (len > maxlen) + return NULL; + memcpy(string, (char *) p, len); + string[len] = '\0'; + p += (len + 3) >> 2; + return p; +} + +static inline int *xdr_encode_data(int *p, char *data, int len) +{ + int quadlen; + + quadlen = (len + 3) >> 2; + *p++ = htonl(len); + memcpy((char *) p, data, len); + memset(((char *) p) + len, '\0', (quadlen << 2) - len); + p += quadlen; + return p; +} + +static inline int *xdr_decode_data(int *p, char *data, int *lenp, int maxlen) +{ + unsigned int len; + + len = *lenp = ntohl(*p++); + if (len > maxlen) + return NULL; + memcpy(data, (char *) p, len); + p += (len + 3) >> 2; + return p; +} + +static int *xdr_decode_fattr(int *p, struct nfs_fattr *fattr) +{ + fattr->type = (enum nfs_ftype) ntohl(*p++); + fattr->mode = ntohl(*p++); + fattr->nlink = ntohl(*p++); + fattr->uid = ntohl(*p++); + fattr->gid = ntohl(*p++); + fattr->size = ntohl(*p++); + fattr->blocksize = ntohl(*p++); + fattr->rdev = ntohl(*p++); + fattr->blocks = ntohl(*p++); + fattr->fsid = ntohl(*p++); + fattr->fileid = ntohl(*p++); + fattr->atime.seconds = ntohl(*p++); + fattr->atime.useconds = ntohl(*p++); + fattr->mtime.seconds = ntohl(*p++); + fattr->mtime.useconds = ntohl(*p++); + fattr->ctime.seconds = ntohl(*p++); + fattr->ctime.useconds = ntohl(*p++); + return p; +} + +static int *xdr_encode_sattr(int *p, struct nfs_sattr *sattr) +{ + *p++ = htonl(sattr->mode); + *p++ = htonl(sattr->uid); + *p++ = htonl(sattr->gid); + *p++ = htonl(sattr->size); + *p++ = htonl(sattr->atime.seconds); + *p++ = htonl(sattr->atime.useconds); + *p++ = htonl(sattr->mtime.seconds); + *p++ = htonl(sattr->mtime.useconds); + return p; +} + +static int *xdr_decode_entry(int *p, struct nfs_entry *entry) +{ + entry->fileid = ntohl(*p++); + if (!(p = xdr_decode_string(p, entry->name, NFS_MAXNAMLEN))) + return NULL; + entry->cookie = ntohl(*p++); + entry->eof = 0; + return p; +} + +static int *xdr_decode_fsinfo(int *p, struct nfs_fsinfo *res) +{ + res->tsize = ntohl(*p++); + res->bsize = ntohl(*p++); + res->blocks = ntohl(*p++); + res->bfree = ntohl(*p++); + res->bavail = ntohl(*p++); + return p; +} + +/* + * One function for each procedure in the NFS protocol. + */ + +int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call getattr\n"); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_GETATTR); + p = xdr_encode_fhandle(p, fhandle); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fattr(p, fattr); + PRINTK("NFS reply getattr\n"); + } + else + PRINTK("NFS reply getattr failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_sattr *sattr, struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call setattr\n"); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_SETATTR); + p = xdr_encode_fhandle(p, fhandle); + p = xdr_encode_sattr(p, sattr); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fattr(p, fattr); + PRINTK("NFS reply setattr\n"); + } + else + PRINTK("NFS reply setattr failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, const char *name, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call lookup %s\n", name); +#ifdef NFS_PROC_DEBUG + if (!strcmp(name, "xyzzy")) + proc_debug = 1 - proc_debug; +#endif + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_LOOKUP); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fhandle(p, fhandle); + p = xdr_decode_fattr(p, fattr); + PRINTK("NFS reply lookup\n"); + } + else + PRINTK("NFS reply lookup failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, + char *res) +{ + int *p, *p0; + int status; + + PRINTK("NFS call readlink\n"); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_READLINK); + p = xdr_encode_fhandle(p, fhandle); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + if (!(p = xdr_decode_string(p, res, NFS_MAXPATHLEN))) { + printk("nfs_proc_readlink: giant pathname\n"); + status = NFSERR_IO; + } + else + PRINTK("NFS reply readlink %s\n", res); + } + else + PRINTK("NFS reply readlink failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, + int offset, int count, char *data, struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + int len = 0; /* = 0 is for gcc */ + + PRINTK("NFS call read %d @ %d\n", count, offset); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_READ); + p = xdr_encode_fhandle(p, fhandle); + *p++ = htonl(offset); + *p++ = htonl(count); + *p++ = htonl(count); /* traditional, could be any value */ + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fattr(p, fattr); + if (!(p = xdr_decode_data(p, data, &len, count))) { + printk("nfs_proc_read: giant data size\n"); + status = NFSERR_IO; + } + else + PRINTK("NFS reply read %d\n", len); + } + else + PRINTK("NFS reply read failed = %d\n", status); + nfs_rpc_free(p0); + return (status == NFS_OK) ? len : -nfs_stat_to_errno(status); +} + +int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, + int offset, int count, char *data, struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call write %d @ %d\n", count, offset); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_WRITE); + p = xdr_encode_fhandle(p, fhandle); + *p++ = htonl(offset); /* traditional, could be any value */ + *p++ = htonl(offset); + *p++ = htonl(count); /* traditional, could be any value */ + p = xdr_encode_data(p, data, count); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fattr(p, fattr); + PRINTK("NFS reply write\n"); + } + else + PRINTK("NFS reply write failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_sattr *sattr, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call create %s\n", name); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_CREATE); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + p = xdr_encode_sattr(p, sattr); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fhandle(p, fhandle); + p = xdr_decode_fattr(p, fattr); + PRINTK("NFS reply create\n"); + } + else + PRINTK("NFS reply create failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, const char *name) +{ + int *p, *p0; + int status; + + PRINTK("NFS call remove %s\n", name); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_REMOVE); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + PRINTK("NFS reply remove\n"); + } + else + PRINTK("NFS reply remove failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_rename(struct nfs_server *server, + struct nfs_fh *old_dir, const char *old_name, + struct nfs_fh *new_dir, const char *new_name) +{ + int *p, *p0; + int status; + + PRINTK("NFS call rename %s -> %s\n", old_name, new_name); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_RENAME); + p = xdr_encode_fhandle(p, old_dir); + p = xdr_encode_string(p, old_name); + p = xdr_encode_fhandle(p, new_dir); + p = xdr_encode_string(p, new_name); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + PRINTK("NFS reply rename\n"); + } + else + PRINTK("NFS reply rename failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fh *dir, const char *name) +{ + int *p, *p0; + int status; + + PRINTK("NFS call link %s\n", name); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_LINK); + p = xdr_encode_fhandle(p, fhandle); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + PRINTK("NFS reply link\n"); + } + else + PRINTK("NFS reply link failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, + const char *name, const char *path, struct nfs_sattr *sattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call symlink %s -> %s\n", name, path); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_SYMLINK); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + p = xdr_encode_string(p, path); + p = xdr_encode_sattr(p, sattr); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + PRINTK("NFS reply symlink\n"); + } + else + PRINTK("NFS reply symlink failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_sattr *sattr, + struct nfs_fh *fhandle, struct nfs_fattr *fattr) +{ + int *p, *p0; + int status; + + PRINTK("NFS call mkdir %s\n", name); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_MKDIR); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + p = xdr_encode_sattr(p, sattr); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fhandle(p, fhandle); + p = xdr_decode_fattr(p, fattr); + PRINTK("NFS reply mkdir\n"); + } + else + PRINTK("NFS reply mkdir failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, const char *name) +{ + int *p, *p0; + int status; + + PRINTK("NFS call rmdir %s\n", name); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_RMDIR); + p = xdr_encode_fhandle(p, dir); + p = xdr_encode_string(p, name); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + PRINTK("NFS reply rmdir\n"); + } + else + PRINTK("NFS reply rmdir failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, + int cookie, int count, struct nfs_entry *entry) +{ + int *p, *p0; + int status; + int i = 0; /* = 0 is for gcc */ + int size; + int eof; + + PRINTK("NFS call readdir %d @ %d\n", count, cookie); + size = server->rsize; + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_READDIR); + p = xdr_encode_fhandle(p, fhandle); + *p++ = htonl(cookie); + *p++ = htonl(size); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + for (i = 0; i < count && *p++; i++) { + if (!(p = xdr_decode_entry(p, entry++))) + break; + } + if (!p) { + printk("nfs_proc_readdir: giant filename\n"); + status = NFSERR_IO; + } + else { + eof = (i == count && !*p++ && *p++) + || (i < count && *p++); + if (eof && i) + entry[-1].eof = 1; + PRINTK("NFS reply readdir %d %s\n", i, + eof ? "eof" : ""); + } + } + else + PRINTK("NFS reply readdir failed = %d\n", status); + nfs_rpc_free(p0); + return (status == NFS_OK) ? i : -nfs_stat_to_errno(status); +} + +int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *res) +{ + int *p, *p0; + int status; + + PRINTK("NFS call statfs\n"); + if (!(p0 = nfs_rpc_alloc())) + return -EIO; + p = nfs_rpc_header(p0, NFSPROC_STATFS); + p = xdr_encode_fhandle(p, fhandle); + if ((status = nfs_rpc_call(server, p0, p)) < 0) { + nfs_rpc_free(p0); + return status; + } + if (!(p = nfs_rpc_verify(p0))) + status = NFSERR_IO; + else if ((status = ntohl(*p++)) == NFS_OK) { + p = xdr_decode_fsinfo(p, res); + PRINTK("NFS reply statfs\n"); + } + else + PRINTK("NFS reply statfs failed = %d\n", status); + nfs_rpc_free(p0); + return -nfs_stat_to_errno(status); +} + +/* + * Here are a few RPC-assist functions. + */ + +static int *nfs_rpc_header(int *p, int procedure) +{ + int *p1, *p2; + int i; + static int xid = 0; + unsigned char *sys = (unsigned char *) system_utsname.nodename; + + if (xid == 0) { + xid = CURRENT_TIME; + xid ^= (sys[3]<<24) | (sys[2]<<16) | (sys[1]<<8) | sys[0]; + } + *p++ = htonl(++xid); + *p++ = htonl(RPC_CALL); + *p++ = htonl(RPC_VERSION); + *p++ = htonl(NFS_PROGRAM); + *p++ = htonl(NFS_VERSION); + *p++ = htonl(procedure); + *p++ = htonl(RPC_AUTH_UNIX); + p1 = p++; + *p++ = htonl(CURRENT_TIME); /* traditional, could be anything */ + p = xdr_encode_string(p, (char *) sys); + *p++ = htonl(current->euid); + *p++ = htonl(current->egid); + p2 = p++; + for (i = 0; i < 16 && i < NGROUPS && current->groups[i] != NOGROUP; i++) + *p++ = htonl(current->groups[i]); + *p2 = htonl(i); + *p1 = htonl((p - (p1 + 1)) << 2); + *p++ = htonl(RPC_AUTH_NULL); + *p++ = htonl(0); + return p; +} + +static int *nfs_rpc_verify(int *p) +{ + unsigned int n; + + p++; + if ((n = ntohl(*p++)) != RPC_REPLY) { + printk("nfs_rpc_verify: not an RPC reply: %d\n", n); + return NULL; + } + if ((n = ntohl(*p++)) != RPC_MSG_ACCEPTED) { + printk("nfs_rpc_verify: RPC call rejected: %d\n", n); + return NULL; + } + switch (n = ntohl(*p++)) { + case RPC_AUTH_NULL: case RPC_AUTH_UNIX: case RPC_AUTH_SHORT: + break; + default: + printk("nfs_rpc_verify: bad RPC authentication type: %d\n", n); + return NULL; + } + if ((n = ntohl(*p++)) > 400) { + printk("nfs_rpc_verify: giant auth size\n"); + return NULL; + } + p += (n + 3) >> 2; + if ((n = ntohl(*p++)) != RPC_SUCCESS) { + printk("nfs_rpc_verify: RPC call failed: %d\n", n); + return NULL; + } + return p; +} + +/* + * We need to translate between nfs status return values and + * the local errno values which may not be the same. + */ + +#ifndef EDQUOT +#define EDQUOT ENOSPC +#endif + +static struct { + int stat; + int errno; +} nfs_errtbl[] = { + { NFS_OK, 0 }, + { NFSERR_PERM, EPERM }, + { NFSERR_NOENT, ENOENT }, + { NFSERR_IO, EIO }, + { NFSERR_NXIO, ENXIO }, + { NFSERR_ACCES, EACCES }, + { NFSERR_EXIST, EEXIST }, + { NFSERR_NODEV, ENODEV }, + { NFSERR_NOTDIR, ENOTDIR }, + { NFSERR_ISDIR, EISDIR }, + { NFSERR_INVAL, EINVAL }, + { NFSERR_FBIG, EFBIG }, + { NFSERR_NOSPC, ENOSPC }, + { NFSERR_ROFS, EROFS }, + { NFSERR_NAMETOOLONG, ENAMETOOLONG }, + { NFSERR_NOTEMPTY, ENOTEMPTY }, + { NFSERR_DQUOT, EDQUOT }, + { NFSERR_STALE, ESTALE }, +#ifdef EWFLUSH + { NFSERR_WFLUSH, EWFLUSH }, +#endif + { -1, EIO } +}; + +static int nfs_stat_to_errno(int stat) +{ + int i; + + for (i = 0; nfs_errtbl[i].stat != -1; i++) { + if (nfs_errtbl[i].stat == stat) + return nfs_errtbl[i].errno; + } + printk("nfs_stat_to_errno: bad nfs status return value: %d\n", stat); + return nfs_errtbl[i].errno; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/sock.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/sock.c new file mode 100644 index 000000000..f355b0c7e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/sock.c @@ -0,0 +1,185 @@ +/* + * linux/fs/nfs/sock.c + * + * Copyright (C) 1992, 1993 Rick Sladkey + * + * low-level nfs remote procedure call interface + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +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 + * functions from kernel-space instead of user space, the socket + * interface does not lend itself well to being cleanly called + * without a file descriptor. Since the nfs calls can run on + * behalf of any process, the superblock maintains a file pointer + * to the server socket. + */ + +static int do_nfs_rpc_call(struct nfs_server *server, int *start, int *end) +{ + struct file *file; + struct inode *inode; + struct socket *sock; + unsigned short fs; + int result; + int xid; + int len; + select_table wait_table; + struct select_table_entry entry; + int (*select) (struct inode *, struct file *, int, select_table *); + int init_timeout, max_timeout; + int timeout; + int retrans; + int major_timeout_seen; + char *server_name; + int n; + int addrlen; + unsigned long old_mask; + + xid = start[0]; + len = ((char *) end) - ((char *) start); + file = server->file; + 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; + 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) { + result = sock->ops->send(sock, (void *) start, len, 0, 0); + if (result < 0) { + printk("nfs_rpc_call: send error = %d\n", result); + break; + } + re_select: + wait_table.nr = 0; + wait_table.entry = &entry; + current->state = TASK_INTERRUPTIBLE; + if (!select(inode, file, SEL_IN, &wait_table) + && !select(inode, file, SEL_IN, NULL)) { + if (timeout > max_timeout) + timeout = max_timeout; + current->timeout = jiffies + timeout; + schedule(); + remove_wait_queue(entry.wait_address, &entry.wait); + current->state = TASK_RUNNING; + if (current->signal & ~current->blocked) { + current->timeout = 0; + result = -ERESTARTSYS; + break; + } + if (!current->timeout) { + if (n < retrans) + continue; + if (server->flags & NFS_MOUNT_SOFT) { + printk("NFS server %s not responding, " + "timed out", server_name); + result = -EIO; + break; + } + n = 0; + timeout = init_timeout; + init_timeout <<= 1; + if (!major_timeout_seen) { + printk("NFS server %s not responding, " + "still trying\n", server_name); + } + major_timeout_seen = 1; + continue; + } + else + current->timeout = 0; + } + else if (wait_table.nr) + remove_wait_queue(entry.wait_address, &entry.wait); + current->state = TASK_RUNNING; + addrlen = 0; + result = sock->ops->recvfrom(sock, (void *) start, PAGE_SIZE, 1, 0, + NULL, &addrlen); + if (result < 0) { + if (result == -EAGAIN) { +#if 0 + printk("nfs_rpc_call: bad select ready\n"); +#endif + goto re_select; + } + if (result == -ECONNREFUSED) { +#if 0 + printk("nfs_rpc_call: server playing coy\n"); +#endif + goto re_select; + } + if (result != -ERESTARTSYS) { + printk("nfs_rpc_call: recv error = %d\n", + -result); + } + break; + } + if (*start == xid) { + if (major_timeout_seen) + printk("NFS server %s OK\n", server_name); + break; + } +#if 0 + printk("nfs_rpc_call: XID mismatch\n"); +#endif + } + current->blocked = old_mask; + set_fs(fs); + return result; +} + +/* + * For now we lock out other simulaneous nfs calls for the same filesytem + * because we are single-threaded and don't want to get mismatched + * RPC replies. + */ + +int nfs_rpc_call(struct nfs_server *server, int *start, int *end) +{ + int result; + + while (server->lock) + sleep_on(&server->wait); + server->lock = 1; + result = do_nfs_rpc_call(server, start, end); + server->lock = 0; + wake_up(&server->wait); + return result; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/symlink.c new file mode 100644 index 000000000..b4984ad70 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/nfs/symlink.c @@ -0,0 +1,108 @@ +/* + * linux/fs/nfs/symlink.c + * + * Copyright (C) 1992 Rick Sladkey + * + * nfs symlink handling code + */ + +#include + +#include +#include +#include +#include +#include +#include + +static int nfs_readlink(struct inode *, char *, int); +static int nfs_follow_link(struct inode *, struct inode *, int, int, + struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations nfs_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + nfs_readlink, /* readlink */ + nfs_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int nfs_follow_link(struct inode *dir, struct inode *inode, + int flag, int mode, struct inode **res_inode) +{ + int error; + char *res; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput(inode); + iput(dir); + return -ELOOP; + } + res = (char *) kmalloc(NFS_MAXPATHLEN + 1, GFP_KERNEL); + error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res); + if (error) { + iput(inode); + iput(dir); + kfree_s(res, NFS_MAXPATHLEN + 1); + return error; + } + iput(inode); + current->link_count++; + error = open_namei(res, flag, mode, res_inode, dir); + current->link_count--; + kfree_s(res, NFS_MAXPATHLEN + 1); + return error; +} + +static int nfs_readlink(struct inode *inode, char *buffer, int buflen) +{ + int i; + char c; + int error; + char *res; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + if (buflen > NFS_MAXPATHLEN) + buflen = NFS_MAXPATHLEN; + res = (char *) kmalloc(buflen + 1, GFP_KERNEL); + error = nfs_proc_readlink(NFS_SERVER(inode), NFS_FH(inode), res); + iput(inode); + if (error) { + kfree_s(res, buflen + 1); + return error; + } + for (i = 0; i < buflen && (c = res[i]); i++) + put_fs_byte(c,buffer++); + kfree_s(res, buflen + 1); + return i; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/open.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/open.c new file mode 100644 index 000000000..88a55917e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/open.c @@ -0,0 +1,494 @@ +/* + * linux/fs/open.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +extern void fcntl_remove_locks(struct task_struct *, struct file *, unsigned int fd); + +asmlinkage int sys_ustat(int dev, struct ustat * ubuf) +{ + return -ENOSYS; +} + +asmlinkage int sys_statfs(const char * path, struct statfs * buf) +{ + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); + if (error) + return error; + error = namei(path,&inode); + if (error) + return error; + if (!inode->i_sb->s_op->statfs) { + iput(inode); + return -ENOSYS; + } + inode->i_sb->s_op->statfs(inode->i_sb, buf); + iput(inode); + return 0; +} + +asmlinkage int sys_fstatfs(unsigned int fd, struct statfs * buf) +{ + struct inode * inode; + struct file * file; + int error; + + error = verify_area(VERIFY_WRITE, buf, sizeof(struct statfs)); + if (error) + return error; + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (!inode->i_sb->s_op->statfs) + return -ENOSYS; + inode->i_sb->s_op->statfs(inode->i_sb, buf); + return 0; +} + +asmlinkage int sys_truncate(const char * path, unsigned int length) +{ + struct inode * inode; + int error; + + error = namei(path,&inode); + if (error) + return error; + if (S_ISDIR(inode->i_mode) || !permission(inode,MAY_WRITE)) { + iput(inode); + return -EACCES; + } + if (IS_RDONLY(inode)) { + iput(inode); + return -EROFS; + } + inode->i_size = length; + if (inode->i_op && inode->i_op->truncate) + inode->i_op->truncate(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_dirt = 1; + error = notify_change(NOTIFY_SIZE, inode); + iput(inode); + return error; +} + +asmlinkage int sys_ftruncate(unsigned int fd, unsigned int length) +{ + struct inode * inode; + struct file * file; + + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (S_ISDIR(inode->i_mode) || !(file->f_mode & 2)) + return -EACCES; + inode->i_size = length; + if (inode->i_op && inode->i_op->truncate) + inode->i_op->truncate(inode); + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_dirt = 1; + return notify_change(NOTIFY_SIZE, inode); +} + +/* If times==NULL, set access and modification to current time, + * must be owner or have write permission. + * Else, update from *times, must be owner or super user. + */ +asmlinkage int sys_utime(char * filename, struct utimbuf * times) +{ + struct inode * inode; + long actime,modtime; + int error; + + error = namei(filename,&inode); + if (error) + return error; + if (IS_RDONLY(inode)) { + iput(inode); + return -EROFS; + } + if (times) { + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EPERM; + } + actime = get_fs_long((unsigned long *) ×->actime); + modtime = get_fs_long((unsigned long *) ×->modtime); + inode->i_ctime = CURRENT_TIME; + } else { + if ((current->euid != inode->i_uid) && + !permission(inode,MAY_WRITE)) { + iput(inode); + return -EACCES; + } + actime = modtime = inode->i_ctime = CURRENT_TIME; + } + inode->i_atime = actime; + inode->i_mtime = modtime; + inode->i_dirt = 1; + error = notify_change(NOTIFY_TIME, inode); + iput(inode); + return error; +} + +/* + * XXX we should use the real ids for checking _all_ components of the + * path. Now we only use them for the final component of the path. + */ +asmlinkage int sys_access(const char * filename,int mode) +{ + struct inode * inode; + int res, i_mode; + + if (mode != (mode & S_IRWXO)) /* where's F_OK, X_OK, W_OK, R_OK? */ + return -EINVAL; + res = namei(filename,&inode); + if (res) + return res; + i_mode = inode->i_mode; + res = i_mode & S_IRWXUGO; + if (current->uid == inode->i_uid) + res >>= 6; /* needs cleaning? */ + else if (in_group_p(inode->i_gid)) + res >>= 3; /* needs cleaning? */ + iput(inode); + if ((res & mode) == mode) + return 0; + /* + * XXX we are doing this test last because we really should be + * swapping the effective with the real user id (temporarily), + * and then calling suser() routine. If we do call the + * suser() routine, it needs to be called last. + * + * XXX nope. suser() is inappropriate and swapping the ids while + * decomposing the path would be racy. + */ + if ((!current->uid) && + (S_ISDIR(i_mode) || !(mode & S_IXOTH) || (i_mode & S_IXUGO))) + return 0; + return -EACCES; +} + +asmlinkage int sys_chdir(const char * filename) +{ + struct inode * inode; + int error; + + error = namei(filename,&inode); + if (error) + return error; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + if (!permission(inode,MAY_EXEC)) { + iput(inode); + return -EACCES; + } + iput(current->pwd); + current->pwd = inode; + return (0); +} + +asmlinkage int sys_fchdir(unsigned int fd) +{ + struct inode * inode; + struct file * file; + + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (!S_ISDIR(inode->i_mode)) + return -ENOTDIR; + if (!permission(inode,MAY_EXEC)) + return -EACCES; + iput(current->pwd); + current->pwd = inode; + inode->i_count++; + return (0); +} + +asmlinkage int sys_chroot(const char * filename) +{ + struct inode * inode; + int error; + + error = namei(filename,&inode); + if (error) + return error; + if (!S_ISDIR(inode->i_mode)) { + iput(inode); + return -ENOTDIR; + } + if (!suser()) { + iput(inode); + return -EPERM; + } + iput(current->root); + current->root = inode; + return (0); +} + +asmlinkage int sys_fchmod(unsigned int fd, mode_t mode) +{ + struct inode * inode; + struct file * file; + + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if ((current->euid != inode->i_uid) && !suser()) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (mode == (mode_t) -1) + mode = inode->i_mode; + inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); + if (!suser() && !in_group_p(inode->i_gid)) + inode->i_mode &= ~S_ISGID; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return notify_change(NOTIFY_MODE, inode); +} + +asmlinkage int sys_chmod(const char * filename, mode_t mode) +{ + struct inode * inode; + int error; + + error = namei(filename,&inode); + if (error) + return error; + if ((current->euid != inode->i_uid) && !suser()) { + iput(inode); + return -EPERM; + } + if (IS_RDONLY(inode)) { + iput(inode); + return -EROFS; + } + if (mode == (mode_t) -1) + mode = inode->i_mode; + inode->i_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); + if (!suser() && !in_group_p(inode->i_gid)) + inode->i_mode &= ~S_ISGID; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + error = notify_change(NOTIFY_MODE, inode); + iput(inode); + return error; +} + +asmlinkage int sys_fchown(unsigned int fd, uid_t user, gid_t group) +{ + struct inode * inode; + struct file * file; + + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + if (!(inode = file->f_inode)) + return -ENOENT; + if (IS_RDONLY(inode)) + return -EROFS; + if (user == (uid_t) -1) + user = inode->i_uid; + if (group == (gid_t) -1) + group = inode->i_gid; + if ((current->euid == inode->i_uid && user == inode->i_uid && + (in_group_p(group) || group == inode->i_gid)) || + suser()) { + inode->i_uid = user; + inode->i_gid = group; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + return notify_change(NOTIFY_UIDGID, inode); + } + return -EPERM; +} + +asmlinkage int sys_chown(const char * filename, uid_t user, gid_t group) +{ + struct inode * inode; + int error; + + error = lnamei(filename,&inode); + if (error) + return error; + if (IS_RDONLY(inode)) { + iput(inode); + return -EROFS; + } + if (user == (uid_t) -1) + user = inode->i_uid; + if (group == (gid_t) -1) + group = inode->i_gid; + if ((current->euid == inode->i_uid && user == inode->i_uid && + (in_group_p(group) || group == inode->i_gid)) || + suser()) { + inode->i_uid = user; + inode->i_gid = group; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + error = notify_change(NOTIFY_UIDGID, inode); + iput(inode); + return error; + } + iput(inode); + return -EPERM; +} + +/* + * Note that while the flag value (low two bits) for sys_open means: + * 00 - read-only + * 01 - write-only + * 10 - read-write + * 11 - special + * it is changed into + * 00 - no permissions needed + * 01 - read-permission + * 10 - write-permission + * 11 - read-write + * for the internal routines (ie open_namei()/follow_link() etc). 00 is + * used by symlinks. + */ +int do_open(const char * filename,int flags,int mode) +{ + struct inode * inode; + struct file * f; + int flag,error,fd; + + for(fd=0 ; fdfilp[fd]) + break; + if (fd>=NR_OPEN) + return -EMFILE; + FD_CLR(fd,¤t->close_on_exec); + f = get_empty_filp(); + if (!f) + return -ENFILE; + current->filp[fd] = f; + f->f_flags = flag = flags; + f->f_mode = (flag+1) & O_ACCMODE; + if (f->f_mode) + flag++; + if (flag & (O_TRUNC | O_CREAT)) + flag |= 2; + error = open_namei(filename,flag,mode,&inode,NULL); + if (error) { + current->filp[fd]=NULL; + f->f_count--; + return error; + } + + f->f_inode = inode; + f->f_pos = 0; + f->f_reada = 0; + f->f_op = NULL; + if (inode->i_op) + f->f_op = inode->i_op->default_file_ops; + if (f->f_op && f->f_op->open) { + error = f->f_op->open(inode,f); + if (error) { + iput(inode); + f->f_count--; + current->filp[fd]=NULL; + return error; + } + } + f->f_flags &= ~(O_CREAT | O_EXCL | O_NOCTTY | O_TRUNC); + return (fd); +} + +asmlinkage int sys_open(const char * filename,int flags,int mode) +{ + char * tmp; + int error; + + error = getname(filename, &tmp); + if (error) + return error; + error = do_open(tmp,flags,mode); + putname(tmp); + return error; +} + +asmlinkage int sys_creat(const char * pathname, int mode) +{ + return sys_open(pathname, O_CREAT | O_WRONLY | O_TRUNC, mode); +} + +int close_fp(struct file *filp, unsigned int fd) +{ + struct inode *inode; + + if (filp->f_count == 0) { + printk("VFS: Close: file count is 0\n"); + return 0; + } + inode = filp->f_inode; + if (inode && S_ISREG(inode->i_mode)) + fcntl_remove_locks(current, filp, fd); + if (filp->f_count > 1) { + filp->f_count--; + return 0; + } + if (filp->f_op && filp->f_op->release) + filp->f_op->release(inode,filp); + filp->f_count--; + filp->f_inode = NULL; + iput(inode); + return 0; +} + +asmlinkage int sys_close(unsigned int fd) +{ + struct file * filp; + + if (fd >= NR_OPEN) + return -EBADF; + FD_CLR(fd, ¤t->close_on_exec); + if (!(filp = current->filp[fd])) + return -EBADF; + current->filp[fd] = NULL; + return (close_fp (filp, fd)); +} + +/* + * This routine simulates a hangup on the tty, to arrange that users + * are given clean terminals at login time. + */ +asmlinkage int sys_vhangup(void) +{ + struct tty_struct *tty; + + if (!suser()) + return -EPERM; + /* See if there is a controlling tty. */ + if (current->tty < 0) + return 0; + tty = TTY_TABLE(MINOR(current->tty)); + tty_vhangup(tty); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/pipe.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/pipe.c new file mode 100644 index 000000000..64784cbe8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/pipe.c @@ -0,0 +1,426 @@ +/* + * linux/fs/pipe.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include +#include +#include +#include +#include + + +/* We don't use the head/tail construction any more. Now we use the start/len*/ +/* contruction providing full use of PIPE_BUF (multiple of PAGE_SIZE) */ +/* Florian Coosmann (FGC) ^ current = 1 */ +/* Additionally, we now use locking technique. This prevents race condition */ +/* in case of paging and multiple read/write on the same pipe. (FGC) */ + + +static int pipe_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int chars = 0, size = 0, read = 0; + char *pipebuf; + + if (filp->f_flags & O_NONBLOCK) { + if (PIPE_LOCK(*inode)) + return -EAGAIN; + if (PIPE_EMPTY(*inode)) + if (PIPE_WRITERS(*inode)) + return -EAGAIN; + else + return 0; + } else while (PIPE_EMPTY(*inode) || PIPE_LOCK(*inode)) { + if (PIPE_EMPTY(*inode)) { + if (!PIPE_WRITERS(*inode)) + return 0; + } + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + interruptible_sleep_on(&PIPE_WAIT(*inode)); + } + PIPE_LOCK(*inode)++; + while (count>0 && (size = PIPE_SIZE(*inode))) { + chars = PIPE_MAX_RCHUNK(*inode); + if (chars > count) + chars = count; + if (chars > size) + chars = size; + read += chars; + pipebuf = PIPE_BASE(*inode)+PIPE_START(*inode); + PIPE_START(*inode) += chars; + PIPE_START(*inode) &= (PIPE_BUF-1); + PIPE_LEN(*inode) -= chars; + count -= chars; + memcpy_tofs(buf, pipebuf, chars ); + buf += chars; + } + PIPE_LOCK(*inode)--; + wake_up_interruptible(&PIPE_WAIT(*inode)); + if (read) + return read; + if (PIPE_WRITERS(*inode)) + return -EAGAIN; + return 0; +} + +static int pipe_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + int chars = 0, free = 0, written = 0; + char *pipebuf; + + if (!PIPE_READERS(*inode)) { /* no readers */ + send_sig(SIGPIPE,current,0); + return -EPIPE; + } +/* if count <= PIPE_BUF, we have to make it atomic */ + if (count <= PIPE_BUF) + free = count; + else + free = 1; /* can't do it atomically, wait for any free space */ + while (count>0) { + while ((PIPE_FREE(*inode) < free) || PIPE_LOCK(*inode)) { + if (!PIPE_READERS(*inode)) { /* no readers */ + send_sig(SIGPIPE,current,0); + return written? :-EPIPE; + } + if (current->signal & ~current->blocked) + return written? :-ERESTARTSYS; + if (filp->f_flags & O_NONBLOCK) + return written? :-EAGAIN; + interruptible_sleep_on(&PIPE_WAIT(*inode)); + } + PIPE_LOCK(*inode)++; + while (count>0 && (free = PIPE_FREE(*inode))) { + chars = PIPE_MAX_WCHUNK(*inode); + if (chars > count) + chars = count; + if (chars > free) + chars = free; + pipebuf = PIPE_BASE(*inode)+PIPE_END(*inode); + written += chars; + PIPE_LEN(*inode) += chars; + count -= chars; + memcpy_fromfs(pipebuf, buf, chars ); + buf += chars; + } + PIPE_LOCK(*inode)--; + wake_up_interruptible(&PIPE_WAIT(*inode)); + free = 1; + } + return written; +} + +static int pipe_lseek(struct inode * inode, struct file * file, off_t offset, int orig) +{ + return -ESPIPE; +} + +static int pipe_readdir(struct inode * inode, struct file * file, struct dirent * de, int count) +{ + return -ENOTDIR; +} + +static int bad_pipe_rw(struct inode * inode, struct file * filp, char * buf, int count) +{ + return -EBADF; +} + +static int pipe_ioctl(struct inode *pino, struct file * filp, + unsigned int cmd, unsigned long arg) +{ + int error; + + switch (cmd) { + case FIONREAD: + error = verify_area(VERIFY_WRITE, (void *) arg,4); + if (!error) + put_fs_long(PIPE_SIZE(*pino),(unsigned long *) arg); + return error; + default: + return -EINVAL; + } +} + +static int pipe_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) +{ + switch (sel_type) { + case SEL_IN: + if (!PIPE_EMPTY(*inode) || !PIPE_WRITERS(*inode)) + return 1; + select_wait(&PIPE_WAIT(*inode), wait); + return 0; + case SEL_OUT: + if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode)) + return 1; + select_wait(&PIPE_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; +} + +/* + * 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_WAIT(*inode), wait); + return 0; + case SEL_OUT: + if (!PIPE_FULL(*inode) || !PIPE_READERS(*inode)) + return 1; + select_wait(&PIPE_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.. + */ +static int connect_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + while (!PIPE_SIZE(*inode)) { + if (PIPE_WRITERS(*inode)) + break; + if (filp->f_flags & O_NONBLOCK) + return -EAGAIN; + wake_up_interruptible(& PIPE_WAIT(*inode)); + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + interruptible_sleep_on(& PIPE_WAIT(*inode)); + } + filp->f_op = &read_fifo_fops; + return pipe_read(inode,filp,buf,count); +} + +static int connect_select(struct inode * inode, struct file * filp, int sel_type, select_table * wait) +{ + switch (sel_type) { + case SEL_IN: + if (!PIPE_EMPTY(*inode)) { + filp->f_op = &read_fifo_fops; + return 1; + } + select_wait(&PIPE_WAIT(*inode), wait); + return 0; + case SEL_OUT: + if (!PIPE_FULL(*inode)) + return 1; + select_wait(&PIPE_WAIT(*inode), wait); + return 0; + case SEL_EX: + if (!PIPE_READERS(*inode) || !PIPE_WRITERS(*inode)) + return 1; + select_wait(&inode->i_wait,wait); + return 0; + } + return 0; +} + +/* + * Ok, these three routines NOW keep track of readers/writers, + * Linus previously did it with inode->i_count checking. + */ +static void pipe_read_release(struct inode * inode, struct file * filp) +{ + PIPE_READERS(*inode)--; + wake_up_interruptible(&PIPE_WAIT(*inode)); +} + +static void pipe_write_release(struct inode * inode, struct file * filp) +{ + PIPE_WRITERS(*inode)--; + wake_up_interruptible(&PIPE_WAIT(*inode)); +} + +static void pipe_rdwr_release(struct inode * inode, struct file * filp) +{ + PIPE_READERS(*inode)--; + PIPE_WRITERS(*inode)--; + wake_up_interruptible(&PIPE_WAIT(*inode)); +} + +/* + * 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_fifo_fops = { + pipe_lseek, + connect_read, + bad_pipe_rw, + pipe_readdir, + connect_select, + pipe_ioctl, + NULL, /* no mmap on pipes.. surprise */ + NULL, /* no special open code */ + pipe_read_release, + 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, + bad_pipe_rw, + pipe_readdir, + pipe_select, + pipe_ioctl, + NULL, /* no mmap on pipes.. surprise */ + NULL, /* no special open code */ + pipe_read_release, + NULL +}; + +struct file_operations write_pipe_fops = { + pipe_lseek, + bad_pipe_rw, + pipe_write, + pipe_readdir, + pipe_select, + pipe_ioctl, + NULL, /* mmap */ + NULL, /* no special open code */ + pipe_write_release, + NULL +}; + +struct file_operations rdwr_pipe_fops = { + pipe_lseek, + pipe_read, + pipe_write, + pipe_readdir, + pipe_select, + pipe_ioctl, + NULL, /* mmap */ + NULL, /* no special open code */ + pipe_rdwr_release, + NULL +}; + +struct inode_operations pipe_inode_operations = { + &rdwr_pipe_fops, + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +asmlinkage int sys_pipe(unsigned long * fildes) +{ + struct inode * inode; + struct file * f[2]; + int fd[2]; + int i,j; + + j = verify_area(VERIFY_WRITE,fildes,8); + if (j) + return j; + for(j=0 ; j<2 ; j++) + if (!(f[j] = get_empty_filp())) + break; + if (j==1) + f[0]->f_count--; + if (j<2) + return -ENFILE; + j=0; + for(i=0;j<2 && ifilp[i]) { + current->filp[ fd[j]=i ] = f[j]; + j++; + } + if (j==1) + current->filp[fd[0]]=NULL; + if (j<2) { + f[0]->f_count--; + f[1]->f_count--; + return -EMFILE; + } + if (!(inode=get_pipe_inode())) { + current->filp[fd[0]] = NULL; + current->filp[fd[1]] = NULL; + f[0]->f_count--; + f[1]->f_count--; + return -ENFILE; + } + f[0]->f_inode = f[1]->f_inode = inode; + f[0]->f_pos = f[1]->f_pos = 0; + f[0]->f_flags = O_RDONLY; + f[0]->f_op = &read_pipe_fops; + f[0]->f_mode = 1; /* read */ + f[1]->f_flags = O_WRONLY; + f[1]->f_op = &write_pipe_fops; + f[1]->f_mode = 2; /* write */ + put_fs_long(fd[0],0+fildes); + put_fs_long(fd[1],1+fildes); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/Makefile new file mode 100644 index 000000000..71c62433c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux proc-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= inode.o root.o base.o mem.o link.o fd.o array.o kmsg.o net.o + +proc.o: $(OBJS) + $(LD) -r -o proc.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/array.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/array.c new file mode 100644 index 000000000..2605d7f35 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/array.c @@ -0,0 +1,548 @@ +/* + * linux/fs/proc/array.c + * + * Copyright (C) 1992 by Linus Torvalds + * based on ideas by Darren Senn + * + * stat,statm extensions by Michael K. Johnson, johnsonm@stolaf.edu + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) + +#ifdef CONFIG_DEBUG_MALLOC +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; + + a = avenrun[0] + (FIXED_1/200); + b = avenrun[1] + (FIXED_1/200); + c = avenrun[2] + (FIXED_1/200); + return sprintf(buffer,"%d.%02d %d.%02d %d.%02d\n", + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c)); +} + +static int get_kstat(char * buffer) +{ + return sprintf(buffer, "cpu %u %u %u %lu\n" + "disk %u %u %u %u\n" + "page %u %u\n" + "swap %u %u\n" + "intr %u\n" + "ctxt %u\n" + "btime %lu\n", + kstat.cpu_user, + kstat.cpu_nice, + kstat.cpu_system, + jiffies - (kstat.cpu_user + kstat.cpu_nice + kstat.cpu_system), + kstat.dk_drive[0], + kstat.dk_drive[1], + kstat.dk_drive[2], + kstat.dk_drive[3], + kstat.pgpgin, + kstat.pgpgout, + kstat.pswpin, + kstat.pswpout, + kstat.interrupts, + kstat.context_swtch, + xtime.tv_sec - jiffies / HZ); +} + + +static int get_uptime(char * buffer) +{ + unsigned long uptime; + unsigned long idle; + + uptime = jiffies; + idle = task[0]->utime + task[0]->stime; + return sprintf(buffer,"%lu.%02lu %lu.%02lu\n", + uptime / HZ, + uptime % HZ, + idle / HZ, + idle % HZ); +} + +static int get_meminfo(char * buffer) +{ + struct sysinfo i; + + si_meminfo(&i); + si_swapinfo(&i); + return sprintf(buffer, " total: used: free: shared: buffers:\n" + "Mem: %8lu %8lu %8lu %8lu %8lu\n" + "Swap: %8lu %8lu %8lu\n", + i.totalram, i.totalram-i.freeram, i.freeram, i.sharedram, i.bufferram, + i.totalswap, i.totalswap-i.freeswap, i.freeswap); +} + +static int get_version(char * buffer) +{ + extern char *linux_banner; + + strcpy(buffer, linux_banner); + return strlen(buffer); +} + +static struct task_struct ** get_task(pid_t pid) +{ + struct task_struct ** p; + + p = task; + while (++p < task+NR_TASKS) { + if (*p && (*p)->pid == pid) + return p; + } + return NULL; +} + +static unsigned long get_phys_addr(struct task_struct ** p, unsigned long ptr) +{ + unsigned long page; + + if (!p || !*p || ptr >= TASK_SIZE) + return 0; + page = *PAGE_DIR_OFFSET((*p)->tss.cr3,ptr); + if (!(page & 1)) + return 0; + page &= PAGE_MASK; + page += PAGE_PTR(ptr); + page = *(unsigned long *) page; + if (!(page & 1)) + return 0; + page &= PAGE_MASK; + page += ptr & ~PAGE_MASK; + return page; +} + +static int get_array(struct task_struct ** p, unsigned long start, unsigned long end, char * buffer) +{ + unsigned long addr; + int size = 0, result = 0; + char c; + + if (start >= end) + return result; + for (;;) { + addr = get_phys_addr(p, start); + if (!addr) + return result; + do { + c = *(char *) addr; + if (!c) + result = size; + if (size < PAGE_SIZE) + buffer[size++] = c; + else + return result; + addr++; + start++; + if (start >= end) + return result; + } while (!(addr & ~PAGE_MASK)); + } +} + +static int get_env(int pid, char * buffer) +{ + struct task_struct ** p = get_task(pid); + + if (!p || !*p) + return 0; + return get_array(p, (*p)->env_start, (*p)->env_end, buffer); +} + +static int get_arg(int pid, char * buffer) +{ + struct task_struct ** p = get_task(pid); + + if (!p || !*p) + return 0; + return get_array(p, (*p)->arg_start, (*p)->arg_end, buffer); +} + +static unsigned long get_wchan(struct task_struct *p) +{ + unsigned long ebp, eip; + unsigned long stack_page; + int count = 0; + + if (!p || p == current || p->state == TASK_RUNNING) + return 0; + stack_page = p->kernel_stack_page; + if (!stack_page) + return 0; + ebp = p->tss.ebp; + do { + if (ebp < stack_page || ebp >= 4092+stack_page) + return 0; + eip = *(unsigned long *) (ebp+4); + if ((void *)eip != sleep_on && + (void *)eip != interruptible_sleep_on) + return eip; + ebp = *(unsigned long *) ebp; + } while (count++ < 16); + return 0; +} + +#define KSTK_EIP(stack) (((unsigned long *)stack)[1019]) +#define KSTK_ESP(stack) (((unsigned long *)stack)[1022]) + +static int get_stat(int pid, char * buffer) +{ + struct task_struct ** p = get_task(pid); + unsigned long sigignore=0, sigcatch=0, bit=1, wchan; + unsigned long vsize, eip, esp; + int i,tty_pgrp; + char state; + + if (!p || !*p) + return 0; + if ((*p)->state < 0 || (*p)->state > 5) + state = '.'; + else + state = "RSDZTD"[(*p)->state]; + eip = esp = 0; + vsize = (*p)->kernel_stack_page; + if (vsize) { + eip = KSTK_EIP(vsize); + esp = KSTK_ESP(vsize); + vsize = (*p)->brk - (*p)->start_code + PAGE_SIZE-1; + if (esp) + vsize += TASK_SIZE - esp; + } + wchan = get_wchan(*p); + for(i=0; i<32; ++i) { + switch((int) (*p)->sigaction[i].sa_handler) { + case 1: sigignore |= bit; break; + case 0: break; + default: sigcatch |= bit; + } bit <<= 1; + } + tty_pgrp = (*p)->tty; + if (tty_pgrp > 0 && tty_table[tty_pgrp]) + tty_pgrp = tty_table[tty_pgrp]->pgrp; + else + tty_pgrp = -1; + return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \ +%lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %u %u %lu %lu %lu %lu %lu %lu \ +%lu %lu %lu %lu\n", + pid, + (*p)->comm, + state, + (*p)->p_pptr->pid, + (*p)->pgrp, + (*p)->session, + (*p)->tty, + tty_pgrp, + (*p)->flags, + (*p)->min_flt, + (*p)->cmin_flt, + (*p)->maj_flt, + (*p)->cmaj_flt, + (*p)->utime, + (*p)->stime, + (*p)->cutime, + (*p)->cstime, + (*p)->counter, /* this is the kernel priority --- + subtract 30 in your user-level program. */ + (*p)->priority, /* this is the nice value --- + subtract 15 in your user-level program. */ + (*p)->timeout, + (*p)->it_real_value, + (*p)->start_time, + vsize, + (*p)->rss, /* you might want to shift this left 3 */ + (*p)->rlim[RLIMIT_RSS].rlim_cur, + (*p)->start_code, + (*p)->end_code, + (*p)->start_stack, + esp, + eip, + (*p)->signal, + (*p)->blocked, + sigignore, + sigcatch, + wchan); +} + +static int get_statm(int pid, char * buffer) +{ + struct task_struct ** p = get_task(pid); + int i, tpag; + int size=0, resident=0, share=0, trs=0, lrs=0, drs=0, dt=0; + unsigned long ptbl, *buf, *pte, *pagedir, map_nr; + + if (!p || !*p) + return 0; + tpag = (*p)->end_code / PAGE_SIZE; + if ((*p)->state != TASK_ZOMBIE) { + pagedir = (unsigned long *) (*p)->tss.cr3; + for (i = 0; i < 0x300; ++i) { + if ((ptbl = pagedir[i]) == 0) { + tpag -= PTRS_PER_PAGE; + continue; + } + buf = (unsigned long *)(ptbl & PAGE_MASK); + for (pte = buf; pte < (buf + PTRS_PER_PAGE); ++pte) { + if (*pte != 0) { + ++size; + if (*pte & 1) { + ++resident; + if (tpag > 0) + ++trs; + else + ++drs; + if (i >= 15 && i < 0x2f0) { + ++lrs; + if (*pte & 0x40) + ++dt; + else + --drs; + } + map_nr = MAP_NR(*pte); + if (map_nr < (high_memory / PAGE_SIZE) && mem_map[map_nr] > 1) + ++share; + } + } + --tpag; + } + } + } + return sprintf(buffer,"%d %d %d %d %d %d %d\n", + 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, "%08lx-%08lx %s %08lx %02x:%02x %lu\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; +} + +asmlinkage int get_module_list( char *); + +static int array_read(struct inode * inode, struct file * file,char * buf, int count) +{ + char * page; + int length; + int end; + unsigned int type, pid; + + if (count < 0) + return -EINVAL; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + type = inode->i_ino; + pid = type >> 16; + type &= 0x0000ffff; + switch (type) { + case 2: + length = get_loadavg(page); + break; + case 3: + length = get_uptime(page); + break; + case 4: + length = get_meminfo(page); + break; + case 6: + length = get_version(page); + break; + case 9: + length = get_env(pid, page); + break; + case 10: + length = get_arg(pid, page); + break; + case 11: + length = get_stat(pid, page); + break; + case 12: + length = get_statm(pid, page); + break; +#ifdef CONFIG_DEBUG_MALLOC + case 13: + 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; + case 16: + length = get_module_list(page); + break; + case 17: + length = get_kstat(page); + break; + default: + free_page((unsigned long) page); + return -EBADF; + } + if (file->f_pos >= length) { + free_page((unsigned long) page); + return 0; + } + if (count + file->f_pos > length) + count = length - file->f_pos; + end = count + file->f_pos; + memcpy_tofs(buf, page + file->f_pos, count); + free_page((unsigned long) page); + file->f_pos = end; + return count; +} + +static struct file_operations proc_array_operations = { + NULL, /* array_lseek */ + array_read, + NULL, /* array_write */ + NULL, /* array_readdir */ + NULL, /* array_select */ + NULL, /* array_ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +struct inode_operations proc_array_inode_operations = { + &proc_array_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/base.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/base.c new file mode 100644 index 000000000..5209d2285 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/base.c @@ -0,0 +1,164 @@ +/* + * linux/fs/proc/base.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc base directory handling functions + */ + +#include + +#include +#include +#include +#include + +static int proc_readbase(struct inode *, struct file *, struct dirent *, int); +static int proc_lookupbase(struct inode *,const char *,int,struct inode **); + +static struct file_operations proc_base_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readbase, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_base_inode_operations = { + &proc_base_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookupbase, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static struct proc_dir_entry base_dir[] = { + { 1,2,".." }, + { 2,1,"." }, + { 3,3,"mem" }, + { 4,3,"cwd" }, + { 5,4,"root" }, + { 6,3,"exe" }, + { 7,2,"fd" }, + { 8,4,"mmap" }, + { 9,7,"environ" }, + { 10,7,"cmdline" }, + { 11,4,"stat" }, + { 12,5,"statm" }, + { 15,4,"maps" } +}; + +#define NR_BASE_DIRENTRY ((sizeof (base_dir))/(sizeof (base_dir[0]))) + +int proc_match(int len,const char * name,struct proc_dir_entry * de) +{ + register int same __asm__("ax"); + + if (!de || !de->low_ino) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + if (de->namelen != len) + return 0; + __asm__("cld\n\t" + "repe ; cmpsb\n\t" + "setz %%al" + :"=a" (same) + :"0" (0),"S" ((long) name),"D" ((long) de->name),"c" (len) + :"cx","di","si"); + return same; +} + +static int proc_lookupbase(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + unsigned int pid, ino; + int i; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + ino = dir->i_ino; + pid = ino >> 16; + i = NR_BASE_DIRENTRY; + while (i-- > 0 && !proc_match(len,name,base_dir+i)) + /* nothing */; + if (i < 0) { + iput(dir); + return -ENOENT; + } + if (base_dir[i].low_ino == 1) + ino = 1; + else + ino = (pid << 16) + base_dir[i].low_ino; + for (i = 0 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) + break; + if (!pid || i >= NR_TASKS) { + iput(dir); + return -ENOENT; + } + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; +} + +static int proc_readbase(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + struct proc_dir_entry * de; + unsigned int pid, ino; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + pid = ino >> 16; + for (i = 0 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) + break; + if (!pid || i >= NR_TASKS) + return 0; + if (((unsigned) filp->f_pos) < NR_BASE_DIRENTRY) { + de = base_dir + filp->f_pos; + filp->f_pos++; + i = de->namelen; + ino = de->low_ino; + if (ino != 1) + ino |= (pid << 16); + put_fs_long(ino, &dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + put_fs_byte(0,i+dirent->d_name); + j = i; + while (i--) + put_fs_byte(de->name[i], i+dirent->d_name); + return j; + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/fd.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/fd.c new file mode 100644 index 000000000..a130e30ce --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/fd.c @@ -0,0 +1,198 @@ +/* + * linux/fs/proc/fd.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc fd directory handling functions + */ + +#include + +#include +#include +#include +#include + +static int proc_readfd(struct inode *, struct file *, struct dirent *, int); +static int proc_lookupfd(struct inode *,const char *,int,struct inode **); + +static struct file_operations proc_fd_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readfd, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_fd_inode_operations = { + &proc_fd_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookupfd, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int proc_lookupfd(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + unsigned int ino, pid, fd, c; + struct task_struct * p; + struct super_block * sb; + int i; + + *result = NULL; + ino = dir->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + ino -= 7; + if (!dir) + return -ENOENT; + sb = dir->i_sb; + if (!pid || ino > 1 || !S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!len || (name[0] == '.' && (len == 1 || + (name[1] == '.' && len == 2)))) { + if (len < 2) { + *result = dir; + return 0; + } + if (!(*result = iget(sb,(pid << 16)+2))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; + } + iput(dir); + fd = 0; + while (len-- > 0) { + c = *name - '0'; + name++; + if (c > 9) { + fd = 0xfffff; + break; + } + fd *= 10; + fd += c; + if (fd & 0xffff0000) { + fd = 0xfffff; + break; + } + } + for (i = 0 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (!pid || i >= NR_TASKS) + return -ENOENT; + if (!ino) { + if (fd >= NR_OPEN || !p->filp[fd] || !p->filp[fd]->f_inode) + return -ENOENT; + ino = (pid << 16) + 0x100 + fd; + } else { + int j = 0; + struct vm_area_struct * mpnt; + for (mpnt = p->mmap; mpnt; mpnt = mpnt->vm_next) + if (mpnt->vm_inode) + j++; + if (fd >= j) + return -ENOENT; + ino = (pid << 16) + 0x200 + fd; + } + if (!(*result = iget(sb,ino))) + return -ENOENT; + return 0; +} + +static int proc_readfd(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + struct task_struct * p; + unsigned int fd, pid, ino; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + ino -= 7; + if (ino > 1) + return 0; + while (1) { + fd = filp->f_pos; + filp->f_pos++; + if (fd < 2) { + i = j = fd+1; + if (!fd) + fd = inode->i_ino; + else + fd = (inode->i_ino & 0xffff0000) | 2; + put_fs_long(fd, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + put_fs_byte(0, i+dirent->d_name); + while (i--) + put_fs_byte('.', i+dirent->d_name); + return j; + } + fd -= 2; + for (i = 1 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (i >= NR_TASKS) + return 0; + if (!ino) { + if (fd >= NR_OPEN) + break; + if (!p->filp[fd] || !p->filp[fd]->f_inode) + continue; + } else { + int j = 0; + struct vm_area_struct * mpnt; + for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next) + if (mpnt->vm_inode) + j++; + if (fd >= j) + break; + } + j = 10; + i = 1; + while (fd >= j) { + j *= 10; + i++; + } + j = i; + if (!ino) + ino = (pid << 16) + 0x100 + fd; + else + ino = (pid << 16) + 0x200 + fd; + put_fs_long(ino, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + put_fs_byte(0, i+dirent->d_name); + while (i--) { + put_fs_byte('0'+(fd % 10), i+dirent->d_name); + fd /= 10; + } + return j; + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/inode.c new file mode 100644 index 000000000..4f102dfda --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/inode.c @@ -0,0 +1,199 @@ +/* + * linux/fs/proc/inode.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +void proc_put_inode(struct inode *inode) +{ + if (inode->i_nlink) + return; + inode->i_size = 0; +} + +void proc_put_super(struct super_block *sb) +{ + lock_super(sb); + sb->s_dev = 0; + unlock_super(sb); +} + +static struct super_operations proc_sops = { + proc_read_inode, + NULL, + proc_write_inode, + proc_put_inode, + proc_put_super, + NULL, + proc_statfs, + NULL +}; + +struct super_block *proc_read_super(struct super_block *s,void *data, + int silent) +{ + lock_super(s); + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = PROC_SUPER_MAGIC; + s->s_op = &proc_sops; + unlock_super(s); + if (!(s->s_mounted = iget(s,PROC_ROOT_INO))) { + s->s_dev = 0; + printk("get root inode failed\n"); + return NULL; + } + return s; +} + +void proc_statfs(struct super_block *sb, struct statfs *buf) +{ + put_fs_long(PROC_SUPER_MAGIC, &buf->f_type); + put_fs_long(PAGE_SIZE/sizeof(long), &buf->f_bsize); + put_fs_long(0, &buf->f_blocks); + put_fs_long(0, &buf->f_bfree); + put_fs_long(0, &buf->f_bavail); + put_fs_long(0, &buf->f_files); + put_fs_long(0, &buf->f_ffree); + put_fs_long(NAME_MAX, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ +} + +void proc_read_inode(struct inode * inode) +{ + unsigned long ino, pid; + struct task_struct * p; + int i; + + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_nlink = 1; + inode->i_size = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = inode->i_blksize = 0; + ino = inode->i_ino; + pid = ino >> 16; + p = task[0]; + for (i = 0; i < NR_TASKS ; i++) + if ((p = task[i]) && (p->pid == pid)) + break; + if (!p || i >= NR_TASKS) + return; + if (ino == PROC_ROOT_INO) { + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_nlink = 2; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i]) + inode->i_nlink++; + inode->i_op = &proc_root_inode_operations; + return; + } + if ((ino >= 128) && (ino <= 160)) { /* files within /proc/net */ + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_net_inode_operations; + return; + } + if (!pid) { + switch (ino) { + case 5: + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_kmsg_inode_operations; + break; + case 8: /* for the net directory */ + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + 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; + break; + } + return; + } + ino &= 0x0000ffff; + inode->i_uid = p->euid; + inode->i_gid = p->egid; + switch (ino) { + case 2: + inode->i_nlink = 4; + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO; + inode->i_op = &proc_base_inode_operations; + return; + case 3: + inode->i_op = &proc_mem_inode_operations; + inode->i_mode = S_IFREG | S_IRUSR | S_IWUSR; + return; + case 4: + case 5: + case 6: + inode->i_op = &proc_link_inode_operations; + inode->i_size = 64; + inode->i_mode = S_IFLNK | S_IRWXU; + return; + case 7: + case 8: + inode->i_mode = S_IFDIR | S_IRUSR | S_IXUSR; + inode->i_op = &proc_fd_inode_operations; + inode->i_nlink = 2; + return; + case 9: + case 10: + case 11: + case 12: + case 15: + inode->i_mode = S_IFREG | S_IRUGO; + inode->i_op = &proc_array_inode_operations; + return; + } + switch (ino >> 8) { + case 1: + ino &= 0xff; + if (ino >= NR_OPEN || !p->filp[ino]) + return; + inode->i_op = &proc_link_inode_operations; + inode->i_size = 64; + inode->i_mode = S_IFLNK | S_IRWXU; + return; + case 2: + ino &= 0xff; + { + int j = 0; + struct vm_area_struct * mpnt; + for (mpnt = p->mmap ; mpnt ; mpnt = mpnt->vm_next) + if(mpnt->vm_inode) + j++; + if (ino >= j) + return; + } + inode->i_op = &proc_link_inode_operations; + inode->i_size = 64; + inode->i_mode = S_IFLNK | S_IRWXU; + return; + } + return; +} + +void proc_write_inode(struct inode * inode) +{ + inode->i_dirt=0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/kmsg.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/kmsg.c new file mode 100644 index 000000000..812ee3dd5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/kmsg.c @@ -0,0 +1,76 @@ +/* + * linux/fs/proc/kmsg.c + * + * Copyright (C) 1992 by Linus Torvalds + * + */ + +#include +#include +#include +#include + +#include +#include + +extern unsigned long log_size; +extern struct wait_queue * log_wait; + +asmlinkage int sys_syslog(int type, char * bug, int count); + +static int kmsg_open(struct inode * inode, struct file * file) +{ + return sys_syslog(1,NULL,0); +} + +static void kmsg_release(struct inode * inode, struct file * file) +{ + (void) sys_syslog(0,NULL,0); +} + +static int kmsg_read(struct inode * inode, struct file * file,char * buf, int count) +{ + return sys_syslog(2,buf,count); +} + +static int kmsg_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + if (sel_type != SEL_IN) + return 0; + if (log_size) + return 1; + select_wait(&log_wait, wait); + return 0; +} + + +static struct file_operations proc_kmsg_operations = { + NULL, /* kmsg_lseek */ + kmsg_read, + NULL, /* kmsg_write */ + NULL, /* kmsg_readdir */ + kmsg_select, /* kmsg_select */ + NULL, /* kmsg_ioctl */ + NULL, /* mmap */ + kmsg_open, + kmsg_release, + NULL /* can't fsync */ +}; + +struct inode_operations proc_kmsg_inode_operations = { + &proc_kmsg_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/link.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/link.c new file mode 100644 index 000000000..2da00b0c1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/link.c @@ -0,0 +1,129 @@ +/* + * linux/fs/proc/link.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * /proc link-file handling code + */ + +#include + +#include +#include +#include +#include +#include + +static int proc_readlink(struct inode *, char *, int); +static int proc_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * links can't do much... + */ +struct inode_operations proc_link_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + proc_readlink, /* readlink */ + proc_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int proc_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + unsigned int pid, ino; + struct task_struct * p; + int i; + + *res_inode = NULL; + if (dir) + iput(dir); + if (!inode) + return -ENOENT; + if (!permission(inode, MAY_EXEC)) { + iput(inode); + return -EACCES; + } + ino = inode->i_ino; + pid = ino >> 16; + ino &= 0x0000ffff; + iput(inode); + for (i = 0 ; i < NR_TASKS ; i++) + if ((p = task[i]) && p->pid == pid) + break; + if (i >= NR_TASKS) + return -ENOENT; + inode = NULL; + switch (ino) { + case 4: + inode = p->pwd; + break; + case 5: + inode = p->root; + break; + case 6: + inode = p->executable; + break; + default: + switch (ino >> 8) { + case 1: + ino &= 0xff; + if (ino < NR_OPEN && p->filp[ino]) + inode = p->filp[ino]->f_inode; + break; + case 2: + ino &= 0xff; + { int j = ino; + struct vm_area_struct * mpnt; + for(mpnt = p->mmap; mpnt && j >= 0; + mpnt = mpnt->vm_next){ + if(mpnt->vm_inode) { + if(j == 0) { + inode = mpnt->vm_inode; + break; + }; + j--; + } + } + }; + } + } + if (!inode) + return -ENOENT; + *res_inode = inode; + inode->i_count++; + return 0; +} + +static int proc_readlink(struct inode * inode, char * buffer, int buflen) +{ + int i; + unsigned int dev,ino; + char buf[64]; + + i = proc_follow_link(NULL, inode, 0, 0, &inode); + if (i) + return i; + if (!inode) + return -EIO; + dev = inode->i_dev; + ino = inode->i_ino; + iput(inode); + i = sprintf(buf,"[%04x]:%u", dev, ino); + if (buflen > i) + buflen = i; + i = 0; + while (i < buflen) + put_fs_byte(buf[i++],buffer++); + return i; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/mem.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/mem.c new file mode 100644 index 000000000..28fd4be8c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/mem.c @@ -0,0 +1,170 @@ +/* + * linux/fs/proc/mem.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include + +#include +#include + +/* + * mem_write isn't really a good idea right now. It needs + * to check a lot more: if the process we try to write to + * dies in the middle right now, mem_write will overwrite + * kernel memory.. This disables it altogether. + */ +#define mem_write NULL + +static int mem_read(struct inode * inode, struct file * file,char * buf, int count) +{ + unsigned long addr, pid, cr3; + char *tmp; + unsigned long pte, page; + int i; + + if (count < 0) + return -EINVAL; + pid = inode->i_ino; + pid >>= 16; + cr3 = 0; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) { + cr3 = task[i]->tss.cr3; + break; + } + if (!cr3) + return -EACCES; + addr = file->f_pos; + tmp = buf; + while (count > 0) { + if (current->signal & ~current->blocked) + break; + pte = *PAGE_DIR_OFFSET(cr3,addr); + if (!(pte & PAGE_PRESENT)) + break; + pte &= PAGE_MASK; + pte += PAGE_PTR(addr); + page = *(unsigned long *) pte; + if (!(page & 1)) + break; + page &= PAGE_MASK; + page += addr & ~PAGE_MASK; + i = PAGE_SIZE-(addr & ~PAGE_MASK); + if (i > count) + i = count; + memcpy_tofs(tmp,(void *) page,i); + addr += i; + tmp += i; + count -= i; + } + file->f_pos = addr; + return tmp-buf; +} + +#ifndef mem_write + +static int mem_write(struct inode * inode, struct file * file,char * buf, int count) +{ + unsigned long addr, pid, cr3; + char *tmp; + unsigned long pte, page; + int i; + + if (count < 0) + return -EINVAL; + addr = file->f_pos; + pid = inode->i_ino; + pid >>= 16; + cr3 = 0; + for (i = 1 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) { + cr3 = task[i]->tss.cr3; + break; + } + if (!cr3) + return -EACCES; + tmp = buf; + while (count > 0) { + if (current->signal & ~current->blocked) + break; + pte = *PAGE_DIR_OFFSET(cr3,addr); + if (!(pte & PAGE_PRESENT)) + break; + pte &= PAGE_MASK; + pte += PAGE_PTR(addr); + page = *(unsigned long *) pte; + if (!(page & PAGE_PRESENT)) + break; + if (!(page & 2)) { + do_wp_page(0,addr,current,0); + continue; + } + page &= PAGE_MASK; + page += addr & ~PAGE_MASK; + i = PAGE_SIZE-(addr & ~PAGE_MASK); + if (i > count) + i = count; + memcpy_fromfs((void *) page,tmp,i); + addr += i; + tmp += i; + count -= i; + } + file->f_pos = addr; + if (tmp != buf) + return tmp-buf; + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + return 0; +} + +#endif + +static int mem_lseek(struct inode * inode, struct file * file, off_t offset, int orig) +{ + switch (orig) { + case 0: + file->f_pos = offset; + return file->f_pos; + case 1: + file->f_pos += offset; + return file->f_pos; + default: + return -EINVAL; + } +} + +static struct file_operations proc_mem_operations = { + mem_lseek, + mem_read, + mem_write, + NULL, /* mem_readdir */ + NULL, /* mem_select */ + NULL, /* mem_ioctl */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +struct inode_operations proc_mem_inode_operations = { + &proc_mem_operations, /* default base directory file-ops */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/net.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/net.c new file mode 100644 index 000000000..c7c300e26 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/net.c @@ -0,0 +1,210 @@ +/* + * linux/fs/proc/net.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * gjh 3/'93 heim@peanuts.informatik.uni-tuebingen.de (Gerald J. Heim) + * most of this file is stolen from base.c + * it works, but you shouldn't use it as a guideline + * for new proc-fs entries. once i'll make it better. + * fvk 3/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen) + * cleaned up the whole thing, moved "net" specific code to + * the NET kernel layer (where it belonged in the first place). + * Michael K. Johnson (johnsonm@stolaf.edu) 3/93 + * Added support from my previous inet.c. Cleaned things up + * quite a bit, modularized the code. + * fvk 4/'93 waltje@uwalt.nl.mugnet.org (Fred N. van Kempen) + * Renamed "route_get_info()" to "rt_get_info()" for consistency. + * + * proc net directory handling functions + */ +#include + +#include + +#include +#include +#include +#include + +/* forward references */ +static int proc_readnet(struct inode * inode, struct file * file, + char * buf, int count); +static int proc_readnetdir(struct inode *, struct file *, + struct dirent *, int); +static int proc_lookupnet(struct inode *,const char *,int,struct inode **); + +/* the get_*_info() functions are in the net code, and are configured + in via the standard mechanism... */ +extern int unix_get_info(char *); +#ifdef CONFIG_INET +extern int tcp_get_info(char *); +extern int udp_get_info(char *); +extern int raw_get_info(char *); +extern int arp_get_info(char *); +extern int dev_get_info(char *); +extern int rt_get_info(char *); +#endif /* CONFIG_INET */ + + +static struct file_operations proc_net_operations = { + NULL, /* lseek - default */ + proc_readnet, /* read - bad */ + NULL, /* write - bad */ + proc_readnetdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* can't fsync */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_net_inode_operations = { + &proc_net_operations, /* default net directory file-ops */ + NULL, /* create */ + proc_lookupnet, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static struct proc_dir_entry net_dir[] = { + { 1,2,".." }, + { 8,1,"." }, + { 128,4,"unix" } +#ifdef CONFIG_INET + ,{ 129,3,"arp" }, + { 130,5,"route" }, + { 131,3,"dev" }, + { 132,3,"raw" }, + { 133,3,"tcp" }, + { 134,3,"udp" } +#endif /* CONFIG_INET */ +}; + +#define NR_NET_DIRENTRY ((sizeof (net_dir))/(sizeof (net_dir[0]))) + + +static int proc_lookupnet(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + unsigned int ino; + int i; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + i = NR_NET_DIRENTRY; + while (i-- > 0 && !proc_match(len,name,net_dir+i)) + /* nothing */; + if (i < 0) { + iput(dir); + return -ENOENT; + } + ino = net_dir[i].low_ino; + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; +} + +static int proc_readnetdir(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + struct proc_dir_entry * de; + unsigned int ino; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; + ino = inode->i_ino; + if (((unsigned) filp->f_pos) < NR_NET_DIRENTRY) { + de = net_dir + filp->f_pos; + filp->f_pos++; + i = de->namelen; + ino = de->low_ino; + put_fs_long(ino, &dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + put_fs_byte(0,i+dirent->d_name); + j = i; + while (i--) + put_fs_byte(de->name[i], i+dirent->d_name); + return j; + } + return 0; +} + + +static int proc_readnet(struct inode * inode, struct file * file, + char * buf, int count) +{ + char * page; + int length; + int end; + unsigned int ino; + + if (count < 0) + return -EINVAL; + if (!(page = (char*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + ino = inode->i_ino; + switch (ino) { +#ifdef CONFIG_INET + case 128: + length = unix_get_info(page); + break; + case 129: + length = arp_get_info(page); + break; + case 130: + length = rt_get_info(page); + break; + case 131: + length = dev_get_info(page); + break; + case 132: + length = raw_get_info(page); + break; + case 133: + length = tcp_get_info(page); + break; + case 134: + length = udp_get_info(page); + break; +#endif /* CONFIG_INET */ + default: + free_page((unsigned long) page); + return -EBADF; + } + if (file->f_pos >= length) { + free_page((unsigned long) page); + return 0; + } + if (count + file->f_pos > length) + count = length - file->f_pos; + end = count + file->f_pos; + memcpy_tofs(buf, page + file->f_pos, count); + free_page((unsigned long) page); + file->f_pos = end; + return count; + +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/root.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/root.c new file mode 100644 index 000000000..1690b431f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/proc/root.c @@ -0,0 +1,179 @@ +/* + * linux/fs/proc/root.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * proc root directory handling functions + */ + +#include + +#include +#include +#include +#include +#include + +static int proc_readroot(struct inode *, struct file *, struct dirent *, int); +static int proc_lookuproot(struct inode *,const char *,int,struct inode **); + +static struct file_operations proc_root_operations = { + NULL, /* lseek - default */ + NULL, /* read - bad */ + NULL, /* write - bad */ + proc_readroot, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + NULL /* no fsync */ +}; + +/* + * proc directories can do almost nothing.. + */ +struct inode_operations proc_root_inode_operations = { + &proc_root_operations, /* default base directory file-ops */ + NULL, /* create */ + proc_lookuproot, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static struct proc_dir_entry root_dir[] = { + { 1,1,"." }, + { 1,2,".." }, + { 2,7,"loadavg" }, + { 3,6,"uptime" }, + { 4,7,"meminfo" }, + { 5,4,"kmsg" }, + { 6,7,"version" }, + { 7,4,"self" }, /* will change inode # */ + { 8,3,"net" }, +#ifdef CONFIG_DEBUG_MALLOC + {13,6,"malloc" }, +#endif + {14,5,"kcore" }, + {16,7,"modules" }, + {17,4,"stat" }, +}; + +#define NR_ROOT_DIRENTRY ((sizeof (root_dir))/(sizeof (root_dir[0]))) + +static int proc_lookuproot(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + unsigned int pid, c; + int i, ino; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + i = NR_ROOT_DIRENTRY; + while (i-- > 0 && !proc_match(len,name,root_dir+i)) + /* nothing */; + if (i >= 0) { + ino = root_dir[i].low_ino; + if (ino == 1) { + *result = dir; + return 0; + } + if (ino == 7) /* self modifying inode ... */ + ino = (current->pid << 16) + 2; + } else { + pid = 0; + while (len-- > 0) { + c = *name - '0'; + name++; + if (c > 9) { + pid = 0; + break; + } + pid *= 10; + pid += c; + if (pid & 0xffff0000) { + pid = 0; + break; + } + } + for (i = 0 ; i < NR_TASKS ; i++) + if (task[i] && task[i]->pid == pid) + break; + if (!pid || i >= NR_TASKS) { + iput(dir); + return -ENOENT; + } + ino = (pid << 16) + 2; + } + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -ENOENT; + } + iput(dir); + return 0; +} + +static int proc_readroot(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + struct task_struct * p; + unsigned int nr,pid; + int i,j; + + if (!inode || !S_ISDIR(inode->i_mode)) + return -EBADF; +repeat: + nr = filp->f_pos; + if (nr < NR_ROOT_DIRENTRY) { + struct proc_dir_entry * de = root_dir + nr; + + filp->f_pos++; + i = de->namelen; + put_fs_long(de->low_ino, &dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + put_fs_byte(0,i+dirent->d_name); + j = i; + while (i--) + put_fs_byte(de->name[i], i+dirent->d_name); + return j; + } + nr -= NR_ROOT_DIRENTRY; + if (nr >= NR_TASKS) + return 0; + filp->f_pos++; + p = task[nr]; + if (!p || !(pid = p->pid)) + goto repeat; + if (pid & 0xffff0000) + goto repeat; + j = 10; + i = 1; + while (pid >= j) { + j *= 10; + i++; + } + j = i; + put_fs_long((pid << 16)+2, &dirent->d_ino); + put_fs_word(i, &dirent->d_reclen); + put_fs_byte(0, i+dirent->d_name); + while (i--) { + put_fs_byte('0'+(pid % 10), i+dirent->d_name); + pid /= 10; + } + return j; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/read_write.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/read_write.c new file mode 100644 index 000000000..3ff9058e9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/read_write.c @@ -0,0 +1,108 @@ +/* + * linux/fs/read_write.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include + +#include + +/* + * Count is not yet used: but we'll probably support reading several entries + * at once in the future. Use count=1 in the library for future expansions. + */ +asmlinkage int sys_readdir(unsigned int fd, struct dirent * dirent, unsigned int count) +{ + int error; + struct file * file; + struct inode * inode; + + if (fd >= NR_OPEN || !(file = current->filp[fd]) || + !(inode = file->f_inode)) + return -EBADF; + error = -ENOTDIR; + if (file->f_op && file->f_op->readdir) { + error = verify_area(VERIFY_WRITE, dirent, sizeof (*dirent)); + if (!error) + error = file->f_op->readdir(inode,file,dirent,count); + } + return error; +} + +asmlinkage int sys_lseek(unsigned int fd, off_t offset, unsigned int origin) +{ + struct file * file; + int tmp = -1; + + if (fd >= NR_OPEN || !(file=current->filp[fd]) || !(file->f_inode)) + return -EBADF; + if (origin > 2) + return -EINVAL; + if (file->f_op && file->f_op->lseek) + return file->f_op->lseek(file->f_inode,file,offset,origin); + +/* this is the default handler if no lseek handler is present */ + switch (origin) { + case 0: + tmp = offset; + break; + case 1: + tmp = file->f_pos + offset; + break; + case 2: + if (!file->f_inode) + return -EINVAL; + tmp = file->f_inode->i_size + offset; + break; + } + if (tmp < 0) + return -EINVAL; + file->f_pos = tmp; + file->f_reada = 0; + return file->f_pos; +} + +asmlinkage int sys_read(unsigned int fd,char * buf,unsigned int count) +{ + int error; + struct file * file; + struct inode * inode; + + if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode)) + return -EBADF; + if (!(file->f_mode & 1)) + return -EBADF; + if (!file->f_op || !file->f_op->read) + return -EINVAL; + if (!count) + return 0; + error = verify_area(VERIFY_WRITE,buf,count); + if (error) + return error; + return file->f_op->read(inode,file,buf,count); +} + +asmlinkage int sys_write(unsigned int fd,char * buf,unsigned int count) +{ + int error; + struct file * file; + struct inode * inode; + + if (fd>=NR_OPEN || !(file=current->filp[fd]) || !(inode=file->f_inode)) + return -EBADF; + if (!(file->f_mode & 2)) + return -EBADF; + if (!file->f_op || !file->f_op->write) + return -EINVAL; + if (!count) + return 0; + error = verify_area(VERIFY_READ,buf,count); + if (error) + return error; + return file->f_op->write(inode,file,buf,count); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/select.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/select.c new file mode 100644 index 000000000..cfa62cde4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/select.c @@ -0,0 +1,253 @@ +/* + * This file contains the procedures for the handling of select + * + * Created for Linux based loosely upon Mathius Lattner's minix + * patches by Peter MacDonald. Heavily edited by Linus. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#define ROUND_UP(x,y) (((x)+(y)-1)/(y)) + +/* + * Ok, Peter made a complicated, but straightforward multiple_wait() function. + * I have rewritten this, taking some shortcuts: This code may not be easy to + * follow, but it should be free of race-conditions, and it's practical. If you + * understand what I'm doing here, then you understand how the linux + * sleep/wakeup mechanism works. + * + * Two very simple procedures, select_wait() and free_wait() make all the work. + * select_wait() is a inline-function defined in , as all select + * functions have to call it to add an entry to the select table. + */ + +/* + * I rewrote this again to make the select_table size variable, take some + * more shortcuts, improve responsiveness, and remove another race that + * Linus noticed. -- jrs + */ + +static void free_wait(select_table * p) +{ + struct select_table_entry * entry = p->entry + p->nr; + + while (p->nr > 0) { + p->nr--; + entry--; + remove_wait_queue(entry->wait_address,&entry->wait); + } +} + +/* + * The check function checks the ready status of a file using the vfs layer. + * + * If the file was not ready we were added to its wait queue. But in + * case it became ready just after the check and just before it called + * select_wait, we call it again, knowing we are already on its + * wait queue this time. The second call is not necessary if the + * select_table is NULL indicating an earlier file check was ready + * and we aren't going to sleep on the select_table. -- jrs + */ + +static int check(int flag, select_table * wait, struct file * file) +{ + struct inode * inode; + struct file_operations *fops; + int (*select) (struct inode *, struct file *, int, select_table *); + + inode = file->f_inode; + if ((fops = file->f_op) && (select = fops->select)) + return select(inode, file, flag, wait) + || (wait && select(inode, file, flag, NULL)); + if (S_ISREG(inode->i_mode)) + return 1; + return 0; +} + +int do_select(int n, fd_set *in, fd_set *out, fd_set *ex, + fd_set *res_in, fd_set *res_out, fd_set *res_ex) +{ + int count; + select_table wait_table, *wait; + struct select_table_entry *entry; + unsigned long set; + int i,j; + int max = -1; + + for (j = 0 ; j < __FDSET_LONGS ; j++) { + i = j << 5; + if (i >= n) + break; + set = in->fds_bits[j] | out->fds_bits[j] | ex->fds_bits[j]; + for ( ; set ; i++,set >>= 1) { + if (i >= n) + goto end_check; + if (!(set & 1)) + continue; + if (!current->filp[i]) + return -EBADF; + if (!current->filp[i]->f_inode) + return -EBADF; + max = i; + } + } +end_check: + n = max + 1; + if(!(entry = (struct select_table_entry*) __get_free_page(GFP_KERNEL))) + return -ENOMEM; + FD_ZERO(res_in); + FD_ZERO(res_out); + FD_ZERO(res_ex); + count = 0; + wait_table.nr = 0; + wait_table.entry = entry; + wait = &wait_table; +repeat: + current->state = TASK_INTERRUPTIBLE; + for (i = 0 ; i < n ; i++) { + if (FD_ISSET(i,in) && check(SEL_IN,wait,current->filp[i])) { + FD_SET(i, res_in); + count++; + wait = NULL; + } + if (FD_ISSET(i,out) && check(SEL_OUT,wait,current->filp[i])) { + FD_SET(i, res_out); + count++; + wait = NULL; + } + if (FD_ISSET(i,ex) && check(SEL_EX,wait,current->filp[i])) { + FD_SET(i, res_ex); + count++; + wait = NULL; + } + } + wait = NULL; + if (!count && current->timeout && !(current->signal & ~current->blocked)) { + schedule(); + goto repeat; + } + free_wait(&wait_table); + free_page((unsigned long) entry); + current->state = TASK_RUNNING; + return count; +} + +/* + * We do a VERIFY_WRITE here even though we are only reading this time: + * we'll write to it eventually.. + */ +static int __get_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdset) +{ + int error; + + FD_ZERO(fdset); + if (!fs_pointer) + return 0; + error = verify_area(VERIFY_WRITE,fs_pointer,sizeof(fd_set)); + if (error) + return error; + while (nr > 0) { + *fdset = get_fs_long(fs_pointer); + fdset++; + fs_pointer++; + nr -= 32; + } + return 0; +} + +static void __set_fd_set(int nr, unsigned long * fs_pointer, unsigned long * fdset) +{ + if (!fs_pointer) + return; + while (nr > 0) { + put_fs_long(*fdset, fs_pointer); + fdset++; + fs_pointer++; + nr -= 32; + } +} + +#define get_fd_set(nr,fsp,fdp) \ +__get_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp)) + +#define set_fd_set(nr,fsp,fdp) \ +__set_fd_set(nr, (unsigned long *) (fsp), (unsigned long *) (fdp)) + +/* + * We can actually return ERESTARTSYS insetad of EINTR, but I'd + * like to be certain this leads to no problems. So I return + * EINTR just for safety. + * + * Update: ERESTARTSYS breaks at least the xview clock binary, so + * I'm trying ERESTARTNOHAND which restart only when you want to. + */ +asmlinkage int sys_select( unsigned long *buffer ) +{ +/* Perform the select(nd, in, out, ex, tv) system call. */ + int i; + fd_set res_in, in, *inp; + fd_set res_out, out, *outp; + fd_set res_ex, ex, *exp; + int n; + struct timeval *tvp; + unsigned long timeout; + + i = verify_area(VERIFY_READ, buffer, 20); + if (i) + return i; + n = get_fs_long(buffer++); + if (n < 0) + return -EINVAL; + if (n > NR_OPEN) + n = NR_OPEN; + inp = (fd_set *) get_fs_long(buffer++); + outp = (fd_set *) get_fs_long(buffer++); + exp = (fd_set *) get_fs_long(buffer++); + tvp = (struct timeval *) get_fs_long(buffer); + if ((i = get_fd_set(n, inp, &in)) || + (i = get_fd_set(n, outp, &out)) || + (i = get_fd_set(n, exp, &ex))) return i; + timeout = ~0UL; + if (tvp) { + i = verify_area(VERIFY_WRITE, tvp, sizeof(*tvp)); + if (i) + return i; + timeout = jiffies; + timeout += ROUND_UP(get_fs_long((unsigned long *)&tvp->tv_usec),(1000000/HZ)); + timeout += get_fs_long((unsigned long *)&tvp->tv_sec) * HZ; + if (timeout <= jiffies) + timeout = 0; + } + current->timeout = timeout; + i = do_select(n, &in, &out, &ex, &res_in, &res_out, &res_ex); + if (current->timeout > jiffies) + timeout = current->timeout - jiffies; + else + timeout = 0; + current->timeout = 0; + if (tvp) { + put_fs_long(timeout/HZ, (unsigned long *) &tvp->tv_sec); + timeout %= HZ; + timeout *= (1000000/HZ); + put_fs_long(timeout, (unsigned long *) &tvp->tv_usec); + } + if (i < 0) + return i; + if (!i && (current->signal & ~current->blocked)) + return -ERESTARTNOHAND; + set_fd_set(n, inp, &res_in); + set_fd_set(n, outp, &res_out); + set_fd_set(n, exp, &res_ex); + return i; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/stat.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/stat.c new file mode 100644 index 000000000..d5cc98e6c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/stat.c @@ -0,0 +1,201 @@ +/* + * linux/fs/stat.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include + +static void cp_old_stat(struct inode * inode, struct old_stat * statbuf) +{ + struct old_stat tmp; + + printk("VFS: Warning: %s using old stat() call. Recompile your binary.\n", + current->comm); + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_rdev; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; + memcpy_tofs(statbuf,&tmp,sizeof(tmp)); +} + +static void cp_new_stat(struct inode * inode, struct new_stat * statbuf) +{ + struct new_stat tmp = {0, }; + unsigned int blocks, indirect; + + tmp.st_dev = inode->i_dev; + tmp.st_ino = inode->i_ino; + tmp.st_mode = inode->i_mode; + tmp.st_nlink = inode->i_nlink; + tmp.st_uid = inode->i_uid; + tmp.st_gid = inode->i_gid; + tmp.st_rdev = inode->i_rdev; + tmp.st_size = inode->i_size; + tmp.st_atime = inode->i_atime; + tmp.st_mtime = inode->i_mtime; + tmp.st_ctime = inode->i_ctime; +/* + * st_blocks and st_blksize are approximated with a simple algorithm if + * they aren't supported directly by the filesystem. The minix and msdos + * filesystems don't keep track of blocks, so they would either have to + * be counted explicitly (by delving into the file itself), or by using + * this simple algorithm to get a reasonable (although not 100% accurate) + * value. + */ + +/* + * Use minix fs values for the number of direct and indirect blocks. The + * count is now exact for the minix fs except that it counts zero blocks. + * Everything is in BLOCK_SIZE'd units until the assignment to + * tmp.st_blksize. + */ +#define D_B 7 +#define I_B (BLOCK_SIZE / sizeof(unsigned short)) + + if (!inode->i_blksize) { + blocks = (tmp.st_size + BLOCK_SIZE - 1) / BLOCK_SIZE; + if (blocks > D_B) { + indirect = (blocks - D_B + I_B - 1) / I_B; + blocks += indirect; + if (indirect > 1) { + indirect = (indirect - 1 + I_B - 1) / I_B; + blocks += indirect; + if (indirect > 1) + blocks++; + } + } + tmp.st_blocks = (BLOCK_SIZE / 512) * blocks; + tmp.st_blksize = BLOCK_SIZE; + } else { + tmp.st_blocks = inode->i_blocks; + tmp.st_blksize = inode->i_blksize; + } + memcpy_tofs(statbuf,&tmp,sizeof(tmp)); +} + +asmlinkage int sys_stat(char * filename, struct old_stat * statbuf) +{ + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf)); + if (error) + return error; + error = namei(filename,&inode); + if (error) + return error; + cp_old_stat(inode,statbuf); + iput(inode); + return 0; +} + +asmlinkage int sys_newstat(char * filename, struct new_stat * statbuf) +{ + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf)); + if (error) + return error; + error = namei(filename,&inode); + if (error) + return error; + cp_new_stat(inode,statbuf); + iput(inode); + return 0; +} + +asmlinkage int sys_lstat(char * filename, struct old_stat * statbuf) +{ + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf)); + if (error) + return error; + error = lnamei(filename,&inode); + if (error) + return error; + cp_old_stat(inode,statbuf); + iput(inode); + return 0; +} + +asmlinkage int sys_newlstat(char * filename, struct new_stat * statbuf) +{ + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf)); + if (error) + return error; + error = lnamei(filename,&inode); + if (error) + return error; + cp_new_stat(inode,statbuf); + iput(inode); + return 0; +} + +asmlinkage int sys_fstat(unsigned int fd, struct old_stat * statbuf) +{ + struct file * f; + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf)); + if (error) + return error; + if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_old_stat(inode,statbuf); + return 0; +} + +asmlinkage int sys_newfstat(unsigned int fd, struct new_stat * statbuf) +{ + struct file * f; + struct inode * inode; + int error; + + error = verify_area(VERIFY_WRITE,statbuf,sizeof (*statbuf)); + if (error) + return error; + if (fd >= NR_OPEN || !(f=current->filp[fd]) || !(inode=f->f_inode)) + return -EBADF; + cp_new_stat(inode,statbuf); + return 0; +} + +asmlinkage int sys_readlink(const char * path, char * buf, int bufsiz) +{ + struct inode * inode; + int error; + + if (bufsiz <= 0) + return -EINVAL; + error = verify_area(VERIFY_WRITE,buf,bufsiz); + if (error) + return error; + error = lnamei(path,&inode); + if (error) + return error; + if (!inode->i_op || !inode->i_op->readlink) { + iput(inode); + return -EINVAL; + } + return inode->i_op->readlink(inode,buf,bufsiz); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/super.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/super.c new file mode 100644 index 000000000..523205708 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/super.c @@ -0,0 +1,537 @@ +/* + * linux/fs/super.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * super.c contains code to handle the super-block tables. + */ +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +/* + * The definition of file_systems that used to be here is now in + * filesystems.c. Now super.c contains no fs specific code. -- jrs + */ + +extern struct file_system_type file_systems[]; +extern struct file_operations * get_blkfops(unsigned int); +extern struct file_operations * get_chrfops(unsigned int); + +extern void wait_for_keypress(void); +extern void fcntl_init_locks(void); + +extern int root_mountflags; + +struct super_block super_blocks[NR_SUPER]; + +static int do_remount_sb(struct super_block *sb, int flags, char * data); + +/* this is initialized in init/main.c */ +dev_t ROOT_DEV = 0; + +struct file_system_type *get_fs_type(char *name) +{ + int a; + + if (!name) + return &file_systems[0]; + for(a = 0 ; file_systems[a].read_super ; a++) + if (!strcmp(name,file_systems[a].name)) + return(&file_systems[a]); + return NULL; +} + +void __wait_on_super(struct super_block * sb) +{ + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&sb->s_wait, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (sb->s_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&sb->s_wait, &wait); + current->state = TASK_RUNNING; +} + +void sync_supers(dev_t dev) +{ + struct super_block * sb; + + for (sb = super_blocks + 0 ; sb < super_blocks + NR_SUPER ; sb++) { + if (!sb->s_dev) + continue; + if (dev && sb->s_dev != dev) + continue; + wait_on_super(sb); + if (!sb->s_dev || !sb->s_dirt) + continue; + if (dev && (dev != sb->s_dev)) + continue; + if (sb->s_op && sb->s_op->write_super) + sb->s_op->write_super(sb); + } +} + +static struct super_block * get_super(dev_t dev) +{ + struct super_block * s; + + if (!dev) + return NULL; + s = 0+super_blocks; + while (s < NR_SUPER+super_blocks) + if (s->s_dev == dev) { + wait_on_super(s); + if (s->s_dev == dev) + return s; + s = 0+super_blocks; + } else + s++; + return NULL; +} + +void put_super(dev_t dev) +{ + struct super_block * sb; + + if (dev == ROOT_DEV) { + printk("VFS: Root device %d/%d: prepare for armageddon\n", + MAJOR(dev), MINOR(dev)); + return; + } + if (!(sb = get_super(dev))) + return; + if (sb->s_covered) { + printk("VFS: Mounted device %d/%d - tssk, tssk\n", + MAJOR(dev), MINOR(dev)); + return; + } + if (sb->s_op && sb->s_op->put_super) + sb->s_op->put_super(sb); +} + +static struct super_block * read_super(dev_t dev,char *name,int flags, + void *data, int silent) +{ + struct super_block * s; + struct file_system_type *type; + + if (!dev) + return NULL; + check_disk_change(dev); + s = get_super(dev); + if (s) + return s; + if (!(type = get_fs_type(name))) { + printk("VFS: on device %d/%d: get_fs_type(%s) failed\n", + MAJOR(dev), MINOR(dev), name); + return NULL; + } + for (s = 0+super_blocks ;; s++) { + if (s >= NR_SUPER+super_blocks) + return NULL; + if (!s->s_dev) + break; + } + s->s_dev = dev; + s->s_flags = flags; + if (!type->read_super(s,data, silent)) { + s->s_dev = 0; + return NULL; + } + s->s_dev = dev; + s->s_covered = NULL; + s->s_rd_only = 0; + s->s_dirt = 0; + return s; +} + +/* + * Unnamed block devices are dummy devices used by virtual + * filesystems which don't use real block-devices. -- jrs + */ + +static char unnamed_dev_in_use[256]; + +static dev_t get_unnamed_dev(void) +{ + static int first_use = 0; + int i; + + if (first_use == 0) { + first_use = 1; + memset(unnamed_dev_in_use, 0, sizeof(unnamed_dev_in_use)); + unnamed_dev_in_use[0] = 1; /* minor 0 (nodev) is special */ + } + for (i = 0; i < sizeof unnamed_dev_in_use/sizeof unnamed_dev_in_use[0]; i++) { + if (!unnamed_dev_in_use[i]) { + unnamed_dev_in_use[i] = 1; + return (UNNAMED_MAJOR << 8) | i; + } + } + return 0; +} + +static void put_unnamed_dev(dev_t dev) +{ + if (!dev) + return; + if (!unnamed_dev_in_use[dev]) { + printk("VFS: put_unnamed_dev: freeing unused device %d/%d\n", + MAJOR(dev), MINOR(dev)); + return; + } + unnamed_dev_in_use[dev] = 0; +} + +static int do_umount(dev_t dev) +{ + struct super_block * sb; + int retval; + + if (dev==ROOT_DEV) { + /* Special case for "unmounting" root. We just try to remount + it readonly, and sync() the device. */ + if (!(sb=get_super(dev))) + return -ENOENT; + if (!(sb->s_flags & MS_RDONLY)) { + fsync_dev(dev); + retval = do_remount_sb(sb, MS_RDONLY, 0); + if (retval) + return retval; + } + return 0; + } + if (!(sb=get_super(dev)) || !(sb->s_covered)) + return -ENOENT; + if (!sb->s_covered->i_mount) + printk("VFS: umount(%d/%d): mounted inode has i_mount=NULL\n", + MAJOR(dev), MINOR(dev)); + if (!fs_may_umount(dev, sb->s_mounted)) + return -EBUSY; + sb->s_covered->i_mount = NULL; + iput(sb->s_covered); + sb->s_covered = NULL; + iput(sb->s_mounted); + sb->s_mounted = NULL; + if (sb->s_op && sb->s_op->write_super && sb->s_dirt) + sb->s_op->write_super(sb); + put_super(dev); + return 0; +} + +/* + * Now umount can handle mount points as well as block devices. + * This is important for filesystems which use unnamed block devices. + * + * There is a little kludge here with the dummy_inode. The current + * vfs release functions only use the r_dev field in the inode so + * we give them the info they need without using a real inode. + * If any other fields are ever needed by any block device release + * functions, they should be faked here. -- jrs + */ + +asmlinkage int sys_umount(char * name) +{ + struct inode * inode; + dev_t dev; + int retval; + struct inode dummy_inode; + struct file_operations * fops; + + if (!suser()) + return -EPERM; + retval = namei(name,&inode); + if (retval) { + retval = lnamei(name,&inode); + if (retval) + return retval; + } + if (S_ISBLK(inode->i_mode)) { + dev = inode->i_rdev; + if (IS_NODEV(inode)) { + iput(inode); + return -EACCES; + } + } else { + if (!inode || !inode->i_sb || inode != inode->i_sb->s_mounted) { + iput(inode); + return -EINVAL; + } + dev = inode->i_sb->s_dev; + iput(inode); + memset(&dummy_inode, 0, sizeof(dummy_inode)); + dummy_inode.i_rdev = dev; + inode = &dummy_inode; + } + if (MAJOR(dev) >= MAX_BLKDEV) { + iput(inode); + return -ENXIO; + } + if (!(retval = do_umount(dev)) && dev != ROOT_DEV) { + fops = get_blkfops(MAJOR(dev)); + if (fops && fops->release) + fops->release(inode,NULL); + if (MAJOR(dev) == UNNAMED_MAJOR) + put_unnamed_dev(dev); + } + if (inode != &dummy_inode) + iput(inode); + if (retval) + return retval; + fsync_dev(dev); + return 0; +} + +/* + * do_mount() does the actual mounting after sys_mount has done the ugly + * parameter parsing. When enough time has gone by, and everything uses the + * new mount() parameters, sys_mount() can then be cleaned up. + * + * We cannot mount a filesystem if it has active, used, or dirty inodes. + * We also have to flush all inode-data for this device, as the new mount + * might need new info. + */ +static int do_mount(dev_t dev, const char * dir, char * type, int flags, void * data) +{ + struct inode * dir_i; + struct super_block * sb; + int error; + + error = namei(dir,&dir_i); + if (error) + return error; + if (dir_i->i_count != 1 || dir_i->i_mount) { + iput(dir_i); + return -EBUSY; + } + if (!S_ISDIR(dir_i->i_mode)) { + iput(dir_i); + return -EPERM; + } + if (!fs_may_mount(dev)) { + iput(dir_i); + return -EBUSY; + } + sb = read_super(dev,type,flags,data,0); + if (!sb || sb->s_covered) { + iput(dir_i); + return -EBUSY; + } + sb->s_covered = dir_i; + dir_i->i_mount = sb->s_mounted; + return 0; /* we don't iput(dir_i) - see umount */ +} + + +/* + * Alters the mount flags of a mounted file system. Only the mount point + * is used as a reference - file system type and the device are ignored. + * FS-specific mount options can't be altered by remounting. + */ + +static int do_remount_sb(struct super_block *sb, int flags, char *data) +{ + int retval; + + /* If we are remounting RDONLY, make sure there are no rw files open */ + if ((flags & MS_RDONLY) && !(sb->s_flags & MS_RDONLY)) + if (!fs_may_remount_ro(sb->s_dev)) + return -EBUSY; + if (sb->s_op && sb->s_op->remount_fs) { + retval = sb->s_op->remount_fs(sb, &flags, data); + if (retval) + return retval; + } + sb->s_flags = (sb->s_flags & ~MS_RMT_MASK) | + (flags & MS_RMT_MASK); + return 0; +} + +static int do_remount(const char *dir,int flags,char *data) +{ + struct inode *dir_i; + int retval; + + retval = namei(dir,&dir_i); + if (retval) + return retval; + if (dir_i != dir_i->i_sb->s_mounted) { + iput(dir_i); + return -EINVAL; + } + retval = do_remount_sb(dir_i->i_sb, flags, data); + iput(dir_i); + return retval; +} + +static int copy_mount_options (char * data, unsigned long *where) +{ + int i; + unsigned long page; + struct vm_area_struct * vma; + + *where = 0; + if (!data) + return 0; + + for (vma = current->mmap ; ; ) { + if (!vma || + (unsigned long) data < vma->vm_start) { + return -EFAULT; + } + if ((unsigned long) data < vma->vm_end) + break; + vma = vma->vm_next; + } + i = vma->vm_end - (unsigned long) data; + if (PAGE_SIZE <= (unsigned long) i) + i = PAGE_SIZE-1; + if (!(page = __get_free_page(GFP_KERNEL))) { + return -ENOMEM; + } + memcpy_fromfs((void *) page,data,i); + *where = page; + return 0; +} + +/* + * Flags is a 16-bit value that allows up to 16 non-fs dependent flags to + * be given to the mount() call (ie: read-only, no-dev, no-suid etc). + * + * data is a (void *) that can point to any structure up to + * PAGE_SIZE-1 bytes, which can contain arbitrary fs-dependent + * information (or be NULL). + * + * NOTE! As old versions of mount() didn't use this setup, the flags + * has to have a special 16-bit magic number in the hight word: + * 0xC0ED. If this magic word isn't present, the flags and data info + * isn't used, as the syscall assumes we are talking to an older + * version that didn't understand them. + */ +asmlinkage int sys_mount(char * dev_name, char * dir_name, char * type, + unsigned long new_flags, void * data) +{ + struct file_system_type * fstype; + struct inode * inode; + struct file_operations * fops; + dev_t dev; + int retval; + char * t; + unsigned long flags = 0; + unsigned long page = 0; + + if (!suser()) + return -EPERM; + if ((new_flags & + (MS_MGC_MSK | MS_REMOUNT)) == (MS_MGC_VAL | MS_REMOUNT)) { + retval = copy_mount_options (data, &page); + if (retval < 0) + return retval; + retval = do_remount(dir_name, + new_flags & ~MS_MGC_MSK & ~MS_REMOUNT, + (char *) page); + free_page(page); + return retval; + } + retval = copy_mount_options (type, &page); + if (retval < 0) + return retval; + fstype = get_fs_type((char *) page); + free_page(page); + if (!fstype) + return -ENODEV; + t = fstype->name; + if (fstype->requires_dev) { + retval = namei(dev_name,&inode); + if (retval) + return retval; + if (!S_ISBLK(inode->i_mode)) { + iput(inode); + return -ENOTBLK; + } + if (IS_NODEV(inode)) { + iput(inode); + return -EACCES; + } + dev = inode->i_rdev; + if (MAJOR(dev) >= MAX_BLKDEV) { + iput(inode); + return -ENXIO; + } + } else { + if (!(dev = get_unnamed_dev())) + return -EMFILE; + inode = NULL; + } + fops = get_blkfops(MAJOR(dev)); + if (fops && fops->open) { + retval = fops->open(inode,NULL); + if (retval) { + iput(inode); + return retval; + } + } + page = 0; + if ((new_flags & MS_MGC_MSK) == MS_MGC_VAL) { + flags = new_flags & ~MS_MGC_MSK; + retval = copy_mount_options(data, &page); + if (retval < 0) { + iput(inode); + return retval; + } + } + retval = do_mount(dev,dir_name,t,flags,(void *) page); + free_page(page); + if (retval && fops && fops->release) + fops->release(inode,NULL); + iput(inode); + return retval; +} + +void mount_root(void) +{ + struct file_system_type * fs_type; + struct super_block * sb; + struct inode * inode; + + memset(super_blocks, 0, sizeof(super_blocks)); + fcntl_init_locks(); + if (MAJOR(ROOT_DEV) == FLOPPY_MAJOR) { + printk(KERN_NOTICE "VFS: Insert root floppy and press ENTER\n"); + wait_for_keypress(); + } + for (fs_type = file_systems; fs_type->read_super; fs_type++) { + if (!fs_type->requires_dev) + continue; + sb = read_super(ROOT_DEV,fs_type->name,root_mountflags,NULL,1); + if (sb) { + inode = sb->s_mounted; + inode->i_count += 3 ; /* NOTE! it is logically used 4 times, not 1 */ + sb->s_covered = inode; + sb->s_flags = root_mountflags; + current->pwd = inode; + current->root = inode; + printk ("VFS: Mounted root (%s filesystem)%s.\n", + fs_type->name, + (sb->s_flags & MS_RDONLY) ? " readonly" : ""); + return; + } + } + panic("VFS: Unable to mount root"); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/INTRO b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/INTRO new file mode 100644 index 000000000..fbf59b4f6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/INTRO @@ -0,0 +1,189 @@ +This is the implementation of the SystemV/Coherent filesystem for Linux. +It grew out of separate filesystem implementations + + Xenix FS Doug Evans June 1992 + SystemV FS Paul B. Monday March-June 1993 + Coherent FS B. Haible June 1993 + +and was merged together in July 1993. + +These filesystems are rather similar. Here is a comparison with Minix FS: + +* Linux fdisk reports on partitions + - Minix FS 0x81 Linux/Minix + - Xenix FS ?? + - SystemV FS ?? + - Coherent FS 0x08 AIX bootable + +* Size of a block or zone (data allocation unit on disk) + - Minix FS 1024 + - Xenix FS 1024 (also 512 ??) + - SystemV FS 1024 (also 512) + - Coherent FS 512 + +* General layout: all have one boot block, one super block and + separate areas for inodes and for directories/data. + On SystemV Release 2 FS (e.g. Microport) the first track is reserved and + all the block numbers (including the super block) are offset by one track. + +* Byte ordering of "short" (16 bit entities) on disk: + - Minix FS little endian 0 1 + - Xenix FS little endian 0 1 + - SystemV FS little endian 0 1 + - Coherent FS little endian 0 1 + Of course, this affects only the file system, not the data of files on it! + +* Byte ordering of "long" (32 bit entities) on disk: + - Minix FS little endian 0 1 2 3 + - Xenix FS little endian 0 1 2 3 + - SystemV FS little endian 0 1 2 3 + - Coherent FS PDP-11 2 3 0 1 + Of course, this affects only the file system, not the data of files on it! + +* Inode on disk: "short", 0 means non-existent, the root dir ino is: + - Minix FS 1 + - Xenix FS, SystemV FS, Coherent FS 2 + +* Maximum number of hard links to a file: + - Minix FS 250 + - Xenix FS ?? + - SystemV FS ?? + - Coherent FS >=10000 + +* Free inode management: + - Minix FS a bitmap + - Xenix FS, SystemV FS, Coherent FS + There is a cache of a certain number of free inodes in the super-block. + When it is exhausted, new free inodes are found using a linear search. + +* Free block management: + - Minix FS a bitmap + - Xenix FS, SystemV FS, Coherent FS + Free blocks are organized in a "free list". Maybe a misleading term, + since it is not true that every free block contains a pointer to + the next free block. Rather, the free blocks are organized in chunks + of limited size, and every now and then a free block contains pointers + to the free blocks pertaining to the next chunk; the first of these + contains pointers and so on. The list terminates with a "block number" + 0 on Xenix FS and SystemV FS, with a block zeroed out on Coherent FS. + +* Super-block location: + - Minix FS block 1 = bytes 1024..2047 + - Xenix FS block 1 = bytes 1024..2047 + - SystemV FS bytes 512..1023 + - Coherent FS block 1 = bytes 512..1023 + +* Super-block layout: + - Minix FS + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; + - Xenix FS, SystemV FS, Coherent FS + unsigned short s_firstdatazone; + unsigned long s_nzones; + unsigned short s_fzone_count; + unsigned long s_fzones[NICFREE]; + unsigned short s_finode_count; + unsigned short s_finodes[NICINOD]; + char s_flock; + char s_ilock; + char s_modified; + char s_rdonly; + unsigned long s_time; + short s_dinfo[4]; -- SystemV FS only + unsigned long s_free_zones; + unsigned short s_free_inodes; + short s_dinfo[4]; -- Xenix FS only + unsigned short s_interleave_m,s_interleave_n; -- Coherent FS only + char s_fname[6]; + char s_fpack[6]; + then they differ considerably: + Xenix FS + char s_clean; + char s_fill[371]; + long s_magic; + long s_type; + SystemV FS + long s_fill[12 or 14]; + long s_state; + long s_magic; + long s_type; + Coherent FS + unsigned long s_unique; + Note that Coherent FS has no magic. + +* Inode layout: + - Minix FS + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_time; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[7+1+1]; + - Xenix FS, SystemV FS, Coherent FS + unsigned short i_mode; + unsigned short i_nlink; + unsigned short i_uid; + unsigned short i_gid; + unsigned long i_size; + unsigned char i_zone[3*(10+1+1+1)]; + unsigned long i_atime; + unsigned long i_mtime; + unsigned long i_ctime; + +* Regular file data blocks are organized as + - Minix FS + 7 direct blocks + 1 indirect block (pointers to blocks) + 1 double-indirect block (pointer to pointers to blocks) + - Xenix FS, SystemV FS, Coherent FS + 10 direct blocks + 1 indirect block (pointers to blocks) + 1 double-indirect block (pointer to pointers to blocks) + 1 triple-indirect block (pointer to pointers to pointers to blocks) + +* Inode size, inodes per block + - Minix FS 32 32 + - Xenix FS 64 16 + - SystemV FS 64 16 + - Coherent FS 64 8 + +* Directory entry on disk + - Minix FS + unsigned short inode; + char name[14/30]; + - Xenix FS, SystemV FS, Coherent FS + unsigned short inode; + char name[14]; + +* Dir entry size, dir entries per block + - Minix FS 16/32 64/32 + - Xenix FS 16 64 + - SystemV FS 16 64 + - Coherent FS 16 32 + +* How to implement symbolic links such that the host fsck doesn't scream: + - Minix FS normal + - Xenix FS kludge: as regular files with chmod 1000 + - SystemV FS ?? + - Coherent FS kludge: as regular files with chmod 1000 + + +Notation: We often speak of a "block" but mean a zone (the allocation unit) +and not the disk driver's notion of "block". + +Because the block size may be smaller than 1024 (which is the unit used by +the disk drivers and the buffer code), many functions must return a pointer +to the buffer data additionally to the buffer head pointer. One must not +assume that the entire buffer is occupied by this single block. This makes +the implementation of truncate() difficult. + + +Bruno Haible + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/Makefile new file mode 100644 index 000000000..94f8d0453 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for the Linux SystemV/Coherent-filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= ialloc.o balloc.o inode.o file.o dir.o symlink.o namei.o \ + fsync.o truncate.o # mmap.o + +sysv.o: $(OBJS) + $(LD) -r -o sysv.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/README b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/README new file mode 100644 index 000000000..6257a0d24 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/README @@ -0,0 +1,37 @@ +This is the implementation of the SystemV/Coherent filesystem for Linux. +It implements all of + - Xenix FS, + - SystemV/386 FS, + - Coherent FS. + +This is version beta 1. + +To install: +* Answer the 'System V and Coherent filesystem support' question with 'y' + when configuring the kernel. +* To mount a disk or a partition, use + mount [-r] -t sysv device mountpoint + The file system type names + -t sysv + -t xenix + -t coherent + may be used interchangeably, but the last two will eventually disappear. + +Bugs in the present implementation: +- Coherent FS: + - The "free list interleave" n:m is currently ignored. + - Only file systems with no filesystem name and no pack name are recognized. + (See Coherent "man mkfs" for a description of these features.) +- SystemV Release 2 FS: + The superblock is only searched in the blocks 9, 15, 18, which corresponds to the + beginning of track 1 on floppy disks. No support for this FS on hard disk yet. + + +Please report any bugs and suggestions to + Bruno Haible or + Pascal Haible . + + +Bruno Haible + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/balloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/balloc.c new file mode 100644 index 000000000..6990b4175 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/balloc.c @@ -0,0 +1,349 @@ +/* + * linux/fs/sysv/balloc.c + * + * minix/bitmap.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext/freelists.c + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * xenix/alloc.c + * Copyright (C) 1992 Doug Evans + * + * coh/alloc.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/balloc.c + * Copyright (C) 1993 Bruno Haible + * + * This file contains code for allocating/freeing blocks. + */ + +#include +#include +#include +#include +#include + +/* We don't trust the value of + sb->sv_sbd->s_tfree = *sb->sv_sb_total_free_blocks + but we nevertheless keep it up to date. */ + +extern inline void memzero (void * s, size_t count) +{ +__asm__("cld\n\t" + "rep\n\t" + "stosl" + : + :"a" (0),"D" (s),"c" (count/4) + :"cx","di","memory"); +} + +void sysv_free_block(struct super_block * sb, unsigned int block) +{ + struct buffer_head * bh; + char * bh_data; + + if (!sb) { + printk("sysv_free_block: trying to free block on nonexistent device\n"); + return; + } + if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { + printk("sysv_free_block: trying to free block not in datazone\n"); + return; + } + lock_super(sb); + if (*sb->sv_sb_flc_count > sb->sv_flc_size) { + printk("sysv_free_block: flc_count > flc_size\n"); + unlock_super(sb); + return; + } + /* If the free list head in super-block is full, it is copied + * into this block being freed: + */ + if (*sb->sv_sb_flc_count == sb->sv_flc_size) { + unsigned short * flc_count; + unsigned long * flc_blocks; + + if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */ + bh = bread(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + else + bh = getblk(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (!bh) { + printk("sysv_free_block: getblk() or bread() failed\n"); + unlock_super(sb); + return; + } + bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + switch (sb->sv_type) { + case FSTYPE_XENIX: + flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_SYSV4: + flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_SYSV2: + flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_COH: + flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; + break; + default: panic("sysv_free_block: invalid fs type\n"); + } + *flc_count = *sb->sv_sb_flc_count; /* = sb->sv_flc_size */ + memcpy(flc_blocks, sb->sv_sb_flc_blocks, *flc_count * sizeof(sysv_zone_t)); + bh->b_dirt = 1; + bh->b_uptodate = 1; + brelse(bh); + *sb->sv_sb_flc_count = 0; + } else + /* If the free list head in super-block is empty, create a new head + * in this block being freed: + */ + if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */ + if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */ + bh = bread(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + else + bh = getblk(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (!bh) { + printk("sysv_free_block: getblk() or bread() failed\n"); + unlock_super(sb); + return; + } + bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + memzero(bh_data, sb->sv_block_size); + /* this implies ((struct ..._freelist_chunk *) bh_data)->flc_count = 0; */ + bh->b_dirt = 1; + bh->b_uptodate = 1; + brelse(bh); + /* still *sb->sv_sb_flc_count = 0 */ + } else { + if (sb->sv_block_size_ratio_bits == 0) { /* block_size == BLOCK_SIZE ? */ + /* Throw away block's contents */ + bh = get_hash_table(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (bh) + bh->b_dirt = 0; + brelse(bh); + } + } + if (sb->sv_convert) + block = to_coh_ulong(block); + sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)++] = block; + if (sb->sv_convert) + *sb->sv_sb_total_free_blocks = + to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) + 1); + else + *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks + 1; + sb->sv_bh->b_dirt = 1; /* super-block has been modified */ + sb->s_dirt = 1; /* and needs time stamp */ + unlock_super(sb); +} + +int sysv_new_block(struct super_block * sb) +{ + unsigned int block; + struct buffer_head * bh; + char * bh_data; + + if (!sb) { + printk("sysv_new_block: trying to get new block from nonexistent device\n"); + return 0; + } + lock_super(sb); + if (*sb->sv_sb_flc_count == 0) { /* Applies only to Coherent FS */ + unlock_super(sb); + return 0; /* no blocks available */ + } + block = sb->sv_sb_flc_blocks[(*sb->sv_sb_flc_count)-1]; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (block == 0) { /* Applies only to Xenix FS, SystemV FS */ + unlock_super(sb); + return 0; /* no blocks available */ + } + (*sb->sv_sb_flc_count)--; + if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { + printk("sysv_new_block: new block %d is not in data zone\n",block); + unlock_super(sb); + return 0; + } + if (*sb->sv_sb_flc_count == 0) { /* the last block continues the free list */ + unsigned short * flc_count; + unsigned long * flc_blocks; + + if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) { + printk("sysv_new_block: cannot read free-list block\n"); + /* retry this same block next time */ + (*sb->sv_sb_flc_count)++; + unlock_super(sb); + return 0; + } + switch (sb->sv_type) { + case FSTYPE_XENIX: + flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_SYSV4: + flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_SYSV2: + flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_COH: + flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; + break; + default: panic("sysv_new_block: invalid fs type\n"); + } + if (*flc_count > sb->sv_flc_size) { + printk("sysv_new_block: free-list block with >flc_size entries\n"); + brelse(bh); + unlock_super(sb); + return 0; + } + *sb->sv_sb_flc_count = *flc_count; + memcpy(sb->sv_sb_flc_blocks, flc_blocks, *flc_count * sizeof(sysv_zone_t)); + brelse(bh); + } + /* Now the free list head in the superblock is valid again. */ + if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */ + bh = bread(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + else + bh = getblk(sb->s_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (!bh) { + printk("sysv_new_block: getblk() or bread() failed\n"); + unlock_super(sb); + return 0; + } + bh_data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + if (sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */ + if (bh->b_count != 1) { + printk("sysv_new_block: block already in use\n"); + unlock_super(sb); + return 0; + } + memzero(bh_data,sb->sv_block_size); + bh->b_dirt = 1; + bh->b_uptodate = 1; + brelse(bh); + if (sb->sv_convert) + *sb->sv_sb_total_free_blocks = + to_coh_ulong(from_coh_ulong(*sb->sv_sb_total_free_blocks) - 1); + else + *sb->sv_sb_total_free_blocks = *sb->sv_sb_total_free_blocks - 1; + sb->sv_bh->b_dirt = 1; /* super-block has been modified */ + sb->s_dirt = 1; /* and needs time stamp */ + unlock_super(sb); + return block; +} + +unsigned long sysv_count_free_blocks(struct super_block * sb) +{ +#if 1 /* test */ + int count, old_count; + unsigned int block; + struct buffer_head * bh; + char * bh_data; + int i; + + /* this causes a lot of disk traffic ... */ + count = 0; + lock_super(sb); + if (*sb->sv_sb_flc_count > 0) { + for (i = *sb->sv_sb_flc_count ; /* i > 0 */ ; ) { + block = sb->sv_sb_flc_blocks[--i]; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (block == 0) /* block 0 terminates list */ + goto done; + count++; + if (i == 0) + break; + } + /* block = sb->sv_sb_flc_blocks[0], the last block continues the free list */ + while (1) { + unsigned short * flc_count; + unsigned long * flc_blocks; + + if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) { + printk("sysv_count_free_blocks: new block %d is not in data zone\n",block); + break; + } + if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) { + printk("sysv_count_free_blocks: cannot read free-list block\n"); + break; + } + switch (sb->sv_type) { + case FSTYPE_XENIX: + flc_count = &((struct xenix_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct xenix_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_SYSV4: + flc_count = &((struct sysv4_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct sysv4_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_SYSV2: + flc_count = &((struct sysv2_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct sysv2_freelist_chunk *) bh_data)->fl_free[0]; + break; + case FSTYPE_COH: + flc_count = &((struct coh_freelist_chunk *) bh_data)->fl_nfree; + flc_blocks = &((struct coh_freelist_chunk *) bh_data)->fl_free[0]; + break; + default: panic("sysv_count_free_blocks: invalid fs type\n"); + } + if (*flc_count > sb->sv_flc_size) { + printk("sysv_count_free_blocks: free-list block with >flc_size entries\n"); + brelse(bh); + break; + } + if (*flc_count == 0) { /* Applies only to Coherent FS */ + brelse(bh); + break; + } + for (i = *flc_count ; /* i > 0 */ ; ) { + block = flc_blocks[--i]; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (block == 0) /* block 0 terminates list */ + break; + count++; + if (i == 0) + break; + } + /* block = flc_blocks[0], the last block continues the free list */ + brelse(bh); + if (block == 0) /* Applies only to Xenix FS and SystemV FS */ + break; + } + done: ; + } + old_count = *sb->sv_sb_total_free_blocks; + if (sb->sv_convert) + old_count = from_coh_ulong(old_count); + if (count != old_count) { + printk("sysv_count_free_blocks: free block count was %d, correcting to %d\n",old_count,count); + if (!(sb->s_flags & MS_RDONLY)) { + *sb->sv_sb_total_free_blocks = (sb->sv_convert ? to_coh_ulong(count) : count); + sb->sv_bh->b_dirt = 1; /* super-block has been modified */ + sb->s_dirt = 1; /* and needs time stamp */ + } + } + unlock_super(sb); + return count; +#else + int count; + + count = *sb->sv_sb_total_free_blocks; + if (sb->sv_convert) + count = from_coh_ulong(count); + return count; +#endif +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/dir.c new file mode 100644 index 000000000..af6647e31 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/dir.c @@ -0,0 +1,110 @@ +/* + * linux/fs/sysv/dir.c + * + * minix/dir.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * coh/dir.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/dir.c + * Copyright (C) 1993 Bruno Haible + * + * SystemV/Coherent directory handling functions + */ + +#include + +#include +#include +#include +#include + +static int sysv_dir_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + return -EISDIR; +} + +static int sysv_readdir(struct inode *, struct file *, struct dirent *, int); + +static struct file_operations sysv_dir_operations = { + NULL, /* lseek - default */ + sysv_dir_read, /* read */ + NULL, /* write - bad */ + sysv_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* default fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations sysv_dir_inode_operations = { + &sysv_dir_operations, /* default directory file-ops */ + sysv_create, /* create */ + sysv_lookup, /* lookup */ + sysv_link, /* link */ + sysv_unlink, /* unlink */ + sysv_symlink, /* symlink */ + sysv_mkdir, /* mkdir */ + sysv_rmdir, /* rmdir */ + sysv_mknod, /* mknod */ + sysv_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + sysv_truncate, /* truncate */ + NULL /* permission */ +}; + +static int sysv_readdir(struct inode * inode, struct file * filp, + struct dirent * dirent, int count) +{ + struct super_block * sb; + unsigned int offset,i; + char c; + struct buffer_head * bh; + char* bh_data; + struct sysv_dir_entry * de; + + if (!inode || !(sb = inode->i_sb) || !S_ISDIR(inode->i_mode)) + return -EBADF; + if ((unsigned long)(filp->f_pos) % SYSV_DIRSIZE) + return -EBADF; + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & sb->sv_block_size_1; + bh = sysv_file_bread(inode, filp->f_pos >> sb->sv_block_size_bits, 0, &bh_data); + if (!bh) { + filp->f_pos += sb->sv_block_size - offset; + continue; + } + while (offset < sb->sv_block_size && filp->f_pos < inode->i_size) { + de = (struct sysv_dir_entry *) (offset + bh_data); + offset += SYSV_DIRSIZE; + filp->f_pos += SYSV_DIRSIZE; + if (de->inode) { + for (i = 0; i < SYSV_NAMELEN; i++) + if ((c = de->name[i]) != 0) + put_fs_byte(c,i+dirent->d_name); + else + break; + if (i) { + if (de->inode > inode->i_sb->sv_ninodes) + printk("sysv_readdir: Bad inode number on dev 0x%04x, ino %ld, offset 0x%04lx: %d is out of range\n", + inode->i_dev, inode->i_ino, filp->f_pos - SYSV_DIRSIZE, de->inode); + put_fs_long(de->inode,&dirent->d_ino); + put_fs_byte(0,i+dirent->d_name); + put_fs_word(i,&dirent->d_reclen); + brelse(bh); + return i; + } + } + } + brelse(bh); + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/file.c new file mode 100644 index 000000000..4c012fc6f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/file.c @@ -0,0 +1,313 @@ +/* + * linux/fs/sysv/file.c + * + * minix/file.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * coh/file.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/file.c + * Copyright (C) 1993 Bruno Haible + * + * SystemV/Coherent regular file handling primitives + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +#include +#include + +static int sysv_file_read(struct inode *, struct file *, char *, int); +static int sysv_file_write(struct inode *, struct file *, char *, int); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the coh filesystem. + */ +static struct file_operations sysv_file_operations = { + NULL, /* lseek - default */ + sysv_file_read, /* read */ + sysv_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + sysv_sync_file /* fsync */ +}; + +static struct file_operations sysv_file_operations_with_bmap = { + NULL, /* lseek - default */ + sysv_file_read, /* read */ + sysv_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + sysv_sync_file /* fsync */ +}; + +struct inode_operations sysv_file_inode_operations = { + &sysv_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + sysv_truncate, /* truncate */ + NULL /* permission */ +}; + +struct inode_operations sysv_file_inode_operations_with_bmap = { + &sysv_file_operations_with_bmap, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + sysv_bmap, /* bmap */ + sysv_truncate, /* truncate */ + NULL /* permission */ +}; + +struct sysv_buffer { + struct buffer_head * bh; + char * bh_data; +}; + +static int sysv_file_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + struct super_block * sb = inode->i_sb; + int read,left,chars; + unsigned int block; + int blocks, offset; + int bhrequest, bhreqi, uptodate; + struct sysv_buffer * bhb, * bhe; + struct buffer_head * bhreq[NBUF]; + struct sysv_buffer buflist[NBUF]; + unsigned int size; + + if (!inode) { + printk("sysv_file_read: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("sysv_file_read: mode = %07o\n",inode->i_mode); + return -EINVAL; + } + offset = filp->f_pos; + size = inode->i_size; + if (offset > size) + left = 0; + else + left = size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + block = offset >> sb->sv_block_size_bits; + offset &= sb->sv_block_size_1; + size = (size + sb->sv_block_size_1) >> sb->sv_block_size_bits; + blocks = (left + offset + sb->sv_block_size_1) >> sb->sv_block_size_bits; + bhb = bhe = buflist; + if (filp->f_reada) { + blocks += read_ahead[MAJOR(inode->i_dev)] >> (sb->sv_block_size_bits - 9); + if (block + blocks > size) + blocks = size - block; + } + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk. + + This routine is optimized to make maximum use of the various + buffers and caches. + + We must remove duplicates from the bhreq array as ll_rw_block + doesn't like duplicate requests (it hangs in wait_on_buffer...). + */ + + do { + bhrequest = 0; + uptodate = 1; + while (blocks) { + --blocks; + bhb->bh = sysv_getblk(inode, block++, 0, &bhb->bh_data); + if (bhb->bh && !bhb->bh->b_uptodate) { + uptodate = 0; + if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */ + for (bhreqi = 0; bhreqi < bhrequest; bhreqi++) + if (bhreq[bhreqi] == bhb->bh) + goto notreq; + bhreq[bhrequest++] = bhb->bh; + notreq: ; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing. */ + if (uptodate) + break; + if (bhb == bhe) + break; + } + + /* Now request them all */ + if (bhrequest) + ll_rw_block(READ, bhrequest, bhreq); + + do { /* Finish off all I/O that has actually completed */ + if (bhe->bh) { + wait_on_buffer(bhe->bh); + if (!bhe->bh->b_uptodate) { /* read error? */ + brelse(bhe->bh); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < sb->sv_block_size - offset) + chars = left; + else + chars = sb->sv_block_size - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (bhe->bh) { + memcpy_tofs(buf,offset+bhe->bh_data,chars); + brelse(bhe->bh); + buf += chars; + } else { + while (chars-- > 0) + put_fs_byte(0,buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!bhe->bh || !bhe->bh->b_lock)); + } while (left > 0); + +/* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse(bhe->bh); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + }; + if (!read) + return -EIO; + filp->f_reada = 1; + if (!IS_RDONLY(inode)) + inode->i_atime = CURRENT_TIME; + return read; +} + +static int sysv_file_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + struct super_block * sb = inode->i_sb; + off_t pos; + int written,c; + struct buffer_head * bh; + char * bh_data; + char * p; + + if (!inode) { + printk("sysv_file_write: inode = NULL\n"); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("sysv_file_write: mode = %07o\n",inode->i_mode); + return -EINVAL; + } +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + * But we need to protect against simultaneous truncate as we may end up + * writing our data into blocks that have meanwhile been incorporated into + * the freelist, thereby trashing the freelist. + */ + if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */ + coh_lock_inode(inode); + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written> sb->sv_block_size_bits, 1, &bh_data); + if (!bh) { + if (!written) + written = -ENOSPC; + break; + } + c = sb->sv_block_size - (pos & sb->sv_block_size_1); + if (c > count-written) + c = count-written; + if (c != BLOCK_SIZE && !bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + if (!written) + written = -EIO; + break; + } + } + /* now either c==BLOCK_SIZE or bh->b_uptodate */ + p = (pos & sb->sv_block_size_1) + bh_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs(p,buf,c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + if (sb->sv_block_size_ratio_bits > 0) /* block_size < BLOCK_SIZE ? */ + coh_unlock_inode(inode); + return written; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/fsync.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/fsync.c new file mode 100644 index 000000000..bd8fd4eea --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/fsync.c @@ -0,0 +1,200 @@ +/* + * linux/fs/sysv/fsync.c + * + * minix/fsync.c + * Copyright (C) 1991, 1992 Linus Torvalds + * Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * + * coh/fsync.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/fsync.c + * Copyright (C) 1993 Bruno Haible + * + * SystemV/Coherent fsync primitive + */ + +#include +#include + +#include +#include + + +/* return values: 0 means OK/done, 1 means redo, -1 means I/O error. */ + +/* Sync one block. The block number is + * from_coh_ulong(*blockp) if convert=1, *blockp if convert=0. + */ +static int sync_block (struct inode * inode, unsigned long * blockp, int convert, int wait) +{ + struct buffer_head * bh; + unsigned long tmp, block; + struct super_block * sb; + + block = tmp = *blockp; + if (convert) + block = from_coh_ulong(block); + if (!block) + return 0; + sb = inode->i_sb; + bh = get_hash_table(inode->i_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (!bh) + return 0; + if (*blockp != tmp) { + brelse (bh); + return 1; + } + if (wait && bh->b_req && !bh->b_uptodate) { + brelse(bh); + return -1; + } + if (wait || !bh->b_uptodate || !bh->b_dirt) { + brelse(bh); + return 0; + } + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + return 0; +} + +/* Sync one block full of indirect pointers and read it because we'll need it. */ +static int sync_iblock (struct inode * inode, unsigned long * iblockp, int convert, + struct buffer_head * *bh, char * *bh_data, int wait) +{ + int rc; + unsigned long tmp, block; + + *bh = NULL; + block = tmp = *iblockp; + if (convert) + block = from_coh_ulong(block); + if (!block) + return 0; + rc = sync_block (inode, iblockp, convert, wait); + if (rc) + return rc; + *bh = sysv_bread(inode->i_sb, inode->i_dev, block, bh_data); + if (tmp != *iblockp) { + brelse(*bh); + *bh = NULL; + return 1; + } + if (!*bh) + return -1; + return 0; +} + + +static int sync_direct(struct inode *inode, int wait) +{ + int i; + int rc, err = 0; + + for (i = 0; i < 10; i++) { + rc = sync_block (inode, inode->u.sysv_i.i_data + i, 0, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + return err; +} + +static int sync_indirect(struct inode *inode, unsigned long *iblockp, int convert, int wait) +{ + int i; + struct buffer_head * ind_bh; + char * ind_bh_data; + int rc, err = 0; + struct super_block * sb; + + rc = sync_iblock (inode, iblockp, convert, &ind_bh, &ind_bh_data, wait); + if (rc || !ind_bh) + return rc; + + sb = inode->i_sb; + for (i = 0; i < sb->sv_ind_per_block; i++) { + rc = sync_block (inode, + ((unsigned long *) ind_bh_data) + i, sb->sv_convert, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(ind_bh); + return err; +} + +static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int convert, + int wait) +{ + int i; + struct buffer_head * dind_bh; + char * dind_bh_data; + int rc, err = 0; + struct super_block * sb; + + rc = sync_iblock (inode, diblockp, convert, &dind_bh, &dind_bh_data, wait); + if (rc || !dind_bh) + return rc; + + sb = inode->i_sb; + for (i = 0; i < sb->sv_ind_per_block; i++) { + rc = sync_indirect (inode, + ((unsigned long *) dind_bh_data) + i, sb->sv_convert, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(dind_bh); + return err; +} + +static int sync_tindirect(struct inode *inode, unsigned long *tiblockp, int convert, + int wait) +{ + int i; + struct buffer_head * tind_bh; + char * tind_bh_data; + int rc, err = 0; + struct super_block * sb; + + rc = sync_iblock (inode, tiblockp, convert, &tind_bh, &tind_bh_data, wait); + if (rc || !tind_bh) + return rc; + + sb = inode->i_sb; + for (i = 0; i < sb->sv_ind_per_block; i++) { + rc = sync_dindirect (inode, + ((unsigned long *) tind_bh_data) + i, sb->sv_convert, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(tind_bh); + return err; +} + +int sysv_sync_file(struct inode * inode, struct file * file) +{ + int wait, err = 0; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + + for (wait=0; wait<=1; wait++) { + err |= sync_direct(inode, wait); + err |= sync_indirect(inode, inode->u.sysv_i.i_data+10, 0, wait); + err |= sync_dindirect(inode, inode->u.sysv_i.i_data+11, 0, wait); + err |= sync_tindirect(inode, inode->u.sysv_i.i_data+12, 0, wait); + } + err |= sysv_sync_inode (inode); + return (err < 0) ? -EIO : 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/ialloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/ialloc.c new file mode 100644 index 000000000..cfa56943d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/ialloc.c @@ -0,0 +1,204 @@ +/* + * linux/fs/sysv/ialloc.c + * + * minix/bitmap.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * ext/freelists.c + * Copyright (C) 1992 Remy Card (card@masi.ibp.fr) + * + * xenix/alloc.c + * Copyright (C) 1992 Doug Evans + * + * coh/alloc.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/ialloc.c + * Copyright (C) 1993 Bruno Haible + * + * This file contains code for allocating/freeing inodes. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* We don't trust the value of + sb->sv_sbd->s_tinode = *sb->sv_sb_total_free_inodes + but we nevertheless keep it up to date. */ + +/* An inode on disk is considered free if both i_mode == 0 and i_nlink == 0. */ + +void sysv_free_inode(struct inode * inode) +{ + struct super_block * sb; + unsigned int ino; + struct buffer_head * bh; + char * bh_data; + struct sysv_inode * raw_inode; + + if (!inode) + return; + if (!inode->i_dev) { + printk("sysv_free_inode: inode has no device\n"); + return; + } + if (inode->i_count != 1) { + printk("sysv_free_inode: inode has count=%d\n", inode->i_count); + return; + } + if (inode->i_nlink) { + printk("sysv_free_inode: inode has nlink=%d\n", inode->i_nlink); + return; + } + if (!(sb = inode->i_sb)) { + printk("sysv_free_inode: inode on nonexistent device\n"); + return; + } + ino = inode->i_ino; + if (ino <= SYSV_ROOT_INO || ino > sb->sv_ninodes) { + printk("sysv_free_inode: inode 0,1,2 or nonexistent inode\n"); + return; + } + if (!(bh = sysv_bread(sb, inode->i_dev, sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits), &bh_data))) { + printk("sysv_free_inode: unable to read inode block on device %d/%d\n",MAJOR(inode->i_dev),MINOR(inode->i_dev)); + clear_inode(inode); + return; + } + raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1); + lock_super(sb); + if (*sb->sv_sb_fic_count < sb->sv_fic_size) + sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)++] = ino; + (*sb->sv_sb_total_free_inodes)++; + sb->sv_bh->b_dirt = 1; /* super-block has been modified */ + sb->s_dirt = 1; /* and needs time stamp */ + memset(raw_inode, 0, sizeof(struct sysv_inode)); + bh->b_dirt = 1; + unlock_super(sb); + brelse(bh); + clear_inode(inode); +} + +struct inode * sysv_new_inode(const struct inode * dir) +{ + struct inode * inode; + struct super_block * sb; + struct buffer_head * bh; + char * bh_data; + struct sysv_inode * raw_inode; + int i,j,ino,block; + + if (!dir || !(inode = get_empty_inode())) + return NULL; + sb = dir->i_sb; + inode->i_sb = sb; + inode->i_flags = inode->i_sb->s_flags; + lock_super(sb); /* protect against task switches */ + if ((*sb->sv_sb_fic_count == 0) + || (sb->sv_sb_fic_inodes[(*sb->sv_sb_fic_count)-1] == 0) /* Applies only to SystemV2 FS */ + ) { + /* Rebuild cache of free inodes: */ + /* i : index into cache slot being filled */ + /* ino : inode we are trying */ + /* block : firstinodezone + (ino-1)/inodes_per_block */ + /* j : (ino-1)%inodes_per_block */ + /* bh : buffer for block */ + /* raw_inode : pointer to inode ino in the block */ + for (i = 0, ino = SYSV_ROOT_INO+1, block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; i < sb->sv_fic_size && block < sb->sv_firstdatazone ; block++, j = 0) { + if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) { + printk("sysv_new_inode: unable to read inode table\n"); + break; /* go with what we've got */ + /* FIXME: Perhaps try the next block? */ + } + raw_inode = (struct sysv_inode *) bh_data + j; + for (; j < sb->sv_inodes_per_block && i < sb->sv_fic_size; ino++, j++, raw_inode++) { + if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) + sb->sv_sb_fic_inodes[i++] = ino; + } + brelse(bh); + } + if (i == 0) { + iput(inode); + unlock_super(sb); + return NULL; /* no inodes available */ + } + *sb->sv_sb_fic_count = i; + } + /* Now *sb->sv_sb_fic_count > 0. */ + ino = sb->sv_sb_fic_inodes[--(*sb->sv_sb_fic_count)]; + sb->sv_bh->b_dirt = 1; /* super-block has been modified */ + sb->s_dirt = 1; /* and needs time stamp */ + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->euid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid; + inode->i_dirt = 1; + inode->i_ino = ino; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = NULL; + inode->i_blocks = inode->i_blksize = 0; + inode->u.sysv_i.i_lock = 0; inode->u.sysv_i.i_wait = NULL; + insert_inode_hash(inode); + /* Change directory entry: */ + inode->i_mode = 0; /* for sysv_write_inode() */ + inode->i_size = 0; /* ditto */ + sysv_write_inode(inode); /* ensure inode not allocated again */ + /* FIXME: caller may call this too. */ + inode->i_dirt = 1; /* cleared by sysv_write_inode() */ + /* That's it. */ + (*sb->sv_sb_total_free_inodes)--; + sb->sv_bh->b_dirt = 1; /* super-block has been modified again */ + sb->s_dirt = 1; /* and needs time stamp again */ + unlock_super(sb); + return inode; +} + +unsigned long sysv_count_free_inodes(struct super_block * sb) +{ +#if 1 /* test */ + struct buffer_head * bh; + char * bh_data; + struct sysv_inode * raw_inode; + int j,block,count; + + /* this causes a lot of disk traffic ... */ + count = 0; + lock_super(sb); + /* i : index into cache slot being filled */ + /* ino : inode we are trying */ + /* block : firstinodezone + (ino-1)/inodes_per_block */ + /* j : (ino-1)%inodes_per_block */ + /* bh : buffer for block */ + /* raw_inode : pointer to inode ino in the block */ + for (block = sb->sv_firstinodezone, j = SYSV_ROOT_INO ; block < sb->sv_firstdatazone ; block++, j = 0) { + if (!(bh = sysv_bread(sb, sb->s_dev, block, &bh_data))) { + printk("sysv_count_free_inodes: unable to read inode table\n"); + break; /* go with what we've got */ + /* FIXME: Perhaps try the next block? */ + } + raw_inode = (struct sysv_inode *) bh_data + j; + for (; j < sb->sv_inodes_per_block ; j++, raw_inode++) + if (raw_inode->i_mode == 0 && raw_inode->i_nlink == 0) + count++; + brelse(bh); + } + if (count != *sb->sv_sb_total_free_inodes) { + printk("sysv_count_free_inodes: free inode count was %d, correcting to %d\n",(short)(*sb->sv_sb_total_free_inodes),count); + if (!(sb->s_flags & MS_RDONLY)) { + *sb->sv_sb_total_free_inodes = count; + sb->sv_bh->b_dirt = 1; /* super-block has been modified */ + sb->s_dirt = 1; /* and needs time stamp */ + } + } + unlock_super(sb); + return count; +#else + return *sb->sv_sb_total_free_inodes; +#endif +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/inode.c new file mode 100644 index 000000000..d9eb8482d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/inode.c @@ -0,0 +1,808 @@ +/* + * linux/fs/sysv/inode.c + * + * minix/inode.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * xenix/inode.c + * Copyright (C) 1992 Doug Evans + * + * coh/inode.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/inode.c + * Copyright (C) 1993 Paul B. Monday + * + * sysv/inode.c + * Copyright (C) 1993 Bruno Haible + * + * This file contains code for allocating/freeing inodes and for read/writing + * the superblock. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +void _coh_wait_on_inode (struct inode * inode) +{ + struct wait_queue wait = { current, NULL }; + + add_wait_queue(&inode->u.sysv_i.i_wait, &wait); +repeat: + current->state = TASK_UNINTERRUPTIBLE; + if (inode->u.sysv_i.i_lock) { + schedule(); + goto repeat; + } + remove_wait_queue(&inode->u.sysv_i.i_wait, &wait); + current->state = TASK_RUNNING; +} + +void sysv_put_inode(struct inode *inode) +{ + if (inode->i_nlink) + return; + inode->i_size = 0; + sysv_truncate(inode); + sysv_free_inode(inode); +} + + +static struct super_operations sysv_sops = { + sysv_read_inode, + sysv_notify_change, + sysv_write_inode, + sysv_put_inode, + sysv_put_super, + sysv_write_super, + sysv_statfs, + NULL +}; + +/* The following functions try to recognize specific filesystems. + * We recognize: + * - Xenix FS by its magic number. + * - SystemV FS by its magic number. + * - Coherent FS by its funny fname/fpack field. + * We discriminate among SystemV4 and SystemV2 FS by the assumption that + * the time stamp is not < 01-01-1980. + */ + +static void detected_bs512 (struct super_block *sb) +{ + sb->sv_block_size = 512; + sb->sv_block_size_1 = 512-1; + sb->sv_block_size_bits = 9; + sb->sv_block_size_ratio = 2; + sb->sv_block_size_ratio_1 = 2-1; + sb->sv_block_size_ratio_bits = 1; + sb->sv_inodes_per_block = 512/64; + sb->sv_inodes_per_block_1 = 512/64-1; + sb->sv_inodes_per_block_bits = 9-6; + sb->sv_toobig_block = 10 + + (sb->sv_ind_per_block = 512/4) + + (sb->sv_ind_per_block_2 = (512/4)*(512/4)) + + (sb->sv_ind_per_block_3 = (512/4)*(512/4)*(512/4)); + sb->sv_ind_per_block_1 = 512/4-1; + sb->sv_ind_per_block_2_1 = (512/4)*(512/4)-1; + sb->sv_ind_per_block_2_bits = 2 * + (sb->sv_ind_per_block_bits = 9-2); +} + +static void detected_bs1024 (struct super_block *sb) +{ + sb->sv_block_size = 1024; + sb->sv_block_size_1 = 1024-1; + sb->sv_block_size_bits = 10; + sb->sv_block_size_ratio = 1; + sb->sv_block_size_ratio_1 = 1-1; + sb->sv_block_size_ratio_bits = 0; + sb->sv_inodes_per_block = 1024/64; + sb->sv_inodes_per_block_1 = 1024/64-1; + sb->sv_inodes_per_block_bits = 10-6; + sb->sv_toobig_block = 10 + + (sb->sv_ind_per_block = 1024/4) + + (sb->sv_ind_per_block_2 = (1024/4)*(1024/4)) + + (sb->sv_ind_per_block_3 = (1024/4)*(1024/4)*(1024/4)); + sb->sv_ind_per_block_1 = 1024/4-1; + sb->sv_ind_per_block_2_1 = (1024/4)*(1024/4)-1; + sb->sv_ind_per_block_2_bits = 2 * + (sb->sv_ind_per_block_bits = 10-2); +} + +static const char* detect_xenix (struct super_block *sb, struct buffer_head *bh) +{ + struct xenix_super_block * sbd; + + sbd = (struct xenix_super_block *) bh->b_data; + if (sbd->s_magic != 0x2b5544) + return NULL; + sb->sv_type = FSTYPE_XENIX; + sb->sv_convert = 0; + sb->sv_kludge_symlinks = 1; + sb->sv_truncate = 1; + sb->sv_link_max = XENIX_LINK_MAX; + sb->sv_fic_size = XENIX_NICINOD; + sb->sv_flc_size = XENIX_NICFREE; + sb->sv_bh = bh; + sb->sv_sbd = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_sb_flc_count = &sbd->s_nfree; + sb->sv_sb_flc_blocks = &sbd->s_free[0]; + sb->sv_sb_total_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_block_base = 0; + sb->sv_firstinodezone = 2; + sb->sv_firstdatazone = sbd->s_isize; + sb->sv_nzones = sbd->s_fsize; + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + switch (sbd->s_type) { + case 1: detected_bs512(sb); break; + case 2: detected_bs1024(sb); break; + default: return NULL; + } + return "Xenix"; +} + +static const char* detect_sysv4 (struct super_block *sb, struct buffer_head *bh) +{ + struct sysv4_super_block * sbd; + + sbd = (struct sysv4_super_block *) (bh->b_data + BLOCK_SIZE/2); + if (sbd->s_magic != 0xfd187e20) + return NULL; + if (sbd->s_time < 315532800) /* this is likely to happen on SystemV2 FS */ + return NULL; + sb->sv_type = FSTYPE_SYSV4; + sb->sv_convert = 0; + sb->sv_kludge_symlinks = 0; /* ?? */ + sb->sv_truncate = 1; + sb->sv_link_max = SYSV_LINK_MAX; + sb->sv_fic_size = SYSV_NICINOD; + sb->sv_flc_size = SYSV_NICFREE; + sb->sv_bh = bh; + sb->sv_sbd = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_sb_flc_count = &sbd->s_nfree; + sb->sv_sb_flc_blocks = &sbd->s_free[0]; + sb->sv_sb_total_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_block_base = 0; + sb->sv_firstinodezone = 2; + sb->sv_firstdatazone = sbd->s_isize; + sb->sv_nzones = sbd->s_fsize; + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + switch (sbd->s_type) { + case 1: detected_bs512(sb); break; + case 2: detected_bs1024(sb); break; + default: return NULL; + } + return "SystemV"; +} + +static const char* detect_sysv2 (struct super_block *sb, struct buffer_head *bh) +{ + struct sysv2_super_block * sbd; + + sbd = (struct sysv2_super_block *) (bh->b_data + BLOCK_SIZE/2); + if (sbd->s_magic != 0xfd187e20) + return NULL; + if (sbd->s_time < 315532800) /* this is likely to happen on SystemV4 FS */ + return NULL; + sb->sv_type = FSTYPE_SYSV2; + sb->sv_convert = 0; + sb->sv_kludge_symlinks = 0; /* ?? */ + sb->sv_truncate = 1; + sb->sv_link_max = SYSV_LINK_MAX; + sb->sv_fic_size = SYSV_NICINOD; + sb->sv_flc_size = SYSV_NICFREE; + sb->sv_bh = bh; + sb->sv_sbd = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_sb_flc_count = &sbd->s_nfree; + sb->sv_sb_flc_blocks = &sbd->s_free[0]; + sb->sv_sb_total_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_block_base = 0; + sb->sv_firstinodezone = 2; + sb->sv_firstdatazone = sbd->s_isize; + sb->sv_nzones = sbd->s_fsize; + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + switch (sbd->s_type) { + case 1: detected_bs512(sb); break; + case 2: detected_bs1024(sb); break; + default: return NULL; + } + return "SystemV Release 2"; +} + +static const char* detect_coherent (struct super_block *sb, struct buffer_head *bh) +{ + struct coh_super_block * sbd; + + sbd = (struct coh_super_block *) (bh->b_data + BLOCK_SIZE/2); + if ((memcmp(sbd->s_fname,"noname",6) && memcmp(sbd->s_fname,"xxxxx ",6)) + || (memcmp(sbd->s_fpack,"nopack",6) && memcmp(sbd->s_fpack,"xxxxx\n",6))) + return NULL; + sb->sv_type = FSTYPE_COH; + sb->sv_convert = 1; + sb->sv_kludge_symlinks = 1; + sb->sv_truncate = 1; + sb->sv_link_max = COH_LINK_MAX; + sb->sv_fic_size = COH_NICINOD; + sb->sv_flc_size = COH_NICFREE; + sb->sv_bh = bh; + sb->sv_sbd = (char *) sbd; + sb->sv_sb_fic_count = &sbd->s_ninode; + sb->sv_sb_fic_inodes = &sbd->s_inode[0]; + sb->sv_sb_total_free_inodes = &sbd->s_tinode; + sb->sv_sb_flc_count = &sbd->s_nfree; + sb->sv_sb_flc_blocks = &sbd->s_free[0]; + sb->sv_sb_total_free_blocks = &sbd->s_tfree; + sb->sv_sb_time = &sbd->s_time; + sb->sv_block_base = 0; + sb->sv_firstinodezone = 2; + sb->sv_firstdatazone = sbd->s_isize; + sb->sv_nzones = from_coh_ulong(sbd->s_fsize); + sb->sv_ndatazones = sb->sv_nzones - sb->sv_firstdatazone; + detected_bs512(sb); + return "Coherent"; +} + +struct super_block *sysv_read_super(struct super_block *sb,void *data, + int silent) +{ + struct buffer_head *bh; + const char *found; + int dev = sb->s_dev; + + if (1024 != sizeof (struct xenix_super_block)) + panic("Xenix FS: bad super-block size"); + if ((512 != sizeof (struct sysv4_super_block)) + || (512 != sizeof (struct sysv2_super_block))) + panic("SystemV FS: bad super-block size"); + if (500 != sizeof (struct coh_super_block)) + panic("Coherent FS: bad super-block size"); + if (64 != sizeof (struct sysv_inode)) + panic("sysv fs: bad i-node size"); + lock_super(sb); + sb->s_blocksize = BLOCK_SIZE; /* anything else not supported by the block device drivers */ + sb->s_blocksize_bits = BLOCK_SIZE_BITS; + + /* Try to read Xenix superblock */ + if ((bh = bread(dev, 1, BLOCK_SIZE)) != NULL) { + if ((found = detect_xenix(sb,bh)) != NULL) + goto ok; + brelse(bh); + } + if ((bh = bread(dev, 0, BLOCK_SIZE)) != NULL) { + /* Try to recognize SystemV superblock */ + if ((found = detect_sysv4(sb,bh)) != NULL) + goto ok; + if ((found = detect_sysv2(sb,bh)) != NULL) + goto ok; + /* Try to recognize Coherent superblock */ + if ((found = detect_coherent(sb,bh)) != NULL) + goto ok; + brelse(bh); + } + /* Try to recognize SystemV2 superblock */ + /* Offset by 1 track, i.e. most probably 9, 15, or 18 kilobytes. */ + { static int offsets[] = { 9, 15, 18, }; + int i; + for (i = 0; i < sizeof(offsets)/sizeof(offsets[0]); i++) + if ((bh = bread(dev, offsets[i], BLOCK_SIZE)) != NULL) { + /* Try to recognize SystemV superblock */ + if ((found = detect_sysv2(sb,bh)) != NULL) { + sb->sv_block_base = offsets[i]; + goto ok; + } + brelse(bh); + } + } + sb->s_dev=0; + unlock_super(sb); + if (!silent) + printk("VFS: unable to read Xenix/SystemV/Coherent superblock on device %d/%d\n",MAJOR(dev),MINOR(dev)); + return NULL; + + ok: + sb->sv_ninodes = (sb->sv_firstdatazone - sb->sv_firstinodezone) << sb->sv_inodes_per_block_bits; + if (!silent) + printk("VFS: Found a %s FS (block size = %d) on device %d/%d\n",found,sb->sv_block_size,MAJOR(dev),MINOR(dev)); + sb->s_magic = SYSV_MAGIC_BASE + sb->sv_type; + /* set up enough so that it can read an inode */ + sb->s_dev = dev; + sb->s_op = &sysv_sops; + sb->s_mounted = iget(sb,SYSV_ROOT_INO); + unlock_super(sb); + if (!sb->s_mounted) { + brelse(bh); + sb->s_dev = 0; + printk("SysV FS: get root inode failed\n"); + return NULL; + } + sb->s_dirt = 1; /* brelse(bh); occurs when the disk is unmounted. */ + return sb; +} + +/* This is only called on sync() and umount(), when s_dirt=1. */ +void sysv_write_super (struct super_block *sb) +{ + lock_super(sb); + if (sb->sv_bh->b_dirt) { + /* If we are going to write out the super block, + then attach current time stamp. */ + unsigned long time = CURRENT_TIME; + if (sb->sv_convert) + time = to_coh_ulong(time); + *sb->sv_sb_time = time; + } + sb->s_dirt = 0; + unlock_super(sb); +} + +void sysv_put_super(struct super_block *sb) +{ + /* we can assume sysv_write_super() has already been called */ + lock_super(sb); + brelse(sb->sv_bh); + sb->s_dev = 0; + unlock_super(sb); +} + +void sysv_statfs(struct super_block *sb, struct statfs *buf) +{ + long tmp; + + put_fs_long(sb->s_magic, &buf->f_type); /* type of filesystem */ + put_fs_long(sb->sv_block_size, &buf->f_bsize); /* block size */ + put_fs_long(sb->sv_ndatazones, &buf->f_blocks); /* total data blocks in file system */ + tmp = sysv_count_free_blocks(sb); + put_fs_long(tmp, &buf->f_bfree); /* free blocks in fs */ + put_fs_long(tmp, &buf->f_bavail); /* free blocks available to non-superuser */ + put_fs_long(sb->sv_ninodes, &buf->f_files); /* total file nodes in file system */ + put_fs_long(sysv_count_free_inodes(sb), &buf->f_ffree); /* free file nodes in fs */ + put_fs_long(SYSV_NAMELEN, &buf->f_namelen); + /* Don't know what value to put in buf->f_fsid */ /* file system id */ +} + + +/* bmap support for running executables and shared libraries. + Used only if block_size = BLOCK_SIZE. */ + +#define IND_PER_BLOCK (BLOCK_SIZE / sizeof(sysv_zone_t)) + +static inline int inode_bmap(struct super_block * sb, struct inode * inode, int nr) +{ + int tmp = inode->u.sysv_i.i_data[nr]; + if (!tmp) + return 0; + return tmp + sb->sv_block_base; +} + +static int block_bmap(struct super_block * sb, struct buffer_head * bh, int nr, int convert) +{ + int tmp; + + if (!bh) + return 0; + tmp = ((sysv_zone_t *) bh->b_data) [nr]; + if (convert) + tmp = from_coh_ulong(tmp); + brelse(bh); + if (!tmp) + return 0; + return tmp + sb->sv_block_base; +} + +int sysv_bmap(struct inode * inode,int block_nr) +{ + unsigned int block = block_nr; + struct super_block * sb = inode->i_sb; + int convert; + int i; + struct buffer_head * bh; + + if (block < 10) + return inode_bmap(sb,inode,block); + block -= 10; + convert = sb->sv_convert; + if (block < IND_PER_BLOCK) { + i = inode_bmap(sb,inode,10); + if (!i) + return 0; + bh = bread(inode->i_dev,i,BLOCK_SIZE); + return block_bmap(sb,bh,block,convert); + } + block -= IND_PER_BLOCK; + if (block < IND_PER_BLOCK*IND_PER_BLOCK) { + i = inode_bmap(sb,inode,11); + if (!i) + return 0; + bh = bread(inode->i_dev,i,BLOCK_SIZE); + i = block_bmap(sb,bh,block/IND_PER_BLOCK,convert); + if (!i) + return 0; + bh = bread(inode->i_dev,i,BLOCK_SIZE); + return block_bmap(sb,bh,block%IND_PER_BLOCK,convert); + } + block -= IND_PER_BLOCK*IND_PER_BLOCK; + if (block < IND_PER_BLOCK*IND_PER_BLOCK*IND_PER_BLOCK) { + i = inode_bmap(sb,inode,12); + if (!i) + return 0; + bh = bread(inode->i_dev,i,BLOCK_SIZE); + i = block_bmap(sb,bh,block/(IND_PER_BLOCK*IND_PER_BLOCK),convert); + if (!i) + return 0; + bh = bread(inode->i_dev,i,BLOCK_SIZE); + i = block_bmap(sb,bh,(block/IND_PER_BLOCK)%IND_PER_BLOCK,convert); + if (!i) + return 0; + bh = bread(inode->i_dev,i,BLOCK_SIZE); + return block_bmap(sb,bh,block%IND_PER_BLOCK,convert); + } + if ((int)block<0) { + printk("sysv_bmap: block<0"); + return 0; + } + printk("sysv_bmap: block>big"); + return 0; +} + +/* End of bmap support. */ + + +/* Access selected blocks of regular files (or directories) */ + +static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create, char * *start) +{ + struct super_block *sb; + unsigned long tmp; + unsigned long *p; + struct buffer_head * result; + + sb = inode->i_sb; + p = inode->u.sysv_i.i_data + nr; +repeat: + tmp = *p; + if (tmp) { + result = getblk(inode->i_dev, (tmp >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (tmp == *p) { + *start = result->b_data + ((tmp & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + return result; + } + brelse(result); + goto repeat; + } + if (!create) + return NULL; + tmp = sysv_new_block(sb); + if (!tmp) + return NULL; + result = getblk(inode->i_dev, (tmp >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (*p) { + sysv_free_block(sb,tmp); + brelse(result); + goto repeat; + } + *p = tmp; + inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + *start = result->b_data + ((tmp & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + return result; +} + +static struct buffer_head * block_getblk(struct inode * inode, + struct buffer_head * bh, int nr, int create, char * *start) +{ + struct super_block *sb; + unsigned long tmp, block; + sysv_zone_t *p; + struct buffer_head * result; + + if (!bh) + return NULL; + if (!bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + return NULL; + } + } + sb = inode->i_sb; + p = nr + (sysv_zone_t *) *start; +repeat: + block = tmp = *p; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (tmp) { + result = getblk(bh->b_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (tmp == *p) { + brelse(bh); + *start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + return result; + } + brelse(result); + goto repeat; + } + if (!create) { + brelse(bh); + return NULL; + } + block = sysv_new_block(sb); + if (!block) { + brelse(bh); + return NULL; + } + result = getblk(bh->b_dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE); + if (*p) { + sysv_free_block(sb,block); + brelse(result); + goto repeat; + } + *p = (sb->sv_convert ? to_coh_ulong(block) : block); + bh->b_dirt = 1; + brelse(bh); + *start = result->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + return result; +} + +struct buffer_head * sysv_getblk(struct inode * inode, unsigned int block, + int create, char * *start) +{ + struct super_block * sb = inode->i_sb; + struct buffer_head * bh; + + if (block < 10) + return inode_getblk(inode,block,create,start); + block -= 10; + if (block < sb->sv_ind_per_block) { + bh = inode_getblk(inode,10,create,start); + return block_getblk(inode, bh, block, create, start); + } + block -= sb->sv_ind_per_block; + if (block < sb->sv_ind_per_block_2) { + bh = inode_getblk(inode,11,create,start); + bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_bits, create, start); + return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create, start); + } + block -= sb->sv_ind_per_block_2; + if (block < sb->sv_ind_per_block_3) { + bh = inode_getblk(inode,12,create,start); + bh = block_getblk(inode, bh, block >> sb->sv_ind_per_block_2_bits, create, start); + bh = block_getblk(inode, bh, (block >> sb->sv_ind_per_block_bits) & sb->sv_ind_per_block_1, create, start); + return block_getblk(inode, bh, block & sb->sv_ind_per_block_1, create, start); + } + if ((int)block<0) { + printk("sysv_getblk: block<0"); + return NULL; + } + printk("sysv_getblk: block>big"); + return NULL; +} + +struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create, char * *start) +{ + struct buffer_head * bh; + + bh = sysv_getblk(inode,block,create,start); + if (!bh || bh->b_uptodate) + return bh; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + + +static inline unsigned long read3byte (char * p) +{ + return (unsigned long)(*(unsigned short *)p) + | (unsigned long)(*(unsigned char *)(p+2)) << 16; +} + +static inline void write3byte (char * p, unsigned long val) +{ + *(unsigned short *)p = (unsigned short) val; + *(unsigned char *)(p+2) = val >> 16; +} + +static inline unsigned long coh_read3byte (char * p) +{ + return (unsigned long)(*(unsigned char *)p) << 16 + | (unsigned long)(*(unsigned short *)(p+1)); +} + +static inline void coh_write3byte (char * p, unsigned long val) +{ + *(unsigned char *)p = val >> 16; + *(unsigned short *)(p+1) = (unsigned short) val; +} + +void sysv_read_inode(struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + struct buffer_head * bh; + char * bh_data; + struct sysv_inode * raw_inode; + unsigned int block, ino; + umode_t mode; + + ino = inode->i_ino; + inode->i_op = NULL; + inode->i_mode = 0; + if (!ino || ino > sb->sv_ninodes) { + printk("Bad inode number on dev 0x%04x: %d is out of range\n", + inode->i_dev, ino); + return; + } + block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits); + if (!(bh=sysv_bread(sb,inode->i_dev,block,&bh_data))) { + printk("Major problem: unable to read inode from dev 0x%04x\n", + inode->i_dev); + return; + } + raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1); + mode = raw_inode->i_mode; + if (sb->sv_kludge_symlinks) + mode = from_coh_imode(mode); + /* SystemV FS: kludge permissions if ino==SYSV_ROOT_INO ?? */ + inode->i_mode = mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_nlink; + if (sb->sv_convert) { + inode->i_size = from_coh_ulong(raw_inode->i_size); + inode->i_atime = from_coh_ulong(raw_inode->i_atime); + inode->i_mtime = from_coh_ulong(raw_inode->i_mtime); + inode->i_ctime = from_coh_ulong(raw_inode->i_ctime); + } else { + inode->i_size = raw_inode->i_size; + inode->i_atime = raw_inode->i_atime; + inode->i_mtime = raw_inode->i_mtime; + inode->i_ctime = raw_inode->i_ctime; + } + inode->i_blocks = inode->i_blksize = 0; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + inode->i_rdev = raw_inode->i_a.i_rdev; + else + if (sb->sv_convert) + for (block = 0; block < 10+1+1+1; block++) + inode->u.sysv_i.i_data[block] = + coh_read3byte(&raw_inode->i_a.i_addb[3*block]); + else + for (block = 0; block < 10+1+1+1; block++) + inode->u.sysv_i.i_data[block] = + read3byte(&raw_inode->i_a.i_addb[3*block]); + brelse(bh); + if (S_ISREG(inode->i_mode)) + if (sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */ + inode->i_op = &sysv_file_inode_operations_with_bmap; + else + inode->i_op = &sysv_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &sysv_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &sysv_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); +} + +/* To avoid inconsistencies between inodes in memory and inodes on disk. */ +extern int sysv_notify_change(int flags, struct inode *inode) +{ + if (flags & NOTIFY_MODE) + if (inode->i_sb->sv_kludge_symlinks) + if (inode->i_mode == COH_KLUDGE_SYMLINK_MODE) { + inode->i_mode = COH_KLUDGE_NOT_SYMLINK; + inode->i_dirt = 1; + } + return 0; +} + +static struct buffer_head * sysv_update_inode(struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + struct buffer_head * bh; + char * bh_data; + struct sysv_inode * raw_inode; + unsigned int ino, block; + umode_t mode; + + ino = inode->i_ino; + if (!ino || ino > sb->sv_ninodes) { + printk("Bad inode number on dev 0x%04x: %d is out of range\n", + inode->i_dev, ino); + inode->i_dirt = 0; + return 0; + } + block = sb->sv_firstinodezone + ((ino-1) >> sb->sv_inodes_per_block_bits); + if (!(bh = sysv_bread(sb,inode->i_dev,block,&bh_data))) { + printk("unable to read i-node block\n"); + inode->i_dirt = 0; + return 0; + } + raw_inode = (struct sysv_inode *) bh_data + ((ino-1) & sb->sv_inodes_per_block_1); + mode = inode->i_mode; + if (sb->sv_kludge_symlinks) + mode = to_coh_imode(mode); + raw_inode->i_mode = mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_nlink = inode->i_nlink; + if (sb->sv_convert) { + raw_inode->i_size = to_coh_ulong(inode->i_size); + raw_inode->i_atime = to_coh_ulong(inode->i_atime); + raw_inode->i_mtime = to_coh_ulong(inode->i_mtime); + raw_inode->i_ctime = to_coh_ulong(inode->i_ctime); + } else { + raw_inode->i_size = inode->i_size; + raw_inode->i_atime = inode->i_atime; + raw_inode->i_mtime = inode->i_mtime; + raw_inode->i_ctime = inode->i_ctime; + } + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_a.i_rdev = inode->i_rdev; /* write 2 or 3 bytes ?? */ + else + if (sb->sv_convert) + for (block = 0; block < 10+1+1+1; block++) + coh_write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]); + else + for (block = 0; block < 10+1+1+1; block++) + write3byte(&raw_inode->i_a.i_addb[3*block],inode->u.sysv_i.i_data[block]); + inode->i_dirt=0; + bh->b_dirt=1; + return bh; +} + +void sysv_write_inode(struct inode * inode) +{ + struct buffer_head *bh; + bh = sysv_update_inode(inode); + brelse(bh); +} + +int sysv_sync_inode(struct inode * inode) +{ + int err = 0; + struct buffer_head *bh; + + bh = sysv_update_inode(inode); + if (bh && bh->b_dirt) { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + if (bh->b_req && !bh->b_uptodate) + { + printk ("IO error syncing sysv inode [%04x:%08lx]\n", + inode->i_dev, inode->i_ino); + err = -1; + } + } + else if (!bh) + err = -1; + brelse (bh); + return err; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/namei.c new file mode 100644 index 000000000..e0e17cdde --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/namei.c @@ -0,0 +1,836 @@ +/* + * linux/fs/sysv/namei.c + * + * minix/namei.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * coh/namei.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/namei.c + * Copyright (C) 1993 Bruno Haible + */ + +#include +#include +#include +#include +#include +#include +#include + +/* compare strings: name[0..len-1] (not zero-terminated) and + * buffer[0..] (filled with zeroes up to buffer[0..maxlen-1]) + */ +static inline int namecompare(int len, int maxlen, + const char * name, const char * buffer) +{ + if (len >= maxlen || !buffer[len]) { + unsigned char same; + __asm__("repe ; cmpsb ; setz %0" + :"=q" (same) + :"S" ((long) name),"D" ((long) buffer),"c" (len) + :"cx","di","si"); + return same; + } + /* if (leninode || len > SYSV_NAMELEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (de->name[0]=='.') && (de->name[1]=='\0')) + return 1; + return namecompare(len,SYSV_NAMELEN,name,de->name); +} + +/* + * sysv_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * sysv_find_entry(struct inode * dir, + const char * name, int namelen, struct sysv_dir_entry ** res_dir) +{ + struct super_block * sb; + unsigned long pos, block, offset; /* pos = block * block_size + offset */ + struct buffer_head * bh; + char * bh_data; + + *res_dir = NULL; + if (!dir) + return NULL; + sb = dir->i_sb; + if (namelen > SYSV_NAMELEN) + if (sb->sv_truncate) + namelen = SYSV_NAMELEN; + else + return NULL; + bh = NULL; + pos = block = offset = 0; + while (pos < dir->i_size) { + if (!bh) { + bh = sysv_file_bread(dir,block,0,&bh_data); + if (!bh) { + /* offset = 0; */ block++; + pos += sb->sv_block_size; + continue; + } + } + if (sysv_match(namelen, name, + *res_dir = (struct sysv_dir_entry *) (bh_data + offset) )) + return bh; + pos += SYSV_DIRSIZE; + offset += SYSV_DIRSIZE; + if (offset < sb->sv_block_size) + continue; + brelse(bh); + bh = NULL; + offset = 0; block++; + } + brelse(bh); + *res_dir = NULL; + return NULL; +} + +int sysv_lookup(struct inode * dir,const char * name, int len, + struct inode ** result) +{ + int ino; + struct sysv_dir_entry * de; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!(bh = sysv_find_entry(dir,name,len,&de))) { + iput(dir); + return -ENOENT; + } + ino = de->inode; + brelse(bh); + if (!(*result = iget(dir->i_sb,ino))) { + iput(dir); + return -EACCES; + } + iput(dir); + return 0; +} + +/* + * sysv_add_entry() + * + * adds a file entry to the specified directory, returning a possible + * error value if it fails. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static int sysv_add_entry(struct inode * dir, + const char * name, int namelen, + struct buffer_head ** res_buf, + struct sysv_dir_entry ** res_dir) +{ + struct super_block * sb; + int i; + unsigned long pos, block, offset; /* pos = block * block_size + offset */ + struct buffer_head * bh; + char * bh_data; + struct sysv_dir_entry * de; + + *res_buf = NULL; + *res_dir = NULL; + if (!dir) + return -ENOENT; + sb = dir->i_sb; + if (namelen > SYSV_NAMELEN) + if (sb->sv_truncate) + namelen = SYSV_NAMELEN; + else + return -ENAMETOOLONG; + if (!namelen) + return -ENOENT; + bh = NULL; + pos = block = offset = 0; + while (1) { + if (!bh) { + bh = sysv_file_bread(dir,block,1,&bh_data); + if (!bh) + return -ENOSPC; + } + de = (struct sysv_dir_entry *) (bh_data + offset); + pos += SYSV_DIRSIZE; + offset += SYSV_DIRSIZE; + if (pos > dir->i_size) { + de->inode = 0; + dir->i_size = pos; + dir->i_dirt = 1; + } + if (de->inode) { + if (namecompare(namelen, SYSV_NAMELEN, name, de->name)) { + brelse(bh); + return -EEXIST; + } + } else { + dir->i_mtime = dir->i_ctime = CURRENT_TIME; + for (i = 0; i < SYSV_NAMELEN ; i++) + de->name[i] = (i < namelen) ? name[i] : 0; + bh->b_dirt = 1; + *res_dir = de; + break; + } + if (offset < sb->sv_block_size) + continue; + brelse(bh); + bh = NULL; + offset = 0; block++; + } + *res_buf = bh; + return 0; +} + +int sysv_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result) +{ + int error; + struct inode * inode; + struct buffer_head * bh; + struct sysv_dir_entry * de; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = sysv_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + if (inode->i_sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */ + inode->i_op = &sysv_file_inode_operations_with_bmap; + else + inode->i_op = &sysv_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + error = sysv_add_entry(dir,name,len, &bh ,&de); + if (error) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return error; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *result = inode; + return 0; +} + +int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev) +{ + int error; + struct inode * inode; + struct buffer_head * bh; + struct sysv_dir_entry * de; + + if (!dir) + return -ENOENT; + bh = sysv_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = sysv_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + if (inode->i_sb->sv_block_size_ratio_bits == 0) /* block_size == BLOCK_SIZE ? */ + inode->i_op = &sysv_file_inode_operations_with_bmap; + else + inode->i_op = &sysv_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &sysv_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &sysv_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; + inode->i_dirt = 1; + error = sysv_add_entry(dir, name, len, &bh, &de); + if (error) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return error; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int sysv_mkdir(struct inode * dir, const char * name, int len, int mode) +{ + int error; + struct inode * inode; + struct buffer_head * bh, *dir_block; + char * bh_data; + struct sysv_dir_entry * de; + + if (!dir) { + iput(dir); + return -EINVAL; + } + bh = sysv_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + if (dir->i_nlink >= dir->i_sb->sv_link_max) { + iput(dir); + return -EMLINK; + } + inode = sysv_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &sysv_dir_inode_operations; + inode->i_size = 2 * SYSV_DIRSIZE; + dir_block = sysv_file_bread(inode,0,1,&bh_data); + if (!dir_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + de = (struct sysv_dir_entry *) (bh_data + 0*SYSV_DIRSIZE); + de->inode = inode->i_ino; + strcpy(de->name,"."); /* rest of de->name is zero, see sysv_new_block */ + de = (struct sysv_dir_entry *) (bh_data + 1*SYSV_DIRSIZE); + de->inode = dir->i_ino; + strcpy(de->name,".."); /* rest of de->name is zero, see sysv_new_block */ + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = S_IFDIR | (mode & 0777 & ~current->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + inode->i_dirt = 1; + error = sysv_add_entry(dir, name, len, &bh, &de); + if (error) { + iput(dir); + inode->i_nlink=0; + iput(inode); + return error; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + dir->i_nlink++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct inode * inode) +{ + struct super_block * sb; + unsigned long pos, block, offset; /* pos = block * block_size + offset */ + struct buffer_head * bh; + char * bh_data; + struct sysv_dir_entry * de; + + if (!inode) + return 1; + block = 0; + bh = NULL; + pos = offset = 2*SYSV_DIRSIZE; + if (inode->i_size % SYSV_DIRSIZE) + goto bad_dir; + if (inode->i_size < pos) + goto bad_dir; + bh = sysv_file_bread(inode,0,0,&bh_data); + if (!bh) + goto bad_dir; + de = (struct sysv_dir_entry *) (bh_data + 0*SYSV_DIRSIZE); + if (!de->inode || strcmp(de->name,".")) + goto bad_dir; + de = (struct sysv_dir_entry *) (bh_data + 1*SYSV_DIRSIZE); + if (!de->inode || strcmp(de->name,"..")) + goto bad_dir; + sb = inode->i_sb; + while (pos < inode->i_size) { + if (!bh) { + bh = sysv_file_bread(inode,block,0,&bh_data); + if (!bh) { + /* offset = 0; */ block++; + pos += sb->sv_block_size; + continue; + } + } + de = (struct sysv_dir_entry *) (bh_data + offset); + pos += SYSV_DIRSIZE; + offset += SYSV_DIRSIZE; + if (de->inode) { + brelse(bh); + return 0; + } + if (offset < sb->sv_block_size) + continue; + brelse(bh); + bh = NULL; + offset = 0; block++; + } + brelse(bh); + return 1; +bad_dir: + brelse(bh); + printk("Bad directory on device %04x\n",inode->i_dev); + return 1; +} + +int sysv_rmdir(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct sysv_dir_entry * de; + + inode = NULL; + bh = sysv_find_entry(dir,name,len,&de); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget(dir->i_sb, de->inode))) + goto end_rmdir; + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir(inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (de->inode != inode->i_ino) { + retval = -ENOENT; + goto end_rmdir; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto end_rmdir; + } + if (inode->i_nlink != 2) + printk("empty directory has nlink!=2 (%d)\n",inode->i_nlink); + de->inode = 0; + bh->b_dirt = 1; + inode->i_nlink=0; + inode->i_dirt=1; + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + retval = 0; +end_rmdir: + iput(dir); + iput(inode); + brelse(bh); + return retval; +} + +int sysv_unlink(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct sysv_dir_entry * de; + +repeat: + retval = -ENOENT; + inode = NULL; + bh = sysv_find_entry(dir,name,len,&de); + if (!bh) + goto end_unlink; + if (!(inode = iget(dir->i_sb, de->inode))) + goto end_unlink; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (de->inode != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (de->inode != inode->i_ino) { + retval = -ENOENT; + goto end_unlink; + } + if (!inode->i_nlink) { + printk("Deleting nonexistent file (%04x:%lu), %d\n", + inode->i_dev,inode->i_ino,inode->i_nlink); + inode->i_nlink=1; + } + de->inode = 0; + bh->b_dirt = 1; + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + inode->i_nlink--; + inode->i_ctime = dir->i_ctime; + inode->i_dirt = 1; + retval = 0; +end_unlink: + brelse(bh); + iput(inode); + iput(dir); + return retval; +} + +int sysv_symlink(struct inode * dir, const char * name, int len, const char * symname) +{ + struct sysv_dir_entry * de; + struct inode * inode; + struct buffer_head * name_block; + char * name_block_data; + struct super_block * sb; + int i; + char c; + struct buffer_head * bh; + + if (!(inode = sysv_new_inode(dir))) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | 0777; + inode->i_op = &sysv_symlink_inode_operations; + name_block = sysv_file_bread(inode,0,1,&name_block_data); + if (!name_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + sb = inode->i_sb; + i = 0; + while (i < sb->sv_block_size_1 && (c = *(symname++))) + name_block_data[i++] = c; + name_block_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = sysv_find_entry(dir,name,len,&de); + if (bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + brelse(bh); + iput(dir); + return -EEXIST; + } + i = sysv_add_entry(dir, name, len, &bh, &de); + if (i) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return i; + } + de->inode = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len) +{ + int error; + struct sysv_dir_entry * de; + struct buffer_head * bh; + + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (oldinode->i_nlink >= oldinode->i_sb->sv_link_max) { + iput(oldinode); + iput(dir); + return -EMLINK; + } + bh = sysv_find_entry(dir,name,len,&de); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + error = sysv_add_entry(dir, name, len, &bh, &de); + if (error) { + iput(dir); + iput(oldinode); + return error; + } + de->inode = oldinode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} + +/* return 1 if `new' is a subdir of `old' on the same device */ +static int subdir(struct inode * new_inode, struct inode * old_inode) +{ + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (sysv_lookup(new_inode,"..",2,&new_inode)) + break; + if (new_inode->i_ino == ino) /* root dir reached ? */ + break; + } + iput(new_inode); + return result; +} + +#define PARENT_INO(buffer) \ +(((struct sysv_dir_entry *) ((buffer) + 1*SYSV_DIRSIZE))->inode) + +/* + * rename uses retrying to avoid race-conditions: at least they should be minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_sysv_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + char * dir_bh_data; + struct sysv_dir_entry * old_de, * new_de; + int retval; + + goto start_up; +try_again: + brelse(old_bh); + brelse(new_bh); + brelse(dir_bh); + iput(old_inode); + iput(new_inode); + current->counter = 0; + schedule(); +start_up: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + old_bh = sysv_find_entry(old_dir,old_name,old_len,&old_de); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = __iget(old_dir->i_sb, old_de->inode, 0); /* don't cross mnt-points */ + if (!old_inode) + goto end_rename; + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = sysv_find_entry(new_dir,new_name,new_len,&new_de); + if (new_bh) { + new_inode = __iget(new_dir->i_sb, new_de->inode, 0); + if (!new_inode) { + brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EISDIR; + if (!S_ISDIR(old_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -ENOTEMPTY; + if (!empty_dir(new_inode)) + goto end_rename; + retval = -EBUSY; + if (new_inode->i_count > 1) + goto end_rename; + } + retval = -EPERM; + if (new_inode && (new_dir->i_mode & S_ISVTX) && + current->euid != new_inode->i_uid && + current->euid != new_dir->i_uid && !suser()) + goto end_rename; + if (S_ISDIR(old_inode->i_mode)) { + retval = -ENOTDIR; + if (new_inode && !S_ISDIR(new_inode->i_mode)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -EIO; + dir_bh = sysv_file_bread(old_inode,0,0,&dir_bh_data); + if (!dir_bh) + goto end_rename; + if (PARENT_INO(dir_bh_data) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (!new_inode && new_dir->i_nlink >= new_dir->i_sb->sv_link_max) + goto end_rename; + } + if (!new_bh) { + retval = sysv_add_entry(new_dir,new_name,new_len,&new_bh,&new_de); + if (retval) + goto end_rename; + } +/* sanity checking before doing the rename - avoid races */ + if (new_inode && (new_de->inode != new_inode->i_ino)) + goto try_again; + if (new_de->inode && !new_inode) + goto try_again; + if (old_de->inode != old_inode->i_ino) + goto try_again; +/* ok, that's it */ + old_de->inode = 0; + 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; + new_bh->b_dirt = 1; + if (dir_bh) { + PARENT_INO(dir_bh_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + old_dir->i_dirt = 1; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } else { + new_dir->i_nlink++; + new_dir->i_dirt = 1; + } + } + retval = 0; +end_rename: + brelse(dir_bh); + brelse(old_bh); + brelse(new_bh); + iput(old_inode); + iput(new_inode); + iput(old_dir); + iput(new_dir); + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + */ +int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + + while (lock) + sleep_on(&wait); + lock = 1; + result = do_sysv_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len); + lock = 0; + wake_up(&wait); + return result; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/symlink.c new file mode 100644 index 000000000..0e1e9bb6a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/sysv/symlink.c @@ -0,0 +1,110 @@ +/* + * linux/fs/sysv/symlink.c + * + * minix/symlink.c + * Copyright (C) 1991, 1992 Linus Torvalds + * + * coh/symlink.c + * Copyright (C) 1993 Pascal Haible, Bruno Haible + * + * sysv/symlink.c + * Copyright (C) 1993 Bruno Haible + * + * SystemV/Coherent symlink handling code + */ + +#include + +#include +#include +#include +#include + +static int sysv_readlink(struct inode *, char *, int); +static int sysv_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations sysv_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + sysv_readlink, /* readlink */ + sysv_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int sysv_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + struct buffer_head * bh; + char * bh_data; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (current->link_count > 5) { + iput(inode); + iput(dir); + return -ELOOP; + } + if (!(bh = sysv_file_bread(inode, 0, 0, &bh_data))) { /* is reading 1 block enough ?? */ + iput(inode); + iput(dir); + return -EIO; + } + iput(inode); + current->link_count++; + error = open_namei(bh_data,flag,mode,res_inode,dir); + current->link_count--; + brelse(bh); + return error; +} + +static int sysv_readlink(struct inode * inode, char * buffer, int buflen) +{ + struct buffer_head * bh; + char * bh_data; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + if (buflen > inode->i_sb->sv_block_size_1) + buflen = inode->i_sb->sv_block_size_1; + bh = sysv_file_bread(inode, 0, 0, &bh_data); + iput(inode); + if (!bh) + return 0; + i = 0; + while (i +#include +#include +#include + + +/* There are two different implementations of truncate() here. + * One (by Bruno) needs to do locking to ensure that noone is writing + * to a block being truncated away and incorporated into the free list. + * The better one (by Linus) doesn't need locking because it can tell from + * looking at bh->b_count whether a given block is in use elsewhere. + * Alas, this doesn't work if block_size < BLOCK_SIZE. + */ + + +/* Bruno's implementation of truncate. */ + +/* Leave at most `blocks' direct blocks. */ +static int coh_trunc_direct (struct inode * inode, unsigned long blocks) +{ + unsigned int i; + unsigned long * p; + unsigned long block; + + for (i = blocks; i < 10 ; i++) { + p = &inode->u.sysv_i.i_data[i]; + block = *p; + if (!block) + continue; + *p = 0; + inode->i_dirt = 1; + sysv_free_block(inode->i_sb,block); + } + return 0; +} + +/* Leave at most `blocks' blocks out of an indirect block whose number is + * from_coh_ulong(*p) if convert=1, *p if convert=0. + */ +static int coh_trunc_indirect (struct inode * inode, unsigned long blocks, unsigned long * p, int convert, unsigned char * dirt) +{ + struct super_block * sb = inode->i_sb; + unsigned long tmp, block, indblock; + struct buffer_head * bh; + char * bh_data; + unsigned long i; + sysv_zone_t * ind; + + if (blocks >= sb->sv_ind_per_block) + return 0; + block = tmp = *p; + if (convert) + block = from_coh_ulong(block); + if (!block) + return 0; + bh = sysv_bread(sb,inode->i_dev,block,&bh_data); + if (tmp != *p) { + brelse(bh); + return 1; + } + if (!bh) { + *p = 0; + *dirt = 1; + return 0; + } + for (i = blocks; i < sb->sv_ind_per_block; i++) { + ind = &((sysv_zone_t *) bh_data)[i]; + indblock = *ind; + if (sb->sv_convert) + indblock = from_coh_ulong(indblock); + if (!indblock) + continue; + *ind = 0; + bh->b_dirt = 1; + sysv_free_block(sb,indblock); + } + for (i = 0; i < sb->sv_ind_per_block; i++) + if (((sysv_zone_t *) bh_data)[i]) + goto done; + if (tmp != *p) { + brelse(bh); + return 1; + } + *p = 0; + *dirt = 1; + sysv_free_block(sb,block); +done: + brelse(bh); + return 0; +} + +/* Leave at most `blocks' blocks out of an double indirect block whose number is + * from_coh_ulong(*p) if convert=1, *p if convert=0. + */ +static int coh_trunc_dindirect (struct inode * inode, unsigned long blocks, unsigned long * p, int convert, unsigned char * dirt) +{ + struct super_block * sb = inode->i_sb; + unsigned long tmp, block, dindblock; + struct buffer_head * bh; + char * bh_data; + unsigned long i, j; + sysv_zone_t * dind; + int retry = 0; + + if (blocks >= sb->sv_ind_per_block_2) + return 0; + block = tmp = *p; + if (convert) + block = from_coh_ulong(block); + if (!block) + return 0; + bh = sysv_bread(sb,inode->i_dev,block,&bh_data); + if (tmp != *p) { + brelse(bh); + return 1; + } + if (!bh) { + *p = 0; + *dirt = 1; + return 0; + } + for (i = blocks >> sb->sv_ind_per_block_bits, j = blocks & sb->sv_ind_per_block_1; + i < sb->sv_ind_per_block; + i++, j = 0) { + /* j = max(blocks-i*ind_per_block,0) */ + dind = &((sysv_zone_t *) bh_data)[i]; + dindblock = *dind; + if (sb->sv_convert) + dindblock = from_coh_ulong(dindblock); + if (!dindblock) + continue; + retry |= coh_trunc_indirect(inode,j,dind,sb->sv_convert,&bh->b_dirt); + } + for (i = 0; i < sb->sv_ind_per_block; i++) + if (((sysv_zone_t *) bh_data)[i]) + goto done; + if (tmp != *p) { + brelse(bh); + return 1; + } + *p = 0; + *dirt = 1; + sysv_free_block(sb,block); +done: + brelse(bh); + return retry; +} + +/* Leave at most `blocks' blocks out of an triple indirect block whose number is + * from_coh_ulong(*p) if convert=1, *p if convert=0. + */ +static int coh_trunc_tindirect (struct inode * inode, unsigned long blocks, unsigned long * p) +{ + struct super_block * sb = inode->i_sb; + unsigned long block, tindblock; + struct buffer_head * bh; + char * bh_data; + unsigned long i, j; + sysv_zone_t * tind; + int retry = 0; + + if (blocks >= sb->sv_ind_per_block_3) + return 0; + block = *p; + if (!block) + return 0; + bh = sysv_bread(sb,inode->i_dev,block,&bh_data); + if (block != *p) { + brelse(bh); + return 1; + } + if (!bh) { + *p = 0; + inode->i_dirt = 1; + return 0; + } + for (i = blocks >> sb->sv_ind_per_block_2_bits, j = blocks & sb->sv_ind_per_block_2_1; + i < sb->sv_ind_per_block; + i++, j = 0) { + /* j = max(blocks-i*ind_per_block^2,0) */ + tind = &((sysv_zone_t *) bh_data)[i]; + tindblock = *tind; + if (sb->sv_convert) + tindblock = from_coh_ulong(tindblock); + if (!tindblock) + continue; + retry |= coh_trunc_dindirect(inode,j,tind,sb->sv_convert,&bh->b_dirt); + } + for (i = 0; i < sb->sv_ind_per_block; i++) + if (((sysv_zone_t *) bh_data)[i]) + goto done; + if (block != *p) { + brelse(bh); + return 1; + } + *p = 0; + inode->i_dirt = 1; + sysv_free_block(sb,block); +done: + brelse(bh); + return retry; +} + +static int coh_trunc_all(struct inode * inode) +{ + struct super_block * sb = inode->i_sb; + long blocks; + int retry; + + blocks = (inode->i_size + sb->sv_block_size_1) >> sb->sv_block_size_bits; + retry = coh_trunc_direct(inode,blocks); + blocks -= 10; + if (blocks < 0) blocks = 0; + retry |= coh_trunc_indirect(inode,blocks,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt); + blocks -= sb->sv_ind_per_block; + if (blocks < 0) blocks = 0; + retry |= coh_trunc_dindirect(inode,blocks,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt); + blocks -= sb->sv_ind_per_block_2; + if (blocks < 0) blocks = 0; + retry |= coh_trunc_tindirect(inode,blocks,&inode->u.sysv_i.i_data[12]); + return retry; +} + + +/* Linus' implementation of truncate. Used only if block_size = BLOCK_SIZE. */ + +/* + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + +/* We throw away any data beyond inode->i_size. */ + +static int trunc_direct(struct inode * inode) +{ + struct super_block * sb; + unsigned int i; + unsigned long * p; + unsigned long block; + struct buffer_head * bh; + int retry = 0; + + sb = inode->i_sb; +repeat: + for (i = ((unsigned long) inode->i_size + BLOCK_SIZE-1) / BLOCK_SIZE; i < 10; i++) { + p = inode->u.sysv_i.i_data + i; + block = *p; + if (!block) + continue; + bh = get_hash_table(inode->i_dev,block+sb->sv_block_base,BLOCK_SIZE); + if (i*BLOCK_SIZE < inode->i_size) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || (block != *p)) { + retry = 1; + brelse(bh); + continue; + } + *p = 0; + inode->i_dirt = 1; + brelse(bh); + sysv_free_block(sb,block); + } + return retry; +} + +#define IND_PER_BLOCK (BLOCK_SIZE / sizeof(sysv_zone_t)) + +static int trunc_indirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) +{ + unsigned long indtmp, indblock; + struct super_block * sb; + struct buffer_head * indbh; + unsigned int i; + sysv_zone_t * ind; + unsigned long tmp, block; + struct buffer_head * bh; + int retry = 0; + + indblock = indtmp = *p; + if (convert) + indblock = from_coh_ulong(indblock); + if (!indblock) + return 0; + sb = inode->i_sb; + indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE); + if (indtmp != *p) { + brelse(indbh); + return 1; + } + if (!indbh) { + *p = 0; + *dirt = 1; + return 0; + } +repeat: + if (inode->i_size < offset) + i = 0; + else + i = (inode->i_size - offset + BLOCK_SIZE-1) / BLOCK_SIZE; + for (; i < IND_PER_BLOCK; i++) { + ind = ((sysv_zone_t *) indbh->b_data) + i; + block = tmp = *ind; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (!block) + continue; + bh = get_hash_table(inode->i_dev,block+sb->sv_block_base,BLOCK_SIZE); + if (i*BLOCK_SIZE + offset < inode->i_size) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || (tmp != *ind)) { + retry = 1; + brelse(bh); + continue; + } + *ind = 0; + indbh->b_dirt = 1; + brelse(bh); + sysv_free_block(sb,block); + } + for (i = 0; i < IND_PER_BLOCK; i++) + if (((sysv_zone_t *) indbh->b_data)[i]) + goto done; + if ((indbh->b_count != 1) || (indtmp != *p)) { + brelse(indbh); + return 1; + } + *p = 0; + *dirt = 1; + sysv_free_block(sb,indblock); +done: + brelse(indbh); + return retry; +} + +static int trunc_dindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) +{ + unsigned long indtmp, indblock; + struct super_block * sb; + struct buffer_head * indbh; + unsigned int i; + sysv_zone_t * ind; + unsigned long tmp, block; + int retry = 0; + + indblock = indtmp = *p; + if (convert) + indblock = from_coh_ulong(indblock); + if (!indblock) + return 0; + sb = inode->i_sb; + indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE); + if (indtmp != *p) { + brelse(indbh); + return 1; + } + if (!indbh) { + *p = 0; + *dirt = 1; + return 0; + } + if (inode->i_size < offset) + i = 0; + else + i = (inode->i_size - offset + IND_PER_BLOCK*BLOCK_SIZE-1) / (IND_PER_BLOCK*BLOCK_SIZE); + for (; i < IND_PER_BLOCK; i++) { + ind = ((sysv_zone_t *) indbh->b_data) + i; + block = tmp = *ind; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (!block) + continue; + retry |= trunc_indirect(inode,offset+i*IND_PER_BLOCK,ind,sb->sv_convert,&indbh->b_dirt); + } + for (i = 0; i < IND_PER_BLOCK; i++) + if (((sysv_zone_t *) indbh->b_data)[i]) + goto done; + if ((indbh->b_count != 1) || (indtmp != *p)) { + brelse(indbh); + return 1; + } + *p = 0; + *dirt = 1; + sysv_free_block(sb,indblock); +done: + brelse(indbh); + return retry; +} + +static int trunc_tindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt) +{ + unsigned long indtmp, indblock; + struct super_block * sb; + struct buffer_head * indbh; + unsigned int i; + sysv_zone_t * ind; + unsigned long tmp, block; + int retry = 0; + + indblock = indtmp = *p; + if (convert) + indblock = from_coh_ulong(indblock); + if (!indblock) + return 0; + sb = inode->i_sb; + indbh = bread(inode->i_dev,indblock+sb->sv_block_base,BLOCK_SIZE); + if (indtmp != *p) { + brelse(indbh); + return 1; + } + if (!indbh) { + *p = 0; + *dirt = 1; + return 0; + } + if (inode->i_size < offset) + i = 0; + else + i = (inode->i_size - offset + IND_PER_BLOCK*IND_PER_BLOCK*BLOCK_SIZE-1) / (IND_PER_BLOCK*IND_PER_BLOCK*BLOCK_SIZE); + for (; i < IND_PER_BLOCK; i++) { + ind = ((sysv_zone_t *) indbh->b_data) + i; + block = tmp = *ind; + if (sb->sv_convert) + block = from_coh_ulong(block); + if (!block) + continue; + retry |= trunc_dindirect(inode,offset+i*IND_PER_BLOCK*IND_PER_BLOCK,ind,sb->sv_convert,&indbh->b_dirt); + } + for (i = 0; i < IND_PER_BLOCK; i++) + if (((sysv_zone_t *) indbh->b_data)[i]) + goto done; + if ((indbh->b_count != 1) || (indtmp != *p)) { + brelse(indbh); + return 1; + } + *p = 0; + *dirt = 1; + sysv_free_block(sb,indblock); +done: + brelse(indbh); + return retry; +} + +static int trunc_all(struct inode * inode) +{ + return trunc_direct(inode) + | trunc_indirect(inode,10*BLOCK_SIZE,&inode->u.sysv_i.i_data[10],0,&inode->i_dirt) + | trunc_dindirect(inode,(10+IND_PER_BLOCK)*BLOCK_SIZE,&inode->u.sysv_i.i_data[11],0,&inode->i_dirt) + | trunc_tindirect(inode,(10+IND_PER_BLOCK+IND_PER_BLOCK*IND_PER_BLOCK)*BLOCK_SIZE,&inode->u.sysv_i.i_data[12],0,&inode->i_dirt); +} + + +void sysv_truncate(struct inode * inode) +{ + /* If this is called from sysv_put_inode, we needn't worry about + * races as we are just losing the last reference to the inode. + * If this is called from another place, let's hope it's a regular + * file. + * Truncating symbolic links is strange. We assume we don't truncate + * a directory we are just modifying. We ensure we don't truncate + * a regular file we are just writing to, by use of a lock. + */ + if (S_ISLNK(inode->i_mode)) + printk("sysv_truncate: truncating symbolic link\n"); + else if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode))) + return; + if (inode->i_sb->sv_block_size_ratio_bits > 0) { /* block_size < BLOCK_SIZE ? */ + coh_lock_inode(inode); /* do not write to the inode while we truncate */ + while (coh_trunc_all(inode)) { + current->counter = 0; + schedule(); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + coh_unlock_inode(inode); + } else { + while (trunc_all(inode)) { + current->counter = 0; + schedule(); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + inode->i_dirt = 1; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/Makefile new file mode 100644 index 000000000..097563244 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/Makefile @@ -0,0 +1,31 @@ +# +# Makefile for the XIAFS filesystem routines. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.c.s: + $(CC) $(CFLAGS) -S $< +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< + +OBJS= bitmap.o truncate.o namei.o inode.o \ + file.o dir.o symlink.o fsync.o + +xiafs.o: $(OBJS) + $(LD) -r -o xiafs.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/bitmap.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/bitmap.c new file mode 100644 index 000000000..3dd74fa59 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/bitmap.c @@ -0,0 +1,395 @@ +/* + * linux/fs/xiafs/bitmap.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/bitmap.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +/* bitmap.c contains the code that handles the inode and block bitmaps */ + +#include +#include +#include +#include +#include +#include + +#include "xiafs_mac.h" + + +#define clear_bit(nr,addr) ({\ +char res; \ +__asm__ __volatile__("btrl %1,%2\n\tsetnb %0": \ +"=q" (res):"r" (nr),"m" (*(addr))); \ +res;}) + +char internal_error_message[]="XIA-FS: internal error %s %d\n"; + +static int find_first_zero(struct buffer_head *bh, int start_bit, int end_bit) +{ + /* This routine searches first 0 bit from (start_bit) to (end_bit-1). + * If found the bit is set to 1 and the bit # is returned, otherwise, + * -1 is returned. Race condition is avoid by using "btsl" and + * "goto repeat". ---Frank. + */ + + int end, i, j, tmp; + u_long *bmap; + char res; + + bmap=(u_long *)bh->b_data; + end = end_bit >> 5; + +repeat: + i=start_bit >> 5; + if ( (tmp=(~bmap[i]) & (0xffffffff << (start_bit & 31))) ) + goto zone_found; + while (++i < end) + if (~bmap[i]) { + tmp=~bmap[i]; + goto zone_found; + } + if ( !(tmp=~bmap[i] & ((1 << (end_bit & 31)) -1)) ) + return -1; +zone_found: + for (j=0; j < 32; j++) + if (tmp & (1 << j)) + break; + __asm__ ("btsl %1,%2\n\tsetb %0": \ + "=q" (res):"r" (j),"m" (bmap[i])); + if (res) { + start_bit=j + (i << 5) + 1; + goto repeat; + } + bh->b_dirt=1; + return j + (i << 5); +} + +static void clear_buf(struct buffer_head * bh) +{ + register int i; + register long * lp; + + lp=(long *)bh->b_data; + for (i= bh->b_size >> 2; i-- > 0; ) + *lp++=0; +} + +static void que(struct buffer_head * bmap[], int bznr[], int pos) +{ + struct buffer_head * tbh; + int tmp; + int i; + + tbh=bmap[pos]; + tmp=bznr[pos]; + for (i=pos; i > 0; i--) { + bmap[i]=bmap[i-1]; + bznr[i]=bznr[i-1]; + } + bmap[0]=tbh; + bznr[0]=tmp; +} + +#define get_imap_zone(sb, bit_nr, not_que) \ + get__map_zone((sb), (sb)->u.xiafs_sb.s_imap_buf, \ + (sb)->u.xiafs_sb.s_imap_iznr, \ + (sb)->u.xiafs_sb.s_imap_cached, 1, \ + (sb)->u.xiafs_sb.s_imap_zones, _XIAFS_IMAP_SLOTS, \ + bit_nr, not_que) + +#define get_zmap_zone(sb, bit_nr, not_que) \ + get__map_zone((sb), (sb)->u.xiafs_sb.s_zmap_buf, \ + (sb)->u.xiafs_sb.s_zmap_zznr, \ + (sb)->u.xiafs_sb.s_zmap_cached, \ + 1+(sb)->u.xiafs_sb.s_imap_zones, \ + (sb)->u.xiafs_sb.s_zmap_zones, _XIAFS_ZMAP_SLOTS, \ + bit_nr, not_que) + +static struct buffer_head * +get__map_zone(struct super_block *sb, struct buffer_head * bmap_buf[], + int bznr[], u_char cache, int first_zone, + int bmap_zones, int slots, u_long bit_nr, int * not_que) +{ + struct buffer_head * tmp_bh; + int z_nr, i; + + z_nr = bit_nr >> XIAFS_BITS_PER_Z_BITS(sb); + if (z_nr >= bmap_zones) { + printk("XIA-FS: bad inode/zone number (%s %d)\n", WHERE_ERR); + return NULL; + } + if (!cache) + return bmap_buf[z_nr]; + lock_super(sb); + for (i=0; i < slots; i++) + if (bznr[i]==z_nr) + break; + if (i < slots) { /* cache hit */ + if (not_que) { + *not_que=i; + return bmap_buf[i]; + } else { + que(bmap_buf, bznr, i); + return bmap_buf[0]; + } + } + tmp_bh=bread(sb->s_dev, z_nr+first_zone, XIAFS_ZSIZE(sb)); /* cache not hit */ + if (!tmp_bh) { + printk("XIA-FS: read bitmap failed (%s %d)\n", WHERE_ERR); + unlock_super(sb); + return NULL; + } + brelse(bmap_buf[slots-1]); + bmap_buf[slots-1]=tmp_bh; + bznr[slots-1]=z_nr; + if (not_que) + *not_que=slots-1; + else + que(bmap_buf, bznr, slots-1); + return tmp_bh; +} + +#define xiafs_unlock_super(sb, cache) if (cache) unlock_super(sb); + +#define get_free_ibit(sb, prev_bit) \ + get_free__bit(sb, sb->u.xiafs_sb.s_imap_buf, \ + sb->u.xiafs_sb.s_imap_iznr, \ + sb->u.xiafs_sb.s_imap_cached, \ + 1, sb->u.xiafs_sb.s_imap_zones, \ + _XIAFS_IMAP_SLOTS, prev_bit); + +#define get_free_zbit(sb, prev_bit) \ + get_free__bit(sb, sb->u.xiafs_sb.s_zmap_buf, \ + sb->u.xiafs_sb.s_zmap_zznr, \ + sb->u.xiafs_sb.s_zmap_cached, \ + 1 + sb->u.xiafs_sb.s_imap_zones, \ + sb->u.xiafs_sb.s_zmap_zones, \ + _XIAFS_ZMAP_SLOTS, prev_bit); + +static u_long +get_free__bit(struct super_block *sb, struct buffer_head * bmap_buf[], + int bznr[], u_char cache, int first_zone, int bmap_zones, + int slots, u_long prev_bit) +{ + struct buffer_head * bh; + int not_done=0; + u_long pos, start_bit, end_bit, total_bits; + int z_nr, tmp; + + total_bits=bmap_zones << XIAFS_BITS_PER_Z_BITS(sb); + if (prev_bit >= total_bits) + prev_bit=0; + pos=prev_bit+1; + end_bit=XIAFS_BITS_PER_Z(sb); + + do { + if (pos >= total_bits) + pos=0; + if (!not_done) { /* first time */ + not_done=1; + start_bit= pos & (end_bit-1); + } else + start_bit=0; + if ( pos < prev_bit && pos+end_bit >= prev_bit) { /* last time */ + not_done=0; + end_bit=prev_bit & (end_bit-1); /* only here end_bit modified */ + } + bh = get__map_zone(sb, bmap_buf, bznr, cache, first_zone, + bmap_zones, slots, pos, &z_nr); + if (!bh) + return 0; + tmp=find_first_zero(bh, start_bit, end_bit); + if (tmp >= 0) + break; + xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached); + pos=(pos & ~(end_bit-1))+end_bit; + } while (not_done); + + if (tmp < 0) + return 0; + if (cache) + que(bmap_buf, bznr, z_nr); + xiafs_unlock_super(sb, cache); + return (pos & ~(XIAFS_BITS_PER_Z(sb)-1))+tmp; +} + +void xiafs_free_zone(struct super_block * sb, int d_addr) +{ + struct buffer_head * bh; + unsigned int bit, offset; + + if (!sb) { + printk(INTERN_ERR); + return; + } + if (d_addr < sb->u.xiafs_sb.s_firstdatazone || + d_addr >= sb->u.xiafs_sb.s_nzones) { + printk("XIA-FS: bad zone number (%s %d)\n", WHERE_ERR); + return; + } + bh = get_hash_table(sb->s_dev, d_addr, XIAFS_ZSIZE(sb)); + if (bh) + bh->b_dirt=0; + brelse(bh); + bit=d_addr - sb->u.xiafs_sb.s_firstdatazone + 1; + bh = get_zmap_zone(sb, bit, NULL); + if (!bh) + return; + offset = bit & (XIAFS_BITS_PER_Z(sb) -1); + if (clear_bit(offset, bh->b_data)) + printk("XIA-FS: dev %04x" + " block bit %u (0x%x) already cleared (%s %d)\n", + sb->s_dev, bit, bit, WHERE_ERR); + bh->b_dirt = 1; + xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached); +} + +int xiafs_new_zone(struct super_block * sb, u_long prev_addr) +{ + struct buffer_head * bh; + int prev_znr, tmp; + + if (!sb) { + printk(INTERN_ERR); + return 0; + } + if (prev_addr < sb->u.xiafs_sb.s_firstdatazone || + prev_addr >= sb->u.xiafs_sb.s_nzones) { + prev_addr=sb->u.xiafs_sb.s_firstdatazone; + } + prev_znr=prev_addr-sb->u.xiafs_sb.s_firstdatazone+1; + tmp=get_free_zbit(sb, prev_znr); + if (!tmp) + return 0; + tmp += sb->u.xiafs_sb.s_firstdatazone -1; + if (!(bh = getblk(sb->s_dev, tmp, XIAFS_ZSIZE(sb)))) { + printk("XIA-FS: I/O error (%s %d)\n", WHERE_ERR); + return 0; + } + if (bh->b_count != 1) { + printk(INTERN_ERR); + return 0; + } + clear_buf(bh); + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + return tmp; +} + +void xiafs_free_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct super_block * sb; + unsigned long ino; + + if (!inode) + return; + if (!inode->i_dev || inode->i_count!=1 || inode->i_nlink || !inode->i_sb || + inode->i_ino < 3 || inode->i_ino > inode->i_sb->u.xiafs_sb.s_ninodes) { + printk("XIA-FS: bad inode (%s %d)\n", WHERE_ERR); + return; + } + sb = inode->i_sb; + ino = inode->i_ino; + bh = get_imap_zone(sb, ino, NULL); + if (!bh) + return; + clear_inode(inode); + if (clear_bit(ino & (XIAFS_BITS_PER_Z(sb)-1), bh->b_data)) + printk("XIA-FS: dev %04x" + "inode bit %ld (0x%lx) already cleared (%s %d)\n", + inode->i_dev, ino, ino, WHERE_ERR); + bh->b_dirt = 1; + xiafs_unlock_super(sb, sb->u.xiafs_sb.s_imap_cached); +} + +struct inode * xiafs_new_inode(struct inode * dir) +{ + struct super_block * sb; + struct inode * inode; + ino_t tmp; + + sb = dir->i_sb; + if (!dir || !(inode = get_empty_inode())) + return NULL; + inode->i_sb = sb; + inode->i_flags = inode->i_sb->s_flags; + + tmp=get_free_ibit(sb, dir->i_ino); + if (!tmp) { + iput(inode); + return NULL; + } + inode->i_count = 1; + inode->i_nlink = 1; + inode->i_dev = sb->s_dev; + inode->i_uid = current->euid; + inode->i_gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->egid; + inode->i_dirt = 1; + inode->i_ino = tmp; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_op = NULL; + inode->i_blocks = 0; + inode->i_blksize = XIAFS_ZSIZE(inode->i_sb); + insert_inode_hash(inode); + return inode; +} + +static int nibblemap[] = { 0,1,1,2,1,2,2,3,1,2,2,3,2,3,3,4 }; + +static u_long count_zone(struct buffer_head * bh) +{ + int i, tmp; + u_long sum; + + sum=0; + for (i=bh->b_size; i-- > 0; ) { + tmp=bh->b_data[i]; + sum += nibblemap[tmp & 0xf] + nibblemap[(tmp & 0xff) >> 4]; + } + return sum; +} + +unsigned long xiafs_count_free_inodes(struct super_block *sb) +{ + struct buffer_head * bh; + int izones, i, not_que; + u_long sum; + + sum=0; + izones=sb->u.xiafs_sb.s_imap_zones; + for (i=0; i < izones; i++) { + bh=get_imap_zone(sb, i << XIAFS_BITS_PER_Z_BITS(sb), ¬_que); + if (bh) { + sum += count_zone(bh); + xiafs_unlock_super(sb, sb->u.xiafs_sb.s_imap_cached); + } + } + i=izones << XIAFS_BITS_PER_Z_BITS(sb); + return i - sum; +} + +unsigned long xiafs_count_free_zones(struct super_block *sb) +{ + struct buffer_head * bh; + int zzones, i, not_que; + u_long sum; + + sum=0; + zzones=sb->u.xiafs_sb.s_zmap_zones; + for (i=0; i < zzones; i++) { + bh=get_zmap_zone(sb, i << XIAFS_BITS_PER_Z_BITS(sb), ¬_que); + if (bh) { + sum += count_zone(bh); + xiafs_unlock_super(sb, sb->u.xiafs_sb.s_zmap_cached); + } + } + i=zzones << XIAFS_BITS_PER_Z_BITS(sb); + return i - sum; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/dir.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/dir.c new file mode 100644 index 000000000..fca3c2b46 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/dir.c @@ -0,0 +1,123 @@ +/* + * linux/fs/xiafs/dir.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/dir.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "xiafs_mac.h" + +static int xiafs_dir_read(struct inode *, struct file *, char *, int); +static int xiafs_readdir(struct inode *, struct file *, struct dirent *, int); + +static struct file_operations xiafs_dir_operations = { + NULL, /* lseek - default */ + xiafs_dir_read, /* read */ + NULL, /* write - bad */ + xiafs_readdir, /* readdir */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + NULL, /* mmap */ + NULL, /* no special open code */ + NULL, /* no special release code */ + file_fsync /* default fsync */ +}; + +/* + * directories can handle most operations... + */ +struct inode_operations xiafs_dir_inode_operations = { + &xiafs_dir_operations, /* default directory file-ops */ + xiafs_create, /* create */ + xiafs_lookup, /* lookup */ + xiafs_link, /* link */ + xiafs_unlink, /* unlink */ + xiafs_symlink, /* symlink */ + xiafs_mkdir, /* mkdir */ + xiafs_rmdir, /* rmdir */ + xiafs_mknod, /* mknod */ + xiafs_rename, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + NULL, /* bmap */ + xiafs_truncate, /* truncate */ + NULL /* permission */ +}; + +static int xiafs_dir_read(struct inode * inode, + struct file * filp, char * buf, int count) +{ + return -EISDIR; +} + +static int xiafs_readdir(struct inode * inode, + struct file * filp, struct dirent * dirent, int count) +{ + u_int offset, i; + struct buffer_head * bh; + struct xiafs_direct * de; + + if (!inode || !inode->i_sb || !S_ISDIR(inode->i_mode)) + return -EBADF; + if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1) ) + return -EBADF; + while (filp->f_pos < inode->i_size) { + offset = filp->f_pos & (XIAFS_ZSIZE(inode->i_sb) - 1); + bh = xiafs_bread(inode, filp->f_pos >> XIAFS_ZSIZE_BITS(inode->i_sb),0); + if (!bh) { + filp->f_pos += XIAFS_ZSIZE(inode->i_sb)-offset; + continue; + } + de = (struct xiafs_direct *) (offset + bh->b_data); + while (offset < XIAFS_ZSIZE(inode->i_sb) && filp->f_pos < inode->i_size) { + if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes || + de->d_rec_len < 12 || + (char *)de+de->d_rec_len > XIAFS_ZSIZE(inode->i_sb)+bh->b_data || + de->d_name_len < 1 || de->d_name_len + 8 > de->d_rec_len || + de->d_name_len > _XIAFS_NAME_LEN || + de->d_name[de->d_name_len] ) { + printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR); + brelse(bh); + return 0; + } + offset += de->d_rec_len; + filp->f_pos += de->d_rec_len; + if (de->d_ino) { + for (i = 0; i < de->d_name_len ; i++) + put_fs_byte(de->d_name[i],i+dirent->d_name); + put_fs_byte(0,i+dirent->d_name); + put_fs_long(de->d_ino,&dirent->d_ino); + put_fs_word(i,&dirent->d_reclen); + brelse(bh); + if (!IS_RDONLY (inode)) { + inode->i_atime=CURRENT_TIME; + inode->i_dirt=1; + } + return i; + } + de = (struct xiafs_direct *) (offset + bh->b_data); + } + brelse(bh); + if (offset > XIAFS_ZSIZE(inode->i_sb)) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + return 0; + } + } + if (!IS_RDONLY (inode)) { + inode->i_atime=CURRENT_TIME; + inode->i_dirt=1; + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/file.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/file.c new file mode 100644 index 000000000..3c5bd5a14 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/file.c @@ -0,0 +1,251 @@ +/* + * linux/fs/xiafs/file.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/file.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xiafs_mac.h" + +#define NBUF 32 + +#define MIN(a,b) (((a)<(b))?(a):(b)) +#define MAX(a,b) (((a)>(b))?(a):(b)) + +static int xiafs_file_read(struct inode *, struct file *, char *, int); +static int xiafs_file_write(struct inode *, struct file *, char *, int); + +/* + * We have mostly NULL's here: the current defaults are ok for + * the xiafs filesystem. + */ +static struct file_operations xiafs_file_operations = { + NULL, /* lseek - default */ + xiafs_file_read, /* read */ + xiafs_file_write, /* write */ + NULL, /* readdir - bad */ + NULL, /* select - default */ + NULL, /* ioctl - default */ + generic_mmap, /* mmap */ + NULL, /* no special open is needed */ + NULL, /* release */ + xiafs_sync_file /* fsync */ +}; + +struct inode_operations xiafs_file_inode_operations = { + &xiafs_file_operations, /* default file operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + NULL, /* readlink */ + NULL, /* follow_link */ + xiafs_bmap, /* bmap */ + xiafs_truncate, /* truncate */ + NULL /* permission */ +}; + +static int +xiafs_file_read(struct inode * inode, struct file * filp, char * buf, int count) +{ + int read, left, chars; + int zone_nr, zones, f_zones, offset; + int bhrequest, uptodate; + struct buffer_head ** bhb, ** bhe; + struct buffer_head * bhreq[NBUF]; + struct buffer_head * buflist[NBUF]; + + if (!inode) { + printk("XIA-FS: inode = NULL (%s %d)\n", WHERE_ERR); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("XIA-FS: mode != regular (%s %d)\n", WHERE_ERR); + return -EINVAL; + } + offset = filp->f_pos; + left = inode->i_size - offset; + if (left > count) + left = count; + if (left <= 0) + return 0; + read = 0; + zone_nr = offset >> XIAFS_ZSIZE_BITS(inode->i_sb); + offset &= XIAFS_ZSIZE(inode->i_sb) -1 ; + f_zones =(inode->i_size+XIAFS_ZSIZE(inode->i_sb)-1)>>XIAFS_ZSIZE_BITS(inode->i_sb); + zones = (left+offset+XIAFS_ZSIZE(inode->i_sb)-1) >> XIAFS_ZSIZE_BITS(inode->i_sb); + bhb = bhe = buflist; + if (filp->f_reada) { + zones += read_ahead[MAJOR(inode->i_dev)] >> (1+XIAFS_ZSHIFT(inode->i_sb)); + if (zone_nr + zones > f_zones) + zones = f_zones - zone_nr; + } + + /* We do this in a two stage process. We first try and request + as many blocks as we can, then we wait for the first one to + complete, and then we try and wrap up as many as are actually + done. This routine is rather generic, in that it can be used + in a filesystem by substituting the appropriate function in + for getblk. + + This routine is optimized to make maximum use of the various + buffers and caches. */ + + do { + bhrequest = 0; + uptodate = 1; + while (zones--) { + *bhb = xiafs_getblk(inode, zone_nr++, 0); + if (*bhb && !(*bhb)->b_uptodate) { + uptodate = 0; + bhreq[bhrequest++] = *bhb; + } + + if (++bhb == &buflist[NBUF]) + bhb = buflist; + + /* If the block we have on hand is uptodate, go ahead + and complete processing. */ + if (uptodate) + break; + if (bhb == bhe) + break; + } + + /* Now request them all */ + if (bhrequest) + ll_rw_block(READ, bhrequest, bhreq); + + do { /* Finish off all I/O that has actually completed */ + if (*bhe) { + wait_on_buffer(*bhe); + if (!(*bhe)->b_uptodate) { /* read error? */ + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + left = 0; + break; + } + } + if (left < XIAFS_ZSIZE(inode->i_sb) - offset) + chars = left; + else + chars = XIAFS_ZSIZE(inode->i_sb) - offset; + filp->f_pos += chars; + left -= chars; + read += chars; + if (*bhe) { + memcpy_tofs(buf,offset+(*bhe)->b_data,chars); + brelse(*bhe); + buf += chars; + } else { + while (chars-->0) + put_fs_byte(0,buf++); + } + offset = 0; + if (++bhe == &buflist[NBUF]) + bhe = buflist; + } while (left > 0 && bhe != bhb && (!*bhe || !(*bhe)->b_lock)); + } while (left > 0); + +/* Release the read-ahead blocks */ + while (bhe != bhb) { + brelse(*bhe); + if (++bhe == &buflist[NBUF]) + bhe = buflist; + }; + if (!read) + return -EIO; + filp->f_reada = 1; + if (!IS_RDONLY (inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + return read; +} + +static int +xiafs_file_write(struct inode * inode, struct file * filp, char * buf, int count) +{ + off_t pos; + int written, c; + struct buffer_head * bh; + char * cp; + + if (!inode) { + printk("XIA-FS: inode = NULL (%s %d)\n", WHERE_ERR); + return -EINVAL; + } + if (!S_ISREG(inode->i_mode)) { + printk("XIA-FS: mode != regular (%s %d)\n", WHERE_ERR); + return -EINVAL; + } +/* + * ok, append may not work when many processes are writing at the same time + * but so what. That way leads to madness anyway. + */ + if (filp->f_flags & O_APPEND) + pos = inode->i_size; + else + pos = filp->f_pos; + written = 0; + while (written < count) { + bh = xiafs_getblk(inode, pos >> XIAFS_ZSIZE_BITS(inode->i_sb), 1); + if (!bh) { + if (!written) + written = -ENOSPC; + break; + } + c = XIAFS_ZSIZE(inode->i_sb) - (pos & (XIAFS_ZSIZE(inode->i_sb) - 1)); + if (c > count-written) + c = count-written; + if (c != XIAFS_ZSIZE(inode->i_sb) && !bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + if (!written) + written = -EIO; + break; + } + } + cp = (pos & (XIAFS_ZSIZE(inode->i_sb)-1)) + bh->b_data; + pos += c; + if (pos > inode->i_size) { + inode->i_size = pos; + inode->i_dirt = 1; + } + written += c; + memcpy_fromfs(cp,buf,c); + buf += c; + bh->b_uptodate = 1; + bh->b_dirt = 1; + brelse(bh); + } + inode->i_mtime = inode->i_ctime = CURRENT_TIME; + filp->f_pos = pos; + inode->i_dirt = 1; + + return written; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/fsync.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/fsync.c new file mode 100644 index 000000000..67681b2c6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/fsync.c @@ -0,0 +1,159 @@ +/* + * linux/fs/xiafs/fsync.c + * + * Changes Copyright (C) 1993 Stephen Tweedie (sct@dcs.ed.ac.uk) + * from + * Copyright (C) 1991, 1992 Linus Torvalds + * + * xiafs fsync primitive + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include +#include + +#include "xiafs_mac.h" + + +#define blocksize (XIAFS_ZSIZE(inode->i_sb)) +#define addr_per_block (XIAFS_ADDRS_PER_Z(inode->i_sb)) + +static int sync_block (struct inode * inode, unsigned long * block, int wait) +{ + struct buffer_head * bh; + int tmp; + + if (!*block) + return 0; + tmp = *block; + bh = get_hash_table(inode->i_dev, *block, blocksize); + if (!bh) + return 0; + if (*block != tmp) { + brelse (bh); + return 1; + } + if (wait && bh->b_req && !bh->b_uptodate) { + brelse(bh); + return -1; + } + if (wait || !bh->b_uptodate || !bh->b_dirt) + { + brelse(bh); + return 0; + } + ll_rw_block(WRITE, 1, &bh); + bh->b_count--; + return 0; +} + +static int sync_iblock (struct inode * inode, unsigned long * iblock, + struct buffer_head **bh, int wait) +{ + int rc, tmp; + + *bh = NULL; + tmp = *iblock; + if (!tmp) + return 0; + rc = sync_block (inode, iblock, wait); + if (rc) + return rc; + *bh = bread(inode->i_dev, tmp, blocksize); + if (tmp != *iblock) { + brelse(*bh); + *bh = NULL; + return 1; + } + if (!*bh) + return -1; + return 0; +} + + +static int sync_direct(struct inode *inode, int wait) +{ + int i; + int rc, err = 0; + + for (i = 0; i < 8; i++) { + rc = sync_block (inode, inode->u.ext_i.i_data + i, wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + return err; +} + +static int sync_indirect(struct inode *inode, unsigned long *iblock, int wait) +{ + int i; + struct buffer_head * ind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, iblock, &ind_bh, wait); + if (rc || !ind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_block (inode, + ((unsigned long *) ind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(ind_bh); + return err; +} + +static int sync_dindirect(struct inode *inode, unsigned long *diblock, + int wait) +{ + int i; + struct buffer_head * dind_bh; + int rc, err = 0; + + rc = sync_iblock (inode, diblock, &dind_bh, wait); + if (rc || !dind_bh) + return rc; + + for (i = 0; i < addr_per_block; i++) { + rc = sync_indirect (inode, + ((unsigned long *) dind_bh->b_data) + i, + wait); + if (rc > 0) + break; + if (rc) + err = rc; + } + brelse(dind_bh); + return err; +} + +int xiafs_sync_file(struct inode * inode, struct file * file) +{ + int wait, err = 0; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return -EINVAL; + for (wait=0; wait<=1; wait++) + { + err |= sync_direct(inode, wait); + err |= sync_indirect(inode, &inode->u.xiafs_i.i_ind_zone, wait); + err |= sync_dindirect(inode, &inode->u.xiafs_i.i_dind_zone, wait); + } + err |= xiafs_sync_inode (inode); + return (err < 0) ? -EIO : 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/inode.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/inode.c new file mode 100644 index 000000000..84e2109ec --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/inode.c @@ -0,0 +1,502 @@ +/* + * linux/fs/xiafs/inode.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/inode.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xiafs_mac.h" + +static u_long random_nr; + +void xiafs_put_inode(struct inode *inode) +{ + if (inode->i_nlink) + return; + inode->i_size = 0; + xiafs_truncate(inode); + xiafs_free_inode(inode); +} + +void xiafs_put_super(struct super_block *sb) +{ + int i; + + lock_super(sb); + sb->s_dev = 0; + for(i = 0 ; i < _XIAFS_IMAP_SLOTS ; i++) + brelse(sb->u.xiafs_sb.s_imap_buf[i]); + for(i = 0 ; i < _XIAFS_ZMAP_SLOTS ; i++) + brelse(sb->u.xiafs_sb.s_zmap_buf[i]); + unlock_super(sb); +} + +static struct super_operations xiafs_sops = { + xiafs_read_inode, + NULL, + xiafs_write_inode, + xiafs_put_inode, + xiafs_put_super, + NULL, + xiafs_statfs, + NULL +}; + +struct super_block *xiafs_read_super(struct super_block *s, void *data, + int silent) +{ + struct buffer_head *bh; + struct xiafs_super_block *sp; + int i, z, dev; + + dev=s->s_dev; + lock_super(s); + + set_blocksize(dev, BLOCK_SIZE); + + if (!(bh = bread(dev, 0, BLOCK_SIZE))) { + s->s_dev=0; + unlock_super(s); + printk("XIA-FS: read super_block failed (%s %d)\n", WHERE_ERR); + return NULL; + } + sp = (struct xiafs_super_block *) bh->b_data; + s->s_magic = sp->s_magic; + if (s->s_magic != _XIAFS_SUPER_MAGIC) { + s->s_dev = 0; + unlock_super(s); + brelse(bh); + if (!silent) + printk("VFS: Can't find a xiafs filesystem on dev 0x%04x.\n", + dev); + return NULL; + } + s->s_blocksize = sp->s_zone_size; + s->s_blocksize_bits = 10 + sp->s_zone_shift; + if (s->s_blocksize != BLOCK_SIZE && + (s->s_blocksize == 1024 || s->s_blocksize == 2048 || + s->s_blocksize == 4096)) { + brelse(bh); + set_blocksize(dev, s->s_blocksize); + bh = bread (dev, 0, s->s_blocksize); + if(!bh) return NULL; + sp = (struct xiafs_super_block *) (((char *)bh->b_data) + BLOCK_SIZE) ; + }; + s->u.xiafs_sb.s_nzones = sp->s_nzones; + s->u.xiafs_sb.s_ninodes = sp->s_ninodes; + s->u.xiafs_sb.s_ndatazones = sp->s_ndatazones; + s->u.xiafs_sb.s_imap_zones = sp->s_imap_zones; + s->u.xiafs_sb.s_zmap_zones = sp->s_zmap_zones; + s->u.xiafs_sb.s_firstdatazone = sp->s_firstdatazone; + s->u.xiafs_sb.s_zone_shift = sp->s_zone_shift; + s->u.xiafs_sb.s_max_size = sp->s_max_size; + brelse(bh); + for (i=0;i < _XIAFS_IMAP_SLOTS;i++) { + s->u.xiafs_sb.s_imap_buf[i] = NULL; + s->u.xiafs_sb.s_imap_iznr[i] = -1; + } + for (i=0;i < _XIAFS_ZMAP_SLOTS;i++) { + s->u.xiafs_sb.s_zmap_buf[i] = NULL; + s->u.xiafs_sb.s_zmap_zznr[i] = -1; + } + z=1; + if ( s->u.xiafs_sb.s_imap_zones > _XIAFS_IMAP_SLOTS ) + s->u.xiafs_sb.s_imap_cached=1; + else { + s->u.xiafs_sb.s_imap_cached=0; + for (i=0 ; i < s->u.xiafs_sb.s_imap_zones ; i++) { + if (!(s->u.xiafs_sb.s_imap_buf[i]=bread(dev, z++, XIAFS_ZSIZE(s)))) + goto xiafs_read_super_fail; + s->u.xiafs_sb.s_imap_iznr[i]=i; + } + } + if ( s->u.xiafs_sb.s_zmap_zones > _XIAFS_ZMAP_SLOTS ) + s->u.xiafs_sb.s_zmap_cached=1; + else { + s->u.xiafs_sb.s_zmap_cached=0; + for (i=0 ; i < s->u.xiafs_sb.s_zmap_zones ; i++) { + if (!(s->u.xiafs_sb.s_zmap_buf[i]=bread(dev, z++, XIAFS_ZSIZE(s)))) + goto xiafs_read_super_fail; + s->u.xiafs_sb.s_zmap_zznr[i]=i; + } + } + /* set up enough so that it can read an inode */ + s->s_dev = dev; + s->s_op = &xiafs_sops; + s->s_mounted = iget(s, _XIAFS_ROOT_INO); + if (!s->s_mounted) + goto xiafs_read_super_fail; + unlock_super(s); + random_nr=CURRENT_TIME; + return s; + +xiafs_read_super_fail: + for(i=0; i < _XIAFS_IMAP_SLOTS; i++) + brelse(s->u.xiafs_sb.s_imap_buf[i]); + for(i=0; i < _XIAFS_ZMAP_SLOTS; i++) + brelse(s->u.xiafs_sb.s_zmap_buf[i]); + s->s_dev=0; + unlock_super(s); + printk("XIA-FS: read bitmaps failed (%s %d)\n", WHERE_ERR); + return NULL; +} + +void xiafs_statfs(struct super_block *sb, struct statfs *buf) +{ + long tmp; + + put_fs_long(_XIAFS_SUPER_MAGIC, &buf->f_type); + put_fs_long(XIAFS_ZSIZE(sb), &buf->f_bsize); + put_fs_long(sb->u.xiafs_sb.s_ndatazones, &buf->f_blocks); + tmp = xiafs_count_free_zones(sb); + put_fs_long(tmp, &buf->f_bfree); + put_fs_long(tmp, &buf->f_bavail); + put_fs_long(sb->u.xiafs_sb.s_ninodes, &buf->f_files); + put_fs_long(xiafs_count_free_inodes(sb), &buf->f_ffree); + put_fs_long(_XIAFS_NAME_LEN, &buf->f_namelen); + /* don't know what should be put in buf->f_fsid */ +} + +static int zone_bmap(struct buffer_head * bh, int nr) +{ + int tmp; + + if (!bh) + return 0; + tmp = ((u_long *) bh->b_data)[nr]; + brelse(bh); + return tmp; +} + +int xiafs_bmap(struct inode * inode,int zone) +{ + int i; + + if (zone < 0) { + printk("XIA-FS: block < 0 (%s %d)\n", WHERE_ERR); + return 0; + } + if (zone >= 8+(1+XIAFS_ADDRS_PER_Z(inode->i_sb))*XIAFS_ADDRS_PER_Z(inode->i_sb)) { + printk("XIA-FS: zone > big (%s %d)\n", WHERE_ERR); + return 0; + } + if (!IS_RDONLY (inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + if (zone < 8) + return inode->u.xiafs_i.i_zone[zone]; + zone -= 8; + if (zone < XIAFS_ADDRS_PER_Z(inode->i_sb)) { + i = inode->u.xiafs_i.i_ind_zone; + if (i) + i = zone_bmap(bread(inode->i_dev, i, XIAFS_ZSIZE(inode->i_sb)), zone); + return i; + } + zone -= XIAFS_ADDRS_PER_Z(inode->i_sb); + i = inode->u.xiafs_i.i_dind_zone; + if (i) + i = zone_bmap(bread(inode->i_dev, i, XIAFS_ZSIZE(inode->i_sb)), + zone >> XIAFS_ADDRS_PER_Z_BITS(inode->i_sb)); + if (i) + i= zone_bmap(bread(inode->i_dev,i, XIAFS_ZSIZE(inode->i_sb)), + zone & (XIAFS_ADDRS_PER_Z(inode->i_sb)-1)); + return i; +} + +static u_long get_prev_addr(struct inode * inode, int zone) +{ + u_long tmp; + + if (zone > 0) + while (--zone >= 0) /* only files with holes suffer */ + if ((tmp=xiafs_bmap(inode, zone))) + return tmp; + random_nr=(random_nr+23)%inode->i_sb->u.xiafs_sb.s_ndatazones; + return random_nr + inode->i_sb->u.xiafs_sb.s_firstdatazone; +} + +static struct buffer_head * +dt_getblk(struct inode * inode, u_long *lp, int create, u_long prev_addr) +{ + int tmp; + struct buffer_head * result; + +repeat: + if ((tmp=*lp)) { + result = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (tmp == *lp) + return result; + brelse(result); + goto repeat; + } + if (!create) + return NULL; + tmp = xiafs_new_zone(inode->i_sb, prev_addr); + if (!tmp) + return NULL; + result = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (*lp) { + xiafs_free_zone(inode->i_sb, tmp); + brelse(result); + goto repeat; + } + *lp = tmp; + inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb); + return result; +} + +static struct buffer_head * +indt_getblk(struct inode * inode, struct buffer_head * bh, + int nr, int create, u_long prev_addr) +{ + int tmp; + u_long *lp; + struct buffer_head * result; + + if (!bh) + return NULL; + if (!bh->b_uptodate) { + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (!bh->b_uptodate) { + brelse(bh); + return NULL; + } + } + lp = nr + (u_long *) bh->b_data; +repeat: + if ((tmp=*lp)) { + result = getblk(bh->b_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (tmp == *lp) { + brelse(bh); + return result; + } + brelse(result); + goto repeat; + } + if (!create) { + brelse(bh); + return NULL; + } + tmp = xiafs_new_zone(inode->i_sb, prev_addr); + if (!tmp) { + brelse(bh); + return NULL; + } + result = getblk(bh->b_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (*lp) { + xiafs_free_zone(inode->i_sb, tmp); + brelse(result); + goto repeat; + } + *lp = tmp; + inode->i_blocks+=2 << XIAFS_ZSHIFT(inode->i_sb); + bh->b_dirt = 1; + brelse(bh); + return result; +} + +struct buffer_head * xiafs_getblk(struct inode * inode, int zone, int create) +{ + struct buffer_head * bh; + u_long prev_addr=0; + + if (zone<0) { + printk("XIA-FS: zone < 0 (%s %d)\n", WHERE_ERR); + return NULL; + } + if (zone >= 8+(1+XIAFS_ADDRS_PER_Z(inode->i_sb))*XIAFS_ADDRS_PER_Z(inode->i_sb)) { + if (!create) + printk("XIA-FS: zone > big (%s %d)\n", WHERE_ERR); + return NULL; + } + if (create) + prev_addr=get_prev_addr(inode, zone); + if (zone < 8) + return dt_getblk(inode, zone+inode->u.xiafs_i.i_zone, create, prev_addr); + zone -= 8; + if (zone < XIAFS_ADDRS_PER_Z(inode->i_sb)) { + bh = dt_getblk(inode, &(inode->u.xiafs_i.i_ind_zone), create, prev_addr); + bh = indt_getblk(inode, bh, zone, create, prev_addr); + return bh; + } + zone -= XIAFS_ADDRS_PER_Z(inode->i_sb); + bh = dt_getblk(inode, &(inode->u.xiafs_i.i_dind_zone), create, prev_addr); + bh = indt_getblk(inode, bh, zone>>XIAFS_ADDRS_PER_Z_BITS(inode->i_sb), + create, prev_addr); + bh = indt_getblk(inode, bh, zone&(XIAFS_ADDRS_PER_Z(inode->i_sb)-1), + create, prev_addr); + return bh; +} + +struct buffer_head * xiafs_bread(struct inode * inode, int zone, int create) +{ + struct buffer_head * bh; + + bh = xiafs_getblk(inode, zone, create); + if (!bh || bh->b_uptodate) + return bh; + ll_rw_block(READ, 1, &bh); + wait_on_buffer(bh); + if (bh->b_uptodate) + return bh; + brelse(bh); + return NULL; +} + +void xiafs_read_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct xiafs_inode * raw_inode; + int zone; + ino_t ino; + + ino = inode->i_ino; + inode->i_op = NULL; + inode->i_mode=0; + if (!ino || ino > inode->i_sb->u.xiafs_sb.s_ninodes) { + printk("XIA-FS: bad inode number (%s %d)\n", WHERE_ERR); + return; + } + zone = 1 + inode->i_sb->u.xiafs_sb.s_imap_zones + + inode->i_sb->u.xiafs_sb.s_zmap_zones + + (ino-1)/ XIAFS_INODES_PER_Z(inode->i_sb); + if (!(bh=bread(inode->i_dev, zone, XIAFS_ZSIZE(inode->i_sb)))) { + printk("XIA-FS: read i-node zone failed (%s %d)\n", WHERE_ERR); + return; + } + raw_inode = ((struct xiafs_inode *) bh->b_data) + + ((ino-1) & (XIAFS_INODES_PER_Z(inode->i_sb) - 1)); + inode->i_mode = raw_inode->i_mode; + inode->i_uid = raw_inode->i_uid; + inode->i_gid = raw_inode->i_gid; + inode->i_nlink = raw_inode->i_nlinks; + inode->i_size = raw_inode->i_size; + inode->i_mtime = raw_inode->i_mtime; + inode->i_atime = raw_inode->i_atime; + inode->i_ctime = raw_inode->i_ctime; + inode->i_blksize = XIAFS_ZSIZE(inode->i_sb); + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) { + inode->i_blocks=0; + inode->i_rdev = raw_inode->i_zone[0]; + } else { + XIAFS_GET_BLOCKS(raw_inode, inode->i_blocks); + for (zone = 0; zone < 8; zone++) + inode->u.xiafs_i.i_zone[zone] = raw_inode->i_zone[zone] & 0xffffff; + inode->u.xiafs_i.i_ind_zone = raw_inode->i_ind_zone & 0xffffff; + inode->u.xiafs_i.i_dind_zone = raw_inode->i_dind_zone & 0xffffff; + } + brelse(bh); + if (S_ISREG(inode->i_mode)) + inode->i_op = &xiafs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) + inode->i_op = &xiafs_dir_inode_operations; + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &xiafs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); +} + +static struct buffer_head * xiafs_update_inode(struct inode * inode) +{ + struct buffer_head * bh; + struct xiafs_inode * raw_inode; + int zone; + ino_t ino; + + if (IS_RDONLY (inode)) { + printk("XIA-FS: write_inode on a read-only filesystem (%s %d)\n", WHERE_ERR); + inode->i_dirt = 0; + return 0; + } + + ino = inode->i_ino; + if (!ino || ino > inode->i_sb->u.xiafs_sb.s_ninodes) { + printk("XIA-FS: bad inode number (%s %d)\n", WHERE_ERR); + inode->i_dirt=0; + return 0; + } + zone = 1 + inode->i_sb->u.xiafs_sb.s_imap_zones + + inode->i_sb->u.xiafs_sb.s_zmap_zones + + (ino-1) / XIAFS_INODES_PER_Z(inode->i_sb); + if (!(bh=bread(inode->i_dev, zone, XIAFS_ZSIZE(inode->i_sb)))) { + printk("XIA-FS: read i-node zone failed (%s %d)\n", WHERE_ERR); + inode->i_dirt=0; + return 0; + } + raw_inode = ((struct xiafs_inode *)bh->b_data) + + ((ino-1) & (XIAFS_INODES_PER_Z(inode->i_sb) -1)); + raw_inode->i_mode = inode->i_mode; + raw_inode->i_uid = inode->i_uid; + raw_inode->i_gid = inode->i_gid; + raw_inode->i_nlinks = inode->i_nlink; + raw_inode->i_size = inode->i_size; + raw_inode->i_atime = inode->i_atime; + raw_inode->i_ctime = inode->i_ctime; + raw_inode->i_mtime = inode->i_mtime; + if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode)) + raw_inode->i_zone[0] = inode->i_rdev; + else { + XIAFS_PUT_BLOCKS(raw_inode, inode->i_blocks); + for (zone = 0; zone < 8; zone++) + raw_inode->i_zone[zone] = (raw_inode->i_zone[zone] & 0xff000000) + | (inode->u.xiafs_i.i_zone[zone] & 0xffffff); + raw_inode->i_ind_zone = (raw_inode->i_ind_zone & 0xff000000) + | (inode->u.xiafs_i.i_ind_zone & 0xffffff); + raw_inode->i_dind_zone = (raw_inode->i_dind_zone & 0xff000000) + | (inode->u.xiafs_i.i_dind_zone & 0xffffff); + } + inode->i_dirt=0; + bh->b_dirt=1; + return bh; +} + + +void xiafs_write_inode(struct inode * inode) +{ + struct buffer_head * bh; + bh = xiafs_update_inode(inode); + brelse (bh); +} + +int xiafs_sync_inode (struct inode *inode) +{ + int err = 0; + struct buffer_head *bh; + + bh = xiafs_update_inode(inode); + if (bh && bh->b_dirt) + { + ll_rw_block(WRITE, 1, &bh); + wait_on_buffer(bh); + if (bh->b_req && !bh->b_uptodate) + { + printk ("IO error syncing xiafs inode [%04X:%lu]\n", + inode->i_dev, inode->i_ino); + err = -1; + } + } + else if (!bh) + err = -1; + brelse (bh); + return err; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/namei.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/namei.c new file mode 100644 index 000000000..52c9a6812 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/namei.c @@ -0,0 +1,847 @@ +/* + * Linux/fs/xiafs/namei.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/namei.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "xiafs_mac.h" + +#define RNDUP4(x) ((3+(u_long)(x)) & ~3) +/* + * ok, we cannot use strncmp, as the name is not in our data space. + * Thus we'll have to use xiafs_match. No big problem. Match also makes + * some sanity tests. + * + * NOTE! unlike strncmp, xiafs_match returns 1 for success, 0 for failure. + */ +static int xiafs_match(int len, const char * name, struct xiafs_direct * dep) +{ + int i; + + if (!dep || !dep->d_ino || len > _XIAFS_NAME_LEN) + return 0; + /* "" means "." ---> so paths like "/usr/lib//libc.a" work */ + if (!len && (dep->d_name[0]=='.') && (dep->d_name[1]=='\0')) + return 1; + if (len != dep->d_name_len) + return 0; + for (i=0; i < len; i++) + if (*name++ != dep->d_name[i]) + return 0; + return 1; +} + +/* + * xiafs_find_entry() + * + * finds an entry in the specified directory with the wanted name. It + * returns the cache buffer in which the entry was found, and the entry + * itself (as a parameter - res_dir). It does NOT read the inode of the + * entry - you'll have to do that yourself if you want to. + */ +static struct buffer_head * +xiafs_find_entry(struct inode * inode, const char * name, int namelen, + struct xiafs_direct ** res_dir, struct xiafs_direct ** res_pre) +{ + int i, zones, pos; + struct buffer_head * bh; + struct xiafs_direct * dep, * dep_pre; + + *res_dir = NULL; + if (!inode) + return NULL; + if (namelen > _XIAFS_NAME_LEN) + return NULL; + + if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1)) { + printk("XIA-FS: bad dir size (%s %d)\n", WHERE_ERR); + return NULL; + } + zones=inode->i_size >> XIAFS_ZSIZE_BITS(inode->i_sb); + for (i=0; i < zones; i++ ) { + bh = xiafs_bread(inode, i, 0); + if (!bh) + continue; + dep_pre=dep=(struct xiafs_direct *)bh->b_data; + if (!i && (dep->d_rec_len != 12 || !dep->d_ino || + dep->d_name_len != 1 || strcmp(dep->d_name, "."))) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + brelse(bh); + return NULL; + } + pos = 0; + while ( pos < XIAFS_ZSIZE(inode->i_sb) ) { + if (dep->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes || + dep->d_rec_len < 12 || + dep->d_rec_len+(char *)dep > bh->b_data+XIAFS_ZSIZE(inode->i_sb) || + dep->d_name_len + 8 > dep->d_rec_len || dep->d_name_len <= 0 || + dep->d_name[dep->d_name_len] ) { + brelse(bh); + return NULL; + } + if (xiafs_match(namelen, name, dep)) { + *res_dir=dep; + if (res_pre) + *res_pre=dep_pre; + return bh; + } + pos += dep->d_rec_len; + dep_pre=dep; + dep=(struct xiafs_direct *)(bh->b_data + pos); + } + brelse(bh); + if (pos > XIAFS_ZSIZE(inode->i_sb)) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + return NULL; + } + } + return NULL; +} + +int xiafs_lookup(struct inode * dir, const char * name, int len, + struct inode ** result) +{ + int ino; + struct xiafs_direct * dep; + struct buffer_head * bh; + + *result = NULL; + if (!dir) + return -ENOENT; + if (!S_ISDIR(dir->i_mode)) { + iput(dir); + return -ENOENT; + } + if (!(bh = xiafs_find_entry(dir, name, len, &dep, NULL))) { + iput(dir); + return -ENOENT; + } + ino = dep->d_ino; + brelse(bh); + if (!(*result = iget(dir->i_sb, ino))) { + iput(dir); + return -EACCES; + } + iput(dir); + return 0; +} + +/* + * xiafs_add_entry() + * + * adds a file entry to the specified directory, using the same + * semantics as xiafs_find_entry(). It returns NULL if it failed. + * + * NOTE!! The inode part of 'de' is left at 0 - which means you + * may not sleep between calling this and putting something into + * the entry, as someone else might have used it while you slept. + */ +static struct buffer_head * xiafs_add_entry(struct inode * dir, + const char * name, int namelen, struct xiafs_direct ** res_dir, + struct xiafs_direct ** res_pre) +{ + int i, pos, offset; + struct buffer_head * bh; + struct xiafs_direct * de, * de_pre; + + *res_dir = NULL; + if (!dir || !namelen || namelen > _XIAFS_NAME_LEN) + return NULL; + + if (dir->i_size & (XIAFS_ZSIZE(dir->i_sb) - 1)) { + printk("XIA-FS: bad dir size (%s %d)\n", WHERE_ERR); + return NULL; + } + pos=0; + for ( ; ; ) { + bh = xiafs_bread(dir, pos >> XIAFS_ZSIZE_BITS(dir->i_sb), pos ? 1:0); + if (!bh) + return NULL; + de_pre=de=(struct xiafs_direct *)bh->b_data; + if (!pos) { + if (de->d_rec_len != 12 || !de->d_ino || de->d_name_len != 1 || + strcmp(de->d_name, ".")) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + brelse(bh); + return NULL; + } + offset = 12; + de_pre=de=(struct xiafs_direct *)(bh->b_data+12); + } else + offset = 0; + while (offset < XIAFS_ZSIZE(dir->i_sb)) { + if (pos >= dir->i_size) { + de->d_ino=0; + de->d_name_len=0; + de->d_name[0]=0; + de->d_rec_len=XIAFS_ZSIZE(dir->i_sb); + dir->i_size += XIAFS_ZSIZE(dir->i_sb); + dir->i_dirt = 1; + } else { + if (de->d_ino > dir->i_sb->u.xiafs_sb.s_ninodes || + de->d_rec_len < 12 || + (char *)de+de->d_rec_len > bh->b_data+XIAFS_ZSIZE(dir->i_sb) || + de->d_name_len + 8 > de->d_rec_len || + de->d_name[de->d_name_len]) { + printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR); + brelse(bh); + return NULL; + } + if (de->d_ino && + RNDUP4(de->d_name_len)+RNDUP4(namelen)+16<=de->d_rec_len) { + i=RNDUP4(de->d_name_len)+8; + de_pre=de; + de=(struct xiafs_direct *)(i+(u_char *)de_pre); + de->d_ino=0; + de->d_rec_len=de_pre->d_rec_len-i; + de_pre->d_rec_len=i; + } + } + if (!de->d_ino && RNDUP4(namelen)+8 <= de->d_rec_len) { + /* + * XXX all times should be set by caller upon successful + * completion. + */ + dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + memcpy(de->d_name, name, namelen); + de->d_name[namelen]=0; + de->d_name_len=namelen; + bh->b_dirt = 1; + *res_dir = de; + if (res_pre) + *res_pre = de_pre; + return bh; + } + offset+=de->d_rec_len; + de_pre=de; + de=(struct xiafs_direct *)(bh->b_data+offset); + } + brelse(bh); + if (offset > XIAFS_ZSIZE(dir->i_sb)) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + return NULL; + } + pos+=XIAFS_ZSIZE(dir->i_sb); + } + return NULL; +} + +int xiafs_create(struct inode * dir, const char * name, int len, int mode, + struct inode ** result) +{ + struct inode * inode; + struct buffer_head * bh; + struct xiafs_direct * de; + + *result = NULL; + if (!dir) + return -ENOENT; + inode = xiafs_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &xiafs_file_inode_operations; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = xiafs_add_entry(dir, name, len, &de, NULL); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->d_ino = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *result = inode; + return 0; +} + +int xiafs_mknod(struct inode *dir, const char *name, int len, int mode, int rdev) +{ + struct inode * inode; + struct buffer_head * bh; + struct xiafs_direct * de; + + if (!dir) + return -ENOENT; + bh = xiafs_find_entry(dir,name,len,&de, NULL); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + inode = xiafs_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_op = NULL; + if (S_ISREG(inode->i_mode)) + inode->i_op = &xiafs_file_inode_operations; + else if (S_ISDIR(inode->i_mode)) { + inode->i_op = &xiafs_dir_inode_operations; + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + } + else if (S_ISLNK(inode->i_mode)) + inode->i_op = &xiafs_symlink_inode_operations; + else if (S_ISCHR(inode->i_mode)) + inode->i_op = &chrdev_inode_operations; + else if (S_ISBLK(inode->i_mode)) + inode->i_op = &blkdev_inode_operations; + else if (S_ISFIFO(inode->i_mode)) + init_fifo(inode); + if (S_ISBLK(mode) || S_ISCHR(mode)) + inode->i_rdev = rdev; + inode->i_atime = inode->i_ctime = inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + bh = xiafs_add_entry(dir, name, len, &de, NULL); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->d_ino = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode) +{ + struct inode * inode; + struct buffer_head * bh, *dir_block; + struct xiafs_direct * de; + + bh = xiafs_find_entry(dir,name,len,&de, NULL); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + if (dir->i_nlink > 64000) { + iput(dir); + return -EMLINK; + } + inode = xiafs_new_inode(dir); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_op = &xiafs_dir_inode_operations; + inode->i_size = XIAFS_ZSIZE(dir->i_sb); + inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME; + dir_block = xiafs_bread(inode,0,1); + if (!dir_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + de = (struct xiafs_direct *) dir_block->b_data; + de->d_ino=inode->i_ino; + strcpy(de->d_name,"."); + de->d_name_len=1; + de->d_rec_len=12; + de =(struct xiafs_direct *)(12 + dir_block->b_data); + de->d_ino = dir->i_ino; + strcpy(de->d_name,".."); + de->d_name_len=2; + de->d_rec_len=XIAFS_ZSIZE(dir->i_sb)-12; + inode->i_nlink = 2; + dir_block->b_dirt = 1; + brelse(dir_block); + inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->umask); + if (dir->i_mode & S_ISGID) + inode->i_mode |= S_ISGID; + inode->i_dirt = 1; + bh = xiafs_add_entry(dir, name, len, &de, NULL); + if (!bh) { + iput(dir); + inode->i_nlink=0; + iput(inode); + return -ENOSPC; + } + de->d_ino = inode->i_ino; + bh->b_dirt = 1; + dir->i_nlink++; + dir->i_dirt = 1; + iput(dir); + iput(inode); + brelse(bh); + return 0; +} + +/* + * routine to check that the specified directory is empty (for rmdir) + */ +static int empty_dir(struct inode * inode) +{ + int i, zones, offset; + struct buffer_head * bh; + struct xiafs_direct * de; + + if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb)-1) ) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + return 1; + } + + zones=inode->i_size >> XIAFS_ZSIZE_BITS(inode->i_sb); + for (i=0; i < zones; i++) { + bh = xiafs_bread(inode, i, 0); + if (!i) { + if (!bh) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + return 1; + } + de=(struct xiafs_direct *)bh->b_data; + if (de->d_ino != inode->i_ino || strcmp(".", de->d_name) || + de->d_rec_len != 12 ) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + brelse(bh); + return 1; + } + de=(struct xiafs_direct *)(12 + bh->b_data); + if (!de->d_ino || strcmp("..", de->d_name)) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + brelse(bh); + return 1; + } + offset=de->d_rec_len+12; + } + else + offset = 0; + if (!bh) + continue; + while (offset < XIAFS_ZSIZE(inode->i_sb)) { + de=(struct xiafs_direct *)(bh->b_data+offset); + if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes || + de->d_rec_len < 12 || + (char *)de+de->d_rec_len > bh->b_data+XIAFS_ZSIZE(inode->i_sb) || + de->d_name_len + 8 > de->d_rec_len || + de->d_name[de->d_name_len]) { + printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR); + brelse(bh); + return 1; + } + if (de->d_ino) { + brelse(bh); + return 0; + } + offset+=de->d_rec_len; + } + brelse(bh); + } + return 1; +} + +static void xiafs_rm_entry(struct xiafs_direct *de, struct xiafs_direct * de_pre) +{ + if (de==de_pre) { + de->d_ino=0; + return; + } + while (de_pre->d_rec_len+(u_char *)de_pre < (u_char *)de) { + if (de_pre->d_rec_len < 12) { + printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR); + return; + } + de_pre=(struct xiafs_direct *)(de_pre->d_rec_len+(u_char *)de_pre); + } + if (de_pre->d_rec_len+(u_char *)de_pre > (u_char *)de) { + printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR); + return; + } + de_pre->d_rec_len+=de->d_rec_len; +} + +int xiafs_rmdir(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct xiafs_direct * de, * de_pre; + + inode = NULL; + bh = xiafs_find_entry(dir, name, len, &de, &de_pre); + retval = -ENOENT; + if (!bh) + goto end_rmdir; + retval = -EPERM; + if (!(inode = iget(dir->i_sb, de->d_ino))) + goto end_rmdir; + if ((dir->i_mode & S_ISVTX) && current->euid && + inode->i_uid != current->euid) + goto end_rmdir; + if (inode->i_dev != dir->i_dev) + goto end_rmdir; + if (inode == dir) /* we may not delete ".", but "../dir" is ok */ + goto end_rmdir; + if (!S_ISDIR(inode->i_mode)) { + retval = -ENOTDIR; + goto end_rmdir; + } + if (!empty_dir(inode)) { + retval = -ENOTEMPTY; + goto end_rmdir; + } + if (inode->i_count > 1) { + retval = -EBUSY; + goto end_rmdir; + } + if (inode->i_nlink != 2) + printk("XIA-FS: empty directory has nlink!=2 (%s %d)\n", WHERE_ERR); + xiafs_rm_entry(de, de_pre); + bh->b_dirt = 1; + inode->i_nlink=0; + inode->i_dirt=1; + dir->i_nlink--; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt=1; + retval = 0; +end_rmdir: + iput(dir); + iput(inode); + brelse(bh); + return retval; +} + +int xiafs_unlink(struct inode * dir, const char * name, int len) +{ + int retval; + struct inode * inode; + struct buffer_head * bh; + struct xiafs_direct * de, * de_pre; + +repeat: + retval = -ENOENT; + inode = NULL; + bh = xiafs_find_entry(dir, name, len, &de, &de_pre); + if (!bh) + goto end_unlink; + if (!(inode = iget(dir->i_sb, de->d_ino))) + goto end_unlink; + retval = -EPERM; + if (S_ISDIR(inode->i_mode)) + goto end_unlink; + if (de->d_ino != inode->i_ino) { + iput(inode); + brelse(bh); + current->counter = 0; + schedule(); + goto repeat; + } + if ((dir->i_mode & S_ISVTX) && !suser() && + current->euid != inode->i_uid && + current->euid != dir->i_uid) + goto end_unlink; + if (!inode->i_nlink) { + printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR); + inode->i_nlink=1; + } + xiafs_rm_entry(de, de_pre); + bh->b_dirt = 1; + inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME; + dir->i_dirt = 1; + inode->i_nlink--; + inode->i_dirt = 1; + retval = 0; +end_unlink: + brelse(bh); + iput(inode); + iput(dir); + return retval; +} + +int xiafs_symlink(struct inode * dir, const char * name, + int len, const char * symname) +{ + struct xiafs_direct * de; + struct inode * inode = NULL; + struct buffer_head * bh = NULL, * name_block = NULL; + int i; + char c; + + bh = xiafs_find_entry(dir,name,len, &de, NULL); + if (bh) { + brelse(bh); + iput(dir); + return -EEXIST; + } + if (!(inode = xiafs_new_inode(dir))) { + iput(dir); + return -ENOSPC; + } + inode->i_mode = S_IFLNK | S_IRWXUGO; + inode->i_op = &xiafs_symlink_inode_operations; + name_block = xiafs_bread(inode,0,1); + if (!name_block) { + iput(dir); + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + return -ENOSPC; + } + for (i = 0; i < BLOCK_SIZE-1 && (c=*symname++); i++) + name_block->b_data[i] = c; + name_block->b_data[i] = 0; + name_block->b_dirt = 1; + brelse(name_block); + inode->i_size = i; + inode->i_dirt = 1; + bh = xiafs_add_entry(dir, name, len, &de, NULL); + if (!bh) { + inode->i_nlink--; + inode->i_dirt = 1; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->d_ino = inode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + iput(inode); + return 0; +} + +int xiafs_link(struct inode * oldinode, struct inode * dir, + const char * name, int len) +{ + struct xiafs_direct * de; + struct buffer_head * bh; + + if (S_ISDIR(oldinode->i_mode)) { + iput(oldinode); + iput(dir); + return -EPERM; + } + if (oldinode->i_nlink > 64000) { + iput(oldinode); + iput(dir); + return -EMLINK; + } + bh = xiafs_find_entry(dir, name, len, &de, NULL); + if (bh) { + brelse(bh); + iput(dir); + iput(oldinode); + return -EEXIST; + } + bh = xiafs_add_entry(dir, name, len, &de, NULL); + if (!bh) { + iput(dir); + iput(oldinode); + return -ENOSPC; + } + de->d_ino = oldinode->i_ino; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + oldinode->i_nlink++; + oldinode->i_ctime = CURRENT_TIME; + oldinode->i_dirt = 1; + iput(oldinode); + return 0; +} + +static int subdir(struct inode * new_inode, struct inode * old_inode) +{ + int ino; + int result; + + new_inode->i_count++; + result = 0; + for (;;) { + if (new_inode == old_inode) { + result = 1; + break; + } + if (new_inode->i_dev != old_inode->i_dev) + break; + ino = new_inode->i_ino; + if (xiafs_lookup(new_inode,"..",2,&new_inode)) + break; + if (new_inode->i_ino == ino) + break; + } + iput(new_inode); + return result; +} + +#define PARENT_INO(buffer) \ + (((struct xiafs_direct *) ((u_char *)(buffer) + 12))->d_ino) + +/* + * rename uses retry to avoid race-conditions: at least they should be minimal. + * it tries to allocate all the blocks, then sanity-checks, and if the sanity- + * checks fail, it tries to restart itself again. Very practical - no changes + * are done until we know everything works ok.. and then all the changes can be + * done in one fell swoop when we have claimed all the buffers needed. + * + * Anybody can rename anything with this: the permission checks are left to the + * higher-level routines. + */ +static int do_xiafs_rename(struct inode * old_dir, const char * old_name, + int old_len, struct inode * new_dir, + const char * new_name, int new_len) +{ + struct inode * old_inode, * new_inode; + struct buffer_head * old_bh, * new_bh, * dir_bh; + struct xiafs_direct * old_de, * old_de_pre, * new_de, * new_de_pre; + int retval; + +try_again: + old_inode = new_inode = NULL; + old_bh = new_bh = dir_bh = NULL; + old_bh = xiafs_find_entry(old_dir, old_name, old_len, &old_de, &old_de_pre); + retval = -ENOENT; + if (!old_bh) + goto end_rename; + old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */ + if (!old_inode) + goto end_rename; + retval = -EPERM; + if ((old_dir->i_mode & S_ISVTX) && + current->euid != old_inode->i_uid && + current->euid != old_dir->i_uid && !suser()) + goto end_rename; + new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL); + if (new_bh) { + new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0); + if (!new_inode) { + brelse(new_bh); + new_bh = NULL; + } + } + if (new_inode == old_inode) { + retval = 0; + goto end_rename; + } + if (new_inode && S_ISDIR(new_inode->i_mode)) { + retval = -EEXIST; + goto end_rename; + } + retval = -EPERM; + if (new_inode && (new_dir->i_mode & S_ISVTX) && + current->euid != new_inode->i_uid && + current->euid != new_dir->i_uid && !suser()) + goto end_rename; + if (S_ISDIR(old_inode->i_mode)) { + retval = -EEXIST; + if (new_bh) + goto end_rename; + retval = -EACCES; + if (!permission(old_inode, MAY_WRITE)) + goto end_rename; + retval = -EINVAL; + if (subdir(new_dir, old_inode)) + goto end_rename; + retval = -EIO; + dir_bh = xiafs_bread(old_inode,0,0); + if (!dir_bh) + goto end_rename; + if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino) + goto end_rename; + retval = -EMLINK; + if (new_dir->i_nlink > 64000) + goto end_rename; + } + if (!new_bh) + new_bh = xiafs_add_entry(new_dir, new_name, new_len, &new_de, &new_de_pre); + retval = -ENOSPC; + if (!new_bh) + goto end_rename; + /* sanity checking */ + if ( (new_inode && (new_de->d_ino != new_inode->i_ino)) + || (new_de->d_ino && !new_inode) + || (old_de->d_ino != old_inode->i_ino)) { + xiafs_rm_entry(new_de, new_de_pre); + brelse(old_bh); + brelse(new_bh); + brelse(dir_bh); + iput(old_inode); + iput(new_inode); + current->counter=0; + schedule(); + goto try_again; + } + xiafs_rm_entry(old_de, old_de_pre); + new_de->d_ino = old_inode->i_ino; + if (new_inode) { + new_inode->i_nlink--; + new_inode->i_dirt = 1; + } + old_bh->b_dirt = 1; + new_bh->b_dirt = 1; + if (dir_bh) { + PARENT_INO(dir_bh->b_data) = new_dir->i_ino; + dir_bh->b_dirt = 1; + old_dir->i_nlink--; + new_dir->i_nlink++; + old_dir->i_dirt = 1; + new_dir->i_dirt = 1; + } + retval = 0; +end_rename: + brelse(dir_bh); + brelse(old_bh); + brelse(new_bh); + iput(old_inode); + iput(new_inode); + iput(old_dir); + iput(new_dir); + return retval; +} + +/* + * Ok, rename also locks out other renames, as they can change the parent of + * a directory, and we don't want any races. Other races are checked for by + * "do_rename()", which restarts if there are inconsistencies. + * + * Note that there is no race between different filesystems: it's only within + * the same device that races occur: many renames can happen at once, as long + * as they are on different partitions. + */ +int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len) +{ + static struct wait_queue * wait = NULL; + static int lock = 0; + int result; + + while (lock) + sleep_on(&wait); + lock = 1; + result = do_xiafs_rename(old_dir, old_name, old_len, + new_dir, new_name, new_len); + lock = 0; + wake_up(&wait); + return result; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/symlink.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/symlink.c new file mode 100644 index 000000000..e3e963bef --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/symlink.c @@ -0,0 +1,118 @@ +/* + * linux/fs/xiafs/symlink.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/symlink.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +#include + +#include +#include +#include +#include +#include + +static int +xiafs_readlink(struct inode *, char *, int); + +static int +xiafs_follow_link(struct inode *, struct inode *, int, int, struct inode **); + +/* + * symlinks can't do much... + */ +struct inode_operations xiafs_symlink_inode_operations = { + NULL, /* no file-operations */ + NULL, /* create */ + NULL, /* lookup */ + NULL, /* link */ + NULL, /* unlink */ + NULL, /* symlink */ + NULL, /* mkdir */ + NULL, /* rmdir */ + NULL, /* mknod */ + NULL, /* rename */ + xiafs_readlink, /* readlink */ + xiafs_follow_link, /* follow_link */ + NULL, /* bmap */ + NULL, /* truncate */ + NULL /* permission */ +}; + +static int xiafs_readlink(struct inode * inode, char * buffer, int buflen) +{ + struct buffer_head * bh; + int i; + char c; + + if (!S_ISLNK(inode->i_mode)) { + iput(inode); + return -EINVAL; + } + if (buflen > BLOCK_SIZE) + buflen = BLOCK_SIZE; + bh = xiafs_bread(inode, 0, 0); + if (!IS_RDONLY (inode)) { + inode->i_atime=CURRENT_TIME; + inode->i_dirt=1; + } + iput(inode); + if (!bh) + return 0; + for (i=0; i < buflen && (c=bh->b_data[i]); i++) + put_fs_byte(c, buffer++); + if (i < buflen-1) + put_fs_byte((char)0, buffer); + brelse(bh); + return i; +} + +static int xiafs_follow_link(struct inode * dir, struct inode * inode, + int flag, int mode, struct inode ** res_inode) +{ + int error; + struct buffer_head * bh; + + *res_inode = NULL; + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return -ENOENT; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + *res_inode = inode; + return 0; + } + if (!IS_RDONLY (inode)) { + inode->i_atime=CURRENT_TIME; + inode->i_dirt=1; + } + if (current->link_count > 5) { + iput(inode); + iput(dir); + return -ELOOP; + } + if (!(bh = xiafs_bread(inode, 0, 0))) { + iput(inode); + iput(dir); + return -EIO; + } + iput(inode); + current->link_count++; + error = open_namei(bh->b_data,flag,mode,res_inode,dir); + current->link_count--; + brelse(bh); + return error; +} + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/truncate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/truncate.c new file mode 100644 index 000000000..336dcb0ab --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/truncate.c @@ -0,0 +1,197 @@ +/* + * linux/fs/xiafs/truncate.c + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix/truncate.c + * Copyright (C) Linus Torvalds, 1991, 1992. + * + * This software may be redistributed per Linux Copyright. + */ + +#include +#include +#include +#include +#include + +#include "xiafs_mac.h" + +/* + * Linus' comment: + * + * Truncate has the most races in the whole filesystem: coding it is + * a pain in the a**. Especially as I don't do any locking... + * + * The code may look a bit weird, but that's just because I've tried to + * handle things like file-size changes in a somewhat graceful manner. + * Anyway, truncating a file at the same time somebody else writes to it + * is likely to result in pretty weird behaviour... + * + * The new code handles normal truncates (size = 0) as well as the more + * general case (size = XXX). I hope. + */ + +#define DT_ZONE ((inode->i_size + XIAFS_ZSIZE(inode->i_sb) - 1) \ + >> XIAFS_ZSIZE_BITS(inode->i_sb) ) + +static int trunc_direct(struct inode * inode) +{ + u_long * lp; + struct buffer_head * bh; + int i, tmp; + int retry = 0; + +repeat: + for (i = DT_ZONE ; i < 8 ; i++) { + if (i < DT_ZONE) + goto repeat; + lp=i + inode->u.xiafs_i.i_zone; + if (!(tmp = *lp)) + continue; + bh = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (i < DT_ZONE) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *lp) + retry = 1; + else { + *lp = 0; + inode->i_dirt = 1; + inode->i_blocks-=2 << XIAFS_ZSHIFT(inode->i_sb); + xiafs_free_zone(inode->i_sb, tmp); + } + brelse(bh); + } + return retry; +} + +static int trunc_indirect(struct inode * inode, int addr_off, u_long * lp) +{ + +#define INDT_ZONE (DT_ZONE - addr_off) + + struct buffer_head * bh, * ind_bh; + int i, tmp; + u_long * indp; + int retry = 0; + + if ( !(tmp=*lp) ) + return 0; + ind_bh = bread(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (tmp != *lp) { + brelse(ind_bh); + return 1; + } + if (!ind_bh) { + *lp = 0; + return 0; + } +repeat: + for (i = INDT_ZONE<0?0:INDT_ZONE; i < XIAFS_ADDRS_PER_Z(inode->i_sb); i++) { + if (i < INDT_ZONE) + goto repeat; + indp = i+(u_long *) ind_bh->b_data; + if (!(tmp=*indp)) + continue; + bh = getblk(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (i < INDT_ZONE) { + brelse(bh); + goto repeat; + } + if ((bh && bh->b_count != 1) || tmp != *indp) + retry = 1; + else { + *indp = 0; + ind_bh->b_dirt = 1; + inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb); + xiafs_free_zone(inode->i_sb, tmp); + } + brelse(bh); + } + indp = (u_long *) ind_bh->b_data; + for (i = 0; i < XIAFS_ADDRS_PER_Z(inode->i_sb) && !(*indp++); i++) ; + if (i >= XIAFS_ADDRS_PER_Z(inode->i_sb)) { + if (ind_bh->b_count != 1) + retry = 1; + else { + tmp = *lp; + *lp = 0; + inode->i_blocks-= 2 << XIAFS_ZSHIFT(inode->i_sb); + xiafs_free_zone(inode->i_sb, tmp); + } + } + brelse(ind_bh); + return retry; +} + +static int trunc_dindirect(struct inode * inode) +{ + +#define DINDT_ZONE \ + ((DT_ZONE-XIAFS_ADDRS_PER_Z(inode->i_sb)-8)>>XIAFS_ADDRS_PER_Z_BITS(inode->i_sb)) + + int i, tmp; + struct buffer_head * dind_bh; + u_long * dindp, * lp; + int retry = 0; + + lp = &(inode->u.xiafs_i.i_dind_zone); + if (!(tmp = *lp)) + return 0; + dind_bh = bread(inode->i_dev, tmp, XIAFS_ZSIZE(inode->i_sb)); + if (tmp != *lp) { + brelse(dind_bh); + return 1; + } + if (!dind_bh) { + *lp = 0; + return 0; + } +repeat: + for (i=DINDT_ZONE<0?0:DINDT_ZONE ; i < XIAFS_ADDRS_PER_Z(inode->i_sb) ; i ++) { + if (i < DINDT_ZONE) + goto repeat; + dindp = i+(u_long *) dind_bh->b_data; + retry |= trunc_indirect(inode, + 8+((1+i)<i_sb)), + dindp); + dind_bh->b_dirt = 1; + } + dindp = (u_long *) dind_bh->b_data; + for (i = 0; i < XIAFS_ADDRS_PER_Z(inode->i_sb) && !(*dindp++); i++); + if (i >= XIAFS_ADDRS_PER_Z(inode->i_sb)) { + if (dind_bh->b_count != 1) + retry = 1; + else { + tmp = *lp; + *lp = 0; + inode->i_dirt = 1; + inode->i_blocks-=2 << XIAFS_ZSHIFT(inode->i_sb); + xiafs_free_zone(inode->i_sb, tmp); + } + } + brelse(dind_bh); + return retry; +} + +void xiafs_truncate(struct inode * inode) +{ + int retry; + + if (!(S_ISREG(inode->i_mode) || S_ISDIR(inode->i_mode) || + S_ISLNK(inode->i_mode))) + return; + while (1) { + retry = trunc_direct(inode); + retry |= trunc_indirect(inode, 8, &(inode->u.xiafs_i.i_ind_zone)); + retry |= trunc_dindirect(inode); + if (!retry) + break; + current->counter = 0; + schedule(); + } + inode->i_ctime = inode->i_mtime = CURRENT_TIME; + inode->i_dirt = 1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/xiafs_mac.h b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/xiafs_mac.h new file mode 100644 index 000000000..2c3509ef7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/fs/xiafs/xiafs_mac.h @@ -0,0 +1,32 @@ +/* + * linux/fs/xiafs/xiafs_mac.h + * + * Copyright (C) Q. Frank Xia, 1993. + */ + +extern char internal_error_message[]; +#define INTERN_ERR internal_error_message, __FILE__, __LINE__ +#define WHERE_ERR __FILE__, __LINE__ + +#define XIAFS_ZSHIFT(sp) ((sp)->u.xiafs_sb.s_zone_shift) +#define XIAFS_ZSIZE(sp) (BLOCK_SIZE << XIAFS_ZSHIFT(sp)) +#define XIAFS_ZSIZE_BITS(sp) (BLOCK_SIZE_BITS + XIAFS_ZSHIFT(sp)) +#define XIAFS_ADDRS_PER_Z(sp) (BLOCK_SIZE >> (2 - XIAFS_ZSHIFT(sp))) +#define XIAFS_ADDRS_PER_Z_BITS(sp) (BLOCK_SIZE_BITS - 2 + XIAFS_ZSHIFT(sp)) +#define XIAFS_BITS_PER_Z(sp) (BLOCK_SIZE << (3 + XIAFS_ZSHIFT(sp))) +#define XIAFS_BITS_PER_Z_BITS(sp) (BLOCK_SIZE_BITS + 3 + XIAFS_ZSHIFT(sp)) +#define XIAFS_INODES_PER_Z(sp) (_XIAFS_INODES_PER_BLOCK << XIAFS_ZSHIFT(sp)) + +/* Use the most significant bytes of zone pointers to store block counter. */ +/* This is ugly, but it works. Note, We have another 7 bytes for "expension". */ + +#define XIAFS_GET_BLOCKS(row_ip, blocks) \ + blocks=((((row_ip)->i_zone[0] >> 24) & 0xff )|\ + (((row_ip)->i_zone[1] >> 16) & 0xff00 )|\ + (((row_ip)->i_zone[2] >> 8) & 0xff0000 ) ) + +/* XIAFS_PUT_BLOCKS should be called before saving zone pointers */ +#define XIAFS_PUT_BLOCKS(row_ip, blocks) \ + (row_ip)->i_zone[2]=((blocks)<< 8) & 0xff000000;\ + (row_ip)->i_zone[1]=((blocks)<<16) & 0xff000000;\ + (row_ip)->i_zone[0]=((blocks)<<24) & 0xff000000 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/Makefile new file mode 100644 index 000000000..a04f9bd45 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/Makefile @@ -0,0 +1,39 @@ +# +# Makefile for the iBCS emulator files +# +# 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... + +.S.s: + $(CPP) -traditional $< -o $*.s +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< + +SUBDIRS = + +OBJS = emulate.o + +ibcs.o: $(OBJS) + $(LD) -r -o ibcs.o $(OBJS) + sync + +dep: + $(CPP) -M *.c > .depend + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/emulate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/emulate.c new file mode 100644 index 000000000..fb03b9c36 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ibcs/emulate.c @@ -0,0 +1,27 @@ +/* + * linux/abi/emulate.c + * + * Copyright (C) 1993 Linus Torvalds + */ + +/* + * Emulate.c contains the entry point for the 'lcall 7,xxx' handler. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +asmlinkage void iABI_emulate(struct pt_regs * regs) +{ + printk("iBCS2 binaries not supported yet\n"); + do_exit(SIGSEGV); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/bitops.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/bitops.h new file mode 100644 index 000000000..41b4f2916 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/bitops.h @@ -0,0 +1,107 @@ +#ifndef _ASM_BITOPS_H +#define _ASM_BITOPS_H +/* + * Copyright 1992, Linus Torvalds. + */ + +#ifdef i386 +/* + * These have to be done with inline assembly: that way the bit-setting + * is guaranteed to be atomic. All bitoperations return 0 if the bit + * was cleared before the operation and != 0 if it was not. + * + * bit 0 is the LSB of addr; bit 32 is the LSB of (addr+1). + */ + +/* + * Some hacks to defeat gcc over-optimizations.. + */ +struct __dummy { unsigned long a[100]; }; +#define ADDR (*(struct __dummy *) addr) + +extern __inline__ int set_bit(int nr, void * addr) +{ + int oldbit; + + __asm__ __volatile__("btsl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"r" (nr)); + return oldbit; +} + +extern __inline__ int clear_bit(int nr, void * addr) +{ + int oldbit; + + __asm__ __volatile__("btrl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit),"=m" (ADDR) + :"r" (nr)); + return oldbit; +} + +/* + * This routine doesn't need to be atomic, but it's faster to code it + * this way. + */ +extern __inline__ int test_bit(int nr, void * addr) +{ + int oldbit; + + __asm__ __volatile__("btl %2,%1\n\tsbbl %0,%0" + :"=r" (oldbit) + :"m" (ADDR),"r" (nr)); + return oldbit; +} + +#else +/* + * For the benefit of those who are trying to port Linux to another + * architecture, here are some C-language equivalents. You should + * recode these in the native assmebly language, if at all possible. + * To guarantee atomicity, these routines call cli() and sti() to + * disable interrupts while they operate. (You have to provide inline + * routines to cli() and sti().) + * + * Also note, these routines assume that you have 32 bit integers. + * You will have to change this if you are trying to port Linux to the + * Alpha architecture or to a Cray. :-) + * + * C language equivalents written by Theodore Ts'o, 9/26/92 + */ + +extern __inline__ int set_bit(int nr,int * addr) +{ + int mask, retval; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + cli(); + retval = (mask & *addr) != 0; + *addr |= mask; + sti(); + return retval; +} + +extern __inline__ int clear_bit(int nr, int * addr) +{ + int mask, retval; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + cli(); + retval = (mask & *addr) == 0; + *addr &= ~mask; + sti(); + return retval; +} + +extern __inline__ int test_bit(int nr, int * addr) +{ + int mask; + + addr += nr >> 5; + mask = 1 << (nr & 0x1f); + return ((mask & *addr) != 0); +} +#endif /* i386 */ +#endif /* _ASM_BITOPS_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/dma.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/dma.h new file mode 100644 index 000000000..a2d4a9e80 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/dma.h @@ -0,0 +1,264 @@ +/* $Id: dma.h,v 1.7 1992/12/14 00:29:34 root Exp root $ + * linux/include/asm/dma.h: Defines for using and allocating dma channels. + * Written by Hennus Bergman, 1992. + * High DMA channel support & info by Hannu Savolainen + * and John Boyd, Nov. 1992. + */ + +#ifndef _ASM_DMA_H +#define _ASM_DMA_H + +#include /* need byte IO */ + + +#ifdef HAVE_REALLY_SLOW_DMA_CONTROLLER +#define outb outb_p +#endif + +/* + * NOTES about DMA transfers: + * + * controller 1: channels 0-3, byte operations, ports 00-1F + * controller 2: channels 4-7, word operations, ports C0-DF + * + * - ALL registers are 8 bits only, regardless of transfer size + * - channel 4 is not used - cascades 1 into 2. + * - channels 0-3 are byte - addresses/counts are for physical bytes + * - channels 5-7 are word - addresses/counts are for physical words + * - transfers must not cross physical 64K (0-3) or 128K (5-7) boundaries + * - transfer count loaded to registers is 1 less than actual count + * - controller 2 offsets are all even (2x offsets for controller 1) + * - page registers for 5-7 don't use data bit 0, represent 128K pages + * - page registers for 0-3 use bit 0, represent 64K pages + * + * DMA transfers are limited to the lower 16MB of _physical_ memory. + * Note that addresses loaded into registers must be _physical_ addresses, + * not logical addresses (which may differ if paging is active). + * + * Address mapping for channels 0-3: + * + * A23 ... A16 A15 ... A8 A7 ... A0 (Physical addresses) + * | ... | | ... | | ... | + * | ... | | ... | | ... | + * | ... | | ... | | ... | + * P7 ... P0 A7 ... A0 A7 ... A0 + * | Page | Addr MSB | Addr LSB | (DMA registers) + * + * Address mapping for channels 5-7: + * + * A23 ... A17 A16 A15 ... A9 A8 A7 ... A1 A0 (Physical addresses) + * | ... | \ \ ... \ \ \ ... \ \ + * | ... | \ \ ... \ \ \ ... \ (not used) + * | ... | \ \ ... \ \ \ ... \ + * P7 ... P1 (0) A7 A6 ... A0 A7 A6 ... A0 + * | Page | Addr MSB | Addr LSB | (DMA registers) + * + * Again, channels 5-7 transfer _physical_ words (16 bits), so addresses + * and counts _must_ be word-aligned (the lowest address bit is _ignored_ at + * the hardware level, so odd-byte transfers aren't possible). + * + * Transfer count (_not # bytes_) is limited to 64K, represented as actual + * count - 1 : 64K => 0xFFFF, 1 => 0x0000. Thus, count is always 1 or more, + * and up to 128K bytes may be transferred on channels 5-7 in one operation. + * + */ + +#define MAX_DMA_CHANNELS 8 + +/* 8237 DMA controllers */ +#define IO_DMA1_BASE 0x00 /* 8 bit slave DMA, channels 0..3 */ +#define IO_DMA2_BASE 0xC0 /* 16 bit master DMA, ch 4(=slave input)..7 */ + +/* DMA controller registers */ +#define DMA1_CMD_REG 0x08 /* command register (w) */ +#define DMA1_STAT_REG 0x08 /* status register (r) */ +#define DMA1_REQ_REG 0x09 /* request register (w) */ +#define DMA1_MASK_REG 0x0A /* single-channel mask (w) */ +#define DMA1_MODE_REG 0x0B /* mode register (w) */ +#define DMA1_CLEAR_FF_REG 0x0C /* clear pointer flip-flop (w) */ +#define DMA1_TEMP_REG 0x0D /* Temporary Register (r) */ +#define DMA1_RESET_REG 0x0D /* Master Clear (w) */ +#define DMA1_CLR_MASK_REG 0x0E /* Clear Mask */ +#define DMA1_MASK_ALL_REG 0x0F /* all-channels mask (w) */ + +#define DMA2_CMD_REG 0xD0 /* command register (w) */ +#define DMA2_STAT_REG 0xD0 /* status register (r) */ +#define DMA2_REQ_REG 0xD2 /* request register (w) */ +#define DMA2_MASK_REG 0xD4 /* single-channel mask (w) */ +#define DMA2_MODE_REG 0xD6 /* mode register (w) */ +#define DMA2_CLEAR_FF_REG 0xD8 /* clear pointer flip-flop (w) */ +#define DMA2_TEMP_REG 0xDA /* Temporary Register (r) */ +#define DMA2_RESET_REG 0xDA /* Master Clear (w) */ +#define DMA2_CLR_MASK_REG 0xDC /* Clear Mask */ +#define DMA2_MASK_ALL_REG 0xDE /* all-channels mask (w) */ + +#define DMA_ADDR_0 0x00 /* DMA address registers */ +#define DMA_ADDR_1 0x02 +#define DMA_ADDR_2 0x04 +#define DMA_ADDR_3 0x06 +#define DMA_ADDR_4 0xC0 +#define DMA_ADDR_5 0xC4 +#define DMA_ADDR_6 0xC8 +#define DMA_ADDR_7 0xCC + +#define DMA_CNT_0 0x01 /* DMA count registers */ +#define DMA_CNT_1 0x03 +#define DMA_CNT_2 0x05 +#define DMA_CNT_3 0x07 +#define DMA_CNT_4 0xC2 +#define DMA_CNT_5 0xC6 +#define DMA_CNT_6 0xCA +#define DMA_CNT_7 0xCE + +#define DMA_PAGE_0 0x87 /* DMA page registers */ +#define DMA_PAGE_1 0x83 +#define DMA_PAGE_2 0x81 +#define DMA_PAGE_3 0x82 +#define DMA_PAGE_5 0x8B +#define DMA_PAGE_6 0x89 +#define DMA_PAGE_7 0x8A + +#define DMA_MODE_READ 0x44 /* I/O to memory, no autoinit, increment, single mode */ +#define DMA_MODE_WRITE 0x48 /* memory to I/O, no autoinit, increment, single mode */ +#define DMA_MODE_CASCADE 0xC0 /* pass thru DREQ->HRQ, DACK<-HLDA only */ + +/* enable/disable a specific DMA channel */ +static __inline__ void enable_dma(unsigned int dmanr) +{ + if (dmanr<=3) + outb(dmanr, DMA1_MASK_REG); + else + outb(dmanr & 3, DMA2_MASK_REG); +} + +static __inline__ void disable_dma(unsigned int dmanr) +{ + if (dmanr<=3) + outb(dmanr | 4, DMA1_MASK_REG); + else + outb((dmanr & 3) | 4, DMA2_MASK_REG); +} + +/* Clear the 'DMA Pointer Flip Flop'. + * Write 0 for LSB/MSB, 1 for MSB/LSB access. + * Use this once to initialize the FF to a known state. + * After that, keep track of it. :-) + * --- In order to do that, the DMA routines below should --- + * --- only be used while interrupts are disabled! --- + */ +static __inline__ void clear_dma_ff(unsigned int dmanr) +{ + if (dmanr<=3) + outb(0, DMA1_CLEAR_FF_REG); + else + outb(0, DMA2_CLEAR_FF_REG); +} + +/* set mode (above) for a specific DMA channel */ +static __inline__ void set_dma_mode(unsigned int dmanr, char mode) +{ + if (dmanr<=3) + outb(mode | dmanr, DMA1_MODE_REG); + else + outb(mode | (dmanr&3), DMA2_MODE_REG); +} + +/* Set only the page register bits of the transfer address. + * This is used for successive transfers when we know the contents of + * the lower 16 bits of the DMA current address register, but a 64k boundary + * may have been crossed. + */ +static __inline__ void set_dma_page(unsigned int dmanr, char pagenr) +{ + switch(dmanr) { + case 0: + outb(pagenr, DMA_PAGE_0); + break; + case 1: + outb(pagenr, DMA_PAGE_1); + break; + case 2: + outb(pagenr, DMA_PAGE_2); + break; + case 3: + outb(pagenr, DMA_PAGE_3); + break; + case 5: + outb(pagenr & 0xfe, DMA_PAGE_5); + break; + case 6: + outb(pagenr & 0xfe, DMA_PAGE_6); + break; + case 7: + outb(pagenr & 0xfe, DMA_PAGE_7); + break; + } +} + + +/* Set transfer address & page bits for specific DMA channel. + * Assumes dma flipflop is clear. + */ +static __inline__ void set_dma_addr(unsigned int dmanr, unsigned int a) +{ + set_dma_page(dmanr, a>>16); + if (dmanr <= 3) { + outb( a & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); + outb( (a>>8) & 0xff, ((dmanr&3)<<1) + IO_DMA1_BASE ); + } else { + outb( (a>>1) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); + outb( (a>>9) & 0xff, ((dmanr&3)<<2) + IO_DMA2_BASE ); + } +} + + +/* Set transfer size (max 64k for DMA1..3, 128k for DMA5..7) for + * a specific DMA channel. + * You must ensure the parameters are valid. + * NOTE: from a manual: "the number of transfers is one more + * than the initial word count"! This is taken into account. + * Assumes dma flip-flop is clear. + * NOTE 2: "count" represents _bytes_ and must be even for channels 5-7. + */ +static __inline__ void set_dma_count(unsigned int dmanr, unsigned int count) +{ + count--; + if (dmanr <= 3) { + outb( count & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); + outb( (count>>8) & 0xff, ((dmanr&3)<<1) + 1 + IO_DMA1_BASE ); + } else { + outb( (count>>1) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); + outb( (count>>9) & 0xff, ((dmanr&3)<<2) + 2 + IO_DMA2_BASE ); + } +} + + +/* Get DMA residue count. After a DMA transfer, this + * should return zero. Reading this while a DMA transfer is + * still in progress will return unpredictable results. + * If called before the channel has been used, it may return 1. + * Otherwise, it returns the number of _bytes_ left to transfer. + * + * Assumes DMA flip-flop is clear. + */ +static __inline__ int get_dma_residue(unsigned int dmanr) +{ + unsigned int io_port = (dmanr<=3)? ((dmanr&3)<<1) + 1 + IO_DMA1_BASE + : ((dmanr&3)<<2) + 2 + IO_DMA2_BASE; + + /* using short to get 16-bit wrap around */ + unsigned short count; + + count = 1 + inb(io_port); + count += inb(io_port) << 8; + + return (dmanr<=3)? count : (count<<1); +} + + +/* These are in kernel/dma.c: */ +extern int request_dma(unsigned int dmanr); /* reserve a DMA channel */ +extern void free_dma(unsigned int dmanr); /* release it again */ + + +#endif /* _ASM_DMA_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/io.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/io.h new file mode 100644 index 000000000..a2527c1e0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/io.h @@ -0,0 +1,146 @@ +#ifndef _ASM_IO_H +#define _ASM_IO_H + +/* + * Thanks to James van Artsdalen for a better timing-fix than + * the two short jumps: using outb's to a nonexistent port seems + * to guarantee better timings even on fast machines. + * + * On the other hand, I'd like to be sure of a non-existent port: + * I feel a bit unsafe about using 0x80 (should be safe, though) + * + * Linus + */ + +#ifdef SLOW_IO_BY_JUMPING +#define __SLOW_DOWN_IO __asm__ __volatile__("jmp 1f\n1:\tjmp 1f\n1:") +#else +#define __SLOW_DOWN_IO __asm__ __volatile__("outb %al,$0x80") +#endif + +#ifdef REALLY_SLOW_IO +#define SLOW_DOWN_IO { __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; __SLOW_DOWN_IO; } +#else +#define SLOW_DOWN_IO __SLOW_DOWN_IO +#endif + +/* + * Talk about misusing macros.. + */ + +#define __OUT1(s,x) \ +extern inline void __out##s(unsigned x value, unsigned short port) { + +#define __OUT2(s,s1,s2) \ +__asm__ __volatile__ ("out" #s " %" s1 "0,%" s2 "1" + +#define __OUT(s,s1,x) \ +__OUT1(s,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); } \ +__OUT1(s##c,x) __OUT2(s,s1,"") : : "a" (value), "i" (port)); } \ +__OUT1(s##_p,x) __OUT2(s,s1,"w") : : "a" (value), "d" (port)); SLOW_DOWN_IO; } \ +__OUT1(s##c_p,x) __OUT2(s,s1,"") : : "a" (value), "i" (port)); SLOW_DOWN_IO; } + +#define __IN1(s) \ +extern inline unsigned int __in##s(unsigned short port) { unsigned int _v; + +#define __IN2(s,s1,s2) \ +__asm__ __volatile__ ("in" #s " %" s2 "1,%" s1 "0" + +#define __IN(s,s1,i...) \ +__IN1(s) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); return _v; } \ +__IN1(s##c) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); return _v; } \ +__IN1(s##_p) __IN2(s,s1,"w") : "=a" (_v) : "d" (port) ,##i ); SLOW_DOWN_IO; return _v; } \ +__IN1(s##c_p) __IN2(s,s1,"") : "=a" (_v) : "i" (port) ,##i ); SLOW_DOWN_IO; return _v; } + +#define __INS(s) \ +extern inline void ins##s(unsigned short port, void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; ins" #s \ +: "=D" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +#define __OUTS(s) \ +extern inline void outs##s(unsigned short port, const void * addr, unsigned long count) \ +{ __asm__ __volatile__ ("cld ; rep ; outs" #s \ +: "=S" (addr), "=c" (count) : "d" (port),"0" (addr),"1" (count)); } + +__IN(b,"b","0" (0)) +__IN(w,"w","0" (0)) +__IN(l,"") + +__OUT(b,"b",char) +__OUT(w,"w",short) +__OUT(l,,int) + +__INS(b) +__INS(w) +__INS(l) + +__OUTS(b) +__OUTS(w) +__OUTS(l) + +/* + * Note that due to the way __builtin_constant_p() works, you + * - can't use it inside a inline function (it will never be true) + * - you don't have to worry about side effects within the __builtin.. + */ +#define outb(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc((val),(port)) : \ + __outb((val),(port))) + +#define inb(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc(port) : \ + __inb(port)) + +#define outb_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outbc_p((val),(port)) : \ + __outb_p((val),(port))) + +#define inb_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inbc_p(port) : \ + __inb_p(port)) + +#define outw(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc((val),(port)) : \ + __outw((val),(port))) + +#define inw(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc(port) : \ + __inw(port)) + +#define outw_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outwc_p((val),(port)) : \ + __outw_p((val),(port))) + +#define inw_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inwc_p(port) : \ + __inw_p(port)) + +#define outl(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outlc((val),(port)) : \ + __outl((val),(port))) + +#define inl(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inlc(port) : \ + __inl(port)) + +#define outl_p(val,port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __outlc_p((val),(port)) : \ + __outl_p((val),(port))) + +#define inl_p(port) \ +((__builtin_constant_p((port)) && (port) < 256) ? \ + __inlc_p(port) : \ + __inl_p(port)) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/irq.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/irq.h new file mode 100644 index 000000000..b9d878105 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/irq.h @@ -0,0 +1,165 @@ +#ifndef _ASM_IRQ_H +#define _ASM_IRQ_H + +/* + * linux/include/asm/irq.h + * + * (C) 1992, 1993 Linus Torvalds + */ + +#include +#include + +extern void disable_irq(unsigned int); +extern void enable_irq(unsigned int); + +#define __STR(x) #x +#define STR(x) __STR(x) + +#define SAVE_ALL \ + "cld\n\t" \ + "push %gs\n\t" \ + "push %fs\n\t" \ + "push %es\n\t" \ + "push %ds\n\t" \ + "pushl %eax\n\t" \ + "pushl %ebp\n\t" \ + "pushl %edi\n\t" \ + "pushl %esi\n\t" \ + "pushl %edx\n\t" \ + "pushl %ecx\n\t" \ + "pushl %ebx\n\t" \ + "movl $" STR(KERNEL_DS) ",%edx\n\t" \ + "mov %dx,%ds\n\t" \ + "mov %dx,%es\n\t" \ + "movl $" STR(USER_DS) ",%edx\n\t" \ + "mov %dx,%fs\n\t" \ + "movl $0,%edx\n\t" \ + "movl %edx,%db7\n\t" + +/* + * SAVE_MOST/RESTORE_MOST is used for the faster version of IRQ handlers, + * installed by using the SA_INTERRUPT flag. These kinds of IRQ's don't + * call the routines that do signal handling etc on return, and can have + * more relaxed register-saving etc. They are also atomic, and are thus + * suited for small, fast interrupts like the serial lines or the harddisk + * drivers, which don't actually need signal handling etc. + * + * Also note that we actually save only those registers that are used in + * C subroutines (%eax, %edx and %ecx), so if you do something weird, + * you're on your own. The only segments that are saved (not counting the + * automatic stack and code segment handling) are %ds and %es, and they + * point to kernel space. No messing around with %fs here. + */ +#define SAVE_MOST \ + "cld\n\t" \ + "push %es\n\t" \ + "push %ds\n\t" \ + "pushl %eax\n\t" \ + "pushl %edx\n\t" \ + "pushl %ecx\n\t" \ + "movl $" STR(KERNEL_DS) ",%edx\n\t" \ + "mov %dx,%ds\n\t" \ + "mov %dx,%es\n\t" + +#define RESTORE_MOST \ + "popl %ecx\n\t" \ + "popl %edx\n\t" \ + "popl %eax\n\t" \ + "pop %ds\n\t" \ + "pop %es\n\t" \ + "iret" + +/* + * The "inb" instructions are not needed, but seem to change the timings + * a bit - without them it seems that the harddisk driver won't work on + * all hardware. Arghh. + */ +#define ACK_FIRST(mask) \ + "inb $0x21,%al\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\torb $" #mask ",_cache_21\n\t" \ + "movb _cache_21,%al\n\t" \ + "outb %al,$0x21\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tmovb $0x20,%al\n\t" \ + "outb %al,$0x20\n\t" + +#define ACK_SECOND(mask) \ + "inb $0xA1,%al\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\torb $" #mask ",_cache_A1\n\t" \ + "movb _cache_A1,%al\n\t" \ + "outb %al,$0xA1\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tmovb $0x20,%al\n\t" \ + "outb %al,$0xA0\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\toutb %al,$0x20\n\t" + +#define UNBLK_FIRST(mask) \ + "inb $0x21,%al\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tandb $~(" #mask "),_cache_21\n\t" \ + "movb _cache_21,%al\n\t" \ + "outb %al,$0x21\n\t" + +#define UNBLK_SECOND(mask) \ + "inb $0xA1,%al\n\t" \ + "jmp 1f\n" \ + "1:\tjmp 1f\n" \ + "1:\tandb $~(" #mask "),_cache_A1\n\t" \ + "movb _cache_A1,%al\n\t" \ + "outb %al,$0xA1\n\t" + +#define IRQ_NAME2(nr) nr##_interrupt(void) +#define IRQ_NAME(nr) IRQ_NAME2(IRQ##nr) +#define FAST_IRQ_NAME(nr) IRQ_NAME2(fast_IRQ##nr) +#define BAD_IRQ_NAME(nr) IRQ_NAME2(bad_IRQ##nr) + +#define BUILD_IRQ(chip,nr,mask) \ +asmlinkage void IRQ_NAME(nr); \ +asmlinkage void FAST_IRQ_NAME(nr); \ +asmlinkage void BAD_IRQ_NAME(nr); \ +__asm__( \ +"\n.align 4\n" \ +"_IRQ" #nr "_interrupt:\n\t" \ + "pushl $-"#nr"-2\n\t" \ + SAVE_ALL \ + ACK_##chip(mask) \ + "incl _intr_count\n\t"\ + "sti\n\t" \ + "movl %esp,%ebx\n\t" \ + "pushl %ebx\n\t" \ + "pushl $" #nr "\n\t" \ + "call _do_IRQ\n\t" \ + "addl $8,%esp\n\t" \ + "cli\n\t" \ + UNBLK_##chip(mask) \ + "decl _intr_count\n\t" \ + "jmp ret_from_sys_call\n" \ +"\n.align 4\n" \ +"_fast_IRQ" #nr "_interrupt:\n\t" \ + SAVE_MOST \ + ACK_##chip(mask) \ + "incl _intr_count\n\t" \ + "pushl $" #nr "\n\t" \ + "call _do_fast_IRQ\n\t" \ + "addl $4,%esp\n\t" \ + "cli\n\t" \ + UNBLK_##chip(mask) \ + "decl _intr_count\n\t" \ + RESTORE_MOST \ +"\n\n.align 4\n" \ +"_bad_IRQ" #nr "_interrupt:\n\t" \ + SAVE_MOST \ + ACK_##chip(mask) \ + RESTORE_MOST); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/segment.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/segment.h new file mode 100644 index 000000000..ec85292da --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/segment.h @@ -0,0 +1,219 @@ +#ifndef _ASM_SEGMENT_H +#define _ASM_SEGMENT_H + +static inline unsigned char get_user_byte(const char * addr) +{ + register unsigned char _v; + + __asm__ ("movb %%fs:%1,%0":"=q" (_v):"m" (*addr)); + return _v; +} + +#define get_fs_byte(addr) get_user_byte((char *)(addr)) + +static inline unsigned short get_user_word(const short *addr) +{ + unsigned short _v; + + __asm__ ("movw %%fs:%1,%0":"=r" (_v):"m" (*addr)); + return _v; +} + +#define get_fs_word(addr) get_user_word((short *)(addr)) + +static inline unsigned long get_user_long(const int *addr) +{ + unsigned long _v; + + __asm__ ("movl %%fs:%1,%0":"=r" (_v):"m" (*addr)); \ + return _v; +} + +#define get_fs_long(addr) get_user_long((int *)(addr)) + +static inline void put_user_byte(char val,char *addr) +{ +__asm__ ("movb %0,%%fs:%1": /* no outputs */ :"iq" (val),"m" (*addr)); +} + +#define put_fs_byte(x,addr) put_user_byte((x),(char *)(addr)) + +static inline void put_user_word(short val,short * addr) +{ +__asm__ ("movw %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr)); +} + +#define put_fs_word(x,addr) put_user_word((x),(short *)(addr)) + +static inline void put_user_long(unsigned long val,int * addr) +{ +__asm__ ("movl %0,%%fs:%1": /* no outputs */ :"ir" (val),"m" (*addr)); +} + +#define put_fs_long(x,addr) put_user_long((x),(int *)(addr)) + +static inline void __generic_memcpy_tofs(void * to, const void * from, unsigned long n) +{ +__asm__("cld\n\t" + "push %%es\n\t" + "push %%fs\n\t" + "pop %%es\n\t" + "testb $1,%%cl\n\t" + "je 1f\n\t" + "movsb\n" + "1:\ttestb $2,%%cl\n\t" + "je 2f\n\t" + "movsw\n" + "2:\tshrl $2,%%ecx\n\t" + "rep ; movsl\n\t" + "pop %%es" + : /* no outputs */ + :"c" (n),"D" ((long) to),"S" ((long) from) + :"cx","di","si"); +} + +static inline void __constant_memcpy_tofs(void * to, const void * from, unsigned long n) +{ + switch (n) { + case 0: + return; + case 1: + put_user_byte(*(const char *) from, (char *) to); + return; + case 2: + put_user_word(*(const short *) from, (short *) to); + return; + case 3: + put_user_word(*(const short *) from, (short *) to); + put_user_byte(*(2+(const char *) from), 2+(char *) to); + return; + case 4: + put_user_long(*(const int *) from, (int *) to); + return; + } +#define COMMON(x) \ +__asm__("cld\n\t" \ + "push %%es\n\t" \ + "push %%fs\n\t" \ + "pop %%es\n\t" \ + "rep ; movsl\n\t" \ + x \ + "pop %%es" \ + : /* no outputs */ \ + :"c" (n/4),"D" ((long) to),"S" ((long) from) \ + :"cx","di","si") + + switch (n % 4) { + case 0: + COMMON(""); + return; + case 1: + COMMON("movsb\n\t"); + return; + case 2: + COMMON("movsw\n\t"); + return; + case 3: + COMMON("movsw\n\tmovsb\n\t"); + return; + } +#undef COMMON +} + +static inline void __generic_memcpy_fromfs(void * to, const void * from, unsigned long n) +{ +__asm__("cld\n\t" + "testb $1,%%cl\n\t" + "je 1f\n\t" + "fs ; movsb\n" + "1:\ttestb $2,%%cl\n\t" + "je 2f\n\t" + "fs ; movsw\n" + "2:\tshrl $2,%%ecx\n\t" + "rep ; fs ; movsl" + : /* no outputs */ + :"c" (n),"D" ((long) to),"S" ((long) from) + :"cx","di","si","memory"); +} + +static inline void __constant_memcpy_fromfs(void * to, const void * from, unsigned long n) +{ + switch (n) { + case 0: + return; + case 1: + *(char *)to = get_user_byte((const char *) from); + return; + case 2: + *(short *)to = get_user_word((const short *) from); + return; + case 3: + *(short *) to = get_user_word((const short *) from); + *(char *) to = get_user_byte(2+(const char *) from); + return; + case 4: + *(int *) to = get_user_long((const int *) from); + return; + } +#define COMMON(x) \ +__asm__("cld\n\t" \ + "rep ; fs ; movsl\n\t" \ + x \ + : /* no outputs */ \ + :"c" (n/4),"D" ((long) to),"S" ((long) from) \ + :"cx","di","si","memory") + + switch (n % 4) { + case 0: + COMMON(""); + return; + case 1: + COMMON("fs ; movsb"); + return; + case 2: + COMMON("fs ; movsw"); + return; + case 3: + COMMON("fs ; movsw\n\tfs ; movsb"); + return; + } +#undef COMMON +} + +#define memcpy_fromfs(to, from, n) \ +(__builtin_constant_p(n) ? \ + __constant_memcpy_fromfs((to),(from),(n)) : \ + __generic_memcpy_fromfs((to),(from),(n))) + +#define memcpy_tofs(to, from, n) \ +(__builtin_constant_p(n) ? \ + __constant_memcpy_tofs((to),(from),(n)) : \ + __generic_memcpy_tofs((to),(from),(n))) + +/* + * Someone who knows GNU asm better than I should double check the followig. + * It seems to work, but I don't know if I'm doing something subtly wrong. + * --- TYT, 11/24/91 + * [ nothing wrong here, Linus: I just changed the ax to be any reg ] + */ + +static inline unsigned long get_fs(void) +{ + unsigned long _v; + __asm__("mov %%fs,%w0":"=r" (_v):"0" (0)); + return _v; +} + +static inline unsigned long get_ds(void) +{ + unsigned long _v; + __asm__("mov %%ds,%w0":"=r" (_v):"0" (0)); + return _v; +} + +static inline void set_fs(unsigned long val) +{ + __asm__ __volatile__("mov %w0,%%fs": /* no output */ :"r" (val)); +} + +#endif /* _ASM_SEGMENT_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/system.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/system.h new file mode 100644 index 000000000..b88e28a8d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/asm/system.h @@ -0,0 +1,107 @@ +#ifndef __ASM_SYSTEM_H +#define __ASM_SYSTEM_H + +#include + +#define move_to_user_mode() \ +__asm__ __volatile__ ("movl %%esp,%%eax\n\t" \ + "pushl %0\n\t" \ + "pushl %%eax\n\t" \ + "pushfl\n\t" \ + "pushl %1\n\t" \ + "pushl $1f\n\t" \ + "iret\n" \ + "1:\tmovl %0,%%eax\n\t" \ + "mov %%ax,%%ds\n\t" \ + "mov %%ax,%%es\n\t" \ + "mov %%ax,%%fs\n\t" \ + "mov %%ax,%%gs" \ + : /* no outputs */ :"i" (USER_DS), "i" (USER_CS):"ax") + +#define sti() __asm__ __volatile__ ("sti": : :"memory") +#define cli() __asm__ __volatile__ ("cli": : :"memory") +#define nop() __asm__ __volatile__ ("nop") + +/* + * Clear and set 'TS' bit respectively + */ +#define clts() __asm__ __volatile__ ("clts") +#define stts() \ +__asm__ __volatile__ ( \ + "movl %%cr0,%%eax\n\t" \ + "orl $8,%%eax\n\t" \ + "movl %%eax,%%cr0" \ + : /* no outputs */ \ + : /* no inputs */ \ + :"ax") + + +extern inline int tas(char * m) +{ + char res; + + __asm__("xchgb %0,%1":"=q" (res),"=m" (*m):"0" (0x1)); + return res; +} + +#define save_flags(x) \ +__asm__ __volatile__("pushfl ; popl %0":"=r" (x): /* no input */ :"memory") + +#define restore_flags(x) \ +__asm__ __volatile__("pushl %0 ; popfl": /* no output */ :"r" (x):"memory") + +#define iret() __asm__ __volatile__ ("iret": : :"memory") + +#define _set_gate(gate_addr,type,dpl,addr) \ +__asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ + "movw %2,%%dx\n\t" \ + "movl %%eax,%0\n\t" \ + "movl %%edx,%1" \ + :"=m" (*((long *) (gate_addr))), \ + "=m" (*(1+(long *) (gate_addr))) \ + :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ + "d" ((char *) (addr)),"a" (KERNEL_CS << 16) \ + :"ax","dx") + +#define set_intr_gate(n,addr) \ + _set_gate(&idt[n],14,0,addr) + +#define set_trap_gate(n,addr) \ + _set_gate(&idt[n],15,0,addr) + +#define set_system_gate(n,addr) \ + _set_gate(&idt[n],15,3,addr) + +#define set_call_gate(a,addr) \ + _set_gate(a,12,3,addr) + +#define _set_seg_desc(gate_addr,type,dpl,base,limit) {\ + *((gate_addr)+1) = ((base) & 0xff000000) | \ + (((base) & 0x00ff0000)>>16) | \ + ((limit) & 0xf0000) | \ + ((dpl)<<13) | \ + (0x00408000) | \ + ((type)<<8); \ + *(gate_addr) = (((base) & 0x0000ffff)<<16) | \ + ((limit) & 0x0ffff); } + +#define _set_tssldt_desc(n,addr,limit,type) \ +__asm__ __volatile__ ("movw $" #limit ",%1\n\t" \ + "movw %%ax,%2\n\t" \ + "rorl $16,%%eax\n\t" \ + "movb %%al,%3\n\t" \ + "movb $" type ",%4\n\t" \ + "movb $0x00,%5\n\t" \ + "movb %%ah,%6\n\t" \ + "rorl $16,%%eax" \ + : /* no output */ \ + :"a" (addr+0xc0000000), "m" (*(n)), "m" (*(n+2)), "m" (*(n+4)), \ + "m" (*(n+5)), "m" (*(n+6)), "m" (*(n+7)) \ + ) + +#define set_tss_desc(n,addr) _set_tssldt_desc(((char *) (n)),((int)(addr)),235,"0x89") +#define set_ldt_desc(n,addr,size) \ + _set_tssldt_desc(((char *) (n)),((int)(addr)),((size << 3) - 1),"0x82") + + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/a.out.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/a.out.h new file mode 100644 index 000000000..15071d376 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/a.out.h @@ -0,0 +1,270 @@ +#ifndef __A_OUT_GNU_H__ +#define __A_OUT_GNU_H__ + +#define __GNU_EXEC_MACROS__ + +#ifndef __STRUCT_EXEC_OVERRIDE__ + +struct exec +{ + unsigned long a_info; /* Use macros N_MAGIC, etc for access */ + unsigned a_text; /* length of text, in bytes */ + unsigned a_data; /* length of data, in bytes */ + unsigned a_bss; /* length of uninitialized data area for file, in bytes */ + unsigned a_syms; /* length of symbol table data in file, in bytes */ + unsigned a_entry; /* start address */ + unsigned a_trsize; /* length of relocation info for text, in bytes */ + unsigned a_drsize; /* length of relocation info for data, in bytes */ +}; + +#endif /* __STRUCT_EXEC_OVERRIDE__ */ + +/* these go in the N_MACHTYPE field */ +enum machine_type { +#if defined (M_OLDSUN2) + M__OLDSUN2 = M_OLDSUN2, +#else + M_OLDSUN2 = 0, +#endif +#if defined (M_68010) + M__68010 = M_68010, +#else + M_68010 = 1, +#endif +#if defined (M_68020) + M__68020 = M_68020, +#else + M_68020 = 2, +#endif +#if defined (M_SPARC) + M__SPARC = M_SPARC, +#else + M_SPARC = 3, +#endif + /* skip a bunch so we don't run into any of sun's numbers */ + M_386 = 100, +}; + +#if !defined (N_MAGIC) +#define N_MAGIC(exec) ((exec).a_info & 0xffff) +#endif +#define N_MACHTYPE(exec) ((enum machine_type)(((exec).a_info >> 16) & 0xff)) +#define N_FLAGS(exec) (((exec).a_info >> 24) & 0xff) +#define N_SET_INFO(exec, magic, type, flags) \ + ((exec).a_info = ((magic) & 0xffff) \ + | (((int)(type) & 0xff) << 16) \ + | (((flags) & 0xff) << 24)) +#define N_SET_MAGIC(exec, magic) \ + ((exec).a_info = (((exec).a_info & 0xffff0000) | ((magic) & 0xffff))) + +#define N_SET_MACHTYPE(exec, machtype) \ + ((exec).a_info = \ + ((exec).a_info&0xff00ffff) | ((((int)(machtype))&0xff) << 16)) + +#define N_SET_FLAGS(exec, flags) \ + ((exec).a_info = \ + ((exec).a_info&0x00ffffff) | (((flags) & 0xff) << 24)) + +/* Code indicating object file or impure executable. */ +#define OMAGIC 0407 +/* Code indicating pure executable. */ +#define NMAGIC 0410 +/* Code indicating demand-paged executable. */ +#define ZMAGIC 0413 +/* This indicates a demand-paged executable with the header in the text. + The first page is unmapped to help trap NULL pointer references */ +#define QMAGIC 0314 + +/* Code indicating core file. */ +#define CMAGIC 0421 + +#if !defined (N_BADMAG) +#define N_BADMAG(x) (N_MAGIC(x) != OMAGIC \ + && N_MAGIC(x) != NMAGIC \ + && N_MAGIC(x) != ZMAGIC \ + && N_MAGIC(x) != QMAGIC) +#endif + +#define _N_HDROFF(x) (1024 - sizeof (struct exec)) + +#if !defined (N_TXTOFF) +#define N_TXTOFF(x) \ + (N_MAGIC(x) == ZMAGIC ? _N_HDROFF((x)) + sizeof (struct exec) : \ + (N_MAGIC(x) == QMAGIC ? 0 : sizeof (struct exec))) +#endif + +#if !defined (N_DATOFF) +#define N_DATOFF(x) (N_TXTOFF(x) + (x).a_text) +#endif + +#if !defined (N_TRELOFF) +#define N_TRELOFF(x) (N_DATOFF(x) + (x).a_data) +#endif + +#if !defined (N_DRELOFF) +#define N_DRELOFF(x) (N_TRELOFF(x) + (x).a_trsize) +#endif + +#if !defined (N_SYMOFF) +#define N_SYMOFF(x) (N_DRELOFF(x) + (x).a_drsize) +#endif + +#if !defined (N_STROFF) +#define N_STROFF(x) (N_SYMOFF(x) + (x).a_syms) +#endif + +/* Address of text segment in memory after it is loaded. */ +#if !defined (N_TXTADDR) +#define N_TXTADDR(x) (N_MAGIC(x) == QMAGIC ? PAGE_SIZE : 0) +#endif + +/* Address of data segment in memory after it is loaded. + Note that it is up to you to define SEGMENT_SIZE + on machines not listed here. */ +#if defined(vax) || defined(hp300) || defined(pyr) +#define SEGMENT_SIZE page_size +#endif +#ifdef sony +#define SEGMENT_SIZE 0x2000 +#endif /* Sony. */ +#ifdef is68k +#define SEGMENT_SIZE 0x20000 +#endif +#if defined(m68k) && defined(PORTAR) +#define PAGE_SIZE 0x400 +#define SEGMENT_SIZE PAGE_SIZE +#endif + +#ifdef linux +#include +#define SEGMENT_SIZE 1024 +#endif + +#define _N_SEGMENT_ROUND(x) (((x) + SEGMENT_SIZE - 1) & ~(SEGMENT_SIZE - 1)) + +#define _N_TXTENDADDR(x) (N_TXTADDR(x)+(x).a_text) + +#ifndef N_DATADDR +#define N_DATADDR(x) \ + (N_MAGIC(x)==OMAGIC? (_N_TXTENDADDR(x)) \ + : (_N_SEGMENT_ROUND (_N_TXTENDADDR(x)))) +#endif + +/* Address of bss segment in memory after it is loaded. */ +#if !defined (N_BSSADDR) +#define N_BSSADDR(x) (N_DATADDR(x) + (x).a_data) +#endif + +#if !defined (N_NLIST_DECLARED) +struct nlist { + union { + char *n_name; + struct nlist *n_next; + long n_strx; + } n_un; + unsigned char n_type; + char n_other; + short n_desc; + unsigned long n_value; +}; +#endif /* no N_NLIST_DECLARED. */ + +#if !defined (N_UNDF) +#define N_UNDF 0 +#endif +#if !defined (N_ABS) +#define N_ABS 2 +#endif +#if !defined (N_TEXT) +#define N_TEXT 4 +#endif +#if !defined (N_DATA) +#define N_DATA 6 +#endif +#if !defined (N_BSS) +#define N_BSS 8 +#endif +#if !defined (N_FN) +#define N_FN 15 +#endif + +#if !defined (N_EXT) +#define N_EXT 1 +#endif +#if !defined (N_TYPE) +#define N_TYPE 036 +#endif +#if !defined (N_STAB) +#define N_STAB 0340 +#endif + +/* The following type indicates the definition of a symbol as being + an indirect reference to another symbol. The other symbol + appears as an undefined reference, immediately following this symbol. + + Indirection is asymmetrical. The other symbol's value will be used + to satisfy requests for the indirect symbol, but not vice versa. + If the other symbol does not have a definition, libraries will + be searched to find a definition. */ +#define N_INDR 0xa + +/* The following symbols refer to set elements. + All the N_SET[ATDB] symbols with the same name form one set. + Space is allocated for the set in the text section, and each set + element's value is stored into one word of the space. + The first word of the space is the length of the set (number of elements). + + The address of the set is made into an N_SETV symbol + whose name is the same as the name of the set. + This symbol acts like a N_DATA global symbol + in that it can satisfy undefined external references. */ + +/* These appear as input to LD, in a .o file. */ +#define N_SETA 0x14 /* Absolute set element symbol */ +#define N_SETT 0x16 /* Text set element symbol */ +#define N_SETD 0x18 /* Data set element symbol */ +#define N_SETB 0x1A /* Bss set element symbol */ + +/* This is output from LD. */ +#define N_SETV 0x1C /* Pointer to set vector in data area. */ + +#if !defined (N_RELOCATION_INFO_DECLARED) +/* This structure describes a single relocation to be performed. + The text-relocation section of the file is a vector of these structures, + all of which apply to the text section. + Likewise, the data-relocation section applies to the data section. */ + +struct relocation_info +{ + /* Address (within segment) to be relocated. */ + int r_address; + /* The meaning of r_symbolnum depends on r_extern. */ + unsigned int r_symbolnum:24; + /* Nonzero means value is a pc-relative offset + and it should be relocated for changes in its own address + as well as for changes in the symbol or section specified. */ + unsigned int r_pcrel:1; + /* Length (as exponent of 2) of the field to be relocated. + Thus, a value of 2 indicates 1<<2 bytes. */ + unsigned int r_length:2; + /* 1 => relocate with value of symbol. + r_symbolnum is the index of the symbol + in file's the symbol table. + 0 => relocate with the address of a segment. + r_symbolnum is N_TEXT, N_DATA, N_BSS or N_ABS + (the N_EXT bit may be set also, but signifies nothing). */ + unsigned int r_extern:1; + /* Four bits that aren't used, but when writing an object file + it is desirable to clear them. */ +#ifdef NS32K + unsigned r_bsr:1; + unsigned r_disp:1; + unsigned r_pad:2; +#else + unsigned int r_pad:4; +#endif +}; +#endif /* no N_RELOCATION_INFO_DECLARED. */ + + +#endif /* __A_OUT_GNU_H__ */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/binfmts.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/binfmts.h new file mode 100644 index 000000000..908144dc4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/binfmts.h @@ -0,0 +1,48 @@ +#ifndef _LINUX_BINFMTS_H +#define _LINUX_BINFMTS_H + +#include + +/* + * MAX_ARG_PAGES defines the number of pages allocated for arguments + * and envelope for the new program. 32 should suffice, this gives + * a maximum env+arg of 128kB ! + */ +#define MAX_ARG_PAGES 32 + +/* + * This structure is used to hold the arguments that are used when loading binaries. + */ +struct linux_binprm{ + char buf[128]; + unsigned long page[MAX_ARG_PAGES]; + unsigned long p; + int sh_bang; + struct inode * inode; + int e_uid, e_gid; + int argc, envc; + char * filename; /* Name of binary */ +}; + +/* This structure defines the functions that are used to load the binary formats that + * linux accepts. */ + +struct linux_binfmt{ + int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); + int (*load_shlib)(int fd); +}; + +extern struct linux_binfmt formats[]; + +extern int read_exec(struct inode *inode, unsigned long offset, + char * addr, unsigned long count); + +extern int open_inode(struct inode * inode, int mode); + +extern void flush_old_exec(struct linux_binprm * bprm); +extern unsigned long change_ldt(unsigned long text_size,unsigned long * page); +extern unsigned long * create_tables(char * p,int argc,int envc,int ibcs); +extern unsigned long copy_strings(int argc,char ** argv,unsigned long *page, + unsigned long p, int from_kmem); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/busmouse.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/busmouse.h new file mode 100644 index 000000000..33c6ec7a9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/busmouse.h @@ -0,0 +1,100 @@ +#ifndef _LINUX_BUSMOUSE_H +#define _LINUX_BUSMOUSE_H + +/* + * linux/include/linux/mouse.h: header file for Logitech Bus Mouse driver + * by James Banks + * + * based on information gleamed from various mouse drivers on the net + * + * Heavily modified by David giller (rafetmad@oxy.edu) + * + * Minor modifications for Linux 0.96c-pl1 by Nathan Laredo + * gt7080a@prism.gatech.edu (13JUL92) + * + * Microsoft BusMouse support by Teemu Rantanen (tvr@cs.hut.fi) (02AUG92) + * + * Microsoft Bus Mouse support modified by Derrick Cole (cole@concert.net) + * 8/28/92 + * + * Microsoft Bus Mouse support folded into 0.97pl4 code + * by Peter Cervasio (pete%q106fm.uucp@wupost.wustl.edu) (08SEP92) + * Changes: Logitech and Microsoft support in the same kernel. + * Defined new constants in busmouse.h for MS mice. + * Added int mse_busmouse_type to distinguish busmouse types + * Added a couple of new functions to handle differences in using + * MS vs. Logitech (where the int variable wasn't appropriate). + * + */ + +#define MOUSE_IRQ 5 +#define LOGITECH_BUSMOUSE 0 /* Minor device # for Logitech */ +#define MICROSOFT_BUSMOUSE 2 /* Minor device # for Microsoft */ + +/*--------- LOGITECH BUSMOUSE ITEMS -------------*/ + +#define MSE_DATA_PORT 0x23c +#define MSE_SIGNATURE_PORT 0x23d +#define MSE_CONTROL_PORT 0x23e +#define MSE_INTERRUPT_PORT 0x23e +#define MSE_CONFIG_PORT 0x23f + +#define MSE_ENABLE_INTERRUPTS 0x00 +#define MSE_DISABLE_INTERRUPTS 0x10 + +#define MSE_READ_X_LOW 0x80 +#define MSE_READ_X_HIGH 0xa0 +#define MSE_READ_Y_LOW 0xc0 +#define MSE_READ_Y_HIGH 0xe0 + +/* Magic number used to check if the mouse exists */ +#define MSE_CONFIG_BYTE 0x91 +#define MSE_DEFAULT_MODE 0x90 +#define MSE_SIGNATURE_BYTE 0xa5 + +/* useful Logitech Mouse macros */ + +#define MSE_INT_OFF() outb(MSE_DISABLE_INTERRUPTS, MSE_CONTROL_PORT) +#define MSE_INT_ON() outb(MSE_ENABLE_INTERRUPTS, MSE_CONTROL_PORT) + +/*--------- MICROSOFT BUSMOUSE ITEMS -------------*/ + +#define MS_MSE_DATA_PORT 0x23d +#define MS_MSE_SIGNATURE_PORT 0x23e +#define MS_MSE_CONTROL_PORT 0x23c +#define MS_MSE_CONFIG_PORT 0x23f + +#define MS_MSE_ENABLE_INTERRUPTS 0x11 +#define MS_MSE_DISABLE_INTERRUPTS 0x10 + +#define MS_MSE_READ_BUTTONS 0x00 +#define MS_MSE_READ_X 0x01 +#define MS_MSE_READ_Y 0x02 + +#define MS_MSE_START 0x80 +#define MS_MSE_COMMAND_MODE 0x07 + +/* useful microsoft busmouse macros */ + +#define MS_MSE_INT_OFF() {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \ + outb(MS_MSE_DISABLE_INTERRUPTS, MS_MSE_DATA_PORT);} +#define MS_MSE_INT_ON() {outb(MS_MSE_COMMAND_MODE, MS_MSE_CONTROL_PORT); \ + outb(MS_MSE_ENABLE_INTERRUPTS, MS_MSE_DATA_PORT);} + + +struct mouse_status { + unsigned char buttons; + unsigned char latch_buttons; + int dx; + int dy; + int present; + int ready; + int active; + struct wait_queue *wait; +}; + +/* Function Prototypes */ +extern long mouse_init(long); + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdrom.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdrom.h new file mode 100644 index 000000000..a4635f846 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdrom.h @@ -0,0 +1,340 @@ +/**************************************************************************************** + * * + * SCSI header library for linux * + * (C) 1992 David Giller rafetmad@oxy.edu * + * * + * -- CD-ROM IOCTLs and structs * + * * + ****************************************************************************************/ + +#ifndef _LINUX_CDROM_H +#define _LINUX_CDROM_H + +/* + * + * For IOCTL calls, we will commandeer byte 0x53, or 'S'. + * + */ + +/* + * CD-ROM-specific SCSI command opcodes + */ + +/* + * Group 2 (10-byte). All of these are called 'optional' by SCSI-II. + */ + +#define SCMD_READ_TOC 0x43 /* read table of contents */ +#define SCMD_PLAYAUDIO_MSF 0x47 /* play data at time offset */ +#define SCMD_PLAYAUDIO_TI 0x48 /* play data at track/index */ +#define SCMD_PAUSE_RESUME 0x4B /* pause/resume audio */ +#define SCMD_READ_SUBCHANNEL 0x42 /* read SC info on playing disc */ +#define SCMD_PLAYAUDIO10 0x45 /* play data at logical block */ +#define SCMD_READ_HEADER 0x44 /* read TOC header */ + +/* + * Group 5 + */ + +#define SCMD_PLAYAUDIO12 0xA5 /* play data at logical block */ +#define SCMD_PLAYTRACK_REL12 0xA9 /* play track at relative offset*/ + +/* + * Group 6 Commands + */ + +#define SCMD_CD_PLAYBACK_CONTROL 0xC9 /* Sony vendor-specific audio */ +#define SCMD_CD_PLAYBACK_STATUS 0xC4 /* control opcodes. info please!*/ + +/* + * CD-ROM capacity structure. + */ + +struct scsi_capacity + { + u_long capacity; + u_long lbasize; + }; + +/* + * CD-ROM MODE_SENSE/MODE_SELECT parameters + */ + +#define ERR_RECOVERY_PARMS 0x01 +#define DISCO_RECO_PARMS 0x02 +#define FORMAT_PARMS 0x03 +#define GEOMETRY_PARMS 0x04 +#define CERTIFICATION_PARMS 0x06 +#define CACHE_PARMS 0x38 + +/* + * standard mode-select header prepended to all mode-select commands + */ + +struct ccs_modesel_head + { + u_char _r1; /* reserved */ + u_char medium; /* device-specific medium type */ + u_char _r2; /* reserved */ + u_char block_desc_length; /* block descriptor length */ + u_char density; /* device-specific density code */ + u_char number_blocks_hi; /* number of blocks in this block desc */ + u_char number_blocks_med; + u_char number_blocks_lo; + u_char _r3; + u_char block_length_hi; /* block length for blocks in this desc */ + u_short block_length; + }; + +/* + * error recovery parameters + */ + +struct ccs_err_recovery + { + u_char _r1 : 2; /* reserved */ + u_char page_code : 6; /* page code */ + u_char page_length; /* page length */ + u_char awre : 1; /* auto write realloc enabled */ + u_char arre : 1; /* auto read realloc enabled */ + u_char tb : 1; /* transfer block */ + u_char rc : 1; /* read continuous */ + u_char eec : 1; /* enable early correction */ + u_char per : 1; /* post error */ + u_char dte : 1; /* disable transfer on error */ + u_char dcr : 1; /* disable correction */ + u_char retry_count; /* error retry count */ + u_char correction_span; /* largest recov. to be attempted, bits */ + u_char head_offset_count; /* head offset (2's C) for each retry */ + u_char strobe_offset_count; /* data strobe " */ + u_char recovery_time_limit; /* time limit on recovery attempts */ +}; + +/* + * disco/reco parameters + */ + +struct ccs_disco_reco + { + u_char _r1 : 2; /* reserved */ + u_char page_code : 6; /* page code */ + u_char page_length; /* page length */ + u_char buffer_full_ratio; /* write buffer reconnect threshold */ + u_char buffer_empty_ratio; /* read " */ + u_short bus_inactivity_limit; /* limit on bus inactivity time */ + u_short disconnect_time_limit; /* minimum disconnect time */ + u_short connect_time_limit; /* minimum connect time */ + u_short _r2; /* reserved */ +}; + +/* + * drive geometry parameters + */ + +struct ccs_geometry + { + u_char _r1 : 2; /* reserved */ + u_char page_code : 6; /* page code */ + u_char page_length; /* page length */ + u_char cyl_ub; /* #cyls */ + u_char cyl_mb; + u_char cyl_lb; + u_char heads; /* #heads */ + u_char precomp_cyl_ub; /* precomp start */ + u_char precomp_cyl_mb; + u_char precomp_cyl_lb; + u_char current_cyl_ub; /* reduced current start */ + u_char current_cyl_mb; + u_char current_cyl_lb; + u_short step_rate; /* stepping motor rate */ + u_char landing_cyl_ub; /* landing zone */ + u_char landing_cyl_mb; + u_char landing_cyl_lb; + u_char _r2; + u_char _r3; + u_char _r4; + }; + +/* + * cache parameters + */ + +struct ccs_cache + { + u_char _r1 : 2; /* reserved */ + u_char page_code : 6; /* page code */ + u_char page_length; /* page length */ + u_char mode; /* cache control byte */ + u_char threshold; /* prefetch threshold */ + u_char max_prefetch; /* maximum prefetch size */ + u_char max_multiplier; /* maximum prefetch multiplier */ + u_char min_prefetch; /* minimum prefetch size */ + u_char min_multiplier; /* minimum prefetch multiplier */ + u_char _r2[8]; + }; + +/* + * CDROM IOCTL structures + */ + +struct cdrom_msf + { + u_char cdmsf_min0; /* start minute */ + u_char cdmsf_sec0; /* start second */ + u_char cdmsf_frame0; /* start frame */ + u_char cdmsf_min1; /* end minute */ + u_char cdmsf_sec1; /* end second */ + u_char cdmsf_frame1; /* end frame */ + }; + +struct cdrom_ti + { + u_char cdti_trk0; /* start track */ + u_char cdti_ind0; /* start index */ + u_char cdti_trk1; /* end track */ + u_char cdti_ind1; /* end index */ + }; + +struct cdrom_tochdr + { + u_char cdth_trk0; /* start track */ + u_char cdth_trk1; /* end track */ + }; + +struct cdrom_tocentry + { + u_char cdte_track; + u_char cdte_adr :4; + u_char cdte_ctrl :4; + u_char cdte_format; + union + { + struct + { + u_char minute; + u_char second; + u_char frame; + } msf; + int lba; + } cdte_addr; + u_char cdte_datamode; + }; + +/* + * CD-ROM address types (cdrom_tocentry.cdte_format) + */ + +#define CDROM_LBA 0x01 +#define CDROM_MSF 0x02 + +/* + * bit to tell whether track is data or audio + */ + +#define CDROM_DATA_TRACK 0x04 + +/* + * The leadout track is always 0xAA, regardless of # of tracks on disc + */ + +#define CDROM_LEADOUT 0xAA + +struct cdrom_subchnl + { + u_char cdsc_format; + u_char cdsc_audiostatus; + u_char cdsc_adr: 4; + u_char cdsc_ctrl: 4; + u_char cdsc_trk; + u_char cdsc_ind; + union + { + struct + { + u_char minute; + u_char second; + u_char frame; + } msf; + int lba; + } cdsc_absaddr; + union + { + struct + { + u_char minute; + u_char second; + u_char frame; + } msf; + int lba; + } cdsc_reladdr; + }; + +/* + * return value from READ SUBCHANNEL DATA + */ + +#define CDROM_AUDIO_INVALID 0x00 /* audio status not supported */ +#define CDROM_AUDIO_PLAY 0x11 /* audio play operation in progress */ +#define CDROM_AUDIO_PAUSED 0x12 /* audio play operation paused */ +#define CDROM_AUDIO_COMPLETED 0x13 /* audio play successfully completed */ +#define CDROM_AUDIO_ERROR 0x14 /* audio play stopped due to error */ +#define CDROM_AUDIO_NO_STATUS 0x15 /* no current audio status to return */ + +struct cdrom_volctrl + { + u_char channel0; + u_char channel1; + u_char channel2; + u_char channel3; + }; + +struct cdrom_read + { + int cdread_lba; + caddr_t cdread_bufaddr; + int cdread_buflen; + }; + +#ifdef FIVETWELVE +#define CDROM_MODE1_SIZE 512 +#else +#define CDROM_MODE1_SIZE 2048 +#endif FIVETWELVE +#define CDROM_MODE2_SIZE 2336 + +/* + * CD-ROM IOCTL commands + */ + +#define CDROMPAUSE 0x5301 /* pause */ +#define CDROMRESUME 0x5302 /* resume */ + +#define CDROMPLAYMSF 0x5303 /* (stuct cdrom_msf) */ + /* SCMD_PLAY_AUDIO_MSF */ + +#define CDROMPLAYTRKIND 0x5304 /* (struct cdrom_ti) */ + /* SCMD_PLAY_AUDIO_TI */ + +#define CDROMREADTOCHDR 0x5305 /* (struct cdrom_tochdr) */ + /* read the TOC header */ +#define CDROMREADTOCENTRY 0x5306 /* (struct cdrom_tocentry) */ + /* read a TOC entry */ + +#define CDROMSTOP 0x5307 /* stop the drive motor */ +#define CDROMSTART 0x5308 /* turn the motor on */ + +#define CDROMEJECT 0x5309 /* eject CD-ROM media */ + +#define CDROMVOLCTRL 0x530a /* (struct cdrom_volctrl) */ + /* vlume control */ + +#define CDROMSUBCHNL 0x530b /* (struct cdrom_subchnl) */ + /* read sub-channel data */ + +#define CDROMREADMODE2 0x530c /* (struct cdrom_read) */ + /* read type-2 data (not suppt) */ + +#define CDROMREADMODE1 0x530d /* (struct cdrom_read) */ + /* read type-1 data */ + +#endif _LINUX_CDROM_H diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdu31a.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdu31a.h new file mode 100644 index 000000000..56ad5ad9f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/cdu31a.h @@ -0,0 +1,313 @@ +/* + * Definitions for a Sony interface CDROM drive. + * + * Corey Minyard (minyard@wf-rch.cirr.com) + * + * Copyright (C) 1993 Corey Minyard + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* + * Offsets (from the base address) and bits for the various write registers + * of the drive. + */ +#define SONY_CMD_REG_OFFSET 0 +#define SONY_PARAM_REG_OFFSET 1 +#define SONY_WRITE_REG_OFFSET 2 +#define SONY_CONTROL_REG_OFFSET 3 +# define SONY_ATTN_CLR_BIT 0x01 +# define SONY_RES_RDY_CLR_BIT 0x02 +# define SONY_DATA_RDY_CLR_BIT 0x04 +# define SONY_ATTN_INT_EN_BIT 0x08 +# define SONY_RES_RDY_INT_EN_BIT 0x10 +# define SONY_DATA_RDY_INT_EN_BIT 0x20 +# define SONY_PARAM_CLR_BIT 0x40 +# define SONY_DRIVE_RESET_BIT 0x80 + +/* + * Offsets (from the base address) and bits for the various read registers + * of the drive. + */ +#define SONY_STATUS_REG_OFFSET 0 +# define SONY_ATTN_BIT 0x01 +# define SONY_RES_RDY_BIT 0x02 +# define SONY_DATA_RDY_BIT 0x04 +# define SONY_ATTN_INT_ST_BIT 0x08 +# define SONY_RES_RDY_INT_ST_BIT 0x10 +# define SONY_DATA_RDY_INT_ST_BIT 0x20 +# define SONY_DATA_REQUEST_BIT 0x40 +# define SONY_BUSY_BIT 0x80 +#define SONY_RESULT_REG_OFFSET 1 +#define SONY_READ_REG_OFFSET 2 +#define SONY_FIFOST_REG_OFFSET 3 +# define SONY_PARAM_WRITE_RDY_BIT 0x01 +# define SONY_PARAM_REG_EMPTY_BIT 0x02 +# define SONY_RES_REG_NOT_EMP_BIT 0x04 +# define SONY_RES_REG_FULL_BIT 0x08 + +#define LOG_START_OFFSET 150 /* Offset of first logical sector */ + +#define SONY_DETECT_TIMEOUT 80 /* Maximum amount of time + that drive detection code + will wait for response + from drive (in 1/100th's + of seconds). */ + +#define SONY_JIFFIES_TIMEOUT 500 /* Maximum number of times the + drive will wait/try for an + operation */ +#define SONY_RESET_TIMEOUT 100 /* Maximum number of times the + drive will wait/try a reset + operation */ +#define SONY_READY_RETRIES 20000 /* How many times to retry a + spin waiting for a register + to come ready */ + +#define MAX_CDU31A_RETRIES 3 /* How many times to retry an + operation */ + +/* Commands to request or set drive control parameters and disc information */ +#define SONY_REQ_DRIVE_CONFIG_CMD 0x00 /* Returns s_sony_drive_config */ +#define SONY_REQ_DRIVE_MODE_CMD 0x01 +#define SONY_REQ_DRIVE_PARAM_CMD 0x02 +#define SONY_REQ_MECH_STATUS_CMD 0x03 +#define SONY_REQ_AUDIO_STATUS_CMD 0x04 +#define SONY_SET_DRIVE_PARAM_CMD 0x10 +#define SONY_REQ_TOC_DATA_CMD 0x20 /* Returns s_sony_toc */ +#define SONY_REQ_SUBCODE_ADDRESS_CMD 0x21 /* Returns s_sony_subcode */ +#define SONY_REQ_UPC_EAN_CMD 0x22 +#define SONY_REQ_ISRC_CMD 0x23 +#define SONY_REQ_TOC_DATA_SPEC_CMD 0x24 + +/* Commands to request information from the drive */ +#define SONY_READ_TOC_CMD 0x30 +#define SONY_SEEK_CMD 0x31 +#define SONY_READ_CMD 0x32 +#define SONY_READ_BLKERR_STAT_CMD 0x34 +#define SONY_ABORT_CMD 0x35 +#define SONY_READ_TOC_SPEC_CMD 0x36 + +/* Commands to control audio */ +#define SONY_AUDIO_PLAYBACK_CMD 0x40 +#define SONY_AUDIO_STOP_CMD 0x41 +#define SONY_AUDIO_SCAN_CMD 0x42 + +/* Miscellaneous control commands */ +#define SONY_EJECT_CMD 0x50 +#define SONY_SPIN_UP_CMD 0x51 +#define SONY_SPIN_DOWN_CMD 0x52 + +/* Diagnostic commands */ +#define SONY_WRITE_BUFFER_CMD 0x60 +#define SONY_READ_BUFFER_CMD 0x61 +#define SONY_DIAGNOSTICS_CMD 0x62 + + +/* + * The following are command paramters for the set drive parameter command + */ +#define SONY_SD_DECODE_PARAM 0x00 +#define SONY_SD_INTERFACE_PARAM 0x01 +#define SONY_SD_BUFFERING_PARAM 0x02 +#define SONY_SD_AUDIO_PARAM 0x03 +#define SONY_SD_AUDIO_VOLUME 0x04 +#define SONY_SD_MECH_CONTROL 0x05 +#define SONY_SD_AUTO_SPIN_DOWN_TIME 0x06 + +/* + * The following extract information from the drive configuration about + * the drive itself. + */ +#define SONY_HWC_GET_LOAD_MECH(c) (c.hw_config[0] & 0x03) +#define SONY_HWC_EJECT(c) (c.hw_config[0] & 0x04) +#define SONY_HWC_LED_SUPPORT(c) (c.hw_config[0] & 0x08) +#define SONY_HWC_GET_BUF_MEM_SIZE(c) ((c.hw_config[0] & 0xc0) >> 6) +#define SONY_HWC_AUDIO_PLAYBACK(c) (c.hw_config[1] & 0x01) +#define SONY_HWC_ELECTRIC_VOLUME(c) (c.hw_config[1] & 0x02) +#define SONY_HWC_ELECTRIC_VOLUME_CTL(c) (c.hw_config[1] & 0x04) + +#define SONY_HWC_CADDY_LOAD_MECH 0x00 +#define SONY_HWC_TRAY_LOAD_MECH 0x01 +#define SONY_HWC_POPUP_LOAD_MECH 0x02 +#define SONY_HWC_UNKWN_LOAD_MECH 0x03 + +#define SONY_HWC_8KB_BUFFER 0x00 +#define SONY_HWC_32KB_BUFFER 0x01 +#define SONY_HWC_64KB_BUFFER 0x02 +#define SONY_HWC_UNKWN_BUFFER 0x03 + +/* + * This is the complete status returned from the drive configuration request + * command. + */ +struct s_sony_drive_config +{ + unsigned char exec_status[2]; + char vendor_id[8]; + char product_id[16]; + char product_rev_level[8]; + unsigned char hw_config[2]; +}; + +/* The following is returned from the request subcode address command */ +struct s_sony_subcode +{ + unsigned char exec_status[2]; + unsigned char address :4; + unsigned char control :4; + unsigned char track_num; + unsigned char index_num; + unsigned char rel_msf[3]; + unsigned char reserved1; + unsigned char abs_msf[3]; +}; + +/* + * The following is returned from the request TOC (Table Of Contents) command. + * (last_track_num-first_track_num+1) values are valid in tracks. + */ +struct s_sony_toc +{ + unsigned char exec_status[2]; + unsigned char address0 :4; + unsigned char control0 :4; + unsigned char point0; + unsigned char first_track_num; + unsigned char disk_type; + unsigned char dummy0; + unsigned char address1 :4; + unsigned char control1 :4; + unsigned char point1; + unsigned char last_track_num; + unsigned char dummy1; + unsigned char dummy2; + unsigned char address2 :4; + unsigned char control2 :4; + unsigned char point2; + unsigned char lead_out_start_msf[3]; + struct + { + unsigned char address :4; + unsigned char control :4; + unsigned char track; + unsigned char track_start_msf[3]; + } tracks[100]; + + unsigned int lead_out_start_lba; +}; + + +/* + * The following are errors returned from the drive. + */ + +/* Command error group */ +#define SONY_ILL_CMD_ERR 0x10 +#define SONY_ILL_PARAM_ERR 0x11 + +/* Mechanism group */ +#define SONY_NOT_LOAD_ERR 0x20 +#define SONY_NO_DISK_ERR 0x21 +#define SONY_NOT_SPIN_ERR 0x22 +#define SONY_SPIN_ERR 0x23 +#define SONY_SPINDLE_SERVO_ERR 0x25 +#define SONY_FOCUS_SERVO_ERR 0x26 +#define SONY_EJECT_MECH_ERR 0x29 +#define SONY_AUDIO_PLAYING_ERR 0x2a +#define SONY_EMERGENCY_EJECT_ERR 0x2c + +/* Seek error group */ +#define SONY_FOCUS_ERR 0x30 +#define SONY_FRAME_SYNC_ERR 0x31 +#define SONY_SUBCODE_ADDR_ERR 0x32 +#define SONY_BLOCK_SYNC_ERR 0x33 +#define SONY_HEADER_ADDR_ERR 0x34 + +/* Read error group */ +#define SONY_ILL_TRACK_R_ERR 0x40 +#define SONY_MODE_0_R_ERR 0x41 +#define SONY_ILL_MODE_R_ERR 0x42 +#define SONY_ILL_BLOCK_SIZE_R_ERR 0x43 +#define SONY_MODE_R_ERR 0x44 +#define SONY_FORM_R_ERR 0x45 +#define SONY_LEAD_OUT_R_ERR 0x46 +#define SONY_BUFFER_OVERRUN_R_ERR 0x47 + +/* Data error group */ +#define SONY_UNREC_CIRC_ERR 0x53 +#define SONY_UNREC_LECC_ERR 0x57 + +/* Subcode error group */ +#define SONY_NO_TOC_ERR 0x60 +#define SONY_SUBCODE_DATA_NVAL_ERR 0x61 +#define SONY_FOCUS_ON_TOC_READ_ERR 0x63 +#define SONY_FRAME_SYNC_ON_TOC_READ_ERR 0x64 +#define SONY_TOC_DATA_ERR 0x65 + +/* Hardware failure group */ +#define SONY_HW_FAILURE_ERR 0x70 +#define SONY_LEAD_IN_A_ERR 0x91 +#define SONY_LEAD_OUT_A_ERR 0x92 +#define SONY_DATA_TRACK_A_ERR 0x93 + +/* + * The following are returned from the Read With Block Error Status command. + * They are not errors but information (Errors from the 0x5x group above may + * also be returned + */ +#define SONY_NO_CIRC_ERR_BLK_STAT 0x50 +#define SONY_NO_LECC_ERR_BLK_STAT 0x54 +#define SONY_RECOV_LECC_ERR_BLK_STAT 0x55 +#define SONY_NO_ERR_DETECTION_STAT 0x59 + +/* + * The following is not an error returned by the drive, but by the code + * that talks to the drive. It is returned because of a timeout. + */ +#define SONY_TIMEOUT_OP_ERR 0x01 +#define SONY_SIGNAL_OP_ERR 0x02 + + +/* + * The following are attention code for asyncronous events from the drive. + */ + +/* Standard attention group */ +#define SONY_EMER_EJECT_ATTN 0x2c +#define SONY_HW_FAILURE_ATTN 0x70 +#define SONY_MECH_LOADED_ATTN 0x80 +#define SONY_EJECT_PUSHED_ATTN 0x81 + +/* Audio attention group */ +#define SONY_AUDIO_PLAY_DONE_ATTN 0x90 +#define SONY_LEAD_IN_ERR_ATTN 0x91 +#define SONY_LEAD_OUT_ERR_ATTN 0x92 +#define SONY_DATA_TRACK_ERR_ATTN 0x93 +#define SONY_AUDIO_PLAYBACK_ERR_ATTN 0x94 + +/* Auto spin up group */ +#define SONY_SPIN_UP_COMPLETE_ATTN 0x24 +#define SONY_SPINDLE_SERVO_ERR_ATTN 0x25 +#define SONY_FOCUS_SERVO_ERR_ATTN 0x26 +#define SONY_TOC_READ_DONE_ATTN 0x62 +#define SONY_FOCUS_ON_TOC_READ_ERR_ATTN 0x63 +#define SONY_SYNC_ON_TOC_READ_ERR_ATTN 0x65 + +/* Auto eject group */ +#define SONY_SPIN_DOWN_COMPLETE_ATTN 0x27 +#define SONY_EJECT_COMPLETE_ATTN 0x28 +#define SONY_EJECT_MECH_ERR_ATTN 0x29 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/coff.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/coff.h new file mode 100644 index 000000000..e37652181 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/coff.h @@ -0,0 +1,351 @@ +/* This file is derrived from the GAS 2.1.4 assembler control file. + The GAS product is under the GNU Public License, version 2 or later. + As such, this file is also uder that license. + + If the file format changes in the COFF object, this file should be + subsequently updated to reflect the changes. + + The actual loader module only uses a few of these structures. The full + set is documented here because I received the full set. If you wish + more information about COFF, then O'Rielly has a very excellent book. +*/ + +#define E_SYMNMLEN 8 /* Number of characters in a symbol name */ +#define E_FILNMLEN 14 /* Number of characters in a file name */ +#define E_DIMNUM 4 /* Number of array dimensions in auxiliary entry */ + +/* + * These defines are byte order independant. There is no alignment of fields + * permitted in the structures. Therefore they are declared as characters + * and the values loaded from the character positions. It also makes it + * nice to have it "endian" independant. + */ + +/* Load a short int from the following tables with little-endian formats */ +#define COFF_SHORT_L(ps) ((short)(((unsigned short)((unsigned char)ps[1])<<8)|\ + ((unsigned short)((unsigned char)ps[0])))) + +/* Load a long int from the following tables with little-endian formats */ +#define COFF_LONG_L(ps) (((long)(((unsigned long)((unsigned char)ps[3])<<24) |\ + ((unsigned long)((unsigned char)ps[2])<<16) |\ + ((unsigned long)((unsigned char)ps[1])<<8) |\ + ((unsigned long)((unsigned char)ps[0]))))) + +/* Load a short int from the following tables with big-endian formats */ +#define COFF_SHORT_H(ps) ((short)(((unsigned short)((unsigned char)ps[0])<<8)|\ + ((unsigned short)((unsigned char)ps[1])))) + +/* Load a long int from the following tables with big-endian formats */ +#define COFF_LONG_H(ps) (((long)(((unsigned long)((unsigned char)ps[0])<<24) |\ + ((unsigned long)((unsigned char)ps[1])<<16) |\ + ((unsigned long)((unsigned char)ps[2])<<8) |\ + ((unsigned long)((unsigned char)ps[3]))))) + +/* These may be overriden later by brain dead implementations which generate + a big-endian header with little-endian data. In that case, generate a + replacement macro which tests a flag and uses either of the two above + as appropriate. */ + +#define COFF_LONG(v) COFF_LONG_L(v) +#define COFF_SHORT(v) COFF_SHORT_L(v) + +/*** coff information for Intel 386/486. */ + +/********************** FILE HEADER **********************/ + +struct COFF_filehdr { + char f_magic[2]; /* magic number */ + char f_nscns[2]; /* number of sections */ + char f_timdat[4]; /* time & date stamp */ + char f_symptr[4]; /* file pointer to symtab */ + char f_nsyms[4]; /* number of symtab entries */ + char f_opthdr[2]; /* sizeof(optional hdr) */ + char f_flags[2]; /* flags */ +}; + +/* + * Bits for f_flags: + * + * F_RELFLG relocation info stripped from file + * F_EXEC file is executable (i.e. no unresolved externel + * references) + * F_LNNO line nunbers stripped from file + * F_LSYMS local symbols stripped from file + * F_MINMAL this is a minimal object file (".m") output of fextract + * F_UPDATE this is a fully bound update file, output of ogen + * F_SWABD this file has had its bytes swabbed (in names) + * F_AR16WR this file has the byte ordering of an AR16WR + * (e.g. 11/70) machine + * F_AR32WR this file has the byte ordering of an AR32WR machine + * (e.g. vax and iNTEL 386) + * F_AR32W this file has the byte ordering of an AR32W machine + * (e.g. 3b,maxi) + * F_PATCH file contains "patch" list in optional header + * F_NODF (minimal file only) no decision functions for + * replaced functions + */ + +#define COFF_F_RELFLG 0000001 +#define COFF_F_EXEC 0000002 +#define COFF_F_LNNO 0000004 +#define COFF_F_LSYMS 0000010 +#define COFF_F_MINMAL 0000020 +#define COFF_F_UPDATE 0000040 +#define COFF_F_SWABD 0000100 +#define COFF_F_AR16WR 0000200 +#define COFF_F_AR32WR 0000400 +#define COFF_F_AR32W 0001000 +#define COFF_F_PATCH 0002000 +#define COFF_F_NODF 0002000 + +#define COFF_I386MAGIC 0x14c /* Linux's system */ + +#if 0 /* Perhaps, someday, these formats may be used. */ +#define COFF_I386PTXMAGIC 0x154 +#define COFF_I386AIXMAGIC 0x175 /* IBM's AIX system */ +#define COFF_I386BADMAG(x) ((COFF_SHORT((x).f_magic) != COFF_I386MAGIC) \ + && COFF_SHORT((x).f_magic) != COFF_I386PTXMAGIC \ + && COFF_SHORT((x).f_magic) != COFF_I386AIXMAGIC) +#else +#define COFF_I386BADMAG(x) (COFF_SHORT((x).f_magic) != COFF_I386MAGIC) +#endif + +#define COFF_FILHDR struct COFF_filehdr +#define COFF_FILHSZ sizeof(COFF_FILHDR) + +/********************** AOUT "OPTIONAL HEADER" **********************/ + +/* Linux COFF must have this "optional" header. Standard COFF has no entry + location for the "entry" point. They normally would start with the first + location of the .text section. This is not a good idea for linux. So, + the use of this "optional" header is not optional. It is required. + + Do not be tempted to assume that the size of the optional header is + a constant and simply index the next byte by the size of this structure. + Use the 'f_opthdr' field in the main coff header for the size of the + structure actually written to the file!! +*/ + +typedef struct +{ + char magic[2]; /* type of file */ + char vstamp[2]; /* version stamp */ + char tsize[4]; /* text size in bytes, padded to FW bdry */ + char dsize[4]; /* initialized data " " */ + char bsize[4]; /* uninitialized data " " */ + char entry[4]; /* entry pt. */ + char text_start[4]; /* base of text used for this file */ + char data_start[4]; /* base of data used for this file */ +} +COFF_AOUTHDR; + +#define COFF_AOUTSZ (sizeof(COFF_AOUTHDR)) + +#define COFF_STMAGIC 0401 +#define COFF_OMAGIC 0404 +#define COFF_JMAGIC 0407 /* dirty text and data image, can't share */ +#define COFF_DMAGIC 0410 /* dirty text segment, data aligned */ +#define COFF_ZMAGIC 0413 /* The proper magic number for executabls */ +#define COFF_SHMAGIC 0443 /* shared library header */ + +/********************** SECTION HEADER **********************/ + +struct COFF_scnhdr { + char s_name[8]; /* section name */ + char s_paddr[4]; /* physical address, aliased s_nlib */ + char s_vaddr[4]; /* virtual address */ + char s_size[4]; /* section size */ + char s_scnptr[4]; /* file ptr to raw data for section */ + char s_relptr[4]; /* file ptr to relocation */ + char s_lnnoptr[4]; /* file ptr to line numbers */ + char s_nreloc[2]; /* number of relocation entries */ + char s_nlnno[2]; /* number of line number entries */ + char s_flags[4]; /* flags */ +}; + +#define COFF_SCNHDR struct COFF_scnhdr +#define COFF_SCNHSZ sizeof(COFF_SCNHDR) + +/* + * names of "special" sections + */ + +#define COFF_TEXT ".text" +#define COFF_DATA ".data" +#define COFF_BSS ".bss" +#define COFF_COMMENT ".comment" +#define COFF_LIB ".lib" + +#define COFF_SECT_TEXT 0 /* Section for instruction code */ +#define COFF_SECT_DATA 1 /* Section for initialized globals */ +#define COFF_SECT_BSS 2 /* Section for un-initialized globals */ +#define COFF_SECT_REQD 3 /* Minimum number of sections for good file */ + +#define COFF_STYP_REG 0x00 /* regular segment */ +#define COFF_STYP_DSECT 0x01 /* dummy segment */ +#define COFF_STYP_NOLOAD 0x02 /* no-load segment */ +#define COFF_STYP_GROUP 0x04 /* group segment */ +#define COFF_STYP_PAD 0x08 /* .pad segment */ +#define COFF_STYP_COPY 0x10 /* copy section */ +#define COFF_STYP_TEXT 0x20 /* .text segment */ +#define COFF_STYP_DATA 0x40 /* .data segment */ +#define COFF_STYP_BSS 0x80 /* .bss segment */ +#define COFF_STYP_INFO 0x200 /* .comment section */ +#define COFF_STYP_OVER 0x400 /* overlay section */ +#define COFF_STYP_LIB 0x800 /* library section */ + +/* + * Shared libraries have the following section header in the data field for + * each library. + */ + +struct COFF_slib { + char sl_entsz[4]; /* Size of this entry */ + char sl_pathndx[4]; /* size of the header field */ +}; + +#define COFF_SLIBHD struct COFF_slib +#define COFF_SLIBSZ sizeof(COFF_SLIBHD) + +/********************** LINE NUMBERS **********************/ + +/* 1 line number entry for every "breakpointable" source line in a section. + * Line numbers are grouped on a per function basis; first entry in a function + * grouping will have l_lnno = 0 and in place of physical address will be the + * symbol table index of the function name. + */ + +struct COFF_lineno { + union { + char l_symndx[4]; /* function name symbol index, iff l_lnno == 0*/ + char l_paddr[4]; /* (physical) address of line number */ + } l_addr; + char l_lnno[2]; /* line number */ +}; + +#define COFF_LINENO struct COFF_lineno +#define COFF_LINESZ 6 + +/********************** SYMBOLS **********************/ + +#define COFF_E_SYMNMLEN 8 /* # characters in a short symbol name */ +#define COFF_E_FILNMLEN 14 /* # characters in a file name */ +#define COFF_E_DIMNUM 4 /* # array dimensions in auxiliary entry */ + +/* + * All symbols and sections have the following definition + */ + +struct COFF_syment +{ + union { + char e_name[E_SYMNMLEN]; /* Symbol name (first 8 characters) */ + struct { + char e_zeroes[4]; /* Leading zeros */ + char e_offset[4]; /* Offset if this is a header section */ + } e; + } e; + + char e_value[4]; /* Value (address) of the segment */ + char e_scnum[2]; /* Section number */ + char e_type[2]; /* Type of section */ + char e_sclass[1]; /* Loader class */ + char e_numaux[1]; /* Number of auxiliary entries which follow */ +}; + +#define COFF_N_BTMASK (0xf) /* Mask for important class bits */ +#define COFF_N_TMASK (0x30) /* Mask for important type bits */ +#define COFF_N_BTSHFT (4) /* # bits to shift class field */ +#define COFF_N_TSHIFT (2) /* # bits to shift type field */ + +/* + * Auxiliary entries because the main table is too limiting. + */ + +union COFF_auxent { + +/* + * Debugger information + */ + + struct { + char x_tagndx[4]; /* str, un, or enum tag indx */ + union { + struct { + char x_lnno[2]; /* declaration line number */ + char x_size[2]; /* str/union/array size */ + } x_lnsz; + char x_fsize[4]; /* size of function */ + } x_misc; + + union { + struct { /* if ISFCN, tag, or .bb */ + char x_lnnoptr[4]; /* ptr to fcn line # */ + char x_endndx[4]; /* entry ndx past block end */ + } x_fcn; + + struct { /* if ISARY, up to 4 dimen. */ + char x_dimen[E_DIMNUM][2]; + } x_ary; + } x_fcnary; + + char x_tvndx[2]; /* tv index */ + } x_sym; + +/* + * Source file names (debugger information) + */ + + union { + char x_fname[E_FILNMLEN]; + struct { + char x_zeroes[4]; + char x_offset[4]; + } x_n; + } x_file; + +/* + * Section information + */ + + struct { + char x_scnlen[4]; /* section length */ + char x_nreloc[2]; /* # relocation entries */ + char x_nlinno[2]; /* # line numbers */ + } x_scn; + +/* + * Transfer vector (branch table) + */ + + struct { + char x_tvfill[4]; /* tv fill value */ + char x_tvlen[2]; /* length of .tv */ + char x_tvran[2][2]; /* tv range */ + } x_tv; /* info about .tv section (in auxent of symbol .tv)) */ +}; + +#define COFF_SYMENT struct COFF_syment +#define COFF_SYMESZ 18 +#define COFF_AUXENT union COFF_auxent +#define COFF_AUXESZ 18 + +#define COFF_ETEXT "etext" + +/********************** RELOCATION DIRECTIVES **********************/ + +struct COFF_reloc { + char r_vaddr[4]; /* Virtual address of item */ + char r_symndx[4]; /* Symbol index in the symtab */ + char r_type[2]; /* Relocation type */ +}; + +#define COFF_RELOC struct COFF_reloc +#define COFF_RELSZ 10 + +#define COFF_DEF_DATA_SECTION_ALIGNMENT 4 +#define COFF_DEF_BSS_SECTION_ALIGNMENT 4 +#define COFF_DEF_TEXT_SECTION_ALIGNMENT 4 + +/* For new sections we havn't heard of before */ +#define COFF_DEF_SECTION_ALIGNMENT 4 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/config.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/config.h new file mode 100644 index 000000000..f4ed9084c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/config.h @@ -0,0 +1,91 @@ +#ifndef _LINUX_CONFIG_H +#define _LINUX_CONFIG_H + +#include + +/* + * Defines for what uname() should return + */ +#ifndef UTS_SYSNAME +#define UTS_SYSNAME "Linux" +#endif +#ifndef UTS_NODENAME +#define UTS_NODENAME "(none)" /* set by sethostname() */ +#endif + +#ifndef UTS_MACHINE +#define UTS_MACHINE "i386" /* hardware type */ +#endif + +#ifndef UTS_DOMAINNAME +#define UTS_DOMAINNAME "(none)" /* set by setdomainname() */ +#endif + +/* + * The definitions for UTS_RELEASE and UTS_VERSION are now defined + * in linux/version.h, and should only be used by linux/version.c + */ + +/* Don't touch these, unless you really know what your doing. */ +#define DEF_INITSEG 0x9000 +#define DEF_SYSSEG 0x1000 +#define DEF_SETUPSEG 0x9020 +#define DEF_SYSSIZE 0x7F00 + +/* internal svga startup constants */ +#define NORMAL_VGA 0xffff /* 80x25 mode */ +#define EXTENDED_VGA 0xfffe /* 80x50 mode */ +#define ASK_VGA 0xfffd /* ask for it at bootup */ + +/* + * The root-device is no longer hard-coded. You can change the default + * root-device by changing the line ROOT_DEV = XXX in boot/bootsect.s + */ + +/* + * The keyboard is now defined in kernel/chr_dev/keyboard.S + */ + +/* + * Normally, Linux can get the drive parameters from the BIOS at + * startup, but if this for some unfathomable reason fails, you'd + * be left stranded. For this case, you can define HD_TYPE, which + * contains all necessary info on your harddisk. + * + * The HD_TYPE macro should look like this: + * + * #define HD_TYPE { head, sect, cyl, wpcom, lzone, ctl} + * + * In case of two harddisks, the info should be sepatated by + * commas: + * + * #define HD_TYPE { h,s,c,wpcom,lz,ctl },{ h,s,c,wpcom,lz,ctl } + */ +/* + This is an example, two drives, first is type 2, second is type 3: + +#define HD_TYPE { 4,17,615,300,615,8 }, { 6,17,615,300,615,0 } + + NOTE: ctl is 0 for all drives with heads<=8, and ctl=8 for drives + with more than 8 heads. + + If you want the BIOS to tell what kind of drive you have, just + leave HD_TYPE undefined. This is the normal thing to do. +*/ + +#undef HD_TYPE + +/* + File type specific stuff goes into this. +*/ + +#ifdef ASM_SRC +#endif + +#ifdef C_SRC +#endif + +#ifdef MAKE +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ctype.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ctype.h new file mode 100644 index 000000000..838ef933d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ctype.h @@ -0,0 +1,34 @@ +#ifndef _LINUX_CTYPE_H +#define _LINUX_CTYPE_H + +#define _U 0x01 /* upper */ +#define _L 0x02 /* lower */ +#define _D 0x04 /* digit */ +#define _C 0x08 /* cntrl */ +#define _P 0x10 /* punct */ +#define _S 0x20 /* white space (space/lf/tab) */ +#define _X 0x40 /* hex digit */ +#define _SP 0x80 /* hard space (0x20) */ + +extern unsigned char _ctype[]; +extern char _ctmp; + +#define isalnum(c) ((_ctype+1)[c]&(_U|_L|_D)) +#define isalpha(c) ((_ctype+1)[c]&(_U|_L)) +#define iscntrl(c) ((_ctype+1)[c]&(_C)) +#define isdigit(c) ((_ctype+1)[c]&(_D)) +#define isgraph(c) ((_ctype+1)[c]&(_P|_U|_L|_D)) +#define islower(c) ((_ctype+1)[c]&(_L)) +#define isprint(c) ((_ctype+1)[c]&(_P|_U|_L|_D|_SP)) +#define ispunct(c) ((_ctype+1)[c]&(_P)) +#define isspace(c) ((_ctype+1)[c]&(_S)) +#define isupper(c) ((_ctype+1)[c]&(_U)) +#define isxdigit(c) ((_ctype+1)[c]&(_D|_X)) + +#define isascii(c) (((unsigned) c)<=0x7f) +#define toascii(c) (((unsigned) c)&0x7f) + +#define tolower(c) (_ctmp=c,isupper(_ctmp)?_ctmp-('A'-'a'):_ctmp) +#define toupper(c) (_ctmp=c,islower(_ctmp)?_ctmp-('a'-'A'):_ctmp) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ddi.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ddi.h new file mode 100644 index 000000000..a136b2a84 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ddi.h @@ -0,0 +1,79 @@ +/* + * ddi.h Define the structure for linking in I/O drivers into the + * operating system kernel. This method is currently only + * used by NET layer drivers, but it will be expanded into + * a link methos for ALL kernel-resident device drivers. + * + * Version: @(#)ddi.h 1.0.2 04/22/93 + * + * Author: Fred N. van Kempen, + */ +#ifndef _LINUX_DDI_H +#define _LINUX_DDI_H + + +/* DDI control block flags. */ +#define DDI_FREADY 0x10000000 /* device is initialized */ +#define DDI_FPRESENT 0x20000000 /* device hardware is present */ +#define DDI_FBLKDEV 0x00000001 /* device has a BLK spec. file */ +#define DDI_FCHRDEV 0x00000002 /* device has a CHR spec. file */ + +/* Various constants. */ +#define DDI_MAXNAME 16 /* length of a DDI ID string */ + + +/* This structure is used to set up a DDI driver. */ +struct ddconf { + int ioaddr; /* main I/O (port) address */ + int ioaux; /* auxiliary I/O (HD, AST) */ + int irq; /* IRQ channel */ + int dma; /* DMA channel to use */ + unsigned long memsize; /* size of onboard memory */ + unsigned long memaddr; /* base address of memory */ +}; + + +/* The DDI device control block. */ +struct ddi_device { + char *title; /* title of the driver */ + char name[DDI_MAXNAME]; /* unit name of the I/O driver */ + short int unit; /* unit number of this driver */ + short int nunits; /* number of units in driver */ + int (*init)(struct ddi_device *); /* initialization func */ + int (*handler)(int, ...); /* command handler */ + short int major; /* driver major dev number */ + short int minor; /* driver minor dev number */ + unsigned long flags; /* various flags */ + struct ddconf config; /* driver HW setup */ +}; + + +/* This structure is used to set up networking protocols. */ +struct ddi_proto { + char *name; /* protocol name */ + void (*init)(struct ddi_proto *); /* initialization func */ +}; + + +/* This structure is used to link a STREAMS interface. */ +struct iflink { + char id[DDI_MAXNAME]; /* DDI ID string */ + char stream[DDI_MAXNAME]; /* STREAMS interface name */ + int family; /* address (protocol) family */ + unsigned int flags; /* any flags needed (unused) */ +}; + + +/* DDI control requests. */ +#define DDIOCSDBG 0x9000 /* set DDI debug level */ +#define DDIOCGNAME 0x9001 /* get DDI ID name */ +#define DDIOCGCONF 0x9002 /* get DDI HW config */ +#define DDIOCSCONF 0x9003 /* set DDI HW config */ + + +/* DDI global functions. */ +extern void ddi_init(void); +extern struct ddi_device *ddi_map(const char *id); + + +#endif /* _LINUX_DDI_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/debugreg.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/debugreg.h new file mode 100644 index 000000000..ba93e10c6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/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/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/delay.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/delay.h new file mode 100644 index 000000000..e3621a2f9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/delay.h @@ -0,0 +1,37 @@ +#ifndef _LINUX_DELAY_H +#define _LINUX_DELAY_H + +/* + * Copyright (C) 1993 Linus Torvalds + * + * Delay routines, using a pre-computed "loops_per_second" value. + */ + +extern unsigned long loops_per_sec; + +extern __inline__ void __delay(int loops) +{ + __asm__(".align 2,0x90\n1:\tdecl %0\n\tjns 1b": :"a" (loops):"ax"); +} + +/* + * division by multiplication: you don't have to worry about + * loss of precision. + * + * Use only for very small delays ( < 1 msec). Should probably use a + * lookup table, really, as the multiplications take much too long with + * short delays. This is a "reasonable" implementation, though (and the + * first constant multiplications gets optimized away if the delay is + * a constant) + */ +extern __inline__ void udelay(unsigned long usecs) +{ + usecs *= 0x000010c6; /* 2**32 / 1000000 */ + __asm__("mull %0" + :"=d" (usecs) + :"a" (usecs),"0" (loops_per_sec) + :"ax"); + __delay(usecs); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/dirent.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/dirent.h new file mode 100644 index 000000000..219faf1cb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/dirent.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_DIRENT_H +#define _LINUX_DIRENT_H + +#include + +struct dirent { + long d_ino; + off_t d_off; + unsigned short d_reclen; + char d_name[NAME_MAX+1]; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/elf.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/elf.h new file mode 100644 index 000000000..fbad2da45 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/elf.h @@ -0,0 +1,153 @@ +#ifndef _ELF_H +#define _ELF_H + +/* THese constants are for the segment types stored in the image headers */ +#define PT_NULL 0 +#define PT_LOAD 1 +#define PT_DYNAMIC 2 +#define PT_INTERP 3 +#define PT_NOTE 4 +#define PT_SHLIB 5 +#define PT_PHDR 6 +#define PT_LOPROC 0x70000000 +#define PT_HIPROC 0x7fffffff + +/* These constants define the different elf file types */ +#define ET_NONE 0 +#define ET_REL 1 +#define ET_EXEC 2 +#define ET_DYN 3 +#define ET_CORE 4 +#define ET_LOPROC 5 +#define ET_HIPROC 6 + +/* These constants define the various ELF target machines */ +#define EM_NONE 0 +#define EM_M32 1 +#define EM_SPARC 2 +#define EM_386 3 +#define EM_68K 4 +#define EM_88K 5 +#define EM_486 6 /* Perhaps disused */ +#define EM_860 7 + +/* This is the info that is needed to parse the dynamic section of the file */ +#define DT_NULL 0 +#define DT_NEEDED 1 +#define DT_PLTRELSZ 2 +#define DT_PLTGOT 3 +#define DT_HASH 4 +#define DT_STRTAB 5 +#define DT_SYMTAB 6 +#define DT_RELA 7 +#define DT_RELASZ 8 +#define DT_RELAENT 9 +#define DT_STRSZ 10 +#define DT_SYMENT 11 +#define DT_INIT 12 +#define DT_FINI 13 +#define DT_SONAME 14 +#define DT_RPATH 15 +#define DT_SYMBOLIC 16 +#define DT_REL 17 +#define DT_RELSZ 18 +#define DT_RELENT 19 +#define DT_PLTREL 20 +#define DT_DEBUG 21 +#define DT_TEXTREL 22 +#define DT_JMPREL 23 +#define DT_LOPROC 0x70000000 +#define DT_HIPROC 0x7fffffff + +/* This info is needed when parsing the symbol table */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +#define STT_NOTYPE 0 +#define STT_OBJECT 1 +#define STT_FUNC 2 +#define STT_SECTION 3 +#define STT_FILE 4 + +#define ELF32_ST_BIND(x) ((x) >> 4) +#define ELF32_ST_TYPE(x) (((unsigned int) x) & 0xf) + + + +struct dynamic{ + int d_tag; + union{ + int d_val; + char * d_ptr; + } d_un; +}; + +/* THe following are used with relocations */ +#define ELF32_R_SYM(x) ((x) >> 8) +#define ELF32_R_TYPE(x) ((x) & 0xff) + +#define R_386_NONE 0 +#define R_386_32 1 +#define R_386_PC32 2 +#define R_386_GOT32 3 +#define R_386_PLT32 4 +#define R_386_COPY 5 +#define R_386_GLOB_DAT 6 +#define R_386_JMP_SLOT 7 +#define R_386_RELATIVE 8 +#define R_386_GOTOFF 9 +#define R_386_GOTPC 10 +#define R_386_NUM 11 + +struct Elf32_Rel{ + unsigned int * offset; + int info; +}; + +struct Elf32_Rela{ + unsigned int * offset; + int info; + int addend; +}; + +struct Elf32_Sym{ + int st_name; + unsigned int st_value; + int st_size; + unsigned char st_info; + unsigned char st_other; + short int st_shndx; +}; + +struct elfhdr{ + char e_ident[16]; + short int e_type; + short int e_machine; + int e_version; + char *e_entry; /* Entry point */ + int e_phoff; + int e_shoff; + int e_flags; + short int e_ehsize; + short int e_phentsize; + short int e_phnum; + short int e_shentsize; + short int e_shnum; + short int e_shstrndx; +}; + +struct elf_phdr{ + int p_type; + int p_offset; + int p_vaddr; + int p_paddr; + int p_filesz; + int p_memsz; + int p_flags; + int p_align; +}; + +#define ELF_START_MMAP 0x80000000 + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/errno.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/errno.h new file mode 100644 index 000000000..b2a8ec013 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/errno.h @@ -0,0 +1,132 @@ +#ifndef _LINUX_ERRNO_H +#define _LINUX_ERRNO_H + +#define EPERM 1 /* Operation not permitted */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No child processes */ +#define EAGAIN 11 /* Try again */ +#define ENOMEM 12 /* Out of memory */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Device or resource busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* File table overflow */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read-only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math argument out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define EDEADLK 35 /* Resource deadlock would occur */ +#define ENAMETOOLONG 36 /* File name too long */ +#define ENOLCK 37 /* No record locks available */ +#define ENOSYS 38 /* Function not implemented */ +#define ENOTEMPTY 39 /* Directory not empty */ +#define ELOOP 40 /* Too many symbolic links encountered */ +#define EWOULDBLOCK EAGAIN /* Operation would block */ +#define ENOMSG 42 /* No message of desired type */ +#define EIDRM 43 /* Identifier removed */ +#define ECHRNG 44 /* Channel number out of range */ +#define EL2NSYNC 45 /* Level 2 not synchronized */ +#define EL3HLT 46 /* Level 3 halted */ +#define EL3RST 47 /* Level 3 reset */ +#define ELNRNG 48 /* Link number out of range */ +#define EUNATCH 49 /* Protocol driver not attached */ +#define ENOCSI 50 /* No CSI structure available */ +#define EL2HLT 51 /* Level 2 halted */ +#define EBADE 52 /* Invalid exchange */ +#define EBADR 53 /* Invalid request descriptor */ +#define EXFULL 54 /* Exchange full */ +#define ENOANO 55 /* No anode */ +#define EBADRQC 56 /* Invalid request code */ +#define EBADSLT 57 /* Invalid slot */ +#define EDEADLOCK 58 /* File locking deadlock error */ +#define EBFONT 59 /* Bad font file format */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data available */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* Object is remote */ +#define ENOLINK 67 /* Link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 72 /* Multihop attempted */ +#define EDOTDOT 73 /* RFS specific error */ +#define EBADMSG 74 /* Not a data message */ +#define EOVERFLOW 75 /* Value too large for defined data type */ +#define ENOTUNIQ 76 /* Name not unique on network */ +#define EBADFD 77 /* File descriptor in bad state */ +#define EREMCHG 78 /* Remote address changed */ +#define ELIBACC 79 /* Can not access a needed shared library */ +#define ELIBBAD 80 /* Accessing a corrupted shared library */ +#define ELIBSCN 81 /* .lib section in a.out corrupted */ +#define ELIBMAX 82 /* Attempting to link in too many shared libraries */ +#define ELIBEXEC 83 /* Cannot exec a shared library directly */ +#define EILSEQ 84 /* Illegal byte sequence */ +#define ERESTART 85 /* Interrupted system call should be restarted */ +#define ESTRPIPE 86 /* Streams pipe error */ +#define EUSERS 87 /* Too many users */ +#define ENOTSOCK 88 /* Socket operation on non-socket */ +#define EDESTADDRREQ 89 /* Destination address required */ +#define EMSGSIZE 90 /* Message too long */ +#define EPROTOTYPE 91 /* Protocol wrong type for socket */ +#define ENOPROTOOPT 92 /* Protocol not available */ +#define EPROTONOSUPPORT 93 /* Protocol not supported */ +#define ESOCKTNOSUPPORT 94 /* Socket type not supported */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define EAFNOSUPPORT 97 /* Address family not supported by protocol */ +#define EADDRINUSE 98 /* Address already in use */ +#define EADDRNOTAVAIL 99 /* Cannot assign requested address */ +#define ENETDOWN 100 /* Network is down */ +#define ENETUNREACH 101 /* Network is unreachable */ +#define ENETRESET 102 /* Network dropped connection because of reset */ +#define ECONNABORTED 103 /* Software caused connection abort */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EISCONN 106 /* Transport endpoint is already connected */ +#define ENOTCONN 107 /* Transport endpoint is not connected */ +#define ESHUTDOWN 108 /* Cannot send after transport endpoint shutdown */ +#define ETOOMANYREFS 109 /* Too many references: cannot splice */ +#define ETIMEDOUT 110 /* Connection timed out */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EHOSTDOWN 112 /* Host is down */ +#define EHOSTUNREACH 113 /* No route to host */ +#define EALREADY 114 /* Operation already in progress */ +#define EINPROGRESS 115 /* Operation now in progress */ +#define ESTALE 116 /* Stale NFS file handle */ +#define EUCLEAN 117 /* Structure needs cleaning */ +#define ENOTNAM 118 /* Not a XENIX named type file */ +#define ENAVAIL 119 /* No XENIX semaphores available */ +#define EISNAM 120 /* Is a named type file */ +#define EREMOTEIO 121 /* Remote I/O error */ +#define EDQUOT 122 /* Quota exceeded */ + +/* Should never be seen by user programs */ +#define ERESTARTSYS 512 +#define ERESTARTNOINTR 513 +#define ERESTARTNOHAND 514 /* restart if no handler.. */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs.h new file mode 100644 index 000000000..7b7bfbb45 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs.h @@ -0,0 +1,447 @@ +/* + * linux/include/linux/ext2_fs.h + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_H +#define _LINUX_EXT2_FS_H + +/* + * The second extended filesystem constants/structures + */ + +/* + * Define EXT2FS_DEBUG to produce debug messages + */ +#undef EXT2FS_DEBUG + +/* + * Define EXT2FS_DEBUG_CACHE to produce cache debug messages + */ +#undef EXT2FS_DEBUG_CACHE + +/* + * Define EXT2FS_CHECK_CACHE to add some checks to the name cache code + */ +#undef EXT2FS_CHECK_CACHE + +/* + * Define EXT2FS_PRE_02B_COMPAT to convert ext 2 fs prior to 0.2b + */ +#undef EXT2FS_PRE_02B_COMPAT + +/* + * Define DONT_USE_DCACHE to inhibit the directory cache + */ +#define DONT_USE_DCACHE + +/* + * Define EXT2_PREALLOCATE to preallocate data blocks for expanding files + */ +#define EXT2_PREALLOCATE + +/* + * The second extended file system version + */ +#define EXT2FS_DATE "94/01/08" +#define EXT2FS_VERSION "0.4b" + +/* + * Debug code + */ +#ifdef EXT2FS_DEBUG +# define ext2_debug(f, a...) { \ + printk ("EXT2-fs DEBUG (%s, %d): %s:", \ + __FILE__, __LINE__, __FUNCTION__); \ + printk (f, ## a); \ + } +#else +# define ext2_debug(f, a...) /**/ +#endif + +/* + * Special inodes numbers + */ +#define EXT2_BAD_INO 1 /* Bad blocks inode */ +#define EXT2_ROOT_INO 2 /* Root inode */ +#define EXT2_ACL_IDX_INO 3 /* ACL inode */ +#define EXT2_ACL_DATA_INO 4 /* ACL inode */ +#define EXT2_BOOT_LOADER_INO 5 /* Boot loader inode */ +#define EXT2_UNDEL_DIR_INO 6 /* Undelete directory inode */ +#define EXT2_FIRST_INO 11 /* First non reserved inode */ + +/* + * The second extended file system magic number + */ +#define EXT2_PRE_02B_MAGIC 0xEF51 +#define EXT2_SUPER_MAGIC 0xEF53 + +/* + * Maximal count of links to a file + */ +#define EXT2_LINK_MAX 32000 + +/* + * Macro-instructions used to manage several block sizes + */ +#define EXT2_MIN_BLOCK_SIZE 1024 +#define EXT2_MAX_BLOCK_SIZE 4096 +#define EXT2_MIN_BLOCK_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE(s) ((s)->s_blocksize) +#else +# define EXT2_BLOCK_SIZE(s) (EXT2_MIN_BLOCK_SIZE << (s)->s_log_block_size) +#endif +#define EXT2_ACLE_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_acl_entry)) +#define EXT2_ADDR_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (unsigned long)) +#ifdef __KERNEL__ +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->u.ext2_sb.s_es->s_log_block_size + 10) +#else +# define EXT2_BLOCK_SIZE_BITS(s) ((s)->s_log_block_size + 10) +#endif +#define EXT2_INODES_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_inode)) + +/* + * Macro-instructions used to manage fragments + */ +#define EXT2_MIN_FRAG_SIZE 1024 +#define EXT2_MAX_FRAG_SIZE 4096 +#define EXT2_MIN_FRAG_LOG_SIZE 10 +#ifdef __KERNEL__ +# define EXT2_FRAG_SIZE(s) ((s)->u.ext2_sb.s_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) ((s)->u.ext2_sb.s_frags_per_block) +#else +# define EXT2_FRAG_SIZE(s) (EXT2_MIN_FRAG_SIZE << (s)->s_log_frag_size) +# define EXT2_FRAGS_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / EXT2_FRAG_SIZE(s)) +#endif + +/* + * ACL structures + */ +struct ext2_acl_header /* Header of Access Control Lists */ +{ + unsigned long aclh_size; + unsigned long aclh_file_count; + unsigned long aclh_acle_count; + unsigned long aclh_first_acle; +}; + +struct ext2_acl_entry /* Access Control List Entry */ +{ + unsigned long acle_size; + unsigned short acle_perms; /* Access permissions */ + unsigned short acle_type; /* Type of entry */ + unsigned short acle_tag; /* User or group identity */ + unsigned short acle_pad1; + unsigned long acle_next; /* Pointer on next entry for the */ + /* same inode or on next free entry */ +}; + +/* + * Structure of a blocks group descriptor + */ +struct ext2_old_group_desc +{ + unsigned long bg_block_bitmap; /* Blocks bitmap block */ + unsigned long bg_inode_bitmap; /* Inodes bitmap block */ + unsigned long bg_inode_table; /* Inodes table block */ + unsigned short bg_free_blocks_count; /* Free blocks count */ + unsigned short bg_free_inodes_count; /* Free inodes count */ +}; + +struct ext2_group_desc +{ + unsigned long bg_block_bitmap; /* Blocks bitmap block */ + unsigned long bg_inode_bitmap; /* Inodes bitmap block */ + unsigned long bg_inode_table; /* Inodes table block */ + unsigned short bg_free_blocks_count; /* Free blocks count */ + unsigned short bg_free_inodes_count; /* Free inodes count */ + unsigned short bg_used_dirs_count; /* Directories count */ + unsigned short bg_pad; + unsigned long bg_reserved[3]; +}; + +/* + * Macro-instructions used to manage group descriptors + */ +#ifdef __KERNEL__ +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->u.ext2_sb.s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) ((s)->u.ext2_sb.s_desc_per_block) +# define EXT2_INODES_PER_GROUP(s) ((s)->u.ext2_sb.s_inodes_per_group) +#else +# define EXT2_BLOCKS_PER_GROUP(s) ((s)->s_blocks_per_group) +# define EXT2_DESC_PER_BLOCK(s) (EXT2_BLOCK_SIZE(s) / sizeof (struct ext2_group_desc)) +# define EXT2_INODES_PER_GROUP(s) ((s)->s_inodes_per_group) +#endif + +/* + * Constants relative to the data blocks + */ +#define EXT2_NDIR_BLOCKS 12 +#define EXT2_IND_BLOCK EXT2_NDIR_BLOCKS +#define EXT2_DIND_BLOCK (EXT2_IND_BLOCK + 1) +#define EXT2_TIND_BLOCK (EXT2_DIND_BLOCK + 1) +#define EXT2_N_BLOCKS (EXT2_TIND_BLOCK + 1) + +/* + * Inode flags + */ +#define EXT2_SECRM_FL 0x0001 /* Secure deletion */ +#define EXT2_UNRM_FL 0x0002 /* Undelete */ +#define EXT2_COMPR_FL 0x0004 /* Compress file */ +#define EXT2_SYNC_FL 0x0008 /* Synchronous updates */ + +/* + * ioctl commands + */ +#define EXT2_IOC_GETFLAGS _IOR('f', 1, long) +#define EXT2_IOC_SETFLAGS _IOW('f', 2, long) +#define EXT2_IOC_GETVERSION _IOR('v', 1, long) +#define EXT2_IOC_SETVERSION _IOW('v', 2, long) + +/* + * Structure of an inode on the disk + */ +struct ext2_inode { + unsigned short i_mode; /* File mode */ + unsigned short i_uid; /* Owner Uid */ + unsigned long i_size; /* Size in bytes */ + unsigned long i_atime; /* Access time */ + unsigned long i_ctime; /* Creation time */ + unsigned long i_mtime; /* Modification time */ + unsigned long i_dtime; /* Deletion Time */ + unsigned short i_gid; /* Group Id */ + unsigned short i_links_count; /* Links count */ + unsigned long i_blocks; /* Blocks count */ + unsigned long i_flags; /* File flags */ + unsigned long i_reserved1; + unsigned long i_block[EXT2_N_BLOCKS];/* Pointers to blocks */ + unsigned long i_version; /* File version (for NFS) */ + unsigned long i_file_acl; /* File ACL */ + unsigned long i_dir_acl; /* Directory ACL */ + unsigned long i_faddr; /* Fragment address */ + unsigned char i_frag; /* Fragment number */ + unsigned char i_fsize; /* Fragment size */ + unsigned short i_pad1; + unsigned long i_reserved2[2]; +}; + +/* + * File system states + */ +#define EXT2_VALID_FS 0x0001 /* Unmounted cleany */ +#define EXT2_ERROR_FS 0x0002 /* Errors detected */ + +/* + * Mount flags + */ +#define EXT2_MOUNT_CHECK_NORMAL 0x0001 /* Do some more checks */ +#define EXT2_MOUNT_CHECK_STRICT 0x0002 /* Do again more checks */ +#define EXT2_MOUNT_CHECK (EXT2_MOUNT_CHECK_NORMAL | \ + EXT2_MOUNT_CHECK_STRICT) +#define EXT2_MOUNT_GRPID 0x0004 /* Create files with directory's group */ +#define EXT2_MOUNT_DEBUG 0x0008 /* Some debugging messages */ +#define EXT2_MOUNT_ERRORS_CONT 0x0010 /* Continue on errors */ +#define EXT2_MOUNT_ERRORS_RO 0x0020 /* Remount fs ro on errors */ +#define EXT2_MOUNT_ERRORS_PANIC 0x0040 /* Panic on errors */ + +#define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt +#define set_opt(o, opt) o |= EXT2_MOUNT_##opt +#define test_opt(sb, opt) ((sb)->u.ext2_sb.s_mount_opt & \ + EXT2_MOUNT_##opt) +/* + * Maximal mount counts between two filesystem checks + */ +#define EXT2_DFL_MAX_MNT_COUNT 20 /* Allow 20 mounts */ + +/* + * Behaviour when detecting errors + */ +#define EXT2_ERRORS_CONTINUE 1 /* Continue execution */ +#define EXT2_ERRORS_RO 2 /* Remount fs read-only */ +#define EXT2_ERRORS_PANIC 3 /* Panic */ +#define EXT2_ERRORS_DEFAULT EXT2_ERRORS_CONTINUE + +/* + * Structure of the super block + */ +struct ext2_super_block { + unsigned long s_inodes_count; /* Inodes count */ + unsigned long s_blocks_count; /* Blocks count */ + unsigned long s_r_blocks_count;/* Reserved blocks count */ + unsigned long s_free_blocks_count;/* Free blocks count */ + unsigned long s_free_inodes_count;/* Free inodes count */ + unsigned long s_first_data_block;/* First Data Block */ + unsigned long s_log_block_size;/* Block size */ + long s_log_frag_size; /* Fragment size */ + unsigned long s_blocks_per_group;/* # Blocks per group */ + unsigned long s_frags_per_group;/* # Fragments per group */ + unsigned long s_inodes_per_group;/* # Inodes per group */ + unsigned long s_mtime; /* Mount time */ + unsigned long s_wtime; /* Write time */ + unsigned short s_mnt_count; /* Mount count */ + short s_max_mnt_count; /* Maximal mount count */ + unsigned short s_magic; /* Magic signature */ + unsigned short s_state; /* File system state */ + unsigned short s_errors; /* Behaviour when detecting errors */ + unsigned short s_pad; + unsigned long s_reserved[240]; /* Padding to the end of the block */ +}; + +/* + * Structure of a directory entry + */ +#define EXT2_NAME_LEN 255 + +struct ext2_dir_entry { + unsigned long inode; /* Inode number */ + unsigned short rec_len; /* Directory entry length */ + unsigned short name_len; /* Name length */ + char name[EXT2_NAME_LEN]; /* File name */ +}; + +/* + * EXT2_DIR_PAD defines the directory entries boundaries + * + * NOTE: It must be a multiple of 4 + */ +#define EXT2_DIR_PAD 4 +#define EXT2_DIR_ROUND (EXT2_DIR_PAD - 1) +#define EXT2_DIR_REC_LEN(name_len) (((name_len) + 8 + EXT2_DIR_ROUND) & \ + ~EXT2_DIR_ROUND) + +#ifdef __KERNEL__ +/* + * Function prototypes + */ + +/* + * Ok, these declarations are also in but none of the + * ext2 source programs needs to include it so they are duplicated here. + */ +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define NORET_TYPE __volatile__ +# define ATTRIB_NORET /**/ +# define NORET_AND /**/ +#else +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, +#endif + +/* acl.c */ +extern int ext2_permission (struct inode *, int); + +/* balloc.c */ +extern int ext2_new_block (struct super_block *, unsigned long, + unsigned long *, unsigned long *); +extern void ext2_free_blocks (struct super_block *, unsigned long, + unsigned long); +extern unsigned long ext2_count_free_blocks (struct super_block *); +extern void ext2_check_blocks_bitmap (struct super_block *); + +/* bitmap.c */ +extern unsigned long ext2_count_free (struct buffer_head *, unsigned); + +#ifndef DONT_USE_DCACHE +/* dcache.c */ +extern void ext2_dcache_invalidate (unsigned short); +extern unsigned long ext2_dcache_lookup (unsigned short, unsigned long, + const char *, int); +extern void ext2_dcache_add (unsigned short, unsigned long, const char *, + int, unsigned long); +extern void ext2_dcache_remove (unsigned short, unsigned long, const char *, + int); +#endif + +/* dir.c */ +extern int ext2_check_dir_entry (char *, struct inode *, + struct ext2_dir_entry *, struct buffer_head *, + unsigned long); + +/* file.c */ +extern int ext2_read (struct inode *, struct file *, char *, int); +extern int ext2_write (struct inode *, struct file *, char *, int); + +/* fsync.c */ +extern int ext2_sync_file (struct inode *, struct file *); + +/* ialloc.c */ +extern struct inode * ext2_new_inode (const struct inode *, int); +extern void ext2_free_inode (struct inode *); +extern unsigned long ext2_count_free_inodes (struct super_block *); +extern void ext2_check_inodes_bitmap (struct super_block *); + +/* inode.c */ +extern int ext2_bmap (struct inode *, int); + +extern struct buffer_head * ext2_getblk (struct inode *, long, int, int *); +extern struct buffer_head * ext2_bread (struct inode *, int, int, int *); + +extern void ext2_read_inode (struct inode *); +extern void ext2_write_inode (struct inode *); +extern void ext2_put_inode (struct inode *); +extern int ext2_sync_inode (struct inode *); +extern void ext2_discard_prealloc (struct inode *); + +/* ioctl.c */ +extern int ext2_ioctl (struct inode *, struct file *, unsigned int, + unsigned long); + +/* namei.c */ +extern int ext2_open (struct inode *, struct file *); +extern void ext2_release (struct inode *, struct file *); +extern int ext2_lookup (struct inode *,const char *, int, struct inode **); +extern int ext2_create (struct inode *,const char *, int, int, + struct inode **); +extern int ext2_mkdir (struct inode *, const char *, int, int); +extern int ext2_rmdir (struct inode *, const char *, int); +extern int ext2_unlink (struct inode *, const char *, int); +extern int ext2_symlink (struct inode *, const char *, int, const char *); +extern int ext2_link (struct inode *, struct inode *, const char *, int); +extern int ext2_mknod (struct inode *, const char *, int, int, int); +extern int ext2_rename (struct inode *, const char *, int, + struct inode *, const char *, int); + +/* super.c */ +extern void ext2_error (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern NORET_TYPE void ext2_panic (struct super_block *, const char *, + const char *, ...) + __attribute__ ((NORET_AND format (printf, 3, 4))); +extern void ext2_warning (struct super_block *, const char *, const char *, ...) + __attribute__ ((format (printf, 3, 4))); +extern void ext2_put_super (struct super_block *); +extern void ext2_write_super (struct super_block *); +extern int ext2_remount (struct super_block *, int *, char *); +extern struct super_block * ext2_read_super (struct super_block *,void *,int); +extern void ext2_statfs (struct super_block *, struct statfs *); + +/* truncate.c */ +extern void ext2_truncate (struct inode *); + +/* + * Inodes and files operations + */ + +/* dir.c */ +extern struct inode_operations ext2_dir_inode_operations; + +/* file.c */ +extern struct inode_operations ext2_file_inode_operations; + +/* symlink.c */ +extern struct inode_operations ext2_symlink_inode_operations; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_EXT2_FS_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_i.h new file mode 100644 index 000000000..777b37bd2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_i.h @@ -0,0 +1,39 @@ +/* + * linux/include/linux/ext2_fs_i.h + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_i.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_I +#define _LINUX_EXT2_FS_I + +/* + * second extended file system inode data in memory + */ +struct ext2_inode_info { + unsigned long i_data[15]; + unsigned long i_flags; + unsigned long i_faddr; + unsigned char i_frag; + unsigned char i_fsize; + unsigned short i_pad1; + unsigned long i_file_acl; + unsigned long i_dir_acl; + unsigned long i_dtime; + unsigned long i_version; + unsigned long i_block_group; + unsigned long i_next_alloc_block; + unsigned long i_next_alloc_goal; + unsigned long i_prealloc_block; + unsigned long i_prealloc_count; +}; + +#endif /* _LINUX_EXT2_FS_I */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_sb.h new file mode 100644 index 000000000..33af83884 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext2_fs_sb.h @@ -0,0 +1,49 @@ +/* + * linux/include/linux/ext2_fs_sb.h + * + * Copyright (C) 1992, 1993, 1994 Remy Card (card@masi.ibp.fr) + * Laboratoire MASI - Institut Blaise Pascal + * Universite Pierre et Marie Curie (Paris VI) + * + * from + * + * linux/include/linux/minix_fs_sb.h + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef _LINUX_EXT2_FS_SB +#define _LINUX_EXT2_FS_SB + +#define EXT2_MAX_GROUP_DESC 8 +#define EXT2_MAX_GROUP_LOADED 8 + +/* + * second extended-fs super-block data in memory + */ +struct ext2_sb_info { + unsigned long s_frag_size; /* Size of a fragment in bytes */ + unsigned long s_frags_per_block;/* Number of fragments per block */ + unsigned long s_inodes_per_block;/* Number of inodes per block */ + unsigned long s_frags_per_group;/* Number of fragments in a group */ + unsigned long s_blocks_per_group;/* Number of blocks in a group */ + unsigned long s_inodes_per_group;/* Number of inodes in a group */ + unsigned long s_itb_per_group; /* Number of inode table blocks per group */ + unsigned long s_desc_per_block; /* Number of group descriptors per block */ + unsigned long s_groups_count; /* Number of groups in the fs */ + struct buffer_head * s_sbh; /* Buffer containing the super block */ + struct ext2_super_block * s_es; /* Pointer to the super block in the buffer */ + struct buffer_head * s_group_desc[EXT2_MAX_GROUP_DESC]; + unsigned short s_loaded_inode_bitmaps; + unsigned short s_loaded_block_bitmaps; + unsigned long s_inode_bitmap_number[EXT2_MAX_GROUP_LOADED]; + struct buffer_head * s_inode_bitmap[EXT2_MAX_GROUP_LOADED]; + unsigned long s_block_bitmap_number[EXT2_MAX_GROUP_LOADED]; + struct buffer_head * s_block_bitmap[EXT2_MAX_GROUP_LOADED]; + int s_rename_lock; + struct wait_queue * s_rename_wait; + unsigned long s_mount_opt; + unsigned short s_mount_state; +}; + +#endif /* _LINUX_EXT2_FS_SB */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs.h new file mode 100644 index 000000000..c2380df3c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs.h @@ -0,0 +1,108 @@ +#ifndef _LINUX_EXT_FS_H +#define _LINUX_EXT_FS_H + +/* + * The ext filesystem constants/structures + */ + +#define EXT_NAME_LEN 255 +#define EXT_ROOT_INO 1 + +#define EXT_SUPER_MAGIC 0x137D + +#define EXT_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct ext_inode))) + +struct ext_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_time; + unsigned short i_gid; + unsigned short i_nlinks; + unsigned long i_zone[12]; +}; + +struct ext_free_inode { + unsigned long count; + unsigned long free[14]; + unsigned long next; +}; + +struct ext_free_block { + unsigned long count; + unsigned long free[254]; + unsigned long next; +}; + +struct ext_super_block { + unsigned long s_ninodes; + unsigned long s_nzones; + unsigned long s_firstfreeblock; + unsigned long s_freeblockscount; + unsigned long s_firstfreeinode; + unsigned long s_freeinodescount; + unsigned long s_firstdatazone; + unsigned long s_log_zone_size; + unsigned long s_max_size; + unsigned long s_reserved1; + unsigned long s_reserved2; + unsigned long s_reserved3; + unsigned long s_reserved4; + unsigned long s_reserved5; + unsigned short s_magic; +}; + +struct ext_dir_entry { + unsigned long inode; + unsigned short rec_len; + unsigned short name_len; + char name[EXT_NAME_LEN]; +}; + +extern int ext_open(struct inode * inode, struct file * filp); +extern void ext_release(struct inode * inode, struct file * filp); +extern int ext_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern int ext_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); +extern int ext_mkdir(struct inode * dir, const char * name, int len, int mode); +extern int ext_rmdir(struct inode * dir, const char * name, int len); +extern int ext_unlink(struct inode * dir, const char * name, int len); +extern int ext_symlink(struct inode * inode, const char * name, int len, + const char * symname); +extern int ext_link(struct inode * oldinode, struct inode * dir, const char * name, int len); +extern int ext_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); +extern int ext_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len); +extern struct inode * ext_new_inode(const struct inode * dir); +extern void ext_free_inode(struct inode * inode); +extern unsigned long ext_count_free_inodes(struct super_block *sb); +extern int ext_new_block(struct super_block * sb); +extern void ext_free_block(struct super_block * sb, int block); +extern unsigned long ext_count_free_blocks(struct super_block *sb); + +extern int ext_bmap(struct inode *,int); + +extern struct buffer_head * ext_getblk(struct inode *, int, int); +extern struct buffer_head * ext_bread(struct inode *, int, int); + +extern void ext_truncate(struct inode *); +extern void ext_put_super(struct super_block *); +extern void ext_write_super(struct super_block *); +extern struct super_block *ext_read_super(struct super_block *,void *,int); +extern void ext_read_inode(struct inode *); +extern void ext_write_inode(struct inode *); +extern void ext_put_inode(struct inode *); +extern void ext_statfs(struct super_block *, struct statfs *); +extern int ext_sync_inode(struct inode *); +extern int ext_sync_file(struct inode *, struct file *); + +extern int ext_lseek(struct inode *, struct file *, off_t, int); +extern int ext_read(struct inode *, struct file *, char *, int); +extern int ext_write(struct inode *, struct file *, char *, int); + +extern struct inode_operations ext_file_inode_operations; +extern struct inode_operations ext_dir_inode_operations; +extern struct inode_operations ext_symlink_inode_operations; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_i.h new file mode 100644 index 000000000..32734f95f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_i.h @@ -0,0 +1,11 @@ +#ifndef _EXT_FS_I +#define _EXT_FS_I + +/* + * extended file system inode data in memory + */ +struct ext_inode_info { + unsigned long i_data[16]; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_sb.h new file mode 100644 index 000000000..19004d80f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ext_fs_sb.h @@ -0,0 +1,21 @@ +#ifndef _EXT_FS_SB +#define _EXT_FS_SB + +/* + * extended-fs super-block data in memory + */ +struct ext_sb_info { + unsigned long s_ninodes; + unsigned long s_nzones; + unsigned long s_firstdatazone; + unsigned long s_log_zone_size; + unsigned long s_max_size; + unsigned long s_firstfreeblocknumber; + unsigned long s_freeblockscount; + struct buffer_head * s_firstfreeblock; + unsigned long s_firstfreeinodenumber; + unsigned long s_freeinodescount; + struct buffer_head * s_firstfreeinodeblock; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fcntl.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fcntl.h new file mode 100644 index 000000000..c39006210 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fcntl.h @@ -0,0 +1,49 @@ +#ifndef _LINUX_FCNTL_H +#define _LINUX_FCNTL_H + +/* open/fcntl - O_SYNC isn't implemented yet */ +#define O_ACCMODE 0003 +#define O_RDONLY 00 +#define O_WRONLY 01 +#define O_RDWR 02 +#define O_CREAT 0100 /* not fcntl */ +#define O_EXCL 0200 /* not fcntl */ +#define O_NOCTTY 0400 /* not fcntl */ +#define O_TRUNC 01000 /* not fcntl */ +#define O_APPEND 02000 +#define O_NONBLOCK 04000 +#define O_NDELAY O_NONBLOCK +#define O_SYNC 010000 + +#define F_DUPFD 0 /* dup */ +#define F_GETFD 1 /* get f_flags */ +#define F_SETFD 2 /* set f_flags */ +#define F_GETFL 3 /* more flags (cloexec) */ +#define F_SETFL 4 +#define F_GETLK 5 +#define F_SETLK 6 +#define F_SETLKW 7 + +#define F_SETOWN 8 /* for sockets. */ +#define F_GETOWN 9 /* for sockets. */ + +/* for F_[GET|SET]FL */ +#define FD_CLOEXEC 1 /* actually anything with low bit set goes */ + +#define F_RDLCK 0 +#define F_WRLCK 1 +#define F_UNLCK 2 + +/* For bsd flock () */ +#define F_EXLCK 4 /* or 3 */ +#define F_SHLCK 8 /* or 4 */ + +struct flock { + short l_type; + short l_whence; + off_t l_start; + off_t l_len; + pid_t l_pid; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fd.h new file mode 100644 index 000000000..12332f3e3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fd.h @@ -0,0 +1,43 @@ +#ifndef _LINUX_FD_H +#define _LINUX_FD_H + +#define FDCLRPRM 0 /* clear user-defined parameters */ +#define FDSETPRM 1 /* set user-defined parameters for current media */ +#define FDDEFPRM 2 /* set user-defined parameters until explicitly cleared */ +#define FDGETPRM 3 /* get disk parameters */ +#define FDMSGON 4 /* issue kernel messages on media type change */ +#define FDMSGOFF 5 /* don't issue kernel messages on media type change */ +#define FDFMTBEG 6 /* begin formatting a disk */ +#define FDFMTTRK 7 /* format the specified track */ +#define FDFMTEND 8 /* end formatting a disk */ +#define FDSETEMSGTRESH 10 /* set fdc error reporting treshold */ +#define FDFLUSH 11 /* flush buffers for media; either for verifying media, or for + handling a media change without closing the file + descriptor */ + +#define FD_FILL_BYTE 0xF6 /* format fill byte */ + +#define FORMAT_NONE 0 /* no format request */ +#define FORMAT_WAIT 1 /* format request is waiting */ +#define FORMAT_BUSY 2 /* formatting in progress */ +#define FORMAT_OKAY 3 /* successful completion */ +#define FORMAT_ERROR 4 /* formatting error */ + +struct floppy_struct { + unsigned int size, /* nr of 512-byte sectors total */ + sect, /* sectors per track */ + head, /* nr of heads */ + track, /* nr of tracks */ + stretch; /* !=0 means double track steps */ + unsigned char gap, /* gap1 size */ + rate, /* data rate. |= 0x40 for perpendicular */ + spec1, /* stepping rate, head unload time */ + fmt_gap; /* gap2 size */ + char * name; /* used only for predefined formats */ +}; + +struct format_descr { + unsigned int device,head,track; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fdreg.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fdreg.h new file mode 100644 index 000000000..de1e9f6fe --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fdreg.h @@ -0,0 +1,73 @@ +#ifndef _LINUX_FDREG_H +#define _LINUX_FDREG_H +/* + * This file contains some defines for the floppy disk controller. + * Various sources. Mostly "IBM Microcomputers: A Programmers + * Handbook", Sanches and Canton. + */ + +/* Fd controller regs. S&C, about page 340 */ +#define FD_STATUS 0x3f4 +#define FD_DATA 0x3f5 +#define FD_DOR 0x3f2 /* Digital Output Register */ +#define FD_DIR 0x3f7 /* Digital Input Register (read) */ +#define FD_DCR 0x3f7 /* Diskette Control Register (write)*/ + +/* Bits of main status register */ +#define STATUS_BUSYMASK 0x0F /* drive busy mask */ +#define STATUS_BUSY 0x10 /* FDC busy */ +#define STATUS_DMA 0x20 /* 0- DMA mode */ +#define STATUS_DIR 0x40 /* 0- cpu->fdc */ +#define STATUS_READY 0x80 /* Data reg ready */ + +/* Bits of FD_ST0 */ +#define ST0_DS 0x03 /* drive select mask */ +#define ST0_HA 0x04 /* Head (Address) */ +#define ST0_NR 0x08 /* Not Ready */ +#define ST0_ECE 0x10 /* Equipment chech error */ +#define ST0_SE 0x20 /* Seek end */ +#define ST0_INTR 0xC0 /* Interrupt code mask */ + +/* Bits of FD_ST1 */ +#define ST1_MAM 0x01 /* Missing Address Mark */ +#define ST1_WP 0x02 /* Write Protect */ +#define ST1_ND 0x04 /* No Data - unreadable */ +#define ST1_OR 0x10 /* OverRun */ +#define ST1_CRC 0x20 /* CRC error in data or addr */ +#define ST1_EOC 0x80 /* End Of Cylinder */ + +/* Bits of FD_ST2 */ +#define ST2_MAM 0x01 /* Missing Addess Mark (again) */ +#define ST2_BC 0x02 /* Bad Cylinder */ +#define ST2_SNS 0x04 /* Scan Not Satisfied */ +#define ST2_SEH 0x08 /* Scan Equal Hit */ +#define ST2_WC 0x10 /* Wrong Cylinder */ +#define ST2_CRC 0x20 /* CRC error in data field */ +#define ST2_CM 0x40 /* Control Mark = deleted */ + +/* Bits of FD_ST3 */ +#define ST3_HA 0x04 /* Head (Address) */ +#define ST3_TZ 0x10 /* Track Zero signal (1=track 0) */ +#define ST3_WP 0x40 /* Write Protect */ + +/* Values for FD_COMMAND */ +#define FD_RECALIBRATE 0x07 /* move to track 0 */ +#define FD_SEEK 0x0F /* seek track */ +#define FD_READ 0xE6 /* read with MT, MFM, SKip deleted */ +#define FD_WRITE 0xC5 /* write with MT, MFM */ +#define FD_SENSEI 0x08 /* Sense Interrupt Status */ +#define FD_SPECIFY 0x03 /* specify HUT etc */ +#define FD_FORMAT 0x4D /* format one track */ +#define FD_VERSION 0x10 /* get version code */ +#define FD_CONFIGURE 0x13 /* configure FIFO operation */ +#define FD_PERPENDICULAR 0x12 /* perpendicular r/w mode */ + +/* DMA commands */ +#define DMA_READ 0x46 +#define DMA_WRITE 0x4A + +/* FDC version return types */ +#define FDC_TYPE_STD 0x80 /* normal 8272A clone FDC */ +#define FDC_TYPE_82077 0x90 /* FIFO + perpendicular support */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fs.h new file mode 100644 index 000000000..cac50aa36 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/fs.h @@ -0,0 +1,411 @@ +#ifndef _LINUX_FS_H +#define _LINUX_FS_H + +/* + * This file has definitions for some important file table + * structures etc. + */ + +#include +#include +#include +#include +#include +#include +#include + +/* + * It's silly to have NR_OPEN bigger than NR_FILE, but I'll fix + * that later. Anyway, now the file code is no longer dependent + * on bitmaps in unsigned longs, but uses the new fd_set structure.. + * + * Some programs (notably those using select()) may have to be + * recompiled to take full advantage of the new limits.. + */ +#undef NR_OPEN +#define NR_OPEN 256 + +#define NR_INODE 2048 /* this should be bigger than NR_FILE */ +#define NR_FILE 1024 /* this can well be larger on a larger system */ +#define NR_SUPER 32 +#define NR_HASH 997 +#define NR_IHASH 131 +#define NR_FILE_LOCKS 64 +#define BLOCK_SIZE 1024 +#define BLOCK_SIZE_BITS 10 + +#define MAY_EXEC 1 +#define MAY_WRITE 2 +#define MAY_READ 4 + +#define READ 0 +#define WRITE 1 +#define READA 2 /* read-ahead - don't pause */ +#define WRITEA 3 /* "write-ahead" - silly, but somewhat useful */ + +extern void buffer_init(void); +extern unsigned long inode_init(unsigned long start, unsigned long end); +extern unsigned long file_table_init(unsigned long start, unsigned long end); + +#define MAJOR(a) (int)((unsigned short)(a) >> 8) +#define MINOR(a) (int)((unsigned short)(a) & 0xFF) +#define MKDEV(a,b) ((int)((((a) & 0xff) << 8) | ((b) & 0xff))) + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#define NIL_FILP ((struct file *)0) +#define SEL_IN 1 +#define SEL_OUT 2 +#define SEL_EX 4 + +/* + * These are the fs-independent mount-flags: up to 16 flags are supported + */ +#define MS_RDONLY 1 /* mount read-only */ +#define MS_NOSUID 2 /* ignore suid and sgid bits */ +#define MS_NODEV 4 /* disallow access to device special files */ +#define MS_NOEXEC 8 /* disallow program execution */ +#define MS_SYNC 16 /* writes are synced at once */ +#define MS_REMOUNT 32 /* alter flags of a mounted FS */ + +/* + * Flags that can be altered by MS_REMOUNT + */ +#define MS_RMT_MASK (MS_RDONLY) + +/* + * Magic mount flag number. Has to be or-ed to the flag values. + */ +#define MS_MGC_VAL 0xC0ED0000 /* magic flag number to indicate "new" flags */ +#define MS_MGC_MSK 0xffff0000 /* magic flag number mask */ + +/* + * Note that read-only etc flags are inode-specific: setting some file-system + * flags just means all the inodes inherit those flags by default. It might be + * possible to overrride it sevelctively if you really wanted to with some + * ioctl() that is not currently implemented. + * + * Exception: MS_RDONLY is always applied to the entire file system. + */ +#define IS_RDONLY(inode) (((inode)->i_sb) && ((inode)->i_sb->s_flags & MS_RDONLY)) +#define IS_NOSUID(inode) ((inode)->i_flags & MS_NOSUID) +#define IS_NODEV(inode) ((inode)->i_flags & MS_NODEV) +#define IS_NOEXEC(inode) ((inode)->i_flags & MS_NOEXEC) +#define IS_SYNC(inode) ((inode)->i_flags & MS_SYNC) + +/* the read-only stuff doesn't really belong here, but any other place is + probably as bad and I don't want to create yet another include file. */ + +#define BLKROSET 4701 /* set device read-only (0 = read-write) */ +#define BLKROGET 4702 /* get read-only status (0 = read_write) */ +#define BLKRRPART 4703 /* re-read partition table */ +#define BLKGETSIZE 4704 /* return device size */ +#define BLKFLSBUF 4705 /* flush buffer cache */ + +/* These are a few other constants only used by scsi devices */ + +#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 */ +#define FIGETBSZ 2 /* get the block size used for bmap */ + +/* these flags tell notify_change what is being changed */ + +#define NOTIFY_SIZE 1 +#define NOTIFY_MODE 2 +#define NOTIFY_TIME 4 +#define NOTIFY_UIDGID 8 + +typedef char buffer_block[BLOCK_SIZE]; + +struct buffer_head { + char * b_data; /* pointer to data block (1024 bytes) */ + unsigned long b_size; /* block size */ + unsigned long b_blocknr; /* block number */ + dev_t b_dev; /* device (0 = free) */ + unsigned short b_count; /* users using this block */ + unsigned char b_uptodate; + unsigned char b_dirt; /* 0-clean,1-dirty */ + unsigned char b_lock; /* 0 - ok, 1 -locked */ + unsigned char b_req; /* 0 if the buffer has been invalidated */ + struct wait_queue * b_wait; + struct buffer_head * b_prev; /* doubly linked list of hash-queue */ + struct buffer_head * b_next; + struct buffer_head * b_prev_free; /* doubly linked list of buffers */ + struct buffer_head * b_next_free; + struct buffer_head * b_this_page; /* circular list of buffers in one page */ + struct buffer_head * b_reqnext; /* request queue */ +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct inode { + dev_t i_dev; + unsigned long i_ino; + umode_t i_mode; + nlink_t i_nlink; + uid_t i_uid; + gid_t i_gid; + dev_t i_rdev; + off_t i_size; + time_t i_atime; + time_t i_mtime; + time_t i_ctime; + unsigned long i_blksize; + unsigned long i_blocks; + struct inode_operations * i_op; + struct super_block * i_sb; + struct wait_queue * i_wait; + struct file_lock * i_flock; + struct vm_area_struct * i_mmap; + struct inode * i_next, * i_prev; + struct inode * i_hash_next, * i_hash_prev; + struct inode * i_bound_to, * i_bound_by; + struct inode * i_mount; + struct socket * i_socket; + unsigned short i_count; + unsigned short i_flags; + unsigned char i_lock; + unsigned char i_dirt; + unsigned char i_pipe; + unsigned char i_seek; + unsigned char i_update; + union { + struct pipe_inode_info pipe_i; + struct minix_inode_info minix_i; + struct ext_inode_info ext_i; + struct ext2_inode_info ext2_i; + struct hpfs_inode_info hpfs_i; + struct msdos_inode_info msdos_i; + struct iso_inode_info isofs_i; + struct nfs_inode_info nfs_i; + struct xiafs_inode_info xiafs_i; + struct sysv_inode_info sysv_i; + } u; +}; + +struct file { + mode_t f_mode; + dev_t f_rdev; /* needed for /dev/tty */ + off_t f_pos; + unsigned short f_flags; + unsigned short f_count; + unsigned short f_reada; + struct file *f_next, *f_prev; + struct inode * f_inode; + struct file_operations * f_op; +}; + +struct file_lock { + struct file_lock *fl_next; /* singly linked list */ + struct task_struct *fl_owner; /* NULL if on free list, for sanity checks */ + unsigned int fl_fd; /* File descriptor for this lock */ + struct wait_queue *fl_wait; + char fl_type; + char fl_whence; + off_t fl_start; + off_t fl_end; +}; + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct super_block { + dev_t s_dev; + unsigned long s_blocksize; + unsigned char s_blocksize_bits; + unsigned char s_lock; + unsigned char s_rd_only; + unsigned char s_dirt; + struct super_operations *s_op; + unsigned long s_flags; + unsigned long s_magic; + unsigned long s_time; + struct inode * s_covered; + struct inode * s_mounted; + struct wait_queue * s_wait; + union { + struct minix_sb_info minix_sb; + struct ext_sb_info ext_sb; + struct ext2_sb_info ext2_sb; + struct hpfs_sb_info hpfs_sb; + struct msdos_sb_info msdos_sb; + struct isofs_sb_info isofs_sb; + struct nfs_sb_info nfs_sb; + struct xiafs_sb_info xiafs_sb; + struct sysv_sb_info sysv_sb; + } u; +}; + +struct file_operations { + int (*lseek) (struct inode *, struct file *, off_t, int); + int (*read) (struct inode *, struct file *, char *, int); + int (*write) (struct inode *, struct file *, char *, int); + int (*readdir) (struct inode *, struct file *, struct dirent *, int); + int (*select) (struct inode *, struct file *, int, select_table *); + int (*ioctl) (struct inode *, struct file *, unsigned int, unsigned long); + int (*mmap) (struct inode *, struct file *, unsigned long, size_t, int, unsigned long); + int (*open) (struct inode *, struct file *); + void (*release) (struct inode *, struct file *); + int (*fsync) (struct inode *, struct file *); +}; + +struct inode_operations { + struct file_operations * default_file_ops; + int (*create) (struct inode *,const char *,int,int,struct inode **); + int (*lookup) (struct inode *,const char *,int,struct inode **); + int (*link) (struct inode *,struct inode *,const char *,int); + int (*unlink) (struct inode *,const char *,int); + int (*symlink) (struct inode *,const char *,int,const char *); + int (*mkdir) (struct inode *,const char *,int,int); + int (*rmdir) (struct inode *,const char *,int); + int (*mknod) (struct inode *,const char *,int,int,int); + int (*rename) (struct inode *,const char *,int,struct inode *,const char *,int); + int (*readlink) (struct inode *,char *,int); + int (*follow_link) (struct inode *,struct inode *,int,int,struct inode **); + int (*bmap) (struct inode *,int); + void (*truncate) (struct inode *); + int (*permission) (struct inode *, int); +}; + +struct super_operations { + void (*read_inode) (struct inode *); + int (*notify_change) (int flags, struct inode *); + void (*write_inode) (struct inode *); + void (*put_inode) (struct inode *); + void (*put_super) (struct super_block *); + void (*write_super) (struct super_block *); + void (*statfs) (struct super_block *, struct statfs *); + int (*remount_fs) (struct super_block *, int *, char *); +}; + +struct file_system_type { + struct super_block *(*read_super) (struct super_block *, void *, int); + char *name; + int requires_dev; +}; + +#ifdef __KERNEL__ + +asmlinkage int sys_open(const char *, int, int); +asmlinkage int sys_close(unsigned int); /* yes, it's really unsigned */ + +extern int getname(const char * filename, char **result); +extern void putname(char * name); + +extern int register_blkdev(unsigned int, const char *, struct file_operations *); +extern int blkdev_open(struct inode * inode, struct file * filp); +extern struct file_operations def_blk_fops; +extern struct inode_operations blkdev_inode_operations; + +extern int register_chrdev(unsigned int, const char *, struct file_operations *); +extern int unregister_chrdev( unsigned int major, const char * name); +extern int chrdev_open(struct inode * inode, struct file * filp); +extern struct file_operations def_chr_fops; +extern struct inode_operations chrdev_inode_operations; + +extern void init_fifo(struct inode * inode); + +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; + +extern struct file_system_type *get_fs_type(char *name); + +extern int fs_may_mount(dev_t dev); +extern int fs_may_umount(dev_t dev, struct inode * mount_root); +extern int fs_may_remount_ro(dev_t dev); + +extern struct file *first_file; +extern int nr_files; +extern struct super_block super_blocks[NR_SUPER]; + +extern int shrink_buffers(unsigned int priority); + +extern int nr_buffers; +extern int buffermem; +extern int nr_buffer_heads; + +extern void check_disk_change(dev_t dev); +extern void invalidate_inodes(dev_t dev); +extern void invalidate_buffers(dev_t dev); +extern int floppy_change(struct buffer_head * first_block); +extern void sync_inodes(dev_t dev); +extern void sync_dev(dev_t dev); +extern int fsync_dev(dev_t dev); +extern void sync_supers(dev_t dev); +extern int bmap(struct inode * inode,int block); +extern int notify_change(int flags, struct inode * inode); +extern int namei(const char * pathname, struct inode ** res_inode); +extern int lnamei(const char * pathname, struct inode ** res_inode); +extern int permission(struct inode * inode,int mask); +extern int open_namei(const char * pathname, int flag, int mode, + struct inode ** res_inode, struct inode * base); +extern int do_mknod(const char * filename, int mode, dev_t dev); +extern void iput(struct inode * inode); +extern struct inode * __iget(struct super_block * sb,int nr,int crsmnt); +extern struct inode * iget(struct super_block * sb,int nr); +extern struct inode * get_empty_inode(void); +extern void insert_inode_hash(struct inode *); +extern void clear_inode(struct inode *); +extern struct inode * get_pipe_inode(void); +extern struct file * get_empty_filp(void); +extern struct buffer_head * get_hash_table(dev_t dev, int block, int size); +extern struct buffer_head * getblk(dev_t dev, int block, int size); +extern void ll_rw_block(int rw, int nr, struct buffer_head * bh[]); +extern void ll_rw_page(int rw, int dev, int nr, char * buffer); +extern void ll_rw_swap_file(int rw, int dev, unsigned int *b, int nb, char *buffer); +extern void brelse(struct buffer_head * buf); +extern void set_blocksize(dev_t dev, int size); +extern struct buffer_head * bread(dev_t dev, int block, int size); +extern unsigned long bread_page(unsigned long addr,dev_t dev,int b[],int size,int prot); +extern struct buffer_head * breada(dev_t dev,int block,...); +extern void put_super(dev_t dev); +extern dev_t ROOT_DEV; + +extern void mount_root(void); + +extern int char_read(struct inode *, struct file *, char *, int); +extern int block_read(struct inode *, struct file *, char *, int); +extern int read_ahead[]; + +extern int char_write(struct inode *, struct file *, char *, int); +extern int block_write(struct inode *, struct file *, char *, int); + +extern int generic_mmap(struct inode *, struct file *, unsigned long, size_t, int, unsigned long); + +extern int block_fsync(struct inode *, struct file *); +extern int file_fsync(struct inode *, struct file *); + +#endif /* __KERNEL__ */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/genhd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/genhd.h new file mode 100644 index 000000000..8ff890e48 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/genhd.h @@ -0,0 +1,52 @@ +#ifndef _LINUX_GENHD_H +#define _LINUX_GENHD_H + +/* + * genhd.h Copyright (C) 1992 Drew Eckhardt + * Generic hard disk header file by + * Drew Eckhardt + * + * + */ + +#define EXTENDED_PARTITION 5 + +struct partition { + unsigned char boot_ind; /* 0x80 - active */ + unsigned char head; /* starting head */ + unsigned char sector; /* starting sector */ + unsigned char cyl; /* starting cylinder */ + unsigned char sys_ind; /* What partition type */ + unsigned char end_head; /* end head */ + unsigned char end_sector; /* end sector */ + unsigned char end_cyl; /* end cylinder */ + unsigned int start_sect; /* starting sector counting from 0 */ + unsigned int nr_sects; /* nr of sectors in partition */ +}; + +struct hd_struct { + long start_sect; + long nr_sects; +}; + +struct gendisk { + int major; /* major number of driver */ + char *major_name; /* name of major driver */ + int minor_shift; /* number of times minor is shifted to + get real minor */ + int max_p; /* maximum partitions per device */ + int max_nr; /* maximum number of real devices */ + + void (*init)(void); /* Initialization called before we do our thing */ + struct hd_struct *part; /* partition table */ + int *sizes; /* size of device in blocks */ + int nr_real; /* number of real devices */ + + void *real_devices; /* internal use */ + struct gendisk *next; +}; + +extern int NR_GENDISKS; /* total */ +extern struct gendisk *gendisk_head; /* linked list of disks */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hdreg.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hdreg.h new file mode 100644 index 000000000..0856ce2a8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hdreg.h @@ -0,0 +1,64 @@ +#ifndef _LINUX_HDREG_H +#define _LINUX_HDREG_H + +/* + * This file contains some defines for the AT-hd-controller. + * Various sources. Check out some definitions (see comments with + * a ques). + */ + +/* Hd controller regs. Ref: IBM AT Bios-listing */ +#define HD_DATA 0x1f0 /* _CTL when writing */ +#define HD_ERROR 0x1f1 /* see err-bits */ +#define HD_NSECTOR 0x1f2 /* nr of sectors to read/write */ +#define HD_SECTOR 0x1f3 /* starting sector */ +#define HD_LCYL 0x1f4 /* starting cylinder */ +#define HD_HCYL 0x1f5 /* high byte of starting cyl */ +#define HD_CURRENT 0x1f6 /* 101dhhhh , d=drive, hhhh=head */ +#define HD_STATUS 0x1f7 /* see status-bits */ +#define HD_PRECOMP HD_ERROR /* same io address, read=error, write=precomp */ +#define HD_COMMAND HD_STATUS /* same io address, read=status, write=cmd */ + +#define HD_CMD 0x3f6 + +/* Bits of HD_STATUS */ +#define ERR_STAT 0x01 +#define INDEX_STAT 0x02 +#define ECC_STAT 0x04 /* Corrected error */ +#define DRQ_STAT 0x08 +#define SEEK_STAT 0x10 +#define WRERR_STAT 0x20 +#define READY_STAT 0x40 +#define BUSY_STAT 0x80 + +/* Values for HD_COMMAND */ +#define WIN_RESTORE 0x10 +#define WIN_READ 0x20 +#define WIN_WRITE 0x30 +#define WIN_VERIFY 0x40 +#define WIN_FORMAT 0x50 +#define WIN_INIT 0x60 +#define WIN_SEEK 0x70 +#define WIN_DIAGNOSE 0x90 +#define WIN_SPECIFY 0x91 + +/* Bits for HD_ERROR */ +#define MARK_ERR 0x01 /* Bad address mark */ +#define TRK0_ERR 0x02 /* couldn't find track 0 */ +#define ABRT_ERR 0x04 /* Command aborted */ +#define ID_ERR 0x10 /* ID field not found */ +#define ECC_ERR 0x40 /* Uncorrectable ECC error */ +#define BBD_ERR 0x80 /* block marked bad */ + + +/* HDIO_GETGEO is the preferred choice - HDIO_REQ will be removed at some + later date */ +#define HDIO_REQ 0x301 +#define HDIO_GETGEO 0x301 +struct hd_geometry { + unsigned char heads; + unsigned char sectors; + unsigned short cylinders; + unsigned long start; +}; +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/head.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/head.h new file mode 100644 index 000000000..8911a6819 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/head.h @@ -0,0 +1,20 @@ +#ifndef _LINUX_HEAD_H +#define _LINUX_HEAD_H + +typedef struct desc_struct { + unsigned long a,b; +} desc_table[256]; + +extern unsigned long swapper_pg_dir[1024]; +extern desc_table idt,gdt; + +#define GDT_NUL 0 +#define GDT_CODE 1 +#define GDT_DATA 2 +#define GDT_TMP 3 + +#define LDT_NUL 0 +#define LDT_CODE 1 +#define LDT_DATA 2 + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs.h new file mode 100644 index 000000000..0094c359c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs.h @@ -0,0 +1,12 @@ +#ifndef _LINUX_HPFS_FS_H +#define _LINUX_HPFS_FS_H + +/* HPFS magic number (word 0 of block 16) */ + +#define HPFS_SUPER_MAGIC 0xf995e849 + +/* The entry point for a VFS */ + +extern struct super_block *hpfs_read_super (struct super_block *, void *, int); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_i.h new file mode 100644 index 000000000..d9aa8f34d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_i.h @@ -0,0 +1,24 @@ +#ifndef _HPFS_FS_I +#define _HPFS_FS_I + +struct hpfs_inode_info { + ino_t i_parent_dir; /* (directories) gives fnode of parent dir */ + unsigned i_dno; /* (directories) root dnode */ + unsigned i_dpos; /* (directories) temp for readdir */ + unsigned i_dsubdno; /* (directories) temp for readdir */ + unsigned i_file_sec; /* (files) minimalist cache of alloc info */ + unsigned i_disk_sec; /* (files) minimalist cache of alloc info */ + unsigned i_n_secs; /* (files) minimalist cache of alloc info */ + unsigned i_conv : 2; /* (files) crlf->newline hackery */ +}; + +#define i_hpfs_dno u.hpfs_i.i_dno +#define i_hpfs_parent_dir u.hpfs_i.i_parent_dir +#define i_hpfs_n_secs u.hpfs_i.i_n_secs +#define i_hpfs_file_sec u.hpfs_i.i_file_sec +#define i_hpfs_disk_sec u.hpfs_i.i_disk_sec +#define i_hpfs_dpos u.hpfs_i.i_dpos +#define i_hpfs_dsubdno u.hpfs_i.i_dsubdno +#define i_hpfs_conv u.hpfs_i.i_conv + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_sb.h new file mode 100644 index 000000000..a383e16ba --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/hpfs_fs_sb.h @@ -0,0 +1,32 @@ +#ifndef _HPFS_FS_SB +#define _HPFS_FS_SB + +struct hpfs_sb_info { + ino_t sb_root; /* inode number of root dir */ + unsigned sb_fs_size; /* file system size, sectors */ + unsigned sb_bitmaps; /* sector number of bitmap list */ + unsigned sb_dirband_size; /* directory band size, dnodes */ + unsigned sb_dmap; /* sector number of dnode bit map */ + unsigned sb_n_free; /* free blocks for statfs, or -1 */ + unsigned sb_n_free_dnodes; /* free dnodes for statfs, or -1 */ + uid_t sb_uid; /* uid from mount options */ + gid_t sb_gid; /* gid from mount options */ + umode_t sb_mode; /* mode from mount options */ + unsigned sb_lowercase : 1; /* downcase filenames hackery */ + unsigned sb_conv : 2; /* crlf->newline hackery */ +}; + +#define s_hpfs_root u.hpfs_sb.sb_root +#define s_hpfs_fs_size u.hpfs_sb.sb_fs_size +#define s_hpfs_bitmaps u.hpfs_sb.sb_bitmaps +#define s_hpfs_dirband_size u.hpfs_sb.sb_dirband_size +#define s_hpfs_dmap u.hpfs_sb.sb_dmap +#define s_hpfs_uid u.hpfs_sb.sb_uid +#define s_hpfs_gid u.hpfs_sb.sb_gid +#define s_hpfs_mode u.hpfs_sb.sb_mode +#define s_hpfs_n_free u.hpfs_sb.sb_n_free +#define s_hpfs_n_free_dnodes u.hpfs_sb.sb_n_free_dnodes +#define s_hpfs_lowercase u.hpfs_sb.sb_lowercase +#define s_hpfs_conv u.hpfs_sb.sb_conv + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/icmp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/icmp.h new file mode 100644 index 000000000..ca1e8c6bf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/icmp.h @@ -0,0 +1,81 @@ +/* + * 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 ICMP protocol. + * + * Version: @(#)icmp.h 1.0.3 04/28/93 + * + * Author: Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_ICMP_H +#define _LINUX_ICMP_H + +#define ICMP_ECHOREPLY 0 /* Echo Reply */ +#define ICMP_DEST_UNREACH 3 /* Destination Unreachable */ +#define ICMP_SOURCE_QUENCH 4 /* Source Quench */ +#define ICMP_REDIRECT 5 /* Redirect (change route) */ +#define ICMP_ECHO 8 /* Echo Request */ +#define ICMP_TIME_EXCEEDED 11 /* Time Exceeded */ +#define ICMP_PARAMETERPROB 12 /* Parameter Problem */ +#define ICMP_TIMESTAMP 13 /* Timestamp Request */ +#define ICMP_TIMESTAMPREPLY 14 /* Timestamp Reply */ +#define ICMP_INFO_REQUEST 15 /* Information Request */ +#define ICMP_INFO_REPLY 16 /* Information Reply */ +#define ICMP_ADDRESS 17 /* Address Mask Request */ +#define ICMP_ADDRESSREPLY 18 /* Address Mask Reply */ + + +/* Codes for UNREACH. */ +#define ICMP_NET_UNREACH 0 /* Network Unreachable */ +#define ICMP_HOST_UNREACH 1 /* Host Unreachable */ +#define ICMP_PROT_UNREACH 2 /* Protocol Unreachable */ +#define ICMP_PORT_UNREACH 3 /* Port Unreachable */ +#define ICMP_FRAG_NEEDED 4 /* Fragmentation Needed/DF set */ +#define ICMP_SR_FAILED 5 /* Source Route failed */ +#define ICMP_NET_UNKNOWN 6 +#define ICMP_HOST_UNKNOWN 7 +#define ICMP_HOST_ISOLATED 8 +#define ICMP_NET_ANO 9 +#define ICMP_HOST_ANO 10 +#define ICMP_NET_UNR_TOS 11 +#define ICMP_HOST_UNR_TOS 12 + +/* Codes for REDIRECT. */ +#define ICMP_REDIR_NET 0 /* Redirect Net */ +#define ICMP_REDIR_HOST 1 /* Redirect Host */ +#define ICMP_REDIR_NETTOS 2 /* Redirect Net for TOS */ +#define ICMP_REDIR_HOSTTOS 3 /* Redirect Host for TOS */ + +/* Codes for TIME_EXCEEDED. */ +#define ICMP_EXC_TTL 0 /* TTL count exceeded */ +#define ICMP_EXC_FRAGTIME 1 /* Fragment Reass time exceeded */ + + +struct icmphdr { + unsigned char type; + unsigned char code; + unsigned short checksum; + union { + struct { + unsigned short id; + unsigned short sequence; + } echo; + unsigned long gateway; + } un; +}; + + +struct icmp_err { + int errno; + unsigned fatal:1; +}; + + +#endif /* _LINUX_ICMP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if.h new file mode 100644 index 000000000..5cbe651a6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if.h @@ -0,0 +1,156 @@ +/* + * 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. + * + * Global definitions for the INET interface module. + * + * Version: @(#)if.h 1.0.2 04/18/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1982-1988 + * Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_IF_H +#define _LINUX_IF_H + +#include /* for "caddr_t" et al */ +#include /* for "struct sockaddr" et al */ + + +/* Structure defining a queue for a network interface. */ +struct ifnet { + char *if_name; /* name, e.g. ``en'' or ``lo'' */ + short if_unit; /* sub-unit for device driver */ + short if_mtu; /* maximum transmission unit */ + short if_flags; /* up/down, broadcast, etc. */ + short if_timer; /* time 'til if_watchdog called */ + int if_metric; /* routing metric (not used) */ + struct ifaddr *if_addrlist; /* linked list of addrs per if */ + struct ifqueue { +#ifdef not_yet_in_linux + struct mbuf *ifq_head; + struct mbuf *ifq_tail; + int ifq_len; + int ifq_maxlen; + int ifq_drops; +#endif + } if_snd; /* output queue */ + + /* Procedure handles. */ + int (*if_init)(); /* init routine */ + int (*if_output)(); /* output routine */ + int (*if_ioctl)(); /* ioctl routine */ + int (*if_reset)(); /* bus reset routine */ + int (*if_watchdog)(); /* timer routine */ + + /* Generic interface statistics. */ + int if_ipackets; /* packets recv'd on interface */ + int if_ierrors; /* input errors on interface */ + int if_opackets; /* packets sent on interface */ + int if_oerrors; /* output errors on interface */ + int if_collisions; /* collisions on CSMA i'faces */ + + /* Linked list: pointer to next interface. */ + struct ifnet *if_next; +}; + +/* Standard interface flags. */ +#define IFF_UP 0x1 /* interface is up */ +#define IFF_BROADCAST 0x2 /* broadcast address valid */ +#define IFF_DEBUG 0x4 /* turn on debugging */ +#define IFF_LOOPBACK 0x8 /* is a loopback net */ +#define IFF_POINTOPOINT 0x10 /* interface is has p-p link */ +#define IFF_NOTRAILERS 0x20 /* avoid use of trailers */ +#define IFF_RUNNING 0x40 /* resources allocated */ +#define IFF_NOARP 0x80 /* no ARP protocol */ + +/* These are not yet used: */ +#define IFF_PROMISC 0x100 /* recve all packets */ +#define IFF_ALLMULTI 0x200 /* recve all multicast packets */ + + +/* + * The ifaddr structure contains information about one address + * of an interface. They are maintained by the different address + * families, are allocated and attached when an address is set, + * and are linked together so all addresses for an interface can + * be located. + */ +struct ifaddr { + struct sockaddr ifa_addr; /* address of interface */ + union { + struct sockaddr ifu_broadaddr; + struct sockaddr ifu_dstaddr; + } ifa_ifu; + struct iface *ifa_ifp; /* back-pointer to interface */ + struct ifaddr *ifa_next; /* next address for interface */ +}; +#define ifa_broadaddr ifa_ifu.ifu_broadaddr /* broadcast address */ +#define ifa_dstaddr ifa_ifu.ifu_dstaddr /* other end of link */ + +/* + * Interface request structure used for socket + * ioctl's. All interface ioctl's must have parameter + * definitions which begin with ifr_name. The + * remainder may be interface specific. + */ +struct ifreq { +#define IFHWADDRLEN 6 +#define IFNAMSIZ 16 + 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; + struct sockaddr ifru_broadaddr; + struct sockaddr ifru_netmask; + short ifru_flags; + int ifru_metric; + int ifru_mtu; + 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 */ +#define ifr_netmask ifr_ifru.ifru_netmask /* interface net mask */ +#define ifr_flags ifr_ifru.ifru_flags /* flags */ +#define ifr_metric ifr_ifru.ifru_metric /* metric */ +#define ifr_mtu ifr_ifru.ifru_mtu /* mtu */ +#define ifr_data ifr_ifru.ifru_data /* for use by interface */ + +/* + * Structure used in SIOCGIFCONF request. + * Used to retrieve interface configuration + * for machine (useful for programs which + * must know all networks accessible). + */ +struct ifconf { + int ifc_len; /* size of buffer */ + union { + caddr_t ifcu_buf; + struct ifreq *ifcu_req; + } ifc_ifcu; +}; +#define ifc_buf ifc_ifcu.ifcu_buf /* buffer address */ +#define ifc_req ifc_ifcu.ifcu_req /* array of structures */ + + +/* BSD UNIX expects to find these here, so here we go: */ +#include +#include + +#endif /* _NET_IF_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_arp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_arp.h new file mode 100644 index 000000000..1fcbed976 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_arp.h @@ -0,0 +1,83 @@ +/* + * 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. + * + * Global definitions for the ARP (RFC 826) protocol. + * + * Version: @(#)if_arp.h 1.0.1 04/16/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + * Portions taken from the KA9Q/NOS (v2.00m PA0GRI) source. + * Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_IF_ARP_H +#define _LINUX_IF_ARP_H + +/* ARP protocol HARDWARE identifiers. */ +#define ARPHRD_NETROM 0 /* from KA9Q: NET/ROM pseudo */ +#define ARPHRD_ETHER 1 /* Ethernet 10Mbps */ +#define ARPHRD_EETHER 2 /* Experimental Ethernet */ +#define ARPHRD_AX25 3 /* AX.25 Level 2 */ +#define ARPHRD_PRONET 4 /* PROnet token ring */ +#define ARPHRD_CHAOS 5 /* Chaosnet */ +#define ARPHRD_IEEE802 6 /* IEEE 802.2 Ethernet- huh? */ +#define ARPHRD_ARCNET 7 /* ARCnet */ +#define ARPHRD_APPLETLK 8 /* APPLEtalk */ + +/* ARP protocol opcodes. */ +#define ARPOP_REQUEST 1 /* ARP request */ +#define ARPOP_REPLY 2 /* ARP reply */ +#define ARPOP_RREQUEST 3 /* RARP request */ +#define ARPOP_RREPLY 4 /* RARP reply */ + + +/* + * Address Resolution Protocol. + * + * See RFC 826 for protocol description. ARP packets are variable + * in size; the arphdr structure defines the fixed-length portion. + * Protocol type values are the same as those for 10 Mb/s Ethernet. + * It is followed by the variable-sized fields ar_sha, arp_spa, + * arp_tha and arp_tpa in that order, according to the lengths + * specified. Field names used correspond to RFC 826. + */ +struct arphdr { + unsigned short ar_hrd; /* format of hardware address */ + unsigned short ar_pro; /* format of protocol address */ + unsigned char ar_hln; /* length of hardware address */ + unsigned char ar_pln; /* length of protocol address */ + unsigned short ar_op; /* ARP opcode (command) */ + + /* The rest is variable in size, according to the sizes above. */ +#if 0 + unsigned char ar_sha[]; /* sender hardware address */ + unsigned char ar_spa[]; /* sender protocol address */ + unsigned char ar_tha[]; /* target hardware address */ + unsigned char ar_tpa[]; /* target protocol address */ +#endif /* not actually included! */ +}; + + +/* ARP ioctl request. */ +struct arpreq { + struct sockaddr arp_pa; /* protocol address */ + struct sockaddr arp_ha; /* hardware address */ + int arp_flags; /* flags */ +}; + +/* ARP Flag values. */ +#define ATF_INUSE 0x01 /* entry in use */ +#define ATF_COM 0x02 /* completed entry (ha valid) */ +#define ATF_PERM 0x04 /* permanent entry */ +#define ATF_PUBL 0x08 /* publish entry */ +#define ATF_USETRAILERS 0x10 /* has requested trailers */ + + +#endif /* _LINUX_IF_ARP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_ether.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_ether.h new file mode 100644 index 000000000..6eeee460f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/if_ether.h @@ -0,0 +1,93 @@ +/* + * 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. + * + * Global definitions for the Ethernet IEE 802.3 interface. + * + * Version: @(#)if_ether.h 1.0.1 03/15/93 + * + * Author: Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_IF_ETHER_H +#define _LINUX_IF_ETHER_H + + +/* IEEE 802.3 Ethernet magic constants. */ +#define ETH_ALEN 6 /* #bytes in eth addr */ +#define ETH_HLEN 14 /* #bytes in eth header */ +#define ETH_ZLEN 64 /* min #bytes in frame */ +#define ETH_FLEN 1536 /* max #bytes in frame */ +#define ETH_DLEN (ETH_FLEN - ETH_HLEN) /* max #bytes of data */ + +/* These are the defined Ethernet Protocol ID's. */ +#define ETH_P_LOOP 0x0060 /* Ethernet Loopback packet */ +#define ETH_P_ECHO 0x0200 /* Ethernet Echo packet */ +#define ETH_P_PUP 0x0400 /* Xerox PUP packet */ +#define ETH_P_IP 0x0800 /* Internet Protocol packet */ +#define ETH_P_ARP 0x0806 /* Address Resolution packet */ +#define ETH_P_RARP 0x8035 /* Reverse Addr Res packet */ +#define ETH_P_X25 0x0805 /* CCITT X.25 */ +#define ETH_P_IPX 0x8137 /* IPX over DIX */ +#define ETH_P_802_3 0x0001 /* Dummy type for 802.3 frames */ +#define ETH_P_AX25 0x0002 /* Dummy protocol id for AX.25 */ +#define ETH_P_ALL 0x0003 /* Every packet (be careful!!!) */ + +/* Define the Ethernet Broadcast Address (48 bits set to "1"). */ +#define ETH_A_BCAST "\377\377\377\377\377\377" + +/* This is an Ethernet frame header. */ +struct ethhdr { + unsigned char h_dest[ETH_ALEN]; /* destination eth addr */ + unsigned char h_source[ETH_ALEN]; /* source ether addr */ + unsigned short h_proto; /* packet type ID field */ +}; + +/* This is the complete Ethernet frame. */ +struct ethframe { + struct ethhdr f_hdr; /* frame header */ + char f_data[ETH_DLEN]; /* frame data (variable)*/ +}; + + +/* Receiver modes */ +#define ETH_MODE_MONITOR 1 /* Monitor mode - no receive */ +#define ETH_MODE_PHYS 2 /* Physical address receive only */ +#define ETH_MODE_BCAST 3 /* Broadcast receive + mode 2 */ +#define ETH_MODE_MCAST 4 /* Multicast receive + mode 3 */ +#define ETH_MODE_PROMISC 5 /* Promiscuous mode - receive all */ + + +/* Ethernet statistics collection data. */ +struct enet_statistics{ + int rx_packets; /* total packets received */ + int tx_packets; /* total packets transmitted */ + int rx_errors; /* bad packets received */ + int tx_errors; /* packet transmit problems */ + int rx_dropped; /* no space in linux buffers */ + int tx_dropped; /* no space available in linux */ + int multicast; /* multicast packets received */ + int collisions; + + /* detailed rx_errors: */ + int rx_length_errors; + int rx_over_errors; /* receiver ring buff overflow */ + int rx_crc_errors; /* recved pkt with crc error */ + int rx_frame_errors; /* recv'd frame alignment error */ + int rx_fifo_errors; /* recv'r fifo overrun */ + int rx_missed_errors; /* receiver missed packet */ + + /* detailed tx_errors */ + int tx_aborted_errors; + int tx_carrier_errors; + int tx_fifo_errors; + int tx_heartbeat_errors; + int tx_window_errors; +}; + +#endif /* _LINUX_IF_ETHER_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/in.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/in.h new file mode 100644 index 000000000..0ce11f50c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/in.h @@ -0,0 +1,184 @@ +/* + * 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 of the Internet Protocol. + * + * Version: @(#)in.h 1.0.1 04/21/93 + * + * Authors: Original taken from the GNU Project file. + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_IN_H +#define _LINUX_IN_H + + +/* Standard well-defined IP protocols. */ +enum { + IPPROTO_IP = 0, /* Dummy protocol for TCP */ + IPPROTO_ICMP = 1, /* Internet Control Message Protocol */ + IPPROTO_GGP = 2, /* Gateway Protocol (deprecated) */ + IPPROTO_TCP = 6, /* Transmission Control Protocol */ + IPPROTO_EGP = 8, /* Exterior Gateway Protocol */ + IPPROTO_PUP = 12, /* PUP protocol */ + IPPROTO_UDP = 17, /* User Datagram Protocol */ + IPPROTO_IDP = 22, /* XNS IDP protocol */ + + IPPROTO_RAW = 255, /* Raw IP packets */ + IPPROTO_MAX +}; + + +/* Internet address. */ +struct in_addr { + unsigned long int s_addr; +}; + + +/* Structure describing an Internet (IP) socket address. */ +#define __SOCK_SIZE__ 16 /* sizeof(struct sockaddr) */ +struct sockaddr_in { + short int sin_family; /* Address family */ + unsigned short int sin_port; /* Port number */ + struct in_addr sin_addr; /* Internet address */ + + /* Pad to size of `struct sockaddr'. */ + unsigned char __pad[__SOCK_SIZE__ - sizeof(short int) - + sizeof(unsigned short int) - sizeof(struct in_addr)]; +}; +#define sin_zero __pad /* for BSD UNIX comp. -FvK */ + + +/* + * Definitions of the bits in an Internet address integer. + * On subnets, host and network parts are found according + * to the subnet mask, not these masks. + */ +#define IN_CLASSA(a) ((((long int) (a)) & 0x80000000) == 0) +#define IN_CLASSA_NET 0xff000000 +#define IN_CLASSA_NSHIFT 24 +#define IN_CLASSA_HOST (0xffffffff & ~IN_CLASSA_NET) +#define IN_CLASSA_MAX 128 + +#define IN_CLASSB(a) ((((long int) (a)) & 0xc0000000) == 0x80000000) +#define IN_CLASSB_NET 0xffff0000 +#define IN_CLASSB_NSHIFT 16 +#define IN_CLASSB_HOST (0xffffffff & ~IN_CLASSB_NET) +#define IN_CLASSB_MAX 65536 + +#define IN_CLASSC(a) ((((long int) (a)) & 0xc0000000) == 0xc0000000) +#define IN_CLASSC_NET 0xffffff00 +#define IN_CLASSC_NSHIFT 8 +#define IN_CLASSC_HOST (0xffffffff & ~IN_CLASSC_NET) + +#define IN_CLASSD(a) ((((long int) (a)) & 0xf0000000) == 0xe0000000) +#define IN_MULTICAST(a) IN_CLASSD(a) + +#define IN_EXPERIMENTAL(a) ((((long int) (a)) & 0xe0000000) == 0xe0000000) +#define IN_BADCLASS(a) ((((long int) (a)) & 0xf0000000) == 0xf0000000) + +/* Address to accept any incoming messages. */ +#define INADDR_ANY ((unsigned long int) 0x00000000) + +/* Address to send to all hosts. */ +#define INADDR_BROADCAST ((unsigned long int) 0xffffffff) + +/* Address indicating an error return. */ +#define INADDR_NONE 0xffffffff + +/* Network number for local host loopback. */ +#define IN_LOOPBACKNET 127 + +/* Address to loopback in software to local host. */ +#define INADDR_LOOPBACK 0x7f000001 /* 127.0.0.1 */ + + +/* + * Options for use with `getsockopt' and `setsockopt' at + * the IP level. LINUX does not yet have the IP_OPTIONS + * option (grin), so we undefine it for now.- HJ && FvK + */ +#if 0 +# define IP_OPTIONS 1 /* IP per-packet options */ +#endif +#define IP_HDRINCL 2 /* raw packet header option */ + + +/* Linux Internet number representation function declarations. */ +#undef ntohl +#undef ntohs +#undef htonl +#undef htons + +extern unsigned long int ntohl(unsigned long int); +extern unsigned short int ntohs(unsigned short int); +extern unsigned long int htonl(unsigned long int); +extern unsigned short int htons(unsigned short int); + +static __inline__ unsigned long int +__ntohl(unsigned long int x) +{ + __asm__("xchgb %b0,%h0\n\t" /* swap lower bytes */ + "rorl $16,%0\n\t" /* swap words */ + "xchgb %b0,%h0" /* swap higher bytes */ + :"=q" (x) + : "0" (x)); + return x; +} + +static __inline__ unsigned long int +__constant_ntohl(unsigned long int x) +{ + return (((x & 0x000000ff) << 24) | + ((x & 0x0000ff00) << 8) | + ((x & 0x00ff0000) >> 8) | + ((x & 0xff000000) >> 24)); +} + +static __inline__ unsigned short int +__ntohs(unsigned short int x) +{ + __asm__("xchgb %b0,%h0" /* swap bytes */ + : "=q" (x) + : "0" (x)); + return x; +} + +static __inline__ unsigned short int +__constant_ntohs(unsigned short int x) +{ + return (((x & 0x00ff) << 8) | + ((x & 0xff00) >> 8)); +} + +#define __htonl(x) __ntohl(x) +#define __htons(x) __ntohs(x) +#define __constant_htonl(x) __constant_ntohl(x) +#define __constant_htons(x) __constant_ntohs(x) + +#ifdef __OPTIMIZE__ +# define ntohl(x) \ +(__builtin_constant_p((x)) ? \ + __constant_ntohl((x)) : \ + __ntohl((x))) +# define ntohs(x) \ +(__builtin_constant_p((x)) ? \ + __constant_ntohs((x)) : \ + __ntohs((x))) +# define htonl(x) \ +(__builtin_constant_p((x)) ? \ + __constant_htonl((x)) : \ + __htonl((x))) +# define htons(x) \ +(__builtin_constant_p((x)) ? \ + __constant_htons((x)) : \ + __htons((x))) +#endif + +#endif /* _LINUX_IN_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/interrupt.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/interrupt.h new file mode 100644 index 000000000..03af7d536 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/interrupt.h @@ -0,0 +1,40 @@ +/* interrupt.h */ +#ifndef _LINUX_INTERRUPT_H +#define _LINUX_INTERRUPT_H + +struct bh_struct { + void (*routine)(void *); + void *data; +}; + +extern unsigned long bh_active; +extern unsigned long bh_mask; +extern struct bh_struct bh_base[32]; + +/* Who gets which entry in bh_base. Things which will occur most often + should come first. */ +enum { + TIMER_BH = 0, + CONSOLE_BH, + SERIAL_BH, + TTY_BH, + INET_BH, + KEYBOARD_BH +}; + +extern inline void mark_bh(int nr) +{ + __asm__ __volatile__("btsl %1,%0":"=m" (bh_active):"ir" (nr)); +} + +extern inline void disable_bh(int nr) +{ + __asm__ __volatile__("btcl %1,%0":"=m" (bh_mask):"ir" (nr)); +} + +extern inline void enable_bh(int nr) +{ + __asm__ __volatile__("btsl %1,%0":"=m" (bh_mask):"ir" (nr)); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioctl.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioctl.h new file mode 100644 index 000000000..ec03d79b2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioctl.h @@ -0,0 +1,47 @@ +/* $Id: ioctl.h,v 1.5 1993/07/19 21:53:50 root Exp root $ + * + * linux/ioctl.h for Linux by H.H. Bergman. + */ + +#ifndef _LINUX_IOCTL_H +#define _LINUX_IOCTL_H + + +/* ioctl command encoding: 32 bits total, command in lower 16 bits, + * size of the parameter structure in the lower 14 bits of the + * upper 16 bits. + * Encoding the size of the parameter structure in the ioctl request + * is useful for catching programs compiled with old versions + * and to avoid overwriting user space outside the user buffer area. + * The highest 2 bits are reserved for indicating the ``access mode''. + * NOTE: This limits the max parameter size to 16kB -1 ! + */ + +#define IOC_VOID 0x00000000 /* param in size field */ +#define IOC_IN 0x40000000 /* user --> kernel */ +#define IOC_OUT 0x80000000 /* kernel --> user */ +#define IOC_INOUT (IOC_IN | IOC_OUT) /* both */ +#define IOCSIZE_MASK 0x3fff0000 /* size (max 16k-1 bytes) */ +#define IOCSIZE_SHIFT 16 /* how to get the size */ +#define IOCCMD_MASK 0x0000ffff /* command code */ +#define IOCCMD_SHIFT 0 + + +/* _IO(magic, subcode); size field is zero and the + * subcode determines the command. + */ +#define _IO(c,d) (IOC_VOID | ((c)<<8) | (d)) /* param encoded */ + +/* _IOXX(magic, subcode, arg_t); where arg_t is the type of the + * (last) argument field in the ioctl call, if present. + */ +#define _IOW(c,d,t) (IOC_IN | ((sizeof(t)<<16) & IOCSIZE_MASK) | \ + ((c)<<8) | (d)) +#define _IOR(c,d,t) (IOC_OUT | ((sizeof(t)<<16) & IOCSIZE_MASK) | \ + ((c)<<8) | (d)) +/* WR rather than RW to avoid conflict with stdio.h */ +#define _IOWR(c,d,t) (IOC_INOUT | ((sizeof(t)<<16) & IOCSIZE_MASK) | \ + ((c)<<8) | (d)) + +#endif /* _LINUX_IOCTL_H */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioport.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioport.h new file mode 100644 index 000000000..1a2512b8e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ioport.h @@ -0,0 +1,28 @@ +/* + * portio.h Definitions of routines for detecting, reserving and + * allocating system resources. + * + * Version: 0.01 8/30/93 + * + * Author: Donald Becker (becker@super.org) + */ + +#ifndef _LINUX_PORTIO_H +#define _LINUX_PORTIO_H + +#define HAVE_PORTRESERVE +/* + * Call check_region() before probing for your hardware. + * Once you have found you hardware, register it with snarf_region(). + */ +extern void reserve_setup(char *str, int *ints); +extern int check_region(unsigned int from, unsigned int extent); +extern void snarf_region(unsigned int from, unsigned int extent); + + +#define HAVE_AUTOIRQ +extern void *irq2dev_map[16]; /* Use only if you own the IRQ. */ +extern void autoirq_setup(int waittime); +extern int autoirq_report(int waittime); + +#endif /* _LINUX_PORTIO_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ip.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ip.h new file mode 100644 index 000000000..26d4a5907 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ip.h @@ -0,0 +1,81 @@ +/* + * 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 IP protocol. + * + * Version: @(#)ip.h 1.0.2 04/28/93 + * + * Authors: Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_IP_H +#define _LINUX_IP_H + + +#define IPOPT_END 0 +#define IPOPT_NOOP 1 +#define IPOPT_SEC 130 +#define IPOPT_LSRR 131 +#define IPOPT_SSRR 137 +#define IPOPT_RR 7 +#define IPOPT_SID 136 +#define IPOPT_TIMESTAMP 68 + + +struct timestamp { + unsigned char len; + unsigned char ptr; + union { + unsigned char flags:4, + overflow:4; + unsigned char full_char; + } x; + unsigned long data[9]; +}; + + +#define MAX_ROUTE 16 + +struct route { + char route_size; + char pointer; + unsigned long route[MAX_ROUTE]; +}; + + +struct options { + struct route record_route; + struct route loose_route; + struct route strict_route; + struct timestamp tstamp; + unsigned short security; + unsigned short compartment; + unsigned short handling; + unsigned short stream; + unsigned tcc; +}; + + +struct iphdr { + unsigned char ihl:4, + version:4; + unsigned char tos; + unsigned short tot_len; + unsigned short id; + unsigned short frag_off; + unsigned char ttl; + unsigned char protocol; + unsigned short check; + unsigned long saddr; + unsigned long daddr; + /*The options start here. */ +}; + + +#endif /* _LINUX_IP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ipc.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ipc.h new file mode 100644 index 000000000..197c6aeb5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ipc.h @@ -0,0 +1,65 @@ +#ifndef _LINUX_IPC_H +#define _LINUX_IPC_H +#include + +typedef int key_t; /* should go in type for IPC key */ +#define IPC_PRIVATE ((key_t) 0) + +struct ipc_perm +{ + key_t key; + ushort uid; /* owner euid and egid */ + ushort gid; + ushort cuid; /* creator euid and egid */ + ushort cgid; + ushort mode; /* access modes see mode flags below */ + ushort seq; /* sequence number */ +}; + + +/* resource get request flags */ +#define IPC_CREAT 00001000 /* create if key is nonexistent */ +#define IPC_EXCL 00002000 /* fail if key exists */ +#define IPC_NOWAIT 00004000 /* return error on wait */ + + +/* + * Control commands used with semctl, msgctl and shmctl + * see also specific commands in sem.h, msg.h and shm.h + */ +#define IPC_RMID 0 /* remove resource */ +#define IPC_SET 1 /* set ipc_perm options */ +#define IPC_STAT 2 /* get ipc_perm options */ +#define IPC_INFO 3 /* see ipcs */ + +#ifdef __KERNEL__ + +/* special shmsegs[id], msgque[id] or semary[id] values */ +#define IPC_UNUSED ((void *) -1) +#define IPC_NOID ((void *) -2) /* being allocated/destroyed */ + +/* + * These are used to wrap system calls. See ipc/util.c, libipc.c + */ +struct ipc_kludge { + struct msgbuf *msgp; + long msgtyp; +}; + +#define SEMOP 1 +#define SEMGET 2 +#define SEMCTL 3 +#define MSGSND 11 +#define MSGRCV 12 +#define MSGGET 13 +#define MSGCTL 14 +#define SHMAT 21 +#define SHMDT 22 +#define SHMGET 23 +#define SHMCTL 24 + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_IPC_H */ + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs.h new file mode 100644 index 000000000..0ff0e5dcf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs.h @@ -0,0 +1,218 @@ + +#ifndef _ISOFS_FS_H +#define _ISOFS_FS_H + +#include +/* + * The isofs filesystem constants/structures + */ + +/* This part borrowed from the bsd386 isofs */ +#define ISODCL(from, to) (to - from + 1) + +struct iso_volume_descriptor { + char type[ISODCL(1,1)]; /* 711 */ + char id[ISODCL(2,6)]; + char version[ISODCL(7,7)]; + char data[ISODCL(8,2048)]; +}; + +/* volume descriptor types */ +#define ISO_VD_PRIMARY 1 +#define ISO_VD_END 255 + +#define ISO_STANDARD_ID "CD001" + +struct iso_primary_descriptor { + char type [ISODCL ( 1, 1)]; /* 711 */ + char id [ISODCL ( 2, 6)]; + char version [ISODCL ( 7, 7)]; /* 711 */ + char unused1 [ISODCL ( 8, 8)]; + char system_id [ISODCL ( 9, 40)]; /* achars */ + char volume_id [ISODCL ( 41, 72)]; /* dchars */ + char unused2 [ISODCL ( 73, 80)]; + char volume_space_size [ISODCL ( 81, 88)]; /* 733 */ + char unused3 [ISODCL ( 89, 120)]; + char volume_set_size [ISODCL (121, 124)]; /* 723 */ + char volume_sequence_number [ISODCL (125, 128)]; /* 723 */ + char logical_block_size [ISODCL (129, 132)]; /* 723 */ + char path_table_size [ISODCL (133, 140)]; /* 733 */ + char type_l_path_table [ISODCL (141, 144)]; /* 731 */ + char opt_type_l_path_table [ISODCL (145, 148)]; /* 731 */ + char type_m_path_table [ISODCL (149, 152)]; /* 732 */ + char opt_type_m_path_table [ISODCL (153, 156)]; /* 732 */ + char root_directory_record [ISODCL (157, 190)]; /* 9.1 */ + char volume_set_id [ISODCL (191, 318)]; /* dchars */ + char publisher_id [ISODCL (319, 446)]; /* achars */ + char preparer_id [ISODCL (447, 574)]; /* achars */ + char application_id [ISODCL (575, 702)]; /* achars */ + char copyright_file_id [ISODCL (703, 739)]; /* 7.5 dchars */ + char abstract_file_id [ISODCL (740, 776)]; /* 7.5 dchars */ + char bibliographic_file_id [ISODCL (777, 813)]; /* 7.5 dchars */ + char creation_date [ISODCL (814, 830)]; /* 8.4.26.1 */ + char modification_date [ISODCL (831, 847)]; /* 8.4.26.1 */ + char expiration_date [ISODCL (848, 864)]; /* 8.4.26.1 */ + char effective_date [ISODCL (865, 881)]; /* 8.4.26.1 */ + char file_structure_version [ISODCL (882, 882)]; /* 711 */ + char unused4 [ISODCL (883, 883)]; + char application_data [ISODCL (884, 1395)]; + char unused5 [ISODCL (1396, 2048)]; +}; + + +#define HS_STANDARD_ID "CDROM" + +struct hs_volume_descriptor { + char foo [ISODCL ( 1, 8)]; /* 733 */ + char type [ISODCL ( 9, 9)]; /* 711 */ + char id [ISODCL ( 10, 14)]; + char version [ISODCL ( 15, 15)]; /* 711 */ + char data[ISODCL(16,2048)]; +}; + + +struct hs_primary_descriptor { + char foo [ISODCL ( 1, 8)]; /* 733 */ + char type [ISODCL ( 9, 9)]; /* 711 */ + char id [ISODCL ( 10, 14)]; + char version [ISODCL ( 15, 15)]; /* 711 */ + char unused1 [ISODCL ( 16, 16)]; /* 711 */ + char system_id [ISODCL ( 17, 48)]; /* achars */ + char volume_id [ISODCL ( 49, 80)]; /* dchars */ + char unused2 [ISODCL ( 81, 88)]; /* 733 */ + char volume_space_size [ISODCL ( 89, 96)]; /* 733 */ + char unused3 [ISODCL ( 97, 128)]; /* 733 */ + char volume_set_size [ISODCL (129, 132)]; /* 723 */ + char volume_sequence_number [ISODCL (133, 136)]; /* 723 */ + char logical_block_size [ISODCL (137, 140)]; /* 723 */ + char path_table_size [ISODCL (141, 148)]; /* 733 */ + char type_l_path_table [ISODCL (149, 152)]; /* 731 */ + char unused4 [ISODCL (153, 180)]; /* 733 */ + char root_directory_record [ISODCL (181, 214)]; /* 9.1 */ +}; + +/* We use this to help us look up the parent inode numbers. */ + +struct iso_path_table{ + unsigned char name_len[2]; /* 721 */ + char extent[4]; /* 731 */ + char parent[2]; /* 721 */ + char name[0]; +}; + +/* high sierra is identical to iso, except that the date is only 6 bytes, and + there is an extra reserved byte after the flags */ + +struct iso_directory_record { + char length [ISODCL (1, 1)]; /* 711 */ + char ext_attr_length [ISODCL (2, 2)]; /* 711 */ + char extent [ISODCL (3, 10)]; /* 733 */ + char size [ISODCL (11, 18)]; /* 733 */ + char date [ISODCL (19, 25)]; /* 7 by 711 */ + char flags [ISODCL (26, 26)]; + char file_unit_size [ISODCL (27, 27)]; /* 711 */ + char interleave [ISODCL (28, 28)]; /* 711 */ + char volume_sequence_number [ISODCL (29, 32)]; /* 723 */ + unsigned char name_len [ISODCL (33, 33)]; /* 711 */ + char name [0]; +}; + +extern int isonum_711(char *); +extern int isonum_712(char *); +extern int isonum_721(char *); +extern int isonum_722(char *); +extern int isonum_723(char *); +extern int isonum_731(char *); +extern int isonum_732(char *); +extern int isonum_733(char *); +extern int iso_date(char *, int); + +extern int parse_rock_ridge_inode(struct iso_directory_record *, struct inode *); +extern int get_rock_ridge_filename(struct iso_directory_record *, char ** name, int * len, struct inode *); + +extern char * get_rock_ridge_symlink(struct inode *); +extern int find_rock_ridge_relocation(struct iso_directory_record *, struct inode *); + +#define ISOFS_BLOCK_BITS 11 +#define ISOFS_BLOCK_SIZE 2048 + +#define ISOFS_BUFFER_SIZE(INODE) ((INODE)->i_sb->s_blocksize) +#define ISOFS_BUFFER_BITS(INODE) ((INODE)->i_sb->s_blocksize_bits) + +#if 0 +#ifdef ISOFS_FIXED_BLOCKSIZE +/* We use these until the buffer cache supports 2048 */ +#define ISOFS_BUFFER_BITS 10 +#define ISOFS_BUFFER_SIZE 1024 + +#define ISOFS_BLOCK_NUMBER(X) (X<<1) +#else +#define ISOFS_BUFFER_BITS 11 +#define ISOFS_BUFFER_SIZE 2048 + +#define ISOFS_BLOCK_NUMBER(X) (X) +#endif +#endif + +#define ISOFS_SUPER_MAGIC 0x9660 +#define ISOFS_FILE_UNKNOWN 0 +#define ISOFS_FILE_TEXT 1 +#define ISOFS_FILE_BINARY 2 +#define ISOFS_FILE_TEXT_M 3 + + +/* The stuff that follows may be totally unneeded. I have not checked to see + which prototypes we are still using. */ + +extern int isofs_open(struct inode * inode, struct file * filp); +extern void isofs_release(struct inode * inode, struct file * filp); +extern int isofs_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern unsigned long isofs_count_free_inodes(struct super_block *sb); +extern int isofs_new_block(int dev); +extern int isofs_free_block(int dev, int block); +extern int isofs_bmap(struct inode *,int); + +extern void isofs_put_super(struct super_block *); +extern struct super_block *isofs_read_super(struct super_block *,void *,int); +extern void isofs_read_inode(struct inode *); +extern void isofs_put_inode(struct inode *); +extern void isofs_statfs(struct super_block *, struct statfs *); + +extern int isofs_lseek(struct inode *, struct file *, off_t, int); +extern int isofs_read(struct inode *, struct file *, char *, int); +extern int isofs_lookup_grandparent(struct inode *, int); + +extern struct inode_operations isofs_file_inode_operations; +extern struct inode_operations isofs_dir_inode_operations; +extern struct inode_operations isofs_symlink_inode_operations; +extern struct inode_operations isofs_chrdev_inode_operations; +extern struct inode_operations isofs_blkdev_inode_operations; +extern struct inode_operations isofs_fifo_inode_operations; + +struct lookup_cache{ + unsigned long dir; /* If this matches... */ + dev_t dev; /* And this matches */ + unsigned short dlen; /* and this matches... */ + char filename[256]; /* and this matches... */ + unsigned long ino; /* Then this is the file we are looking for */ +}; + +extern struct lookup_cache cache; + +/* The following macros are used to check for memory leaks. */ +#ifdef LEAK_CHECK +#define free_s leak_check_free_s +#define malloc leak_check_malloc +#define bread leak_check_bread +#define brelse leak_check_brelse +extern void * leak_check_malloc(unsigned int size); +extern void leak_check_free_s(void * obj, int size); +extern struct buffer_head * leak_check_bread(int dev, int block, int size); +extern void leak_check_brelse(struct buffer_head * bh); +#endif /* LEAK_CHECK */ + +#endif + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_i.h new file mode 100644 index 000000000..d8065500f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_i.h @@ -0,0 +1,13 @@ +#ifndef _ISO_FS_I +#define _ISO_FS_I + +/* + * iso fs inode data in memory + */ +struct iso_inode_info { + unsigned int i_first_extent; + unsigned int i_backlink; + unsigned char i_file_format; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_sb.h new file mode 100644 index 000000000..ee2595a41 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/iso_fs_sb.h @@ -0,0 +1,30 @@ +#ifndef _ISOFS_FS_SB +#define _ISOFS_FS_SB + +/* + * minix super-block data in memory + */ +struct isofs_sb_info { + unsigned long s_ninodes; + unsigned long s_nzones; + unsigned long s_firstdatazone; + unsigned long s_log_zone_size; + unsigned long s_max_size; + + unsigned char s_high_sierra; /* A simple flag */ + unsigned char s_mapping; + unsigned char s_conversion; + unsigned char s_rock; + unsigned char s_cruft; /* Broken disks with high + byte of length containing + junk */ +}; + +#endif + + + + + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kd.h new file mode 100644 index 000000000..c67c539ef --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kd.h @@ -0,0 +1,209 @@ +#ifndef _LINUX_KD_H +#define _LINUX_KD_H + +/* 0x4B is 'K', to avoid collision with termios and vt */ + +#define SWAPMONO 0x4B00 /* use mca as output device */ +#define SWAPCGA 0x4B01 /* use cga as output device */ +#define SWAPEGA 0x4B02 /* use ega as output device */ +#define SWAPVGA 0x4B03 /* use vga as output device */ +#define CONS_CURRENT 0x4B04 /* return current output device */ +#define MONO 0x01 +#define CGA 0x02 +#define EGA 0x03 + +#define SW_B40x25 0x4B05 /* 40x25 mono text (cga/ega) */ +#define SW_C40x25 0x4B06 /* 40x24 color text (cga/ega) */ +#define SW_B80x25 0x4B07 /* 80x25 mono text (cga/ega) */ +#define SW_C80x25 0x4B08 /* 80x25 color text (cga/ega) */ +#define SW_BG320 0x4B09 /* 320x200 mono graphics (cga/ega) */ +#define SW_CG320 0x4B0A /* 320x200 color graphics (cga/ega) */ +#define SW_BG640 0x4B0B /* 640x200 mono graphics (cga/ega) */ +#define SW_CG320_D 0x4B0C /* 320x200 graphics (ega mode d) */ +#define SW_CG640_E 0x4B0D /* 640x200 graphics (ega mode e) */ +#define SW_EGAMONOAPA 0x4B0E /* 640x350 graphics (ega mode f) */ +#define SW_ENH_MONOAPA2 0x4B0F /* 640x350 graphics extd mem (ega mode f*) */ +#define SW_CG640x350 0x4B10 /* 640x350 graphics (ega mode 10) */ +#define SW_ENH_CG640 0x4B11 /* 640x350 graphics extd mem (ega mode 10*) */ +#define SW_EGAMONO80x25 0x4B12 /* 80x25 mono text (ega mode 7) */ +#define SW_ENHB40x25 0x4B13 /* enhanced 40x25 mono text (ega) */ +#define SW_ENHC40x25 0x4B14 /* enhanced 40x25 color text (ega) */ +#define SW_ENHB80x25 0x4B15 /* enhanced 80x25 mono text (ega) */ +#define SW_ENHC80x25 0x4B16 /* enhanced 80x25 color text (ega) */ +#define SW_ENHB80x43 0x4B17 /* enhanced 80x43 mono text (ega) */ +#define SW_ENHC80x43 0x4B18 /* enhanced 80x43 color text (ega) */ +#define SW_MCAMODE 0x4B19 /* reinit mca */ +#define SW_ATT640 0x4B1A /* 640x400 16color */ +/* should add more vga modes, etc */ + +#define CONS_GET 0x4B1B /* get current display mode */ +#define M_B40x25 0 /* 40x25 mono (cga/ega) */ +#define M_C40x25 1 /* 40x25 color (cga/ega) */ +#define M_B80x25 2 /* 80x25 mono (cga/ega) */ +#define M_C80x25 3 /* 80x25 color (cga/ega) */ +#define M_BG320 4 /* 320x200 mono (cga/ega) */ +#define M_CG320 5 /* 320x200 color (cga/ega) */ +#define M_BG640 6 /* 640x200 mono (cga/ega) */ +#define M_EGAMONO80x25 7 /* 80x25 mono (ega) */ +#define M_CG320_D 13 /* ega mode d */ +#define M_CG640_E 14 /* ega mode e */ +#define M_EFAMONOAPA 15 /* ega mode f */ +#define M_CG640x350 16 /* ega mode 10 */ +#define M_ENHMONOAPA2 17 /* ega mode f with ext mem */ +#define M_ENH_CG640 18 /* ega mode 10* */ +#define M_ENH_B40x25 19 /* ega enh 40x25 mono */ +#define M_ENH_C40x25 20 /* ega enh 40x25 color */ +#define M_ENH_B80x25 21 /* ega enh 80x25 mono */ +#define M_ENH_C80x25 22 /* ega enh 80x25 color */ +#define M_ENH_B80x43 0x70 /* ega enh 80x43 mono */ +#define M_ENH_C80x43 0x71 /* ega enh 80x43 color */ +#define M_MCA_MODE 0xff /* monochrome adapter mode */ +#define MCA_GET 0x4B1C /* get mca display mode */ +#define CGA_GET 0x4B1D /* get cga display mode */ +#define EGA_GET 0x4B1E /* get ega display mode */ + +#define MAPCONS 0x4B1F /* map current video mem into address space */ +#define MAPMONO 0x4B20 /* map mca video mem into address space */ +#define MAPCGA 0x4B21 /* map cga video mem into address space */ +#define MAPEGA 0x4B22 /* map ega video mem into address space */ +#define MAPVGA 0x4B23 /* map vga video mem into address space */ + +struct port_io_struc { + char dir; /* direction in vs out */ + unsigned short port; + char data; +}; +#define IN_ON_PORT 0x00 +#define OUT_ON_PORT 0x01 +struct port_io_arg { + struct port_io_struc args[4]; +}; +#define MCAIO 0x4B24 /* i/o to mca video board */ +#define CGAIO 0x4B25 /* i/o to cga video board */ +#define EGAIO 0x4B26 /* i/o to ega video board */ +#define VGAIO 0x4B27 /* i/o to vga video board */ + +#define GIO_FONT8x8 0x4B28 /* gets current 8x8 font used */ +#define PIO_FONT8x8 0x4B29 /* use supplied 8x8 font */ +#define GIO_FONT8x14 0x4B2A /* gets current 8x14 font used */ +#define PIO_FONT8x14 0x4B2B /* use supplied 8x14 font */ +#define GIO_FONT8x16 0x4B2C /* gets current 8x16 font used */ +#define PIO_FONT8x16 0x4B2D /* use supplied 8x16 font */ + +#define GIO_FONT 0x4B60 /* gets font in expanded form */ +#define PIO_FONT 0x4B61 /* use font in expanded form */ + +#define MKDIOADDR 32 /* io bitmap size from */ +struct kd_disparam { + long type; /* type of display */ + char *addr; /* display mem address */ + ushort ioaddr[MKDIOADDR]; /* valid i/o addresses */ +}; +#define KDDISPTYPE 0x4B2E /* gets display info */ +#define KD_MONO 0x01 +#define KD_HERCULES 0x02 +#define KD_CGA 0x03 +#define KD_EGA 0x04 + +#define KIOCSOUND 0x4B2F /* start sound generation (0 for off) */ +#define KDMKTONE 0x4B30 /* generate tone */ + +#define KDGETLED 0x4B31 /* return current led flags */ +#define KDSETLED 0x4B32 /* set current led flags */ +#define LED_SCR 0x01 /* scroll lock */ +#define LED_CAP 0x04 /* caps lock */ +#define LED_NUM 0x02 /* num lock */ + +#define KDGKBTYPE 0x4B33 /* get keyboard type */ +#define KB_84 0x01 +#define KB_101 0x02 +#define KB_OTHER 0x03 + +#define KDADDIO 0x4B34 /* add i/o port as valid */ +#define KDDELIO 0x4B35 /* del i/o port as valid */ +#define KDENABIO 0x4B36 /* enable i/o to video board */ +#define KDDISABIO 0x4B37 /* disable i/o to video board */ + +struct kd_quemode { + int qsize; /* desired # elem in queue */ + int signo; /* signal to send when queue not empty */ + char *qaddr; /* user virt addr of queue */ +}; +#define KDQUEMODE 0x4B38 /* enable/disable special queue mode */ + +#define KDSBORDER 0x4B39 /* set screen boarder in ega text mode */ + +#define KDSETMODE 0x4B3A /* set text/grahics mode */ +#define KD_TEXT 0x00 +#define KD_GRAPHICS 0x01 +#define KD_TEXT0 0x02 /* ? */ +#define KD_TEXT1 0x03 /* ? */ +#define KDGETMODE 0x4B3B /* get current mode */ + +struct kd_memloc { + char *vaddr; /* virt addr to map to */ + char *physaddr; /* phys addr to map from */ + long length; /* number of bytes */ + long ioflg; /* enable i/o if set */ +}; +#define KDMAPDISP 0x4B3C /* map display into address space */ +#define KDUNMAPDISP 0x4B3D /* unmap display from address space */ + +#define KDVDCTYPE 0x4B3E /* return vdc controller/display info */ + +#define KIOCINFO 0x4B3F /* tell what the device is */ + +typedef char scrnmap_t; +#define E_TABSZ 256 +#define GIO_SCRNMAP 0x4B40 /* get screen mapping from kernel */ +#define PIO_SCRNMAP 0x4B41 /* put screen mapping table in kernel */ + +#define GIO_ATTR 0x4B42 /* get screen attributes */ +#define GIO_COLOR 0x4B43 /* return nonzero if display is color */ + +#define K_RAW 0x00 +#define K_XLATE 0x01 +#define K_MEDIUMRAW 0x02 +#define KDGKBMODE 0x4B44 /* gets current keyboard mode */ +#define KDSKBMODE 0x4B45 /* sets current keyboard mode */ + +/* merge with previous pair of ioctls? */ +#define K_METABIT 0x03 +#define K_ESCPREFIX 0x04 +#define KDGKBMETA 0x4B62 /* gets meta key handling mode */ +#define KDSKBMETA 0x4B63 /* sets meta key handling mode */ + +struct kbentry { + u_char kb_table; + u_char kb_index; + u_short kb_value; +}; +#define K_NORMTAB 0x00 +#define K_SHIFTTAB 0x01 +#define K_ALTTAB 0x02 +#define K_ALTSHIFTTAB 0x03 +#define K_SRQTAB 0x04 +#define KDGKBENT 0x4B46 /* gets one entry in translation table */ +#define KDSKBENT 0x4B47 /* sets one entry in translation table */ + +struct kbsentry { + u_char kb_func; + u_char kb_string[512]; /* FUNC_BUFSIZE from keyboard.h */ +}; +#define KDGKBSENT 0x4B48 /* gets one function key string entry */ +#define KDSKBSENT 0x4B49 /* sets one function key string entry */ + +struct kbdiacr { + u_char diacr, base, result; +}; +struct kbdiacrs { + unsigned int kb_cnt; /* number of entries in following array */ + struct kbdiacr kbdiacr[256]; /* MAX_DIACR from keyboard.h */ +}; +#define KDGKBDIACR 0x4B4A /* read kernel accent table */ +#define KDSKBDIACR 0x4B4B /* write kernel accent table */ + +/* note: 0x4B60 and 0x4B61 used above for GIO_FONT and PIO_FONT + 0x4B62 and 0x4B63 used above for KDGKBMETA and KDSKBMETA */ + +#endif /* _LINUX_KD_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel.h new file mode 100644 index 000000000..665e42f85 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel.h @@ -0,0 +1,78 @@ +#ifndef _LINUX_KERNEL_H +#define _LINUX_KERNEL_H + +/* + * 'kernel.h' contains some often-used function prototypes etc + */ + +#ifdef __KERNEL__ + +#include + +#define INT_MAX ((int)(~0U>>1)) +#define UINT_MAX (~0U) +#define LONG_MAX ((long)(~0UL>>1)) +#define ULONG_MAX (~0UL) + +#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 */ + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) +# define NORET_TYPE __volatile__ +# define ATTRIB_NORET /**/ +# define NORET_AND /**/ +#else +# define NORET_TYPE /**/ +# define ATTRIB_NORET __attribute__((noreturn)) +# define NORET_AND noreturn, +#endif + +extern void math_error(void); +NORET_TYPE void panic(const char * fmt, ...) + __attribute__ ((NORET_AND format (printf, 1, 2))); +NORET_TYPE void do_exit(long error_code) + ATTRIB_NORET; +unsigned long simple_strtoul(const char *,char **,unsigned int); +int sprintf(char * buf, const char * fmt, ...); + +int session_of_pgrp(int pgrp); + +int kill_proc(int pid, int sig, int priv); +int kill_pg(int pgrp, int sig, int priv); +int kill_sl(int sess, int sig, int priv); + +asmlinkage int printk(const char * fmt, ...) + __attribute__ ((format (printf, 1, 2))); + +/* + * 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 + * BSD-style accounting where the process is flagged if it uses root + * privs). The implication of this is that you should do normal + * permissions checks first, and check suser() last. + */ +#define suser() (current->euid == 0) + +#endif /* __KERNEL__ */ + +#define SI_LOAD_SHIFT 16 +struct sysinfo { + long uptime; /* Seconds since boot */ + unsigned long loads[3]; /* 1, 5, and 15 minute load averages */ + unsigned long totalram; /* Total usable main memory size */ + unsigned long freeram; /* Available memory size */ + unsigned long sharedram; /* Amount of shared memory */ + unsigned long bufferram; /* Memory used by buffers */ + unsigned long totalswap; /* Total swap space size */ + unsigned long freeswap; /* swap space still available */ + unsigned short procs; /* Number of current processes */ + char _f[22]; /* Pads structure to 64 bytes */ +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel_stat.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel_stat.h new file mode 100644 index 000000000..2f3e53b8e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/kernel_stat.h @@ -0,0 +1,26 @@ +#ifndef _LINUX_KERNEL_STAT_H +#define _LINUX_KERNEL_STAT_H + +/* + * 'kernel_stat.h' contains the definitions needed for doing + * some kernel statistics (cpu usage, context switches ...), + * used by rstatd/perfmeter + */ + +#define DK_NDRIVE 4 + +struct kernel_stat { + unsigned int cpu_user, cpu_nice, cpu_system; + unsigned int dk_drive[DK_NDRIVE]; + unsigned int pgpgin, pgpgout; + unsigned int pswpin, pswpout; + unsigned int interrupts; + unsigned int ipackets, opackets; + unsigned int ierrors, oerrors; + unsigned int collisions; + unsigned int context_swtch; +}; + +extern struct kernel_stat kstat; + +#endif /* _LINUX_KERNEL_STAT_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/keyboard.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/keyboard.h new file mode 100644 index 000000000..b95643527 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/keyboard.h @@ -0,0 +1,140 @@ +#ifndef __LINUX_KEYBOARD_H +#define __LINUX_KEYBOARD_H + +#define KG_SHIFT 0 +#define KG_CTRL 2 +#define KG_ALT 3 +#define KG_ALTGR 1 + +#define NR_KEYS 128 +#define NR_KEYMAPS 16 +extern const int NR_TYPES; +extern const int max_vals[]; +extern unsigned short key_map[NR_KEYMAPS][NR_KEYS]; + +#define NR_FUNC 36 +#define FUNC_BUFSIZE 512 +extern char func_buf[FUNC_BUFSIZE]; +extern char *func_table[NR_FUNC]; + +#define KT_LATIN 0 /* we depend on this being zero */ +#define KT_LETTER 11 /* symbol that can be acted upon by CapsLock */ +#define KT_FN 1 +#define KT_SPEC 2 +#define KT_PAD 3 +#define KT_DEAD 4 +#define KT_CONS 5 +#define KT_CUR 6 +#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) +#define KVAL(x) ((x) & 0xff) + +#define K_F1 K(KT_FN,0) +#define K_F2 K(KT_FN,1) +#define K_F3 K(KT_FN,2) +#define K_F4 K(KT_FN,3) +#define K_F5 K(KT_FN,4) +#define K_F6 K(KT_FN,5) +#define K_F7 K(KT_FN,6) +#define K_F8 K(KT_FN,7) +#define K_F9 K(KT_FN,8) +#define K_F10 K(KT_FN,9) +#define K_F11 K(KT_FN,10) +#define K_F12 K(KT_FN,11) +#define K_F13 K(KT_FN,12) +#define K_F14 K(KT_FN,13) +#define K_F15 K(KT_FN,14) +#define K_F16 K(KT_FN,15) +#define K_F17 K(KT_FN,16) +#define K_F18 K(KT_FN,17) +#define K_F19 K(KT_FN,18) +#define K_F20 K(KT_FN,19) +#define K_FIND K(KT_FN,20) +#define K_INSERT K(KT_FN,21) +#define K_REMOVE K(KT_FN,22) +#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_PAUSE K(KT_FN,29) + +#define K_HOLE K(KT_SPEC,0) +#define K_ENTER K(KT_SPEC,1) +#define K_SH_REGS K(KT_SPEC,2) +#define K_SH_MEM K(KT_SPEC,3) +#define K_SH_STAT K(KT_SPEC,4) +#define K_BREAK K(KT_SPEC,5) +#define K_CONS K(KT_SPEC,6) +#define K_CAPS K(KT_SPEC,7) +#define K_NUM K(KT_SPEC,8) +#define K_HOLD K(KT_SPEC,9) +#define K_SCROLLFORW K(KT_SPEC,10) +#define K_SCROLLBACK K(KT_SPEC,11) +#define K_BOOT K(KT_SPEC,12) +#define K_CAPSON K(KT_SPEC,13) +#define K_COMPOSE K(KT_SPEC,14) + +#define K_P0 K(KT_PAD,0) +#define K_P1 K(KT_PAD,1) +#define K_P2 K(KT_PAD,2) +#define K_P3 K(KT_PAD,3) +#define K_P4 K(KT_PAD,4) +#define K_P5 K(KT_PAD,5) +#define K_P6 K(KT_PAD,6) +#define K_P7 K(KT_PAD,7) +#define K_P8 K(KT_PAD,8) +#define K_P9 K(KT_PAD,9) +#define K_PPLUS K(KT_PAD,10) /* key-pad plus */ +#define K_PMINUS K(KT_PAD,11) /* key-pad minus */ +#define K_PSTAR K(KT_PAD,12) /* key-pad asterisk (star) */ +#define K_PSLASH K(KT_PAD,13) /* key-pad slash */ +#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) +#define K_DCIRCM K(KT_DEAD,2) +#define K_DTILDE K(KT_DEAD,3) +#define K_DDIERE K(KT_DEAD,4) + +#define K_DOWN K(KT_CUR,0) +#define K_LEFT K(KT_CUR,1) +#define K_RIGHT K(KT_CUR,2) +#define K_UP K(KT_CUR,3) + +#define K_SHIFT K(KT_SHIFT,KG_SHIFT) +#define K_CTRL K(KT_SHIFT,KG_CTRL) +#define K_ALT K(KT_SHIFT,KG_ALT) +#define K_ALTGR K(KT_SHIFT,KG_ALTGR) + +#define NR_SHIFT 4 + +#define K_CAPSSHIFT K(KT_SHIFT,NR_SHIFT) + +#define K_ASC0 K(KT_ASCII,0) +#define K_ASC1 K(KT_ASCII,1) +#define K_ASC2 K(KT_ASCII,2) +#define K_ASC3 K(KT_ASCII,3) +#define K_ASC4 K(KT_ASCII,4) +#define K_ASC5 K(KT_ASCII,5) +#define K_ASC6 K(KT_ASCII,6) +#define K_ASC7 K(KT_ASCII,7) +#define K_ASC8 K(KT_ASCII,8) +#define K_ASC9 K(KT_ASCII,9) + +#define K_SHIFTLOCK K(KT_LOCK,KG_SHIFT) +#define K_CTRLLOCK K(KT_LOCK,KG_CTRL) +#define K_ALTLOCK K(KT_LOCK,KG_ALT) +#define K_ALTGRLOCK K(KT_LOCK,KG_ALTGR) + +#define MAX_DIACR 256 +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ldt.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ldt.h new file mode 100644 index 000000000..3deed0727 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ldt.h @@ -0,0 +1,33 @@ +/* + * ldt.h + * + * Definitions of structures used with the modify_ldt system call. + */ +#ifndef _LINUX_LDT_H +#define _LINUX_LDT_H + +/* Maximum number of LDT entries supported. */ +#define LDT_ENTRIES 8192 +/* The size of each LDT entry. */ +#define LDT_ENTRY_SIZE 8 + +struct modify_ldt_ldt_s { + unsigned int entry_number; + unsigned long base_addr; + unsigned int limit; + unsigned int seg_32bit:1; + unsigned int contents:2; + unsigned int read_exec_only:1; + unsigned int limit_in_pages:1; +}; + +#define MODIFY_LDT_CONTENTS_DATA 0 +#define MODIFY_LDT_CONTENTS_STACK 1 +#define MODIFY_LDT_CONTENTS_CODE 2 + +extern int get_ldt(void *buffer); +extern int set_ldt_entry(int entry, unsigned long base, unsigned int limit, + int seg_32bit_flag, int contents, int read_only_flag, + int limit_in_pages_flag); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/limits.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/limits.h new file mode 100644 index 000000000..d0f300c4f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/limits.h @@ -0,0 +1,17 @@ +#ifndef _LINUX_LIMITS_H +#define _LINUX_LIMITS_H + +#define NR_OPEN 256 + +#define NGROUPS_MAX 32 /* supplemental group IDs are available */ +#define ARG_MAX 131072 /* # bytes of args + environ for exec() */ +#define CHILD_MAX 999 /* no limit :-) */ +#define OPEN_MAX 256 /* # open files a process may have */ +#define LINK_MAX 127 /* # links a file may have */ +#define MAX_CANON 255 /* size of the canonical input queue */ +#define MAX_INPUT 255 /* size of the type-ahead buffer */ +#define NAME_MAX 255 /* # chars in a file name */ +#define PATH_MAX 1024 /* # chars in a path name */ +#define PIPE_BUF 4096 /* # bytes in atomic write to a pipe */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/linkage.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/linkage.h new file mode 100644 index 000000000..8f5c4d5f2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/linkage.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_LINKAGE_H +#define _LINUX_LINKAGE_H + +#ifdef __cplusplus +#define asmlinkage extern "C" +#else +#define asmlinkage +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/locks.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/locks.h new file mode 100644 index 000000000..ac9b29076 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/locks.h @@ -0,0 +1,56 @@ +#ifndef _LINUX_LOCKS_H +#define _LINUX_LOCKS_H + +/* + * Buffer cache locking - note that interrupts may only unlock, not + * lock buffers. + */ +extern void __wait_on_buffer(struct buffer_head *); + +extern inline void wait_on_buffer(struct buffer_head * bh) +{ + if (bh->b_lock) + __wait_on_buffer(bh); +} + +extern inline void lock_buffer(struct buffer_head * bh) +{ + if (bh->b_lock) + __wait_on_buffer(bh); + bh->b_lock = 1; +} + +extern inline void unlock_buffer(struct buffer_head * bh) +{ + bh->b_lock = 0; + wake_up(&bh->b_wait); +} + +/* + * super-block locking. Again, interrupts may only unlock + * a super-block (although even this isn't done right now. + * nfs may need it). + */ +extern void __wait_on_super(struct super_block *); + +extern inline void wait_on_super(struct super_block * sb) +{ + if (sb->s_lock) + __wait_on_super(sb); +} + +extern inline void lock_super(struct super_block * sb) +{ + if (sb->s_lock) + __wait_on_super(sb); + sb->s_lock = 1; +} + +extern inline void unlock_super(struct super_block * sb) +{ + sb->s_lock = 0; + wake_up(&sb->s_wait); +} + +#endif /* _LINUX_LOCKS_H */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/lp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/lp.h new file mode 100644 index 000000000..de3061e2e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/lp.h @@ -0,0 +1,147 @@ +#ifndef _LINUX_LP_H +#define _LINUX_LP_H + +/* + * usr/include/linux/lp.h c.1991-1992 James Wiegand + * many modifications copyright (C) 1992 Michael K. Johnson + * Interrupt support added 1993 Nigel Gamble + */ + +/* + * Per POSIX guidelines, this module reserves the LP and lp prefixes + * These are the lp_table[minor].flags flags... + */ +#define LP_EXIST 0x0001 +#define LP_SELEC 0x0002 +#define LP_BUSY 0x0004 +#define LP_OFFL 0x0008 +#define LP_NOPA 0x0010 +#define LP_ERR 0x0020 +#define LP_ABORT 0x0040 + +/* timeout for each character. This is relative to bus cycles -- it + * is the count in a busy loop. THIS IS THE VALUE TO CHANGE if you + * have extremely slow printing, or if the machine seems to slow down + * a lot when you print. If you have slow printing, increase this + * number and recompile, and if your system gets bogged down, decrease + * this number. This can be changed with the tunelp(8) command as well. + */ + +#define LP_INIT_CHAR 1000 + +/* The parallel port specs apparently say that there needs to be + * a .5usec wait before and after the strobe. Since there are wildly + * different computers running linux, I can't come up with a perfect + * value, but since it worked well on most printers before without, + * I'll initialize it to 0. + */ + +#define LP_INIT_WAIT 0 + +/* This is the amount of time that the driver waits for the printer to + * catch up when the printer's buffer appears to be filled. If you + * want to tune this and have a fast printer (i.e. HPIIIP), decrease + * this number, and if you have a slow printer, increase this number. + * This is in hundredths of a second, the default 2 being .05 second. + * Or use the tunelp(8) command, which is especially nice if you want + * change back and forth between character and graphics printing, which + * are wildly different... + */ + +#define LP_INIT_TIME 2 + +/* IOCTL numbers */ +#define LPCHAR 0x0001 /* corresponds to LP_INIT_CHAR */ +#define LPTIME 0x0002 /* corresponds to LP_INIT_TIME */ +#define LPABORT 0x0004 /* call with TRUE arg to abort on error, + FALSE to retry. Default is retry. */ +#define LPSETIRQ 0x0005 /* call with new IRQ number, + or 0 for polling (no IRQ) */ +#define LPGETIRQ 0x0006 /* get the current IRQ number */ +#define LPWAIT 0x0008 /* corresponds to LP_INIT_WAIT */ + +/* timeout for printk'ing a timeout, in jiffies (100ths of a second). + This is also used for re-checking error conditions if LP_ABORT is + not set. This is the default behavior. */ + +#define LP_TIMEOUT_INTERRUPT (60 * HZ) +#define LP_TIMEOUT_POLLED (10 * HZ) + +#define LP_B(minor) lp_table[(minor)].base /* IO address */ +#define LP_F(minor) lp_table[(minor)].flags /* flags for busy, etc. */ +#define LP_S(minor) inb_p(LP_B((minor)) + 1) /* status port */ +#define LP_C(minor) (lp_table[(minor)].base + 2) /* control port */ +#define LP_CHAR(minor) lp_table[(minor)].chars /* busy timeout */ +#define LP_TIME(minor) lp_table[(minor)].time /* wait time */ +#define LP_WAIT(minor) lp_table[(minor)].wait /* strobe wait */ +#define LP_IRQ(minor) lp_table[(minor)].irq /* interrupt # */ + /* 0 means polled */ + +#define LP_BUFFER_SIZE 256 + +struct lp_struct { + int base; + unsigned int irq; + int flags; + unsigned int chars; + unsigned int time; + unsigned int wait; + struct wait_queue *lp_wait_q; + char *lp_buffer; +}; + +/* the BIOS manuals say there can be up to 4 lpt devices + * but I have not seen a board where the 4th address is listed + * if you have different hardware change the table below + * please let me know if you have different equipment + * if you have more than 3 printers, remember to increase LP_NO + */ +struct lp_struct lp_table[] = { + { 0x3bc, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, + { 0x378, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, + { 0x278, 0, 0, LP_INIT_CHAR, LP_INIT_TIME, LP_INIT_WAIT, NULL, NULL, }, +}; +#define LP_NO 3 + +/* + * bit defines for 8255 status port + * base + 1 + * accessed with LP_S(minor), which gets the byte... + */ +#define LP_PBUSY 0x80 /* active low */ +#define LP_PACK 0x40 /* active low */ +#define LP_POUTPA 0x20 +#define LP_PSELECD 0x10 +#define LP_PERRORP 0x08 /* active low*/ + +/* + * defines for 8255 control port + * base + 2 + * accessed with LP_C(minor) + */ +#define LP_PINTEN 0x10 +#define LP_PSELECP 0x08 +#define LP_PINITP 0x04 /* active low */ +#define LP_PAUTOLF 0x02 +#define LP_PSTROBE 0x01 + +/* + * the value written to ports to test existence. PC-style ports will + * return the value written. AT-style ports will return 0. so why not + * make them the same ? + */ +#define LP_DUMMY 0x00 + +/* + * This is the port delay time. Your mileage may vary. + * It is used only in the lp_init() routine. + */ +#define LP_DELAY 150000 + +/* + * function prototypes + */ + +extern long lp_init(long); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/major.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/major.h new file mode 100644 index 000000000..8b3a8ab2f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/major.h @@ -0,0 +1,91 @@ +#ifndef _LINUX_MAJOR_H +#define _LINUX_MAJOR_H + +/* + * This file has definitions for major device numbers + */ + +/* limits */ + +#define MAX_CHRDEV 32 +#define MAX_BLKDEV 32 + +/* + * assignments + * + * devices are as follows (same as minix, so we can use the minix fs): + * + * character block comments + * -------------------- -------------------- -------------------- + * 0 - unnamed unnamed minor 0 = true nodev + * 1 - /dev/mem ramdisk + * 2 - floppy + * 3 - hd + * 4 - /dev/tty* + * 5 - /dev/tty; /dev/cua* + * 6 - lp + * 7 - UNUSED + * 8 - scsi disk + * 9 - scsi tape + * 10 - mice + * 11 - scsi cdrom + * 12 - qic02 tape + * 13 - xt disk + * 14 - sound card + * 15 - cdu31a cdrom + * 16 - sockets + * 17 - af_unix + * 18 - af_inet + * 19 - UNUSED + * 20 - UNUSED + * 21 - scsi generic + * 22 - (at2disk) + * 23 - mitsumi cdrom + * 24 - sony535 cdrom + * 25 - matsushita cdrom minors 0..3 + * 26 - + * 27 - qic117 tape + */ + +#define UNNAMED_MAJOR 0 +#define MEM_MAJOR 1 +#define FLOPPY_MAJOR 2 +#define HD_MAJOR 3 +#define TTY_MAJOR 4 +#define TTYAUX_MAJOR 5 +#define LP_MAJOR 6 +/* unused: 7 */ +#define SCSI_DISK_MAJOR 8 +#define SCSI_TAPE_MAJOR 9 +#define MOUSE_MAJOR 10 +#define SCSI_CDROM_MAJOR 11 +#define QIC02_TAPE_MAJOR 12 +#define XT_DISK_MAJOR 13 +#define SOUND_MAJOR 14 +#define CDU31A_CDROM_MAJOR 15 +#define SOCKET_MAJOR 16 +#define AF_UNIX_MAJOR 17 +#define AF_INET_MAJOR 18 +/* unused: 19, 20 */ +#define SCSI_GENERIC_MAJOR 21 +/* unused: 22 */ +#define MITSUMI_CDROM_MAJOR 23 +#define CDU535_CDROM_MAJOR 24 +#define MATSUSHITA_CDROM_MAJOR 25 +#define QIC117_TAPE_MAJOR 27 + +/* + * Tests for SCSI devices. + */ + +#define SCSI_MAJOR(M) \ + ((M) == SCSI_DISK_MAJOR \ + || (M) == SCSI_TAPE_MAJOR \ + || (M) == SCSI_CDROM_MAJOR \ + || (M) == SCSI_GENERIC_MAJOR) + +static inline int scsi_major(int m) { + return SCSI_MAJOR(m); +} + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/malloc.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/malloc.h new file mode 100644 index 000000000..b803b8b8d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/malloc.h @@ -0,0 +1,30 @@ +#ifndef _LINUX_MALLOC_H +#define _LINUX_MALLOC_H + +#include + +#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/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/math_emu.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/math_emu.h new file mode 100644 index 000000000..ec8d6ba0e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/math_emu.h @@ -0,0 +1,58 @@ +#ifndef _LINUX_MATH_EMU_H +#define _LINUX_MATH_EMU_H + +struct fpu_reg { + char sign; + char tag; + long exp; + unsigned sigl; + unsigned sigh; +}; + +struct info { + long ___orig_eip; + long ___ret_from_system_call; + long ___ebx; + long ___ecx; + long ___edx; + long ___esi; + long ___edi; + long ___ebp; + long ___eax; + long ___ds; + long ___es; + long ___fs; + long ___gs; + long ___orig_eax; + long ___eip; + long ___cs; + long ___eflags; + long ___esp; + long ___ss; +}; + +#if 0 +#define EAX (info->___eax) +#define EBX (info->___ebx) +#define ECX (info->___ecx) +#define EDX (info->___edx) +#define ESI (info->___esi) +#define EDI (info->___edi) +#define EBP (info->___ebp) +#define ESP (info->___esp) +#define EIP (info->___eip) +#define ORIG_EIP (info->___orig_eip) +#define EFLAGS (info->___eflags) +#define DS (*(unsigned short *) &(info->___ds)) +#define ES (*(unsigned short *) &(info->___es)) +#define FS (*(unsigned short *) &(info->___fs)) +#define CS (*(unsigned short *) &(info->___cs)) +#define SS (*(unsigned short *) &(info->___ss)) +#endif + +void __math_abort(struct info *, unsigned int); + +#define math_abort(x,y) \ +(((volatile void (*)(struct info *,unsigned int)) __math_abort)((x),(y))) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mc146818rtc.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mc146818rtc.h new file mode 100644 index 000000000..741aa2dc5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mc146818rtc.h @@ -0,0 +1,104 @@ +/* mc146818rtc.h - register definitions for the Real-Time-Clock / CMOS RAM + * Copyright Torsten Duwe 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 + +#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/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mcd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mcd.h new file mode 100644 index 000000000..3dedf801d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mcd.h @@ -0,0 +1,106 @@ +/* + * Definitions for a Mitsumi CD-ROM interface + * + * Copyright (C) 1992 Martin Harriss + * + * martin@bdsi.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. + * + */ + +/* *** change this to set the I/O port address */ +#define MCD_BASE_ADDR 0x300 + +/* *** change this to set the interrupt number */ +#define MCD_INTR_NR 11 + +/* Increase this if you get lots of timeouts */ +#define MCD_STATUS_DELAY 100 + +/* number of times to retry a command before giving up */ +#define MCD_RETRY_ATTEMPTS 3 + +/* port access macro */ +#define MCDPORT(x) (mcd_port + (x)) + +/* status bits */ + +#define MST_CMD_CHECK 0x01 /* command error */ +#define MST_BUSY 0x02 /* now playing */ +#define MST_READ_ERR 0x04 /* read error */ +#define MST_DSK_TYPE 0x08 +#define MST_SERVO_CHECK 0x10 +#define MST_DSK_CHG 0x20 /* disk removed or changed */ +#define MST_READY 0x40 /* disk in the drive */ +#define MST_DOOR_OPEN 0x80 /* door is open */ + +/* flag bits */ + +#define MFL_DATA 0x02 /* data available */ +#define MFL_STATUS 0x04 /* status available */ + +/* commands */ + +#define MCMD_GET_DISK_INFO 0x10 /* read info from disk */ +#define MCMD_GET_Q_CHANNEL 0x20 /* read info from q channel */ +#define MCMD_GET_STATUS 0x40 +#define MCMD_SET_MODE 0x50 +#define MCMD_SOFT_RESET 0x60 +#define MCMD_STOP 0x70 /* stop play */ +#define MCMD_CONFIG_DRIVE 0x90 +#define MCMD_SET_VOLUME 0xAE /* set audio level */ +#define MCMD_PLAY_READ 0xC0 /* play or read data */ +#define MCMD_GET_VERSION 0xDC + +/* borrowed from hd.c */ + +#define READ_DATA(port, buf, nr) \ +insb(port, buf, nr) + +#define SET_TIMER(func, jifs) \ + ((timer_table[MCD_TIMER].expires = jiffies + jifs), \ + (timer_table[MCD_TIMER].fn = func), \ + (timer_active |= 1<. Oh well. */ +#define MINIX_LINK_MAX 250 + +#define MINIX_I_MAP_SLOTS 8 +#define MINIX_Z_MAP_SLOTS 8 +#define MINIX_SUPER_MAGIC 0x137F /* original minix fs */ +#define MINIX_SUPER_MAGIC2 0x138F /* minix fs, 30 char names */ +#define NEW_MINIX_SUPER_MAGIC 0x2468 /* minix V2 - not implemented */ +#define MINIX_VALID_FS 0x0001 /* Clean fs. */ +#define MINIX_ERROR_FS 0x0002 /* fs has errors. */ + +#define MINIX_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof (struct minix_inode))) + +struct minix_inode { + unsigned short i_mode; + unsigned short i_uid; + unsigned long i_size; + unsigned long i_time; + unsigned char i_gid; + unsigned char i_nlinks; + unsigned short i_zone[9]; +}; + +/* + * The new minix inode has all the time entries, as well as + * long block numbers and a third indirect block (7+1+1+1 + * instead of 7+1+1). Also, some previously 8-bit values are + * now 16-bit. The inode is now 64 bytes instead of 32. + */ +struct new_minix_inode { + unsigned short i_mode; + unsigned short i_nlinks; + unsigned short i_uid; + unsigned short i_gid; + unsigned long i_size; + unsigned long i_atime; + unsigned long i_mtime; + unsigned long i_ctime; + unsigned long i_zone[10]; +}; + +/* + * minix super-block data on disk + */ +struct minix_super_block { + unsigned short s_ninodes; + unsigned short s_nzones; + unsigned short s_imap_blocks; + unsigned short s_zmap_blocks; + unsigned short s_firstdatazone; + unsigned short s_log_zone_size; + unsigned long s_max_size; + unsigned short s_magic; + unsigned short s_state; +}; + +struct minix_dir_entry { + unsigned short inode; + char name[0]; +}; + +extern int minix_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern int minix_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); +extern int minix_mkdir(struct inode * dir, const char * name, int len, int mode); +extern int minix_rmdir(struct inode * dir, const char * name, int len); +extern int minix_unlink(struct inode * dir, const char * name, int len); +extern int minix_symlink(struct inode * inode, const char * name, int len, + const char * symname); +extern int minix_link(struct inode * oldinode, struct inode * dir, const char * name, int len); +extern int minix_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); +extern int minix_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len); +extern struct inode * minix_new_inode(const struct inode * dir); +extern void minix_free_inode(struct inode * inode); +extern unsigned long minix_count_free_inodes(struct super_block *sb); +extern int minix_new_block(struct super_block * sb); +extern void minix_free_block(struct super_block * sb, int block); +extern unsigned long minix_count_free_blocks(struct super_block *sb); + +extern int minix_bmap(struct inode *,int); + +extern struct buffer_head * minix_getblk(struct inode *, int, int); +extern struct buffer_head * minix_bread(struct inode *, int, int); + +extern void minix_truncate(struct inode *); +extern void minix_put_super(struct super_block *); +extern struct super_block *minix_read_super(struct super_block *,void *,int); +extern void minix_write_super(struct super_block *); +extern int minix_remount (struct super_block * sb, int * flags, char * data); +extern void minix_read_inode(struct inode *); +extern void minix_write_inode(struct inode *); +extern void minix_put_inode(struct inode *); +extern void minix_statfs(struct super_block *, struct statfs *); +extern int minix_sync_inode(struct inode *); +extern int minix_sync_file(struct inode *, struct file *); + +extern struct inode_operations minix_file_inode_operations; +extern struct inode_operations minix_dir_inode_operations; +extern struct inode_operations minix_symlink_inode_operations; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_i.h new file mode 100644 index 000000000..6478627bc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_i.h @@ -0,0 +1,11 @@ +#ifndef _MINIX_FS_I +#define _MINIX_FS_I + +/* + * minix fs inode data in memory + */ +struct minix_inode_info { + unsigned short i_data[16]; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_sb.h new file mode 100644 index 000000000..a48347980 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/minix_fs_sb.h @@ -0,0 +1,24 @@ +#ifndef _MINIX_FS_SB +#define _MINIX_FS_SB + +/* + * minix super-block data in memory + */ +struct minix_sb_info { + unsigned long s_ninodes; + unsigned long s_nzones; + unsigned long s_imap_blocks; + unsigned long s_zmap_blocks; + unsigned long s_firstdatazone; + unsigned long s_log_zone_size; + unsigned long s_max_size; + struct buffer_head * s_imap[8]; + struct buffer_head * s_zmap[8]; + unsigned long s_dirsize; + unsigned long s_namelen; + struct buffer_head * s_sbh; + struct minix_super_block * s_ms; + unsigned short s_mount_state; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mktime.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mktime.h new file mode 100644 index 000000000..1c58e6302 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mktime.h @@ -0,0 +1,13 @@ +#ifndef _LINUX_MKTIME_H +#define _LINUX_MKTIME_H + +struct mktime { + int sec; + int min; + int hour; + int day; + int mon; + int year; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mm.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mm.h new file mode 100644 index 000000000..d8900969a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mm.h @@ -0,0 +1,195 @@ +#ifndef _LINUX_MM_H +#define _LINUX_MM_H + +#include +#include +#include +#include + +#define VERIFY_READ 0 +#define VERIFY_WRITE 1 + +int __verify_write(unsigned long addr, unsigned long count); + +extern inline int verify_area(int type, void * addr, unsigned long size) +{ + if (TASK_SIZE <= (unsigned long) addr) + return -EFAULT; + if (size > TASK_SIZE - (unsigned long) addr) + return -EFAULT; + if (wp_works_ok || type == VERIFY_READ || !size) + return 0; + return __verify_write((unsigned long) addr,size); +} + +/* + * Linux kernel virtual memory manager primitives. + * The idea being to have a "virtual" mm in the same way + * we have a virtual fs - giving a cleaner interface to the + * mm details, and allowing different kinds of memory mappings + * (from shared memory to executable loading to arbitrary + * mmap() functions). + */ + +/* + * This struct defines a memory VMM memory area. There is one of these + * per VM-area/task. A VM area is any part of the process virtual memory + * space that has a special rule for the page-fault handlers (ie a shared + * library, the executable area etc). + */ +struct vm_area_struct { + struct task_struct * vm_task; /* VM area parameters */ + unsigned long vm_start; + unsigned long vm_end; + unsigned short vm_page_prot; + struct vm_area_struct * vm_next; /* linked list */ + struct vm_area_struct * vm_share; /* linked list */ + struct inode * vm_inode; + unsigned long vm_offset; + struct vm_operations_struct * vm_ops; +}; + +/* + * These are the virtual MM functions - opening of an area, closing it (needed to + * keep files on disk up-to-date etc), pointer to the functions called when a + * no-page or a wp-page exception occurs, and the function which decides on sharing + * of pages between different processes. + */ +struct vm_operations_struct { + void (*open)(struct vm_area_struct * area); + void (*close)(struct vm_area_struct * area); + void (*nopage)(int error_code, + 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); +extern unsigned long __bad_pagetable(void); +extern unsigned long __zero_page(void); + +#define BAD_PAGETABLE __bad_pagetable() +#define BAD_PAGE __bad_page() +#define ZERO_PAGE __zero_page() + +extern volatile short free_page_ptr; /* used by malloc and tcp/ip. */ + +extern int nr_swap_pages; +extern int nr_free_pages; +extern unsigned long free_page_list; +extern int nr_secondary_pages; +extern unsigned long secondary_page_list; + +#define MAX_SECONDARY_PAGES 10 + +/* + * This is timing-critical - most of the time in getting a new page + * goes to clearing the page. If you want a page without the clearing + * overhead, just use __get_free_page() directly.. + */ +extern unsigned long __get_free_page(int priority); +extern inline unsigned long get_free_page(int priority) +{ + unsigned long page; + + page = __get_free_page(priority); + if (page) + __asm__ __volatile__("rep ; stosl" + : /* no outputs */ \ + :"a" (0),"c" (1024),"D" (page) + :"di","cx"); + return page; +} + +/* memory.c */ + +extern void free_page(unsigned long addr); +extern unsigned long put_dirty_page(struct task_struct * tsk,unsigned long page, + unsigned long address); +extern void free_page_tables(struct task_struct * tsk); +extern void clear_page_tables(struct task_struct * tsk); +extern int copy_page_tables(struct task_struct * to); +extern int clone_page_tables(struct task_struct * to); +extern int unmap_page_range(unsigned long from, unsigned long size); +extern int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask); +extern int zeromap_page_range(unsigned long from, unsigned long size, int mask); + +extern void do_wp_page(unsigned long error_code, unsigned long address, + struct task_struct *tsk, unsigned long user_esp); +extern void do_no_page(unsigned long error_code, unsigned long address, + struct task_struct *tsk, unsigned long user_esp); + +extern unsigned long paging_init(unsigned long start_mem, unsigned long end_mem); +extern void mem_init(unsigned long low_start_mem, + unsigned long start_mem, unsigned long end_mem); +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); +extern int vread(char *buf, char *addr, int count); + +/* swap.c */ + +extern void swap_free(unsigned long page_nr); +extern unsigned long swap_duplicate(unsigned long page_nr); +extern void swap_in(unsigned long *table_ptr); +extern void si_swapinfo(struct sysinfo * val); +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)) +#define write_swap_page(nr,buf) \ + rw_swap_page(WRITE,(nr),(buf)) + +#define invalidate() \ +__asm__ __volatile__("movl %%cr3,%%eax\n\tmovl %%eax,%%cr3": : :"ax") + +extern unsigned long high_memory; + +#define MAP_NR(addr) ((addr) >> PAGE_SHIFT) +#define MAP_PAGE_RESERVED (1<<15) + +extern unsigned short * mem_map; + +#define PAGE_PRESENT 0x001 +#define PAGE_RW 0x002 +#define PAGE_USER 0x004 +#define PAGE_PWT 0x008 /* 486 only - not used currently */ +#define PAGE_PCD 0x010 /* 486 only - not used currently */ +#define PAGE_ACCESSED 0x020 +#define PAGE_DIRTY 0x040 +#define PAGE_COW 0x200 /* implemented in software (one of the AVL bits) */ + +#define PAGE_PRIVATE (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED | PAGE_COW) +#define PAGE_SHARED (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED) +#define PAGE_COPY (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED | PAGE_COW) +#define PAGE_READONLY (PAGE_PRESENT | PAGE_USER | PAGE_ACCESSED) +#define PAGE_TABLE (PAGE_PRESENT | PAGE_RW | PAGE_USER | PAGE_ACCESSED) + +#define GFP_BUFFER 0x00 +#define GFP_ATOMIC 0x01 +#define GFP_USER 0x02 +#define GFP_KERNEL 0x03 + + +/* vm_ops not present page codes */ +#define SHM_SWP_TYPE 0x41 +extern void shm_no_page (ulong *); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mman.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mman.h new file mode 100644 index 000000000..4b42f737f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mman.h @@ -0,0 +1,15 @@ +#ifndef _LINUX_MMAN_H +#define _LINUX_MMAN_H + +#define PROT_READ 0x1 /* page can be read */ +#define PROT_WRITE 0x2 /* page can be written */ +#define PROT_EXEC 0x4 /* page can be executed */ +#define PROT_NONE 0x0 /* page can not be accessed */ + +#define MAP_SHARED 1 /* Share changes */ +#define MAP_PRIVATE 2 /* Changes are private */ +#define MAP_TYPE 0xf /* Mask for type of mapping */ +#define MAP_FIXED 0x10 /* Interpret addr exactly */ +#define MAP_ANONYMOUS 0x20 /* don't use a file */ + +#endif /* _LINUX_MMAN_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/module.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/module.h new file mode 100644 index 000000000..117478c0c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/module.h @@ -0,0 +1,58 @@ +/* + * Dynamic loading of modules into the kernel. + */ + +#ifndef _LINUX_MODULE_H +#define _LINUX_MODULE_H + +/* values of module.state */ +#define MOD_UNINITIALIZED 0 +#define MOD_RUNNING 1 +#define MOD_DELETED 2 + +/* maximum length of module name */ +#define MOD_MAX_NAME 64 + +/* maximum length of symbol name */ +#define SYM_MAX_NAME 60 + + +struct module { + struct module *next; + char *name; + int size; /* size of module in pages */ + void* addr; /* address of module */ + int state; + void (*cleanup)(void); /* cleanup routine */ +}; + + +struct mod_routines { + int (*init)(void); /* initialization routine */ + void (*cleanup)(void); /* cleanup routine */ +}; + + +struct kernel_sym { + unsigned long value; /* value of symbol */ + char name[SYM_MAX_NAME]; /* name of symbol */ +}; + +extern struct module *module_list; + + +/* + * The first word of the module contains the use count. + */ +#define GET_USE_COUNT(module) (* (int *) (module)->addr) +/* + * define the count variable, and usage macros. + */ + +extern int mod_use_count_; + +#define MOD_INC_USE_COUNT mod_use_count_++ +#define MOD_DEC_USE_COUNT mod_use_count_-- +#define MOD_IN_USE (mod_use_count_ != 0) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mouse.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mouse.h new file mode 100644 index 000000000..df4e42718 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mouse.h @@ -0,0 +1,11 @@ +#ifndef _LINUX_MOUSE_H +#define _LINUX_MOUSE_H + +#define BUSMOUSE_MINOR 0 +#define PSMOUSE_MINOR 1 +#define MS_BUSMOUSE_MINOR 2 +#define ATIXL_BUSMOUSE_MINOR 3 + +unsigned long mouse_init(unsigned long); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs.h new file mode 100644 index 000000000..756abaa33 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs.h @@ -0,0 +1,190 @@ +#ifndef _LINUX_MSDOS_FS_H +#define _LINUX_MSDOS_FS_H + +/* + * The MS-DOS filesystem constants/structures + */ + +#include +#include +#include + +#define MSDOS_ROOT_INO 1 /* == MINIX_ROOT_INO */ +#define SECTOR_SIZE 512 /* sector size (bytes) */ +#define SECTOR_BITS 9 /* log2(SECTOR_SIZE) */ +#define MSDOS_DPB (MSDOS_DPS*2) /* dir entries per block */ +#define MSDOS_DPB_BITS 5 /* log2(MSDOS_DPB) */ +#define MSDOS_DPS (SECTOR_SIZE/sizeof(struct msdos_dir_entry)) +#define MSDOS_DPS_BITS 4 /* log2(MSDOS_DPS) */ +#define MSDOS_DIR_BITS 5 /* log2(sizeof(struct msdos_dir_entry)) */ + +#define MSDOS_SUPER_MAGIC 0x4d44 /* MD */ + +#define FAT_CACHE 8 /* FAT cache size */ + +#define ATTR_RO 1 /* read-only */ +#define ATTR_HIDDEN 2 /* hidden */ +#define ATTR_SYS 4 /* system */ +#define ATTR_VOLUME 8 /* volume label */ +#define ATTR_DIR 16 /* directory */ +#define ATTR_ARCH 32 /* archived */ + +#define ATTR_NONE 0 /* no attribute bits */ +#define ATTR_UNUSED (ATTR_VOLUME | ATTR_ARCH | ATTR_SYS | ATTR_HIDDEN) + /* attribute bits that are copied "as is" */ + +#define DELETED_FLAG 0xe5 /* marks file as deleted when in name[0] */ +#define IS_FREE(n) (!*(n) || *(unsigned char *) (n) == DELETED_FLAG || \ + *(unsigned char *) (n) == FD_FILL_BYTE) + +#define MSDOS_VALID_MODE (S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO) + /* valid file mode bits */ + +#define MSDOS_SB(s) (&((s)->u.msdos_sb)) +#define MSDOS_I(i) (&((i)->u.msdos_i)) + +#define MSDOS_NAME 11 /* maximum name length */ +#define MSDOS_DOT ". " /* ".", padded to MSDOS_NAME chars */ +#define MSDOS_DOTDOT ".. " /* "..", padded to MSDOS_NAME chars */ + +#define MSDOS_FAT12 4078 /* maximum number of clusters in a 12 bit FAT */ + +/* + * Conversion from and to little-endian byte order. (no-op on i386/i486) + * + * Naming: Ca_b_c, where a: F = from, T = to, b: LE = little-endian, BE = big- + * endian, c: W = word (16 bits), L = longword (32 bits) + */ + +#define CF_LE_W(v) (v) +#define CF_LE_L(v) (v) +#define CT_LE_W(v) (v) +#define CT_LE_L(v) (v) + + +struct msdos_boot_sector { + char ignored[3]; /* Boot strap short or near jump */ + char system_id[8]; /* Name - can be used to special case + partition manager volumes */ + unsigned char sector_size[2];/* bytes per logical sector */ + unsigned char cluster_size; /* sectors/cluster */ + unsigned short reserved; /* reserved sectors */ + unsigned char fats; /* number of FATs */ + unsigned char dir_entries[2];/* root directory entries */ + unsigned char sectors[2]; /* number of sectors */ + unsigned char media; /* media code (unused) */ + unsigned short fat_length; /* sectors/FAT */ + unsigned short secs_track; /* sectors per track */ + unsigned short heads; /* number of heads */ + unsigned long hidden; /* hidden sectors (unused) */ + unsigned long total_sect; /* number of sectors (if sectors == 0) */ +}; + +struct msdos_dir_entry { + char name[8],ext[3]; /* name and extension */ + unsigned char attr; /* attribute bits */ + char unused[10]; + unsigned short time,date,start; /* time, date and first cluster */ + unsigned long size; /* file size (in bytes) */ +}; + +struct fat_cache { + int device; /* device number. 0 means unused. */ + int ino; /* inode number. */ + int file_cluster; /* cluster number in the file. */ + int disk_cluster; /* cluster number on disk. */ + struct fat_cache *next; /* next cache entry */ +}; + +/* Determine whether this FS has kB-aligned data. */ + +#define MSDOS_CAN_BMAP(mib) (!(((mib)->cluster_size & 1) || \ + ((mib)->data_start & 1))) + +/* Convert attribute bits and a mask to the UNIX mode. */ + +#define MSDOS_MKMODE(a,m) (m & (a & ATTR_RO ? S_IRUGO|S_IXUGO : S_IRWXUGO)) + +/* Convert the UNIX mode to MS-DOS attribute bits. */ + +#define MSDOS_MKATTR(m) ((m & S_IWUGO) ? ATTR_NONE : ATTR_RO) + + +static inline struct buffer_head *msdos_sread(int dev,int sector,void **start) +{ + struct buffer_head *bh; + + if (!(bh = bread(dev,sector >> 1, 1024))) + return NULL; + *start = bh->b_data+((sector & 1) << SECTOR_BITS); + return bh; +} + + +/* misc.c */ + +extern void fs_panic(struct super_block *s,char *msg); +extern int is_binary(char conversion,char *extension); +extern void lock_creation(void); +extern void unlock_creation(void); +extern void lock_fat(struct super_block *sb); +extern void unlock_fat(struct super_block *sb); +extern int msdos_add_cluster(struct inode *inode); +extern int date_dos2unix(unsigned short time,unsigned short date); +extern void date_unix2dos(int unix_date,unsigned short *time, + unsigned short *date); +extern int msdos_get_entry(struct inode *dir,off_t *pos,struct buffer_head **bh, + struct msdos_dir_entry **de); +extern int msdos_scan(struct inode *dir,char *name,struct buffer_head **res_bh, + struct msdos_dir_entry **res_de,int *ino); +extern int msdos_parent_ino(struct inode *dir,int locked); +extern int msdos_subdirs(struct inode *dir); + +/* fat.c */ + +extern int fat_access(struct super_block *sb,int nr,int new_value); +extern int msdos_smap(struct inode *inode,int sector); +extern int fat_free(struct inode *inode,int skip); +extern void cache_init(void); +void cache_lookup(struct inode *inode,int cluster,int *f_clu,int *d_clu); +void cache_add(struct inode *inode,int f_clu,int d_clu); +void cache_inval_inode(struct inode *inode); +void cache_inval_dev(int device); +int get_cluster(struct inode *inode,int cluster); + +/* namei.c */ + +extern int msdos_lookup(struct inode *dir,const char *name,int len, + struct inode **result); +extern int msdos_create(struct inode *dir,const char *name,int len,int mode, + struct inode **result); +extern int msdos_mkdir(struct inode *dir,const char *name,int len,int mode); +extern int msdos_rmdir(struct inode *dir,const char *name,int len); +extern int msdos_unlink(struct inode *dir,const char *name,int len); +extern int msdos_rename(struct inode *old_dir,const char *old_name,int old_len, + struct inode *new_dir,const char *new_name,int new_len); + +/* inode.c */ + +extern void msdos_put_inode(struct inode *inode); +extern void msdos_put_super(struct super_block *sb); +extern struct super_block *msdos_read_super(struct super_block *s, + void *data,int); +extern void msdos_statfs(struct super_block *sb,struct statfs *buf); +extern int msdos_bmap(struct inode *inode,int block); +extern void msdos_read_inode(struct inode *inode); +extern void msdos_write_inode(struct inode *inode); +extern int msdos_notify_change(int flags,struct inode *inode); + +/* dir.c */ + +extern struct inode_operations msdos_dir_inode_operations; + +/* file.c */ + +extern struct inode_operations msdos_file_inode_operations; +extern struct inode_operations msdos_file_inode_operations_no_bmap; + +extern void msdos_truncate(struct inode *inode); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_i.h new file mode 100644 index 000000000..21eb99977 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_i.h @@ -0,0 +1,20 @@ +#ifndef _MSDOS_FS_I +#define _MSDOS_FS_I + +/* + * MS-DOS file system inode data in memory + */ + +struct msdos_inode_info { + int i_start; /* first cluster or 0 */ + int i_attrs; /* unused attribute bits */ + int i_busy; /* file is either deleted but still open, or + inconsistent (mkdir) */ + struct inode *i_depend; /* pointer to inode that depends on the + current inode */ + struct inode *i_old; /* pointer to the old inode this inode + depends on */ + int i_binary; /* file contains non-text data */ +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_sb.h new file mode 100644 index 000000000..8e5f3041b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msdos_fs_sb.h @@ -0,0 +1,27 @@ +#ifndef _MSDOS_FS_SB +#define _MSDOS_FS_SB + +/* + * MS-DOS file system in-core superblock data + */ + +struct msdos_sb_info { + unsigned short cluster_size; /* sectors/cluster */ + unsigned char fats,fat_bits; /* number of FATs, FAT bits (12 or 16) */ + unsigned short fat_start,fat_length; /* FAT start & length (sec.) */ + unsigned short dir_start,dir_entries; /* root dir start & entries */ + unsigned short data_start; /* first data sector */ + unsigned long clusters; /* number of clusters */ + uid_t fs_uid; + gid_t fs_gid; + int quiet; /* fake successful chmods and chowns */ + unsigned short fs_umask; + unsigned char name_check; /* r = relaxed, n = normal, s = strict */ + unsigned char conversion; /* b = binary, t = text, a = auto */ + struct wait_queue *fat_wait; + int fat_lock; + int prev_free; /* previously returned free cluster number */ + int free_clusters; /* -1 if undefined */ +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msg.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msg.h new file mode 100644 index 000000000..da0226936 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/msg.h @@ -0,0 +1,74 @@ +#ifndef _LINUX_MSG_H +#define _LINUX_MSG_H +#include + +/* msgrcv options */ +#define MSG_NOERROR 010000 /* no error if message is too big */ +#define MSG_EXCEPT 020000 /* recv any msg except of specified type.*/ + + +/* one msg structure for each message */ +struct msg { + struct msg *msg_next; /* next message on queue */ + long msg_type; + char *msg_spot; /* message text address */ + short msg_ts; /* message text size */ +}; + +/* one msqid structure for each queue on the system */ +struct msqid_ds { + struct ipc_perm msg_perm; + struct msg *msg_first; /* first message on queue */ + struct msg *msg_last; /* last message in queue */ + time_t msg_stime; /* last msgsnd time */ + time_t msg_rtime; /* last msgrcv time */ + time_t msg_ctime; /* last change time */ + struct wait_queue *wwait; + struct wait_queue *rwait; + ushort msg_cbytes; /* current number of bytes on queue */ + ushort msg_qnum; /* number of messages in queue */ + ushort msg_qbytes; /* max number of bytes on queue */ + ushort msg_lspid; /* pid of last msgsnd */ + ushort msg_lrpid; /* last receive pid */ +}; + + +/* message buffer for msgsnd and msgrcv calls */ +struct msgbuf { + long mtype; /* type of message */ + char mtext[1]; /* message text */ +}; + + +struct msginfo { + int msgpool; + int msgmap; + int msgmax; + int msgmnb; + int msgmni; + int msgssz; + int msgtql; + ushort msgseg; +}; + +#define MSGMNI 128 /* <= 1K */ /* max # of msg queue identifiers */ +#define MSGMAX 4080 /* <= 4080 */ /* max size of message (bytes) */ +#define MSGMNB 16384 /* ? */ /* default max size of a message queue */ + +/* unused */ +#define MSGPOOL (MSGMNI*MSGMNB/1024) /* size in kilobytes of message pool */ +#define MSGTQL MSGMNB /* number of system message headers */ +#define MSGMAP MSGMNB /* number of entries in message map */ +#define MSGSSZ 16 /* message segment size */ +#define __MSGSEG ((MSGPOOL*1024)/ MSGSSZ) /* max no. of segments */ +#define MSGSEG (__MSGSEG <= 0xffff ? __MSGSEG : 0xffff) + +#ifdef __KERNEL__ + +/* ipcs ctl commands */ +#define MSG_STAT 11 +#define MSG_INFO 12 + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_MSG_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mtio.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mtio.h new file mode 100644 index 000000000..446667e38 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/mtio.h @@ -0,0 +1,156 @@ +/* $Id: mtio.h,v 1.4 1992/11/18 01:32:03 root Exp root $ + * + * linux/mtio.h header file for Linux. Written by H. Bergman + */ + +#ifndef _LINUX_MTIO_H +#define _LINUX_MTIO_H + +#include + +/* + * Structures and definitions for mag tape io control commands + */ + +/* structure for MTIOCTOP - mag tape op command */ +struct mtop { + short mt_op; /* operations defined below */ + int mt_count; /* how many of them */ +}; + +/* Magnetic Tape operations [Not all operations supported by all drivers]: */ +#define MTRESET 0 /* +reset drive in case of problems */ +#define MTFSF 1 /* forward space over FileMark, + * position at first record of next file + */ +#define MTBSF 2 /* backward space FileMark (position before FM) */ +#define MTFSR 3 /* forward space record */ +#define MTBSR 4 /* backward space record */ +#define MTWEOF 5 /* write an end-of-file record (mark) */ +#define MTREW 6 /* rewind */ +#define MTOFFL 7 /* rewind and put the drive offline (eject?) */ +#define MTNOP 8 /* no op, set status only (read with MTIOCGET) */ +#define MTRETEN 9 /* retension tape */ +#define MTBSFM 10 /* +backward space FileMark, position at FM */ +#define MTFSFM 11 /* +forward space FileMark, position at FM */ +#define MTEOM 12 /* goto end of recorded media (for appending files). + * MTEOM positions after the last FM, ready for + * appending another file. + */ +#define MTERASE 13 /* erase tape -- be careful! */ + +#define MTRAS1 14 /* run self test 1 (nondestructive) */ +#define MTRAS2 15 /* run self test 2 (destructive) */ +#define MTRAS3 16 /* reserved for self test 3 */ + + +#define MTSETBLK 20 /* set block length (SCSI) */ +#define MTSETDENSITY 21 /* set tape density (SCSI) */ +#define MTSEEK 22 /* seek to block (Tandberg, etc.) */ +#define MTTELL 23 /* tell block (Tandber, etc.) */ +#define MTSETDRVBUFFER 24 /* set the drive buffering according to SCSI-2 */ + /* ordinary buffered operation with code 1 */ + + +/* structure for MTIOCGET - mag tape get status command */ + +struct mtget { + long mt_type; /* type of magtape device */ + long mt_resid; /* residual count: (not sure) + * number of bytes ignored, or + * number of files not skipped, or + * number of records not skipped. + */ + /* the following registers are device dependent */ + long mt_dsreg; /* status register */ + long mt_gstat; /* generic (device independent) status */ + long mt_erreg; /* error register */ + /* The next two fields are not always used */ + daddr_t mt_fileno; /* number of current file on tape */ + daddr_t mt_blkno; /* current block number */ +}; + +/* + * Constants for mt_type. Not all of these are supported. + */ +#define MT_ISUNKNOWN 0x01 +#define MT_ISQIC02 0x02 /* Generic QIC-02 tape streamer */ +#define MT_ISWT5150 0x03 /* Wangtek 5150EQ, QIC-150, QIC-02 */ +#define MT_ISARCHIVE_5945L2 0x04 /* Archive 5945L-2, QIC-24, QIC-02? */ +#define MT_ISCMSJ500 0x05 /* CMS Jumbo 500 (QIC-02?) */ +#define MT_ISTDC3610 0x06 /* Tandberg 6310, QIC-24 */ +#define MT_ISARCHIVE_VP60I 0x07 /* Archive VP60i, QIC-02 */ +#define MT_ISARCHIVE_2150L 0x08 /* Archive Viper 2150L */ +#define MT_ISARCHIVE_2060L 0x09 /* Archive Viper 2060L */ +#define MT_ISQIC02_ALL_FEATURES 0x0F /* Generic QIC-02 with all features */ +#define MT_ISWT5099EEN24 0x11 /* Wangtek 5099-een24, 60MB, QIC-24 */ +#define MT_ISEVEREX_FT40A 0x32 /* Everex FT40A (QIC-40) */ +#define MT_ISDDS1 0x51 /* DDS device without partitions */ +#define MT_ISDDS2 0x52 /* DDS device with partitions */ +#define MT_ISSCSI1 0x71 /* Generic ANSI SCSI-1 tape unit */ + +struct mt_tape_info { + long t_type; /* device type id (mt_type) */ + char *t_name; /* descriptive name */ +}; +#define MT_TAPE_INFO { \ + {MT_ISUNKNOWN, "Unknown type of tape device"}, \ + {MT_ISQIC02, "Generic QIC-02 tape streamer"}, \ + {MT_ISWT5150, "Wangtek 5150, QIC-150"}, \ + {MT_ISARCHIVE_5945L2, "Archive 5945L-2"}, \ + {MT_ISCMSJ500, "CMS Jumbo 500"}, \ + {MT_ISTDC3610, "Tandberg TDC 3610, QIC-24"}, \ + {MT_ISARCHIVE_VP60I, "Archive VP60i, QIC-02"}, \ + {MT_ISARCHIVE_2150L, "Archive Viper 2150L"}, \ + {MT_ISARCHIVE_2060L, "Archive Viper 2060L"}, \ + {MT_ISWT5099EEN24, "Wangtek 5099-een24, 60MB"}, \ + {MT_ISEVEREX_FT40A, "Everex FT40A, QIC-40"}, \ + {MT_ISSCSI1, "Generic SCSI-1 tape"}, \ + {0, NULL} \ +} + + +/* structure for MTIOCPOS - mag tape get position command */ + +struct mtpos { + long mt_blkno; /* current block number */ +}; + + +/* mag tape io control commands */ +#define MTIOCTOP _IOW('m', 1, struct mtop) /* do a mag tape op */ +#define MTIOCGET _IOR('m', 2, struct mtget) /* get tape status */ +#define MTIOCPOS _IOR('m', 3, struct mtpos) /* get tape position */ + + +/* Generic Mag Tape (device independent) status macros for examining + * mt_gstat -- HP-UX compatible. + * There is room for more generic status bits here, but I don't + * know which of them are reserved. At least three or so should + * be added to make this really useful. + */ +#define GMT_EOF(x) ((x) & 0x80000000) +#define GMT_BOT(x) ((x) & 0x40000000) +#define GMT_EOT(x) ((x) & 0x20000000) +#define GMT_SM(x) ((x) & 0x10000000) /* DDS setmark */ +#define GMT_EOD(x) ((x) & 0x08000000) /* DDS EOD */ +#define GMT_WR_PROT(x) ((x) & 0x04000000) +/* #define GMT_ ? ((x) & 0x02000000) */ +#define GMT_ONLINE(x) ((x) & 0x01000000) +#define GMT_D_6250(x) ((x) & 0x00800000) +#define GMT_D_1600(x) ((x) & 0x00400000) +#define GMT_D_800(x) ((x) & 0x00200000) +/* #define GMT_ ? ((x) & 0x00100000) */ +/* #define GMT_ ? ((x) & 0x00080000) */ +#define GMT_DR_OPEN(x) ((x) & 0x00040000) /* door open (no tape) */ +/* #define GMT_ ? ((x) & 0x00020000) */ +#define GMT_IM_REP_EN(x) ((x) & 0x00010000) /* immediate report mode */ +/* 16 generic status bits unused */ + +/* DDS drives have 'setmarks', sort of like filemarks but used to group + * files, rather than blocks. Not used. Not supported. + * I think DDS drives are DAT drives. + */ + +#endif /* _LINUX_MTIO_H */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/net.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/net.h new file mode 100644 index 000000000..0806f9286 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/net.h @@ -0,0 +1,130 @@ +/* + * NET An implementation of the SOCKET network access protocol. + * This is the master header file for the Linux NET layer, + * or, in plain English: the networking handling part of the + * kernel. + * + * Version: @(#)net.h 1.0.3 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_NET_H +#define _LINUX_NET_H + + +#include +#include + + +#define NSOCKETS 128 /* should be dynamic, later... */ +#define NPROTO 16 /* should be enough for now.. */ + + +#define SYS_SOCKET 1 /* sys_socket(2) */ +#define SYS_BIND 2 /* sys_bind(2) */ +#define SYS_CONNECT 3 /* sys_connect(2) */ +#define SYS_LISTEN 4 /* sys_listen(2) */ +#define SYS_ACCEPT 5 /* sys_accept(2) */ +#define SYS_GETSOCKNAME 6 /* sys_getsockname(2) */ +#define SYS_GETPEERNAME 7 /* sys_getpeername(2) */ +#define SYS_SOCKETPAIR 8 /* sys_socketpair(2) */ +#define SYS_SEND 9 /* sys_send(2) */ +#define SYS_RECV 10 /* sys_recv(2) */ +#define SYS_SENDTO 11 /* sys_sendto(2) */ +#define SYS_RECVFROM 12 /* sys_recvfrom(2) */ +#define SYS_SHUTDOWN 13 /* sys_shutdown(2) */ +#define SYS_SETSOCKOPT 14 /* sys_setsockopt(2) */ +#define SYS_GETSOCKOPT 15 /* sys_getsockopt(2) */ + + +typedef enum { + SS_FREE = 0, /* not allocated */ + SS_UNCONNECTED, /* unconnected to any socket */ + SS_CONNECTING, /* in process of connecting */ + SS_CONNECTED, /* connected to socket */ + SS_DISCONNECTING /* in process of disconnecting */ +} socket_state; + +#define SO_ACCEPTCON (1<<16) /* performed a listen */ + + +/* + * Internel representation of a socket. not all the fields are used by + * all configurations: + * + * server client + * conn client connected to server connected to + * iconn list of clients -unused- + * awaiting connections + * wait sleep for clients, sleep for connection, + * sleep for i/o sleep for i/o + */ +struct socket { + short type; /* SOCK_STREAM, ... */ + socket_state state; + long flags; + struct proto_ops *ops; /* protocols do most everything */ + void *data; /* protocol data */ + struct socket *conn; /* server socket connected to */ + struct socket *iconn; /* incomplete client conn.s */ + struct socket *next; + struct wait_queue **wait; /* ptr to place to wait on */ + struct inode *inode; +}; + +#define SOCK_INODE(S) ((S)->inode) + +struct proto_ops { + int family; + + int (*create) (struct socket *sock, int protocol); + int (*dup) (struct socket *newsock, struct socket *oldsock); + int (*release) (struct socket *sock, struct socket *peer); + int (*bind) (struct socket *sock, struct sockaddr *umyaddr, + int sockaddr_len); + int (*connect) (struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags); + int (*socketpair) (struct socket *sock1, struct socket *sock2); + int (*accept) (struct socket *sock, struct socket *newsock, + int flags); + int (*getname) (struct socket *sock, struct sockaddr *uaddr, + int *usockaddr_len, int peer); + int (*read) (struct socket *sock, char *ubuf, int size, + int nonblock); + int (*write) (struct socket *sock, char *ubuf, int size, + int nonblock); + int (*select) (struct socket *sock, int sel_type, + select_table *wait); + int (*ioctl) (struct socket *sock, unsigned int cmd, + unsigned long arg); + int (*listen) (struct socket *sock, int len); + int (*send) (struct socket *sock, void *buff, int len, int nonblock, + unsigned flags); + int (*recv) (struct socket *sock, void *buff, int len, int nonblock, + unsigned flags); + int (*sendto) (struct socket *sock, void *buff, int len, int nonblock, + unsigned flags, struct sockaddr *, int addr_len); + int (*recvfrom) (struct socket *sock, void *buff, int len, int nonblock, + unsigned flags, struct sockaddr *, int *addr_len); + int (*shutdown) (struct socket *sock, int flags); + int (*setsockopt) (struct socket *sock, int level, int optname, + char *optval, int optlen); + int (*getsockopt) (struct socket *sock, int level, int optname, + char *optval, int *optlen); + int (*fcntl) (struct socket *sock, unsigned int cmd, + unsigned long arg); +}; + + +extern int sock_awaitconn(struct socket *mysock, struct socket *servsock); +extern int sock_register(int family, struct proto_ops *ops); + + +#endif /* _LINUX_NET_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs.h new file mode 100644 index 000000000..3cfbd1d12 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs.h @@ -0,0 +1,169 @@ +#ifndef _LINUX_NFS_H +#define _LINUX_NFS_H + +#define NFS_PORT 2049 +#define NFS_MAXDATA 8192 +#define NFS_MAXPATHLEN 1024 +#define NFS_MAXNAMLEN 255 +#define NFS_MAXGROUPS 16 +#define NFS_FHSIZE 32 +#define NFS_COOKIESIZE 4 +#define NFS_FIFO_DEV (-1) +#define NFSMODE_FMT 0170000 +#define NFSMODE_DIR 0040000 +#define NFSMODE_CHR 0020000 +#define NFSMODE_BLK 0060000 +#define NFSMODE_REG 0100000 +#define NFSMODE_LNK 0120000 +#define NFSMODE_SOCK 0140000 +#define NFSMODE_FIFO 0010000 + +#ifdef __KERNEL__ /* user programs should get these from the rpc header files */ + +#define RPC_VERSION 2 + +enum rpc_auth_flavor { + RPC_AUTH_NULL = 0, + RPC_AUTH_UNIX = 1, + RPC_AUTH_SHORT = 2 +}; + +enum rpc_msg_type { + RPC_CALL = 0, + RPC_REPLY = 1 +}; + +enum rpc_reply_stat { + RPC_MSG_ACCEPTED = 0, + RPC_MSG_DENIED = 1 +}; + +enum rpc_accept_stat { + RPC_SUCCESS = 0, + RPC_PROG_UNAVAIL = 1, + RPC_PROG_MISMATCH = 2, + RPC_PROC_UNAVAIL = 3, + RPC_GARBAGE_ARGS = 4 +}; + +enum rpc_reject_stat { + RPC_MISMATCH = 0, + RPC_AUTH_ERROR = 1 +}; + +enum rpc_auth_stat { + RPC_AUTH_BADCRED = 1, + RPC_AUTH_REJECTEDCRED = 2, + RPC_AUTH_BADVERF = 3, + RPC_AUTH_REJECTEDVERF = 4, + RPC_AUTH_TOOWEAK = 5 +}; + +#endif /* __KERNEL__ */ + +enum nfs_stat { + NFS_OK = 0, + NFSERR_PERM = 1, + NFSERR_NOENT = 2, + NFSERR_IO = 5, + NFSERR_NXIO = 6, + NFSERR_ACCES = 13, + NFSERR_EXIST = 17, + NFSERR_NODEV = 19, + NFSERR_NOTDIR = 20, + NFSERR_ISDIR = 21, + NFSERR_INVAL = 22, /* that Sun forgot */ + NFSERR_FBIG = 27, + NFSERR_NOSPC = 28, + NFSERR_ROFS = 30, + NFSERR_NAMETOOLONG = 63, + NFSERR_NOTEMPTY = 66, + NFSERR_DQUOT = 69, + NFSERR_STALE = 70, + NFSERR_WFLUSH = 99 +}; + +enum nfs_ftype { + NFNON = 0, + NFREG = 1, + NFDIR = 2, + NFBLK = 3, + NFCHR = 4, + NFLNK = 5, + NFSOCK = 6, + NFBAD = 7, + NFFIFO = 8 +}; + +#define NFS_PROGRAM 100003 +#define NFS_VERSION 2 +#define NFSPROC_NULL 0 +#define NFSPROC_GETATTR 1 +#define NFSPROC_SETATTR 2 +#define NFSPROC_ROOT 3 +#define NFSPROC_LOOKUP 4 +#define NFSPROC_READLINK 5 +#define NFSPROC_READ 6 +#define NFSPROC_WRITECACHE 7 +#define NFSPROC_WRITE 8 +#define NFSPROC_CREATE 9 +#define NFSPROC_REMOVE 10 +#define NFSPROC_RENAME 11 +#define NFSPROC_LINK 12 +#define NFSPROC_SYMLINK 13 +#define NFSPROC_MKDIR 14 +#define NFSPROC_RMDIR 15 +#define NFSPROC_READDIR 16 +#define NFSPROC_STATFS 17 + +struct nfs_fh { + char data[NFS_FHSIZE]; +}; + +struct nfs_time { + u_int seconds; + u_int useconds; +}; + +struct nfs_fattr { + enum nfs_ftype type; + u_int mode; + u_int nlink; + u_int uid; + u_int gid; + u_int size; + u_int blocksize; + u_int rdev; + u_int blocks; + u_int fsid; + u_int fileid; + struct nfs_time atime; + struct nfs_time mtime; + struct nfs_time ctime; +}; + +struct nfs_sattr { + u_int mode; + u_int uid; + u_int gid; + u_int size; + struct nfs_time atime; + struct nfs_time mtime; +}; + +struct nfs_entry { + u_int fileid; + char *name; + int cookie; + int eof; +}; + +struct nfs_fsinfo { + u_int tsize; + u_int bsize; + u_int blocks; + u_int bfree; + u_int bavail; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs.h new file mode 100644 index 000000000..367a9fbb8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs.h @@ -0,0 +1,124 @@ +#ifndef _LINUX_NFS_FS_H +#define _LINUX_NFS_FS_H + +/* + * linux/include/linux/nfs_fs.h + * + * Copyright (C) 1992 Rick Sladkey + * + * OS-specific nfs filesystem definitions and declarations + */ + +#include + +#include +#include + +/* + * The readdir cache size controls how many directory entries are cached. + * Its size is limited by the number of nfs_entry structures that can fit + * in one 4096-byte page, currently 256. + */ + +#define NFS_READDIR_CACHE_SIZE 64 + +/* + * WARNING! The I/O buffer size cannot be bigger than about 3900 for now. + * It needs to fit inside a 4096-byte page and leave room for the RPC and + * NFS headers. But it ought to at least be a multiple of 512 and probably + * should be a power of 2. I don't think Linux TCP/IP can handle more than + * about 1800 yet. + */ + +#define NFS_MAX_FILE_IO_BUFFER_SIZE (7*512) +#define NFS_DEF_FILE_IO_BUFFER_SIZE 1024 + +/* + * The upper limit on timeouts for the exponential backoff algorithm + * in tenths of a second. + */ + +#define NFS_MAX_RPC_TIMEOUT 600 + +/* + * Size of the lookup cache in units of number of entries cached. + * It is better not to make this too large although the optimimum + * depends on a usage and environment. + */ + +#define NFS_LOOKUP_CACHE_SIZE 64 + +#define NFS_SUPER_MAGIC 0x6969 + +#define NFS_SERVER(inode) (&(inode)->i_sb->u.nfs_sb.s_server) +#define NFS_FH(inode) (&(inode)->u.nfs_i.fhandle) + +/* linux/fs/nfs/proc.c */ + +extern int nfs_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fattr *fattr); +extern int nfs_proc_setattr(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_sattr *sattr, struct nfs_fattr *fattr); +extern int nfs_proc_lookup(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_fh *fhandle, + struct nfs_fattr *fattr); +extern int nfs_proc_readlink(struct nfs_server *server, struct nfs_fh *fhandle, + char *res); +extern int nfs_proc_read(struct nfs_server *server, struct nfs_fh *fhandle, + int offset, int count, char *data, + struct nfs_fattr *fattr); +extern int nfs_proc_write(struct nfs_server *server, struct nfs_fh *fhandle, + int offset, int count, char *data, + struct nfs_fattr *fattr); +extern int nfs_proc_create(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_sattr *sattr, + struct nfs_fh *fhandle, struct nfs_fattr *fattr); +extern int nfs_proc_remove(struct nfs_server *server, struct nfs_fh *dir, + const char *name); +extern int nfs_proc_rename(struct nfs_server *server, + struct nfs_fh *old_dir, const char *old_name, + struct nfs_fh *new_dir, const char *new_name); +extern int nfs_proc_link(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fh *dir, const char *name); +extern int nfs_proc_symlink(struct nfs_server *server, struct nfs_fh *dir, + const char *name, const char *path, struct nfs_sattr *sattr); +extern int nfs_proc_mkdir(struct nfs_server *server, struct nfs_fh *dir, + const char *name, struct nfs_sattr *sattr, + struct nfs_fh *fhandle, struct nfs_fattr *fattr); +extern int nfs_proc_rmdir(struct nfs_server *server, struct nfs_fh *dir, + const char *name); +extern int nfs_proc_readdir(struct nfs_server *server, struct nfs_fh *fhandle, + int cookie, int count, struct nfs_entry *entry); +extern int nfs_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, + struct nfs_fsinfo *res); + +/* linux/fs/nfs/sock.c */ + +extern int nfs_rpc_call(struct nfs_server *server, int *start, int *end); + +/* linux/fs/nfs/inode.c */ + +extern struct super_block *nfs_read_super(struct super_block *sb, + void *data,int); +extern struct inode *nfs_fhget(struct super_block *sb, struct nfs_fh *fhandle, + struct nfs_fattr *fattr); +extern void nfs_refresh_inode(struct inode *inode, struct nfs_fattr *fattr); + +/* linux/fs/nfs/file.c */ + +extern struct inode_operations nfs_file_inode_operations; + +/* linux/fs/nfs/dir.c */ + +extern struct inode_operations nfs_dir_inode_operations; + +/* linux/fs/nfs/symlink.c */ + +extern struct inode_operations nfs_symlink_inode_operations; + +/* linux/fs/nfs/mmap.c */ + +extern int nfs_mmap(struct inode * inode, struct file * file, + unsigned long addr, size_t len, int prot, unsigned long off); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_i.h new file mode 100644 index 000000000..d4652865b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_i.h @@ -0,0 +1,13 @@ +#ifndef _NFS_FS_I +#define _NFS_FS_I + +#include + +/* + * nfs fs inode data in memory + */ +struct nfs_inode_info { + struct nfs_fh fhandle; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_sb.h new file mode 100644 index 000000000..25db9e83f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_fs_sb.h @@ -0,0 +1,31 @@ +#ifndef _NFS_FS_SB +#define _NFS_FS_SB + +#include + +struct nfs_server { + struct file *file; + int lock; + struct wait_queue *wait; + int flags; + int rsize; + int wsize; + int timeo; + int retrans; + int acregmin; + int acregmax; + int acdirmin; + int acdirmax; + char hostname[256]; +}; + +/* + * nfs super-block data in memory + */ + +struct nfs_sb_info { + struct nfs_server s_server; + struct nfs_fh s_root; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_mount.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_mount.h new file mode 100644 index 000000000..24eff62ed --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/nfs_mount.h @@ -0,0 +1,48 @@ +#ifndef _LINUX_NFS_MOUNT_H +#define _LINUX_NFS_MOUNT_H + +/* + * linux/include/linux/nfs_mount.h + * + * Copyright (C) 1992 Rick Sladkey + * + * structure passed from user-space to kernel-space during an nfs mount + */ + +/* + * WARNING! Do not delete or change the order of these fields. If + * a new field is required then add it to the end. The version field + * tracks which fields are present. This will ensure some measure of + * mount-to-kernel version compatibilty. Some of these aren't used yet + * but here they are anyway. + */ + +#define NFS_MOUNT_VERSION 1 /* current version */ + +struct nfs_mount_data { + int version; /* 1 */ + int fd; /* 1 */ + struct nfs_fh root; /* 1 */ + int flags; /* 1 */ + int rsize; /* 1 */ + int wsize; /* 1 */ + int timeo; /* 1 */ + int retrans; /* 1 */ + int acregmin; /* 1 */ + int acregmax; /* 1 */ + int acdirmin; /* 1 */ + int acdirmax; /* 1 */ + struct sockaddr_in addr; /* 1 */ + char hostname[256]; /* 1 */ +}; + +/* bits in the flags field */ + +#define NFS_MOUNT_SOFT 0x0001 /* 1 */ +#define NFS_MOUNT_INTR 0x0002 /* 1 */ +#define NFS_MOUNT_SECURE 0x0004 /* 1 */ +#define NFS_MOUNT_POSIX 0x0008 /* 1 */ +#define NFS_MOUNT_NOCTO 0x0010 /* 1 */ +#define NFS_MOUNT_NOAC 0x0020 /* 1 */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/page.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/page.h new file mode 100644 index 000000000..5140a852b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/page.h @@ -0,0 +1,34 @@ +#ifndef _LINUX_PAGE_H +#define _LINUX_PAGE_H + + /* PAGE_SHIFT determines the page size */ +#define PAGE_SHIFT 12 +#define PAGE_SIZE ((unsigned long)1<>(PAGE_SHIFT-SIZEOF_PTR_LOG2)*2&PTR_MASK&~PAGE_MASK))) + /* to find an entry in a page-table */ +#define PAGE_PTR(address) \ + ((unsigned long)(address)>>(PAGE_SHIFT-SIZEOF_PTR_LOG2)&PTR_MASK&~PAGE_MASK) + /* the no. of pointers that fit on a page */ +#define PTRS_PER_PAGE (PAGE_SIZE/sizeof(void*)) + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_PAGE_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/param.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/param.h new file mode 100644 index 000000000..c634b1ea3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/param.h @@ -0,0 +1,20 @@ +#ifndef _LINUX_PARAM_H +#define _LINUX_PARAM_H + +#ifndef HZ +#define HZ 100 +#endif + +#define EXEC_PAGESIZE 4096 + +#ifndef NGROUPS +#define NGROUPS 32 +#endif + +#ifndef NOGROUP +#define NOGROUP (-1) +#endif + +#define MAXHOSTNAMELEN 64 /* max length of hostname */ + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/pipe_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/pipe_fs_i.h new file mode 100644 index 000000000..21b39d628 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/pipe_fs_i.h @@ -0,0 +1,35 @@ +#ifndef _LINUX_PIPE_FS_I_H +#define _LINUX_PIPE_FS_I_H + +struct pipe_inode_info { + struct wait_queue * wait; + char * base; + unsigned int start; + unsigned int len; + unsigned int lock; + unsigned int rd_openers; + unsigned int wr_openers; + unsigned int readers; + unsigned int writers; +}; + +#define PIPE_WAIT(inode) ((inode).u.pipe_i.wait) +#define PIPE_BASE(inode) ((inode).u.pipe_i.base) +#define PIPE_START(inode) ((inode).u.pipe_i.start) +#define PIPE_LEN(inode) ((inode).u.pipe_i.len) +#define PIPE_RD_OPENERS(inode) ((inode).u.pipe_i.rd_openers) +#define PIPE_WR_OPENERS(inode) ((inode).u.pipe_i.wr_openers) +#define PIPE_READERS(inode) ((inode).u.pipe_i.readers) +#define PIPE_WRITERS(inode) ((inode).u.pipe_i.writers) +#define PIPE_LOCK(inode) ((inode).u.pipe_i.lock) +#define PIPE_SIZE(inode) PIPE_LEN(inode) + +#define PIPE_EMPTY(inode) (PIPE_SIZE(inode)==0) +#define PIPE_FULL(inode) (PIPE_SIZE(inode)==PIPE_BUF) +#define PIPE_FREE(inode) (PIPE_BUF - PIPE_LEN(inode)) +#define PIPE_END(inode) ((PIPE_START(inode)+PIPE_LEN(inode))&\ + (PIPE_BUF-1)) +#define PIPE_MAX_RCHUNK(inode) (PIPE_BUF - PIPE_START(inode)) +#define PIPE_MAX_WCHUNK(inode) (PIPE_BUF - PIPE_END(inode)) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/proc_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/proc_fs.h new file mode 100644 index 000000000..14f1a3b38 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/proc_fs.h @@ -0,0 +1,36 @@ +#ifndef _LINUX_PROC_FS_H +#define _LINUX_PROC_FS_H + +/* + * The proc filesystem constants/structures + */ + +#define PROC_ROOT_INO 1 + +#define PROC_SUPER_MAGIC 0x9fa0 + +struct proc_dir_entry { + unsigned short low_ino; + unsigned short namelen; + char * name; +}; + +extern struct super_block *proc_read_super(struct super_block *,void *,int); +extern void proc_put_inode(struct inode *); +extern void proc_put_super(struct super_block *); +extern void proc_statfs(struct super_block *, struct statfs *); +extern void proc_read_inode(struct inode *); +extern void proc_write_inode(struct inode *); +extern int proc_match(int, const char *, struct proc_dir_entry *); + +extern struct inode_operations proc_root_inode_operations; +extern struct inode_operations proc_base_inode_operations; +extern struct inode_operations proc_net_inode_operations; +extern struct inode_operations proc_mem_inode_operations; +extern struct inode_operations proc_array_inode_operations; +extern struct inode_operations proc_kmsg_inode_operations; +extern struct inode_operations proc_link_inode_operations; +extern struct inode_operations proc_fd_inode_operations; +extern struct inode_operations proc_net_inode_operations; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ptrace.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ptrace.h new file mode 100644 index 000000000..c20f6e19e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ptrace.h @@ -0,0 +1,69 @@ +#ifndef _LINUX_PTRACE_H +#define _LINUX_PTRACE_H +/* ptrace.h */ +/* structs and defines to help the user use the ptrace system call. */ + +/* has the defines to get at the registers. */ + +#define PTRACE_TRACEME 0 +#define PTRACE_PEEKTEXT 1 +#define PTRACE_PEEKDATA 2 +#define PTRACE_PEEKUSR 3 +#define PTRACE_POKETEXT 4 +#define PTRACE_POKEDATA 5 +#define PTRACE_POKEUSR 6 +#define PTRACE_CONT 7 +#define PTRACE_KILL 8 +#define PTRACE_SINGLESTEP 9 + +#define PTRACE_ATTACH 0x10 +#define PTRACE_DETACH 0x11 + +#define PTRACE_SYSCALL 24 + +/* use ptrace (3 or 6, pid, PT_EXCL, data); to read or write + the processes registers. */ + +#define EBX 0 +#define ECX 1 +#define EDX 2 +#define ESI 3 +#define EDI 4 +#define EBP 5 +#define EAX 6 +#define DS 7 +#define ES 8 +#define FS 9 +#define GS 10 +#define ORIG_EAX 11 +#define EIP 12 +#define CS 13 +#define EFL 14 +#define UESP 15 +#define SS 16 + + +/* this struct defines the way the registers are stored on the + stack during a system call. */ + +struct pt_regs { + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + unsigned short ds, __dsu; + unsigned short es, __esu; + unsigned short fs, __fsu; + unsigned short gs, __gsu; + long orig_eax; + long eip; + unsigned short cs, __csu; + long eflags; + long esp; + unsigned short ss, __ssu; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/resource.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/resource.h new file mode 100644 index 000000000..9d9bc161c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/resource.h @@ -0,0 +1,71 @@ +#ifndef _LINUX_RESOURCE_H +#define _LINUX_RESOURCE_H + +/* + * Resource control/accounting header file for linux + */ + +/* + * Definition of struct rusage taken from BSD 4.3 Reno + * + * We don't support all of these yet, but we might as well have them.... + * Otherwise, each time we add new items, programs which depend on this + * structure will lose. This reduces the chances of that happening. + */ +#define RUSAGE_SELF 0 +#define RUSAGE_CHILDREN (-1) +#define RUSAGE_BOTH (-2) /* sys_wait4() uses this */ + +struct rusage { + struct timeval ru_utime; /* user time used */ + struct timeval ru_stime; /* system time used */ + long ru_maxrss; /* maximum resident set size */ + long ru_ixrss; /* integral shared memory size */ + long ru_idrss; /* integral unshared data size */ + long ru_isrss; /* integral unshared stack size */ + long ru_minflt; /* page reclaims */ + long ru_majflt; /* page faults */ + long ru_nswap; /* swaps */ + long ru_inblock; /* block input operations */ + long ru_oublock; /* block output operations */ + long ru_msgsnd; /* messages sent */ + long ru_msgrcv; /* messages received */ + long ru_nsignals; /* signals received */ + long ru_nvcsw; /* voluntary context switches */ + long ru_nivcsw; /* involuntary " */ +}; + +/* + * Resource limits + */ + +#define RLIMIT_CPU 0 /* CPU time in ms */ +#define RLIMIT_FSIZE 1 /* Maximum filesize */ +#define RLIMIT_DATA 2 /* max data size */ +#define RLIMIT_STACK 3 /* max stack size */ +#define RLIMIT_CORE 4 /* max core file size */ +#define RLIMIT_RSS 5 /* max resident set size */ + +#ifdef notdef +#define RLIMIT_MEMLOCK 6 /* max locked-in-memory address space*/ +#define RLIMIT_NPROC 7 /* max number of processes */ +#define RLIMIT_OFILE 8 /* max number of open files */ +#endif + +#define RLIM_NLIMITS 6 + +#define RLIM_INFINITY 0x7FFFFFFF + +struct rlimit { + int rlim_cur; + int rlim_max; +}; + +#define PRIO_MIN (-99) +#define PRIO_MAX 14 + +#define PRIO_PROCESS 0 +#define PRIO_PGRP 1 +#define PRIO_USER 2 + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/route.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/route.h new file mode 100644 index 000000000..6326a10b8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/route.h @@ -0,0 +1,46 @@ +/* + * 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. + * + * Global definitions for the IP router interface. + * + * Version: @(#)route.h 1.0.3 05/27/93 + * + * Authors: Original taken from Berkeley UNIX 4.3, (c) UCB 1986-1988 + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_ROUTE_H +#define _LINUX_ROUTE_H + +#include + + +/* This structure gets passed by the SIOCADDRT and SIOCDELRT calls. */ +struct rtentry { + unsigned long rt_hash; /* hash key for lookups */ +#define rt_genmask rt_hash + struct sockaddr rt_dst; + struct sockaddr rt_gateway; + short rt_flags; + short rt_refcnt; + unsigned long rt_use; +#ifdef BSD_COMPATIBLE + struct ifnet *rt_ifp; +#else + void *rt_dev; +#endif +}; +#define RTF_UP 0x0001 /* route useable */ +#define RTF_GATEWAY 0x0002 /* destination is a gateway */ +#define RTF_HOST 0x0004 /* host entry (net otherwise) */ +#define RTF_REINSTATE 0x0008 /* re-instate route after tmout */ +#define RTF_DYNAMIC 0x0010 /* created dyn. (by redirect) */ +#define RTF_MODIFIED 0x0020 /* modified dyn. (by redirect) */ + +#endif /* _LINUX_ROUTE_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sbpcd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sbpcd.h new file mode 100644 index 000000000..880781ffd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sbpcd.h @@ -0,0 +1,473 @@ +/* + * sbpcd.h Specify interface address and interface type here. + */ + +/* + * these definitions can get overridden by the kernel command line + * ("lilo boot option"). Examples: + * sbpcd=0x230,SoundBlaster + * or + * sbpcd=0x300,LaserMate + * these strings are case sensitive !!! + */ + +/* + * change this to select the type of your interface board: + * + * set SBPRO to 1 for "true" SoundBlaster card + * set SBPRO to 0 for "poor" (no sound) interface cards + * and for "compatible" soundcards. + * + * most "compatible" sound boards like Galaxy need to set SBPRO to 0 !!! + * if SBPRO gets set wrong, the drive will get found - but any + * data access will give errors (audio access will work). + * The OmniCD interface card from CreativeLabs needs SBPRO 1. + * + * mail to emoenke@gwdg.de if your "compatible" card needs SBPRO 1 + * (currently I do not know any "compatible" with SBPRO 1) + * then I can include better information with the next release. + */ +#define SBPRO 1 + +/* + * put your CDROM port base address here: + * SBPRO addresses typically are 0x0230 (=0x220+0x10), 0x0250, ... + * LASERMATE (CI-101P) adresses typically are 0x0300, 0x0310, ... + * there are some soundcards on the market with 0x0630, 0x0650, ... + * + * obey! changed against v0.4 !!! + * for SBPRO cards, specify the CDROM address - no longer the audio address! + * example: if your SBPRO audio address is 0x220, specify 0x230. + * + * a fill-in is not always necessary - the driver does auto-probing now, + * with the here specified address first... + */ +#define CDROM_PORT 0x0230 + + +/*==========================================================================*/ +/*==========================================================================*/ +/* + * nothing to change below here if you are not experimenting + */ +/*==========================================================================*/ +/*==========================================================================*/ +/* + * Debug output levels + */ +#define DBG_INF 1 /* necessary information */ +#define DBG_IRQ 2 /* interrupt trace */ +#define DBG_REA 3 /* "read" status trace */ +#define DBG_CHK 4 /* "media check" trace */ +#define DBG_TIM 5 /* datarate timer test */ +#define DBG_INI 6 /* initialization trace */ +#define DBG_TOC 7 /* tell TocEntry values */ +#define DBG_IOC 8 /* ioctl trace */ +#define DBG_STA 9 /* "ResponseStatus" trace */ +#define DBG_ERR 10 /* "xx_ReadError" trace */ +#define DBG_CMD 11 /* "cmd_out" trace */ +#define DBG_WRN 12 /* give explanation before auto-probing */ +#define DBG_MUL 13 /* multi session code test */ +#define DBG_ID 14 /* "drive_id !=0" test code */ +#define DBG_IOX 15 /* some special information */ +#define DBG_DID 16 /* drive ID test */ +#define DBG_RES 17 /* drive reset info */ +#define DBG_SPI 18 /* SpinUp test */ +#define DBG_000 19 /* unnecessary information */ + +/*==========================================================================*/ +/*==========================================================================*/ + +/* + * bits of flags_cmd_out: + */ +#define f_respo3 0x100 +#define f_putcmd 0x80 +#define f_respo2 0x40 +#define f_lopsta 0x20 +#define f_getsta 0x10 +#define f_ResponseStatus 0x08 +#define f_obey_p_check 0x04 +#define f_bit1 0x02 +#define f_wait_if_busy 0x01 + +/* + * diskstate_flags: + */ +#define upc_bit 0x40 +#define volume_bit 0x20 +#define toc_bit 0x10 +#define multisession_bit 0x08 +#define cd_size_bit 0x04 +#define subq_bit 0x02 +#define frame_size_bit 0x01 + +/* + * disk states (bits of diskstate_flags): + */ +#define upc_valid (DS[d].diskstate_flags&upc_bit) +#define volume_valid (DS[d].diskstate_flags&volume_bit) +#define toc_valid (DS[d].diskstate_flags&toc_bit) +#define multisession_valid (DS[d].diskstate_flags&multisession_bit) +#define cd_size_valid (DS[d].diskstate_flags&cd_size_bit) +#define subq_valid (DS[d].diskstate_flags&subq_bit) +#define frame_size_valid (DS[d].diskstate_flags&frame_size_bit) + + +/* + * bits of the status_byte (result of xx_ReadStatus): + */ +#define p_door_closed 0x80 +#define p_caddy_in 0x40 +#define p_spinning 0x20 +#define p_check 0x10 +#define p_busy_new 0x08 +#define p_door_locked 0x04 +#define p_bit_1 0x02 +#define p_disk_ok 0x01 +/* + * "old" drives status result bits: + */ +#define p_caddin_old 0x40 +#define p_success_old 0x08 +#define p_busy_old 0x04 + +/* + * used drive states: + */ +#define st_door_closed (DS[d].status_byte&p_door_closed) +#define st_caddy_in (DS[d].status_byte&p_caddy_in) +#define st_spinning (DS[d].status_byte&p_spinning) +#define st_check (DS[d].status_byte&p_check) +#define st_busy (DS[d].status_byte&p_busy_new) +#define st_door_locked (DS[d].status_byte&p_door_locked) +#define st_diskok (DS[d].status_byte&p_disk_ok) + +/* + * bits of the CDi_status register: + */ +#define s_not_result_ready 0x04 /* 0: "result ready" */ +#define s_not_data_ready 0x02 /* 0: "data ready" */ +#define s_attention 0x01 /* 1: "attention required" */ +/* + * usable as: + */ +#define DRV_ATTN ((inb(CDi_status)&s_attention)!=0) +#define DATA_READY ((inb(CDi_status)&s_not_data_ready)==0) +#define RESULT_READY ((inb(CDi_status)&s_not_result_ready)==0) + +/* + * drive types (firmware versions): + */ +#define drv_199 0 /* <200 */ +#define drv_200 1 /* <201 */ +#define drv_201 2 /* <210 */ +#define drv_210 3 /* <211 */ +#define drv_211 4 /* <300 */ +#define drv_300 5 /* else */ +#define drv_099 0x10 /* new, <100 */ +#define drv_100 0x11 /* new, >=100 */ +#define drv_new 0x10 /* all new drives have that bit set */ +#define drv_old 0x00 /* */ + +/* + * drv_099 and drv_100 are the "new" drives + */ +#define new_drive (DS[d].drv_type&0x10) + +/* + * audio states: + */ +#define audio_playing 2 +#define audio_pausing 1 + +/* + * drv_pattern, drv_options: + */ +#define speed_auto 0x80 +#define speed_300 0x40 +#define speed_150 0x20 +#define sax_a 0x04 +#define sax_xn2 0x02 +#define sax_xn1 0x01 + +/* + * values of cmd_type (0 else): + */ +#define cmd_type_READ_M1 0x01 /* "data mode 1": 2048 bytes per frame */ +#define cmd_type_READ_M2 0x02 /* "data mode 2": 12+2048+280 bytes per frame */ +#define cmd_type_READ_SC 0x04 /* "subchannel info": 96 bytes per frame */ + +/* + * sense byte: used only if new_drive + * only during cmd 09 00 xx ah al 00 00 + * + * values: 00 + * 82 + * xx from infobuf[0] after 85 00 00 00 00 00 00 + */ + + +#define CD_MINS 75 /* minutes per CD */ +#define CD_SECS 60 /* seconds per minutes */ +#define CD_FRAMES 75 /* frames per second */ +#define CD_FRAMESIZE 2048 /* bytes per frame, data mode */ +#define CD_FRAMESIZE_XA 2340 /* bytes per frame, "xa" mode */ +#define CD_FRAMESIZE_RAW 2352 /* bytes per frame, "raw" mode */ +#define CD_BLOCK_OFFSET 150 /* offset of first logical frame */ + + +/* audio status (bin) */ +#define aud_00 0x00 /* Audio status byte not supported or not valid */ +#define audx11 0x0b /* Audio play operation in progress */ +#define audx12 0x0c /* Audio play operation paused */ +#define audx13 0x0d /* Audio play operation successfully completed */ +#define audx14 0x0e /* Audio play operation stopped due to error */ +#define audx15 0x0f /* No current audio status to return */ + +/* audio status (bcd) */ +#define aud_11 0x11 /* Audio play operation in progress */ +#define aud_12 0x12 /* Audio play operation paused */ +#define aud_13 0x13 /* Audio play operation successfully completed */ +#define aud_14 0x14 /* Audio play operation stopped due to error */ +#define aud_15 0x15 /* No current audio status to return */ + +/*============================================================================ +============================================================================== + +COMMAND SET of "old" drives like CR-521, CR-522 + (the CR-562 family is different): + +No. Command Code +-------------------------------------------- + +Drive Commands: + 1 Seek 01 + 2 Read Data 02 + 3 Read XA-Data 03 + 4 Read Header 04 + 5 Spin Up 05 + 6 Spin Down 06 + 7 Diagnostic 07 + 8 Read UPC 08 + 9 Read ISRC 09 +10 Play Audio 0A +11 Play Audio MSF 0B +12 Play Audio Track/Index 0C + +Status Commands: +13 Read Status 81 +14 Read Error 82 +15 Read Drive Version 83 +16 Mode Select 84 +17 Mode Sense 85 +18 Set XA Parameter 86 +19 Read XA Parameter 87 +20 Read Capacity 88 +21 Read SUB_Q 89 +22 Read Disc Code 8A +23 Read Disc Information 8B +24 Read TOC 8C +25 Pause/Resume 8D +26 Read Packet 8E +27 Read Path Check 00 + + +all numbers (lba, msf-bin, msf-bcd, counts) to transfer high byte first + +mnemo 7-byte command #bytes response (r0...rn) +________ ____________________ ____ + +Read Status: +status: 81. (1) one-byte command, gives the main + status byte +Read Error: +check1: 82 00 00 00 00 00 00. (6) r1: audio status + +Read Packet: +check2: 8e xx 00 00 00 00 00. (xx) gets xx bytes response, relating + to commands 01 04 05 07 08 09 + +Play Audio: +play: 0a ll-bb-aa nn-nn-nn. (0) play audio, ll-bb-aa: starting block (lba), + nn-nn-nn: #blocks +Play Audio MSF: + 0b mm-ss-ff mm-ss-ff (0) play audio from/to + +Play Audio Track/Index: + 0c ... + +Pause/Resume: +pause: 8d pr 00 00 00 00 00. (0) pause (pr=00) + resume (pr=80) audio playing + +Mode Select: + 84 00 nn-nn ??-?? 00 (0) nn-nn: 2048 or 2340 + possibly defines transfer size + +set_vol: 84 83 00 00 sw le 00. (0) sw(itch): lrxxxxxx (off=1) + le(vel): min=0, max=FF, else half + (firmware 2.11) + +Mode Sense: +get_vol: 85 03 00 00 00 00 00. (2) tell current audio volume setting + +Read Disc Information: +tocdesc: 8b 00 00 00 00 00 00. (6) read the toc descriptor ("msf-bin"-format) + +Read TOC: +tocent: 8c fl nn 00 00 00 00. (8) read toc entry #nn + (fl=0:"lba"-, =2:"msf-bin"-format) + +Read Capacity: +capacit: 88 00 00 00 00 00 00. (5) "read CD-ROM capacity" + + +Read Path Check: +ping: 00 00 00 00 00 00 00. (2) r0=AA, r1=55 + ("ping" if the drive is connected) + +Read Drive Version: +ident: 83 00 00 00 00 00 00. (12) gives "MATSHITAn.nn" + (n.nn = 2.01, 2.11., 3.00, ...) + +Seek: +seek: 01 00 ll-bb-aa 00 00. (0) +seek: 01 02 mm-ss-ff 00 00. (0) + +Read Data: +read: 02 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2048 bytes, + starting at block xx-xx-xx + fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx + +Read XA-Data: +read: 03 xx-xx-xx nn-nn fl. (??) read nn-nn blocks of 2340 bytes, + starting at block xx-xx-xx + fl=0: "lba"-, =2:"msf-bcd"-coded xx-xx-xx + +Read SUB_Q: + 89 fl 00 00 00 00 00. (13) r0: audio status, r4-r7: lba/msf, + fl=0: "lba", fl=2: "msf" + +Read Disc Code: + 8a 00 00 00 00 00 00. (14) possibly extended "check condition"-info + +Read Header: + 04 00 ll-bb-aa 00 00. (0) 4 bytes response with "check2" + 04 02 mm-ss-ff 00 00. (0) 4 bytes response with "check2" + +Spin Up: + 05 00 ll-bb-aa 00 00. (0) possibly implies a "seek" + +Spin Down: + 06 ... + +Diagnostic: + 07 00 ll-bb-aa 00 00. (2) 2 bytes response with "check2" + 07 02 mm-ss-ff 00 00. (2) 2 bytes response with "check2" + +Read UPC: + 08 00 ll-bb-aa 00 00. (16) + 08 02 mm-ss-ff 00 00. (16) + +Read ISRC: + 09 00 ll-bb-aa 00 00. (15) 15 bytes response with "check2" + 09 02 mm-ss-ff 00 00. (15) 15 bytes response with "check2" + +Set XA Parameter: + 86 ... + +Read XA Parameter: + 87 ... + +============================================================================== +============================================================================*/ + +/*==========================================================================*/ +/*==========================================================================*/ + +/* + * highest allowed drive number (MINOR+1) + * currently only one controller, maybe later up to 4 + */ +#define NR_SBPCD 4 + +/* + * we try to never disable interrupts - seems to work + */ +#define SBPCD_DIS_IRQ 0 + +/* + * we don't use the IRQ line - leave it free for the sound driver + */ +#define SBPCD_USE_IRQ 0 + +/* + * you can set the interrupt number of your interface board here: + * It is not used at this time. No need to set it correctly. + */ +#define SBPCD_INTR_NR 7 + +/* + * "write byte to port" + */ +#define OUT(x,y) outb(y,x) + + +#define MIXER_CD_Volume 0x28 + +/*==========================================================================*/ +/* + * use "REP INSB" for strobing the data in: + */ +#if PATCHLEVEL<15 +#define READ_DATA(port, buf, nr) \ +__asm__("cld;rep;insb": :"d" (port),"D" (buf),"c" (nr):"cx","dx","di") +#else +#define READ_DATA(port, buf, nr) insb(port, buf, nr) +#endif + +/*==========================================================================*/ +/* + * to fork and execute a function after some elapsed time: + * one "jifs" unit is 10 msec. + */ +#define SET_TIMER(func, jifs) \ + ((timer_table[SBPCD_TIMER].expires = jiffies + jifs), \ + (timer_table[SBPCD_TIMER].fn = func), \ + (timer_active |= 1< +#include + +/* + * User space process size: 3GB. This is hardcoded into a few places, + * so don't change it unless you know what you are doing. + */ +#define TASK_SIZE 0xc0000000 + +/* + * Size of io_bitmap in longwords: 32 is ports 0-0x3ff. + */ +#define IO_BITMAP_SIZE 32 + +/* + * These are the constant used to fake the fixed-point load-average + * counting. Some notes: + * - 11 bit fractions expand to 22 bits by the multiplies: this gives + * a load-average precision of 10 bits integer + 11 bits fractional + * - if you want to count load-averages more often, you need more + * precision, or rounding will get you. With 2-second counting freq, + * the EXP_n values would be 1981, 2034 and 2043 if still using only + * 11 bit fractions. + */ +extern unsigned long avenrun[]; /* Load averages */ + +#define FSHIFT 11 /* nr of bits of precision */ +#define FIXED_1 (1<>= FSHIFT; + +#define CT_TO_SECS(x) ((x) / HZ) +#define CT_TO_USECS(x) (((x) % HZ) * 1000000/HZ) + +#define FIRST_TASK task[0] +#define LAST_TASK task[NR_TASKS-1] + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define TASK_RUNNING 0 +#define TASK_INTERRUPTIBLE 1 +#define TASK_UNINTERRUPTIBLE 2 +#define TASK_ZOMBIE 3 +#define TASK_STOPPED 4 +#define TASK_SWAPPING 5 + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +#ifdef __KERNEL__ + +extern void sched_init(void); +extern void show_state(void); +extern void trap_init(void); + +asmlinkage void schedule(void); + +#endif /* __KERNEL__ */ + +struct i387_hard_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +struct i387_soft_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long top; + struct fpu_reg regs[8]; /* 8*16 bytes for each FP-reg = 128 bytes */ + unsigned char lookahead; + struct info *info; + unsigned long entry_eip; +}; + +union i387_union { + struct i387_hard_struct hard; + struct i387_soft_struct soft; +}; + +struct tss_struct { + unsigned short back_link,__blh; + unsigned long esp0; + unsigned short ss0,__ss0h; + unsigned long esp1; + unsigned short ss1,__ss1h; + unsigned long esp2; + unsigned short ss2,__ss2h; + unsigned long cr3; + unsigned long eip; + unsigned long eflags; + unsigned long eax,ecx,edx,ebx; + unsigned long esp; + unsigned long ebp; + unsigned long esi; + unsigned long edi; + unsigned short es, __esh; + unsigned short cs, __csh; + unsigned short ss, __ssh; + unsigned short ds, __dsh; + unsigned short fs, __fsh; + unsigned short gs, __gsh; + unsigned short ldt, __ldth; + unsigned short trace, bitmap; + unsigned long io_bitmap[IO_BITMAP_SIZE+1]; + unsigned long tr; + unsigned long cr2, trap_no, error_code; + union i387_union i387; +}; + +struct task_struct { +/* these are hardcoded - don't touch */ + long state; /* -1 unrunnable, 0 runnable, >0 stopped */ + long counter; + long priority; + unsigned long signal; + 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]; + unsigned long saved_kernel_stack; + unsigned long kernel_stack_page; + int exit_code, exit_signal; + int elf_executable:1; + int dumpable:1; + int swappable:1; + unsigned long start_code,end_code,end_data,start_brk,brk,start_stack,start_mmap; + unsigned long arg_start, arg_end, env_start, env_end; + int pid,pgrp,session,leader; + int groups[NGROUPS]; + /* + * pointers to (original) parent process, youngest child, younger sibling, + * older sibling, respectively. (p->father can be replaced with + * p->p_pptr->pid) + */ + struct task_struct *p_opptr,*p_pptr, *p_cptr, *p_ysptr, *p_osptr; + struct wait_queue *wait_chldexit; /* for wait4() */ + /* + * For ease of programming... Normal sleeps don't need to + * keep track of a wait-queue: every task has an entry of its own + */ + unsigned short uid,euid,suid; + unsigned short gid,egid,sgid; + unsigned long timeout; + unsigned long it_real_value, it_prof_value, it_virt_value; + unsigned long it_real_incr, it_prof_incr, it_virt_incr; + long utime,stime,cutime,cstime,start_time; + unsigned long min_flt, maj_flt; + unsigned long cmin_flt, cmaj_flt; + struct rlimit rlim[RLIM_NLIMITS]; + unsigned short used_math; + unsigned short rss; /* number of resident pages */ + char comm[16]; + struct vm86_struct * vm86_info; + unsigned long screen_bitmap; +/* file system info */ + int link_count; + int tty; /* -1 if no tty, so it must be signed */ + unsigned short umask; + struct inode * pwd; + struct inode * root; + struct inode * executable; + struct vm_area_struct * mmap; + struct shm_desc *shm; + struct sem_undo *semun; + struct file * filp[NR_OPEN]; + fd_set close_on_exec; +/* ldt for this task - used by Wine. If NULL, default_ldt is used */ + struct desc_struct *ldt; +/* tss for this task */ + struct tss_struct tss; +#ifdef NEW_SWAP + unsigned long old_maj_flt; /* old value of maj_flt */ + unsigned long dec_flt; /* page fault count of the last time */ + unsigned long swap_cnt; /* number of pages to swap on next pass */ + short swap_table; /* current page table */ + short swap_page; /* current page */ +#endif NEW_SWAP + struct vm_area_struct *stk_vma; +}; + +/* + * Per process flags + */ +#define PF_ALIGNWARN 0x00000001 /* Print alignment warning msgs */ + /* Not implemented yet, only for 486*/ +#define PF_PTRACED 0x00000010 /* set if ptrace (0) has been called. */ +#define PF_TRACESYS 0x00000020 /* tracing system calls */ + +/* + * cloning flags: + */ +#define CSIGNAL 0x000000ff /* signal mask to be sent at exit */ +#define COPYVM 0x00000100 /* set if VM copy desired (like normal fork()) */ +#define COPYFD 0x00000200 /* set if fd's should be copied, not shared (NI) */ + +/* + * INIT_TASK is used to set up the first task table, touch at + * your own risk!. Base=0, limit=0x1fffff (=2MB) + */ +#define INIT_TASK \ +/* state etc */ { 0,15,15,0,0,0,0, \ +/* debugregs */ { 0, }, \ +/* schedlink */ &init_task,&init_task, \ +/* signals */ {{ 0, },}, \ +/* stack */ 0,(unsigned long) &init_kernel_stack, \ +/* ec,brk... */ 0,0,0,0,0,0,0,0,0,0,0,0, \ +/* argv.. */ 0,0,0,0, \ +/* pid etc.. */ 0,0,0,0, \ +/* suppl grps*/ {NOGROUP,}, \ +/* proc links*/ &init_task,&init_task,NULL,NULL,NULL,NULL, \ +/* uid etc */ 0,0,0,0,0,0, \ +/* timeout */ 0,0,0,0,0,0,0,0,0,0,0,0, \ +/* min_flt */ 0,0,0,0, \ +/* rlimits */ { {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ + {LONG_MAX, LONG_MAX}, {LONG_MAX, LONG_MAX}, \ + { 0, LONG_MAX}, {LONG_MAX, LONG_MAX}}, \ +/* math */ 0, \ +/* rss */ 2, \ +/* comm */ "swapper", \ +/* vm86_info */ NULL, 0, \ +/* fs info */ 0,-1,0022,NULL,NULL,NULL,NULL, \ +/* ipc */ NULL, NULL, \ +/* filp */ {NULL,}, \ +/* cloe */ {{ 0, }}, \ +/* ldt */ NULL, \ +/*tss*/ {0,0, \ + sizeof(init_kernel_stack) + (long) &init_kernel_stack, KERNEL_DS, 0, \ + 0,0,0,0,0,0, \ + (long) &swapper_pg_dir, \ + 0,0,0,0,0,0,0,0,0,0, \ + USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0,USER_DS,0, \ + _LDT(0),0, \ + 0, 0x8000, \ +/* ioperm */ {~0, }, \ + _TSS(0), 0, 0,0, \ +/* 387 state */ { { 0, }, } \ + } \ +} + +extern struct task_struct init_task; +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 struct timeval xtime; +extern int need_resched; + +#define CURRENT_TIME (xtime.tv_sec) + +extern void sleep_on(struct wait_queue ** p); +extern void interruptible_sleep_on(struct wait_queue ** p); +extern void wake_up(struct wait_queue ** p); +extern void wake_up_interruptible(struct wait_queue ** p); + +extern void notify_parent(struct task_struct * tsk); +extern int send_sig(unsigned long sig,struct task_struct * p,int priv); +extern int in_group_p(gid_t grp); + +extern int request_irq(unsigned int irq,void (*handler)(int)); +extern void free_irq(unsigned int irq); +extern int irqaction(unsigned int irq,struct sigaction * sa); + +/* + * Entry into gdt where to find first TSS. GDT layout: + * 0 - nul + * 1 - kernel code segment + * 2 - kernel data segment + * 3 - user code segment + * 4 - user data segment + * ... + * 8 - TSS #0 + * 9 - LDT #0 + * 10 - TSS #1 + * 11 - LDT #1 + */ +#define FIRST_TSS_ENTRY 8 +#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1) +#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3)) +#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3)) +#define load_TR(n) __asm__("ltr %%ax": /* no output */ :"a" (_TSS(n))) +#define load_ldt(n) __asm__("lldt %%ax": /* no output */ :"a" (_LDT(n))) +#define store_TR(n) \ +__asm__("str %%ax\n\t" \ + "subl %2,%%eax\n\t" \ + "shrl $4,%%eax" \ + :"=a" (n) \ + :"0" (0),"i" (FIRST_TSS_ENTRY<<3)) +/* + * switch_to(n) should switch tasks to task nr n, first + * checking that n isn't the current task, in which case it does nothing. + * This also clears the TS-flag if the task we switched to has used + * tha math co-processor latest. + */ +#define switch_to(tsk) \ +__asm__("cmpl %%ecx,_current\n\t" \ + "je 1f\n\t" \ + "cli\n\t" \ + "xchgl %%ecx,_current\n\t" \ + "ljmp %0\n\t" \ + "sti\n\t" \ + "cmpl %%ecx,_last_task_used_math\n\t" \ + "jne 1f\n\t" \ + "clts\n" \ + "1:" \ + : /* no output */ \ + :"m" (*(((char *)&tsk->tss.tr)-4)), \ + "c" (tsk) \ + :"cx") + +#define _set_base(addr,base) \ +__asm__("movw %%dx,%0\n\t" \ + "rorl $16,%%edx\n\t" \ + "movb %%dl,%1\n\t" \ + "movb %%dh,%2" \ + : /* no output */ \ + :"m" (*((addr)+2)), \ + "m" (*((addr)+4)), \ + "m" (*((addr)+7)), \ + "d" (base) \ + :"dx") + +#define _set_limit(addr,limit) \ +__asm__("movw %%dx,%0\n\t" \ + "rorl $16,%%edx\n\t" \ + "movb %1,%%dh\n\t" \ + "andb $0xf0,%%dh\n\t" \ + "orb %%dh,%%dl\n\t" \ + "movb %%dl,%1" \ + : /* no output */ \ + :"m" (*(addr)), \ + "m" (*((addr)+6)), \ + "d" (limit) \ + :"dx") + +#define set_base(ldt,base) _set_base( ((char *)&(ldt)) , base ) +#define set_limit(ldt,limit) _set_limit( ((char *)&(ldt)) , (limit-1)>>12 ) + +/* + * The wait-queues are circular lists, and you have to be *very* sure + * to keep them correct. Use only these two functions to add/remove + * entries in the queues. + */ +extern inline void add_wait_queue(struct wait_queue ** p, struct wait_queue * wait) +{ + unsigned long flags; + +#ifdef DEBUG + if (wait->next) { + unsigned long pc; + __asm__ __volatile__("call 1f\n" + "1:\tpopl %0":"=r" (pc)); + printk("add_wait_queue (%08x): wait->next = %08x\n",pc,(unsigned long) wait->next); + } +#endif + save_flags(flags); + cli(); + if (!*p) { + wait->next = wait; + *p = wait; + } else { + wait->next = (*p)->next; + (*p)->next = wait; + } + restore_flags(flags); +} + +extern inline void remove_wait_queue(struct wait_queue ** p, struct wait_queue * wait) +{ + unsigned long flags; + struct wait_queue * tmp; +#ifdef DEBUG + unsigned long ok = 0; +#endif + + save_flags(flags); + cli(); + if ((*p == wait) && +#ifdef DEBUG + (ok = 1) && +#endif + ((*p = wait->next) == wait)) { + *p = NULL; + } else { + tmp = wait; + while (tmp->next != wait) { + tmp = tmp->next; +#ifdef DEBUG + if (tmp == *p) + ok = 1; +#endif + } + tmp->next = wait->next; + } + wait->next = NULL; + restore_flags(flags); +#ifdef DEBUG + if (!ok) { + printk("removed wait_queue not on list.\n"); + 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); + } +#endif +} + +extern inline void select_wait(struct wait_queue ** wait_address, select_table * p) +{ + struct select_table_entry * entry; + + if (!p || !wait_address) + return; + if (p->nr >= __MAX_SELECT_TABLE_ENTRIES) + return; + entry = p->entry + p->nr; + entry->wait_address = wait_address; + entry->wait.task = current; + entry->wait.next = NULL; + add_wait_queue(wait_address,&entry->wait); + p->nr++; +} + +static inline unsigned long _get_base(char * addr) +{ + unsigned long __base; + __asm__("movb %3,%%dh\n\t" + "movb %2,%%dl\n\t" + "shll $16,%%edx\n\t" + "movw %1,%%dx" + :"=&d" (__base) + :"m" (*((addr)+2)), + "m" (*((addr)+4)), + "m" (*((addr)+7))); + return __base; +} + +#define get_base(ldt) _get_base( ((char *)&(ldt)) ) + +static inline unsigned long get_limit(unsigned long segment) +{ + unsigned long __limit; + __asm__("lsll %1,%0" + :"=r" (__limit):"r" (segment)); + return __limit+1; +} + +#define REMOVE_LINKS(p) do { unsigned long flags; \ + save_flags(flags) ; cli(); \ + (p)->next_task->prev_task = (p)->prev_task; \ + (p)->prev_task->next_task = (p)->next_task; \ + restore_flags(flags); \ + if ((p)->p_osptr) \ + (p)->p_osptr->p_ysptr = (p)->p_ysptr; \ + if ((p)->p_ysptr) \ + (p)->p_ysptr->p_osptr = (p)->p_osptr; \ + else \ + (p)->p_pptr->p_cptr = (p)->p_osptr; \ + } while (0) + +#define SET_LINKS(p) do { unsigned long flags; \ + save_flags(flags); cli(); \ + (p)->next_task = &init_task; \ + (p)->prev_task = init_task.prev_task; \ + init_task.prev_task->next_task = (p); \ + init_task.prev_task = (p); \ + restore_flags(flags); \ + (p)->p_ysptr = NULL; \ + if (((p)->p_osptr = (p)->p_pptr->p_cptr) != NULL) \ + (p)->p_osptr->p_ysptr = p; \ + (p)->p_pptr->p_cptr = p; \ + } while (0) + +#define for_each_task(p) \ + for (p = &init_task ; (p = p->next_task) != &init_task ; ) + +/* + * This is the ldt that every process will get unless we need + * something other than this. + */ +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/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/segment.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/segment.h new file mode 100644 index 000000000..aa2a98ace --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/segment.h @@ -0,0 +1,10 @@ +#ifndef _LINUX_SEGMENT_H +#define _LINUX_SEGMENT_H + +#define KERNEL_CS 0x10 +#define KERNEL_DS 0x18 + +#define USER_CS 0x23 +#define USER_DS 0x2B + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sem.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sem.h new file mode 100644 index 000000000..02d535ff9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sem.h @@ -0,0 +1,96 @@ +#ifndef _LINUX_SEM_H +#define _LINUX_SEM_H +#include + +/* semop flags */ +#define SEM_UNDO 010000 /* undo the operation on exit */ + +/* semctl Command Definitions. */ +#define GETPID 11 /* get sempid */ +#define GETVAL 12 /* get semval */ +#define GETALL 13 /* get all semval's */ +#define GETNCNT 14 /* get semncnt */ +#define GETZCNT 15 /* get semzcnt */ +#define SETVAL 16 /* set semval */ +#define SETALL 17 /* set all semval's */ + +/* One semid data structure for each set of semaphores in the system. */ +struct semid_ds { + struct ipc_perm sem_perm; /* permissions .. see ipc.h */ + time_t sem_otime; /* last semop time */ + time_t sem_ctime; /* last change time */ + struct sem *sem_base; /* ptr to first semaphore in array */ + struct wait_queue *eventn; + struct wait_queue *eventz; + struct sem_undo *undo; /* undo requests on this array */ + ushort sem_nsems; /* no. of semaphores in array */ +}; + + +/* One semaphore structure for each semaphore in the system. */ +struct sem { + short sempid; /* pid of last operation */ + ushort semval; /* current value */ + ushort semncnt; /* num procs awaiting increase in semval */ + ushort semzcnt; /* num procs awaiting semval = 0 */ +}; + +/* semop system calls takes an array of these.*/ +struct sembuf { + ushort sem_num; /* semaphore index in array */ + short sem_op; /* semaphore operation */ + short sem_flg; /* operation flags */ +}; + +/* arg for semctl system calls. */ +union semun { + int val; /* value for SETVAL */ + struct semid_ds *buf; /* buffer for IPC_STAT & IPC_SET */ + ushort *array; /* array for GETALL & SETALL */ +}; + + +struct seminfo { + int semmap; + int semmni; + int semmns; + int semmnu; + int semmsl; + int semopm; + int semume; + int semusz; + int semvmx; + int semaem; +}; + +#define SEMMNI 128 /* ? max # of semaphore identifiers */ +#define SEMMSL 32 /* <= 512 max num of semaphores per id */ +#define SEMMNS (SEMMNI*SEMMSL) /* ? max # of semaphores in system */ +#define SEMOPM 32 /* ~ 100 max num of ops per semop call */ +#define SEMVMX 32767 /* semaphore maximum value */ + +/* unused */ +#define SEMUME SEMOPM /* max num of undo entries per process */ +#define SEMMNU SEMMNS /* num of undo structures system wide */ +#define SEMAEM (SEMVMX >> 1) /* adjust on exit max value */ +#define SEMMAP SEMMNS /* # of entries in semaphore map */ +#define SEMUSZ 20 /* sizeof struct sem_undo */ + +#ifdef __KERNEL__ +/* ipcs ctl cmds */ +#define SEM_STAT 18 +#define SEM_INFO 19 + +/* per process undo requests */ +/* this gets linked into the task_struct */ +struct sem_undo { + struct sem_undo *proc_next; + struct sem_undo *id_next; + int semid; + short semadj; /* semval adjusted by exit */ + ushort sem_num; /* semaphore index in array semid */ +}; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SEM_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/serial.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/serial.h new file mode 100644 index 000000000..6250c0da2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/serial.h @@ -0,0 +1,161 @@ +/* + * include/linux/serial.h + * + * Copyright (C) 1992 by Theodore Ts'o. + * + * Redistribution of this file is permitted under the terms of the GNU + * Public License (GPL) + */ + +/* + * This is our internal structure for each serial port's state. + * + * Many fields are paralleled by the structure used by the serial_struct + * structure. + * + * For definitions of the flags field, see tty.h + */ +#ifndef _LINUX_SERIAL_H +#define _LINUX_SERIAL_H + +struct async_struct { + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int hub6; /* HUB6 plus one */ + int type; /* UART type */ + struct tty_struct *tty; + int read_status_mask; + int timeout; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff characater */ + int close_delay; + int IER; /* Interrupt Enable Register */ + int event; + int line; + int count; /* # of fd on device */ + int blocked_open; /* # of blocked opens */ + long session; /* Session of opening process */ + long pgrp; /* pgrp of opening process */ + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; + struct wait_queue *xmit_wait; + struct async_struct *next_port; /* For the linked list */ + struct async_struct *prev_port; +}; + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_READ_PROCESS 0 +#define RS_EVENT_WRITE_WAKEUP 1 +#define RS_EVENT_HANGUP 2 +#define RS_EVENT_BREAK 3 +#define RS_EVENT_OPEN_WAKEUP 4 + +/* + * These are the UART port assignments, expressed as offsets from the base + * register. These assignments should hold for any serial port based on + * a 8250, 16450, or 16550(A). + */ +#define UART_RX 0 /* In: Receive buffer (DLAB=0) */ +#define UART_TX 0 /* Out: Transmit buffer (DLAB=0) */ +#define UART_DLL 0 /* Out: Devisor Latch Low (DLAB=1) */ +#define UART_DLM 1 /* Out: Devisor Latch High (DLAB=1) */ +#define UART_IER 1 /* Out: Interrupt Enable Register */ +#define UART_IIR 2 /* In: Interrupt ID Register */ +#define UART_FCR 2 /* Out: FIFO Control Register */ +#define UART_LCR 3 /* Out: Line Control Register */ +#define UART_MCR 4 /* Out: Modem Control Register */ +#define UART_LSR 5 /* In: Line Status Register */ +#define UART_MSR 6 /* In: Modem Status Register */ +#define UART_SCR 7 /* I/O: Scratch Register */ + +/* + * These are the definitions for the FIFO Control Register + */ +#define UART_FCR_ENABLE_FIFO 0x01 /* Enable the FIFO */ +#define UART_FCR_CLEAR_RCVR 0x02 /* Clear the RCVR FIFO */ +#define UART_FCR_CLEAR_XMIT 0x04 /* Clear the XMIT FIFO */ +#define UART_FCR_DMA_SELECT 0x08 /* For DMA applications */ +#define UART_FCR_TRIGGER_MASK 0xC0 /* Mask for the FIFO trigger range */ +#define UART_FCR_TRIGGER_1 0x00 /* Mask for trigger set at 1 */ +#define UART_FCR_TRIGGER_4 0x40 /* Mask for trigger set at 4 */ +#define UART_FCR_TRIGGER_8 0x80 /* Mask for trigger set at 8 */ +#define UART_FCR_TRIGGER_14 0xC0 /* Mask for trigger set at 14 */ + +/* + * These are the definitions for the Line Control Register + * + * Note: if the word length is 5 bits (UART_LCR_WLEN5), then setting + * UART_LCR_STOP will select 1.5 stop bits, not 2 stop bits. + */ +#define UART_LCR_DLAB 0x80 /* Devisor latch access bit */ +#define UART_LCR_SBC 0x40 /* Set break control */ +#define UART_LCR_SPAR 0x20 /* Stick parity (?) */ +#define UART_LCR_EPAR 0x10 /* Even paraity select */ +#define UART_LCR_PARITY 0x08 /* Parity Enable */ +#define UART_LCR_STOP 0x04 /* Stop bits: 0=1 stop bit, 1= 2 stop bits */ +#define UART_LCR_WLEN5 0x00 /* Wordlength: 5 bits */ +#define UART_LCR_WLEN6 0x01 /* Wordlength: 6 bits */ +#define UART_LCR_WLEN7 0x02 /* Wordlength: 7 bits */ +#define UART_LCR_WLEN8 0x03 /* Wordlength: 8 bits */ + +/* + * These are the definitions for the Line Status Register + */ +#define UART_LSR_TEMT 0x40 /* Transmitter empty */ +#define UART_LSR_THRE 0x20 /* Transmit-hold-register empty */ +#define UART_LSR_BI 0x10 /* Break interrupt indicator */ +#define UART_LSR_FE 0x08 /* Frame error indicator */ +#define UART_LSR_PE 0x04 /* Parity error indicator */ +#define UART_LSR_OE 0x02 /* Overrun error indicator */ +#define UART_LSR_DR 0x01 /* Receiver data ready */ + +/* + * These are the definitions for the Interrupt Indentification Register + */ +#define UART_IIR_NO_INT 0x01 /* No interrupts pending */ +#define UART_IIR_ID 0x06 /* Mask for the interrupt ID */ + +#define UART_IIR_MSI 0x00 /* Modem status interrupt */ +#define UART_IIR_THRI 0x02 /* Transmitter holding register empty */ +#define UART_IIR_RDI 0x04 /* Receiver data interrupt */ +#define UART_IIR_RLSI 0x06 /* Receiver line status interrupt */ + +/* + * These are the definitions for the Interrupt Enable Register + */ +#define UART_IER_MSI 0x08 /* Enable Modem status interrupt */ +#define UART_IER_RLSI 0x04 /* Enable receiver line status interrupt */ +#define UART_IER_THRI 0x02 /* Enable Transmitter holding register int. */ +#define UART_IER_RDI 0x01 /* Enable receiver data interrupt */ + +/* + * These are the definitions for the Modem Control Register + */ +#define UART_MCR_LOOP 0x10 /* Enable loopback test mode */ +#define UART_MCR_OUT2 0x08 /* Out2 complement */ +#define UART_MCR_OUT1 0x04 /* Out1 complement */ +#define UART_MCR_RTS 0x02 /* RTS complement */ +#define UART_MCR_DTR 0x01 /* DTR complement */ + +/* + * These are the definitions for the Modem Status Register + */ +#define UART_MSR_DCD 0x80 /* Data Carrier Detect */ +#define UART_MSR_RI 0x40 /* Ring Indicator */ +#define UART_MSR_DSR 0x20 /* Data Set Ready */ +#define UART_MSR_CTS 0x10 /* Clear to Send */ +#define UART_MSR_DDCD 0x08 /* Delta DCD */ +#define UART_MSR_TERI 0x04 /* Trailing edge ring indicator */ +#define UART_MSR_DDSR 0x02 /* Delta DSR */ +#define UART_MSR_DCTS 0x01 /* Delta CTS */ +#define UART_MSR_ANY_DELTA 0x0F /* Any of the delta bits! */ + +#endif /* _LINUX_SERIAL_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/shm.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/shm.h new file mode 100644 index 000000000..4328318fa --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/shm.h @@ -0,0 +1,109 @@ +#ifndef _LINUX_SHM_H_ +#define _LINUX_SHM_H_ +#include + +struct shmid_ds { + struct ipc_perm shm_perm; /* operation perms */ + int shm_segsz; /* size of segment (bytes) */ + time_t shm_atime; /* last attach time */ + time_t shm_dtime; /* last detach time */ + time_t shm_ctime; /* last change time */ + unsigned short shm_cpid; /* pid of creator */ + unsigned short shm_lpid; /* pid of last operator */ + short shm_nattch; /* no. of current attaches */ + /* the following are private */ + unsigned short shm_npages; /* size of segment (pages) */ + unsigned long *shm_pages; /* array of ptrs to frames -> SHMMAX */ + struct shm_desc *attaches; /* descriptors for attaches */ +}; + +/* mode for attach */ +#define SHM_RDONLY 010000 /* read-only access */ +#define SHM_RND 020000 /* round attach address to SHMLBA boundary */ +#define SHM_REMAP 040000 /* take-over region on attach */ + +/* super user shmctl commands */ +#define SHM_LOCK 11 +#define SHM_UNLOCK 12 + +struct shminfo { + int shmmax; + int shmmin; + int shmmni; + int shmseg; + int shmall; +}; + +#define SHM_RANGE_START 0x40000000 +#define SHM_RANGE_END 0x60000000 + + /* _SHM_ID_BITS is a variable you can adjust to */ + /* tune the kernel. It determines the value of */ + /* SHMMNI, which specifies the maximum no. of */ + /* shared segments (system wide). SRB. */ +#define _SHM_ID_BITS 7 /* keep as low as possible */ + /* a static array is declared */ + /* using SHMMNI */ + +#define __SHM_IDX_BITS (BITS_PER_PTR-2-SHM_IDX_SHIFT) + +/* !!!!!!!????? + * Why reserve the two (2) high bits of the signature (shm_sgn) field? + * Since, as far as I can see, only the high bit is used (SHM_READ_ONLY). + * SRB. + */ + +#define _SHM_IDX_BITS (__SHM_IDX_BITS+PAGE_SHIFT>=BITS_PER_PTR?\ + BITS_PER_PTR-PAGE_SHIFT-1:__SHM_IDX_BITS) /* sanity check */ + +/* not present page table entry format bit 0 is 0, low byte defined in mm.h */ +#define SHM_ID_SHIFT 8 +#define SHM_ID_MASK ((1<<_SHM_ID_BITS)-1) +#define SHM_IDX_SHIFT (SHM_ID_SHIFT+_SHM_ID_BITS) +#define SHM_IDX_MASK ((1<<_SHM_IDX_BITS)-1) +#define SHM_READ_ONLY (1<<(BITS_PER_PTR-1)) + +#define SHMMAX 0x3fa000 /* max shared seg size (bytes) */ +#define SHMMIN 1 /* really PAGE_SIZE */ /* min shared seg size (bytes) */ +#define SHMMNI (1<<_SHM_ID_BITS) /* max num of segs system wide */ +#define SHMALL (1<<(_SHM_IDX_BITS+_SHM_ID_BITS))/* max shm system wide (pages) */ +#define SHMLBA 0x1000 /* attach addr a multiple of this */ +#define SHMSEG SHMMNI /* max shared segs per process */ + +#ifdef __KERNEL__ + +/* shm_mode upper byte flags */ +#define SHM_DEST 01000 /* segment will be destroyed on last detach */ +#define SHM_LOCKED 02000 /* segment will not be swapped */ + +/* ipcs ctl commands */ +#define SHM_STAT 13 +#define SHM_INFO 14 +struct shm_info { + int used_ids; + ulong shm_tot; /* total allocated shm */ + ulong shm_rss; /* total resident shm */ + ulong shm_swp; /* total swapped shm */ + ulong swap_attempts; + ulong swap_successes; +}; + + +/* + * Per process internal structure for managing segments. + * A shmat will add to and shmdt will remove from the list. + */ +struct shm_desc { + struct task_struct *task; /* attacher */ + unsigned long shm_sgn; /* signature for this attach */ + unsigned long start; /* virt addr of attach, multiple of SHMLBA */ + unsigned long end; /* multiple of SHMLBA */ + struct shm_desc *task_next; /* next attach for task */ + struct shm_desc *seg_next; /* next attach for segment */ +}; + +#endif /* __KERNEL__ */ + +#endif /* _LINUX_SHM_H_ */ + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/signal.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/signal.h new file mode 100644 index 000000000..21ad9e7aa --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/signal.h @@ -0,0 +1,92 @@ +#ifndef _LINUX_SIGNAL_H +#define _LINUX_SIGNAL_H + +typedef unsigned int sigset_t; /* 32 bits */ + +#define _NSIG 32 +#define NSIG _NSIG + +#define SIGHUP 1 +#define SIGINT 2 +#define SIGQUIT 3 +#define SIGILL 4 +#define SIGTRAP 5 +#define SIGABRT 6 +#define SIGIOT 6 +#define SIGUNUSED 7 +#define SIGFPE 8 +#define SIGKILL 9 +#define SIGUSR1 10 +#define SIGSEGV 11 +#define SIGUSR2 12 +#define SIGPIPE 13 +#define SIGALRM 14 +#define SIGTERM 15 +#define SIGSTKFLT 16 +#define SIGCHLD 17 +#define SIGCONT 18 +#define SIGSTOP 19 +#define SIGTSTP 20 +#define SIGTTIN 21 +#define SIGTTOU 22 + +/* + * Most of these aren't used yet (and perhaps never will), + * so they are commented out. + */ + + +#define SIGIO 23 +#define SIGPOLL SIGIO +#define SIGURG SIGIO +#define SIGXCPU 24 +#define SIGXFSZ 25 + + +#define SIGVTALRM 26 +#define SIGPROF 27 + +#define SIGWINCH 28 + +/* +#define SIGLOST 29 +*/ +#define SIGPWR 30 + +/* Arggh. Bad user source code wants this.. */ +#define SIGBUS SIGUNUSED + +/* + * sa_flags values: SA_STACK is not currently supported, but will allow the + * usage of signal stacks by using the (now obsolete) sa_restorer field in + * the sigaction structure as a stack pointer. This is now possible due to + * the changes in signal handling. LBT 010493. + * SA_INTERRUPT is a no-op, but left due to historical reasons. Use the + * SA_RESTART flag to get restarting signals (which were the default long ago) + */ +#define SA_NOCLDSTOP 1 +#define SA_STACK 0x08000000 +#define SA_RESTART 0x10000000 +#define SA_INTERRUPT 0x20000000 +#define SA_NOMASK 0x40000000 +#define SA_ONESHOT 0x80000000 + +#define SIG_BLOCK 0 /* for blocking signals */ +#define SIG_UNBLOCK 1 /* for unblocking signals */ +#define SIG_SETMASK 2 /* for setting the signal mask */ + +/* Type of a signal handler. */ +typedef void (*__sighandler_t)(int); + +#define SIG_DFL ((__sighandler_t)0) /* default signal handling */ +#define SIG_IGN ((__sighandler_t)1) /* ignore signal */ +#define SIG_ERR ((__sighandler_t)-1) /* error return from signal */ + +struct sigaction { + __sighandler_t sa_handler; + sigset_t sa_mask; + int sa_flags; + void (*sa_restorer)(void); +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/socket.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/socket.h new file mode 100644 index 000000000..3826b0254 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/socket.h @@ -0,0 +1,91 @@ +#ifndef _LINUX_SOCKET_H +#define _LINUX_SOCKET_H + +#include /* the SIOCxxx I/O controls */ + + +struct sockaddr { + unsigned short sa_family; /* address family, AF_xxx */ + char sa_data[14]; /* 14 bytes of protocol address */ +}; + +struct linger { + int l_onoff; /* Linger active */ + int l_linger; /* How long to linger for */ +}; + +/* Socket types. */ +#define SOCK_STREAM 1 /* stream (connection) socket */ +#define SOCK_DGRAM 2 /* datagram (conn.less) socket */ +#define SOCK_RAW 3 /* raw socket */ +#define SOCK_RDM 4 /* reliably-delivered message */ +#define SOCK_SEQPACKET 5 /* sequential packet socket */ +#define SOCK_PACKET 10 /* linux specific way of */ + /* getting packets at the dev */ + /* level. For writing rarp and */ + /* other similiar things on the */ + /* user level. */ + +/* Supported address families. */ +#define AF_UNSPEC 0 +#define AF_UNIX 1 +#define AF_INET 2 +#define AF_AX25 3 +#define AF_IPX 4 + +/* Protocol families, same as address families. */ +#define PF_UNIX AF_UNIX +#define PF_INET AF_INET +#define PF_AX25 AF_AX25 +#define PF_IPX AF_IPX + +/* Flags we can use with send/ and recv. */ +#define MSG_OOB 1 +#define MSG_PEEK 2 + +/* Setsockoptions(2) level. Thanks to BSD these must match IPPROTO_xxx */ +#define SOL_SOCKET 1 +#define SOL_IP 0 +#define SOL_IPX 256 +#define SOL_AX25 257 +#define SOL_TCP 6 +#define SOL_UDP 17 + +/* For setsockoptions(2) */ +#define SO_DEBUG 1 +#define SO_REUSEADDR 2 +#define SO_TYPE 3 +#define SO_ERROR 4 +#define SO_DONTROUTE 5 +#define SO_BROADCAST 6 +#define SO_SNDBUF 7 +#define SO_RCVBUF 8 +#define SO_KEEPALIVE 9 +#define SO_OOBINLINE 10 +#define SO_NO_CHECK 11 +#define SO_PRIORITY 12 +#define SO_LINGER 13 + +/* IP options */ +#define IP_TOS 1 +#define IPTOS_LOWDELAY 0x10 +#define IPTOS_THROUGHPUT 0x08 +#define IPTOS_RELIABILITY 0x04 +#define IP_TTL 2 + +/* IPX options */ +#define IPX_TYPE 1 + +/* AX.25 options */ +#define AX25_WINDOW 1 + +/* TCP options - this way around because someone left a set in the c library includes */ +#define TCP_NODELAY 1 +#define TCP_MAXSEG 2 + +/* The various priorities. */ +#define SOPRI_INTERACTIVE 0 +#define SOPRI_NORMAL 1 +#define SOPRI_BACKGROUND 2 + +#endif /* _LINUX_SOCKET_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sockios.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sockios.h new file mode 100644 index 000000000..2090c33c9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sockios.h @@ -0,0 +1,76 @@ +/* + * 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 of the socket-level I/O control calls. + * + * Version: @(#)sockios.h 1.0.2 03/09/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_SOCKIOS_H +#define _LINUX_SOCKIOS_H + +/* This section will go away soon! */ +#if 1 /* FIXME: */ +#define MAX_IP_NAME 20 +#define IP_SET_DEV 0x2401 + +struct ip_config { + char name[MAX_IP_NAME]; + unsigned long paddr; + unsigned long router; + unsigned long net; + unsigned long up:1,destroy:1; +}; +#endif /* FIXME: */ + +/* Socket-level I/O control calls. */ +#define FIOSETOWN 0x8901 +#define SIOCSPGRP 0x8902 +#define FIOGETOWN 0x8903 +#define SIOCGPGRP 0x8904 +#define SIOCATMARK 0x8905 + +/* Socket configuration controls. */ +#define SIOCGIFNAME 0x8910 /* get iface name */ +#define SIOCSIFLINK 0x8911 /* set iface channel */ +#define SIOCGIFCONF 0x8912 /* get iface list */ +#define SIOCGIFFLAGS 0x8913 /* get flags */ +#define SIOCSIFFLAGS 0x8914 /* set flags */ +#define SIOCGIFADDR 0x8915 /* get PA address */ +#define SIOCSIFADDR 0x8916 /* set PA address */ +#define SIOCGIFDSTADDR 0x8917 /* get remote PA address */ +#define SIOCSIFDSTADDR 0x8918 /* set remote PA address */ +#define SIOCGIFBRDADDR 0x8919 /* get broadcast PA address */ +#define SIOCSIFBRDADDR 0x891a /* set broadcast PA address */ +#define SIOCGIFNETMASK 0x891b /* get network PA mask */ +#define SIOCSIFNETMASK 0x891c /* set network PA mask */ +#define SIOCGIFMETRIC 0x891d /* get metric */ +#define SIOCSIFMETRIC 0x891e /* set metric */ +#define SIOCGIFMEM 0x891f /* get memory address (BSD) */ +#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) */ +#define SIOCGIFENCAP 0x8925 /* get/set slip encapsulation */ +#define SIOCSIFENCAP 0x8926 + +/* Routing table calls. */ +#define SIOCADDRT 0x8940 /* add routing table entry */ +#define SIOCDELRT 0x8941 /* delete routing table entry */ + +/* ARP cache control calls. */ +#define SIOCDARP 0x8950 /* delete ARP table entry */ +#define SIOCGARP 0x8951 /* get ARP table entry */ +#define SIOCSARP 0x8952 /* set ARP table entry */ + +#endif /* _LINUX_SOCKIOS_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/soundcard.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/soundcard.h new file mode 100644 index 000000000..0603dd3b6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/soundcard.h @@ -0,0 +1,743 @@ +#ifndef SOUNDCARD_H +#define SOUNDCARD_H +/* + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * + */ + + /* + * If you make modifications to this file, please contact me before + * distributing the modified version. There is already enough + * divercity in the world. + * + * Regards, + * Hannu Savolainen + * hsavolai@cs.helsinki.fi + */ + +#define SOUND_VERSION 203 +#define VOXWARE + +#include + +/* + * Supported card ID numbers (Should be somewhere else?) + */ + +#define SNDCARD_ADLIB 1 +#define SNDCARD_SB 2 +#define SNDCARD_PAS 3 +#define SNDCARD_GUS 4 +#define SNDCARD_MPU401 5 +#define SNDCARD_SB16 6 +#define SNDCARD_SB16MIDI 7 + +/*********************************** + * IOCTL Commands for /dev/sequencer + */ + +#ifndef _IOWR +/* @(#)ioctlp.h */ + +/* Ioctl's have the command encoded in the lower word, + * and the size of any in or out parameters in the upper + * word. The high 2 bits of the upper word are used + * to encode the in/out status of the parameter; for now + * we restrict parameters to at most 128 bytes. + */ +/* #define IOCTYPE (0xff<<8) */ +#define IOCPARM_MASK 0x7f /* parameters must be < 128 bytes */ +#define IOC_VOID 0x00000000 /* no parameters */ +#define IOC_OUT 0x20000000 /* copy out parameters */ +#define IOC_IN 0x40000000 /* copy in parameters */ +#define IOC_INOUT (IOC_IN|IOC_OUT) +/* the 0x20000000 is so we can distinguish new ioctl's from old */ +#define _IO(x,y) ((int)(IOC_VOID|(x<<8)|y)) +#define _IOR(x,y,t) ((int)(IOC_OUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)) +#define _IOW(x,y,t) ((int)(IOC_IN|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)) +/* this should be _IORW, but stdio got there first */ +#define _IOWR(x,y,t) ((int)(IOC_INOUT|((sizeof(t)&IOCPARM_MASK)<<16)|(x<<8)|y)) +#endif /* !_IOWR */ + +#define SNDCTL_SEQ_RESET _IO ('Q', 0) +#define SNDCTL_SEQ_SYNC _IO ('Q', 1) +#define SNDCTL_SYNTH_INFO _IOWR('Q', 2, struct synth_info) +#define SNDCTL_SEQ_CTRLRATE _IOWR('Q', 3, int) /* Set/get timer resolution (HZ) */ +#define SNDCTL_SEQ_GETOUTCOUNT _IOR ('Q', 4, int) +#define SNDCTL_SEQ_GETINCOUNT _IOR ('Q', 5, int) +#define SNDCTL_SEQ_PERCMODE _IOW ('Q', 6, int) +#define SNDCTL_FM_LOAD_INSTR _IOW ('Q', 7, struct sbi_instrument) /* Valid for FM only */ +#define SNDCTL_SEQ_TESTMIDI _IOW ('Q', 8, int) +#define SNDCTL_SEQ_RESETSAMPLES _IOW ('Q', 9, int) +#define SNDCTL_SEQ_NRSYNTHS _IOR ('Q',10, int) +#define SNDCTL_SEQ_NRMIDIS _IOR ('Q',11, int) +#define SNDCTL_MIDI_INFO _IOWR('Q',12, struct midi_info) +#define SNDCTL_SEQ_TRESHOLD _IOW ('Q',13, int) +#define SNDCTL_SYNTH_MEMAVL _IOWR('Q',14, int) /* in=dev#, out=memsize */ +#define SNDCTL_FM_4OP_ENABLE _IOW ('Q',15, int) /* in=dev# */ +#define SNDCTL_PMGR_ACCESS _IOWR('Q',16, struct patmgr_info) + +/* + * Sample loading mechanism for internal synthesizers (/dev/sequencer) + * The following patch_info structure has been designed to support + * Gravis UltraSound. It tries to be universal format for uploading + * sample based patches but is propably too limited. + */ + +struct patch_info { + short key; /* Use GUS_PATCH here */ +#define GUS_PATCH 0x04fd +#define OBSOLETE_GUS_PATCH 0x02fd + short device_no; /* Synthesizer number */ + short instr_no; /* Midi pgm# */ + + unsigned long mode; +/* + * The least significant byte has the same format than the GUS .PAT + * files + */ +#define WAVE_16_BITS 0x01 /* bit 0 = 8 or 16 bit wave data. */ +#define WAVE_UNSIGNED 0x02 /* bit 1 = Signed - Unsigned data. */ +#define WAVE_LOOPING 0x04 /* bit 2 = looping enabled-1. */ +#define WAVE_BIDIR_LOOP 0x08 /* bit 3 = Set is bidirectional looping. */ +#define WAVE_LOOP_BACK 0x10 /* bit 4 = Set is looping backward. */ +#define WAVE_SUSTAIN_ON 0x20 /* bit 5 = Turn sustaining on. (Env. pts. 3)*/ +#define WAVE_ENVELOPES 0x40 /* bit 6 = Enable envelopes - 1 */ + /* (use the env_rate/env_offs fields). */ +/* Linux specific bits */ +#define WAVE_VIBRATO 0x00010000 /* The vibrato info is valid */ +#define WAVE_TREMOLO 0x00020000 /* The tremolo info is valid */ +#define WAVE_SCALE 0x00040000 /* The scaling info is valid */ +/* Other bits must be zeroed */ + + long len; /* Size of the wave data in bytes */ + long loop_start, loop_end; /* Byte offsets from the beginning */ + +/* + * The base_freq and base_note fields are used when computing the + * playback speed for a note. The base_note defines the tone frequency + * which is heard if the sample is played using the base_freq as the + * playback speed. + * + * The low_note and high_note fields define the minimum and maximum note + * frequencies for which this sample is valid. It is possible to define + * more than one samples for a instrument number at the same time. The + * low_note and high_note fields are used to select the most suitable one. + * + * The fields base_note, high_note and low_note should contain + * the note frequency multiplied by 1000. For example value for the + * middle A is 440*1000. + */ + + unsigned int base_freq; + unsigned long base_note; + unsigned long high_note; + unsigned long low_note; + int panning; /* -128=left, 127=right */ + int detuning; + +/* New fields introduced in version 1.99.5 */ + + /* Envelope. Enabled by mode bit WAVE_ENVELOPES */ + unsigned char env_rate[ 6 ]; /* GUS HW ramping rate */ + unsigned char env_offset[ 6 ]; /* 255 == 100% */ + + /* + * The tremolo, vibrato and scale info are not supported yet. + * Enable by setting the mode bits WAVE_TREMOLO, WAVE_VIBRATO or + * WAVE_SCALE + */ + + unsigned char tremolo_sweep; + unsigned char tremolo_rate; + unsigned char tremolo_depth; + + unsigned char vibrato_sweep; + unsigned char vibrato_rate; + unsigned char vibrato_depth; + + int scale_frequency; + unsigned int scale_factor; /* from 0 to 2048 or 0 to 2 */ + + int volume; + int spare[4]; + char data[1]; /* The waveform data starts here */ + }; + + +/* + * Patch management interface (/dev/sequencer, /dev/patmgr#) + * Don't use these calls if you want to maintain compatibility with + * the future versions of the driver. + */ + +#define PS_NO_PATCHES 0 /* No patch support on device */ +#define PS_MGR_NOT_OK 1 /* Plain patch support (no mgr) */ +#define PS_MGR_OK 2 /* Patch manager supported */ +#define PS_MANAGED 3 /* Patch manager running */ + +#define SNDCTL_PMGR_IFACE _IOWR('P', 1, struct patmgr_info) + +/* + * The patmgr_info is a fixed size structure which is used for two + * different purposes. The intended use is for communication between + * the application using /dev/sequencer and the patch manager daemon + * associated with a synthesizer device (ioctl(SNDCTL_PMGR_ACCESS)). + * + * This structure is also used with ioctl(SNDCTL_PGMR_IFACE) which allows + * a patch manager daemon to read and write device parameters. This + * ioctl available through /dev/sequencer also. Avoid using it since it's + * extremely hardware dependent. In addition access trough /dev/sequencer + * may confuse the patch manager daemon. + */ + +struct patmgr_info { /* Note! size must be < 4k since kmalloc() is used */ + unsigned long key; /* Don't worry. Reserved for communication + between the patch manager and the driver. */ +#define PM_K_EVENT 1 /* Event from the /dev/sequencer driver */ +#define PM_K_COMMAND 2 /* Request from a application */ +#define PM_K_RESPONSE 3 /* From patmgr to application */ +#define PM_ERROR 4 /* Error returned by the patmgr */ + int device; + int command; + +/* + * Commands 0x000 to 0xfff reserved for patch manager programs + */ +#define PM_GET_DEVTYPE 1 /* Returns type of the patch mgr interface of dev */ +#define PMTYPE_FM2 1 /* 2 OP fm */ +#define PMTYPE_FM4 2 /* Mixed 4 or 2 op FM (OPL-3) */ +#define PMTYPE_WAVE 3 /* Wave table synthesizer (GUS) */ +#define PM_GET_NRPGM 2 /* Returns max # of midi programs in parm1 */ +#define PM_GET_PGMMAP 3 /* Returns map of loaded midi programs in data8 */ +#define PM_GET_PGM_PATCHES 4 /* Return list of patches of a program (parm1) */ +#define PM_GET_PATCH 5 /* Return patch header of patch parm1 */ +#define PM_SET_PATCH 6 /* Set patch header of patch parm1 */ +#define PM_READ_PATCH 7 /* Read patch (wave) data */ +#define PM_WRITE_PATCH 8 /* Write patch (wave) data */ + +/* + * Commands 0x1000 to 0xffff are for communication between the patch manager + * and the client + */ +#define _PM_LOAD_PATCH 0x100 + +/* + * Commands above 0xffff reserved for device specific use + */ + + long parm1; + long parm2; + long parm3; + + union { + unsigned char data8[4000]; + unsigned short data16[2000]; + unsigned long data32[1000]; + struct patch_info patch; + } data; + }; + +/* + * When a patch manager daemon is present, it will be informed by the + * driver when something important happens. For example when the + * /dev/sequencer is opened or closed. A record with key == PM_K_EVENT is + * returned. The command field contains the event type: + */ +#define PM_E_OPENED 1 /* /dev/sequencer opened */ +#define PM_E_CLOSED 2 /* /dev/sequencer closed */ +#define PM_E_PATCH_RESET 3 /* SNDCTL_RESETSAMPLES called */ +#define PM_E_PATCH_LOADED 4 /* A patch has been loaded by appl */ + +/* + * /dev/sequencer input events. + * + * The data written to the /dev/sequencer is a stream of events. Events + * are records of 4 or 8 bytes. The first byte defines the size. + * Any number of events can be written with a write call. There + * is a set of macros for sending these events. Use these macros if you + * want to maximize portability of your program. + * + * Events SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO. Are also input events. + * (All input events are currently 4 bytes long. Be prepared to support + * 8 byte events also. If you receive any event having first byte >= 0xf0, + * it's a 8 byte event. + * + * The events are documented at the end of this file. + * + * Normal events (4 bytes) + * There is also a 8 byte version of most of the 4 byte events. The + * 8 byte one is recommended. + */ +#define SEQ_NOTEOFF 0 +#define SEQ_FMNOTEOFF SEQ_NOTEOFF /* Just old name */ +#define SEQ_NOTEON 1 +#define SEQ_FMNOTEON SEQ_NOTEON +#define SEQ_WAIT 2 +#define SEQ_PGMCHANGE 3 +#define SEQ_FMPGMCHANGE SEQ_PGMCHANGE +#define SEQ_SYNCTIMER 4 +#define SEQ_MIDIPUTC 5 +#define SEQ_DRUMON 6 /*** OBSOLETE ***/ +#define SEQ_DRUMOFF 7 /*** OBSOLETE ***/ +#define SEQ_ECHO 8 /* For synching programs with output */ +#define SEQ_AFTERTOUCH 9 +#define SEQ_CONTROLLER 10 +#define CTRL_PITCH_BENDER 255 +#define CTRL_PITCH_BENDER_RANGE 254 +#define CTRL_EXPRESSION 253 +#define CTRL_MAIN_VOLUME 252 +#define SEQ_BALANCE 11 + +/* + * Note! SEQ_WAIT, SEQ_MIDIPUTC and SEQ_ECHO are used also as + * input events. + */ + +/* + * Event codes 0xf0 to 0xfc are reserved for future extensions. + */ + +#define SEQ_FULLSIZE 0xfd /* Long events */ +/* + * SEQ_FULLSIZE events are used for loading patches/samples to the + * synthesizer devices. These events are passed directly to the driver + * of the associated synthesizer device. There is no limit to the size + * of the extended events. These events are not queued but executed + * immediately when the write() is called (execution can take several + * seconds of time). + * + * When a SEQ_FULLSIZE message is written to the device, it must + * be written using exactly one write() call. Other events cannot + * be mixed to the same write. + * + * For FM synths (YM3812/OPL3) use struct sbi_instrument and write it to the + * /dev/sequencer. Don't write other data together with the instrument structure + * Set the key field of the structure to FM_PATCH. The device field is used to + * route the patch to the corresponding device. + * + * For Gravis UltraSound use struct patch_info. Initialize the key field + * to GUS_PATCH. + */ +#define SEQ_PRIVATE 0xfe /* Low level HW dependent events (8 bytes) */ +#define SEQ_EXTENDED 0xff /* Extended events (8 bytes) */ + +/* + * Extended events for synthesizers (8 bytes) + * + * Format: + * + * b0 = SEQ_EXTENDED + * b1 = command + * b2 = device + * b3-b7 = parameters + * + * Command b3 b4 b5 b6 b7 + * ---------------------------------------------------------------------------- + * SEQ_NOTEON voice note volume 0 0 + * SEQ_NOTEOFF voice note volume 0 0 + * SEQ_PGMCHANGE voice pgm 0 0 0 + * SEQ_DRUMON (voice) drum# volume 0 0 + * SEQ_DRUMOFF (voice) drum# volume 0 0 + */ + +/* + * Record for FM patches + */ + +typedef unsigned char sbi_instr_data[32]; + +struct sbi_instrument { + unsigned short key; /* Initialize to FM_PATCH or OPL3_PATCH */ +#define FM_PATCH 0x01fd +#define OPL3_PATCH 0x03fd + short device; /* Synth# (0-4) */ + int channel; /* Program# to be initialized */ + sbi_instr_data operators; /* Register settings for operator cells (.SBI format) */ + }; + +struct synth_info { /* Read only */ + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + int synth_type; +#define SYNTH_TYPE_FM 0 +#define SYNTH_TYPE_SAMPLE 1 + + int synth_subtype; +#define FM_TYPE_ADLIB 0x00 +#define FM_TYPE_OPL3 0x01 + +#define SAMPLE_TYPE_GUS 0x10 + + int perc_mode; /* No longer supported */ + int nr_voices; + int nr_drums; /* Obsolete field */ + int instr_bank_size; + unsigned long capabilities; +#define SYNTH_CAP_PERCMODE 0x00000001 /* No longer used */ +#define SYNTH_CAP_OPL3 0x00000002 /* Set if OPL3 supported */ + int dummies[19]; /* Reserve space */ + }; + +struct midi_info { + char name[30]; + int device; /* 0-N. INITIALIZE BEFORE CALLING */ + unsigned long capabilities; /* To be defined later */ + int dev_type; + int dummies[18]; /* Reserve space */ + }; + +/******************************************** + * IOCTL commands for /dev/dsp and /dev/audio + */ + +#define SNDCTL_DSP_RESET _IO ('P', 0) +#define SNDCTL_DSP_SYNC _IO ('P', 1) +#define SNDCTL_DSP_SPEED _IOWR('P', 2, int) +#define SNDCTL_DSP_STEREO _IOWR('P', 3, int) +#define SNDCTL_DSP_GETBLKSIZE _IOWR('P', 4, int) +#define SNDCTL_DSP_SAMPLESIZE _IOWR('P', 5, int) /* 8, 12 or 16 */ +#define SOUND_PCM_WRITE_CHANNELS _IOWR('P', 6, int) +#define SOUND_PCM_WRITE_FILTER _IOWR('P', 7, int) +#define SNDCTL_DSP_POST _IO ('P', 8) +#define SNDCTL_DSP_SUBDIVIDE _IOWR('P', 9, int) + +#define SOUND_PCM_READ_RATE _IOR ('P', 2, int) +#define SOUND_PCM_READ_CHANNELS _IOR ('P', 6, int) +#define SOUND_PCM_READ_BITS _IOR ('P', 5, int) +#define SOUND_PCM_READ_FILTER _IOR ('P', 7, int) + +/* Some alias names */ +#define SOUND_PCM_WRITE_BITS SNDCTL_DSP_SAMPLESIZE +#define SOUND_PCM_WRITE_RATE SNDCTL_DSP_SPEED +#define SOUND_PCM_POST SNDCTL_DSP_POST +#define SOUND_PCM_RESET SNDCTL_DSP_RESET +#define SOUND_PCM_SYNC SNDCTL_DSP_SYNC +#define SOUND_PCM_SUBDIVIDE SNDCTL_DSP_SUBDIVIDE + +/********************************************* + * IOCTL commands for /dev/mixer + */ + +/* + * Mixer devices + * + * There can be up to 20 different analog mixer channels. The + * SOUND_MIXER_NRDEVICES gives the currently supported maximum. + * The SOUND_MIXER_READ_DEVMASK returns a bitmask which tells + * the devices supported by the particular mixer. + */ + +#define SOUND_MIXER_NRDEVICES 12 +#define SOUND_MIXER_VOLUME 0 +#define SOUND_MIXER_BASS 1 +#define SOUND_MIXER_TREBLE 2 +#define SOUND_MIXER_SYNTH 3 +#define SOUND_MIXER_PCM 4 +#define SOUND_MIXER_SPEAKER 5 +#define SOUND_MIXER_LINE 6 +#define SOUND_MIXER_MIC 7 +#define SOUND_MIXER_CD 8 +#define SOUND_MIXER_IMIX 9 /* Recording monitor */ +#define SOUND_MIXER_ALTPCM 10 +#define SOUND_MIXER_RECLEV 11 /* Recording level */ + +/* Some on/off settings (SOUND_SPECIAL_MIN - SOUND_SPECIAL_MAX) */ +/* Not counted to SOUND_MIXER_NRDEVICES, but use the same number space */ +#define SOUND_ONOFF_MIN 28 +#define SOUND_ONOFF_MAX 30 +#define SOUND_MIXER_MUTE 28 /* 0 or 1 */ +#define SOUND_MIXER_ENHANCE 29 /* Enhanced stereo (0, 40, 60 or 80) */ +#define SOUND_MIXER_LOUD 30 /* 0 or 1 */ + +/* Note! Number 31 cannot be used since the sign bit is reserved */ + +#define SOUND_DEVICE_LABELS {"Vol ", "Bass ", "Trebl", "Synth", "Pcm ", "Spkr ", "Line ", \ + "Mic ", "CD ", "Mix ", "Pcm2 ", "rec"} + +#define SOUND_DEVICE_NAMES {"vol", "bass", "treble", "synth", "pcm", "speaker", "line", \ + "mic", "cd", "mix", "pcm2", "rec"} + +/* Device bitmask identifiers */ + +#define SOUND_MIXER_RECSRC 0xff /* Arg contains a bit for each recording source */ +#define SOUND_MIXER_DEVMASK 0xfe /* Arg contains a bit for each supported device */ +#define SOUND_MIXER_RECMASK 0xfd /* Arg contains a bit for each supported recording source */ +#define SOUND_MIXER_CAPS 0xfc + #define SOUND_CAP_EXCL_INPUT 0x00000001 /* Only one recording source at a time */ +#define SOUND_MIXER_STEREODEVS 0xfb /* Mixer channels supporting stereo */ + +/* Device mask bits */ + +#define SOUND_MASK_VOLUME (1 << SOUND_MIXER_VOLUME) +#define SOUND_MASK_BASS (1 << SOUND_MIXER_BASS) +#define SOUND_MASK_TREBLE (1 << SOUND_MIXER_TREBLE) +#define SOUND_MASK_SYNTH (1 << SOUND_MIXER_SYNTH) +#define SOUND_MASK_PCM (1 << SOUND_MIXER_PCM) +#define SOUND_MASK_SPEAKER (1 << SOUND_MIXER_SPEAKER) +#define SOUND_MASK_LINE (1 << SOUND_MIXER_LINE) +#define SOUND_MASK_MIC (1 << SOUND_MIXER_MIC) +#define SOUND_MASK_CD (1 << SOUND_MIXER_CD) +#define SOUND_MASK_IMIX (1 << SOUND_MIXER_IMIX) +#define SOUND_MASK_ALTPCM (1 << SOUND_MIXER_ALTPCM) +#define SOUND_MASK_RECLEV (1 << SOUND_MIXER_RECLEV) + +#define SOUND_MASK_MUTE (1 << SOUND_MIXER_MUTE) +#define SOUND_MASK_ENHANCE (1 << SOUND_MIXER_ENHANCE) +#define SOUND_MASK_LOUD (1 << SOUND_MIXER_LOUD) + +#define MIXER_READ(dev) _IOR('M', dev, int) +#define SOUND_MIXER_READ_VOLUME MIXER_READ(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_READ_BASS MIXER_READ(SOUND_MIXER_BASS) +#define SOUND_MIXER_READ_TREBLE MIXER_READ(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_READ_SYNTH MIXER_READ(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_READ_PCM MIXER_READ(SOUND_MIXER_PCM) +#define SOUND_MIXER_READ_SPEAKER MIXER_READ(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_READ_LINE MIXER_READ(SOUND_MIXER_LINE) +#define SOUND_MIXER_READ_MIC MIXER_READ(SOUND_MIXER_MIC) +#define SOUND_MIXER_READ_CD MIXER_READ(SOUND_MIXER_CD) +#define SOUND_MIXER_READ_IMIX MIXER_READ(SOUND_MIXER_IMIX) +#define SOUND_MIXER_READ_ALTPCM MIXER_READ(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_READ_RECLEV MIXER_READ(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_READ_MUTE MIXER_READ(SOUND_MIXER_MUTE) +#define SOUND_MIXER_READ_ENHANCE MIXER_READ(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_READ_LOUD MIXER_READ(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_READ_RECSRC MIXER_READ(SOUND_MIXER_RECSRC) +#define SOUND_MIXER_READ_DEVMASK MIXER_READ(SOUND_MIXER_DEVMASK) +#define SOUND_MIXER_READ_RECMASK MIXER_READ(SOUND_MIXER_RECMASK) +#define SOUND_MIXER_READ_STEREODEVS MIXER_READ(SOUND_MIXER_STEREODEVS) +#define SOUND_MIXER_READ_CAPS MIXER_READ(SOUND_MIXER_CAPS) + +#define MIXER_WRITE(dev) _IOWR('M', dev, int) +#define SOUND_MIXER_WRITE_VOLUME MIXER_WRITE(SOUND_MIXER_VOLUME) +#define SOUND_MIXER_WRITE_BASS MIXER_WRITE(SOUND_MIXER_BASS) +#define SOUND_MIXER_WRITE_TREBLE MIXER_WRITE(SOUND_MIXER_TREBLE) +#define SOUND_MIXER_WRITE_SYNTH MIXER_WRITE(SOUND_MIXER_SYNTH) +#define SOUND_MIXER_WRITE_PCM MIXER_WRITE(SOUND_MIXER_PCM) +#define SOUND_MIXER_WRITE_SPEAKER MIXER_WRITE(SOUND_MIXER_SPEAKER) +#define SOUND_MIXER_WRITE_LINE MIXER_WRITE(SOUND_MIXER_LINE) +#define SOUND_MIXER_WRITE_MIC MIXER_WRITE(SOUND_MIXER_MIC) +#define SOUND_MIXER_WRITE_CD MIXER_WRITE(SOUND_MIXER_CD) +#define SOUND_MIXER_WRITE_IMIX MIXER_WRITE(SOUND_MIXER_IMIX) +#define SOUND_MIXER_WRITE_ALTPCM MIXER_WRITE(SOUND_MIXER_ALTPCM) +#define SOUND_MIXER_WRITE_RECLEV MIXER_WRITE(SOUND_MIXER_RECLEV) +#define SOUND_MIXER_WRITE_MUTE MIXER_WRITE(SOUND_MIXER_MUTE) +#define SOUND_MIXER_WRITE_ENHANCE MIXER_WRITE(SOUND_MIXER_ENHANCE) +#define SOUND_MIXER_WRITE_LOUD MIXER_WRITE(SOUND_MIXER_LOUD) + +#define SOUND_MIXER_WRITE_RECSRC MIXER_WRITE(SOUND_MIXER_RECSRC) + +/* + * The following mixer ioctl calls are compatible with the BSD driver by + * Steve Haehnichen + * + * Since this interface is entirely SB specific, it will be dropped in the + * near future. + */ + +typedef unsigned char S_BYTE; +typedef unsigned char S_FLAG; +struct stereo_vol +{ + S_BYTE l; /* Left volume */ + S_BYTE r; /* Right volume */ +}; + +#define MIXER_IOCTL_SET_LEVELS _IOW ('s', 20, struct sb_mixer_levels) +#define MIXER_IOCTL_SET_PARAMS _IOW ('s', 21, struct sb_mixer_params) +#define MIXER_IOCTL_READ_LEVELS _IOR ('s', 22, struct sb_mixer_levels) +#define MIXER_IOCTL_READ_PARAMS _IOR ('s', 23, struct sb_mixer_params) +#define MIXER_IOCTL_RESET _IO ('s', 24) + +/* + * Mixer volume levels for MIXER_IOCTL_SET_VOL & MIXER_IOCTL_READ_VOL + */ +struct sb_mixer_levels +{ + struct stereo_vol master; /* Master volume */ + struct stereo_vol voc; /* DSP Voice volume */ + struct stereo_vol fm; /* FM volume */ + struct stereo_vol line; /* Line-in volume */ + struct stereo_vol cd; /* CD audio */ + S_BYTE mic; /* Microphone level */ +}; + +/* + * Mixer parameters for MIXER_IOCTL_SET_PARAMS & MIXER_IOCTL_READ_PARAMS + */ +struct sb_mixer_params +{ + S_BYTE record_source; /* Recording source (See SRC_xxx below) */ + S_FLAG hifreq_filter; /* Filter frequency (hi/low) */ + S_FLAG filter_input; /* ANFI input filter */ + S_FLAG filter_output; /* DNFI output filter */ + S_FLAG dsp_stereo; /* 1 if DSP is in Stereo mode */ +}; + +#define SRC_MIC 1 /* Select Microphone recording source */ +#define SRC_CD 3 /* Select CD recording source */ +#define SRC_LINE 7 /* Use Line-in for recording source */ + +#if !defined(KERNEL) && !defined(INKERNEL) +/* + * Some convenience macros to simplify programming of the + * /dev/sequencer interface + * + * These macros define the API which should be used when possible. + */ + +void seqbuf_dump(void); /* This function must be provided by programs */ + +/* Sample seqbuf_dump() implementation: + * + * SEQ_DEFINEBUF (2048); -- Defines a buffer for 2048 bytes + * + * int seqfd; -- The file descriptor for /dev/sequencer. + * + * void + * seqbuf_dump () + * { + * if (_seqbufptr) + * if (write (seqfd, _seqbuf, _seqbufptr) == -1) + * { + * perror ("write /dev/sequencer"); + * exit (-1); + * } + * _seqbufptr = 0; + * } + */ + +#define SEQ_DEFINEBUF(len) unsigned char _seqbuf[len]; int _seqbuflen = len, _seqbufptr = 0 +#define SEQ_PM_DEFINES struct patmgr_info _pm_info +#define _SEQ_NEEDBUF(len) if ((_seqbufptr+(len)) > _seqbuflen) seqbuf_dump() +#define _SEQ_ADVBUF(len) _seqbufptr += len +#define SEQ_DUMPBUF seqbuf_dump +#define PM_LOAD_PATCH(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ + _pm_info.device=dev, _pm_info.data.data8[0]=pgm, \ + _pm_info.parm1 = bank, _pm_info.parm2 = 1, \ + ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info)) +#define PM_LOAD_PATCHES(dev, bank, pgm) (SEQ_DUMPBUF(), _pm_info.command = _PM_LOAD_PATCH, \ + _pm_info.device=dev, memcpy(_pm_info.data.data8, pgm, 128), \ + _pm_info.parm1 = bank, _pm_info.parm2 = 128, \ + ioctl(seqfd, SNDCTL_PMGR_ACCESS, &_pm_info)) + +#define SEQ_START_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_NOTEON;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (note);\ + _seqbuf[_seqbufptr+5] = (vol);\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_STOP_NOTE(dev, voice, note, vol) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_NOTEOFF;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (note);\ + _seqbuf[_seqbufptr+5] = (vol);\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_CHN_PRESSURE(dev, voice, pressure) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_AFTERTOUCH;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (pressure);\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_PANNING(dev, voice, pos) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_BALANCE;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + (char)_seqbuf[_seqbufptr+4] = (pos);\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_CONTROL(dev, voice, controller, value) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_CONTROLLER;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (controller);\ + *(short *)&_seqbuf[_seqbufptr+5] = (value);\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_PITCHBEND(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER, value) +#define SEQ_BENDER_RANGE(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_PITCH_BENDER_RANGE, value) +#define SEQ_EXPRESSION(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_EXPRESSION, value) +#define SEQ_MAIN_VOLUME(dev, voice, value) SEQ_CONTROL(dev, voice, CTRL_MAIN_VOLUME, value) + +#define SEQ_START_TIMER() {_SEQ_NEEDBUF(4);\ + _seqbuf[_seqbufptr] = SEQ_SYNCTIMER;\ + _seqbuf[_seqbufptr+1] = 0;\ + _seqbuf[_seqbufptr+2] = 0;\ + _seqbuf[_seqbufptr+3] = 0;\ + _SEQ_ADVBUF(4);} +#define SEQ_SET_PATCH(dev, voice, patch) {_SEQ_NEEDBUF(8);\ + _seqbuf[_seqbufptr] = SEQ_EXTENDED;\ + _seqbuf[_seqbufptr+1] = SEQ_PGMCHANGE;\ + _seqbuf[_seqbufptr+2] = (dev);\ + _seqbuf[_seqbufptr+3] = (voice);\ + _seqbuf[_seqbufptr+4] = (patch);\ + _seqbuf[_seqbufptr+5] = 0;\ + _seqbuf[_seqbufptr+6] = 0;\ + _seqbuf[_seqbufptr+7] = 0;\ + _SEQ_ADVBUF(8);} + +#define SEQ_WAIT_TIME(ticks) {_SEQ_NEEDBUF(4);\ + *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_WAIT | ((ticks) << 8);\ + _SEQ_ADVBUF(4);} + +#define SEQ_ECHO_BACK(key) {_SEQ_NEEDBUF(4);\ + *(unsigned long *)&_seqbuf[_seqbufptr] = SEQ_ECHO | ((key) << 8);\ + _SEQ_ADVBUF(4);} + +#define SEQ_MIDIOUT(device, byte) {_SEQ_NEEDBUF(4);\ + _seqbuf[_seqbufptr] = SEQ_MIDIPUTC;\ + _seqbuf[_seqbufptr+1] = (byte);\ + _seqbuf[_seqbufptr+2] = (device);\ + _seqbuf[_seqbufptr+3] = 0;\ + _SEQ_ADVBUF(4);} +#define SEQ_WRPATCH(patch, len) {if (_seqbufptr) seqbuf_dump();\ + if (write(seqfd, (char*)(patch), len)==-1) \ + perror("Write patch: /dev/sequencer");} + +#endif +long soundcard_init(long mem_start); +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stat.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stat.h new file mode 100644 index 000000000..86fbd821b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stat.h @@ -0,0 +1,88 @@ +#ifndef _LINUX_STAT_H +#define _LINUX_STAT_H + +#ifdef __KERNEL__ + +struct old_stat { + unsigned short st_dev; + unsigned short st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned long st_size; + unsigned long st_atime; + unsigned long st_mtime; + unsigned long st_ctime; +}; + +struct new_stat { + unsigned short st_dev; + unsigned short __pad1; + unsigned long st_ino; + unsigned short st_mode; + unsigned short st_nlink; + unsigned short st_uid; + unsigned short st_gid; + unsigned short st_rdev; + unsigned short __pad2; + unsigned long st_size; + unsigned long st_blksize; + unsigned long st_blocks; + unsigned long st_atime; + unsigned long __unused1; + unsigned long st_mtime; + unsigned long __unused2; + unsigned long st_ctime; + unsigned long __unused3; + unsigned long __unused4; + unsigned long __unused5; +}; + +#endif + +#define S_IFMT 00170000 +#define S_IFSOCK 0140000 +#define S_IFLNK 0120000 +#define S_IFREG 0100000 +#define S_IFBLK 0060000 +#define S_IFDIR 0040000 +#define S_IFCHR 0020000 +#define S_IFIFO 0010000 +#define S_ISUID 0004000 +#define S_ISGID 0002000 +#define S_ISVTX 0001000 + +#define S_ISLNK(m) (((m) & S_IFMT) == S_IFLNK) +#define S_ISREG(m) (((m) & S_IFMT) == S_IFREG) +#define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR) +#define S_ISCHR(m) (((m) & S_IFMT) == S_IFCHR) +#define S_ISBLK(m) (((m) & S_IFMT) == S_IFBLK) +#define S_ISFIFO(m) (((m) & S_IFMT) == S_IFIFO) +#define S_ISSOCK(m) (((m) & S_IFMT) == S_IFSOCK) + +#define S_IRWXU 00700 +#define S_IRUSR 00400 +#define S_IWUSR 00200 +#define S_IXUSR 00100 + +#define S_IRWXG 00070 +#define S_IRGRP 00040 +#define S_IWGRP 00020 +#define S_IXGRP 00010 + +#define S_IRWXO 00007 +#define S_IROTH 00004 +#define S_IWOTH 00002 +#define S_IXOTH 00001 + +#ifdef __KERNEL__ +#define S_IRWXUGO (S_IRWXU|S_IRWXG|S_IRWXO) +#define S_IALLUGO (S_ISUID|S_ISGID|S_ISVTX|S_IRWXUGO) +#define S_IRUGO (S_IRUSR|S_IRGRP|S_IROTH) +#define S_IWUGO (S_IWUSR|S_IWGRP|S_IWOTH) +#define S_IXUGO (S_IXUSR|S_IXGRP|S_IXOTH) +#endif + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stddef.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stddef.h new file mode 100644 index 000000000..c6221e712 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/stddef.h @@ -0,0 +1,15 @@ +#ifndef _LINUX_STDDEF_H +#define _LINUX_STDDEF_H + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#undef NULL +#define NULL ((void *)0) + +#undef offsetof +#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/string.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/string.h new file mode 100644 index 000000000..eacc6d164 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/string.h @@ -0,0 +1,419 @@ +#ifndef _LINUX_STRING_H_ +#define _LINUX_STRING_H_ + +#include /* for size_t */ + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +/* + * This string-include defines all string functions as inline + * functions. Use gcc. It also assumes ds=es=data space, this should be + * normal. Most of the string-functions are rather heavily hand-optimized, + * see especially strtok,strstr,str[c]spn. They should work, but are not + * very easy to understand. Everything is done entirely within the register + * set, making the functions fast and clean. String instructions have been + * used through-out, making for "slightly" unclear code :-) + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +extern inline char * strcpy(char * dest,const char *src) +{ +__asm__("cld\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : /* no output */ + :"S" (src),"D" (dest):"si","di","ax","memory"); +return dest; +} + +extern inline char * strncpy(char * dest,const char *src,size_t count) +{ +__asm__("cld\n" + "1:\tdecl %2\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "rep\n\t" + "stosb\n" + "2:" + : /* no output */ + :"S" (src),"D" (dest),"c" (count):"si","di","ax","cx","memory"); +return dest; +} + +extern inline char * strcat(char * dest,const char * src) +{ +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "decl %1\n" + "1:\tlodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b" + : /* no output */ + :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff):"si","di","ax","cx"); +return dest; +} + +extern inline char * strncat(char * dest,const char * src,size_t count) +{ +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "decl %1\n\t" + "movl %4,%3\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "stosb\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %2,%2\n\t" + "stosb" + : /* no output */ + :"S" (src),"D" (dest),"a" (0),"c" (0xffffffff),"g" (count) + :"si","di","ax","cx","memory"); +return dest; +} + +extern inline int strcmp(const char * cs,const char * ct) +{ +register int __res __asm__("ax"); +__asm__("cld\n" + "1:\tlodsb\n\t" + "scasb\n\t" + "jne 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "jmp 3f\n" + "2:\tmovl $1,%%eax\n\t" + "jb 3f\n\t" + "negl %%eax\n" + "3:" + :"=a" (__res):"D" (cs),"S" (ct):"si","di"); +return __res; +} + +extern inline int strncmp(const char * cs,const char * ct,size_t count) +{ +register int __res __asm__("ax"); +__asm__("cld\n" + "1:\tdecl %3\n\t" + "js 2f\n\t" + "lodsb\n\t" + "scasb\n\t" + "jne 3f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n" + "2:\txorl %%eax,%%eax\n\t" + "jmp 4f\n" + "3:\tmovl $1,%%eax\n\t" + "jb 4f\n\t" + "negl %%eax\n" + "4:" + :"=a" (__res):"D" (cs),"S" (ct),"c" (count):"si","di","cx"); +return __res; +} + +extern inline char * strchr(const char * s,char c) +{ +register char * __res __asm__("ax"); +__asm__("cld\n\t" + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "je 2f\n\t" + "testb %%al,%%al\n\t" + "jne 1b\n\t" + "movl $1,%1\n" + "2:\tmovl %1,%0\n\t" + "decl %0" + :"=a" (__res):"S" (s),"0" (c):"si"); +return __res; +} + +extern inline char * strrchr(const char * s,char c) +{ +register char * __res __asm__("dx"); +__asm__("cld\n\t" + "movb %%al,%%ah\n" + "1:\tlodsb\n\t" + "cmpb %%ah,%%al\n\t" + "jne 2f\n\t" + "movl %%esi,%0\n\t" + "decl %0\n" + "2:\ttestb %%al,%%al\n\t" + "jne 1b" + :"=d" (__res):"0" (0),"S" (s),"a" (c):"ax","si"); +return __res; +} + +extern inline size_t strspn(const char * cs, const char * ct) +{ +register char * __res __asm__("si"); +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "je 1b\n" + "2:\tdecl %0" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + :"ax","cx","dx","di"); +return __res-cs; +} + +extern inline size_t strcspn(const char * cs, const char * ct) +{ +register char * __res __asm__("si"); +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 1b\n" + "2:\tdecl %0" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + :"ax","cx","dx","di"); +return __res-cs; +} + +extern inline char * strpbrk(const char * cs,const char * ct) +{ +register char * __res __asm__("si"); +__asm__("cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "movl %%ecx,%%edx\n" + "1:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 2f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 1b\n\t" + "decl %0\n\t" + "jmp 3f\n" + "2:\txorl %0,%0\n" + "3:" + :"=S" (__res):"a" (0),"c" (0xffffffff),"0" (cs),"g" (ct) + :"ax","cx","dx","di"); +return __res; +} + +extern inline char * strstr(const char * cs,const char * ct) +{ +register char * __res __asm__("ax"); +__asm__("cld\n\t" \ + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" /* NOTE! This also sets Z if searchstring='' */ + "movl %%ecx,%%edx\n" + "1:\tmovl %4,%%edi\n\t" + "movl %%esi,%%eax\n\t" + "movl %%edx,%%ecx\n\t" + "repe\n\t" + "cmpsb\n\t" + "je 2f\n\t" /* also works for empty string, see above */ + "xchgl %%eax,%%esi\n\t" + "incl %%esi\n\t" + "cmpb $0,-1(%%eax)\n\t" + "jne 1b\n\t" + "xorl %%eax,%%eax\n\t" + "2:" + :"=a" (__res):"0" (0),"c" (0xffffffff),"S" (cs),"g" (ct) + :"cx","dx","di","si"); +return __res; +} + +extern inline size_t strlen(const char * s) +{ +register int __res __asm__("cx"); +__asm__("cld\n\t" + "repne\n\t" + "scasb\n\t" + "notl %0\n\t" + "decl %0" + :"=c" (__res):"D" (s),"a" (0),"0" (0xffffffff):"di"); +return __res; +} + +extern char * ___strtok; + +extern inline char * strtok(char * s,const char * ct) +{ +register char * __res; +__asm__("testl %1,%1\n\t" + "jne 1f\n\t" + "testl %0,%0\n\t" + "je 8f\n\t" + "movl %0,%1\n" + "1:\txorl %0,%0\n\t" + "movl $-1,%%ecx\n\t" + "xorl %%eax,%%eax\n\t" + "cld\n\t" + "movl %4,%%edi\n\t" + "repne\n\t" + "scasb\n\t" + "notl %%ecx\n\t" + "decl %%ecx\n\t" + "je 7f\n\t" /* empty delimeter-string */ + "movl %%ecx,%%edx\n" + "2:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 7f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "je 2b\n\t" + "decl %1\n\t" + "cmpb $0,(%1)\n\t" + "je 7f\n\t" + "movl %1,%0\n" + "3:\tlodsb\n\t" + "testb %%al,%%al\n\t" + "je 5f\n\t" + "movl %4,%%edi\n\t" + "movl %%edx,%%ecx\n\t" + "repne\n\t" + "scasb\n\t" + "jne 3b\n\t" + "decl %1\n\t" + "cmpb $0,(%1)\n\t" + "je 5f\n\t" + "movb $0,(%1)\n\t" + "incl %1\n\t" + "jmp 6f\n" + "5:\txorl %1,%1\n" + "6:\tcmpb $0,(%0)\n\t" + "jne 7f\n\t" + "xorl %0,%0\n" + "7:\ttestl %0,%0\n\t" + "jne 8f\n\t" + "movl %0,%1\n" + "8:" + :"=b" (__res),"=S" (___strtok) + :"0" (___strtok),"1" (s),"g" (ct) + :"ax","cx","dx","di","memory"); +return __res; +} + +extern inline void * memcpy(void * to, const void * from, size_t n) +{ +__asm__("cld\n\t" + "movl %%edx, %%ecx\n\t" + "shrl $2,%%ecx\n\t" + "rep ; movsl\n\t" + "testb $1,%%dl\n\t" + "je 1f\n\t" + "movsb\n" + "1:\ttestb $2,%%dl\n\t" + "je 2f\n\t" + "movsw\n" + "2:\n" + : /* no output */ + :"d" (n),"D" ((long) to),"S" ((long) from) + : "cx","di","si","memory"); +return (to); +} + +extern inline void * memmove(void * dest,const void * src, size_t n) +{ +if (dest /* declares S_IFLNK etc. */ +#include /* declares wake_up() */ +#include /* defines the sv_... shortcuts */ + + +/* Layout on disk */ +/* ============== */ + + +/* The block size is sb->sv_block_size which may be smaller than BLOCK_SIZE. */ + +/* zones (= data allocation units) are blocks */ + +/* On Coherent FS, 32 bit quantities are stored using (I quote the Coherent + manual) a "canonical byte ordering". This is the PDP-11 byte ordering: + x = 2^24 * byte3 + 2^16 * byte2 + 2^8 * byte1 + byte0 is stored + as { byte2, byte3, byte0, byte1 }. We need conversions. +*/ + +typedef unsigned long coh_ulong; + +static inline coh_ulong to_coh_ulong (unsigned long x) +{ + return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16); +} + +static inline unsigned long from_coh_ulong (coh_ulong x) +{ + return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16); +} + +/* inode numbers are 16 bit */ + +typedef unsigned short sysv_ino_t; + +/* Block numbers are 24 bit, sometimes stored in 32 bit. + On Coherent FS, they are always stored in PDP-11 manner: the least + significant 16 bits come last. +*/ + +typedef unsigned long sysv_zone_t; + +/* Among the blocks ... */ +/* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block. + SystemV FS: block 0 contains both the boot sector and the super-block. */ +/* The first inode zone is sb->sv_firstinodezone (1 or 2). */ + +/* Among the inodes ... */ +/* 0 is non-existent */ +#define SYSV_BADBL_INO 1 /* inode of bad blocks file */ +#define SYSV_ROOT_INO 2 /* inode of root directory */ + + +/* Xenix super-block data on disk */ +#define XENIX_NICINOD 100 /* number of inode cache entries */ +#define XENIX_NICFREE 100 /* number of free block list chunk entries */ +struct xenix_super_block { + unsigned short s_isize; /* index of first data zone */ + unsigned long s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ + unsigned short s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */ + unsigned long s_free[XENIX_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ + unsigned short s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */ + sysv_ino_t s_inode[XENIX_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + unsigned long s_time __packed2__; /* time of last super block update */ + unsigned long s_tfree __packed2__; /* total number of free zones */ + unsigned short s_tinode; /* total number of free inodes */ + short s_dinfo[4]; /* device information ?? */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + char s_clean; /* set to 0x46 when filesystem is properly unmounted */ + char s_fill[371]; + long s_magic; /* version of file system */ + long s_type; /* type of file system: 1 for 512 byte blocks + 2 for 1024 byte blocks */ +}; + +/* Xenix free list block on disk */ +struct xenix_freelist_chunk { + unsigned short fl_nfree; /* number of free blocks in fl_free, <= XENIX_NICFREE] */ + unsigned long fl_free[XENIX_NICFREE] __packed2__; +}; + +/* SystemV FS comes in two variants: + * sysv2: System V Release 2 (e.g. Microport), structure elements aligned(2). + * sysv4: System V Release 4 (e.g. Consensys), structure elements aligned(4). + */ +#define SYSV_NICINOD 100 /* number of inode cache entries */ +#define SYSV_NICFREE 50 /* number of free block list chunk entries */ + +/* SystemV4 super-block data on disk */ +struct sysv4_super_block { + unsigned short s_isize; /* index of first data zone */ + unsigned long s_fsize; /* total number of zones of this fs */ + /* the start of the free block list: */ + unsigned short s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ + unsigned long s_free[SYSV_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ + unsigned short s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ + sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + unsigned long s_time; /* time of last super block update */ + short s_dinfo[4]; /* device information ?? */ + unsigned long s_tfree; /* total number of free zones */ + unsigned short s_tinode; /* total number of free inodes */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + long s_fill[12]; + long s_state; /* file system state */ + long s_magic; /* version of file system */ + long s_type; /* type of file system: 1 for 512 byte blocks + 2 for 1024 byte blocks */ +}; + +/* SystemV4 free list block on disk */ +struct sysv4_freelist_chunk { + unsigned short fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ + unsigned long fl_free[SYSV_NICFREE]; +}; + +/* SystemV2 super-block data on disk */ +struct sysv2_super_block { + unsigned short s_isize; /* index of first data zone */ + unsigned long s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ + unsigned short s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */ + unsigned long s_free[SYSV_NICFREE]; /* first free block list chunk */ + /* the cache of free inodes: */ + unsigned short s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */ + sysv_ino_t s_inode[SYSV_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + unsigned long s_time __packed2__; /* time of last super block update */ + short s_dinfo[4]; /* device information ?? */ + unsigned long s_tfree __packed2__; /* total number of free zones */ + unsigned short s_tinode; /* total number of free inodes */ + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + long s_fill[14]; + long s_state; /* file system state */ + long s_magic; /* version of file system */ + long s_type; /* type of file system: 1 for 512 byte blocks + 2 for 1024 byte blocks */ +}; + +/* SystemV2 free list block on disk */ +struct sysv2_freelist_chunk { + unsigned short fl_nfree; /* number of free blocks in fl_free, <= SYSV_NICFREE] */ + unsigned long fl_free[SYSV_NICFREE] __packed2__; +}; + +/* Coherent super-block data on disk */ +#define COH_NICINOD 100 /* number of inode cache entries */ +#define COH_NICFREE 64 /* number of free block list chunk entries */ +struct coh_super_block { + unsigned short s_isize; /* index of first data zone */ + coh_ulong s_fsize __packed2__; /* total number of zones of this fs */ + /* the start of the free block list: */ + unsigned short s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */ + coh_ulong s_free[COH_NICFREE] __packed2__; /* first free block list chunk */ + /* the cache of free inodes: */ + unsigned short s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */ + sysv_ino_t s_inode[COH_NICINOD]; /* some free inodes */ + /* locks, not used by Linux: */ + char s_flock; /* lock during free block list manipulation */ + char s_ilock; /* lock during inode cache manipulation */ + char s_fmod; /* super-block modified flag */ + char s_ronly; /* flag whether fs is mounted read-only */ + coh_ulong s_time __packed2__; /* time of last super block update */ + coh_ulong s_tfree __packed2__; /* total number of free zones */ + unsigned short s_tinode; /* total number of free inodes */ + unsigned short s_interleave_m; /* interleave factor */ + unsigned short s_interleave_n; + char s_fname[6]; /* file system volume name */ + char s_fpack[6]; /* file system pack name */ + unsigned long s_unique; /* zero, not used */ +}; + +/* Coherent free list block on disk */ +struct coh_freelist_chunk { + unsigned short fl_nfree; /* number of free blocks in fl_free, <= COH_NICFREE] */ + unsigned long fl_free[COH_NICFREE] __packed2__; +}; + + +/* SystemV/Coherent inode data on disk */ + +struct sysv_inode { + unsigned short i_mode; + unsigned short i_nlink; + unsigned short i_uid; + unsigned short i_gid; + unsigned long i_size; + union { /* directories, regular files, ... */ + char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks, + * then 1 indirection block, + * then 1 double indirection block, + * then 1 triple indirection block. + * Then maybe a "file generation number" ?? + */ + /* devices */ + dev_t i_rdev; + /* named pipes on Coherent */ + struct { + char p_addp[30]; + short p_pnc; + short p_prx; + short p_pwx; + } i_p; + } i_a; + unsigned long i_atime; /* time of last access */ + unsigned long i_mtime; /* time of last modification */ + unsigned long i_ctime; /* time of creation */ +}; + +/* The admissible values for i_mode are listed in : + * #define S_IFMT 00170000 mask for type + * #define S_IFREG 0100000 type = regular file + * #define S_IFBLK 0060000 type = block device + * #define S_IFDIR 0040000 type = directory + * #define S_IFCHR 0020000 type = character device + * #define S_IFIFO 0010000 type = named pipe + * #define S_ISUID 0004000 set user id + * #define S_ISGID 0002000 set group id + * #define S_ISVTX 0001000 save swapped text even after use + * Additionally for SystemV: + * #define S_IFLNK 0120000 type = symbolic link + * #define S_IFNAM 0050000 type = XENIX special named file ?? + * Additionally for Coherent: + * #define S_IFMPB 0070000 type = multiplexed block device ?? + * #define S_IFMPC 0030000 type = multiplexed character device ?? + * + * Since Coherent doesn't know about symbolic links, we use a kludgey + * implementation of symbolic links: i_mode = COH_KLUDGE_SYMLINK_MODE + * denotes a symbolic link. When a regular file should get this mode by + * accident, it is automatically converted to COH_KLUDGE_NOT_SYMLINK. + * We use S_IFREG because only regular files (and Coherent pipes...) can have + * data blocks with arbitrary contents associated with them, and S_ISVTX + * ("save swapped text after use") because it is unused on both Linux and + * Coherent: Linux does much more intelligent paging, and Coherent hasn't + * virtual memory at all. + * Same trick for Xenix. + */ +#define COH_KLUDGE_SYMLINK_MODE (S_IFREG | S_ISVTX) +#define COH_KLUDGE_NOT_SYMLINK (S_IFREG | S_ISVTX | S_IRUSR) /* force read access */ +extern inline mode_t from_coh_imode(unsigned short mode) +{ + if (mode == COH_KLUDGE_SYMLINK_MODE) + return (S_IFLNK | 0777); + else + return mode; +} +extern inline unsigned short to_coh_imode(mode_t mode) +{ + if (S_ISLNK(mode)) + return COH_KLUDGE_SYMLINK_MODE; + else if (mode == COH_KLUDGE_SYMLINK_MODE) + return COH_KLUDGE_NOT_SYMLINK; + else + return mode; +} + +/* Admissible values for i_nlink: 0.._LINK_MAX */ +#define XENIX_LINK_MAX 126 /* ?? */ +#define SYSV_LINK_MAX 126 /* 127? 251? */ +#define COH_LINK_MAX 10000 /* max number of hard links to an inode */ + +/* The number of inodes per block is + sb->sv_inodes_per_block = block_size / sizeof(struct sysv_inode) */ +/* The number of indirect pointers per block is + sb->sv_ind_per_block = block_size / sizeof(unsigned long) */ + + +/* SystemV/Coherent directory entry on disk */ + +#define SYSV_NAMELEN 14 /* max size of name in struct sysv_dir_entry */ + +struct sysv_dir_entry { + sysv_ino_t inode; + char name[SYSV_NAMELEN]; /* up to 14 characters, the rest are zeroes */ +}; + +#define SYSV_DIRSIZE sizeof(struct sysv_dir_entry) /* size of every directory entry */ + + +/* Operations */ +/* ========== */ + + +/* identify the FS in memory */ +#define FSTYPE_XENIX 1 +#define FSTYPE_SYSV4 2 +#define FSTYPE_SYSV2 3 +#define FSTYPE_COH 4 + +#define SYSV_MAGIC_BASE 0x012FF7B3 + +#define XENIX_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_XENIX) +#define SYSV4_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV4) +#define SYSV2_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_SYSV2) +#define COH_SUPER_MAGIC (SYSV_MAGIC_BASE+FSTYPE_COH) + +/* Because the block size may be smaller than 1024 (which is the unit used by + the disk drivers and the buffer code), many functions must return a pointer + to the buffer data additionally to the buffer head pointer. +*/ +#if 0 +struct bh_data { + struct buffer_head * bh; + char * bh_data; +}; +#endif + +/* sysv_bread(sb,dev,block,...) would be equivalent to + bread(dev,block,BLOCK_SIZE) + if the block size were always 1024, which is the only one bread() supports. +*/ +static inline struct buffer_head * +sysv_bread (struct super_block *sb, int dev, unsigned int block, char* * data) +{ + struct buffer_head *bh; + + if (!(bh = bread (dev, (block >> sb->sv_block_size_ratio_bits) + sb->sv_block_base, BLOCK_SIZE))) + return NULL; + *data = bh->b_data + ((block & sb->sv_block_size_ratio_1) << sb->sv_block_size_bits); + return bh; +} + + +/* locks - protect against simultaneous write and truncate */ + +extern void _coh_wait_on_inode (struct inode * inode); + +extern inline void coh_wait_on_inode (struct inode * inode) +{ + if (inode->u.sysv_i.i_lock) + _coh_wait_on_inode(inode); +} + +extern inline void coh_lock_inode (struct inode * inode) +{ + if (inode->u.sysv_i.i_lock) + _coh_wait_on_inode(inode); + inode->u.sysv_i.i_lock = 1; +} + +extern inline void coh_unlock_inode (struct inode * inode) +{ + inode->u.sysv_i.i_lock = 0; + wake_up(&inode->u.sysv_i.i_wait); +} + + +/* + * Function prototypes + */ + +extern int sysv_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern int sysv_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); +extern int sysv_mkdir(struct inode * dir, const char * name, int len, int mode); +extern int sysv_rmdir(struct inode * dir, const char * name, int len); +extern int sysv_unlink(struct inode * dir, const char * name, int len); +extern int sysv_symlink(struct inode * inode, const char * name, int len, + const char * symname); +extern int sysv_link(struct inode * oldinode, struct inode * dir, const char * name, int len); +extern int sysv_mknod(struct inode * dir, const char * name, int len, int mode, int rdev); +extern int sysv_rename(struct inode * old_dir, const char * old_name, int old_len, + struct inode * new_dir, const char * new_name, int new_len); +extern struct inode * sysv_new_inode(const struct inode * dir); +extern void sysv_free_inode(struct inode * inode); +extern unsigned long sysv_count_free_inodes(struct super_block *sb); +extern int sysv_new_block(struct super_block * sb); +extern void sysv_free_block(struct super_block * sb, unsigned int block); +extern unsigned long sysv_count_free_blocks(struct super_block *sb); + +extern int sysv_bmap(struct inode *,int); + +extern struct buffer_head * sysv_getblk(struct inode *, unsigned int, int, char* *); +extern struct buffer_head * sysv_file_bread(struct inode *, int, int, char* *); + +extern void sysv_truncate(struct inode *); +extern void sysv_put_super(struct super_block *); +extern struct super_block *sysv_read_super(struct super_block *,void *,int); +extern void sysv_write_super(struct super_block *); +extern void sysv_read_inode(struct inode *); +extern int sysv_notify_change(int,struct inode *); +extern void sysv_write_inode(struct inode *); +extern void sysv_put_inode(struct inode *); +extern void sysv_statfs(struct super_block *, struct statfs *); +extern int sysv_sync_inode(struct inode *); +extern int sysv_sync_file(struct inode *, struct file *); +#if 0 +extern int sysv_mmap(struct inode *, struct file *, unsigned long, size_t, int, unsigned long); +#endif + +extern struct inode_operations sysv_file_inode_operations; +extern struct inode_operations sysv_file_inode_operations_with_bmap; +extern struct inode_operations sysv_dir_inode_operations; +extern struct inode_operations sysv_symlink_inode_operations; + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_i.h new file mode 100644 index 000000000..87f0b626b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_i.h @@ -0,0 +1,20 @@ +#ifndef _SYSV_FS_I +#define _SYSV_FS_I + +/* + * SystemV/Coherent FS inode data in memory + */ +struct sysv_inode_info { + unsigned long i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks, + * then 1 indirection block, + * then 1 double indirection block, + * then 1 triple indirection block. + */ + /* the following are only used if block_size < BLOCK_SIZE */ + int i_lock; /* lock to protect against simultaneous */ + struct wait_queue * i_wait; /* write and truncate */ + /* */ +}; + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_sb.h new file mode 100644 index 000000000..969268637 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/sysv_fs_sb.h @@ -0,0 +1,104 @@ +#ifndef _SYSV_FS_SB +#define _SYSV_FS_SB + +/* + * SystemV/Coherent super-block data in memory + * The SystemV/Coherent superblock contains dynamic data (it gets modified + * while the system is running). This is in contrast to the Minix and Berkeley + * filesystems (where the superblock is never modified). This affects the + * sync() operation: we must keep the superblock in a disk buffer and use this + * one as our "working copy". + */ + +struct sysv_sb_info { + int s_type; /* file system type: FSTYPE_{XENIX|SYSV|COH} */ + unsigned int s_block_size; /* zone size, = 512 or = 1024 */ + unsigned int s_block_size_1; /* block_size - 1 */ + unsigned int s_block_size_bits; /* log2(block_size) */ + unsigned int s_block_size_ratio; /* BLOCK_SIZE / block_size */ + unsigned int s_block_size_ratio_1; /* block_size_ratio - 1 */ + unsigned int s_block_size_ratio_bits; /* log2(block_size_ratio) */ + char s_convert; /* flag whether byte ordering requires conversion */ + char s_kludge_symlinks; /* flag whether symlinks have a kludgey mode */ + char s_truncate; /* if 1: names > SYSV_NAMELEN chars are truncated */ + /* if 0: they are disallowed (ENAMETOOLONG) */ + nlink_t s_link_max; /* max number of hard links to a file */ + unsigned int s_inodes_per_block; /* number of inodes per block */ + unsigned int s_inodes_per_block_1; /* inodes_per_block - 1 */ + unsigned int s_inodes_per_block_bits; /* log2(inodes_per_block) */ + unsigned int s_ind_per_block; /* number of indirections per block */ + unsigned int s_ind_per_block_1; /* ind_per_block - 1 */ + unsigned int s_ind_per_block_bits; /* log2(ind_per_block) */ + unsigned int s_ind_per_block_2; /* ind_per_block ^ 2 */ + unsigned int s_ind_per_block_2_1; /* ind_per_block ^ 2 - 1 */ + unsigned int s_ind_per_block_2_bits; /* log2(ind_per_block^2) */ + unsigned int s_ind_per_block_3; /* ind_per_block ^ 3 */ + unsigned int s_toobig_block; /* 10 + ipb + ipb^2 + ipb^3 */ + unsigned int s_block_base; /* physical block number of block 0 */ + unsigned short s_fic_size; /* free inode cache size, NICINOD */ + unsigned short s_flc_size; /* free block list chunk size, NICFREE */ + /* The superblock is kept in a disk buffer: */ + struct buffer_head *s_bh; + /* These are pointers into the disk buffer, to compensate for + different superblock layout. */ + char * s_sbd; /* entire superblock data */ + unsigned short *s_sb_fic_count; /* pointer to s_sbd->s_ninode */ + unsigned short *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */ + unsigned short *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */ + unsigned short *s_sb_flc_count; /* pointer to s_sbd->s_nfree */ + unsigned long *s_sb_flc_blocks; /* pointer to s_sbd->s_free */ + unsigned long *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */ + unsigned long *s_sb_time; /* pointer to s_sbd->s_time */ + /* We keep those superblock entities that don't change here; + this saves us an indirection and perhaps a conversion. */ + unsigned long s_firstinodezone; /* index of first inode zone */ + unsigned long s_firstdatazone; /* same as s_sbd->s_isize */ + unsigned long s_ninodes; /* total number of inodes */ + unsigned long s_ndatazones; /* total number of data zones */ + unsigned long s_nzones; /* same as s_sbd->s_fsize */ +}; +/* The fields s_block_size_ratio, s_toobig_block, s_sbd are currently unused. */ + +/* sv_ == u.sysv_sb.s_ */ +#define sv_type u.sysv_sb.s_type +#define sv_block_size u.sysv_sb.s_block_size +#define sv_block_size_1 u.sysv_sb.s_block_size_1 +#define sv_block_size_bits u.sysv_sb.s_block_size_bits +#define sv_block_size_ratio u.sysv_sb.s_block_size_ratio +#define sv_block_size_ratio_1 u.sysv_sb.s_block_size_ratio_1 +#define sv_block_size_ratio_bits u.sysv_sb.s_block_size_ratio_bits +#define sv_convert u.sysv_sb.s_convert +#define sv_kludge_symlinks u.sysv_sb.s_kludge_symlinks +#define sv_truncate u.sysv_sb.s_truncate +#define sv_link_max u.sysv_sb.s_link_max +#define sv_inodes_per_block u.sysv_sb.s_inodes_per_block +#define sv_inodes_per_block_1 u.sysv_sb.s_inodes_per_block_1 +#define sv_inodes_per_block_bits u.sysv_sb.s_inodes_per_block_bits +#define sv_ind_per_block u.sysv_sb.s_ind_per_block +#define sv_ind_per_block_1 u.sysv_sb.s_ind_per_block_1 +#define sv_ind_per_block_bits u.sysv_sb.s_ind_per_block_bits +#define sv_ind_per_block_2 u.sysv_sb.s_ind_per_block_2 +#define sv_ind_per_block_2_1 u.sysv_sb.s_ind_per_block_2_1 +#define sv_ind_per_block_2_bits u.sysv_sb.s_ind_per_block_2_bits +#define sv_ind_per_block_3 u.sysv_sb.s_ind_per_block_3 +#define sv_toobig_block u.sysv_sb.s_toobig_block +#define sv_block_base u.sysv_sb.s_block_base +#define sv_fic_size u.sysv_sb.s_fic_size +#define sv_flc_size u.sysv_sb.s_flc_size +#define sv_bh u.sysv_sb.s_bh +#define sv_sbd u.sysv_sb.s_sbd +#define sv_sb_fic_count u.sysv_sb.s_sb_fic_count +#define sv_sb_fic_inodes u.sysv_sb.s_sb_fic_inodes +#define sv_sb_total_free_inodes u.sysv_sb.s_sb_total_free_inodes +#define sv_sb_flc_count u.sysv_sb.s_sb_flc_count +#define sv_sb_flc_blocks u.sysv_sb.s_sb_flc_blocks +#define sv_sb_total_free_blocks u.sysv_sb.s_sb_total_free_blocks +#define sv_sb_time u.sysv_sb.s_sb_time +#define sv_firstinodezone u.sysv_sb.s_firstinodezone +#define sv_firstdatazone u.sysv_sb.s_firstdatazone +#define sv_ninodes u.sysv_sb.s_ninodes +#define sv_ndatazones u.sysv_sb.s_ndatazones +#define sv_nzones u.sysv_sb.s_nzones + +#endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tasks.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tasks.h new file mode 100644 index 000000000..12facf200 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tasks.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_TASKS_H +#define _LINUX_TASKS_H + +/* + * This is the maximum nr of tasks - change it if you need to + */ +#define NR_TASKS 128 + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tcp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tcp.h new file mode 100644 index 000000000..e666f5106 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tcp.h @@ -0,0 +1,61 @@ +/* + * 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 TCP protocol. + * + * Version: @(#)tcp.h 1.0.2 04/28/93 + * + * Author: Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_TCP_H +#define _LINUX_TCP_H + + +#define HEADER_SIZE 64 /* maximum header size */ + + +struct tcphdr { + unsigned short source; + unsigned short dest; + unsigned long seq; + unsigned long ack_seq; + unsigned short res1:4, + doff:4, + fin:1, + syn:1, + rst:1, + psh:1, + ack:1, + urg:1, + res2:2; + unsigned short window; + unsigned short check; + unsigned short urg_ptr; +}; + + +enum { + TCP_ESTABLISHED = 1, + TCP_SYN_SENT, + TCP_SYN_RECV, +#if 0 + TCP_CLOSING, /* not a valid state, just a seperator so we can use + < tcp_closing or > tcp_closing for checks. */ +#endif + TCP_FIN_WAIT1, + TCP_FIN_WAIT2, + TCP_TIME_WAIT, + TCP_CLOSE, + TCP_CLOSE_WAIT, + TCP_LAST_ACK, + TCP_LISTEN +}; + +#endif /* _LINUX_TCP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/termios.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/termios.h new file mode 100644 index 000000000..a2528bd67 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/termios.h @@ -0,0 +1,243 @@ +#ifndef _LINUX_TERMIOS_H +#define _LINUX_TERMIOS_H + +/* 0x54 is just a magic number to make these relatively uniqe ('T') */ + +#define TCGETS 0x5401 +#define TCSETS 0x5402 +#define TCSETSW 0x5403 +#define TCSETSF 0x5404 +#define TCGETA 0x5405 +#define TCSETA 0x5406 +#define TCSETAW 0x5407 +#define TCSETAF 0x5408 +#define TCSBRK 0x5409 +#define TCXONC 0x540A +#define TCFLSH 0x540B +#define TIOCEXCL 0x540C +#define TIOCNXCL 0x540D +#define TIOCSCTTY 0x540E +#define TIOCGPGRP 0x540F +#define TIOCSPGRP 0x5410 +#define TIOCOUTQ 0x5411 +#define TIOCSTI 0x5412 +#define TIOCGWINSZ 0x5413 +#define TIOCSWINSZ 0x5414 +#define TIOCMGET 0x5415 +#define TIOCMBIS 0x5416 +#define TIOCMBIC 0x5417 +#define TIOCMSET 0x5418 +#define TIOCGSOFTCAR 0x5419 +#define TIOCSSOFTCAR 0x541A +#define FIONREAD 0x541B +#define TIOCINQ FIONREAD +#define TIOCLINUX 0x541C +#define TIOCCONS 0x541D +#define TIOCGSERIAL 0x541E +#define TIOCSSERIAL 0x541F +#define TIOCPKT 0x5420 +#define FIONBIO 0x5421 +#define TIOCNOTTY 0x5422 +#define TIOCSETD 0x5423 +#define TIOCGETD 0x5424 +#define TCSBRKP 0x5425 /* Needed for POSIX tcsendbreak() */ +#define FIONCLEX 0x5450 /* these numbers need to be adjusted. */ +#define FIOCLEX 0x5451 +#define FIOASYNC 0x5452 +#define TIOCSERCONFIG 0x5453 +#define TIOCSERGWILD 0x5454 +#define TIOCSERSWILD 0x5455 +#define TIOCGLCKTRMIOS 0x5456 +#define TIOCSLCKTRMIOS 0x5457 + +/* Used for packet mode */ +#define TIOCPKT_DATA 0 +#define TIOCPKT_FLUSHREAD 1 +#define TIOCPKT_FLUSHWRITE 2 +#define TIOCPKT_STOP 4 +#define TIOCPKT_START 8 +#define TIOCPKT_NOSTOP 16 +#define TIOCPKT_DOSTOP 32 + +struct winsize { + unsigned short ws_row; + unsigned short ws_col; + unsigned short ws_xpixel; + unsigned short ws_ypixel; +}; + +#define NCC 8 +struct termio { + unsigned short c_iflag; /* input mode flags */ + unsigned short c_oflag; /* output mode flags */ + unsigned short c_cflag; /* control mode flags */ + unsigned short c_lflag; /* local mode flags */ + unsigned char c_line; /* line discipline */ + unsigned char c_cc[NCC]; /* control characters */ +}; + +#define NCCS 19 +struct termios { + tcflag_t c_iflag; /* input mode flags */ + tcflag_t c_oflag; /* output mode flags */ + tcflag_t c_cflag; /* control mode flags */ + tcflag_t c_lflag; /* local mode flags */ + cc_t c_line; /* line discipline */ + cc_t c_cc[NCCS]; /* control characters */ +}; + +/* c_cc characters */ +#define VINTR 0 +#define VQUIT 1 +#define VERASE 2 +#define VKILL 3 +#define VEOF 4 +#define VTIME 5 +#define VMIN 6 +#define VSWTC 7 +#define VSTART 8 +#define VSTOP 9 +#define VSUSP 10 +#define VEOL 11 +#define VREPRINT 12 +#define VDISCARD 13 +#define VWERASE 14 +#define VLNEXT 15 +#define VEOL2 16 + +/* c_iflag bits */ +#define IGNBRK 0000001 +#define BRKINT 0000002 +#define IGNPAR 0000004 +#define PARMRK 0000010 +#define INPCK 0000020 +#define ISTRIP 0000040 +#define INLCR 0000100 +#define IGNCR 0000200 +#define ICRNL 0000400 +#define IUCLC 0001000 +#define IXON 0002000 +#define IXANY 0004000 +#define IXOFF 0010000 +#define IMAXBEL 0020000 + +/* c_oflag bits */ +#define OPOST 0000001 +#define OLCUC 0000002 +#define ONLCR 0000004 +#define OCRNL 0000010 +#define ONOCR 0000020 +#define ONLRET 0000040 +#define OFILL 0000100 +#define OFDEL 0000200 +#define NLDLY 0000400 +#define NL0 0000000 +#define NL1 0000400 +#define CRDLY 0003000 +#define CR0 0000000 +#define CR1 0001000 +#define CR2 0002000 +#define CR3 0003000 +#define TABDLY 0014000 +#define TAB0 0000000 +#define TAB1 0004000 +#define TAB2 0010000 +#define TAB3 0014000 +#define XTABS 0014000 +#define BSDLY 0020000 +#define BS0 0000000 +#define BS1 0020000 +#define VTDLY 0040000 +#define VT0 0000000 +#define VT1 0040000 +#define FFDLY 0040000 +#define FF0 0000000 +#define FF1 0040000 + +/* c_cflag bit meaning */ +#define CBAUD 0000017 +#define B0 0000000 /* hang up */ +#define B50 0000001 +#define B75 0000002 +#define B110 0000003 +#define B134 0000004 +#define B150 0000005 +#define B200 0000006 +#define B300 0000007 +#define B600 0000010 +#define B1200 0000011 +#define B1800 0000012 +#define B2400 0000013 +#define B4800 0000014 +#define B9600 0000015 +#define B19200 0000016 +#define B38400 0000017 +#define EXTA B19200 +#define EXTB B38400 +#define CSIZE 0000060 +#define CS5 0000000 +#define CS6 0000020 +#define CS7 0000040 +#define CS8 0000060 +#define CSTOPB 0000100 +#define CREAD 0000200 +#define PARENB 0000400 +#define PARODD 0001000 +#define HUPCL 0002000 +#define CLOCAL 0004000 +#define CIBAUD 03600000 /* input baud rate (not used) */ +#define CRTSCTS 020000000000 /* flow control */ + +/* c_lflag bits */ +#define ISIG 0000001 +#define ICANON 0000002 +#define XCASE 0000004 +#define ECHO 0000010 +#define ECHOE 0000020 +#define ECHOK 0000040 +#define ECHONL 0000100 +#define NOFLSH 0000200 +#define TOSTOP 0000400 +#define ECHOCTL 0001000 +#define ECHOPRT 0002000 +#define ECHOKE 0004000 +#define FLUSHO 0010000 +#define PENDIN 0040000 +#define IEXTEN 0100000 + +/* modem lines */ +#define TIOCM_LE 0x001 +#define TIOCM_DTR 0x002 +#define TIOCM_RTS 0x004 +#define TIOCM_ST 0x008 +#define TIOCM_SR 0x010 +#define TIOCM_CTS 0x020 +#define TIOCM_CAR 0x040 +#define TIOCM_RNG 0x080 +#define TIOCM_DSR 0x100 +#define TIOCM_CD TIOCM_CAR +#define TIOCM_RI TIOCM_RNG + +/* tcflow() and TCXONC use these */ +#define TCOOFF 0 +#define TCOON 1 +#define TCIOFF 2 +#define TCION 3 + +/* tcflush() and TCFLSH use these */ +#define TCIFLUSH 0 +#define TCOFLUSH 1 +#define TCIOFLUSH 2 + +/* tcsetattr uses these */ +#define TCSANOW 0 +#define TCSADRAIN 1 +#define TCSAFLUSH 2 + +/* line disciplines */ +#define N_TTY 0 +#define N_SLIP 1 +#define N_MOUSE 2 +#define N_PPP 3 + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/time.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/time.h new file mode 100644 index 000000000..65891b748 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/time.h @@ -0,0 +1,35 @@ +#ifndef _LINUX_TIME_H +#define _LINUX_TIME_H + +struct timeval { + long tv_sec; /* seconds */ + long tv_usec; /* microseconds */ +}; + +struct timezone { + int tz_minuteswest; /* minutes west of Greenwich */ + int tz_dsttime; /* type of dst correction */ +}; + +#define NFDBITS __NFDBITS + +#define FD_SETSIZE __FD_SETSIZE +#define FD_SET(fd,fdsetp) __FD_SET(fd,fdsetp) +#define FD_CLR(fd,fdsetp) __FD_CLR(fd,fdsetp) +#define FD_ISSET(fd,fdsetp) __FD_ISSET(fd,fdsetp) +#define FD_ZERO(fdsetp) __FD_ZERO(fdsetp) + +/* + * Names of the interval timers, and structure + * defining a timer setting. + */ +#define ITIMER_REAL 0 +#define ITIMER_VIRTUAL 1 +#define ITIMER_PROF 2 + +struct itimerval { + struct timeval it_interval; /* timer interval */ + struct timeval it_value; /* current value */ +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timer.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timer.h new file mode 100644 index 000000000..ad23e32d6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timer.h @@ -0,0 +1,86 @@ +#ifndef _LINUX_TIMER_H +#define _LINUX_TIMER_H + +/* + * DON'T CHANGE THESE!! Most of them are hardcoded into some assembly language + * as well as being defined here. + */ + +/* + * The timers are: + * + * BLANK_TIMER console screen-saver timer + * + * BEEP_TIMER console beep timer + * + * RS_TIMER timer for the RS-232 ports + * + * HD_TIMER harddisk timer + * + * HD_TIMER2 (atdisk2 patches) + * + * FLOPPY_TIMER floppy disk timer (not used right now) + * + * SCSI_TIMER scsi.c timeout timer + * + * NET_TIMER tcp/ip timeout timer + * + * COPRO_TIMER 387 timeout for buggy hardware.. + * + * TAPE_QIC02_TIMER timer for QIC-02 tape driver (it's not hardcoded) + * + * MCD_TIMER Mitsumi CD-ROM Timer + * + * SBPCD_TIMER SoundBlaster/Matsushita/Panasonic CD-ROM timer + */ + +#define BLANK_TIMER 0 +#define BEEP_TIMER 1 +#define RS_TIMER 2 + +#define HD_TIMER 16 +#define FLOPPY_TIMER 17 +#define SCSI_TIMER 18 +#define NET_TIMER 19 +#define SOUND_TIMER 20 +#define COPRO_TIMER 21 + +#define TAPE_QIC02_TIMER 22 /* hhb */ +#define MCD_TIMER 23 + +#define HD_TIMER2 24 + +#define SBPCD_TIMER 25 + +struct timer_struct { + unsigned long expires; + void (*fn)(void); +}; + +extern unsigned long timer_active; +extern struct timer_struct timer_table[32]; + +/* + * This is completely separate from the above, and is the + * "new and improved" way of handling timers more dynamically. + * Hopefully efficient and general enough for most things. + * + * The "hardcoded" timers above are still useful for well- + * defined problems, but the timer-list is probably better + * when you need multiple outstanding timers or similar. + * + * The "data" field is in case you want to use the same + * timeout function for several timeouts. You can use this + * to distinguish between the different invocations. + */ +struct timer_list { + struct timer_list *next; + unsigned long expires; + unsigned long data; + void (*function)(unsigned long); +}; + +extern void add_timer(struct timer_list * timer); +extern int del_timer(struct timer_list * timer); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/times.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/times.h new file mode 100644 index 000000000..569349ef4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/times.h @@ -0,0 +1,11 @@ +#ifndef _LINUX_TIMES_H +#define _LINUX_TIMES_H + +struct tms { + clock_t tms_utime; + clock_t tms_stime; + clock_t tms_cutime; + clock_t tms_cstime; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timex.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timex.h new file mode 100644 index 000000000..bf4b3900c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/timex.h @@ -0,0 +1,142 @@ +/***************************************************************************** + * * + * 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 + +/* + * 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) */ + long tick; /* (modified) usecs between clock ticks */ +}; + +/* + * 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 */ +#define ADJ_TICK 0x4000 /* tick value */ +#define ADJ_OFFSET_SINGLESHOT 0x8001 /* old-fashioned adjtime */ + +/* + * 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 */ + +#ifdef __KERNEL__ +/* + * 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/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tpqic02.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tpqic02.h new file mode 100644 index 000000000..56f676de3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/tpqic02.h @@ -0,0 +1,374 @@ +/* $Id: tpqic02.h,v 0.16 1993/04/19 23:15:39 root Exp root $ + * + * Include file for QIC-02 driver for Linux. + * + * Copyright (c) 1992 by H. H. Bergman. All rights reserved. + * + * ******* USER CONFIG SECTION BELOW ******* + */ + +#ifndef _LINUX_TPQIC02_H +#define _LINUX_TPQIC02_H + +#include + +#if CONFIG_TAPE_QIC02 + +/* need to have TAPE_QIC02_DRIVE and TAPE_QIC02_IFC expand to something */ +#include + + +/* make TAPE_QIC02_IFC expand to something */ +#define WANGTEK 1 /* don't know about Wangtek QIC-36 */ +#define EVEREX WANGTEK /* I heard *some* of these are identical */ +#define EVEREX_811V EVEREX /* With TEAC MT 2ST 45D */ +#define EVEREX_831V EVEREX +#define ARCHIVE 3 +#define ARCHIVE_SC400 ARCHIVE /* rumoured to be from the pre-SMD-age */ +#define ARCHIVE_SC402 ARCHIVE /* don't know much about SC400 */ +#define ARCHIVE_SC499 ARCHIVE /* SC402 and SC499R should be identical */ + + +/*********** START OF USER CONFIGURABLE SECTION ************/ + +/* Tape configuration: + * + * Tape drive configuration: (MT_IS* constants are defined in sys/mtio.h) + * + * TAPE_QIC02_DRIVE = MT_ISWT5150 + * - Wangtek 5150, format: up to QIC-150. + * TAPE_QIC02_DRIVE = MT_ISQIC02_ALL_FEATURES + * - Enables some optional QIC commands that some drives may lack. + * It is provided so you can check which are supported by your drive. + * Refer to tpqic02.h for others. + * + * Supported interface cards: TAPE_QIC02_IFC = + * WANGTEK, + * ARCHIVE_SC402, ARCHIVE_SC499. (both same programming interface) + * + * Make sure you have the I/O ports/DMA channels + * and IRQ stuff configured properly! + * NOTE: Check for conflicts with TAPE_QIC02_TIMER in timer.h. + */ + +#define TAPE_QIC02_DRIVE MT_ISQIC02_ALL_FEATURES /* drive type */ +/* #define TAPE_QIC02_DRIVE MT_ISWT5150 */ +#define TAPE_QIC02_IFC WANGTEK /* interface card type */ +/* #define TAPE_QIC02_IFC ARCHIVE */ +#define TAPE_QIC02_PORT 0x300 /* controller port adress */ +#define TAPE_QIC02_IRQ 5 /* Muhammad, please don't use 2 here. -- Hennus */ +#define TAPE_QIC02_DMA 1 /* either 1 or 3, because 2 is used by the floppy */ + + +/************ END OF USER CONFIGURABLE SECTION *************/ + + +/* NOTE: TP_HAVE_DENS should distinguish between available densities + * NOTE: Drive select is not implemented -- I have only one tape streamer, + * so I'm unable and unmotivated to test and implement that. ;-) ;-) + */ +#if TAPE_QIC02_DRIVE == MT_ISWT5150 +#define TP_HAVE_DENS +#define TP_HAVE_BSF /* nope */ +#define TP_HAVE_FSR /* nope */ +#define TP_HAVE_BSR /* nope */ +#define TP_HAVE_EOD /* most of the time */ +#define TP_HAVE_RAS1 +#define TP_HAVE_RAS2 + +#elif TAPE_QIC02_DRIVE == MT_ISARCHIVESC499 /* Archive SC-499 QIC-36 controller */ +#define TP_HAVE_DENS /* can do set density (QIC-11 / QIC-24) */ +#define TP_HAVE_FSR /* can skip one block forwards */ +#define TP_HAVE_BSR /* can skip one block backwards */ +#define TP_HAVE_EOD /* can seek to end of recorded data */ +#define TP_HAVE_RAS1 /* can run selftest 1 */ +#define TP_HAVE_RAS2 /* can run selftest 2 */ +/* These last two selftests shouldn't be used yet! */ + +#elif (TAPE_QIC02_DRIVE == MT_ISARCHIVE_2060L) || (TAPE_QIC02_DRIVE == MT_ISARCHIVE_2150L) +#define TP_HAVE_DENS /* can do set density (QIC-24 / QIC-120 / QIC-150) */ +#define TP_HAVE_FSR /* can skip one block forwards */ +#define TP_HAVE_BSR /* can skip one block backwards */ +#define TP_HAVE_EOD /* can seek to end of recorded data */ +#define TP_HAVE_TELL /* can read current block address */ +#define TP_HAVE_SEEK /* can seek to block */ +#define TP_HAVE_RAS1 /* can run selftest 1 */ +#define TP_HAVE_RAS2 /* can run selftest 2 */ +/* These last two selftests shouldn't be used yet! */ + +#elif TAPE_QIC02_DRIVE == MT_ISQIC02_ALL_FEATURES +#define TP_HAVE_DENS /* can do set density */ +#define TP_HAVE_BSF /* can search filemark backwards */ +#define TP_HAVE_FSR /* can skip one block forwards */ +#define TP_HAVE_BSR /* can skip one block backwards */ +#define TP_HAVE_EOD /* can seek to end of recorded data */ +#define TP_HAVE_SEEK /* seek to block address */ +#define TP_HAVE_TELL /* tell current block address */ +#define TP_HAVE_RAS1 /* can run selftest 1 */ +#define TP_HAVE_RAS2 /* can run selftest 2 */ +/* These last two selftests shouldn't be used yet! */ + + +#else +#error No QIC-02 tape drive type defined! +/* If your drive is not listed above, first try the 'ALL_FEATURES', + * to see what commands are supported, then create your own entry in + * the list above. You may want to mail it to me, so that I can include + * it in the next release. + */ +#endif + + +/* NR_BLK_BUF is a `tuneable parameter'. If you're really low on + * kernel space, you could decrease it to 1, or if you got a very + * slow machine, you could increase it up to 128 blocks. Less kernel + * buffer blocks result in more context-switching. + */ +#define NR_BLK_BUF 20 /* max 128 blocks */ +#define TAPE_BLKSIZE 512 /* streamer tape block size (fixed) */ +#define TPQBUF_SIZE (TAPE_BLKSIZE*NR_BLK_BUF) /* buffer size */ + + +#define BLOCKS_BEYOND_EW 2 /* nr of blocks after Early Warning hole */ + +#if TAPE_QIC02_IFC == WANGTEK + /* Wangtek interface card port locations */ +# define QIC_STAT_PORT TAPE_QIC02_PORT +# define QIC_CTL_PORT TAPE_QIC02_PORT +# define QIC_CMD_PORT (TAPE_QIC02_PORT+1) +# define QIC_DATA_PORT (TAPE_QIC02_PORT+1) + +/* status register bits (Active LOW!) */ +# define QIC_STAT_READY 0x01 +# define QIC_STAT_EXCEPTION 0x02 +# define QIC_STAT_MASK (QIC_STAT_READY|QIC_STAT_EXCEPTION) + +# define QIC_STAT_RESETMASK 0x07 +# define QIC_STAT_RESETVAL (QIC_STAT_RESETMASK & ~QIC_STAT_EXCEPTION) + +/* controller register (QIC_CTL_PORT) bits */ +# define WT_CTL_ONLINE 0x01 +# define QIC_CTL_RESET 0x02 +# define QIC_CTL_REQUEST 0x04 +# define WT_CTL_CMDOFF 0xC0 +# if TAPE_QIC02_DMA == 3 /* dip-switches alone don't seem to cut it */ +# define WT_CTL_DMA 0x10 /* enable dma chan3 */ +# elif TAPE_QIC02_DMA == 1 +# define WT_CTL_DMA 0x08 /* enable dma chan1 or chan2 */ +# else +# error Unsupported or incorrect DMA configuration. +# endif + +#elif TAPE_QIC02_IFC == ARCHIVE + /* Archive interface card port locations */ +# define QIC_STAT_PORT (TAPE_QIC02_PORT+1) +# define QIC_CTL_PORT (TAPE_QIC02_PORT+1) +# define QIC_CMD_PORT (TAPE_QIC02_PORT) +# define QIC_DATA_PORT (TAPE_QIC02_PORT) +# define AR_START_DMA_PORT (TAPE_QIC02_PORT+2) +# define AR_RESET_DMA_PORT (TAPE_QIC02_PORT+3) + + /* STAT port bits */ +# define AR_STAT_IRQF 0x80 /* active high, interrupt request flag */ +# define QIC_STAT_READY 0x40 /* active low */ +# define QIC_STAT_EXCEPTION 0x20 /* active low */ +# define QIC_STAT_MASK (QIC_STAT_READY|QIC_STAT_EXCEPTION) +# define AR_STAT_DMADONE 0x10 /* active high, DMA done */ +# define AR_STAT_DIRC 0x08 /* active high, direction */ + +# define QIC_STAT_RESETMASK 0x70 /* check RDY,EXC,DMADONE */ +# define QIC_STAT_RESETVAL ((QIC_STAT_RESETMASK & ~AR_STAT_IRQF & ~QIC_STAT_EXCEPTION) | AR_STAT_DMADONE) + + /* CTL port bits */ +# define QIC_CTL_RESET 0x80 /* drive reset */ +# define QIC_CTL_REQUEST 0x40 /* notify of new command */ +# define AR_CTL_IEN 0x20 /* interrupt enable */ +# define AR_CTL_DNIEN 0x10 /* done-interrupt enable */ + /* Note: All of these bits are cleared automatically when writing to + * AR_RESET_DMA_PORT. So AR_CTL_IEN and AR_CTL_DNIEN must be + * reprogrammed before the write to AR_START_DMA_PORT. + */ + +# if TAPE_QIC02_DMA > 3 /* channel 2 is used by the floppy driver */ +# error DMA channels other than 1 and 3 are not supported. +# endif + +#else +# error No valid interface card specified! +#endif /* TAPE_QIC02_IFC */ + +/* Standard QIC-02 commands -- rev F. All QIC-02 drives must support these */ +#define QCMD_SEL_1 0x01 /* select drive 1 */ +#define QCMD_SEL_2 0x02 /* select drive 2 */ +#define QCMD_SEL_3 0x04 /* select drive 3 */ +#define QCMD_SEL_4 0x08 /* select drive 4 */ +#define QCMD_REWIND 0x21 /* rewind tape*/ +#define QCMD_ERASE 0x22 /* erase tape */ +#define QCMD_RETEN 0x24 /* retension tape */ +#define QCMD_WRT_DATA 0x40 /* write data */ +#define QCMD_WRT_FM 0x60 /* write file mark */ +#define QCMD_RD_DATA 0x80 /* read data */ +#define QCMD_RD_FM 0xA0 /* read file mark (forward direction) */ +#define QCMD_RD_STAT 0xC0 /* read status */ + +/* Other (optional/vendor unique) commands */ + /* Density commands are only valid when TP_BOM is set! */ +#define QCMD_DENS_11 0x26 /* QIC-11 */ +#define QCMD_DENS_24 0x27 /* QIC-24: 9 track 60MB */ +#define QCMD_DENS_120 0x28 /* QIC-120: 15 track 120MB */ +#define QCMD_DENS_150 0x29 /* QIC-150: 18 track 150MB */ +#define QCMD_DENS_300 0x2A /* QIC-300/QIC-2100 */ +#define QCMD_DENS_600 0x2B /* QIC-600/QIC-2200 */ +/* don't know about QIC-1000 and QIC-1350 */ + +#define QCMD_WRTNU_DATA 0x40 /* write data, no underruns, insert filler. */ +#define QCMD_SPACE_FWD 0x81 /* skip next block */ +#define QCMD_SPACE_BCK 0x89 /* move tape head one block back -- very useful! */ +#define QCMD_RD_FM_BCK 0xA8 /* read filemark (backwards) */ +#define QCMD_SEEK_EOD 0xA3 /* skip to EOD */ +#define QCMD_RD_STAT_X1 0xC1 /* read extended status 1 */ +#define QCMD_RD_STAT_X2 0xC4 /* read extended status 2 */ +#define QCMD_RD_STAT_X3 0xE0 /* read extended status 3 */ +#define QCMD_SELF_TST1 0xC2 /* run self test 1 (nondestructive) */ +#define QCMD_SELF_TST2 0xCA /* run self test 2 (destructive) */ + + + +/* "Vendor Unique" codes */ +#if defined(MT_ISARCHIVESC499) || defined(MT_ISARCHIVE_2150L) +# define QCMDV_TELL_BLK 0xAE /* read current block address */ +# define QCMDV_SEEK_BLK 0xAD /* seek to specific block */ +# define SEEK_BUF_SIZE 3 /* address is 3 bytes */ +#endif + + +/* Optional, QFA (Quick File Access) commands. + * Not all drives support this, but those that do could use these commands + * to implement semi-non-sequential access. `mt fsf` would benefit from this. + * QFA divides the tape into 2 partitions, a data and a directory partition, + * causing some incompatibility problems wrt std QIC-02 data exchange. + * It would be useful to cache the directory info, but that might be tricky + * to do in kernel-space. [Size constraints.] + * Refer to QIC-02, appendix A for more information. + * I have no idea how other *nix variants implement QFA. + * I have no idea which drives support QFA and which don't. + */ +#define QFA_ENABLE 0x2D /* enter QFA mode, give @ BOT only */ +#define QFA_DATA 0x20 /* select data partition */ +#define QFA_DIR 0x23 /* select directory partition */ +#define QFA_RD_POS 0xCF /* read position+status bytes */ +#define QFA_SEEK_EOD 0xA1 /* seek EOD within current partition */ +#define QFA_SEEK_BLK 0xAF /* seek to a block within current partition */ + + + +/* Minor device codes for tapes: + * |7|6|5|4|3|2|1|0| + * | \ | / \ | / |_____ 1=rewind on close, 0=no rewind on close + * | \|/ |_________ Density: 000=none, 001=QIC-11, 010=24, 011=120, + * | | 100=QIC-150, 101..111 reserved. + * | |_______________ Reserved for unit numbers. + * |___________________ Reserved for diagnostics during debugging. + */ + +#define TP_REWCLOSE(d) ((MINOR(d)&0x01) == 1) /* rewind bit */ + /* rewind is only done if data has been transfered */ +#define TP_DENS(dev) ((MINOR(dev) >> 1) & 0x07) /* tape density */ +#define TP_UNIT(dev) ((MINOR(dev) >> 4) & 0x07) /* unit number */ +#define TP_DIAGS(dev) (MINOR(dev) & 0x80) /* print excessive diagnostics */ + + +/* status codes returned by a WTS_RDSTAT call */ +struct tpstatus { /* sizeof(short)==2), LSB first */ + unsigned short exs; /* Drive exception flags */ + unsigned short dec; /* data error count: nr of blocks rewritten/soft read errors */ + unsigned short urc; /* underrun count: nr of times streaming was interrupted */ +}; +#define TPSTATSIZE sizeof(struct tpstatus) + + +/* defines for tpstatus.exs -- taken from 386BSD wt driver */ +#define TP_POR 0x100 /* Power on or reset occurred */ +#define TP_EOR 0x200 /* REServed for end of RECORDED media */ +#define TP_PAR 0x400 /* REServed for bus parity */ +#define TP_BOM 0x800 /* Beginning of media */ +#define TP_MBD 0x1000 /* Marginal block detected */ +#define TP_NDT 0x2000 /* No data detected */ +#define TP_ILL 0x4000 /* Illegal command */ +#define TP_ST1 0x8000 /* Status byte 1 flag */ +#define TP_FIL 0x01 /* File mark detected */ +#define TP_BNL 0x02 /* Bad block not located */ +#define TP_UDA 0x04 /* Unrecoverable data error */ +#define TP_EOM 0x08 /* End of media */ +#define TP_WRP 0x10 /* Write protected cartridge */ +#define TP_USL 0x20 /* Unselected drive */ +#define TP_CNI 0x40 /* Cartridge not in place */ +#define TP_ST0 0x80 /* Status byte 0 flag */ + +#define REPORT_ERR0 (TP_CNI|TP_USL|TP_WRP|TP_EOM|TP_UDA|TP_BNL|TP_FIL) +#define REPORT_ERR1 (TP_ILL|TP_NDT|TP_MBD|TP_PAR) + + +#define EXC_UNKNOWN 0 /* (extra) Unknown exception code */ +#define EXC_NCART 1 /* No cartridge */ +#define EXC_NDRV 2 /* No drive */ +#define EXC_WP 3 /* Write protected */ +#define EXC_EOM 4 /* EOM */ +#define EXC_RWA 5 /* read/write abort */ +#define EXC_XBAD 6 /* read error, bad block transfered */ +#define EXC_XFILLER 7 /* read error, filler block transfered */ +#define EXC_NDT 8 /* read error, no data */ +#define EXC_NDTEOM 9 /* read error, no data & EOM */ +#define EXC_NDTBOM 10 /* read error, no data & BOM */ +#define EXC_FM 11 /* Read a filemark */ +#define EXC_ILL 12 /* Illegal command */ +#define EXC_POR 13 /* Power on/reset */ +#define EXC_MARGINAL 14 /* Marginal block detected */ +#define EXC_EOR 15 /* (extra, for SEEKEOD) End Of Recorded data reached */ +#define EXC_BOM 16 /* (extra) BOM reached */ + + +#define TAPE_NOTIFY_TIMEOUT 1000000 + +/* internal function return codes */ +#define TE_OK 0 /* everything is fine */ +#define TE_EX 1 /* exception detected */ +#define TE_ERR 2 /* some error */ +#define TE_NS 3 /* can't read status */ +#define TE_TIM 4 /* timed out */ +#define TE_DEAD 5 /* tape drive doesn't respond */ +#define TE_END 6 /******** Archive hack *****/ + +/* timeout timer values -- check these! */ +#define TIM_S (4*HZ) /* 4 seconds (normal cmds) */ +#define TIM_M (30*HZ) /* 30 seconds (write FM) */ +#define TIM_R (8*60*HZ) /* 8 minutes (retensioning) */ +#define TIM_F (2*3600*HZ) /* est. 1.2hr for full tape read/write+2 retens */ + +#define TIMERON(t) timer_table[TAPE_QIC02_TIMER].expires = jiffies + (t); \ + timer_active |= (1< + +#include + +#define NR_CONSOLES 8 +#define NR_LDISCS 16 + +/* + * These are set up by the setup-routine at boot-time: + */ + +struct screen_info { + unsigned char orig_x; + unsigned char orig_y; + unsigned char unused1[2]; + unsigned short orig_video_page; + unsigned char orig_video_mode; + unsigned char orig_video_cols; + unsigned short orig_video_ega_ax; + unsigned short orig_video_ega_bx; + unsigned short orig_video_ega_cx; + unsigned char orig_video_lines; +}; + +extern struct screen_info screen_info; + +#define ORIG_X (screen_info.orig_x) +#define ORIG_Y (screen_info.orig_y) +#define ORIG_VIDEO_PAGE (screen_info.orig_video_page) +#define ORIG_VIDEO_MODE (screen_info.orig_video_mode) +#define ORIG_VIDEO_COLS (screen_info.orig_video_cols) +#define ORIG_VIDEO_EGA_AX (screen_info.orig_video_ega_ax) +#define ORIG_VIDEO_EGA_BX (screen_info.orig_video_ega_bx) +#define ORIG_VIDEO_EGA_CX (screen_info.orig_video_ega_cx) +#define ORIG_VIDEO_LINES (screen_info.orig_video_lines) + +#define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ +#define VIDEO_TYPE_CGA 0x11 /* CGA Display */ +#define VIDEO_TYPE_EGAM 0x20 /* EGA/VGA in Monochrome Mode */ +#define VIDEO_TYPE_EGAC 0x21 /* EGA/VGA in Color Mode */ + +/* + * This character is the same as _POSIX_VDISABLE: it cannot be used as + * a c_cc[] character, but indicates that a particular special character + * isn't in use (eg VINTR ahs no character etc) + */ +#define __DISABLED_CHAR '\0' + +/* + * See comment for the tty_struct structure before changing + * TTY_BUF_SIZE. Actually, there should be different sized tty_queue + * structures for different purposes. 1024 bytes for the transmit + * queue is way overkill. TYT, 9/14/92 + */ +#define TTY_BUF_SIZE 1024 /* Must be a power of 2 */ + +struct tty_queue { + unsigned long head; + unsigned long tail; + struct wait_queue * proc_list; + unsigned char buf[TTY_BUF_SIZE]; +}; + +struct serial_struct { + int type; + int line; + int port; + int irq; + int flags; + int xmit_fifo_size; + int custom_divisor; + int baud_base; + unsigned short close_delay; + char reserved_char[2]; + int hub6; + int reserved[5]; +}; + +/* + * These are the supported serial types. + */ +#define PORT_UNKNOWN 0 +#define PORT_8250 1 +#define PORT_16450 2 +#define PORT_16550 3 +#define PORT_16550A 4 +#define PORT_MAX 4 + +/* + * Definitions for async_struct (and serial_struct) flags field + */ +#define ASYNC_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define ASYNC_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define ASYNC_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define ASYNC_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define ASYNC_SPD_MASK 0x0030 +#define ASYNC_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ +#define ASYNC_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ASYNC_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define ASYNC_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define ASYNC_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define ASYNC_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define ASYNC_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define ASYNC_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define ASYNC_FLAGS 0x0FFF /* Possible legal async flags */ +#define ASYNC_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define ASYNC_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ASYNC_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ASYNC_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ASYNC_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ASYNC_CLOSING 0x08000000 /* Serial port is closing */ + +#define IS_A_CONSOLE(min) (((min) & 0xC0) == 0x00) +#define IS_A_SERIAL(min) (((min) & 0xC0) == 0x40) +#define IS_A_PTY(min) ((min) & 0x80) +#define IS_A_PTY_MASTER(min) (((min) & 0xC0) == 0x80) +#define IS_A_PTY_SLAVE(min) (((min) & 0xC0) == 0xC0) +#define PTY_OTHER(min) ((min) ^ 0x40) + +#define SL_TO_DEV(line) ((line) | 0x40) +#define DEV_TO_SL(min) ((min) & 0x3F) + +#define INC(a) ((a) = ((a)+1) & (TTY_BUF_SIZE-1)) +#define DEC(a) ((a) = ((a)-1) & (TTY_BUF_SIZE-1)) +#define EMPTY(a) ((a)->head == (a)->tail) +#define LEFT(a) (((a)->tail-(a)->head-1)&(TTY_BUF_SIZE-1)) +#define LAST(a) ((a)->buf[(TTY_BUF_SIZE-1)&((a)->head-1)]) +#define FULL(a) (!LEFT(a)) +#define CHARS(a) (((a)->head-(a)->tail)&(TTY_BUF_SIZE-1)) + +extern void put_tty_queue(unsigned char c, struct tty_queue * queue); +extern int get_tty_queue(struct tty_queue * queue); + +#define INTR_CHAR(tty) ((tty)->termios->c_cc[VINTR]) +#define QUIT_CHAR(tty) ((tty)->termios->c_cc[VQUIT]) +#define ERASE_CHAR(tty) ((tty)->termios->c_cc[VERASE]) +#define KILL_CHAR(tty) ((tty)->termios->c_cc[VKILL]) +#define EOF_CHAR(tty) ((tty)->termios->c_cc[VEOF]) +#define TIME_CHAR(tty) ((tty)->termios->c_cc[VTIME]) +#define MIN_CHAR(tty) ((tty)->termios->c_cc[VMIN]) +#define SWTC_CHAR(tty) ((tty)->termios->c_cc[VSWTC]) +#define START_CHAR(tty) ((tty)->termios->c_cc[VSTART]) +#define STOP_CHAR(tty) ((tty)->termios->c_cc[VSTOP]) +#define SUSP_CHAR(tty) ((tty)->termios->c_cc[VSUSP]) +#define EOL_CHAR(tty) ((tty)->termios->c_cc[VEOL]) +#define REPRINT_CHAR(tty) ((tty)->termios->c_cc[VREPRINT]) +#define DISCARD_CHAR(tty) ((tty)->termios->c_cc[VDISCARD]) +#define WERASE_CHAR(tty) ((tty)->termios->c_cc[VWERASE]) +#define LNEXT_CHAR(tty) ((tty)->termios->c_cc[VLNEXT]) +#define EOL2_CHAR(tty) ((tty)->termios->c_cc[VEOL2]) + +#define _I_FLAG(tty,f) ((tty)->termios->c_iflag & (f)) +#define _O_FLAG(tty,f) ((tty)->termios->c_oflag & (f)) +#define _C_FLAG(tty,f) ((tty)->termios->c_cflag & (f)) +#define _L_FLAG(tty,f) ((tty)->termios->c_lflag & (f)) + +#define I_IGNBRK(tty) _I_FLAG((tty),IGNBRK) +#define I_BRKINT(tty) _I_FLAG((tty),BRKINT) +#define I_IGNPAR(tty) _I_FLAG((tty),IGNPAR) +#define I_PARMRK(tty) _I_FLAG((tty),PARMRK) +#define I_INPCK(tty) _I_FLAG((tty),INPCK) +#define I_ISTRIP(tty) _I_FLAG((tty),ISTRIP) +#define I_INLCR(tty) _I_FLAG((tty),INLCR) +#define I_IGNCR(tty) _I_FLAG((tty),IGNCR) +#define I_ICRNL(tty) _I_FLAG((tty),ICRNL) +#define I_IUCLC(tty) _I_FLAG((tty),IUCLC) +#define I_IXON(tty) _I_FLAG((tty),IXON) +#define I_IXANY(tty) _I_FLAG((tty),IXANY) +#define I_IXOFF(tty) _I_FLAG((tty),IXOFF) +#define I_IMAXBEL(tty) _I_FLAG((tty),IMAXBEL) + +#define O_OPOST(tty) _O_FLAG((tty),OPOST) +#define O_OLCUC(tty) _O_FLAG((tty),OLCUC) +#define O_ONLCR(tty) _O_FLAG((tty),ONLCR) +#define O_OCRNL(tty) _O_FLAG((tty),OCRNL) +#define O_ONOCR(tty) _O_FLAG((tty),ONOCR) +#define O_ONLRET(tty) _O_FLAG((tty),ONLRET) +#define O_OFILL(tty) _O_FLAG((tty),OFILL) +#define O_OFDEL(tty) _O_FLAG((tty),OFDEL) +#define O_NLDLY(tty) _O_FLAG((tty),NLDLY) +#define O_CRDLY(tty) _O_FLAG((tty),CRDLY) +#define O_TABDLY(tty) _O_FLAG((tty),TABDLY) +#define O_BSDLY(tty) _O_FLAG((tty),BSDLY) +#define O_VTDLY(tty) _O_FLAG((tty),VTDLY) +#define O_FFDLY(tty) _O_FLAG((tty),FFDLY) + +#define C_BAUD(tty) _C_FLAG((tty),CBAUD) +#define C_CSIZE(tty) _C_FLAG((tty),CSIZE) +#define C_CSTOPB(tty) _C_FLAG((tty),CSTOPB) +#define C_CREAD(tty) _C_FLAG((tty),CREAD) +#define C_PARENB(tty) _C_FLAG((tty),PARENB) +#define C_PARODD(tty) _C_FLAG((tty),PARODD) +#define C_HUPCL(tty) _C_FLAG((tty),HUPCL) +#define C_CLOCAL(tty) _C_FLAG((tty),CLOCAL) +#define C_CIBAUD(tty) _C_FLAG((tty),CIBAUD) +#define C_CRTSCTS(tty) _C_FLAG((tty),CRTSCTS) + +#define L_ISIG(tty) _L_FLAG((tty),ISIG) +#define L_ICANON(tty) _L_FLAG((tty),ICANON) +#define L_XCASE(tty) _L_FLAG((tty),XCASE) +#define L_ECHO(tty) _L_FLAG((tty),ECHO) +#define L_ECHOE(tty) _L_FLAG((tty),ECHOE) +#define L_ECHOK(tty) _L_FLAG((tty),ECHOK) +#define L_ECHONL(tty) _L_FLAG((tty),ECHONL) +#define L_NOFLSH(tty) _L_FLAG((tty),NOFLSH) +#define L_TOSTOP(tty) _L_FLAG((tty),TOSTOP) +#define L_ECHOCTL(tty) _L_FLAG((tty),ECHOCTL) +#define L_ECHOPRT(tty) _L_FLAG((tty),ECHOPRT) +#define L_ECHOKE(tty) _L_FLAG((tty),ECHOKE) +#define L_FLUSHO(tty) _L_FLAG((tty),FLUSHO) +#define L_PENDIN(tty) _L_FLAG((tty),PENDIN) +#define L_IEXTEN(tty) _L_FLAG((tty),IEXTEN) + +/* + * Where all of the state associated with a tty is kept while the tty + * is open. Since the termios state should be kept even if the tty + * has been closed --- for things like the baud rate, etc --- it is + * not stored here, but rather a pointer to the real state is stored + * here. Possible the winsize structure should have the same + * treatment, but (1) the default 80x24 is usually right and (2) it's + * most often used by a windowing system, which will set the correct + * size each time the window is created or resized anyway. + * IMPORTANT: since this structure is dynamically allocated, it must + * be no larger than 4096 bytes. Changing TTY_BUF_SIZE will change + * the size of this structure, and it needs to be done with care. + * - TYT, 9/14/92 + */ +struct tty_struct { + struct termios *termios; + int pgrp; + int session; + unsigned char stopped:1, hw_stopped:1, packet:1, lnext:1; + unsigned char char_error:3; + unsigned char erasing:1; + unsigned char ctrl_status; + short line; + int disc; + int flags; + int count; + unsigned int column; + struct winsize winsize; + int (*open)(struct tty_struct * tty, struct file * filp); + void (*close)(struct tty_struct * tty, struct file * filp); + void (*write)(struct tty_struct * tty); + int (*ioctl)(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg); + void (*throttle)(struct tty_struct * tty, int status); + void (*set_termios)(struct tty_struct *tty, struct termios * old); + void (*stop)(struct tty_struct *tty); + void (*start)(struct tty_struct *tty); + void (*hangup)(struct tty_struct *tty); + struct tty_struct *link; + unsigned char *write_data_ptr; + int write_data_cnt; + void (*write_data_callback)(void * data); + void * write_data_arg; + int readq_flags[TTY_BUF_SIZE/32]; + int secondary_flags[TTY_BUF_SIZE/32]; + int canon_data; + unsigned long canon_head; + unsigned int canon_column; + struct tty_queue read_q; + struct tty_queue write_q; + struct tty_queue secondary; + void *disc_data; +}; + +struct tty_ldisc { + int flags; + /* + * The following routines are called from above. + */ + int (*open)(struct tty_struct *); + void (*close)(struct tty_struct *); + int (*read)(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr); + int (*write)(struct tty_struct * tty, struct file * file, + unsigned char * buf, unsigned int nr); + int (*ioctl)(struct tty_struct * tty, struct file * file, + unsigned int cmd, unsigned long arg); + int (*select)(struct tty_struct * tty, struct inode * inode, + struct file * file, int sel_type, + struct select_table_struct *wait); + /* + * The following routines are called from below. + */ + void (*handler)(struct tty_struct *); +}; + +#define LDISC_FLAG_DEFINED 0x00000001 + +/* + * These are the different types of thottle status which can be sent + * to the low-level tty driver. The tty_io.c layer is responsible for + * notifying the low-level tty driver of the following conditions: + * secondary queue full, secondary queue available, and read queue + * available. The low-level driver must send the read queue full + * command to itself, if it is interested in that condition. + * + * Note that the low-level tty driver may elect to ignore one or both + * of these conditions; normally, however, it will use ^S/^Q or some + * sort of hardware flow control to regulate the input to try to avoid + * overflow. While the low-level driver is responsible for all + * receiving flow control, note that the ^S/^Q handling (but not + * hardware flow control) is handled by the upper layer, in + * copy_to_cooked. + */ +#define TTY_THROTTLE_SQ_FULL 1 +#define TTY_THROTTLE_SQ_AVAIL 2 +#define TTY_THROTTLE_RQ_FULL 3 +#define TTY_THROTTLE_RQ_AVAIL 4 + +/* + * This defines the low- and high-watermarks for the various conditions. + * Again, the low-level driver is free to ignore any of these, and has + * to implement RQ_THREHOLD_LW for itself if it wants it. + */ +#define SQ_THRESHOLD_LW 16 +#define SQ_THRESHOLD_HW 768 +#define RQ_THRESHOLD_LW 16 +#define RQ_THRESHOLD_HW 768 + +/* + * These bits are used in the flags field of the tty structure. + * + * So that interrupts won't be able to mess up the queues, + * copy_to_cooked must be atomic with repect to itself, as must + * tty->write. Thus, you must use the inline functions set_bit() and + * clear_bit() to make things atomic. + */ +#define TTY_WRITE_BUSY 0 +#define TTY_READ_BUSY 1 +#define TTY_SQ_THROTTLED 2 +#define TTY_RQ_THROTTLED 3 +#define TTY_IO_ERROR 4 +#define TTY_SLAVE_CLOSED 5 +#define TTY_EXCLUSIVE 6 + +/* + * When a break, frame error, or parity error happens, these codes are + * stuffed into the read queue, and the relevant bit in readq_flag bit + * array is set. + */ +#define TTY_BREAK 1 +#define TTY_FRAME 2 +#define TTY_PARITY 3 +#define TTY_OVERRUN 4 + +#define TTY_WRITE_FLUSH(tty) tty_write_flush((tty)) +#define TTY_READ_FLUSH(tty) tty_read_flush((tty)) + +extern void tty_write_flush(struct tty_struct *); +extern void tty_read_flush(struct tty_struct *); + +/* Number of chars that must be available in a write queue before + the queue is awakened. */ +#define WAKEUP_CHARS (3*TTY_BUF_SIZE/4) + +extern struct tty_struct *tty_table[]; +extern struct termios *tty_termios[]; +extern struct termios *termios_locked[]; +extern int tty_check_write[]; +extern struct tty_struct * redirect; +extern struct tty_ldisc ldiscs[]; +extern int fg_console; +extern unsigned long video_num_columns; +extern unsigned long video_num_lines; +extern struct wait_queue * keypress_wait; + +#define TTY_TABLE_IDX(nr) ((nr) ? (nr) : (fg_console+1)) +#define TTY_TABLE(nr) (tty_table[TTY_TABLE_IDX(nr)]) + +/* intr=^C quit=^| erase=del kill=^U + eof=^D vtime=\0 vmin=\1 sxtc=\0 + start=^Q stop=^S susp=^Z eol=\0 + reprint=^R discard=^U werase=^W lnext=^V + eol2=\0 +*/ +#define INIT_C_CC "\003\034\177\025\004\0\1\0\021\023\032\0\022\017\027\026\0" + +extern long rs_init(long); +extern long lp_init(long); +extern long con_init(long); +extern long tty_init(long); + +extern void flush_input(struct tty_struct * tty); +extern void flush_output(struct tty_struct * tty); +extern void wait_until_sent(struct tty_struct * tty); +extern int check_change(struct tty_struct * tty, int channel); +extern void stop_tty(struct tty_struct * tty); +extern void start_tty(struct tty_struct * tty); +extern int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc); +extern int tty_read_raw_data(struct tty_struct *tty, unsigned char *bufp, + int buflen); +extern int tty_write_data(struct tty_struct *tty, char *bufp, int buflen, + void (*callback)(void * data), void * callarg); + +extern int tty_ioctl(struct inode *, struct file *, unsigned int, unsigned long); +extern int is_orphaned_pgrp(int pgrp); +extern int is_ignored(int sig); +extern int tty_signal(int sig, struct tty_struct *tty); +extern void tty_hangup(struct tty_struct * tty); +extern void tty_vhangup(struct tty_struct * tty); +extern void tty_unhangup(struct file *filp); +extern int tty_hung_up_p(struct file * filp); +extern void do_SAK(struct tty_struct *tty); +extern void disassociate_ctty(int priv); + +/* tty write functions */ + +extern void rs_write(struct tty_struct * tty); +extern void con_write(struct tty_struct * tty); + +/* serial.c */ + +extern int rs_open(struct tty_struct * tty, struct file * filp); + +/* pty.c */ + +extern int pty_open(struct tty_struct * tty, struct file * filp); + +/* console.c */ + +extern int con_open(struct tty_struct * tty, struct file * filp); +extern void update_screen(int new_console); +extern void blank_screen(void); +extern void unblank_screen(void); + +/* vt.c */ + +extern int vt_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg); + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/types.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/types.h new file mode 100644 index 000000000..70071cedb --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/types.h @@ -0,0 +1,126 @@ +#ifndef _LINUX_TYPES_H +#define _LINUX_TYPES_H + +#ifndef _SIZE_T +#define _SIZE_T +typedef unsigned int size_t; +#endif + +#ifndef _SSIZE_T +#define _SSIZE_T +typedef int ssize_t; +#endif + +#ifndef _TIME_T +#define _TIME_T +typedef long time_t; +#endif + +#ifndef _CLOCK_T +#define _CLOCK_T +typedef long clock_t; +#endif + +#ifndef _PTRDIFF_T +#define _PTRDIFF_T +typedef int ptrdiff_t; +#endif + +#ifndef NULL +#define NULL ((void *) 0) +#endif + +typedef int pid_t; +typedef unsigned short uid_t; +typedef unsigned short gid_t; +typedef unsigned short dev_t; +#ifdef OLD_LINUX +typedef unsigned short ino_t; +#else +typedef unsigned long ino_t; +#endif +typedef unsigned short mode_t; +typedef unsigned short umode_t; +typedef unsigned short nlink_t; +typedef int daddr_t; +typedef long off_t; + +/* bsd */ +typedef unsigned char u_char; +typedef unsigned short u_short; +typedef unsigned int u_int; +typedef unsigned long u_long; + +/* sysv */ +typedef unsigned char unchar; +typedef unsigned short ushort; +typedef unsigned int uint; +typedef unsigned long ulong; + +typedef char *caddr_t; + +typedef unsigned char cc_t; +typedef unsigned int speed_t; +typedef unsigned long tcflag_t; + +/* + * This allows for 256 file descriptors: if NR_OPEN is ever grown beyond that + * you'll have to change this too. But 256 fd's seem to be enough even for such + * "real" unices like SunOS, so hopefully this is one limit that doesn't have + * to be changed. + * + * Note that POSIX wants the FD_CLEAR(fd,fdsetp) defines to be in + * (and thus ) - but this is a more logical place for them. Solved + * by having dummy defines in . + */ + +/* + * Those macros may have been defined in . But we always + * use the ones here. + */ +#undef __FDSET_LONGS +#define __FDSET_LONGS 8 + +typedef struct fd_set { + unsigned long fds_bits [__FDSET_LONGS]; +} fd_set; + +#undef __NFDBITS +#define __NFDBITS (8 * sizeof(unsigned long)) + +#undef __FD_SETSIZE +#define __FD_SETSIZE (__FDSET_LONGS*__NFDBITS) + +#undef __FD_SET +#define __FD_SET(fd,fdsetp) \ + __asm__ __volatile__("btsl %1,%0": \ + "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) + +#undef __FD_CLR +#define __FD_CLR(fd,fdsetp) \ + __asm__ __volatile__("btrl %1,%0": \ + "=m" (*(fd_set *) (fdsetp)):"r" ((int) (fd))) + +#undef __FD_ISSET +#define __FD_ISSET(fd,fdsetp) (__extension__ ({ \ + unsigned char __result; \ + __asm__ __volatile__("btl %1,%2 ; setb %0" \ + :"=q" (__result) :"r" ((int) (fd)), \ + "m" (*(fd_set *) (fdsetp))); \ + __result; })) + +#undef __FD_ZERO +#define __FD_ZERO(fdsetp) \ + __asm__ __volatile__("cld ; rep ; stosl" \ + :"=m" (*(fd_set *) (fdsetp)) \ + :"a" (0), "c" (__FDSET_LONGS), \ + "D" ((fd_set *) (fdsetp)) :"cx","di") + +struct ustat { + daddr_t f_tfree; + ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/udp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/udp.h new file mode 100644 index 000000000..471301a2f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/udp.h @@ -0,0 +1,29 @@ +/* + * 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 UDP protocol. + * + * Version: @(#)udp.h 1.0.2 04/28/93 + * + * Author: Fred N. van Kempen, + * + * 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. + */ +#ifndef _LINUX_UDP_H +#define _LINUX_UDP_H + + +struct udphdr { + unsigned short source; + unsigned short dest; + unsigned short len; + unsigned short check; +}; + + +#endif /* _LINUX_UDP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ultrasound.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ultrasound.h new file mode 100644 index 000000000..40e2443e6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/ultrasound.h @@ -0,0 +1,121 @@ +#ifndef _ULTRASOUND_H_ +#define _ULTRASOUND_H_ +/* + * Copyright by Hannu Savolainen 1993 + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + */ + +/* + * ultrasound.h - Macros for programming the Gravis Ultrasound + * These macros are extremely device dependent + * and not portable. + */ + +/* + * Private events for Gravis Ultrasound (GUS) + * + * Format: + * byte 0 - SEQ_PRIVATE (0xfe) + * byte 1 - Synthesizer device number (0-N) + * byte 2 - Command (see below) + * byte 3 - Voice number (0-31) + * bytes 4 and 5 - parameter P1 (unsigned short) + * bytes 6 and 7 - parameter P2 (unsigned short) + * + * Commands: + * Each command affects one voice defined in byte 3. + * Unused parameters (P1 and/or P2 *MUST* be initialized to zero). + * _GUS_NUMVOICES - Sets max. number of concurrent voices (P1=14-31, default 16) + * _GUS_VOICESAMPLE- ************ OBSOLETE ************* + * _GUS_VOICEON - Starts voice (P1=voice mode) + * _GUS_VOICEOFF - Stops voice (no parameters) + * _GUS_VOICEFADE - Stops the voice smoothly. + * _GUS_VOICEMODE - Alters the voice mode, don't start or stop voice (P1=voice mode) + * _GUS_VOICEBALA - Sets voice balence (P1, 0=left, 7=middle and 15=right, default 7) + * _GUS_VOICEFREQ - Sets voice (sample) playback frequency (P1=Hz) + * _GUS_VOICEVOL - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) + * _GUS_VOICEVOL2 - Sets voice volume (P1=volume, 0xfff=max, 0xeff=half, 0x000=off) + * (Like GUS_VOICEVOL but doesn't change the hw + * volume. It just updates volume in the voice table). + * + * _GUS_RAMPRANGE - Sets limits for volume ramping (P1=low volume, P2=high volume) + * _GUS_RAMPRATE - Sets the speed for volume ramping (P1=scale, P2=rate) + * _GUS_RAMPMODE - Sets the volume ramping mode (P1=ramping mode) + * _GUS_RAMPON - Starts volume ramping (no parameters) + * _GUS_RAMPOFF - Stops volume ramping (no parameters) + * _GUS_VOLUME_SCALE - Changes the volume calculation constants + * for all voices. + */ + +#define _GUS_NUMVOICES 0x00 +#define _GUS_VOICESAMPLE 0x01 /* OBSOLETE */ +#define _GUS_VOICEON 0x02 +#define _GUS_VOICEOFF 0x03 +#define _GUS_VOICEMODE 0x04 +#define _GUS_VOICEBALA 0x05 +#define _GUS_VOICEFREQ 0x06 +#define _GUS_VOICEVOL 0x07 +#define _GUS_RAMPRANGE 0x08 +#define _GUS_RAMPRATE 0x09 +#define _GUS_RAMPMODE 0x0a +#define _GUS_RAMPON 0x0b +#define _GUS_RAMPOFF 0x0c +#define _GUS_VOICEFADE 0x0d +#define _GUS_VOLUME_SCALE 0x0e +#define _GUS_VOICEVOL2 0x0f +#define _GUS_VOICE_POS 0x10 + +/* + * GUS API macros + */ + +#define _GUS_CMD(chn, voice, cmd, p1, p2) \ + {_SEQ_NEEDBUF(8); _seqbuf[_seqbufptr] = SEQ_PRIVATE;\ + _seqbuf[_seqbufptr+1] = (chn); _seqbuf[_seqbufptr+2] = cmd;\ + _seqbuf[_seqbufptr+3] = voice;\ + *(unsigned short*)&_seqbuf[_seqbufptr+4] = p1;\ + *(unsigned short*)&_seqbuf[_seqbufptr+6] = p2;\ + _SEQ_ADVBUF(8);} + +#define GUS_NUMVOICES(chn, p1) _GUS_CMD(chn, 0, _GUS_NUMVOICES, (p1), 0) +#define GUS_VOICESAMPLE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICESAMPLE, (p1), 0) /* OBSOLETE */ +#define GUS_VOICEON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEON, (p1), 0) +#define GUS_VOICEOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEOFF, 0, 0) +#define GUS_VOICEFADE(chn, voice) _GUS_CMD(chn, voice, _GUS_VOICEFADE, 0, 0) +#define GUS_VOICEMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEMODE, (p1), 0) +#define GUS_VOICEBALA(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEBALA, (p1), 0) +#define GUS_VOICEFREQ(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICEFREQ, \ + (p) & 0xffff, ((p) >> 16) & 0xffff) +#define GUS_VOICEVOL(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL, (p1), 0) +#define GUS_VOICEVOL2(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_VOICEVOL2, (p1), 0) +#define GUS_RAMPRANGE(chn, voice, low, high) _GUS_CMD(chn, voice, _GUS_RAMPRANGE, (low), (high)) +#define GUS_RAMPRATE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_RAMPRATE, (p1), (p2)) +#define GUS_RAMPMODE(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPMODE, (p1), 0) +#define GUS_RAMPON(chn, voice, p1) _GUS_CMD(chn, voice, _GUS_RAMPON, (p1), 0) +#define GUS_RAMPOFF(chn, voice) _GUS_CMD(chn, voice, _GUS_RAMPOFF, 0, 0) +#define GUS_VOLUME_SCALE(chn, voice, p1, p2) _GUS_CMD(chn, voice, _GUS_VOLUME_SCALE, (p1), (p2)) +#define GUS_VOICE_POS(chn, voice, p) _GUS_CMD(chn, voice, _GUS_VOICE_POS, \ + (p) & 0xffff, ((p) >> 16) & 0xffff) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/un.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/un.h new file mode 100644 index 000000000..d04a90753 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/un.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_UN_H +#define _LINUX_UN_H + +struct sockaddr_un { + unsigned short sun_family; /* AF_UNIX */ + char sun_path[108]; /* pathname */ +}; + +#endif /* _LINUX_UN_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/unistd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/unistd.h new file mode 100644 index 000000000..c499a132d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/unistd.h @@ -0,0 +1,228 @@ +#ifndef _LINUX_UNISTD_H +#define _LINUX_UNISTD_H + +/* + * This file contains the system call numbers and the syscallX + * macros + */ + +#define __NR_setup 0 /* used only by init, to get system going */ +#define __NR_exit 1 +#define __NR_fork 2 +#define __NR_read 3 +#define __NR_write 4 +#define __NR_open 5 +#define __NR_close 6 +#define __NR_waitpid 7 +#define __NR_creat 8 +#define __NR_link 9 +#define __NR_unlink 10 +#define __NR_execve 11 +#define __NR_chdir 12 +#define __NR_time 13 +#define __NR_mknod 14 +#define __NR_chmod 15 +#define __NR_chown 16 +#define __NR_break 17 +#define __NR_oldstat 18 +#define __NR_lseek 19 +#define __NR_getpid 20 +#define __NR_mount 21 +#define __NR_umount 22 +#define __NR_setuid 23 +#define __NR_getuid 24 +#define __NR_stime 25 +#define __NR_ptrace 26 +#define __NR_alarm 27 +#define __NR_oldfstat 28 +#define __NR_pause 29 +#define __NR_utime 30 +#define __NR_stty 31 +#define __NR_gtty 32 +#define __NR_access 33 +#define __NR_nice 34 +#define __NR_ftime 35 +#define __NR_sync 36 +#define __NR_kill 37 +#define __NR_rename 38 +#define __NR_mkdir 39 +#define __NR_rmdir 40 +#define __NR_dup 41 +#define __NR_pipe 42 +#define __NR_times 43 +#define __NR_prof 44 +#define __NR_brk 45 +#define __NR_setgid 46 +#define __NR_getgid 47 +#define __NR_signal 48 +#define __NR_geteuid 49 +#define __NR_getegid 50 +#define __NR_acct 51 +#define __NR_phys 52 +#define __NR_lock 53 +#define __NR_ioctl 54 +#define __NR_fcntl 55 +#define __NR_mpx 56 +#define __NR_setpgid 57 +#define __NR_ulimit 58 +#define __NR_oldolduname 59 +#define __NR_umask 60 +#define __NR_chroot 61 +#define __NR_ustat 62 +#define __NR_dup2 63 +#define __NR_getppid 64 +#define __NR_getpgrp 65 +#define __NR_setsid 66 +#define __NR_sigaction 67 +#define __NR_sgetmask 68 +#define __NR_ssetmask 69 +#define __NR_setreuid 70 +#define __NR_setregid 71 +#define __NR_sigsuspend 72 +#define __NR_sigpending 73 +#define __NR_sethostname 74 +#define __NR_setrlimit 75 +#define __NR_getrlimit 76 +#define __NR_getrusage 77 +#define __NR_gettimeofday 78 +#define __NR_settimeofday 79 +#define __NR_getgroups 80 +#define __NR_setgroups 81 +#define __NR_select 82 +#define __NR_symlink 83 +#define __NR_oldlstat 84 +#define __NR_readlink 85 +#define __NR_uselib 86 +#define __NR_swapon 87 +#define __NR_reboot 88 +#define __NR_readdir 89 +#define __NR_mmap 90 +#define __NR_munmap 91 +#define __NR_truncate 92 +#define __NR_ftruncate 93 +#define __NR_fchmod 94 +#define __NR_fchown 95 +#define __NR_getpriority 96 +#define __NR_setpriority 97 +#define __NR_profil 98 +#define __NR_statfs 99 +#define __NR_fstatfs 100 +#define __NR_ioperm 101 +#define __NR_socketcall 102 +#define __NR_syslog 103 +#define __NR_setitimer 104 +#define __NR_getitimer 105 +#define __NR_stat 106 +#define __NR_lstat 107 +#define __NR_fstat 108 +#define __NR_olduname 109 +#define __NR_iopl 110 +#define __NR_vhangup 111 +#define __NR_idle 112 +#define __NR_vm86 113 +#define __NR_wait4 114 +#define __NR_swapoff 115 +#define __NR_sysinfo 116 +#define __NR_ipc 117 +#define __NR_fsync 118 +#define __NR_sigreturn 119 +#define __NR_clone 120 +#define __NR_setdomainname 121 +#define __NR_uname 122 +#define __NR_modify_ldt 123 +#define __NR_adjtimex 124 +#define __NR_mprotect 125 +#define __NR_sigprocmask 126 +#define __NR_create_module 127 +#define __NR_init_module 128 +#define __NR_delete_module 129 +#define __NR_get_kernel_syms 130 +#define __NR_quotactl 131 +#define __NR_getpgid 132 +#define __NR_fchdir 133 +#define __NR_bdflush 134 + +extern int errno; + +/* XXX - _foo needs to be __foo, while __NR_bar could be _NR_bar. */ +#define _syscall0(type,name) \ +type name(void) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name)); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall1(type,name,atype,a) \ +type name(atype a) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall2(type,name,atype,a,btype,b) \ +type name(atype a,btype b) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b))); \ +if (__res >= 0) \ + return (type) __res; \ +errno = -__res; \ +return -1; \ +} + +#define _syscall3(type,name,atype,a,btype,b,ctype,c) \ +type name(atype a,btype b,ctype c) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)),"d" ((long)(c))); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#define _syscall4(type,name,atype,a,btype,b,ctype,c,dtype,d) \ +type name (atype a, btype b, ctype c, dtype d) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)), \ + "d" ((long)(c)),"S" ((long)(d))); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#define _syscall5(type,name,atype,a,btype,b,ctype,c,dtype,d,etype,e) \ +type name (atype a,btype b,ctype c,dtype d,etype e) \ +{ \ +long __res; \ +__asm__ volatile ("int $0x80" \ + : "=a" (__res) \ + : "0" (__NR_##name),"b" ((long)(a)),"c" ((long)(b)), \ + "d" ((long)(c)),"S" ((long)(d)),"D" ((long)(e))); \ +if (__res>=0) \ + return (type) __res; \ +errno=-__res; \ +return -1; \ +} + +#endif /* _LINUX_UNISTD_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/user.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/user.h new file mode 100644 index 000000000..3fbee19e4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/user.h @@ -0,0 +1,77 @@ +#ifndef _LINUX_USER_H +#define _LINUX_USER_H + +#include +/* Core file format: The core file is written in such a way that gdb + can understand it and provide useful information to the user (under + linux we use the 'trad-core' bfd). There are quite a number of + obstacles to being able to view the contents of the floating point + registers, and until these are solved you will not be able to view the + contents of them. Actually, you can read in the core file and look at + the contents of the user struct to find out what the floating point + registers contain. + The actual file contents are as follows: + UPAGE: 1 page consisting of a user struct that tells gdb what is present + in the file. Directly after this is a copy of the task_struct, which + is currently not used by gdb, but it may come in useful at some point. + All of the registers are stored as part of the upage. The upage should + always be only one page. + DATA: The data area is stored. We use current->end_text to + current->brk to pick up all of the user variables, plus any memory + that may have been malloced. No attempt is made to determine if a page + is demand-zero or if a page is totally unused, we just cover the entire + range. All of the addresses are rounded in such a way that an integral + number of pages is written. + STACK: We need the stack information in order to get a meaningful + backtrace. We need to write the data from (esp) to + current->start_stack, so we round each of these off in order to be able + to write an integer number of pages. + The minimum core file size is 3 pages, or 12288 bytes. +*/ + +struct user_i387_struct { + long cwd; + long swd; + long twd; + long fip; + long fcs; + long foo; + long fos; + long st_space[20]; /* 8*10 bytes for each FP-reg = 80 bytes */ +}; + +/* When the kernel dumps core, it starts by dumping the user struct - + this will be used by gdb to figure out where the data and stack segments + are within the file, and what virtual addresses to use. */ +struct user{ +/* We start with the registers, to mimic the way that "memory" is returned + from the ptrace(3,...) function. */ + struct pt_regs regs; /* Where the registers are actually stored */ +/* ptrace does not yet supply these. Someday.... */ + int u_fpvalid; /* True if math co-processor being used. */ + /* for this mess. Not yet used. */ + struct user_i387_struct i387; /* Math Co-processor registers. */ +/* The rest of this junk is to help gdb figure out what goes where */ + unsigned long int u_tsize; /* Text segment size (pages). */ + unsigned long int u_dsize; /* Data segment size (pages). */ + unsigned long int u_ssize; /* Stack segment size (pages). */ + unsigned long start_code; /* Starting virtual address of text. */ + unsigned long start_stack; /* Starting virtual address of stack area. + This is actually the bottom of the stack, + the top of the stack is always found in the + esp register. */ + long int signal; /* Signal that caused the core dump. */ + 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 +#define HOST_TEXT_START_ADDR (u.start_code) +#define HOST_STACK_END_ADDR (u.start_stack + u.u_ssize * NBPG) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utime.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utime.h new file mode 100644 index 000000000..c6bf27b78 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utime.h @@ -0,0 +1,9 @@ +#ifndef _LINUX_UTIME_H +#define _LINUX_UTIME_H + +struct utimbuf { + time_t actime; + time_t modtime; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utsname.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utsname.h new file mode 100644 index 000000000..7aef28fc3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/utsname.h @@ -0,0 +1,35 @@ +#ifndef _LINUX_UTSNAME_H +#define _LINUX_UTSNAME_H + +#define __OLD_UTS_LEN 8 + +struct oldold_utsname { + char sysname[9]; + char nodename[9]; + char release[9]; + char version[9]; + char machine[9]; +}; + +#define __NEW_UTS_LEN 64 + +struct old_utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; +}; + +struct new_utsname { + char sysname[65]; + char nodename[65]; + char release[65]; + char version[65]; + char machine[65]; + char domainname[65]; +}; + +extern struct new_utsname system_utsname; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vfs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vfs.h new file mode 100644 index 000000000..463df2fd7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vfs.h @@ -0,0 +1,21 @@ +#ifndef _LINUX_VFS_H +#define _LINUX_VFS_H + +typedef struct { + long val[2]; +} fsid_t; + +struct statfs { + long f_type; + long f_bsize; + long f_blocks; + long f_bfree; + long f_bavail; + long f_files; + long f_ffree; + fsid_t f_fsid; + long f_namelen; + long f_spare[6]; +}; + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vm86.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vm86.h new file mode 100644 index 000000000..0ef4c2272 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vm86.h @@ -0,0 +1,56 @@ +#ifndef _LINUX_VM86_H +#define _LINUX_VM86_H + +#define VM_MASK 0x00020000 + +/* + * This is the stack-layout when we have done a "SAVE_ALL" from vm86 + * mode - the main change is that the old segment descriptors aren't + * useful any more and are forced to be zero by the kernel (and the + * hardware when a trap occurs), and the real segment descriptors are + * at the end of the structure. Look at ptrace.h to see the "normal" + * setup. + */ + +struct vm86_regs { +/* + * normal regs, with special meaning for the segment descriptors.. + */ + long ebx; + long ecx; + long edx; + long esi; + long edi; + long ebp; + long eax; + long __null_ds; + long __null_es; + long __null_fs; + long __null_gs; + long orig_eax; + long eip; + long cs; + long eflags; + long esp; + long ss; +/* + * these are specific to v86 mode: + */ + long es; + long ds; + long fs; + long gs; +}; + +struct vm86_struct { + struct vm86_regs regs; + unsigned long flags; + unsigned long screen_bitmap; +}; + +/* + * flags masks + */ +#define VM86_SCREEN_BITMAP 1 + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vt.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vt.h new file mode 100644 index 000000000..107ad3154 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/vt.h @@ -0,0 +1,34 @@ +#ifndef _LINUX_VT_H +#define _LINUX_VT_H + +/* 0x56 is 'V', to avoid collision with termios and kd */ + +#define VT_OPENQRY 0x5600 /* find available vt */ + +struct vt_mode { + char mode; /* vt mode */ + char waitv; /* if set, hang on writes if not active */ + short relsig; /* signal to raise on release req */ + short acqsig; /* signal to raise on acquisition */ + short frsig; /* unused (set to 0) */ +}; +#define VT_GETMODE 0x5601 /* get mode of active vt */ +#define VT_SETMODE 0x5602 /* set mode of active vt */ +#define VT_AUTO 0x00 /* auto vt switching */ +#define VT_PROCESS 0x01 /* process controls switching */ +#define VT_ACKACQ 0x02 /* acknowledge switch */ + +struct vt_stat { + ushort v_active; /* active vt */ + ushort v_signal; /* signal to send */ + ushort v_state; /* vt bitmask */ +}; +#define VT_GETSTATE 0x5603 /* get global vt state info */ +#define VT_SENDSIG 0x5604 /* signal to send to bitmask of vts */ + +#define VT_RELDISP 0x5605 /* release display */ + +#define VT_ACTIVATE 0x5606 /* make vt active */ +#define VT_WAITACTIVE 0x5607 /* wait for vt active */ + +#endif /* _LINUX_VT_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/wait.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/wait.h new file mode 100644 index 000000000..92fb67dc6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/wait.h @@ -0,0 +1,26 @@ +#ifndef _LINUX_WAIT_H +#define _LINUX_WAIT_H + +#define WNOHANG 0x00000001 +#define WUNTRACED 0x00000002 + +#define __WCLONE 0x80000000 + +struct wait_queue { + struct task_struct * task; + struct wait_queue * next; +}; + +struct select_table_entry { + struct wait_queue wait; + struct wait_queue ** wait_address; +}; + +typedef struct select_table_struct { + int nr; + struct select_table_entry * entry; +} select_table; + +#define __MAX_SELECT_TABLE_ENTRIES (4096 / sizeof (struct select_table_entry)) + +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xd.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xd.h new file mode 100644 index 000000000..567584b17 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xd.h @@ -0,0 +1,137 @@ +#ifndef _LINUX_XD_H +#define _LINUX_XD_H + +/* + * This file contains the definitions for the IO ports and errors etc. for XT hard disk controllers (at least the DTC 5150X). + * + * Author: Pat Mackinlay, smackinla@cc.curtin.edu.au + * Date: 29/09/92 + * + * Revised: 01/01/93, ... + * + * Ref: DTC 5150X Controller Specification (thanks to Kevin Fowler, kevinf@agora.rain.com) + * Also thanks to: Salvador Abreu, Dave Thaler, Risto Kankkunen and Wim Van Dorst. + */ + +/* XT hard disk controller registers */ +#define XD_DATA (xd_iobase + 0x00) /* data RW register */ +#define XD_RESET (xd_iobase + 0x01) /* reset WO register */ +#define XD_STATUS (xd_iobase + 0x01) /* status RO register */ +#define XD_SELECT (xd_iobase + 0x02) /* select WO register */ +#define XD_JUMPER (xd_iobase + 0x02) /* jumper RO register */ +#define XD_CONTROL (xd_iobase + 0x03) /* DMAE/INTE WO register */ +#define XD_RESERVED (xd_iobase + 0x03) /* reserved */ + +/* XT hard disk controller commands (incomplete list) */ +#define CMD_TESTREADY 0x00 /* test drive ready */ +#define CMD_RECALIBRATE 0x01 /* recalibrate drive */ +#define CMD_SENSE 0x03 /* request sense */ +#define CMD_FORMATDRV 0x04 /* format drive */ +#define CMD_VERIFY 0x05 /* read verify */ +#define CMD_FORMATTRK 0x06 /* format track */ +#define CMD_FORMATBAD 0x07 /* format bad track */ +#define CMD_READ 0x08 /* read */ +#define CMD_WRITE 0x0A /* write */ +#define CMD_SEEK 0x0B /* seek */ + +/* Controller specific commands */ +#define CMD_DTCSETPARAM 0x0C /* set drive parameters (DTC 5150X only?) */ +#define CMD_DTCGETECC 0x0D /* get ecc error length (DTC 5150X only?) */ +#define CMD_DTCREADBUF 0x0E /* read sector buffer (DTC 5150X only?) */ +#define CMD_DTCWRITEBUF 0x0F /* write sector buffer (DTC 5150X only?) */ +#define CMD_DTCREMAPTRK 0x11 /* assign alternate track (DTC 5150X only?) */ +#define CMD_DTCGETPARAM 0xFB /* get drive parameters (DTC 5150X only?) */ +#define CMD_DTCSETSTEP 0xFC /* set step rate (DTC 5150X only?) */ +#define CMD_DTCSETGEOM 0xFE /* set geometry data (DTC 5150X only?) */ +#define CMD_DTCGETGEOM 0xFF /* get geometry data (DTC 5150X only?) */ +#define CMD_ST11GETGEOM 0xF8 /* get geometry data (Seagate ST11R/M only?) */ +#define CMD_WDSETPARAM 0x0C /* set drive parameters (WD 1004A27X only?) */ + +/* Bits for command status byte */ +#define CSB_ERROR 0x02 /* error */ +#define CSB_LUN 0x20 /* logical Unit Number */ + +/* XT hard disk controller status bits */ +#define STAT_READY 0x01 /* controller is ready */ +#define STAT_INPUT 0x02 /* data flowing from controller to host */ +#define STAT_COMMAND 0x04 /* controller in command phase */ +#define STAT_SELECT 0x08 /* controller is selected */ +#define STAT_REQUEST 0x10 /* controller requesting data */ +#define STAT_INTERRUPT 0x20 /* controller requesting interrupt */ + +/* XT hard disk controller control bits */ +#define PIO_MODE 0x00 /* control bits to set for PIO */ +#define DMA_MODE 0x03 /* control bits to set for DMA & interrupt */ + +#define XD_MAXDRIVES 2 /* maximum 2 drives */ +#define XD_TIMEOUT 100 /* 1 second timeout */ +#define XD_RETRIES 4 /* maximum 4 retries */ + +#undef DEBUG /* define for debugging output */ + +#ifdef DEBUG + #define DEBUG_STARTUP /* debug driver initialisation */ + #define DEBUG_OVERRIDE /* debug override geometry detection */ + #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 */ + +/* this structure defines the XT drives and their types */ +typedef struct { + u_char heads; + u_short cylinders; + u_char sectors; + u_char control; +} XD_INFO; + +#define HDIO_GETGEO 0x0301 /* get drive geometry */ + +/* this structure is returned to the HDIO_GETGEO ioctl */ +typedef struct { + u_char heads; + u_char sectors; + u_short cylinders; + u_long start; +} XD_GEOMETRY; + +/* this structure defines a ROM BIOS signature */ +typedef struct { + u_long offset; + char *string; + void (*init_controller)(u_char *address); + void (*init_drive)(u_char drive); + char *name; +} XD_SIGNATURE; + +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); + +static int xd_open (struct inode *inode,struct file *file); +static void do_xd_request (void); +static int xd_ioctl (struct inode *inode,struct file *file,unsigned int cmd,unsigned long arg); +static void xd_release (struct inode *inode,struct file *file); +static int xd_reread_partitions (int dev); +static int xd_readwrite (u_char operation,u_char drive,char *buffer,u_int block,u_int count); +static void xd_recalibrate (u_char drive); + +static void xd_interrupt_handler (int unused); +static u_char xd_setup_dma (u_char opcode,u_char *buffer,u_int count); +static u_char *xd_build (u_char *cmdblk,u_char command,u_char drive,u_char head,u_short cylinder,u_char sector,u_char count,u_char control); +static inline u_char xd_waitport (u_short port,u_char flags,u_char mask,u_long timeout); +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 */ +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); +static void xd_override_init_drive (u_char drive); + +#endif /* _LINUX_XD_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs.h new file mode 100644 index 000000000..47f3e3f16 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs.h @@ -0,0 +1,115 @@ +#ifndef _XIA_FS_H +#define _XIA_FS_H + +/* + * include/linux/xia_fs.h + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix_fs.h. + * Copyright (C) Linus Torvalds, 1991, 1992. + */ + +#define _XIAFS_SUPER_MAGIC 0x012FD16D +#define _XIAFS_ROOT_INO 1 +#define _XIAFS_BAD_INO 2 + +#define _XIAFS_NAME_LEN 248 + +#define _XIAFS_INODES_PER_BLOCK ((BLOCK_SIZE)/(sizeof(struct xiafs_inode))) + +struct xiafs_inode { /* 64 bytes */ + mode_t i_mode; + nlink_t i_nlinks; + uid_t i_uid; + gid_t i_gid; + size_t i_size; /* 8 */ + time_t i_ctime; + time_t i_atime; + time_t i_mtime; + daddr_t i_zone[8]; + daddr_t i_ind_zone; + daddr_t i_dind_zone; +}; + +/* + * linux super-block data on disk + */ +struct xiafs_super_block { + u_char s_boot_segment[512]; /* 1st sector reserved for boot */ + u_long s_zone_size; /* 0: the name says it */ + u_long s_nzones; /* 1: volume size, zone aligned */ + u_long s_ninodes; /* 2: # of inodes */ + u_long s_ndatazones; /* 3: # of data zones */ + u_long s_imap_zones; /* 4: # of imap zones */ + u_long s_zmap_zones; /* 5: # of zmap zones */ + u_long s_firstdatazone; /* 6: first data zone */ + u_long s_zone_shift; /* 7: z size = 1KB << z shift */ + u_long s_max_size; /* 8: max size of a single file */ + u_long s_reserved0; /* 9: reserved */ + u_long s_reserved1; /* 10: */ + u_long s_reserved2; /* 11: */ + u_long s_reserved3; /* 12: */ + u_long s_firstkernzone; /* 13: first kernel zone */ + u_long s_kernzones; /* 14: kernel size in zones */ + u_long s_magic; /* 15: magic number for xiafs */ +}; + +struct xiafs_direct { + ino_t d_ino; + u_short d_rec_len; + u_char d_name_len; + char d_name[_XIAFS_NAME_LEN+1]; +}; + +extern int xiafs_lookup(struct inode * dir,const char * name, int len, + struct inode ** result); +extern int xiafs_create(struct inode * dir,const char * name, int len, int mode, + struct inode ** result); +extern int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode); +extern int xiafs_rmdir(struct inode * dir, const char * name, int len); +extern int xiafs_unlink(struct inode * dir, const char * name, int len); +extern int xiafs_symlink(struct inode * inode, const char * name, int len, + const char * symname); +extern int xiafs_link(struct inode * oldinode, struct inode * dir, + const char * name, int len); +extern int xiafs_mknod(struct inode * dir, const char * name, int len, + int mode, int rdev); +extern int xiafs_rename(struct inode * old_dir, const char * old_name, + int old_len, struct inode * new_dir, + const char * new_name, int new_len); +extern struct inode * xiafs_new_inode(struct inode * dir); +extern void xiafs_free_inode(struct inode * inode); +extern unsigned long xiafs_count_free_inodes(struct super_block *sb); +extern int xiafs_new_zone(struct super_block * sb, u_long prev_addr); +extern void xiafs_free_zone(struct super_block * sb, int block); +extern unsigned long xiafs_count_free_zones(struct super_block *sb); + +extern int xiafs_bmap(struct inode *,int); + +extern struct buffer_head * xiafs_getblk(struct inode *, int, int); +extern struct buffer_head * xiafs_bread(struct inode *, int, int); + +extern void xiafs_truncate(struct inode *); +extern void xiafs_put_super(struct super_block *); +extern struct super_block *xiafs_read_super(struct super_block *,void *,int); +extern void xiafs_read_inode(struct inode *); +extern void xiafs_write_inode(struct inode *); +extern void xiafs_put_inode(struct inode *); +extern void xiafs_statfs(struct super_block *, struct statfs *); +extern int xiafs_sync_inode(struct inode *); +extern int xiafs_sync_file(struct inode *, struct file *); + +extern struct inode_operations xiafs_file_inode_operations; +extern struct inode_operations xiafs_dir_inode_operations; +extern struct inode_operations xiafs_symlink_inode_operations; + +#endif /* _XIA_FS_H */ + + + + + + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_i.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_i.h new file mode 100644 index 000000000..3000a44a5 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_i.h @@ -0,0 +1,19 @@ +#ifndef _XIA_FS_I_H +#define _XIA_FS_I_H + +/* + * include/linux/xia_fs_i.h + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix_fs_i.h. + * Copyright (C) Linus Torvalds, 1991, 1992. + */ + +struct xiafs_inode_info { /* for data zone pointers */ + unsigned long i_zone[8]; + unsigned long i_ind_zone; + unsigned long i_dind_zone; +}; + +#endif /* _XIA_FS_I_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_sb.h b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_sb.h new file mode 100644 index 000000000..1166ae965 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/include/linux/xia_fs_sb.h @@ -0,0 +1,36 @@ +#ifndef _XIA_FS_SB_H +#define _XIA_FS_SB_H + +/* + * include/linux/xia_fs_sb.h + * + * Copyright (C) Q. Frank Xia, 1993. + * + * Based on Linus' minix_fs_sb.h. + * Copyright (C) Linus Torvalds, 1991, 1992. + */ + +#define _XIAFS_IMAP_SLOTS 8 +#define _XIAFS_ZMAP_SLOTS 32 + +struct xiafs_sb_info { + u_long s_nzones; + u_long s_ninodes; + u_long s_ndatazones; + u_long s_imap_zones; + u_long s_zmap_zones; + u_long s_firstdatazone; + u_long s_zone_shift; + u_long s_max_size; /* 32 bytes */ + struct buffer_head * s_imap_buf[_XIAFS_IMAP_SLOTS]; /* 32 bytes */ + struct buffer_head * s_zmap_buf[_XIAFS_ZMAP_SLOTS]; /* 128 bytes */ + int s_imap_iznr[_XIAFS_IMAP_SLOTS]; /* 32 bytes */ + int s_zmap_zznr[_XIAFS_ZMAP_SLOTS]; /* 128 bytes */ + u_char s_imap_cached; /* flag for cached imap */ + u_char s_zmap_cached; /* flag for cached imap */ +}; + +#endif /* _XIA_FS_SB_H */ + + + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/init/main.c b/gems-kernel.git/source/THIRDPARTY/linux-old/init/main.c new file mode 100644 index 000000000..41309a4ba --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/init/main.c @@ -0,0 +1,514 @@ +/* + * linux/init/main.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern unsigned long * prof_buffer; +extern unsigned long prof_len; +extern char edata, end; +extern char *linux_banner; +asmlinkage void lcall7(void); +struct desc_struct default_ldt; + +/* + * we need this inline - forking from kernel space will result + * in NO COPY ON WRITE (!!!), until an execve is executed. This + * is no problem, but for the stack. This is handled by not letting + * main() use the stack at all after fork(). Thus, no function + * calls - which means inline code for fork too, as otherwise we + * would use the stack upon exit from 'fork()'. + * + * Actually only pause and fork are needed inline, so that there + * won't be any messing with the stack from main(), but we define + * some others too. + */ +#define __NR__exit __NR_exit +static inline _syscall0(int,idle) +static inline _syscall0(int,fork) +static inline _syscall0(int,pause) +static inline _syscall1(int,setup,void *,BIOS) +static inline _syscall0(int,sync) +static inline _syscall0(pid_t,setsid) +static inline _syscall3(int,write,int,fd,const char *,buf,off_t,count) +static inline _syscall1(int,dup,int,fd) +static inline _syscall3(int,execve,const char *,file,char **,argv,char **,envp) +static inline _syscall3(int,open,const char *,file,int,flag,int,mode) +static inline _syscall1(int,close,int,fd) +static inline _syscall1(int,_exit,int,exitcode) +static inline _syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +static inline pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} + +static char printbuf[1024]; + +extern int console_loglevel; + +extern char empty_zero_page[PAGE_SIZE]; +extern int vsprintf(char *,const char *,va_list); +extern void init(void); +extern void init_IRQ(void); +extern long kmalloc_init (long,long); +extern long blk_dev_init(long,long); +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); +unsigned long net_dev_init(unsigned long, unsigned long); +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 mcd_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); +extern void sound_setup(char *str, int *ints); +#ifdef CONFIG_SBPCD +extern void sbpcd_setup(char *str, int *ints); +#endif CONFIG_SBPCD + +#ifdef CONFIG_SYSVIPC +extern void ipc_init(void); +#endif +#ifdef CONFIG_SCSI +extern unsigned long scsi_dev_init(unsigned long, unsigned long); +#endif + +/* + * This is set up by the setup-routine at boot-time + */ +#define PARAM empty_zero_page +#define EXT_MEM_K (*(unsigned short *) (PARAM+2)) +#define DRIVE_INFO (*(struct drive_info_struct *) (PARAM+0x80)) +#define SCREEN_INFO (*(struct screen_info *) (PARAM+0)) +#define MOUNT_ROOT_RDONLY (*(unsigned short *) (PARAM+0x1F2)) +#define RAMDISK_SIZE (*(unsigned short *) (PARAM+0x1F8)) +#define ORIG_ROOT_DEV (*(unsigned short *) (PARAM+0x1FC)) +#define AUX_DEVICE_INFO (*(unsigned char *) (PARAM+0x1FF)) + +/* + * Boot command-line arguments + */ +#define MAX_INIT_ARGS 8 +#define MAX_INIT_ENVS 8 +#define COMMAND_LINE ((char *) (PARAM+2048)) + +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, NULL, }; + +static char * argv_rc[] = { "/bin/sh", NULL }; +static char * envp_rc[] = { "HOME=/", term, NULL }; + +static char * argv[] = { "-/bin/sh",NULL }; +static char * envp[] = { "HOME=/usr/root", term, NULL }; + +struct drive_info_struct { char dummy[32]; } drive_info; +struct screen_info screen_info; + +unsigned char aux_device_present; +int ramdisk_size; +int root_mountflags = 0; + +static char fpu_error = 0; + +static char command_line[80] = { 0, }; + +char *get_options(char *str, int *ints) +{ + char *cur = str; + int i=1; + + while (cur && isdigit(*cur) && i <= 10) { + ints[i++] = simple_strtoul(cur,NULL,0); + if ((cur = strchr(cur,',')) != NULL) + cur++; + } + ints[0] = i-1; + return(cur); +} + +struct { + char *str; + void (*setup_func)(char *, int *); +} bootsetups[] = { + { "reserve=", reserve_setup }, +#ifdef CONFIG_INET + { "ether=", eth_setup }, +#endif +#ifdef CONFIG_BLK_DEV_HD + { "hd=", hd_setup }, +#endif +#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 +#ifdef CONFIG_MCD + { "mcd=", mcd_setup }, +#endif +#ifdef CONFIG_SOUND + { "sound=", sound_setup }, +#endif +#ifdef CONFIG_SBPCD + { "sbpcd=", sbpcd_setup }, +#endif CONFIG_SBPCD + { 0, 0 } +}; + +int checksetup(char *line) +{ + int i = 0; + int ints[11]; + + while (bootsetups[i].str) { + int n = strlen(bootsetups[i].str); + if (!strncmp(line,bootsetups[i].str,n)) { + bootsetups[i].setup_func(get_options(line+n,ints), ints); + return(0); + } + i++; + } + return(1); +} + +unsigned long loops_per_sec = 1; + +static void calibrate_delay(void) +{ + int ticks; + + printk("Calibrating delay loop.. "); + while (loops_per_sec <<= 1) { + ticks = jiffies; + __delay(loops_per_sec); + ticks = jiffies - ticks; + if (ticks >= HZ) { + __asm__("mull %1 ; divl %2" + :"=a" (loops_per_sec) + :"d" (HZ), + "r" (ticks), + "0" (loops_per_sec) + :"dx"); + printk("ok - %lu.%02lu BogoMips\n", + loops_per_sec/500000, + (loops_per_sec/5000) % 100); + return; + } + } + printk("failed\n"); +} + + +/* + * This is a simple kernel command line parsing function: it parses + * the command line, and fills in the arguments/environment to init + * as appropriate. Any cmd-line option is taken to be an environment + * variable if it contains the character '='. + * + * + * This routine also checks for options meant for the kernel - currently + * only the "root=XXXX" option is recognized. These options are not given + * to init - they are for internal kernel use only. + */ +static void parse_options(char *line) +{ + char *next; + 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) + return; + args = 0; + envs = 1; /* TERM is set to 'console' by default */ + next = line; + while ((line = next) != NULL) { + if ((next = strchr(line,' ')) != NULL) + *next++ = 0; + /* + * check for kernel options first.. + */ + if (!strncmp(line,"root=",5)) { + int n; + line += 5; + if (strncmp(line,"/dev/",5)) { + ROOT_DEV = simple_strtoul(line,NULL,16); + continue; + } + line += 5; + for (n = 0 ; devnames[n] ; n++) { + int len = strlen(devnames[n]); + if (!strncmp(line,devnames[n],len)) { + ROOT_DEV = devnums[n]+simple_strtoul(line+len,NULL,16); + break; + } + } + } else if (!strcmp(line,"ro")) + root_mountflags |= MS_RDONLY; + else if (!strcmp(line,"rw")) + root_mountflags &= ~MS_RDONLY; + else if (!strcmp(line,"debug")) + console_loglevel = 10; + else if (!strcmp(line,"no387")) { + hard_math = 0; + __asm__("movl %%cr0,%%eax\n\t" + "orl $0xE,%%eax\n\t" + "movl %%eax,%%cr0\n\t" : : : "ax"); + } else + checksetup(line); + /* + * Then check if it's an environment variable or + * an option. + */ + if (strchr(line,'=')) { + if (envs >= MAX_INIT_ENVS) + break; + envp_init[++envs] = line; + } else { + if (args >= MAX_INIT_ARGS) + break; + argv_init[++args] = line; + } + } + argv_init[args+1] = NULL; + envp_init[envs+1] = NULL; +} + +static void copro_timeout(void) +{ + fpu_error = 1; + timer_table[COPRO_TIMER].expires = jiffies+100; + timer_active |= 1< 16*1024*1024) + memory_end = 16*1024*1024; +#endif + if (MOUNT_ROOT_RDONLY) + root_mountflags |= MS_RDONLY; + if ((unsigned long)&end >= (1024*1024)) { + memory_start = (unsigned long) &end; + low_memory_start = PAGE_SIZE; + } else { + memory_start = 1024*1024; + low_memory_start = (unsigned long) &end; + } + low_memory_start = PAGE_ALIGN(low_memory_start); + memory_start = paging_init(memory_start,memory_end); + if (strncmp((char*)0x0FFFD9, "EISA", 4) == 0) + EISA_bus = 1; + trap_init(); + init_IRQ(); + sched_init(); + parse_options(command_line); +#ifdef CONFIG_PROFILE + prof_buffer = (unsigned long *) memory_start; + prof_len = (unsigned long) &end; + prof_len >>= 2; + memory_start += prof_len * sizeof(unsigned long); +#endif + memory_start = kmalloc_init(memory_start,memory_end); + memory_start = chr_dev_init(memory_start,memory_end); + memory_start = blk_dev_init(memory_start,memory_end); + sti(); + calibrate_delay(); +#ifdef CONFIG_INET + memory_start = net_dev_init(memory_start,memory_end); +#endif +#ifdef CONFIG_SCSI + memory_start = scsi_dev_init(memory_start,memory_end); +#endif + memory_start = inode_init(memory_start,memory_end); + memory_start = file_table_init(memory_start,memory_end); + mem_init(low_memory_start,memory_start,memory_end); + buffer_init(); + time_init(); + floppy_init(); + sock_init(); +#ifdef CONFIG_SYSVIPC + ipc_init(); +#endif + sti(); + + /* + * check if exception 16 works correctly.. This is truly evil + * code: it disables the high 8 interrupts to make sure that + * the irq13 doesn't happen. But as this will lead to a lockup + * if no exception16 arrives, it depends on the fact that the + * high 8 interrupts will be re-enabled by the next timer tick. + * So the irq13 will happen eventually, but the exception 16 + * should get there first.. + */ + if (hard_math) { + unsigned short control_word; + + printk("Checking 386/387 coupling... "); + timer_table[COPRO_TIMER].expires = jiffies+50; + timer_table[COPRO_TIMER].fn = copro_timeout; + timer_active |= 1<0) + while (pid != wait(&i)) + /* nothing */; + while (1) { + if ((pid = fork()) < 0) { + printf("Fork failed in init\n\r"); + continue; + } + if (!pid) { + close(0);close(1);close(2); + setsid(); + (void) open("/dev/tty1",O_RDWR,0); + (void) dup(0); + (void) dup(0); + _exit(execve("/bin/sh",argv,envp)); + } + while (1) + if (pid == wait(&i)) + break; + printf("\n\rchild %d died with code %04x\n\r",pid,i); + sync(); + } + _exit(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/Makefile new file mode 100644 index 000000000..a3a18a7ae --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/Makefile @@ -0,0 +1,38 @@ +# +# Makefile for the linux ipc. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) -S $< + +OBJS = 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) + +dep: + $(CPP) -M $(SRCS) > .depend + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/msg.c b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/msg.c new file mode 100644 index 000000000..fa900515e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/msg.c @@ -0,0 +1,420 @@ +/* + * linux/ipc/msg.c + * Copyright (C) 1992 Krishna Balasubramanian + */ + +#include +#include +#include +#include +#include + +#include + +extern int ipcperms (struct ipc_perm *ipcp, short msgflg); + +static void freeque (int id); +static int newque (key_t key, int msgflg); +static int findkey (key_t key); + +static struct msqid_ds *msgque[MSGMNI]; +static int msgbytes = 0; +static int msghdrs = 0; +static unsigned short msg_seq = 0; +static int used_queues = 0; +static int max_msqid = 0; +static struct wait_queue *msg_lock = NULL; + +void msg_init (void) +{ + int id; + + for (id=0; id < MSGMNI; id++) + msgque[id] = (struct msqid_ds *) IPC_UNUSED; + msgbytes = msghdrs = msg_seq = max_msqid = used_queues = 0; + msg_lock = NULL; + return; +} + +int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg) +{ + int id, err; + struct msqid_ds *msq; + struct ipc_perm *ipcp; + struct msg *msgh; + long mtype; + + if (msgsz > MSGMAX || msgsz < 0 || msqid < 0) + return -EINVAL; + if (!msgp) + return -EFAULT; + err = verify_area (VERIFY_READ, msgp->mtext, msgsz); + if (err) + return err; + if ((mtype = get_fs_long (&msgp->mtype)) < 1) + return -EINVAL; + id = msqid % MSGMNI; + msq = msgque [id]; + if (msq == IPC_UNUSED || msq == IPC_NOID) + return -EINVAL; + ipcp = &msq->msg_perm; + + slept: + if (ipcp->seq != (msqid / MSGMNI)) + return -EIDRM; + if (ipcperms(ipcp, S_IWUGO)) + return -EACCES; + + if (msgsz + msq->msg_cbytes > msq->msg_qbytes) { + /* no space in queue */ + if (msgflg & IPC_NOWAIT) + return -EAGAIN; + if (current->signal & ~current->blocked) + return -EINTR; + interruptible_sleep_on (&msq->wwait); + goto slept; + } + + /* allocate message header and text space*/ + msgh = (struct msg *) kmalloc (sizeof(*msgh) + msgsz, GFP_USER); + if (!msgh) + return -ENOMEM; + msgh->msg_spot = (char *) (msgh + 1); + memcpy_fromfs (msgh->msg_spot, msgp->mtext, msgsz); + + if (msgque[id] == IPC_UNUSED || msgque[id] == IPC_NOID + || ipcp->seq != msqid / MSGMNI) { + kfree_s (msgh, sizeof(*msgh) + msgsz); + return -EIDRM; + } + + msgh->msg_next = NULL; + if (!msq->msg_first) + msq->msg_first = msq->msg_last = msgh; + else { + msq->msg_last->msg_next = msgh; + msq->msg_last = msgh; + } + msgh->msg_ts = msgsz; + msgh->msg_type = mtype; + msq->msg_cbytes += msgsz; + msgbytes += msgsz; + msghdrs++; + msq->msg_qnum++; + msq->msg_lspid = current->pid; + msq->msg_stime = CURRENT_TIME; + if (msq->rwait) + wake_up (&msq->rwait); + return msgsz; +} + +int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, + int msgflg) +{ + struct msqid_ds *msq; + struct ipc_perm *ipcp; + struct msg *tmsg, *leastp = NULL; + struct msg *nmsg = NULL; + int id, err; + + if (msqid < 0 || msgsz < 0) + return -EINVAL; + if (!msgp || !msgp->mtext) + return -EFAULT; + err = verify_area (VERIFY_WRITE, msgp->mtext, msgsz); + if (err) + return err; + + id = msqid % MSGMNI; + msq = msgque [id]; + if (msq == IPC_NOID || msq == IPC_UNUSED) + return -EINVAL; + ipcp = &msq->msg_perm; + + /* + * find message of correct type. + * msgtyp = 0 => get first. + * msgtyp > 0 => get first message of matching type. + * msgtyp < 0 => get message with least type must be < abs(msgtype). + */ + while (!nmsg) { + if(ipcp->seq != msqid / MSGMNI) + return -EIDRM; + if (ipcperms (ipcp, S_IRUGO)) + return -EACCES; + if (msgtyp == 0) + nmsg = msq->msg_first; + else if (msgtyp > 0) { + if (msgflg & MSG_EXCEPT) { + for (tmsg = msq->msg_first; tmsg; + tmsg = tmsg->msg_next) + if (tmsg->msg_type != msgtyp) + break; + nmsg = tmsg; + } else { + for (tmsg = msq->msg_first; tmsg; + tmsg = tmsg->msg_next) + if (tmsg->msg_type == msgtyp) + break; + nmsg = tmsg; + } + } else { + for (leastp = tmsg = msq->msg_first; tmsg; + tmsg = tmsg->msg_next) + if (tmsg->msg_type < leastp->msg_type) + leastp = tmsg; + if (leastp && leastp->msg_type <= - msgtyp) + nmsg = leastp; + } + + if (nmsg) { /* done finding a message */ + if ((msgsz < nmsg->msg_ts) && !(msgflg & MSG_NOERROR)) + return -E2BIG; + msgsz = (msgsz > nmsg->msg_ts)? nmsg->msg_ts : msgsz; + if (nmsg == msq->msg_first) + msq->msg_first = nmsg->msg_next; + else { + for (tmsg= msq->msg_first; tmsg; + tmsg = tmsg->msg_next) + if (tmsg->msg_next == nmsg) + break; + tmsg->msg_next = nmsg->msg_next; + if (nmsg == msq->msg_last) + msq->msg_last = tmsg; + } + if (!(--msq->msg_qnum)) + msq->msg_last = msq->msg_first = NULL; + + msq->msg_rtime = CURRENT_TIME; + msq->msg_lrpid = current->pid; + msgbytes -= nmsg->msg_ts; + msghdrs--; + msq->msg_cbytes -= nmsg->msg_ts; + if (msq->wwait) + wake_up (&msq->wwait); + put_fs_long (nmsg->msg_type, &msgp->mtype); + memcpy_tofs (msgp->mtext, nmsg->msg_spot, msgsz); + kfree_s (nmsg, sizeof(*nmsg) + msgsz); + return msgsz; + } else { /* did not find a message */ + if (msgflg & IPC_NOWAIT) + return -ENOMSG; + if (current->signal & ~current->blocked) + return -EINTR; + interruptible_sleep_on (&msq->rwait); + } + } /* end while */ + return -1; +} + + +static int findkey (key_t key) +{ + int id; + struct msqid_ds *msq; + + for (id=0; id <= max_msqid; id++) { + while ((msq = msgque[id]) == IPC_NOID) + interruptible_sleep_on (&msg_lock); + if (msq == IPC_UNUSED) + continue; + if (key == msq->msg_perm.key) + return id; + } + return -1; +} + +static int newque (key_t key, int msgflg) +{ + int id; + struct msqid_ds *msq; + struct ipc_perm *ipcp; + + for (id=0; id < MSGMNI; id++) + if (msgque[id] == IPC_UNUSED) { + msgque[id] = (struct msqid_ds *) IPC_NOID; + goto found; + } + return -ENOSPC; + +found: + msq = (struct msqid_ds *) kmalloc (sizeof (*msq), GFP_KERNEL); + if (!msq) { + msgque[id] = (struct msqid_ds *) IPC_UNUSED; + if (msg_lock) + wake_up (&msg_lock); + return -ENOMEM; + } + ipcp = &msq->msg_perm; + ipcp->mode = (msgflg & S_IRWXUGO); + ipcp->key = key; + ipcp->cuid = ipcp->uid = current->euid; + ipcp->gid = ipcp->cgid = current->egid; + ipcp->seq = msg_seq; + msq->msg_first = msq->msg_last = NULL; + msq->rwait = msq->wwait = NULL; + msq->msg_cbytes = msq->msg_qnum = 0; + msq->msg_lspid = msq->msg_lrpid = 0; + msq->msg_stime = msq->msg_rtime = 0; + msq->msg_qbytes = MSGMNB; + msq->msg_ctime = CURRENT_TIME; + if (id > max_msqid) + max_msqid = id; + msgque[id] = msq; + used_queues++; + if (msg_lock) + wake_up (&msg_lock); + return (int) msg_seq * MSGMNI + id; +} + +int sys_msgget (key_t key, int msgflg) +{ + int id; + struct msqid_ds *msq; + + if (key == IPC_PRIVATE) + return newque(key, msgflg); + if ((id = findkey (key)) == -1) { /* key not used */ + if (!(msgflg & IPC_CREAT)) + return -ENOENT; + return newque(key, msgflg); + } + if (msgflg & IPC_CREAT && msgflg & IPC_EXCL) + return -EEXIST; + msq = msgque[id]; + if (msq == IPC_UNUSED || msq == IPC_NOID) + return -EIDRM; + if (ipcperms(&msq->msg_perm, msgflg)) + return -EACCES; + return msq->msg_perm.seq * MSGMNI +id; +} + +static void freeque (int id) +{ + struct msqid_ds *msq = msgque[id]; + struct msg *msgp, *msgh; + + msq->msg_perm.seq++; + msg_seq++; + msgbytes -= msq->msg_cbytes; + if (id == max_msqid) + while (max_msqid && (msgque[--max_msqid] == IPC_UNUSED)); + msgque[id] = (struct msqid_ds *) IPC_UNUSED; + used_queues--; + while (msq->rwait || msq->wwait) { + if (msq->rwait) + wake_up (&msq->rwait); + if (msq->wwait) + wake_up (&msq->wwait); + schedule(); + } + for (msgp = msq->msg_first; msgp; msgp = msgh ) { + msgh = msgp->msg_next; + msghdrs--; + kfree_s (msgp, sizeof(*msgp) + msgp->msg_ts); + } + kfree_s (msq, sizeof (*msq)); +} + +int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf) +{ + int id, err; + struct msqid_ds *msq, tbuf; + struct ipc_perm *ipcp; + + if (msqid < 0 || cmd < 0) + return -EINVAL; + switch (cmd) { + case IPC_INFO: + case MSG_INFO: + if (!buf) + return -EFAULT; + { + struct msginfo msginfo; + msginfo.msgmni = MSGMNI; + msginfo.msgmax = MSGMAX; + msginfo.msgmnb = MSGMNB; + msginfo.msgmap = MSGMAP; + msginfo.msgpool = MSGPOOL; + msginfo.msgtql = MSGTQL; + msginfo.msgssz = MSGSSZ; + msginfo.msgseg = MSGSEG; + if (cmd == MSG_INFO) { + msginfo.msgpool = used_queues; + msginfo.msgmap = msghdrs; + msginfo.msgtql = msgbytes; + } + err = verify_area (VERIFY_WRITE, buf, sizeof (struct msginfo)); + if (err) + return err; + memcpy_tofs (buf, &msginfo, sizeof(struct msginfo)); + return max_msqid; + } + case MSG_STAT: + if (!buf) + return -EFAULT; + err = verify_area (VERIFY_WRITE, buf, sizeof (*msq)); + if (err) + return err; + if (msqid > max_msqid) + return -EINVAL; + msq = msgque[msqid]; + if (msq == IPC_UNUSED || msq == IPC_NOID) + return -EINVAL; + if (ipcperms (&msq->msg_perm, S_IRUGO)) + return -EACCES; + id = msqid + msq->msg_perm.seq * MSGMNI; + memcpy_tofs (buf, msq, sizeof(*msq)); + return id; + case IPC_SET: + if (!buf) + return -EFAULT; + memcpy_fromfs (&tbuf, buf, sizeof (*buf)); + break; + case IPC_STAT: + if (!buf) + return -EFAULT; + err = verify_area (VERIFY_WRITE, buf, sizeof(*msq)); + if (err) + return err; + break; + } + + id = msqid % MSGMNI; + msq = msgque [id]; + if (msq == IPC_UNUSED || msq == IPC_NOID) + return -EINVAL; + ipcp = &msq->msg_perm; + if (ipcp->seq != msqid / MSGMNI) + return -EIDRM; + + switch (cmd) { + case IPC_STAT: + if (ipcperms (ipcp, S_IRUGO)) + return -EACCES; + memcpy_tofs (buf, msq, sizeof (*msq)); + return 0; + break; + case IPC_RMID: case IPC_SET: + if (!suser() && current->euid != ipcp->cuid && + current->euid != ipcp->uid) + return -EPERM; + if (cmd == IPC_RMID) { + freeque (id); + return 0; + } + if (tbuf.msg_qbytes > MSGMNB && !suser()) + return -EPERM; + msq->msg_qbytes = tbuf.msg_qbytes; + ipcp->uid = tbuf.msg_perm.uid; + ipcp->gid = tbuf.msg_perm.gid; + ipcp->mode = (ipcp->mode & ~S_IRWXUGO) | + (S_IRWXUGO & tbuf.msg_perm.mode); + msq->msg_ctime = CURRENT_TIME; + break; + default: + return -EINVAL; + break; + } + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/sem.c b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/sem.c new file mode 100644 index 000000000..a8ec596d0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/sem.c @@ -0,0 +1,508 @@ +/* + * linux/ipc/sem.c + * Copyright (C) 1992 Krishna Balasubramanian + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +extern int ipcperms (struct ipc_perm *ipcp, short semflg); +static int newary (key_t, int, int); +static int findkey (key_t key); +static void freeary (int id); + +static struct semid_ds *semary[SEMMNI]; +static int used_sems = 0, used_semids = 0; +static struct wait_queue *sem_lock = NULL; +static int max_semid = 0; + +static unsigned short sem_seq = 0; + +void sem_init (void) +{ + int i=0; + + sem_lock = NULL; + used_sems = used_semids = max_semid = sem_seq = 0; + for (i=0; i < SEMMNI; i++) + semary[i] = (struct semid_ds *) IPC_UNUSED; + return; +} + +static int findkey (key_t key) +{ + int id; + struct semid_ds *sma; + + for (id=0; id <= max_semid; id++) { + while ((sma = semary[id]) == IPC_NOID) + interruptible_sleep_on (&sem_lock); + if (sma == IPC_UNUSED) + continue; + if (key == sma->sem_perm.key) + return id; + } + return -1; +} + +static int newary (key_t key, int nsems, int semflg) +{ + int id; + struct semid_ds *sma; + struct ipc_perm *ipcp; + int size; + + if (!nsems) + return -EINVAL; + if (used_sems + nsems > SEMMNS) + return -ENOSPC; + for (id=0; id < SEMMNI; id++) + if (semary[id] == IPC_UNUSED) { + semary[id] = (struct semid_ds *) IPC_NOID; + goto found; + } + return -ENOSPC; +found: + size = sizeof (*sma) + nsems * sizeof (struct sem); + used_sems += nsems; + sma = (struct semid_ds *) kmalloc (size, GFP_KERNEL); + if (!sma) { + semary[id] = (struct semid_ds *) IPC_UNUSED; + used_sems -= nsems; + if (sem_lock) + wake_up (&sem_lock); + return -ENOMEM; + } + memset (sma, 0, size); + sma->sem_base = (struct sem *) &sma[1]; + ipcp = &sma->sem_perm; + ipcp->mode = (semflg & S_IRWXUGO); + ipcp->key = key; + ipcp->cuid = ipcp->uid = current->euid; + ipcp->gid = ipcp->cgid = current->egid; + ipcp->seq = sem_seq; + sma->eventn = sma->eventz = NULL; + sma->sem_nsems = nsems; + sma->sem_ctime = CURRENT_TIME; + if (id > max_semid) + max_semid = id; + used_semids++; + semary[id] = sma; + if (sem_lock) + wake_up (&sem_lock); + return (int) sem_seq * SEMMNI + id; +} + +int sys_semget (key_t key, int nsems, int semflg) +{ + int id; + struct semid_ds *sma; + + if (nsems < 0 || nsems > SEMMSL) + return -EINVAL; + if (key == IPC_PRIVATE) + return newary(key, nsems, semflg); + if ((id = findkey (key)) == -1) { /* key not used */ + if (!(semflg & IPC_CREAT)) + return -ENOENT; + return newary(key, nsems, semflg); + } + if (semflg & IPC_CREAT && semflg & IPC_EXCL) + return -EEXIST; + sma = semary[id]; + if (nsems > sma->sem_nsems) + return -EINVAL; + if (ipcperms(&sma->sem_perm, semflg)) + return -EACCES; + return sma->sem_perm.seq*SEMMNI + id; +} + +static void freeary (int id) +{ + struct semid_ds *sma = semary[id]; + struct sem_undo *un; + + sma->sem_perm.seq++; + sem_seq++; + used_sems -= sma->sem_nsems; + if (id == max_semid) + while (max_semid && (semary[--max_semid] == IPC_UNUSED)); + semary[id] = (struct semid_ds *) IPC_UNUSED; + used_semids--; + for (un=sma->undo; un; un=un->id_next) + un->semadj = 0; + while (sma->eventz || sma->eventn) { + if (sma->eventz) + wake_up (&sma->eventz); + if (sma->eventn) + wake_up (&sma->eventn); + schedule(); + } + kfree_s (sma, sizeof (*sma) + sma->sem_nsems * sizeof (struct sem)); + return; +} + +int sys_semctl (int semid, int semnum, int cmd, void *arg) +{ + int i, id, val = 0; + struct semid_ds *sma, *buf = NULL, tbuf; + struct ipc_perm *ipcp; + struct sem *curr; + struct sem_undo *un; + ushort nsems, *array = NULL; + ushort sem_io[SEMMSL]; + + if (semid < 0 || semnum < 0 || cmd < 0) + return -EINVAL; + + switch (cmd) { + case IPC_INFO: + case SEM_INFO: + { + struct seminfo seminfo, *tmp; + if (!arg || ! (tmp = (struct seminfo *) get_fs_long((int *)arg))) + return -EFAULT; + seminfo.semmni = SEMMNI; + seminfo.semmns = SEMMNS; + seminfo.semmsl = SEMMSL; + seminfo.semopm = SEMOPM; + seminfo.semvmx = SEMVMX; + seminfo.semmnu = SEMMNU; + seminfo.semmap = SEMMAP; + seminfo.semume = SEMUME; + seminfo.semusz = SEMUSZ; + seminfo.semaem = SEMAEM; + if (cmd == SEM_INFO) { + seminfo.semusz = used_semids; + seminfo.semaem = used_sems; + } + i= verify_area(VERIFY_WRITE, tmp, sizeof(struct seminfo)); + if (i) + return i; + memcpy_tofs (tmp, &seminfo, sizeof(struct seminfo)); + return max_semid; + } + + case SEM_STAT: + if (!arg || ! (buf = (struct semid_ds *) get_fs_long((int *) arg))) + return -EFAULT; + i = verify_area (VERIFY_WRITE, buf, sizeof (*sma)); + if (i) + return i; + if (semid > max_semid) + return -EINVAL; + sma = semary[semid]; + if (sma == IPC_UNUSED || sma == IPC_NOID) + return -EINVAL; + if (ipcperms (&sma->sem_perm, S_IRUGO)) + return -EACCES; + id = semid + sma->sem_perm.seq * SEMMNI; + memcpy_tofs (buf, sma, sizeof(*sma)); + return id; + } + + id = semid % SEMMNI; + sma = semary [id]; + if (sma == IPC_UNUSED || sma == IPC_NOID) + return -EINVAL; + ipcp = &sma->sem_perm; + nsems = sma->sem_nsems; + if (ipcp->seq != semid / SEMMNI) + return -EIDRM; + if (semnum >= nsems) + return -EINVAL; + curr = &sma->sem_base[semnum]; + + switch (cmd) { + case GETVAL: + case GETPID: + case GETNCNT: + case GETZCNT: + case GETALL: + if (ipcperms (ipcp, S_IRUGO)) + return -EACCES; + switch (cmd) { + case GETVAL : return curr->semval; + case GETPID : return curr->sempid; + case GETNCNT: return curr->semncnt; + case GETZCNT: return curr->semzcnt; + case GETALL: + if (!arg || ! (array = (ushort *) get_fs_long((int *) arg))) + return -EFAULT; + i = verify_area (VERIFY_WRITE, array, nsems* sizeof(short)); + if (i) + return i; + } + break; + case SETVAL: + if (!arg) + return -EFAULT; + if ((val = (int) get_fs_long ((int *) arg)) > SEMVMX || val < 0) + return -ERANGE; + break; + case IPC_RMID: + if (suser() || current->euid == ipcp->cuid || + current->euid == ipcp->uid) { + freeary (id); + return 0; + } + return -EPERM; + case SETALL: /* arg is a pointer to an array of ushort */ + if (!arg || ! (array = (ushort *) get_fs_long ((int *) arg)) ) + return -EFAULT; + if ((i = verify_area (VERIFY_READ, array, sizeof tbuf))) + return i; + memcpy_fromfs (sem_io, array, nsems*sizeof(ushort)); + for (i=0; i< nsems; i++) + if (sem_io[i] > SEMVMX) + return -ERANGE; + break; + case IPC_STAT: + if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) + return -EFAULT; + if ((i = verify_area (VERIFY_WRITE, arg, sizeof tbuf))) + return i; + break; + case IPC_SET: + if (!arg || !(buf = (struct semid_ds *) get_fs_long((int *) arg))) + return -EFAULT; + if ((i = verify_area (VERIFY_READ, buf, sizeof tbuf))) + return i; + memcpy_fromfs (&tbuf, buf, sizeof tbuf); + break; + } + + if (semary[id] == IPC_UNUSED || semary[id] == IPC_NOID) + return -EIDRM; + if (ipcp->seq != semid / SEMMNI) + return -EIDRM; + + switch (cmd) { + case GETALL: + if (ipcperms (ipcp, S_IRUGO)) + return -EACCES; + for (i=0; i< sma->sem_nsems; i++) + sem_io[i] = sma->sem_base[i].semval; + memcpy_tofs (array, sem_io, nsems*sizeof(ushort)); + break; + case SETVAL: + if (ipcperms (ipcp, S_IWUGO)) + return -EACCES; + for (un = sma->undo; un; un = un->id_next) + if (semnum == un->sem_num) + un->semadj = 0; + sma->sem_ctime = CURRENT_TIME; + curr->semval = val; + if (sma->eventn) + wake_up (&sma->eventn); + if (sma->eventz) + wake_up (&sma->eventz); + break; + case IPC_SET: + if (suser() || current->euid == ipcp->cuid || + current->euid == ipcp->uid) { + ipcp->uid = tbuf.sem_perm.uid; + ipcp->gid = tbuf.sem_perm.gid; + ipcp->mode = (ipcp->mode & ~S_IRWXUGO) + | (tbuf.sem_perm.mode & S_IRWXUGO); + sma->sem_ctime = CURRENT_TIME; + return 0; + } + return -EPERM; + case IPC_STAT: + if (ipcperms (ipcp, S_IRUGO)) + return -EACCES; + memcpy_tofs (buf, sma, sizeof (*sma)); + break; + case SETALL: + if (ipcperms (ipcp, S_IWUGO)) + return -EACCES; + for (i=0; isem_base[i].semval = sem_io[i]; + for (un = sma->undo; un; un = un->id_next) + un->semadj = 0; + if (sma->eventn) + wake_up (&sma->eventn); + if (sma->eventz) + wake_up (&sma->eventz); + sma->sem_ctime = CURRENT_TIME; + break; + default: + return -EINVAL; + } + return 0; +} + +int sys_semop (int semid, struct sembuf *tsops, unsigned nsops) +{ + int i, id; + struct semid_ds *sma; + struct sem *curr = NULL; + struct sembuf sops[SEMOPM], *sop; + struct sem_undo *un; + int undos = 0, alter = 0, semncnt = 0, semzcnt = 0; + + if (nsops < 1 || semid < 0) + return -EINVAL; + if (nsops > SEMOPM) + return -E2BIG; + if (!tsops) + return -EFAULT; + memcpy_fromfs (sops, tsops, nsops * sizeof(*tsops)); + id = semid % SEMMNI; + if ((sma = semary[id]) == IPC_UNUSED || sma == IPC_NOID) + return -EINVAL; + for (i=0; isem_num > sma->sem_nsems) + return -EFBIG; + if (sop->sem_flg & SEM_UNDO) + undos++; + if (sop->sem_op) { + alter++; + if (sop->sem_op > 0) + semncnt ++; + } + } + if (ipcperms(&sma->sem_perm, alter ? S_IWUGO : S_IRUGO)) + return -EACCES; + /* + * ensure every sop with undo gets an undo structure + */ + if (undos) { + for (i=0; isemun; un; un = un->proc_next) + if ((un->semid == semid) && + (un->sem_num == sops[i].sem_num)) + break; + if (un) + continue; + un = (struct sem_undo *) + kmalloc (sizeof(*un), GFP_ATOMIC); + if (!un) + return -ENOMEM; /* freed on exit */ + un->semid = semid; + un->semadj = 0; + un->sem_num = sops[i].sem_num; + un->proc_next = current->semun; + current->semun = un; + un->id_next = sma->undo; + sma->undo = un; + } + } + + slept: + if (sma->sem_perm.seq != semid / SEMMNI) + return -EIDRM; + for (i=0; isem_base[sop->sem_num]; + if (sop->sem_op + curr->semval > SEMVMX) + return -ERANGE; + if (!sop->sem_op && curr->semval) { + if (sop->sem_flg & IPC_NOWAIT) + return -EAGAIN; + if (current->signal & ~current->blocked) + return -EINTR; + curr->semzcnt++; + interruptible_sleep_on (&sma->eventz); + curr->semzcnt--; + goto slept; + } + if ((sop->sem_op + curr->semval < 0) ) { + if (sop->sem_flg & IPC_NOWAIT) + return -EAGAIN; + if (current->signal & ~current->blocked) + return -EINTR; + curr->semncnt++; + interruptible_sleep_on (&sma->eventn); + curr->semncnt--; + goto slept; + } + } + + for (i=0; isem_base[sop->sem_num]; + curr->sempid = current->pid; + if (!(curr->semval += sop->sem_op)) + semzcnt++; + if (!(sop->sem_flg & SEM_UNDO)) + continue; + for (un = current->semun; un; un = un->proc_next) + if ((un->semid == semid) && + (un->sem_num == sop->sem_num)) + break; + if (!un) { + printk ("semop : no undo for op %d\n", i); + continue; + } + un->semadj -= sop->sem_op; + } + sma->sem_otime = CURRENT_TIME; + if (semncnt && sma->eventn) + wake_up(&sma->eventn); + if (semzcnt && sma->eventz) + wake_up(&sma->eventz); + return curr->semval; +} + +/* + * add semadj values to semaphores, free undo structures. + * undo structures are not freed when semaphore arrays are destroyed + * so some of them may be out of date. + */ +void sem_exit (void) +{ + struct sem_undo *u, *un = NULL, **up, **unp; + struct semid_ds *sma; + struct sem *sem = NULL; + + for (up = ¤t->semun; (u = *up); *up = u->proc_next, kfree(u)) { + sma = semary[u->semid % SEMMNI]; + if (sma == IPC_UNUSED || sma == IPC_NOID) + continue; + if (sma->sem_perm.seq != u->semid / SEMMNI) + continue; + for (unp = &sma->undo; (un = *unp); unp = &un->id_next) { + if (u == un) + goto found; + } + printk ("sem_exit undo list error id=%d\n", u->semid); + break; +found: + *unp = un->id_next; + if (!un->semadj) + continue; + while (1) { + if (sma->sem_perm.seq != un->semid / SEMMNI) + break; + sem = &sma->sem_base[un->sem_num]; + if (sem->semval + un->semadj >= 0) { + sem->semval += un->semadj; + sem->sempid = current->pid; + sma->sem_otime = CURRENT_TIME; + if (un->semadj > 0 && sma->eventn) + wake_up (&sma->eventn); + if (!sem->semval && sma->eventz) + wake_up (&sma->eventz); + break; + } + if (current->signal & ~current->blocked) + break; + sem->semncnt++; + interruptible_sleep_on (&sma->eventn); + sem->semncnt--; + } + } + current->semun = NULL; + return; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/shm.c b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/shm.c new file mode 100644 index 000000000..b486e625b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/shm.c @@ -0,0 +1,728 @@ +/* + * linux/ipc/shm.c + * Copyright (C) 1992, 1993 Krishna Balasubramanian + * Many improvements/fixes by Bruno Haible. + * assume user segments start at 0x0 + */ + +#include +#include +#include +#include +#include +#include +#include + +extern int ipcperms (struct ipc_perm *ipcp, short semflg); +extern unsigned int get_swap_page(void); +static int findkey (key_t key); +static int newseg (key_t key, int shmflg, int size); +static int shm_map (struct shm_desc *shmd, int remap); +static void killseg (int id); + +static int shm_tot = 0; /* total number of shared memory pages */ +static int shm_rss = 0; /* number of shared memory pages that are in memory */ +static int shm_swp = 0; /* number of shared memory pages that are in swap */ +static int max_shmid = 0; /* every used id is <= max_shmid */ +static struct wait_queue *shm_lock = NULL; +static struct shmid_ds *shm_segs[SHMMNI]; + +static unsigned short shm_seq = 0; /* incremented, for recognizing stale ids */ + +/* some statistics */ +static ulong swap_attempts = 0; +static ulong swap_successes = 0; +static ulong used_segs = 0; + +void shm_init (void) +{ + int id; + + for (id = 0; id < SHMMNI; id++) + shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; + shm_tot = shm_rss = shm_seq = max_shmid = used_segs = 0; + shm_lock = NULL; + return; +} + +static int findkey (key_t key) +{ + int id; + struct shmid_ds *shp; + + for (id=0; id <= max_shmid; id++) { + while ((shp = shm_segs[id]) == IPC_NOID) + sleep_on (&shm_lock); + if (shp == IPC_UNUSED) + continue; + if (key == shp->shm_perm.key) + return id; + } + return -1; +} + +/* + * allocate new shmid_ds and pgtable. protected by shm_segs[id] = NOID. + */ +static int newseg (key_t key, int shmflg, int size) +{ + struct shmid_ds *shp; + int numpages = (size + PAGE_SIZE -1) >> PAGE_SHIFT; + int id, i; + + if (size < SHMMIN) + return -EINVAL; + if (shm_tot + numpages >= SHMALL) + return -ENOSPC; + for (id=0; id < SHMMNI; id++) + if (shm_segs[id] == IPC_UNUSED) { + shm_segs[id] = (struct shmid_ds *) IPC_NOID; + goto found; + } + return -ENOSPC; + +found: + shp = (struct shmid_ds *) kmalloc (sizeof (*shp), GFP_KERNEL); + if (!shp) { + shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; + if (shm_lock) + wake_up (&shm_lock); + return -ENOMEM; + } + + shp->shm_pages = (ulong *) kmalloc (numpages*sizeof(ulong),GFP_KERNEL); + if (!shp->shm_pages) { + shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; + if (shm_lock) + wake_up (&shm_lock); + kfree_s (shp, sizeof (*shp)); + return -ENOMEM; + } + + for (i=0; i< numpages; shp->shm_pages[i++] = 0); + shm_tot += numpages; + shp->shm_perm.key = key; + shp->shm_perm.mode = (shmflg & S_IRWXUGO); + shp->shm_perm.cuid = shp->shm_perm.uid = current->euid; + shp->shm_perm.cgid = shp->shm_perm.gid = current->egid; + shp->shm_perm.seq = shm_seq; + shp->shm_segsz = size; + shp->shm_cpid = current->pid; + shp->attaches = NULL; + shp->shm_lpid = shp->shm_nattch = 0; + shp->shm_atime = shp->shm_dtime = 0; + shp->shm_ctime = CURRENT_TIME; + shp->shm_npages = numpages; + + if (id > max_shmid) + max_shmid = id; + shm_segs[id] = shp; + used_segs++; + if (shm_lock) + wake_up (&shm_lock); + return id + (int)shm_seq*SHMMNI; +} + +int sys_shmget (key_t key, int size, int shmflg) +{ + struct shmid_ds *shp; + int id = 0; + + if (size < 0 || size > SHMMAX) + return -EINVAL; + if (key == IPC_PRIVATE) + return newseg(key, shmflg, size); + if ((id = findkey (key)) == -1) { + if (!(shmflg & IPC_CREAT)) + return -ENOENT; + return newseg(key, shmflg, size); + } + if ((shmflg & IPC_CREAT) && (shmflg & IPC_EXCL)) + return -EEXIST; + shp = shm_segs[id]; + if (shp->shm_perm.mode & SHM_DEST) + return -EIDRM; + if (size > shp->shm_segsz) + return -EINVAL; + if (ipcperms (&shp->shm_perm, shmflg)) + return -EACCES; + return shp->shm_perm.seq*SHMMNI + id; +} + +/* + * Only called after testing nattch and SHM_DEST. + * Here pages, pgtable and shmid_ds are freed. + */ +static void killseg (int id) +{ + struct shmid_ds *shp; + int i, numpages; + ulong page; + + shp = shm_segs[id]; + if (shp == IPC_NOID || shp == IPC_UNUSED) { + printk ("shm nono: killseg called on unused seg id=%d\n", id); + return; + } + shp->shm_perm.seq++; /* for shmat */ + numpages = shp->shm_npages; + shm_seq++; + shm_segs[id] = (struct shmid_ds *) IPC_UNUSED; + used_segs--; + if (id == max_shmid) + while (max_shmid && (shm_segs[--max_shmid] == IPC_UNUSED)); + if (!shp->shm_pages) { + printk ("shm nono: killseg shp->pages=NULL. id=%d\n", id); + return; + } + for (i=0; i< numpages ; i++) { + if (!(page = shp->shm_pages[i])) + continue; + if (page & 1) { + free_page (page & PAGE_MASK); + shm_rss--; + } else { + swap_free (page); + shm_swp--; + } + } + kfree_s (shp->shm_pages, numpages * sizeof (ulong)); + shm_tot -= numpages; + kfree_s (shp, sizeof (*shp)); + return; +} + +int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf) +{ + struct shmid_ds *shp, tbuf; + struct ipc_perm *ipcp; + int id, err; + + if (cmd < 0 || shmid < 0) + return -EINVAL; + if (cmd == IPC_SET) { + if (!buf) + return -EFAULT; + err = verify_area (VERIFY_READ, buf, sizeof (*buf)); + if (err) + return err; + memcpy_fromfs (&tbuf, buf, sizeof (*buf)); + } + + switch (cmd) { /* replace with proc interface ? */ + case IPC_INFO: + { + struct shminfo shminfo; + if (!buf) + return -EFAULT; + shminfo.shmmni = SHMMNI; + shminfo.shmmax = SHMMAX; + shminfo.shmmin = SHMMIN; + shminfo.shmall = SHMALL; + shminfo.shmseg = SHMSEG; + err = verify_area (VERIFY_WRITE, buf, sizeof (struct shminfo)); + if (err) + return err; + memcpy_tofs (buf, &shminfo, sizeof(struct shminfo)); + return max_shmid; + } + case SHM_INFO: + { + struct shm_info shm_info; + if (!buf) + return -EFAULT; + err = verify_area (VERIFY_WRITE, buf, sizeof (shm_info)); + if (err) + return err; + shm_info.used_ids = used_segs; + shm_info.shm_rss = shm_rss; + shm_info.shm_tot = shm_tot; + shm_info.shm_swp = shm_swp; + shm_info.swap_attempts = swap_attempts; + shm_info.swap_successes = swap_successes; + memcpy_tofs (buf, &shm_info, sizeof(shm_info)); + return max_shmid; + } + case SHM_STAT: + if (!buf) + return -EFAULT; + err = verify_area (VERIFY_WRITE, buf, sizeof (*shp)); + if (err) + return err; + if (shmid > max_shmid) + return -EINVAL; + shp = shm_segs[shmid]; + if (shp == IPC_UNUSED || shp == IPC_NOID) + return -EINVAL; + if (ipcperms (&shp->shm_perm, S_IRUGO)) + return -EACCES; + id = shmid + shp->shm_perm.seq * SHMMNI; + memcpy_tofs (buf, shp, sizeof(*shp)); + return id; + } + + shp = shm_segs[id = shmid % SHMMNI]; + if (shp == IPC_UNUSED || shp == IPC_NOID) + return -EINVAL; + ipcp = &shp->shm_perm; + if (ipcp->seq != shmid / SHMMNI) + return -EIDRM; + + switch (cmd) { + case SHM_UNLOCK: + if (!suser()) + return -EPERM; + if (!(ipcp->mode & SHM_LOCKED)) + return -EINVAL; + ipcp->mode &= ~SHM_LOCKED; + break; + case SHM_LOCK: +/* Allow superuser to lock segment in memory */ +/* Should the pages be faulted in here or leave it to user? */ +/* need to determine interaction with current->swappable */ + if (!suser()) + return -EPERM; + if (ipcp->mode & SHM_LOCKED) + return -EINVAL; + ipcp->mode |= SHM_LOCKED; + break; + case IPC_STAT: + if (ipcperms (ipcp, S_IRUGO)) + return -EACCES; + if (!buf) + return -EFAULT; + err = verify_area (VERIFY_WRITE, buf, sizeof (*shp)); + if (err) + return err; + memcpy_tofs (buf, shp, sizeof(*shp)); + break; + case IPC_SET: + if (suser() || current->euid == shp->shm_perm.uid || + current->euid == shp->shm_perm.cuid) { + ipcp->uid = tbuf.shm_perm.uid; + ipcp->gid = tbuf.shm_perm.gid; + ipcp->mode = (ipcp->mode & ~S_IRWXUGO) + | (tbuf.shm_perm.mode & S_IRWXUGO); + shp->shm_ctime = CURRENT_TIME; + break; + } + return -EPERM; + case IPC_RMID: + if (suser() || current->euid == shp->shm_perm.uid || + current->euid == shp->shm_perm.cuid) { + shp->shm_perm.mode |= SHM_DEST; + if (shp->shm_nattch <= 0) + killseg (id); + break; + } + return -EPERM; + default: + return -EINVAL; + } + return 0; +} + +/* + * check range is unmapped, ensure page tables exist + * mark page table entries with shm_sgn. + * if remap != 0 the range is remapped. + */ +static int shm_map (struct shm_desc *shmd, int remap) +{ + unsigned long invalid = 0; + unsigned long *page_table; + unsigned long tmp, shm_sgn; + unsigned long page_dir = shmd->task->tss.cr3; + + /* check that the range is unmapped and has page_tables */ + for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE) { + page_table = PAGE_DIR_OFFSET(page_dir,tmp); + if (*page_table & PAGE_PRESENT) { + page_table = (ulong *) (PAGE_MASK & *page_table); + page_table += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1)); + if (*page_table) { + if (!remap) + return -EINVAL; + if (*page_table & PAGE_PRESENT) { + --current->rss; + free_page (*page_table & PAGE_MASK); + } + else + swap_free (*page_table); + invalid++; + } + continue; + } + { + unsigned long new_pt; + if(!(new_pt = get_free_page(GFP_KERNEL))) /* clearing needed? SRB. */ + return -ENOMEM; + *page_table = new_pt | PAGE_TABLE; + tmp |= ((PAGE_SIZE << 10) - PAGE_SIZE); + }} + if (invalid) + invalidate(); + + /* map page range */ + shm_sgn = shmd->shm_sgn; + for (tmp = shmd->start; tmp < shmd->end; tmp += PAGE_SIZE, + shm_sgn += (1 << SHM_IDX_SHIFT)) { + page_table = PAGE_DIR_OFFSET(page_dir,tmp); + page_table = (ulong *) (PAGE_MASK & *page_table); + page_table += (tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + *page_table = shm_sgn; + } + return 0; +} + +/* + * Fix shmaddr, allocate descriptor, map shm, add attach descriptor to lists. + * raddr is needed to return addresses above 2Gig. + * Specific attaches are allowed over the executable.... + */ +int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr) +{ + struct shmid_ds *shp; + struct shm_desc *shmd; + int err; + unsigned int id; + unsigned long addr; + + if (shmid < 0) + return -EINVAL; + + shp = shm_segs[id = shmid % SHMMNI]; + if (shp == IPC_UNUSED || shp == IPC_NOID) + return -EINVAL; + + if (!(addr = (ulong) shmaddr)) { + if (shmflg & SHM_REMAP) + return -EINVAL; + /* set addr below all current unspecified attaches */ + addr = SHM_RANGE_END; + for (shmd = current->shm; shmd; shmd = shmd->task_next) { + if (shmd->start < SHM_RANGE_START) + continue; + if (addr >= shmd->start) + addr = shmd->start; + } + addr = (addr - shp->shm_segsz) & PAGE_MASK; + } else if (addr & (SHMLBA-1)) { + if (shmflg & SHM_RND) + addr &= ~(SHMLBA-1); /* round down */ + else + return -EINVAL; + } + if ((addr > current->start_stack - 16384 - PAGE_SIZE*shp->shm_npages)) + return -EINVAL; + if (shmflg & SHM_REMAP) + for (shmd = current->shm; shmd; shmd = shmd->task_next) { + if (addr >= shmd->start && addr < shmd->end) + return -EINVAL; + if (addr + shp->shm_segsz >= shmd->start && + addr + shp->shm_segsz < shmd->end) + return -EINVAL; + } + + if (ipcperms(&shp->shm_perm, shmflg & SHM_RDONLY ? S_IRUGO : S_IRUGO|S_IWUGO)) + return -EACCES; + if (shp->shm_perm.seq != shmid / SHMMNI) + return -EIDRM; + + shmd = (struct shm_desc *) kmalloc (sizeof(*shmd), GFP_KERNEL); + if (!shmd) + return -ENOMEM; + if ((shp != shm_segs[id]) || (shp->shm_perm.seq != shmid / SHMMNI)) { + kfree_s (shmd, sizeof (*shmd)); + return -EIDRM; + } + shmd->shm_sgn = (SHM_SWP_TYPE << 1) | (id << SHM_ID_SHIFT) | + (shmflg & SHM_RDONLY ? SHM_READ_ONLY : 0); + shmd->start = addr; + shmd->end = addr + shp->shm_npages * PAGE_SIZE; + shmd->task = current; + + shp->shm_nattch++; /* prevent destruction */ + if (addr < current->end_data) { + iput (current->executable); + current->executable = NULL; +/* current->end_data = current->end_code = 0; */ + } + + if ((err = shm_map (shmd, shmflg & SHM_REMAP))) { + if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST) + killseg(id); + kfree_s (shmd, sizeof (*shmd)); + return err; + } + + shmd->task_next = current->shm; + current->shm = shmd; + shmd->seg_next = shp->attaches; + shp->attaches = shmd; + shp->shm_lpid = current->pid; + shp->shm_atime = CURRENT_TIME; + put_fs_long (addr, raddr); + return 0; +} + +/* + * remove the first attach descriptor from the list *shmdp. + * free memory for segment if it is marked destroyed. + * The descriptor is detached before the sleep in unmap_page_range. + */ +static void detach (struct shm_desc **shmdp) +{ + struct shm_desc *shmd = *shmdp; + struct shmid_ds *shp; + int id; + + id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK; + shp = shm_segs[id]; + *shmdp = shmd->task_next; + for (shmdp = &shp->attaches; *shmdp; shmdp = &(*shmdp)->seg_next) + if (*shmdp == shmd) { + *shmdp = shmd->seg_next; + goto found; + } + printk("detach: shm segment (id=%d) attach list inconsistent\n",id); + + found: + unmap_page_range (shmd->start, shp->shm_segsz); /* sleeps */ + kfree_s (shmd, sizeof (*shmd)); + shp->shm_lpid = current->pid; + shp->shm_dtime = CURRENT_TIME; + if (--shp->shm_nattch <= 0 && shp->shm_perm.mode & SHM_DEST) + killseg (id); /* sleeps */ + return; +} + +/* + * detach and kill segment if marked destroyed. + * The work is done in detach. + */ +int sys_shmdt (char *shmaddr) +{ + struct shm_desc *shmd, **shmdp; + + for (shmdp = ¤t->shm; (shmd = *shmdp); shmdp=&shmd->task_next) { + if (shmd->start == (ulong) shmaddr) { + detach (shmdp); + return 0; + } + } + return -EINVAL; +} + +/* + * detach all attached segments. + */ +void shm_exit (void) +{ + while (current->shm) + detach(¤t->shm); + return; +} + +/* + * copy the parent shm descriptors and update nattch + * parent is stuck in fork so an attach on each segment is assured. + * copy_page_tables does the mapping. + */ +int shm_fork (struct task_struct *p1, struct task_struct *p2) +{ + struct shm_desc *shmd, *new_desc = NULL, *tmp; + struct shmid_ds *shp; + int id; + + if (!p1->shm) + return 0; + for (shmd = p1->shm; shmd; shmd = shmd->task_next) { + tmp = (struct shm_desc *) kmalloc(sizeof(*tmp), GFP_KERNEL); + if (!tmp) { + while (new_desc) { + tmp = new_desc->task_next; + kfree_s (new_desc, sizeof (*new_desc)); + new_desc = tmp; + } + free_page_tables (p2); + return -ENOMEM; + } + *tmp = *shmd; + tmp->task = p2; + tmp->task_next = new_desc; + new_desc = tmp; + } + p2->shm = new_desc; + for (shmd = new_desc; shmd; shmd = shmd->task_next) { + id = (shmd->shm_sgn >> SHM_ID_SHIFT) & SHM_ID_MASK; + shp = shm_segs[id]; + if (shp == IPC_UNUSED) { + printk("shm_fork: unused id=%d PANIC\n", id); + return -ENOMEM; + } + shmd->seg_next = shp->attaches; + shp->attaches = shmd; + shp->shm_nattch++; + shp->shm_atime = CURRENT_TIME; + shp->shm_lpid = current->pid; + } + return 0; +} + +/* + * page not present ... go through shm_pages .. called from swap_in() + */ +void shm_no_page (unsigned long *ptent) +{ + unsigned long page; + unsigned long code = *ptent; + struct shmid_ds *shp; + unsigned int id, idx; + + id = (code >> SHM_ID_SHIFT) & SHM_ID_MASK; + if (id > max_shmid) { + printk ("shm_no_page: id=%d too big. proc mem corruptedn", id); + return; + } + shp = shm_segs[id]; + if (shp == IPC_UNUSED || shp == IPC_NOID) { + printk ("shm_no_page: id=%d invalid. Race.\n", id); + return; + } + idx = (code >> SHM_IDX_SHIFT) & SHM_IDX_MASK; + if (idx >= shp->shm_npages) { + printk ("shm_no_page : too large page index. id=%d\n", id); + return; + } + + if (!(shp->shm_pages[idx] & PAGE_PRESENT)) { + if(!(page = get_free_page(GFP_KERNEL))) { + oom(current); + *ptent = BAD_PAGE | PAGE_ACCESSED | 7; + return; + } + if (shp->shm_pages[idx] & PAGE_PRESENT) { + free_page (page); + goto done; + } + if (shp->shm_pages[idx]) { + read_swap_page (shp->shm_pages[idx], (char *) page); + if (shp->shm_pages[idx] & PAGE_PRESENT) { + free_page (page); + goto done; + } + swap_free (shp->shm_pages[idx]); + shm_swp--; + } + shm_rss++; + shp->shm_pages[idx] = page | (PAGE_SHARED | PAGE_DIRTY); + } else + --current->maj_flt; /* was incremented in do_no_page */ + +done: + current->min_flt++; + page = shp->shm_pages[idx]; + if (code & SHM_READ_ONLY) /* write-protect */ + page &= ~2; + mem_map[MAP_NR(page)]++; + *ptent = page; + return; +} + +/* + * Goes through counter = (shm_rss << prio) present shm pages. + */ +static unsigned long swap_id = 0; /* currently being swapped */ +static unsigned long swap_idx = 0; /* next to swap */ + +int shm_swap (int prio) +{ + unsigned long page; + struct shmid_ds *shp; + struct shm_desc *shmd; + unsigned int swap_nr; + unsigned long id, idx, invalid = 0; + int counter; + + counter = shm_rss >> prio; + if (!counter || !(swap_nr = get_swap_page())) + return 0; + + check_id: + shp = shm_segs[swap_id]; + if (shp == IPC_UNUSED || shp == IPC_NOID || shp->shm_perm.mode & SHM_LOCKED ) { + swap_idx = 0; + if (++swap_id > max_shmid) + swap_id = 0; + goto check_id; + } + id = swap_id; + + check_table: + idx = swap_idx++; + if (idx >= shp->shm_npages) { + swap_idx = 0; + if (++swap_id > max_shmid) + swap_id = 0; + goto check_id; + } + + page = shp->shm_pages[idx]; + if (!(page & PAGE_PRESENT)) + goto check_table; + swap_attempts++; + + if (--counter < 0) { /* failed */ + if (invalid) + invalidate(); + swap_free (swap_nr); + return 0; + } + for (shmd = shp->attaches; shmd; shmd = shmd->seg_next) { + unsigned long tmp, *pte; + if ((shmd->shm_sgn >> SHM_ID_SHIFT & SHM_ID_MASK) != id) { + printk ("shm_swap: id=%ld does not match shmd\n", id); + continue; + } + tmp = shmd->start + (idx << PAGE_SHIFT); + if (tmp >= shmd->end) { + printk ("shm_swap: too large idx=%ld id=%ld PANIC\n",idx, id); + continue; + } + pte = PAGE_DIR_OFFSET(shmd->task->tss.cr3,tmp); + if (!(*pte & 1)) { + printk("shm_swap: bad pgtbl! id=%ld start=%lx idx=%ld\n", + id, shmd->start, idx); + *pte = 0; + continue; + } + pte = (ulong *) (PAGE_MASK & *pte); + pte += ((tmp >> PAGE_SHIFT) & (PTRS_PER_PAGE-1)); + tmp = *pte; + if (!(tmp & PAGE_PRESENT)) + continue; + if (tmp & PAGE_ACCESSED) { + *pte &= ~PAGE_ACCESSED; + continue; + } + tmp = shmd->shm_sgn | idx << SHM_IDX_SHIFT; + *pte = tmp; + mem_map[MAP_NR(page)]--; + shmd->task->rss--; + invalid++; + } + + if (mem_map[MAP_NR(page)] != 1) + goto check_table; + page &= PAGE_MASK; + shp->shm_pages[idx] = swap_nr; + if (invalid) + invalidate(); + write_swap_page (swap_nr, (char *) page); + free_page (page); + swap_successes++; + shm_swp++; + shm_rss--; + return 1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/util.c b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/util.c new file mode 100644 index 000000000..c7bebd7ea --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/ipc/util.c @@ -0,0 +1,156 @@ +/* + * linux/ipc/util.c + * Copyright (C) 1992 Krishna Balasubramanian + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +void ipc_init (void); +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr); + +#ifdef CONFIG_SYSVIPC + +int ipcperms (struct ipc_perm *ipcp, short flag); +extern void sem_init (void), msg_init (void), shm_init (void); +extern int sys_semget (key_t key, int nsems, int semflg); +extern int sys_semop (int semid, struct sembuf *sops, unsigned nsops); +extern int sys_semctl (int semid, int semnum, int cmd, void *arg); +extern int sys_msgget (key_t key, int msgflg); +extern int sys_msgsnd (int msqid, struct msgbuf *msgp, int msgsz, int msgflg); +extern int sys_msgrcv (int msqid, struct msgbuf *msgp, int msgsz, long msgtyp, + int msgflg); +extern int sys_msgctl (int msqid, int cmd, struct msqid_ds *buf); +extern int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); +extern int sys_shmget (key_t key, int size, int flag); +extern int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *addr); +extern int sys_shmdt (char *shmaddr); + +void ipc_init (void) +{ + sem_init(); + msg_init(); + shm_init(); + return; +} + +/* + * Check user, group, other permissions for access + * to ipc resources. return 0 if allowed + */ +int ipcperms (struct ipc_perm *ipcp, short flag) +{ + int i; mode_t perm; uid_t euid; int egid; + + if (suser()) + return 0; + + perm = S_IRWXO; euid = current->euid; + + if (euid == ipcp->cuid || euid == ipcp->uid) + perm = S_IRWXU; + else { + for (i = 0; (egid = current->groups[i]) != NOGROUP; i++) + if ((egid == ipcp->cgid) || (egid == ipcp->gid)) { + perm = S_IRWXG; + break; + } + } + if (!(flag & perm) || flag & perm & ~ipcp->mode) + return -1; + return 0; +} + +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) +{ + + if (call <= SEMCTL) + switch (call) { + case SEMOP: + return sys_semop (first, (struct sembuf *)ptr, second); + case SEMGET: + return sys_semget (first, second, third); + case SEMCTL: + return sys_semctl (first, second, third, ptr); + default: + return -EINVAL; + } + if (call <= MSGCTL) + switch (call) { + case MSGSND: + return sys_msgsnd (first, (struct msgbuf *) ptr, + second, third); + case MSGRCV: { + struct ipc_kludge tmp; + if (!ptr) + return -EINVAL; + memcpy_fromfs (&tmp,(struct ipc_kludge *) ptr, + sizeof (tmp)); + return sys_msgrcv (first, tmp.msgp, second, tmp.msgtyp, + third); + } + case MSGGET: + return sys_msgget ((key_t) first, second); + case MSGCTL: + return sys_msgctl (first, second, + (struct msqid_ds *) ptr); + default: + return -EINVAL; + } + if (call <= SHMCTL) + switch (call) { + case SHMAT: /* returning shmaddr > 2G will screw up */ + return sys_shmat (first, (char *) ptr, second, + (ulong *) third); + case SHMDT: + return sys_shmdt ((char *)ptr); + case SHMGET: + return sys_shmget (first, second, third); + case SHMCTL: + return sys_shmctl (first, second, + (struct shmid_ds *) ptr); + default: + return -EINVAL; + } + return -EINVAL; +} + +#else /* not CONFIG_SYSVIPC */ + +asmlinkage int sys_ipc (uint call, int first, int second, int third, void *ptr) +{ + return -ENOSYS; +} + +int shm_fork (struct task_struct *p1, struct task_struct *p2) +{ + return 0; +} + +void sem_exit (void) +{ + return; +} + +void shm_exit (void) +{ + return; +} + +int shm_swap (int prio) +{ + return 0; +} + +void shm_no_page (unsigned long *ptent) +{ + return; +} + +#endif /* CONFIG_SYSVIPC */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/Makefile new file mode 100644 index 000000000..861cf85d9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/Makefile @@ -0,0 +1,56 @@ +# +# Makefile for the linux kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definitions are now in the main makefile... + +.S.s: + $(CPP) -traditional $< -o $*.s +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< + +OBJS = sched.o sys_call.o traps.o irq.o dma.o fork.o \ + panic.o printk.o vsprintf.o sys.o module.o ksyms.o exit.o \ + signal.o mktime.o ptrace.o ioport.o itimer.o \ + info.o ldt.o time.o + +all: kernel.o + +kernel.o: $(OBJS) + $(LD) -r -o kernel.o $(OBJS) + sync + +sys_call.s: sys_call.S + +sys_call.o: sys_call.s + +sched.o: sched.c + $(CC) $(CFLAGS) $(PROFILING) -fno-omit-frame-pointer -c $< + +ksyms.lst: ksyms.S ../include/linux/autoconf.h + $(CPP) $(CFLAGS) $< > $@ + +ksyms.s: ksyms.sh ksyms.lst + sh $< > $@ + +ksyms.o: ksyms.s + +dep: + $(CPP) -M *.c > .depend + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/dma.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/dma.c new file mode 100644 index 000000000..b0101632c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/dma.c @@ -0,0 +1,87 @@ +/* $Id: dma.c,v 1.5 1992/11/18 02:49:05 root Exp root $ + * linux/kernel/dma.c: A DMA channel allocator. Inspired by linux/kernel/irq.c. + * Written by Hennus Bergman, 1992. + */ + +#include +#include +#include + + +/* A note on resource allocation: + * + * All drivers needing DMA channels, should allocate and release them + * through the public routines `request_dma()' and `free_dma()'. + * + * In order to avoid problems, all processes should allocate resources in + * the same sequence and release them in the reverse order. + * + * So, when allocating DMAs and IRQs, first allocate the IRQ, then the DMA. + * When releasing them, first release the DMA, then release the IRQ. + * If you don't, you may cause allocation requests to fail unnecessarily. + * This doesn't really matter now, but it will once we get real semaphores + * in the kernel. + */ + + + +/* Channel n is busy iff dma_chan_busy[n] != 0. + * DMA0 is reserved for DRAM refresh, I think. + * DMA4 is reserved for cascading (?). + */ +static volatile unsigned int dma_chan_busy[MAX_DMA_CHANNELS] = { + 1, 0, 0, 0, 1, 0, 0, 0 +}; + + + +/* Atomically swap memory location [32 bits] with `newval'. + * This avoid the cli()/sti() junk and related problems. + * [And it's faster too :-)] + * Maybe this should be in include/asm/mutex.h and be used for + * implementing kernel-semaphores as well. + */ +static __inline__ unsigned int mutex_atomic_swap(volatile unsigned int * p, unsigned int newval) +{ + unsigned int semval = newval; + + /* If one of the operands for the XCHG instructions is a memory ref, + * it makes the swap an uninterruptible RMW cycle. + * + * One operand must be in memory, the other in a register, otherwise + * the swap may not be atomic. + */ + + asm __volatile__ ("xchgl %2, %0\n" + : /* outputs: semval */ "=r" (semval) + : /* inputs: newval, p */ "0" (semval), "m" (*p) + ); /* p is a var, containing an address */ + return semval; +} /* mutex_atomic_swap */ + + + +int request_dma(unsigned int dmanr) +{ + if (dmanr >= MAX_DMA_CHANNELS) + return -EINVAL; + + if (mutex_atomic_swap(&dma_chan_busy[dmanr], 1) != 0) + return -EBUSY; + else + /* old flag was 0, now contains 1 to indicate busy */ + return 0; +} /* request_dma */ + + +void free_dma(unsigned int dmanr) +{ + if (dmanr >= MAX_DMA_CHANNELS) { + printk("Trying to free DMA%d\n", dmanr); + return; + } + + if (mutex_atomic_swap(&dma_chan_busy[dmanr], 0) == 0) + printk("Trying to free free DMA%d\n", dmanr); +} /* free_dma */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/exit.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/exit.c new file mode 100644 index 000000000..41e774296 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/exit.c @@ -0,0 +1,578 @@ +/* + * linux/kernel/exit.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define DEBUG_PROC_TREE + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +extern void shm_exit (void); +extern void sem_exit (void); + +int getrusage(struct task_struct *, int, struct rusage *); + +static int generate(unsigned long sig, struct task_struct * p) +{ + unsigned long mask = 1 << (sig-1); + struct sigaction * sa = sig + p->sigaction - 1; + + /* always generate signals for traced processes ??? */ + if (p->flags & PF_PTRACED) { + p->signal |= mask; + return 1; + } + /* don't bother with ignored signals (but SIGCHLD is special) */ + if (sa->sa_handler == SIG_IGN && sig != SIGCHLD) + return 0; + /* some signals are ignored by default.. (but SIGCONT already did its deed) */ + if ((sa->sa_handler == SIG_DFL) && + (sig == SIGCONT || sig == SIGCHLD || sig == SIGWINCH)) + return 0; + p->signal |= mask; + return 1; +} + +int send_sig(unsigned long sig,struct task_struct * p,int priv) +{ + if (!p || sig > 32) + return -EINVAL; + if (!priv && ((sig != SIGCONT) || (current->session != p->session)) && + (current->euid != p->euid) && (current->uid != p->uid) && !suser()) + return -EPERM; + if (!sig) + return 0; + if ((sig == SIGKILL) || (sig == SIGCONT)) { + if (p->state == TASK_STOPPED) + p->state = TASK_RUNNING; + p->exit_code = 0; + p->signal &= ~( (1<<(SIGSTOP-1)) | (1<<(SIGTSTP-1)) | + (1<<(SIGTTIN-1)) | (1<<(SIGTTOU-1)) ); + } + /* Depends on order SIGSTOP, SIGTSTP, SIGTTIN, SIGTTOU */ + if ((sig >= SIGSTOP) && (sig <= SIGTTOU)) + p->signal &= ~(1<<(SIGCONT-1)); + /* Actually generate the signal */ + generate(sig,p); + return 0; +} + +void notify_parent(struct task_struct * tsk) +{ + if (tsk->p_pptr == task[1]) + tsk->exit_signal = SIGCHLD; + send_sig(tsk->exit_signal, tsk->p_pptr, 1); + wake_up_interruptible(&tsk->p_pptr->wait_chldexit); +} + +void release(struct task_struct * p) +{ + int i; + + if (!p) + return; + if (p == current) { + printk("task releasing itself\n"); + return; + } + for (i=1 ; ikernel_stack_page); + free_page((long) p); + return; + } + panic("trying to release non-existent task"); +} + +#ifdef DEBUG_PROC_TREE +/* + * Check to see if a task_struct pointer is present in the task[] array + * Return 0 if found, and 1 if not found. + */ +int bad_task_ptr(struct task_struct *p) +{ + int i; + + if (!p) + return 0; + for (i=0 ; ip_pptr)) + printk("Warning, pid %d's parent link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_cptr)) + printk("Warning, pid %d's child link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_ysptr)) + printk("Warning, pid %d's ys link is bad\n", + task[i]->pid); + if (bad_task_ptr(task[i]->p_osptr)) + printk("Warning, pid %d's os link is bad\n", + task[i]->pid); + if (task[i]->p_pptr == task[i]) + printk("Warning, pid %d parent link points to self\n", + task[i]->pid); + if (task[i]->p_cptr == task[i]) + printk("Warning, pid %d child link points to self\n", + task[i]->pid); + if (task[i]->p_ysptr == task[i]) + printk("Warning, pid %d ys link points to self\n", + task[i]->pid); + if (task[i]->p_osptr == task[i]) + printk("Warning, pid %d os link points to self\n", + task[i]->pid); + if (task[i]->p_osptr) { + if (task[i]->p_pptr != task[i]->p_osptr->p_pptr) + printk( + "Warning, pid %d older sibling %d parent is %d\n", + task[i]->pid, task[i]->p_osptr->pid, + task[i]->p_osptr->p_pptr->pid); + if (task[i]->p_osptr->p_ysptr != task[i]) + printk( + "Warning, pid %d older sibling %d has mismatched ys link\n", + task[i]->pid, task[i]->p_osptr->pid); + } + if (task[i]->p_ysptr) { + if (task[i]->p_pptr != task[i]->p_ysptr->p_pptr) + printk( + "Warning, pid %d younger sibling %d parent is %d\n", + task[i]->pid, task[i]->p_osptr->pid, + task[i]->p_osptr->p_pptr->pid); + if (task[i]->p_ysptr->p_osptr != task[i]) + printk( + "Warning, pid %d younger sibling %d has mismatched os link\n", + task[i]->pid, task[i]->p_ysptr->pid); + } + if (task[i]->p_cptr) { + if (task[i]->p_cptr->p_pptr != task[i]) + printk( + "Warning, pid %d youngest child %d has mismatched parent link\n", + task[i]->pid, task[i]->p_cptr->pid); + if (task[i]->p_cptr->p_ysptr) + printk( + "Warning, pid %d youngest child %d has non-NULL ys link\n", + task[i]->pid, task[i]->p_cptr->pid); + } + } +} +#endif /* DEBUG_PROC_TREE */ + +/* + * This checks not only the pgrp, but falls back on the pid if no + * satisfactory prgp is found. I dunno - gdb doesn't work correctly + * without this... + */ +int session_of_pgrp(int pgrp) +{ + struct task_struct *p; + int fallback; + + fallback = -1; + for_each_task(p) { + if (p->session <= 0) + continue; + if (p->pgrp == pgrp) + return p->session; + if (p->pid == pgrp) + fallback = p->session; + } + return fallback; +} + +/* + * kill_pg() sends a signal to a process group: this is what the tty + * control characters do (^C, ^Z etc) + */ +int kill_pg(int pgrp, int sig, int priv) +{ + struct task_struct *p; + int err,retval = -ESRCH; + int found = 0; + + if (sig<0 || sig>32 || pgrp<=0) + return -EINVAL; + for_each_task(p) { + if (p->pgrp == pgrp) { + if ((err = send_sig(sig,p,priv)) != 0) + retval = err; + else + found++; + } + } + return(found ? 0 : retval); +} + +/* + * kill_sl() sends a signal to the session leader: this is used + * to send SIGHUP to the controlling process of a terminal when + * the connection is lost. + */ +int kill_sl(int sess, int sig, int priv) +{ + struct task_struct *p; + int err,retval = -ESRCH; + int found = 0; + + if (sig<0 || sig>32 || sess<=0) + return -EINVAL; + for_each_task(p) { + if (p->session == sess && p->leader) { + if ((err = send_sig(sig,p,priv)) != 0) + retval = err; + else + found++; + } + } + return(found ? 0 : retval); +} + +int kill_proc(int pid, int sig, int priv) +{ + struct task_struct *p; + + if (sig<0 || sig>32) + return -EINVAL; + for_each_task(p) { + if (p && p->pid == pid) + return send_sig(sig,p,priv); + } + return(-ESRCH); +} + +/* + * POSIX specifies that kill(-1,sig) is unspecified, but what we have + * is probably wrong. Should make it like BSD or SYSV. + */ +asmlinkage int sys_kill(int pid,int sig) +{ + int err, retval = 0, count = 0; + + if (!pid) + return(kill_pg(current->pgrp,sig,0)); + if (pid == -1) { + struct task_struct * p; + for_each_task(p) { + if (p->pid > 1 && p != current) { + ++count; + if ((err = send_sig(sig,p,0)) != -EPERM) + retval = err; + } + } + return(count ? retval : -ESRCH); + } + if (pid < 0) + return(kill_pg(-pid,sig,0)); + /* Normal kill */ + return(kill_proc(pid,sig,0)); +} + +/* + * Determine if a process group is "orphaned", according to the POSIX + * definition in 2.2.2.52. Orphaned process groups are not to be affected + * by terminal-generated stop signals. Newly orphaned process groups are + * to receive a SIGHUP and a SIGCONT. + * + * "I ask you, have you ever known what it is to be an orphan?" + */ +int is_orphaned_pgrp(int pgrp) +{ + struct task_struct *p; + + for_each_task(p) { + if ((p->pgrp != pgrp) || + (p->state == TASK_ZOMBIE) || + (p->p_pptr->pid == 1)) + continue; + if ((p->p_pptr->pgrp != pgrp) && + (p->p_pptr->session == p->session)) + return 0; + } + return(1); /* (sighing) "Often!" */ +} + +static int has_stopped_jobs(int pgrp) +{ + struct task_struct * p; + + for_each_task(p) { + if (p->pgrp != pgrp) + continue; + if (p->state == TASK_STOPPED) + return(1); + } + return(0); +} + +static void forget_original_parent(struct task_struct * father) +{ + struct task_struct * p; + + for_each_task(p) { + if (p->p_opptr == father) + if (task[1]) + p->p_opptr = task[1]; + else + p->p_opptr = task[0]; + } +} + +NORET_TYPE void do_exit(long code) +{ + struct task_struct *p; + int i; + +fake_volatile: + if (current->semun) + sem_exit(); + if (current->shm) + shm_exit(); + free_page_tables(current); + for (i=0 ; ifilp[i]) + sys_close(i); + forget_original_parent(current); + iput(current->pwd); + current->pwd = NULL; + iput(current->root); + current->root = NULL; + iput(current->executable); + current->executable = NULL; + /* Release all of the old mmap stuff. */ + + { + struct vm_area_struct * mpnt, *mpnt1; + mpnt = current->mmap; + current->mmap = NULL; + while (mpnt) { + mpnt1 = mpnt->vm_next; + if (mpnt->vm_ops && mpnt->vm_ops->close) + mpnt->vm_ops->close(mpnt); + kfree(mpnt); + mpnt = mpnt1; + } + } + + if (current->ldt) { + vfree(current->ldt); + current->ldt = NULL; + for (i=1 ; istate = TASK_ZOMBIE; + current->exit_code = code; + current->rss = 0; + /* + * Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jobs, send them a SIGUP and then a SIGCONT. (POSIX 3.2.2.2) + * + * Case i: Our father is in a different pgrp than we are + * and we were the only connection outside, so our pgrp + * is about to become orphaned. + */ + if ((current->p_pptr->pgrp != current->pgrp) && + (current->p_pptr->session == current->session) && + is_orphaned_pgrp(current->pgrp) && + has_stopped_jobs(current->pgrp)) { + kill_pg(current->pgrp,SIGHUP,1); + kill_pg(current->pgrp,SIGCONT,1); + } + /* Let father know we died */ + notify_parent(current); + + /* + * This loop does two things: + * + * A. Make init inherit all the child processes + * B. Check to see if any process groups have become orphaned + * as a result of our exiting, and if they have any stopped + * jobs, send them a SIGHUP and then a SIGCONT. (POSIX 3.2.2.2) + */ + while ((p = current->p_cptr) != NULL) { + current->p_cptr = p->p_osptr; + p->p_ysptr = NULL; + p->flags &= ~(PF_PTRACED|PF_TRACESYS); + if (task[1] && task[1] != current) + p->p_pptr = task[1]; + else + p->p_pptr = task[0]; + p->p_osptr = p->p_pptr->p_cptr; + p->p_osptr->p_ysptr = p; + p->p_pptr->p_cptr = p; + if (p->state == TASK_ZOMBIE) + notify_parent(p); + /* + * process group orphan check + * Case ii: Our child is in a different pgrp + * than we are, and it was the only connection + * outside, so the child pgrp is now orphaned. + */ + if ((p->pgrp != current->pgrp) && + (p->session == current->session) && + is_orphaned_pgrp(p->pgrp) && + has_stopped_jobs(p->pgrp)) { + kill_pg(p->pgrp,SIGHUP,1); + kill_pg(p->pgrp,SIGCONT,1); + } + } + if (current->leader) + disassociate_ctty(1); + if (last_task_used_math == current) + last_task_used_math = NULL; +#ifdef DEBUG_PROC_TREE + audit_ptree(); +#endif + schedule(); +/* + * In order to get rid of the "volatile function does return" message + * I did this little loop that confuses gcc to think do_exit really + * is volatile. In fact it's schedule() that is volatile in some + * circumstances: when current->state = ZOMBIE, schedule() never + * returns. + * + * In fact the natural way to do all this is to have the label and the + * goto right after each other, but I put the fake_volatile label at + * the start of the function just in case something /really/ bad + * happens, and the schedule returns. This way we can try again. I'm + * not paranoid: it's just that everybody is out to get me. + */ + goto fake_volatile; +} + +asmlinkage int sys_exit(int error_code) +{ + do_exit((error_code&0xff)<<8); +} + +asmlinkage int sys_wait4(pid_t pid,unsigned long * stat_addr, int options, struct rusage * ru) +{ + int flag, retval; + struct wait_queue wait = { current, NULL }; + struct task_struct *p; + + if (stat_addr) { + flag = verify_area(VERIFY_WRITE, stat_addr, 4); + if (flag) + return flag; + } + add_wait_queue(¤t->wait_chldexit,&wait); +repeat: + flag=0; + for (p = current->p_cptr ; p ; p = p->p_osptr) { + if (pid>0) { + if (p->pid != pid) + continue; + } else if (!pid) { + if (p->pgrp != current->pgrp) + continue; + } else if (pid != -1) { + if (p->pgrp != -pid) + continue; + } + /* wait for cloned processes iff the __WCLONE flag is set */ + if ((p->exit_signal != SIGCHLD) ^ ((options & __WCLONE) != 0)) + continue; + flag = 1; + switch (p->state) { + case TASK_STOPPED: + if (!p->exit_code) + continue; + if (!(options & WUNTRACED) && !(p->flags & PF_PTRACED)) + continue; + if (stat_addr) + put_fs_long((p->exit_code << 8) | 0x7f, + stat_addr); + p->exit_code = 0; + if (ru != NULL) + getrusage(p, RUSAGE_BOTH, ru); + retval = p->pid; + goto end_wait4; + case TASK_ZOMBIE: + current->cutime += p->utime + p->cutime; + current->cstime += p->stime + p->cstime; + current->cmin_flt += p->min_flt + p->cmin_flt; + current->cmaj_flt += p->maj_flt + p->cmaj_flt; + if (ru != NULL) + getrusage(p, RUSAGE_BOTH, ru); + flag = p->pid; + if (stat_addr) + put_fs_long(p->exit_code, stat_addr); + if (p->p_opptr != p->p_pptr) { + REMOVE_LINKS(p); + p->p_pptr = p->p_opptr; + SET_LINKS(p); + notify_parent(p); + } else + release(p); +#ifdef DEBUG_PROC_TREE + audit_ptree(); +#endif + retval = flag; + goto end_wait4; + default: + continue; + } + } + if (flag) { + retval = 0; + if (options & WNOHANG) + goto end_wait4; + current->state=TASK_INTERRUPTIBLE; + schedule(); + current->signal &= ~(1<<(SIGCHLD-1)); + retval = -ERESTARTSYS; + if (current->signal & ~current->blocked) + goto end_wait4; + goto repeat; + } + retval = -ECHILD; +end_wait4: + remove_wait_queue(¤t->wait_chldexit,&wait); + return retval; +} + +/* + * sys_waitpid() remains for compatibility. waitpid() should be + * implemented by calling sys_wait4() from libc.a. + */ +asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options) +{ + return sys_wait4(pid, stat_addr, options, NULL); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/fork.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/fork.c new file mode 100644 index 000000000..306ddaba0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/fork.c @@ -0,0 +1,232 @@ +/* + * linux/kernel/fork.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'fork.c' contains the help-routines for the 'fork' system call + * (see also system_call.s). + * Fork is rather simple, once you get the hang of it, but the memory + * management can be a bitch. See 'mm/mm.c': 'copy_page_tables()' + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +asmlinkage void ret_from_sys_call(void) __asm__("ret_from_sys_call"); + +/* These should maybe be in */ + +#define MAX_TASKS_PER_USER (NR_TASKS/2) +#define MIN_TASKS_LEFT_FOR_ROOT 4 + +extern int shm_fork(struct task_struct *, struct task_struct *); +long last_pid=0; + +static int find_empty_process(void) +{ + int free_task; + int i, tasks_free; + int this_user_tasks; + +repeat: + if ((++last_pid) & 0xffff8000) + last_pid=1; + this_user_tasks = 0; + 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 || + task[i]->session == last_pid) + goto repeat; + } + 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) +{ + struct file * new_file = get_empty_filp(); + int error; + + if (new_file) { + memcpy(new_file,old_file,sizeof(struct file)); + new_file->f_count = 1; + if (new_file->f_inode) + new_file->f_inode->i_count++; + if (new_file->f_op && new_file->f_op->open) { + error = new_file->f_op->open(new_file->f_inode,new_file); + if (error) { + iput(new_file->f_inode); + new_file->f_count = 0; + new_file = NULL; + } + } + } + return new_file; +} + +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); + if (!tmp) + return -ENOMEM; + *tmp = *mpnt; + tmp->vm_task = tsk; + tmp->vm_next = NULL; + if (tmp->vm_inode) + tmp->vm_inode->i_count++; + *p = tmp; + p = &tmp->vm_next; + if (current->stk_vma == mpnt) + tsk->stk_vma = tmp; + } + return 0; +} + +#define IS_CLONE (regs.orig_eax == __NR_clone) +#define copy_vm(p) ((clone_flags & COPYVM)?copy_page_tables(p):clone_page_tables(p)) + +/* + * Ok, this is the main fork-routine. It copies the system process + * information (task[nr]) and sets up the necessary registers. It + * also copies the data segment in its entirety. + */ +asmlinkage int sys_fork(struct pt_regs regs) +{ + struct pt_regs * childregs; + struct task_struct *p; + int i,nr; + struct file *f; + unsigned long clone_flags = COPYVM | SIGCHLD; + + if(!(p = (struct task_struct*)__get_free_page(GFP_KERNEL))) + goto bad_fork; + nr = find_empty_process(); + if (nr < 0) + goto bad_fork_free; + task[nr] = p; + *p = *current; + p->kernel_stack_page = 0; + p->state = TASK_UNINTERRUPTIBLE; + p->flags &= ~(PF_PTRACED|PF_TRACESYS); + p->pid = last_pid; + p->swappable = 1; + p->p_pptr = p->p_opptr = current; + p->p_cptr = NULL; + SET_LINKS(p); + p->signal = 0; + p->it_real_value = p->it_virt_value = p->it_prof_value = 0; + p->it_real_incr = p->it_virt_incr = p->it_prof_incr = 0; + p->leader = 0; /* process leadership doesn't inherit */ + p->utime = p->stime = 0; + p->cutime = p->cstime = 0; + p->min_flt = p->maj_flt = 0; + p->cmin_flt = p->cmaj_flt = 0; + p->start_time = jiffies; +/* + * set up new TSS and kernel stack + */ + if (!(p->kernel_stack_page = __get_free_page(GFP_KERNEL))) + goto bad_fork_cleanup; + p->tss.es = KERNEL_DS; + p->tss.cs = KERNEL_CS; + p->tss.ss = KERNEL_DS; + p->tss.ds = KERNEL_DS; + p->tss.fs = USER_DS; + p->tss.gs = KERNEL_DS; + p->tss.ss0 = KERNEL_DS; + p->tss.esp0 = p->kernel_stack_page + PAGE_SIZE; + p->tss.tr = _TSS(nr); + childregs = ((struct pt_regs *) (p->kernel_stack_page + PAGE_SIZE)) - 1; + p->tss.esp = (unsigned long) childregs; + p->tss.eip = (unsigned long) ret_from_sys_call; + *childregs = regs; + childregs->eax = 0; + p->tss.back_link = 0; + p->tss.eflags = regs.eflags & 0xffffcfff; /* iopl is always 0 for a new process */ + if (IS_CLONE) { + if (regs.ebx) + childregs->esp = regs.ebx; + clone_flags = regs.ecx; + if (childregs->esp == regs.esp) + clone_flags |= COPYVM; + } + p->exit_signal = clone_flags & CSIGNAL; + p->tss.ldt = _LDT(nr); + if (p->ldt) { + p->ldt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE); + if (p->ldt != NULL) + memcpy(p->ldt, current->ldt, LDT_ENTRIES*LDT_ENTRY_SIZE); + } + p->tss.bitmap = offsetof(struct tss_struct,io_bitmap); + for (i = 0; i < IO_BITMAP_SIZE+1 ; i++) /* IO bitmap is actually SIZE+1 */ + p->tss.io_bitmap[i] = ~0; + if (last_task_used_math == current) + __asm__("clts ; fnsave %0 ; frstor %0":"=m" (p->tss.i387)); + p->semun = NULL; p->shm = NULL; + if (copy_vm(p) || shm_fork(current, p)) + goto bad_fork_cleanup; + if (clone_flags & COPYFD) { + for (i=0; ifilp[i]) != NULL) + p->filp[i] = copy_fd(f); + } else { + for (i=0; ifilp[i]) != NULL) + f->f_count++; + } + if (current->pwd) + current->pwd->i_count++; + if (current->root) + current->root->i_count++; + if (current->executable) + current->executable->i_count++; + dup_mmap(p); + set_tss_desc(gdt+(nr<<1)+FIRST_TSS_ENTRY,&(p->tss)); + if (p->ldt) + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,p->ldt, 512); + else + set_ldt_desc(gdt+(nr<<1)+FIRST_LDT_ENTRY,&default_ldt, 1); + + p->counter = current->counter >> 1; + p->state = TASK_RUNNING; /* do this last, just in case */ + return p->pid; +bad_fork_cleanup: + task[nr] = NULL; + REMOVE_LINKS(p); + free_page(p->kernel_stack_page); +bad_fork_free: + free_page((long) p); +bad_fork: + return -EAGAIN; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/info.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/info.c new file mode 100644 index 000000000..c7b2b9a8c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/info.c @@ -0,0 +1,42 @@ +/* + * linux/kernel/info.c + * + * Copyright (C) 1992 Darren Senn + */ + +/* This implements the sysinfo() system call */ + +#include + +#include +#include +#include +#include +#include + +asmlinkage int sys_sysinfo(struct sysinfo *info) +{ + int error; + struct sysinfo val; + struct task_struct **p; + + error = verify_area(VERIFY_WRITE, info, sizeof(struct sysinfo)); + if (error) + return error; + memset((char *)&val, 0, sizeof(struct sysinfo)); + + val.uptime = jiffies / HZ; + + val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); + val.loads[1] = avenrun[1] << (SI_LOAD_SHIFT - FSHIFT); + val.loads[2] = avenrun[2] << (SI_LOAD_SHIFT - FSHIFT); + + for (p = &LAST_TASK; p > &FIRST_TASK; p--) + if (*p) val.procs++; + + si_meminfo(&val); + si_swapinfo(&val); + + memcpy_tofs(info, &val, sizeof(struct sysinfo)); + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ioport.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ioport.c new file mode 100644 index 000000000..883e58c9c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ioport.c @@ -0,0 +1,184 @@ +/* + * linux/kernel/ioport.c + * + * This contains the io-permission bitmap code - written by obz, with changes + * by Linus. + */ + +#include +#include +#include +#include +#include + +static unsigned long ioport_registrar[IO_BITMAP_SIZE] = {0, /* ... */}; + +#define _IODEBUG + +#ifdef IODEBUG +static char * ios(unsigned long l) +{ + static char str[33] = { '\0' }; + int i; + unsigned long mask; + + for (i = 0, mask = 0x80000000; i < 32; ++i, mask >>= 1) + str[i] = (l & mask) ? '1' : '0'; + return str; +} + +static void dump_io_bitmap(void) +{ + int i, j; + int numl = sizeof(current->tss.io_bitmap) >> 2; + + for (i = j = 0; j < numl; ++i) + { + printk("%4d [%3x]: ", 64*i, 64*i); + printk("%s ", ios(current->tss.io_bitmap[j++])); + if (j < numl) + printk("%s", ios(current->tss.io_bitmap[j++])); + printk("\n"); + } +} +#endif + +/* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ +asmlinkage void set_bitmap(unsigned long *bitmap, + short base, short extent, int new_value) +{ + int mask; + unsigned long *bitmap_base = bitmap + (base >> 5); + unsigned short low_index = base & 0x1f; + int length = low_index + extent; + + if (low_index != 0) { + mask = (~0 << low_index); + if (length < 32) + mask &= ~(~0 << length); + if (new_value) + *bitmap_base++ |= mask; + else + *bitmap_base++ &= ~mask; + length -= 32; + } + + mask = (new_value ? ~0 : 0); + while (length >= 32) { + *bitmap_base++ = mask; + length -= 32; + } + + if (length > 0) { + mask = ~(~0 << length); + if (new_value) + *bitmap_base++ |= mask; + else + *bitmap_base++ &= ~mask; + } +} + +/* Check for set bits in BITMAP starting at BASE, going to EXTENT. */ +asmlinkage int check_bitmap(unsigned long *bitmap, short base, short extent) +{ + int mask; + unsigned long *bitmap_base = bitmap + (base >> 5); + unsigned short low_index = base & 0x1f; + int length = low_index + extent; + + if (low_index != 0) { + mask = (~0 << low_index); + if (length < 32) + mask &= ~(~0 << length); + if (*bitmap_base++ & mask) + return 1; + length -= 32; + } + while (length >= 32) { + if (*bitmap_base++ != 0) + return 1; + length -= 32; + } + + if (length > 0) { + mask = ~(~0 << length); + if (*bitmap_base++ & mask) + return 1; + } + return 0; +} + +/* + * this changes the io permissions bitmap in the current task. + */ +asmlinkage int sys_ioperm(unsigned long from, unsigned long num, int turn_on) +{ + if (from + num <= from) + return -EINVAL; + if (from + num > IO_BITMAP_SIZE*32) + return -EINVAL; + if (!suser()) + return -EPERM; + +#ifdef IODEBUG + printk("io: from=%d num=%d %s\n", from, num, (turn_on ? "on" : "off")); +#endif + set_bitmap((unsigned long *)current->tss.io_bitmap, from, num, !turn_on); + return 0; +} + +unsigned int *stack; + +/* + * sys_iopl has to be used when you want to access the IO ports + * beyond the 0x3ff range: to get the full 65536 ports bitmapped + * you'd need 8kB of bitmaps/process, which is a bit excessive. + * + * Here we just change the eflags value on the stack: we allow + * only the super-user to do it. This depends on the stack-layout + * on system-call entry - see also fork() and the signal handling + * code. + */ +asmlinkage int sys_iopl(long ebx,long ecx,long edx, + long esi, long edi, long ebp, long eax, long ds, + long es, long fs, long gs, long orig_eax, + long eip,long cs,long eflags,long esp,long ss) +{ + unsigned int level = ebx; + + if (level > 3) + return -EINVAL; + if (!suser()) + return -EPERM; + *(&eflags) = (eflags & 0xffffcfff) | (level << 12); + return 0; +} + + +void snarf_region(unsigned int from, unsigned int num) +{ + if (from > IO_BITMAP_SIZE*32) + return; + if (from + num > IO_BITMAP_SIZE*32) + num = IO_BITMAP_SIZE*32 - from; + set_bitmap(ioport_registrar, from, num, 1); + return; +} + +int check_region(unsigned int from, unsigned int num) +{ + if (from > IO_BITMAP_SIZE*32) + return 0; + if (from + num > IO_BITMAP_SIZE*32) + num = IO_BITMAP_SIZE*32 - from; + return check_bitmap(ioport_registrar, from, num); +} + +/* Called from init/main.c to reserve IO ports. */ +void reserve_setup(char *str, int *ints) +{ + int i; + + for (i = 1; i < ints[0]; i += 2) + snarf_region(ints[i], ints[i+1]); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/irq.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/irq.c new file mode 100644 index 000000000..e38d9e806 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/irq.c @@ -0,0 +1,341 @@ +/* + * linux/kernel/irq.c + * + * Copyright (C) 1992 Linus Torvalds + * + * This file contains the code used by various IRQ handling routines: + * asking for different IRQ's should be done through these routines + * instead of just grabbing them. Thus setups with different IRQ numbers + * shouldn't result in any weird surprises, and installing new handlers + * should be easier. + */ + +/* + * IRQ's are in fact implemented a bit like signal handlers for the kernel. + * The same sigaction struct is used, and with similar semantics (ie there + * is a SA_INTERRUPT flag etc). Naturally it's not a 1:1 relation, but there + * are similarities. + * + * sa_handler(int irq_NR) is the default function called. + * sa_mask is 0 if nothing uses this IRQ + * sa_flags contains various info: SA_INTERRUPT etc + * sa_restorer is the unused + */ + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define CR0_NE 32 + +static unsigned char cache_21 = 0xff; +static unsigned char cache_A1 = 0xff; + +unsigned long intr_count = 0; +unsigned long bh_active = 0; +unsigned long bh_mask = 0xFFFFFFFF; +struct bh_struct bh_base[32]; + +void disable_irq(unsigned int irq_nr) +{ + unsigned long flags; + unsigned char mask; + + mask = 1 << (irq_nr & 7); + save_flags(flags); + if (irq_nr < 8) { + cli(); + cache_21 |= mask; + outb(cache_21,0x21); + restore_flags(flags); + return; + } + cli(); + cache_A1 |= mask; + outb(cache_A1,0xA1); + restore_flags(flags); +} + +void enable_irq(unsigned int irq_nr) +{ + unsigned long flags; + unsigned char mask; + + mask = ~(1 << (irq_nr & 7)); + save_flags(flags); + if (irq_nr < 8) { + cli(); + cache_21 &= mask; + outb(cache_21,0x21); + restore_flags(flags); + return; + } + cli(); + cache_A1 &= mask; + outb(cache_A1,0xA1); + restore_flags(flags); +} + +/* + * do_bottom_half() runs at normal kernel priority: all interrupts + * enabled. do_bottom_half() is atomic with respect to itself: a + * bottom_half handler need not be re-entrant. + */ +asmlinkage void do_bottom_half(void) +{ + unsigned long active; + unsigned long mask, left; + struct bh_struct *bh; + + bh = bh_base; + active = bh_active & bh_mask; + for (mask = 1, left = ~0 ; left & active ; bh++,mask += mask,left += left) { + if (mask & active) { + void (*fn)(void *); + bh_active &= ~mask; + fn = bh->routine; + if (!fn) + goto bad_bh; + fn(bh->data); + } + } + return; +bad_bh: + printk ("irq.c:bad bottom half entry\n"); +} + +/* + * This builds up the IRQ handler stubs using some ugly macros in irq.h + * + * These macros create the low-level assembly IRQ routines that do all + * the operations that are needed to keep the AT interrupt-controller + * happy. They are also written to be fast - and to disable interrupts + * as little as humanly possible. + * + * NOTE! These macros expand to three different handlers for each line: one + * complete handler that does all the fancy stuff (including signal handling), + * and one fast handler that is meant for simple IRQ's that want to be + * atomic. The specific handler is chosen depending on the SA_INTERRUPT + * flag when installing a handler. Finally, one "bad interrupt" handler, that + * is used when no handler is present. + */ +BUILD_IRQ(FIRST,0,0x01) +BUILD_IRQ(FIRST,1,0x02) +BUILD_IRQ(FIRST,2,0x04) +BUILD_IRQ(FIRST,3,0x08) +BUILD_IRQ(FIRST,4,0x10) +BUILD_IRQ(FIRST,5,0x20) +BUILD_IRQ(FIRST,6,0x40) +BUILD_IRQ(FIRST,7,0x80) +BUILD_IRQ(SECOND,8,0x01) +BUILD_IRQ(SECOND,9,0x02) +BUILD_IRQ(SECOND,10,0x04) +BUILD_IRQ(SECOND,11,0x08) +BUILD_IRQ(SECOND,12,0x10) +BUILD_IRQ(SECOND,13,0x20) +BUILD_IRQ(SECOND,14,0x40) +BUILD_IRQ(SECOND,15,0x80) + +/* + * Pointers to the low-level handlers: first the general ones, then the + * fast ones, then the bad ones. + */ +static void (*interrupt[16])(void) = { + IRQ0_interrupt, IRQ1_interrupt, IRQ2_interrupt, IRQ3_interrupt, + IRQ4_interrupt, IRQ5_interrupt, IRQ6_interrupt, IRQ7_interrupt, + IRQ8_interrupt, IRQ9_interrupt, IRQ10_interrupt, IRQ11_interrupt, + IRQ12_interrupt, IRQ13_interrupt, IRQ14_interrupt, IRQ15_interrupt +}; + +static void (*fast_interrupt[16])(void) = { + fast_IRQ0_interrupt, fast_IRQ1_interrupt, + fast_IRQ2_interrupt, fast_IRQ3_interrupt, + fast_IRQ4_interrupt, fast_IRQ5_interrupt, + fast_IRQ6_interrupt, fast_IRQ7_interrupt, + fast_IRQ8_interrupt, fast_IRQ9_interrupt, + fast_IRQ10_interrupt, fast_IRQ11_interrupt, + fast_IRQ12_interrupt, fast_IRQ13_interrupt, + fast_IRQ14_interrupt, fast_IRQ15_interrupt +}; + +static void (*bad_interrupt[16])(void) = { + bad_IRQ0_interrupt, bad_IRQ1_interrupt, + bad_IRQ2_interrupt, bad_IRQ3_interrupt, + bad_IRQ4_interrupt, bad_IRQ5_interrupt, + bad_IRQ6_interrupt, bad_IRQ7_interrupt, + bad_IRQ8_interrupt, bad_IRQ9_interrupt, + bad_IRQ10_interrupt, bad_IRQ11_interrupt, + bad_IRQ12_interrupt, bad_IRQ13_interrupt, + bad_IRQ14_interrupt, bad_IRQ15_interrupt +}; + +/* + * Initial irq handlers. + */ +static struct sigaction irq_sigaction[16] = { + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL }, + { NULL, 0, 0, NULL }, { NULL, 0, 0, NULL } +}; + +/* + * do_IRQ handles IRQ's that have been installed without the + * SA_INTERRUPT flag: it uses the full signal-handling return + * and runs with other interrupts enabled. All relatively slow + * IRQ's should use this format: notably the keyboard/timer + * routines. + */ +asmlinkage void do_IRQ(int irq, struct pt_regs * regs) +{ + struct sigaction * sa = irq + irq_sigaction; + + kstat.interrupts++; + sa->sa_handler((int) regs); +} + +/* + * do_fast_IRQ handles IRQ's that don't need the fancy interrupt return + * stuff - the handler is also running with interrupts disabled unless + * it explicitly enables them later. + */ +asmlinkage void do_fast_IRQ(int irq) +{ + struct sigaction * sa = irq + irq_sigaction; + + kstat.interrupts++; + sa->sa_handler(irq); +} + +int irqaction(unsigned int irq, struct sigaction * new_sa) +{ + struct sigaction * sa; + unsigned long flags; + + if (irq > 15) + return -EINVAL; + sa = irq + irq_sigaction; + if (sa->sa_mask) + return -EBUSY; + if (!new_sa->sa_handler) + return -EINVAL; + save_flags(flags); + cli(); + *sa = *new_sa; + sa->sa_mask = 1; + if (sa->sa_flags & SA_INTERRUPT) + set_intr_gate(0x20+irq,fast_interrupt[irq]); + else + set_intr_gate(0x20+irq,interrupt[irq]); + if (irq < 8) { + cache_21 &= ~(1< 15) { + printk("Trying to free IRQ%d\n",irq); + return; + } + if (!sa->sa_mask) { + printk("Trying to free free IRQ%d\n",irq); + return; + } + save_flags(flags); + cli(); + if (irq < 8) { + cache_21 |= 1 << irq; + outb(cache_21,0x21); + } else { + cache_A1 |= 1 << (irq-8); + outb(cache_A1,0xA1); + } + set_intr_gate(0x20+irq,bad_interrupt[irq]); + sa->sa_handler = NULL; + sa->sa_flags = 0; + sa->sa_mask = 0; + sa->sa_restorer = NULL; + restore_flags(flags); +} + +/* + * Note that on a 486, we don't want to do a SIGFPE on a irq13 + * as the irq is unreliable, and exception 16 works correctly + * (ie as explained in the intel litterature). On a 386, you + * can't use exception 16 due to bad IBM design, so we have to + * rely on the less exact irq13. + * + * Careful.. Not only is IRQ13 unreliable, but it is also + * leads to races. IBM designers who came up with it should + * be shot. + */ +static void math_error_irq(int cpl) +{ + outb(0,0xF0); + if (ignore_irq13) + return; + math_error(); +} + +static void no_action(int cpl) { } + +static struct sigaction ignore_IRQ = { + no_action, + 0, + SA_INTERRUPT, + NULL +}; + +void init_IRQ(void) +{ + int i; + + for (i = 0; i < 16 ; i++) + set_intr_gate(0x20+i,bad_interrupt[i]); + if (irqaction(2,&ignore_IRQ)) + printk("Unable to get IRQ2 for cascade\n"); + if (request_irq(13,math_error_irq)) + printk("Unable to get IRQ13 for math-error handler\n"); + + /* intialize the bottom half routines. */ + for (i = 0; i < 32; i++) { + bh_base[i].routine = NULL; + bh_base[i].data = NULL; + } + bh_active = 0; + intr_count = 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/itimer.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/itimer.c new file mode 100644 index 000000000..39d95e38d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/itimer.c @@ -0,0 +1,117 @@ +/* + * linux/kernel/itimer.c + * + * Copyright (C) 1992 Darren Senn + */ + +/* These are all the functions necessary to implement itimers */ + +#include +#include +#include +#include +#include + +#include + +static unsigned long tvtojiffies(struct timeval *value) +{ + return((unsigned long )value->tv_sec * HZ + + (unsigned long )(value->tv_usec + (1000000 / HZ - 1)) / + (1000000 / HZ)); +} + +static void jiffiestotv(unsigned long jiffies, struct timeval *value) +{ + value->tv_usec = (jiffies % HZ) * (1000000 / HZ); + value->tv_sec = jiffies / HZ; + return; +} + +int _getitimer(int which, struct itimerval *value) +{ + register unsigned long val, interval; + + switch (which) { + case ITIMER_REAL: + val = current->it_real_value; + interval = current->it_real_incr; + break; + case ITIMER_VIRTUAL: + val = current->it_virt_value; + interval = current->it_virt_incr; + break; + case ITIMER_PROF: + val = current->it_prof_value; + interval = current->it_prof_incr; + break; + default: + return(-EINVAL); + } + jiffiestotv(val, &value->it_value); + jiffiestotv(interval, &value->it_interval); + return(0); +} + +asmlinkage int sys_getitimer(int which, struct itimerval *value) +{ + int error; + struct itimerval get_buffer; + + if (!value) + return -EFAULT; + error = _getitimer(which, &get_buffer); + if (error) + return error; + error = verify_area(VERIFY_WRITE, value, sizeof(struct itimerval)); + if (error) + return error; + memcpy_tofs(value, &get_buffer, sizeof(get_buffer)); + return 0; +} + +int _setitimer(int which, struct itimerval *value, struct itimerval *ovalue) +{ + register unsigned long i, j; + int k; + + i = tvtojiffies(&value->it_interval); + j = tvtojiffies(&value->it_value); + if (ovalue && (k = _getitimer(which, ovalue)) < 0) + return k; + switch (which) { + case ITIMER_REAL: + current->it_real_value = j; + current->it_real_incr = i; + break; + case ITIMER_VIRTUAL: + current->it_virt_value = j; + current->it_virt_incr = i; + break; + case ITIMER_PROF: + current->it_prof_value = j; + current->it_prof_incr = i; + break; + default: + return -EINVAL; + } + return 0; +} + +asmlinkage int sys_setitimer(int which, struct itimerval *value, struct itimerval *ovalue) +{ + int error; + struct itimerval set_buffer, get_buffer; + + if (!value) + memset((char *) &set_buffer, 0, sizeof(set_buffer)); + else + memcpy_fromfs(&set_buffer, value, sizeof(set_buffer)); + error = _setitimer(which, &set_buffer, ovalue ? &get_buffer : 0); + if (error || !ovalue) + return error; + error = verify_area(VERIFY_WRITE, ovalue, sizeof(struct itimerval)); + if (!error) + memcpy_tofs(ovalue, &get_buffer, sizeof(get_buffer)); + return error; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.S b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.S new file mode 100644 index 000000000..d2196438d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.S @@ -0,0 +1,28 @@ +#include +/* + * Herein lies all the functions/variables that are "exported" for linkage + * With dynamically loaded kernel modules. Could do with making this a bit + * cleaner! + * + * Jon. + */ + +_register_chrdev +_unregister_chrdev +_wake_up_interruptible + +_wp_works_ok +___verify_write + +_current +_jiffies +_printk +_schedule + +#ifdef CONFIG_FTAPE +# +# The next labels are needed for ftape driver. +# +_ftape_big_buffer +_do_floppy +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.sh b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.sh new file mode 100644 index 000000000..d46f0910e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ksyms.sh @@ -0,0 +1,37 @@ +# This program will construct ksyms.s. Ksyms.s contains a symbol table +# for all the kernel symbols included in the file ksyms.lst. The following +# variables are defined in ksym.s: +# +# int symbol_table_size; /* number of symbols */ +# struct { +# void *value; /* value of symbol */ +# char *name; /* name of symbol */ +# } symbol_table[]; +# +# + +trap "rm -f ksyms.tmp ksyms.lst" 1 2 + +sed -e '/^#/d' -e '/^[ ]*$/d' ksyms.lst | sort > ksyms.tmp + +echo ' .data + .globl _symbol_table_size, _symbol_table + +_symbol_table_size:' +echo " .long" `wc -l < ksyms.tmp` +echo ' +_symbol_table:' +awk 'BEGIN {stringloc = 0} +{print " .long " $1; print " .long strings+" stringloc; \ + stringloc += length($1) + 1;}' ksyms.tmp +echo ' +strings:' +awk '{print " .ascii \"" $1 "\\0\""}' ksyms.tmp +rm -f ksyms.tmp + + +# +# Alternativly, if the kernel is c++ compiled: +# By using gsub() we can forse all function names to appear as extern "C". +# This allows linkable drivers written in C or C++ - Jon +# awk '{gsub(/__F.*/, "") ; print " .ascii \"" $0 "\\0\""}' ksyms.tmp diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ldt.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ldt.c new file mode 100644 index 000000000..f014cdc3d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ldt.c @@ -0,0 +1,102 @@ +/* + * linux/kernel/ldt.c + * + * Copyright (C) 1992 Krishna Balasubramanian and Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +static int read_ldt(void * ptr, unsigned long bytecount) +{ + int error; + void * address = current->ldt; + unsigned long size; + + if (!ptr) + return -EINVAL; + size = LDT_ENTRIES*LDT_ENTRY_SIZE; + if (!address) { + address = &default_ldt; + size = sizeof(default_ldt); + } + if (size > bytecount) + size = bytecount; + error = verify_area(VERIFY_WRITE, ptr, size); + if (error) + return error; + memcpy_tofs(ptr, address, size); + return size; +} + +static int write_ldt(void * ptr, unsigned long bytecount) +{ + struct modify_ldt_ldt_s ldt_info; + unsigned long *lp; + unsigned long base, limit; + int error, i; + + if (bytecount != sizeof(ldt_info)) + return -EINVAL; + error = verify_area(VERIFY_READ, ptr, sizeof(ldt_info)); + if (error) + return error; + + memcpy_fromfs(&ldt_info, ptr, sizeof(ldt_info)); + + if (ldt_info.contents == 3 || ldt_info.entry_number >= LDT_ENTRIES) + return -EINVAL; + + limit = ldt_info.limit; + base = ldt_info.base_addr; + if (ldt_info.limit_in_pages) + limit *= PAGE_SIZE; + + limit += base; + if (limit < base || limit >= 0xC0000000) + return -EINVAL; + + if (!current->ldt) { + for (i=1 ; ildt = (struct desc_struct*) vmalloc(LDT_ENTRIES*LDT_ENTRY_SIZE))) + return -ENOMEM; + set_ldt_desc(gdt+(i<<1)+FIRST_LDT_ENTRY, current->ldt, LDT_ENTRIES); + load_ldt(i); + } + } + } + + lp = (unsigned long *) ¤t->ldt[ldt_info.entry_number]; + /* Allow LDTs to be cleared by the user. */ + if (ldt_info.base_addr == 0 && ldt_info.limit == 0) { + *lp = 0; + *(lp+1) = 0; + return 0; + } + *lp = ((ldt_info.base_addr & 0x0000ffff) << 16) | + (ldt_info.limit & 0x0ffff); + *(lp+1) = (ldt_info.base_addr & 0xff000000) | + ((ldt_info.base_addr & 0x00ff0000)>>16) | + (ldt_info.limit & 0xf0000) | + (ldt_info.contents << 10) | + ((ldt_info.read_exec_only ^ 1) << 9) | + (ldt_info.seg_32bit << 22) | + (ldt_info.limit_in_pages << 23) | + 0xf000; + return 0; +} + +asmlinkage int sys_modify_ldt(int func, void *ptr, unsigned long bytecount) +{ + if (func == 0) + return read_ldt(ptr, bytecount); + if (func == 1) + return write_ldt(ptr, bytecount); + return -ENOSYS; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/mktime.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/mktime.c new file mode 100644 index 000000000..26abae258 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/mktime.c @@ -0,0 +1,58 @@ +/* + * linux/kernel/mktime.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +/* + * This isn't the library routine, it is only used in the kernel. + * as such, we don't care about years<1970 etc, but assume everything + * is ok. Similarly, TZ etc is happily ignored. We just do everything + * as easily as possible. Let's find something public for the library + * routines (although I think minix times is public). + */ +/* + * PS. I hate whoever though up the year 1970 - couldn't they have gotten + * a leap-year instead? I also hate Gregorius, pope or no. I'm grumpy. + */ +#define MINUTE 60 +#define HOUR (60*MINUTE) +#define DAY (24*HOUR) +#define YEAR (365*DAY) + +/* interestingly, we assume leap-years */ +static int month[12] = { + 0, + DAY*(31), + DAY*(31+29), + DAY*(31+29+31), + DAY*(31+29+31+30), + DAY*(31+29+31+30+31), + DAY*(31+29+31+30+31+30), + DAY*(31+29+31+30+31+30+31), + DAY*(31+29+31+30+31+30+31+31), + DAY*(31+29+31+30+31+30+31+31+30), + DAY*(31+29+31+30+31+30+31+31+30+31), + DAY*(31+29+31+30+31+30+31+31+30+31+30) +}; + +long kernel_mktime(struct mktime * time) +{ + long res; + int year; + + year = time->year - 70; +/* magic offsets (y+1) needed to get leapyears right.*/ + res = YEAR*year + DAY*((year+1)/4); + res += month[time->mon]; +/* and (y+2) here. If it wasn't a leap-year, we have to adjust */ + if (time->mon>1 && ((year+2)%4)) + res -= DAY; + res += DAY*(time->day-1); + res += HOUR*time->hour; + res += MINUTE*time->min; + res += time->sec; + return res; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/module.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/module.c new file mode 100644 index 000000000..2e38de595 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/module.c @@ -0,0 +1,277 @@ +#include +#include +#include +#include /* defines GFP_KERNEL */ +#include +#include +#include +#include + +struct module *module_list = NULL; +int freeing_modules; /* true if some modules are marked for deletion */ + +struct module *find_module( const char *name); +int get_mod_name( char *user_name, char *buf); +int free_modules( void); + +/* + * Allocate space for a module. + */ +asmlinkage int +sys_create_module(char *module_name, unsigned long size) +{ + int npages; + void* addr; + int len; + char name[MOD_MAX_NAME]; + char *savename; + struct module *mp; + int error; + + if (!suser()) + return -EPERM; + if (module_name == NULL || size == 0) + return -EINVAL; + if ((error = get_mod_name(module_name, name)) != 0) + return error; + if (find_module(name) != NULL) { + return -EEXIST; + } + len = strlen(name) + 1; + if ((savename = (char*) kmalloc(len, GFP_KERNEL)) == NULL) + return -ENOMEM; + memcpy(savename, name, len); + if ((mp = (struct module*) kmalloc(sizeof *mp, GFP_KERNEL)) == NULL) { + kfree(savename); + return -ENOMEM; + } + npages = (size + sizeof (int) + 4095) / 4096; + if ((addr = vmalloc(npages * 4096)) == 0) { + kfree_s(mp, sizeof *mp); + kfree(savename); + return -ENOMEM; + } + mp->name = savename; + mp->size = npages; + mp->addr = addr; + mp->state = MOD_UNINITIALIZED; + * (int *) addr = 0; /* set use count to zero */ + mp->cleanup = NULL; + mp->next = module_list; + module_list = mp; + printk("module `%s' (%lu pages @ 0x%08lx) created\n", + mp->name, (unsigned long) mp->size, (unsigned long) mp->addr); + return (int) addr; +} + +/* + * Initialize a module. + */ +asmlinkage int +sys_init_module(char *module_name, char *code, unsigned codesize, + struct mod_routines *routines) +{ + struct module *mp; + char name[MOD_MAX_NAME]; + int error; + struct mod_routines rt; + + if (!suser()) + return -EPERM; + /* + * First reclaim any memory from dead modules that where not + * freed when deleted. Should I think be done by timers when + * the module was deleted - Jon. + */ + free_modules(); + + if ((error = get_mod_name(module_name, name)) != 0) + return error; + printk( "initializing module `%s', %d (0x%x) bytes\n", + name, codesize, codesize); + memcpy_fromfs(&rt, routines, sizeof rt); + if ((mp = find_module(name)) == NULL) + return -ENOENT; + if ((codesize + sizeof (int) + 4095) / 4096 > mp->size) + return -EINVAL; + memcpy_fromfs((char *)mp->addr + sizeof (int), code, codesize); + memset((char *)mp->addr + sizeof (int) + codesize, 0, + mp->size * 4096 - (codesize + sizeof (int))); + printk( " init entry @ 0x%08lx, cleanup entry @ 0x%08lx\n", + (unsigned long) rt.init, (unsigned long) rt.cleanup); + mp->cleanup = rt.cleanup; + if ((*rt.init)() != 0) + return -EBUSY; + mp->state = MOD_RUNNING; + return 0; +} + +asmlinkage int +sys_delete_module(char *module_name) +{ + struct module *mp; + char name[MOD_MAX_NAME]; + int error; + + if (!suser()) + return -EPERM; + if (module_name != NULL) { + if ((error = get_mod_name(module_name, name)) != 0) + return error; + if ((mp = find_module(name)) == NULL) + return -ENOENT; + if (mp->state == MOD_RUNNING) + (*mp->cleanup)(); + mp->state = MOD_DELETED; + } + free_modules(); + return 0; +} + +/* + * Copy the kernel symbol table to user space. If the argument is null, + * just return the size of the table. + */ +asmlinkage int +sys_get_kernel_syms(struct kernel_sym *table) +{ + struct symbol { + unsigned long addr; + char *name; + }; + extern int symbol_table_size; + extern struct symbol symbol_table[]; + int i; + struct symbol *from; + struct kernel_sym *to; + struct kernel_sym sym; + + if (table != NULL) { + from = symbol_table; + to = table; + i = verify_area(VERIFY_WRITE, to, symbol_table_size * sizeof *table); + if (i) + return i; + for (i = symbol_table_size ; --i >= 0 ; ) { + sym.value = from->addr; + strncpy(sym.name, from->name, sizeof sym.name); + memcpy_tofs(to, &sym, sizeof sym); + from++, to++; + } + } + return symbol_table_size; +} + + +/* + * Copy the name of a module from user space. + */ +int +get_mod_name(char *user_name, char *buf) +{ + int i; + + i = 0; + for (i = 0 ; (buf[i] = get_fs_byte(user_name + i)) != '\0' ; ) { + if (++i >= MOD_MAX_NAME) + return -E2BIG; + } + return 0; +} + + +/* + * Look for a module by name, ignoring modules marked for deletion. + */ +struct module * +find_module( const char *name) +{ + struct module *mp; + + for (mp = module_list ; mp ; mp = mp->next) { + if (mp->state == MOD_DELETED) + continue; + if (!strcmp(mp->name, name)) + break; + } + return mp; +} + + +/* + * Try to free modules which have been marked for deletion. Returns nonzero + * if a module was actually freed. + */ +int +free_modules( void) +{ + struct module *mp; + struct module **mpp; + int did_deletion; + + did_deletion = 0; + freeing_modules = 0; + mpp = &module_list; + while ((mp = *mpp) != NULL) { + if (mp->state != MOD_DELETED) { + mpp = &mp->next; + } else if (GET_USE_COUNT(mp) != 0) { + freeing_modules = 1; + mpp = &mp->next; + } else { /* delete it */ + *mpp = mp->next; + vfree(mp->addr); + kfree(mp->name); + kfree_s(mp, sizeof *mp); + did_deletion = 1; + } + } + return did_deletion; +} + + +/* + * Called by the /proc file system to return a current list of modules. + */ +int +get_module_list( char *buf) +{ + char *p; + char *q; + int i; + struct module *mp; + char size[32]; + + p = buf; + for (mp = module_list ; mp ; mp = mp->next) { + if (p - buf > 4096 - 100) + break; /* avoid overflowing buffer */ + q = mp->name; + i = 20; + while (*q) { + *p++ = *q++; + i--; + } + sprintf(size, "%d", mp->size); + i -= strlen(size); + if (i <= 0) + i = 1; + while (--i >= 0) + *p++ = ' '; + q = size; + while (*q) + *p++ = *q++; + if (mp->state == MOD_UNINITIALIZED) + q = " (uninitialized)"; + else if (mp->state == MOD_RUNNING) + q = ""; + else if (mp->state == MOD_DELETED) + q = " (deleted)"; + else + q = " (bad state)"; + while (*q) + *p++ = *q++; + *p++ = '\n'; + } + return p - buf; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/panic.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/panic.c new file mode 100644 index 000000000..43ba3c684 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/panic.c @@ -0,0 +1,34 @@ +/* + * linux/kernel/panic.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This function is used through-out the kernel (includeinh mm and fs) + * to indicate a major problem. + */ +#include + +#include +#include + +asmlinkage void sys_sync(void); /* it's really int */ + +extern int vsprintf(char * buf, const char * fmt, va_list args); + +NORET_TYPE void panic(const char * fmt, ...) +{ + static char buf[1024]; + va_list args; + + va_start(args, fmt); + vsprintf(buf, fmt, args); + va_end(args); + printk(KERN_EMERG "Kernel panic: %s\n",buf); + if (current == task[0]) + printk(KERN_EMERG "In swapper task - not syncing\n"); + else + sys_sync(); + for(;;); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/printk.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/printk.c new file mode 100644 index 000000000..13c6b243f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/printk.c @@ -0,0 +1,230 @@ +/* + * linux/kernel/printk.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Modified to make sys_syslog() more flexible: added commands to + * return the last 4k of kernel messages, regardless of whether + * they've been read or not. Added option to suppress kernel printk's + * to the console. Added hook for sending the console messages + * elsewhere, in preparation for a serial line console (someday). + * Ted Ts'o, 2/11/93. + */ + +#include + +#include +#include + +#include +#include +#include + +#define LOG_BUF_LEN 4096 + +static char buf[1024]; + +extern int vsprintf(char * buf, const char * fmt, va_list args); +extern void console_print(const char *); + +#define DEFAULT_MESSAGE_LOGLEVEL 7 /* KERN_DEBUG */ +#define DEFAULT_CONSOLE_LOGLEVEL 7 /* anything more serious than KERN_DEBUG */ + +unsigned long log_size = 0; +struct wait_queue * log_wait = NULL; +int console_loglevel = DEFAULT_CONSOLE_LOGLEVEL; + +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; + +/* + * Commands to sys_syslog: + * + * 0 -- Close the log. Currently a NOP. + * 1 -- Open the log. Currently a NOP. + * 2 -- Read from the log. + * 3 -- Read up to the last 4k of messages in the ring buffer. + * 4 -- Read and clear last 4k of messages in the ring buffer + * 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) +{ + unsigned long i, j, count; + int do_clear = 0; + char c; + int error; + + if ((type != 3) && !suser()) + return -EPERM; + switch (type) { + case 0: /* Close log */ + return 0; + case 1: /* Open log */ + return 0; + case 2: /* Read from log */ + if (!buf || len < 0) + return -EINVAL; + if (!len) + return 0; + error = verify_area(VERIFY_WRITE,buf,len); + if (error) + return error; + cli(); + while (!log_size) { + if (current->signal & ~current->blocked) { + sti(); + return -ERESTARTSYS; + } + interruptible_sleep_on(&log_wait); + } + i = 0; + while (log_size && i < len) { + c = *((char *) log_buf+log_start); + log_start++; + log_size--; + log_start &= LOG_BUF_LEN-1; + sti(); + put_fs_byte(c,buf); + buf++; + i++; + cli(); + } + sti(); + return i; + case 4: /* Read/clear last kernel messages */ + do_clear = 1; + /* FALL THRU */ + case 3: /* Read last kernel messages */ + if (!buf || len < 0) + return -EINVAL; + if (!len) + return 0; + error = verify_area(VERIFY_WRITE,buf,len); + if (error) + return error; + count = len; + if (count > LOG_BUF_LEN) + count = LOG_BUF_LEN; + if (count > logged_chars) + count = logged_chars; + j = log_start + log_size - count; + for (i = 0; i < count; i++) { + c = *((char *) log_buf+(j++ & (LOG_BUF_LEN-1))); + put_fs_byte(c, buf++); + } + if (do_clear) + logged_chars = 0; + return i; + case 5: /* Clear ring buffer */ + logged_chars = 0; + return 0; + case 6: /* Disable logging to console */ + console_loglevel = 1; /* only panic messages shown */ + return 0; + case 7: /* Enable logging to console */ + console_loglevel = DEFAULT_CONSOLE_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; + char *msg, *p, *buf_end; + static char msg_level = -1; + long flags; + + save_flags(flags); + cli(); + va_start(args, fmt); + i = vsprintf(buf + 3, fmt, args); /* hopefully i < sizeof(buf)-4 */ + buf_end = buf + 3 + i; + va_end(args); + 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_MESSAGE_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; + } + restore_flags(flags); + wake_up_interruptible(&log_wait); + return i; +} + +/* + * 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 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 (buf[j-1] != '\n' && i < log_size - 1 && j < sizeof(buf)-1) + continue; + buf[j] = 0; + 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; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ptrace.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ptrace.c new file mode 100644 index 000000000..d40dc7d57 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/ptrace.c @@ -0,0 +1,480 @@ +/* ptrace.c */ +/* By Ross Biro 1/23/92 */ +/* edited by Linus Torvalds */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +/* + * does not yet catch signals sent when the child dies. + * in exit.c or in signal.c. + */ + +/* determines which flags the user has access to. */ +/* 1 = access 0 = no access */ +#define FLAG_MASK 0x00044dd5 + +/* set's the trap flag. */ +#define TRAP_FLAG 0x100 + +/* + * this is the number to subtract from the top of the stack. To find + * the local frame. + */ +#define MAGICNUMBER 68 + +/* change a pid into a task struct. */ +static inline struct task_struct * get_task(int pid) +{ + int i; + + for (i = 1; i < NR_TASKS; i++) { + if (task[i] != NULL && (task[i]->pid == pid)) + return task[i]; + } + return NULL; +} + +/* + * this routine will get a word off of the processes priviledged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the priviledged stacks are in our + * data space. + */ +static inline int get_stack_long(struct task_struct *task, int offset) +{ + unsigned char *stack; + + stack = (unsigned char *)task->tss.esp0; + stack += offset; + return (*((int *)stack)); +} + +/* + * this routine will put a word on the processes priviledged stack. + * the offset is how far from the base addr as stored in the TSS. + * this routine assumes that all the priviledged stacks are in our + * data space. + */ +static inline int put_stack_long(struct task_struct *task, int offset, + unsigned long data) +{ + unsigned char * stack; + + stack = (unsigned char *) task->tss.esp0; + stack += offset; + *(unsigned long *) stack = data; + return 0; +} + +/* + * This routine gets a long from any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + * NOTE2! This uses "tsk->tss.cr3" even though we know it's currently always + * zero. This routine shouldn't have to change when we make a better mm. + */ +static unsigned long get_long(struct task_struct * tsk, + unsigned long addr) +{ + unsigned long page; + +repeat: + page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr); + if (page & PAGE_PRESENT) { + page &= PAGE_MASK; + page += PAGE_PTR(addr); + page = *((unsigned long *) page); + } + if (!(page & PAGE_PRESENT)) { + do_no_page(0,addr,tsk,0); + goto repeat; + } +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page >= high_memory) + return 0; + page &= PAGE_MASK; + page += addr & ~PAGE_MASK; + return *(unsigned long *) page; +} + +/* + * This routine puts a long into any process space by following the page + * tables. NOTE! You should check that the long isn't on a page boundary, + * and that it is in the task area before calling this: this routine does + * no checking. + * + * Now keeps R/W state of page so that a text page stays readonly + * even if a debugger scribbles breakpoints into it. -M.U- + */ +static void put_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) +{ + unsigned long page, pte = 0; + int readonly = 0; + +repeat: + page = *PAGE_DIR_OFFSET(tsk->tss.cr3,addr); + if (page & PAGE_PRESENT) { + page &= PAGE_MASK; + page += PAGE_PTR(addr); + pte = page; + page = *((unsigned long *) page); + } + if (!(page & PAGE_PRESENT)) { + do_no_page(0 /* PAGE_RW */ ,addr,tsk,0); + goto repeat; + } + if (!(page & PAGE_RW)) { + if(!(page & PAGE_COW)) + readonly = 1; + do_wp_page(PAGE_RW | PAGE_PRESENT,addr,tsk,0); + goto repeat; + } +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page >= high_memory) + return; +/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ + *(unsigned long *) pte |= (PAGE_DIRTY|PAGE_COW); + page &= PAGE_MASK; + page += addr & ~PAGE_MASK; + *(unsigned long *) page = data; + if(readonly) { + *(unsigned long *) pte &=~ (PAGE_RW|PAGE_COW); + invalidate(); + } +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls get_long() to read a long. + */ +static int read_long(struct task_struct * tsk, unsigned long addr, + unsigned long * result) +{ + unsigned long low,high; + + if (addr > TASK_SIZE-sizeof(long)) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + low = get_long(tsk,addr & ~(sizeof(long)-1)); + high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 1: + low >>= 8; + low |= high << 24; + break; + case 2: + low >>= 16; + low |= high << 16; + break; + case 3: + low >>= 24; + low |= high << 8; + break; + } + *result = low; + } else + *result = get_long(tsk,addr); + return 0; +} + +/* + * This routine checks the page boundaries, and that the offset is + * within the task area. It then calls put_long() to write a long. + */ +static int write_long(struct task_struct * tsk, unsigned long addr, + unsigned long data) +{ + unsigned long low,high; + + if (addr > TASK_SIZE-sizeof(long)) + return -EIO; + if ((addr & ~PAGE_MASK) > PAGE_SIZE-sizeof(long)) { + low = get_long(tsk,addr & ~(sizeof(long)-1)); + high = get_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1)); + switch (addr & (sizeof(long)-1)) { + case 0: /* shouldn't happen, but safety first */ + low = data; + break; + case 1: + low &= 0x000000ff; + low |= data << 8; + high &= ~0xff; + high |= data >> 24; + break; + case 2: + low &= 0x0000ffff; + low |= data << 16; + high &= ~0xffff; + high |= data >> 16; + break; + case 3: + low &= 0x00ffffff; + low |= data << 24; + high &= ~0xffffff; + high |= data >> 8; + break; + } + put_long(tsk,addr & ~(sizeof(long)-1),low); + put_long(tsk,(addr+sizeof(long)) & ~(sizeof(long)-1),high); + } else + put_long(tsk,addr,data); + return 0; +} + +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? */ + if (current->flags & PF_PTRACED) + return -EPERM; + /* set the ptrace bit in the proccess flags. */ + current->flags |= PF_PTRACED; + return 0; + } + if (pid == 1) /* you may not mess with init */ + return -EPERM; + if (!(child = get_task(pid))) + return -ESRCH; + if (request == PTRACE_ATTACH) { + if (child == current) + return -EPERM; + if ((!child->dumpable || (current->uid != child->euid) || + (current->gid != child->egid)) && !suser()) + return -EPERM; + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) + return -EPERM; + child->flags |= PF_PTRACED; + if (child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + send_sig(SIGSTOP, child, 1); + return 0; + } + if (!(child->flags & PF_PTRACED)) + return -ESRCH; + if (child->state != TASK_STOPPED) { + if (request != PTRACE_KILL) + return -ESRCH; + } + if (child->p_pptr != current) + return -ESRCH; + + switch (request) { + /* when I and D space are seperate, these will need to be fixed. */ + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int res; + + res = read_long(child, addr, &tmp); + if (res < 0) + return res; + res = verify_area(VERIFY_WRITE, (void *) data, sizeof(long)); + if (!res) + put_fs_long(tmp,(unsigned long *) data); + return res; + } + + /* read the word at location addr in the USER area. */ + case PTRACE_PEEKUSR: { + unsigned long tmp; + int res; + + 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 = 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; + } + + /* when I and D space are seperate, this will have to be fixed. */ + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: + return write_long(child,addr,data); + + case PTRACE_POKEUSR: /* write the word at location addr in the USER area */ + 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 || + addr == FS || addr == GS || + addr == CS || addr == SS) { + data &= 0xffff; + if (data && (data & 3) != 3) + return -EIO; + } + if (addr == EFL) { /* flags. */ + data &= FLAG_MASK; + data |= get_stack_long(child, EFL*sizeof(long)-MAGICNUMBER) & ~FLAG_MASK; + } + /* 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. */ + long tmp; + + if ((unsigned long) data > NSIG) + return -EIO; + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + child->state = TASK_RUNNING; + /* make sure the single step bit is not set. */ + tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; + put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + return 0; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it want's to + * exit. + */ + case PTRACE_KILL: { + long tmp; + + child->state = TASK_RUNNING; + child->exit_code = SIGKILL; + /* make sure the single step bit is not set. */ + tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; + put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + return 0; + } + + case PTRACE_SINGLESTEP: { /* set the trap flag. */ + long tmp; + + if ((unsigned long) data > NSIG) + return -EIO; + child->flags &= ~PF_TRACESYS; + tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) | TRAP_FLAG; + put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + child->state = TASK_RUNNING; + child->exit_code = data; + /* give it a chance to run. */ + return 0; + } + + case PTRACE_DETACH: { /* detach a process that was attached. */ + long tmp; + + if ((unsigned long) data > NSIG) + return -EIO; + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + child->state = TASK_RUNNING; + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + /* make sure the single step bit is not set. */ + tmp = get_stack_long(child, sizeof(long)*EFL-MAGICNUMBER) & ~TRAP_FLAG; + put_stack_long(child, sizeof(long)*EFL-MAGICNUMBER,tmp); + return 0; + } + + default: + return -EIO; + } +} + +asmlinkage void syscall_trace(void) +{ + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + /* + * this isn't the same as continuing with a signal, but it will do + * for normal use. strace only continues with a signal if the + * stopping signal is not SIGTRAP. -brl + */ + if (current->exit_code) + current->signal |= (1 << (current->exit_code - 1)); + current->exit_code = 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sched.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sched.c new file mode 100644 index 000000000..43c648953 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sched.c @@ -0,0 +1,828 @@ +/* + * linux/kernel/sched.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'sched.c' is the main kernel file. It contains scheduling primitives + * (sleep_on, wakeup, schedule etc) as well as a number of simple system + * call functions (type getpid(), which just extracts a field from + * current-task + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#define TIMER_IRQ 0 + +#include + +/* + * 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; +long time_adjust_step = 0; + +int need_resched = 0; + +/* + * Tell us the machine setup.. + */ +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; /* set if paging hardware honours WP */ + +/* + * Bus types .. + */ +int EISA_bus = 0; + +extern int _setitimer(int, struct itimerval *, struct itimerval *); +unsigned long * prof_buffer = NULL; +unsigned long prof_len = 0; + +#define _S(nr) (1<<((nr)-1)) + +extern void mem_use(void); + +extern int timer_interrupt(void); +asmlinkage int system_call(void); + +static unsigned long init_kernel_stack[1024]; +struct task_struct init_task = INIT_TASK; + +unsigned long volatile jiffies=0; + +struct task_struct *current = &init_task; +struct task_struct *last_task_used_math = NULL; + +struct task_struct * task[NR_TASKS] = {&init_task, }; + +long user_stack [ PAGE_SIZE>>2 ] ; + +struct { + long * a; + short b; + } stack_start = { & user_stack [PAGE_SIZE>>2] , KERNEL_DS }; + +struct kernel_stat kstat = + { 0, 0, 0, { 0, 0, 0, 0 }, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; + +/* + * int 0x80 entry points.. Moved away from the header file, as + * iBCS2 may also want to use the '' headers.. + */ +#ifdef __cplusplus +extern "C" { +#endif + +int sys_ni_syscall(void) +{ + return -EINVAL; +} + +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, sys_mprotect, sys_sigprocmask, sys_create_module, +sys_init_module, sys_delete_module, sys_get_kernel_syms, sys_quotactl, +sys_getpgid, sys_fchdir, sys_bdflush }; + +/* 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 + * + * Careful.. There are problems with IBM-designed IRQ13 behaviour. + * Don't touch unless you *really* know how it works. + */ +asmlinkage void math_state_restore(void) +{ + __asm__ __volatile__("clts"); + if (last_task_used_math == current) + return; + timer_table[COPRO_TIMER].expires = jiffies+50; + timer_active |= 1<tss.i387)); + else + __asm__("fnclex"); + last_task_used_math = current; + if (current->used_math) { + __asm__("frstor %0": :"m" (current->tss.i387)); + } else { + __asm__("fninit"); + current->used_math=1; + } + timer_active &= ~(1<comm); + send_sig(SIGFPE,current,1); + schedule(); +} + +#endif /* CONFIG_MATH_EMULATION */ + +static unsigned long itimer_ticks = 0; +static unsigned long itimer_next = ~0; +static unsigned long lost_ticks = 0; + +/* + * 'schedule()' is the scheduler function. It's a very simple and nice + * scheduler: it's not perfect, but certainly works for most things. + * The one thing you might take a look at is the signal-handler code here. + * + * NOTE!! Task 0 is the 'idle' task, which gets called when no other + * tasks can run. It can not be killed, and it cannot sleep. The 'state' + * information in task[0] is never used. + * + * The "confuse_gcc" goto is used only to get better assembly code.. + * Djikstra probably hates me. + */ +asmlinkage void schedule(void) +{ + int c; + struct task_struct * p; + struct task_struct * next; + unsigned long ticks; + +/* check alarm, wake up any interruptible tasks that have got a signal */ + + cli(); + ticks = itimer_ticks; + itimer_ticks = 0; + itimer_next = ~0; + sti(); + need_resched = 0; + p = &init_task; + for (;;) { + if ((p = p->next_task) == &init_task) + goto confuse_gcc1; + if (ticks && p->it_real_value) { + if (p->it_real_value <= ticks) { + send_sig(SIGALRM, p, 1); + if (!p->it_real_incr) { + p->it_real_value = 0; + goto end_itimer; + } + do { + p->it_real_value += p->it_real_incr; + } while (p->it_real_value <= ticks); + } + p->it_real_value -= ticks; + if (p->it_real_value < itimer_next) + itimer_next = p->it_real_value; + } +end_itimer: + if (p->state != TASK_INTERRUPTIBLE) + continue; + if (p->signal & ~p->blocked) { + p->state = TASK_RUNNING; + continue; + } + if (p->timeout && p->timeout <= jiffies) { + p->timeout = 0; + p->state = TASK_RUNNING; + } + } +confuse_gcc1: + +/* this is the scheduler proper: */ +#if 0 + /* give processes that go to sleep a bit higher priority.. */ + /* This depends on the values for TASK_XXX */ + /* This gives smoother scheduling for some things, but */ + /* can be very unfair under some circumstances, so.. */ + if (TASK_UNINTERRUPTIBLE >= (unsigned) current->state && + current->counter < current->priority*2) { + ++current->counter; + } +#endif + c = -1; + next = p = &init_task; + for (;;) { + if ((p = p->next_task) == &init_task) + goto confuse_gcc2; + if (p->state == TASK_RUNNING && p->counter > c) + c = p->counter, next = p; + } +confuse_gcc2: + if (!c) { + for_each_task(p) + p->counter = (p->counter >> 1) + p->priority; + } + if(current != next) + kstat.context_swtch++; + 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) +{ + current->state = TASK_INTERRUPTIBLE; + schedule(); + return -ERESTARTNOHAND; +} + +/* + * wake_up doesn't wake up stopped processes - they have to be awakened + * with signals or similar. + * + * Note that this doesn't need cli-sti pairs: interrupts may not change + * the wait-queue structures directly, but only call wake_up() to wake + * a process. The process itself must remove the queue once it has woken. + */ +void wake_up(struct wait_queue **q) +{ + struct wait_queue *tmp; + struct task_struct * p; + + if (!q || !(tmp = *q)) + return; + do { + if ((p = tmp->task) != NULL) { + if ((p->state == TASK_UNINTERRUPTIBLE) || + (p->state == TASK_INTERRUPTIBLE)) { + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } + } + if (!tmp->next) { + printk("wait_queue is bad (eip = %08lx)\n",((unsigned long *) q)[-1]); + printk(" q = %p\n",q); + printk(" *q = %p\n",*q); + printk(" tmp = %p\n",tmp); + break; + } + tmp = tmp->next; + } while (tmp != *q); +} + +void wake_up_interruptible(struct wait_queue **q) +{ + struct wait_queue *tmp; + struct task_struct * p; + + if (!q || !(tmp = *q)) + return; + do { + if ((p = tmp->task) != NULL) { + if (p->state == TASK_INTERRUPTIBLE) { + p->state = TASK_RUNNING; + if (p->counter > current->counter) + need_resched = 1; + } + } + if (!tmp->next) { + printk("wait_queue is bad (eip = %08lx)\n",((unsigned long *) q)[-1]); + printk(" q = %p\n",q); + printk(" *q = %p\n",*q); + printk(" tmp = %p\n",tmp); + break; + } + tmp = tmp->next; + } while (tmp != *q); +} + +static inline void __sleep_on(struct wait_queue **p, int state) +{ + unsigned long flags; + struct wait_queue wait = { current, NULL }; + + if (!p) + return; + if (current == task[0]) + panic("task[0] trying to sleep"); + current->state = state; + add_wait_queue(p, &wait); + save_flags(flags); + sti(); + schedule(); + remove_wait_queue(p, &wait); + restore_flags(flags); +} + +void interruptible_sleep_on(struct wait_queue **p) +{ + __sleep_on(p,TASK_INTERRUPTIBLE); +} + +void sleep_on(struct wait_queue **p) +{ + __sleep_on(p,TASK_UNINTERRUPTIBLE); +} + +static struct timer_list * next_timer = NULL; + +void add_timer(struct timer_list * timer) +{ + unsigned long flags; + struct timer_list ** p; + + if (!timer) + return; + timer->next = NULL; + p = &next_timer; + save_flags(flags); + cli(); + while (*p) { + if ((*p)->expires > timer->expires) { + (*p)->expires -= timer->expires; + timer->next = *p; + break; + } + timer->expires -= (*p)->expires; + p = &(*p)->next; + } + *p = timer; + restore_flags(flags); +} + +int del_timer(struct timer_list * timer) +{ + unsigned long flags; + unsigned long expires = 0; + struct timer_list **p; + + p = &next_timer; + save_flags(flags); + cli(); + while (*p) { + if (*p == timer) { + if ((*p = timer->next) != NULL) + (*p)->expires += timer->expires; + timer->expires += expires; + restore_flags(flags); + return 1; + } + expires += (*p)->expires; + p = &(*p)->next; + } + restore_flags(flags); + return 0; +} + +unsigned long timer_active = 0; +struct timer_struct timer_table[32]; + +/* + * Hmm.. Changed this, as the GNU make sources (load.c) seems to + * imply that avenrun[] is the standard name for this kind of thing. + * Nothing else seems to be standardized: the fractional size etc + * all seem to differ on different machines. + */ +unsigned long avenrun[3] = { 0,0,0 }; + +/* + * Nr of active tasks - counted in fixed-point numbers + */ +static unsigned long count_active_tasks(void) +{ + struct task_struct **p; + unsigned long nr = 0; + + for(p = &LAST_TASK; p > &FIRST_TASK; --p) + if (*p && ((*p)->state == TASK_RUNNING || + (*p)->state == TASK_UNINTERRUPTIBLE || + (*p)->state == TASK_SWAPPING)) + nr += FIXED_1; + return nr; +} + +static inline void calc_load(void) +{ + unsigned long active_tasks; /* fixed-point */ + static int count = LOAD_FREQ; + + if (count-- > 0) + return; + count = LOAD_FREQ; + active_tasks = count_active_tasks(); + CALC_LOAD(avenrun[0], EXP_1, active_tasks); + CALC_LOAD(avenrun[1], EXP_5, active_tasks); + CALC_LOAD(avenrun[2], EXP_15, active_tasks); +} + +/* + * 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; +} + +/* + * disregard lost ticks for now.. We don't care enough. + */ +static void timer_bh(void * unused) +{ + unsigned long mask; + struct timer_struct *tp; + + cli(); + while (next_timer && next_timer->expires == 0) { + void (*fn)(unsigned long) = next_timer->function; + unsigned long data = next_timer->data; + next_timer = next_timer->next; + sti(); + fn(data); + cli(); + } + sti(); + + for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) { + if (mask > timer_active) + break; + if (!(mask & timer_active)) + continue; + if (tp->expires > jiffies) + continue; + timer_active &= ~mask; + tp->fn(); + sti(); + } +} + +/* + * The int argument is really a (struct pt_regs *), in case the + * interrupt wants to know from where it was called. The timer + * irq uses this to decide if it should update the user or system + * times. + */ +static void do_timer(struct pt_regs * regs) +{ + unsigned long mask; + struct timer_struct *tp; + + 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 + time_adjust_step - ltemp; + } + else if (time_phase > FINEUSEC) { + ltemp = time_phase >> SHIFT_SCALE; + time_phase -= ltemp << SHIFT_SCALE; + xtime.tv_usec += tick + time_adjust_step + ltemp; + } else + xtime.tv_usec += tick + time_adjust_step; + + if (time_adjust) + { + /* We are doing an adjtime thing. + * + * 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 + * + * Limit the amount of the step for *next* tick to be + * in the range -tickadj .. +tickadj + */ + if (time_adjust > tickadj) + time_adjust_step = tickadj; + else if (time_adjust < -tickadj) + time_adjust_step = -tickadj; + else + time_adjust_step = time_adjust; + + /* Reduce by this step the amount of time left */ + time_adjust -= time_adjust_step; + } + else + time_adjust_step = 0; + + 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)) { + current->utime++; + if (current != task[0]) { + if (current->priority < 15) + kstat.cpu_nice++; + else + kstat.cpu_user++; + } + /* Update ITIMER_VIRT for current task if not in a system call */ + if (current->it_virt_value && !(--current->it_virt_value)) { + current->it_virt_value = current->it_virt_incr; + send_sig(SIGVTALRM,current,1); + } + } else { + current->stime++; + if(current != task[0]) + kstat.cpu_system++; +#ifdef CONFIG_PROFILE + if (prof_buffer && current != task[0]) { + unsigned long eip = regs->eip; + eip >>= 2; + if (eip < prof_len) + prof_buffer[eip]++; + } +#endif + } + if (current == task[0] || (--current->counter)<=0) { + current->counter=0; + need_resched = 1; + } + /* Update ITIMER_PROF for the current task */ + if (current->it_prof_value && !(--current->it_prof_value)) { + current->it_prof_value = current->it_prof_incr; + send_sig(SIGPROF,current,1); + } + for (mask = 1, tp = timer_table+0 ; mask ; tp++,mask += mask) { + if (mask > timer_active) + break; + if (!(mask & timer_active)) + continue; + if (tp->expires > jiffies) + continue; + mark_bh(TIMER_BH); + } + cli(); + itimer_ticks++; + if (itimer_ticks > itimer_next) + need_resched = 1; + if (next_timer) { + if (next_timer->expires) { + next_timer->expires--; + if (!next_timer->expires) + mark_bh(TIMER_BH); + } else { + lost_ticks++; + mark_bh(TIMER_BH); + } + } + sti(); +} + +asmlinkage int sys_alarm(long seconds) +{ + struct itimerval it_new, it_old; + + it_new.it_interval.tv_sec = it_new.it_interval.tv_usec = 0; + it_new.it_value.tv_sec = seconds; + it_new.it_value.tv_usec = 0; + _setitimer(ITIMER_REAL, &it_new, &it_old); + return(it_old.it_value.tv_sec + (it_old.it_value.tv_usec / 1000000)); +} + +asmlinkage int sys_getpid(void) +{ + return current->pid; +} + +asmlinkage int sys_getppid(void) +{ + return current->p_opptr->pid; +} + +asmlinkage int sys_getuid(void) +{ + return current->uid; +} + +asmlinkage int sys_geteuid(void) +{ + return current->euid; +} + +asmlinkage int sys_getgid(void) +{ + return current->gid; +} + +asmlinkage int sys_getegid(void) +{ + return current->egid; +} + +asmlinkage int sys_nice(long increment) +{ + int newprio; + + if (increment < 0 && !suser()) + return -EPERM; + newprio = current->priority - increment; + if (newprio < 1) + newprio = 1; + if (newprio > 35) + newprio = 35; + current->priority = newprio; + return 0; +} + +static void show_task(int nr,struct task_struct * p) +{ + static char * stat_nam[] = { "R", "S", "D", "Z", "T", "W" }; + + printk("%-8s %3d ", p->comm, (p == current) ? -nr : nr); + if (((unsigned) p->state) < sizeof(stat_nam)/sizeof(char *)) + printk(stat_nam[p->state]); + else + printk(" "); + if (p == current) + printk(" current "); + else + printk(" %08lX ", ((unsigned long *)p->tss.esp)[3]); + printk("%5lu %5d %6d ", + p->tss.esp - p->kernel_stack_page, p->pid, p->p_pptr->pid); + if (p->p_cptr) + printk("%5d ", p->p_cptr->pid); + else + printk(" "); + if (p->p_ysptr) + printk("%7d", p->p_ysptr->pid); + else + printk(" "); + if (p->p_osptr) + printk(" %5d\n", p->p_osptr->pid); + else + printk("\n"); +} + +void show_state(void) +{ + int i; + + printk(" free sibling\n"); + printk(" task PC stack pid father child younger older\n"); + for (i=0 ; ia=p->b=0; + p++; + p->a=p->b=0; + p++; + } +/* Clear NT, so that we won't have troubles with that later on */ + __asm__("pushfl ; andl $0xffffbfff,(%esp) ; popfl"); + load_TR(0); + load_ldt(0); + outb_p(0x34,0x43); /* binary, mode 2, LSB/MSB, ch 0 */ + outb_p(LATCH & 0xff , 0x40); /* LSB */ + outb(LATCH >> 8 , 0x40); /* MSB */ + if (request_irq(TIMER_IRQ,(void (*)(int)) do_timer)!=0) + panic("Could not allocate timer IRQ!"); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/signal.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/signal.c new file mode 100644 index 000000000..a284eea75 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/signal.c @@ -0,0 +1,414 @@ +/* + * linux/kernel/signal.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include + +#include + +#define _S(nr) (1<<((nr)-1)) + +#define _BLOCKABLE (~(_S(SIGKILL) | _S(SIGSTOP))) + +extern int core_dump(long signr,struct pt_regs * regs); + +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs); + +struct sigcontext_struct { + unsigned short gs, __gsh; + unsigned short fs, __fsh; + unsigned short es, __esh; + unsigned short ds, __dsh; + unsigned long edi; + unsigned long esi; + unsigned long ebp; + unsigned long esp; + unsigned long ebx; + unsigned long edx; + unsigned long ecx; + unsigned long eax; + unsigned long trapno; + unsigned long err; + unsigned long eip; + unsigned short cs, __csh; + unsigned long eflags; + unsigned long esp_at_signal; + unsigned short ss, __ssh; + unsigned long i387; + unsigned long oldmask; + unsigned long cr2; +}; + +asmlinkage int sys_sigprocmask(int how, sigset_t *set, sigset_t *oset) +{ + sigset_t new_set, old_set = current->blocked; + int error; + + if (set) { + error = verify_area(VERIFY_READ, set, sizeof(sigset_t)); + if (error) + return error; + new_set = get_fs_long((unsigned long *) set) & _BLOCKABLE; + switch (how) { + case SIG_BLOCK: + current->blocked |= new_set; + break; + case SIG_UNBLOCK: + current->blocked &= ~new_set; + break; + case SIG_SETMASK: + current->blocked = new_set; + break; + default: + return -EINVAL; + } + } + if (oset) { + error = verify_area(VERIFY_WRITE, oset, sizeof(sigset_t)); + if (error) + return error; + put_fs_long(old_set, (unsigned long *) oset); + } + return 0; +} + +asmlinkage int sys_sgetmask(void) +{ + return current->blocked; +} + +asmlinkage int sys_ssetmask(int newmask) +{ + int old=current->blocked; + + current->blocked = newmask & _BLOCKABLE; + return old; +} + +asmlinkage int sys_sigpending(sigset_t *set) +{ + int error; + /* fill in "set" with signals pending but blocked. */ + error = verify_area(VERIFY_WRITE, set, 4); + if (!error) + put_fs_long(current->blocked & current->signal, (unsigned long *)set); + return error; +} + +/* + * atomically swap in the new signal mask, and wait for a signal. + */ +asmlinkage int sys_sigsuspend(int restart, unsigned long oldmask, unsigned long set) +{ + unsigned long mask; + struct pt_regs * regs = (struct pt_regs *) &restart; + + mask = current->blocked; + current->blocked = set & _BLOCKABLE; + regs->eax = -EINTR; + while (1) { + current->state = TASK_INTERRUPTIBLE; + schedule(); + if (do_signal(mask,regs)) + return -EINTR; + } +} + +/* + * POSIX 3.3.1.3: + * "Setting a signal action to SIG_IGN for a signal that is pending + * shall cause the pending signal to be discarded, whether or not + * it is blocked" (but SIGCHLD is unspecified: linux leaves it alone). + * + * "Setting a signal action to SIG_DFL for a signal that is pending + * and whose default action is to ignore the signal (for example, + * SIGCHLD), shall cause the pending signal to be discarded, whether + * or not it is blocked" + * + * Note the silly behaviour of SIGCHLD: SIG_IGN means that the signal + * isn't actually ignored, but does automatic child reaping, while + * SIG_DFL is explicitly said by POSIX to force the signal to be ignored.. + */ +static void check_pending(int signum) +{ + struct sigaction *p; + + p = signum - 1 + current->sigaction; + if (p->sa_handler == SIG_IGN) { + if (signum == SIGCHLD) + return; + current->signal &= ~_S(signum); + return; + } + if (p->sa_handler == SIG_DFL) { + if (signum != SIGCONT && signum != SIGCHLD && signum != SIGWINCH) + return; + current->signal &= ~_S(signum); + return; + } +} + +asmlinkage int sys_signal(int signum, unsigned long handler) +{ + struct sigaction tmp; + + if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + if (handler >= TASK_SIZE) + return -EFAULT; + tmp.sa_handler = (void (*)(int)) handler; + tmp.sa_mask = 0; + tmp.sa_flags = SA_ONESHOT | SA_NOMASK; + tmp.sa_restorer = NULL; + handler = (long) current->sigaction[signum-1].sa_handler; + current->sigaction[signum-1] = tmp; + check_pending(signum); + return handler; +} + +asmlinkage int sys_sigaction(int signum, const struct sigaction * action, + struct sigaction * oldaction) +{ + struct sigaction new_sa, *p; + + if (signum<1 || signum>32 || signum==SIGKILL || signum==SIGSTOP) + return -EINVAL; + p = signum - 1 + current->sigaction; + if (action) { + memcpy_fromfs(&new_sa, action, sizeof(struct sigaction)); + if (new_sa.sa_flags & SA_NOMASK) + new_sa.sa_mask = 0; + else { + new_sa.sa_mask |= _S(signum); + new_sa.sa_mask &= _BLOCKABLE; + } + if (TASK_SIZE <= (unsigned long) new_sa.sa_handler) + return -EFAULT; + } + if (oldaction) { + if (!verify_area(VERIFY_WRITE,oldaction, sizeof(struct sigaction))) + memcpy_tofs(oldaction, p, sizeof(struct sigaction)); + } + if (action) { + *p = new_sa; + check_pending(signum); + } + return 0; +} + +asmlinkage int sys_waitpid(pid_t pid,unsigned long * stat_addr, int options); + +/* + * This sets regs->esp even though we don't actually use sigstacks yet.. + */ +asmlinkage int sys_sigreturn(unsigned long __unused) +{ +#define CHECK_SEG(x) if (x) x |= 3 +#define COPY(x) regs->x = context.x + struct sigcontext_struct context; + struct pt_regs * regs; + + regs = (struct pt_regs *) &__unused; + memcpy_fromfs(&context,(void *) regs->esp, sizeof(context)); + current->blocked = context.oldmask & _BLOCKABLE; + CHECK_SEG(context.ss); + CHECK_SEG(context.cs); + CHECK_SEG(context.ds); + CHECK_SEG(context.es); + CHECK_SEG(context.fs); + CHECK_SEG(context.gs); + COPY(eip); COPY(eflags); + COPY(ecx); COPY(edx); + COPY(ebx); + COPY(esp); COPY(ebp); + COPY(edi); COPY(esi); + COPY(cs); COPY(ss); + COPY(ds); COPY(es); + COPY(fs); COPY(gs); + regs->orig_eax = -1; /* disable syscall checks */ + return context.eax; +} + +/* + * Set up a signal frame... Make the stack look the way iBCS2 expects + * it to look. + */ +static void setup_frame(struct sigaction * sa, unsigned long ** fp, unsigned long eip, + struct pt_regs * regs, int signr, unsigned long oldmask) +{ + unsigned long * frame; + +#define __CODE ((unsigned long)(frame+24)) +#define CODE(x) ((unsigned long *) ((x)+__CODE)) + frame = *fp; + if (regs->ss != USER_DS) + frame = (unsigned long *) sa->sa_restorer; + frame -= 32; + if (verify_area(VERIFY_WRITE,frame,32*4)) + do_exit(SIGSEGV); +/* set up the "normal" stack seen by the signal handler (iBCS2) */ + put_fs_long(__CODE,frame); + put_fs_long(signr, frame+1); + put_fs_long(regs->gs, frame+2); + put_fs_long(regs->fs, frame+3); + put_fs_long(regs->es, frame+4); + put_fs_long(regs->ds, frame+5); + put_fs_long(regs->edi, frame+6); + put_fs_long(regs->esi, frame+7); + put_fs_long(regs->ebp, frame+8); + put_fs_long((long)*fp, frame+9); + put_fs_long(regs->ebx, frame+10); + put_fs_long(regs->edx, frame+11); + put_fs_long(regs->ecx, frame+12); + put_fs_long(regs->eax, frame+13); + put_fs_long(current->tss.trap_no, frame+14); + put_fs_long(current->tss.error_code, frame+15); + put_fs_long(eip, frame+16); + put_fs_long(regs->cs, frame+17); + put_fs_long(regs->eflags, frame+18); + put_fs_long(regs->esp, frame+19); + put_fs_long(regs->ss, frame+20); + put_fs_long(0,frame+21); /* 387 state pointer - not implemented*/ +/* non-iBCS2 extensions.. */ + put_fs_long(oldmask, frame+22); + put_fs_long(current->tss.cr2, frame+23); +/* set up the return code... */ + put_fs_long(0x0000b858, CODE(0)); /* popl %eax ; movl $,%eax */ + put_fs_long(0x80cd0000, CODE(4)); /* int $0x80 */ + put_fs_long(__NR_sigreturn, CODE(2)); + *fp = frame; +#undef __CODE +#undef CODE +} + +/* + * Note that 'init' is a special process: it doesn't get signals it doesn't + * want to handle. Thus you cannot kill init even with a SIGKILL even by + * mistake. + * + * Note that we go through the signals twice: once to check the signals that + * the kernel can handle, and then we build all the user-level signal handling + * stack-frames in one go after that. + */ +asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) +{ + unsigned long mask = ~current->blocked; + unsigned long handler_signal = 0; + unsigned long *frame = NULL; + unsigned long eip = 0; + unsigned long signr; + struct sigaction * sa; + + while ((signr = current->signal & mask)) { + __asm__("bsf %2,%1\n\t" + "btrl %1,%0" + :"=m" (current->signal),"=r" (signr) + :"1" (signr)); + sa = current->sigaction + signr; + signr++; + if ((current->flags & PF_PTRACED) && signr != SIGKILL) { + current->exit_code = signr; + current->state = TASK_STOPPED; + notify_parent(current); + schedule(); + if (!(signr = current->exit_code)) + continue; + current->exit_code = 0; + if (signr == SIGSTOP) + continue; + if (_S(signr) & current->blocked) { + current->signal |= _S(signr); + continue; + } + sa = current->sigaction + signr - 1; + } + if (sa->sa_handler == SIG_IGN) { + if (signr != SIGCHLD) + continue; + /* check for SIGCHLD: it's special */ + while (sys_waitpid(-1,NULL,WNOHANG) > 0) + /* nothing */; + continue; + } + if (sa->sa_handler == SIG_DFL) { + if (current->pid == 1) + continue; + switch (signr) { + case SIGCONT: case SIGCHLD: case SIGWINCH: + continue; + + case SIGSTOP: case SIGTSTP: case SIGTTIN: case SIGTTOU: + if (current->flags & PF_PTRACED) + continue; + current->state = TASK_STOPPED; + current->exit_code = signr; + if (!(current->p_pptr->sigaction[SIGCHLD-1].sa_flags & + SA_NOCLDSTOP)) + notify_parent(current); + schedule(); + continue; + + case SIGQUIT: case SIGILL: case SIGTRAP: + case SIGIOT: case SIGFPE: case SIGSEGV: + if (core_dump(signr,regs)) + signr |= 0x80; + /* fall through */ + default: + current->signal |= _S(signr & 0x7f); + do_exit(signr); + } + } + /* + * OK, we're invoking a handler + */ + if (regs->orig_eax >= 0) { + if (regs->eax == -ERESTARTNOHAND || + (regs->eax == -ERESTARTSYS && !(sa->sa_flags & SA_RESTART))) + regs->eax = -EINTR; + } + handler_signal |= 1 << (signr-1); + mask &= ~sa->sa_mask; + } + if (regs->orig_eax >= 0 && + (regs->eax == -ERESTARTNOHAND || + regs->eax == -ERESTARTSYS || + regs->eax == -ERESTARTNOINTR)) { + regs->eax = regs->orig_eax; + regs->eip -= 2; + } + if (!handler_signal) /* no handler will be called - return 0 */ + return 0; + eip = regs->eip; + frame = (unsigned long *) regs->esp; + signr = 1; + sa = current->sigaction; + for (mask = 1 ; mask ; sa++,signr++,mask += mask) { + if (mask > handler_signal) + break; + if (!(mask & handler_signal)) + continue; + setup_frame(sa,&frame,eip,regs,signr,oldmask); + eip = (unsigned long) sa->sa_handler; + if (sa->sa_flags & SA_ONESHOT) + sa->sa_handler = NULL; +/* force a supervisor-mode page-in of the signal handler to reduce races */ + __asm__("testb $0,%%fs:%0": :"m" (*(char *) eip)); + regs->cs = USER_CS; regs->ss = USER_DS; + regs->ds = USER_DS; regs->es = USER_DS; + regs->gs = USER_DS; regs->fs = USER_DS; + current->blocked |= sa->sa_mask; + oldmask |= sa->sa_mask; + } + regs->esp = (unsigned long) frame; + regs->eip = eip; /* "return" to the first handler */ + current->tss.trap_no = current->tss.error_code = 0; + return 1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys.c new file mode 100644 index 000000000..a15839320 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys.c @@ -0,0 +1,766 @@ +/* + * linux/kernel/sys.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +/* + * this indicates wether you can reboot with ctrl-alt-del: the default is yes + */ +static int C_A_D = 1; + +extern void adjust_clock(void); + +#define PZERO 15 + +static int proc_sel(struct task_struct *p, int which, int who) +{ + switch (which) { + case PRIO_PROCESS: + if (!who && p == current) + return 1; + return(p->pid == who); + case PRIO_PGRP: + if (!who) + who = current->pgrp; + return(p->pgrp == who); + case PRIO_USER: + if (!who) + who = current->uid; + return(p->uid == who); + } + return 0; +} + +asmlinkage int sys_setpriority(int which, int who, int niceval) +{ + struct task_struct **p; + int error = ESRCH; + int priority; + + if (which > 2 || which < 0) + return -EINVAL; + + if ((priority = PZERO - niceval) <= 0) + priority = 1; + + for(p = &LAST_TASK; p > &FIRST_TASK; --p) { + if (!*p || !proc_sel(*p, which, who)) + continue; + if ((*p)->uid != current->euid && + (*p)->uid != current->uid && !suser()) { + error = EPERM; + continue; + } + if (error == ESRCH) + error = 0; + if (priority > (*p)->priority && !suser()) + error = EACCES; + else + (*p)->priority = priority; + } + return -error; +} + +asmlinkage int sys_getpriority(int which, int who) +{ + struct task_struct **p; + int max_prio = 0; + + if (which > 2 || which < 0) + return -EINVAL; + + for(p = &LAST_TASK; p > &FIRST_TASK; --p) { + if (!*p || !proc_sel(*p, which, who)) + continue; + if ((*p)->priority > max_prio) + max_prio = (*p)->priority; + } + return(max_prio ? max_prio : -ESRCH); +} + +asmlinkage int sys_profil(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_ftime(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_break(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_stty(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_gtty(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_prof(void) +{ + return -ENOSYS; +} + +asmlinkage unsigned long save_v86_state(struct vm86_regs * regs) +{ + unsigned long stack; + + if (!current->vm86_info) { + printk("no vm86_info: BAD\n"); + do_exit(SIGSEGV); + } + memcpy_tofs(&(current->vm86_info->regs),regs,sizeof(*regs)); + put_fs_long(current->screen_bitmap,&(current->vm86_info->screen_bitmap)); + stack = current->tss.esp0; + current->tss.esp0 = current->saved_kernel_stack; + current->saved_kernel_stack = 0; + return stack; +} + +static void mark_screen_rdonly(struct task_struct * tsk) +{ + unsigned long tmp; + unsigned long *pg_table; + + if ((tmp = tsk->tss.cr3) != 0) { + tmp = *(unsigned long *) tmp; + if (tmp & PAGE_PRESENT) { + tmp &= PAGE_MASK; + pg_table = (0xA0000 >> PAGE_SHIFT) + (unsigned long *) tmp; + tmp = 32; + while (tmp--) { + if (PAGE_PRESENT & *pg_table) + *pg_table &= ~PAGE_RW; + pg_table++; + } + } + } +} + +asmlinkage int sys_vm86(struct vm86_struct * v86) +{ + struct vm86_struct info; + struct pt_regs * pt_regs = (struct pt_regs *) &v86; + + if (current->saved_kernel_stack) + return -EPERM; + memcpy_fromfs(&info,v86,sizeof(info)); +/* + * make sure the vm86() system call doesn't try to do anything silly + */ + info.regs.__null_ds = 0; + info.regs.__null_es = 0; + info.regs.__null_fs = 0; + info.regs.__null_gs = 0; +/* + * The eflags register is also special: we cannot trust that the user + * has set it up safely, so this makes sure interrupt etc flags are + * inherited from protected mode. + */ + info.regs.eflags &= 0x00000dd5; + info.regs.eflags |= ~0x00000dd5 & pt_regs->eflags; + info.regs.eflags |= VM_MASK; + current->saved_kernel_stack = current->tss.esp0; + current->tss.esp0 = (unsigned long) pt_regs; + current->vm86_info = v86; + current->screen_bitmap = info.screen_bitmap; + if (info.flags & VM86_SCREEN_BITMAP) + mark_screen_rdonly(current); + __asm__ __volatile__("movl %0,%%esp\n\t" + "pushl $ret_from_sys_call\n\t" + "ret" + : /* no outputs */ + :"g" ((long) &(info.regs)),"a" (info.regs.eax)); + return 0; +} + +extern void hard_reset_now(void); + +/* + * Reboot system call: for obvious reasons only root may call it, + * and even root needs to set up some magic numbers in the registers + * so that some mistake won't make this reboot the whole machine. + * You can also set the meaning of the ctrl-alt-del-key here. + * + * reboot doesn't sync: do that yourself before calling this. + */ +asmlinkage int sys_reboot(int magic, int magic_too, int flag) +{ + if (!suser()) + return -EPERM; + if (magic != 0xfee1dead || magic_too != 672274793) + return -EINVAL; + if (flag == 0x01234567) + hard_reset_now(); + else if (flag == 0x89ABCDEF) + C_A_D = 1; + else if (!flag) + C_A_D = 0; + else + return -EINVAL; + return (0); +} + +/* + * This function gets called by ctrl-alt-del - ie the keyboard interrupt. + * As it's called within an interrupt, it may NOT sync: the only choice + * is wether to reboot at once, or just ignore the ctrl-alt-del. + */ +void ctrl_alt_del(void) +{ + if (C_A_D) + hard_reset_now(); + else + send_sig(SIGINT,task[1],1); +} + + +/* + * This is done BSD-style, with no consideration of the saved gid, except + * that if you set the effective gid, it sets the saved gid too. This + * makes it possible for a setgid program to completely drop its privileges, + * which is often a useful assertion to make when you are doing a security + * audit over a program. + * + * The general idea is that a program which uses just setregid() will be + * 100% compatible with BSD. A program which uses just setgid() will be + * 100% compatible with POSIX w/ Saved ID's. + */ +asmlinkage int sys_setregid(gid_t rgid, gid_t egid) +{ + int old_rgid = current->gid; + + if (rgid != (gid_t) -1) { + if ((current->egid==rgid) || + (old_rgid == rgid) || + suser()) + current->gid = rgid; + else + return(-EPERM); + } + if (egid != (gid_t) -1) { + if ((old_rgid == egid) || + (current->egid == egid) || + suser()) { + current->egid = egid; + current->sgid = egid; + } else { + current->gid = old_rgid; + return(-EPERM); + } + } + return 0; +} + +/* + * setgid() is implemeneted like SysV w/ SAVED_IDS + */ +asmlinkage int sys_setgid(gid_t gid) +{ + if (suser()) + current->gid = current->egid = current->sgid = gid; + else if ((gid == current->gid) || (gid == current->sgid)) + current->egid = gid; + else + return -EPERM; + return 0; +} + +asmlinkage int sys_acct(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_phys(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_lock(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_mpx(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_ulimit(void) +{ + return -ENOSYS; +} + +asmlinkage int sys_old_syscall(void) +{ + return -ENOSYS; +} + +/* + * Unprivileged users may change the real user id to the effective uid + * or vice versa. (BSD-style) + * + * When you set the effective uid, it sets the saved uid too. This + * makes it possible for a setuid program to completely drop its privileges, + * which is often a useful assertion to make when you are doing a security + * audit over a program. + * + * The general idea is that a program which uses just setreuid() will be + * 100% compatible with BSD. A program which uses just setuid() will be + * 100% compatible with POSIX w/ Saved ID's. + */ +asmlinkage int sys_setreuid(uid_t ruid, uid_t euid) +{ + int old_ruid = current->uid; + + if (ruid != (uid_t) -1) { + if ((current->euid==ruid) || + (old_ruid == ruid) || + suser()) + current->uid = ruid; + else + return(-EPERM); + } + if (euid != (uid_t) -1) { + if ((old_ruid == euid) || + (current->euid == euid) || + suser()) { + current->euid = euid; + current->suid = euid; + } else { + current->uid = old_ruid; + return(-EPERM); + } + } + return 0; +} + +/* + * setuid() is implemeneted like SysV w/ SAVED_IDS + * + * Note that SAVED_ID's is deficient in that a setuid root program + * like sendmail, for example, cannot set its uid to be a normal + * user and then switch back, because if you're root, setuid() sets + * the saved uid too. If you don't like this, blame the bright people + * in the POSIX commmittee and/or USG. Note that the BSD-style setreuid() + * will allow a root program to temporarily drop privileges and be able to + * regain them by swapping the real and effective uid. + */ +asmlinkage int sys_setuid(uid_t uid) +{ + if (suser()) + current->uid = current->euid = current->suid = uid; + else if ((uid == current->uid) || (uid == current->suid)) + current->euid = uid; + else + return -EPERM; + return(0); +} + +asmlinkage int sys_times(struct tms * tbuf) +{ + if (tbuf) { + int error = verify_area(VERIFY_WRITE,tbuf,sizeof *tbuf); + if (error) + return error; + put_fs_long(current->utime,(unsigned long *)&tbuf->tms_utime); + put_fs_long(current->stime,(unsigned long *)&tbuf->tms_stime); + put_fs_long(current->cutime,(unsigned long *)&tbuf->tms_cutime); + put_fs_long(current->cstime,(unsigned long *)&tbuf->tms_cstime); + } + return jiffies; +} + +asmlinkage int sys_brk(unsigned long brk) +{ + int freepages; + unsigned long rlim; + unsigned long newbrk, oldbrk; + + if (brk < current->end_code) + 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; + do_munmap(newbrk, oldbrk-newbrk); + return brk; + } + /* + * Check against rlimit and stack.. + */ + rlim = current->rlim[RLIMIT_DATA].rlim_cur; + if (rlim >= RLIM_INFINITY) + rlim = ~0; + if (brk - current->end_code > rlim || brk >= current->start_stack - 16384) + return current->brk; + /* + * stupid algorithm to decide if we have enough memory: while + * simple, it hopefully works in most obvious cases.. Easy to + * fool it, but this should catch most mistakes. + */ + freepages = buffermem >> 12; + freepages += nr_free_pages; + freepages += nr_swap_pages; + freepages -= (high_memory - 0x100000) >> 16; + freepages -= (newbrk-oldbrk) >> 12; + if (freepages < 0) + return current->brk; +#if 0 + freepages += current->rss; + freepages -= oldbrk >> 12; + if (freepages < 0) + return current->brk; +#endif + /* + * Ok, we have probably got enough memory - let it rip. + */ + current->brk = brk; + do_mmap(NULL, oldbrk, newbrk-oldbrk, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + return brk; +} + +/* + * This needs some heave checking ... + * I just haven't get the stomach for it. I also don't fully + * understand sessions/pgrp etc. Let somebody who does explain it. + * + * OK, I think I have the protection semantics right.... this is really + * only important on a multi-user system anyway, to make sure one user + * can't send a signal to a process owned by another. -TYT, 12/12/91 + */ +asmlinkage int sys_setpgid(pid_t pid, pid_t pgid) +{ + int i; + + if (!pid) + pid = current->pid; + if (!pgid) + pgid = current->pid; + if (pgid < 0) + return -EINVAL; + for (i=0 ; ipid == pid) && + ((task[i]->p_pptr == current) || + (task[i]->p_opptr == current) || + (task[i] == current))) { + if (task[i]->leader) + return -EPERM; + if ((task[i]->session != current->session) || + ((pgid != pid) && + (session_of_pgrp(pgid) != current->session))) + return -EPERM; + task[i]->pgrp = pgid; + return 0; + } + return -ESRCH; +} + +asmlinkage int sys_getpgid(pid_t pid) +{ + struct task_struct * p; + + if (!pid) + return current->pgrp; + for_each_task(p) { + if (p->pid == pid) + return p->pgrp; + } + return -ESRCH; +} + +asmlinkage int sys_getpgrp(void) +{ + return current->pgrp; +} + +asmlinkage int sys_setsid(void) +{ + if (current->leader) + return -EPERM; + current->leader = 1; + current->session = current->pgrp = current->pid; + current->tty = -1; + return current->pgrp; +} + +/* + * Supplementary group ID's + */ +asmlinkage int sys_getgroups(int gidsetsize, gid_t *grouplist) +{ + int i; + + if (gidsetsize) { + i = verify_area(VERIFY_WRITE, grouplist, sizeof(gid_t) * gidsetsize); + if (i) + return i; + } + for (i = 0 ; (i < NGROUPS) && (current->groups[i] != NOGROUP) ; i++) { + if (!gidsetsize) + continue; + if (i >= gidsetsize) + break; + put_fs_word(current->groups[i], (short *) grouplist); + grouplist++; + } + return(i); +} + +asmlinkage int sys_setgroups(int gidsetsize, gid_t *grouplist) +{ + int i; + + if (!suser()) + return -EPERM; + if (gidsetsize > NGROUPS) + return -EINVAL; + for (i = 0; i < gidsetsize; i++, grouplist++) { + current->groups[i] = get_fs_word((unsigned short *) grouplist); + } + if (i < NGROUPS) + current->groups[i] = NOGROUP; + return 0; +} + +int in_group_p(gid_t grp) +{ + int i; + + if (grp == current->egid) + return 1; + + for (i = 0; i < NGROUPS; i++) { + if (current->groups[i] == NOGROUP) + break; + if (current->groups[i] == grp) + return 1; + } + return 0; +} + +asmlinkage int sys_newuname(struct new_utsname * name) +{ + int error; + + if (!name) + return -EFAULT; + error = verify_area(VERIFY_WRITE, name, sizeof *name); + if (!error) + memcpy_tofs(name,&system_utsname,sizeof *name); + return error; +} + +asmlinkage int sys_uname(struct old_utsname * name) +{ + int error; + if (!name) + return -EFAULT; + error = verify_area(VERIFY_WRITE, name,sizeof *name); + if (error) + return error; + memcpy_tofs(&name->sysname,&system_utsname.sysname, + sizeof (system_utsname.sysname)); + memcpy_tofs(&name->nodename,&system_utsname.nodename, + sizeof (system_utsname.nodename)); + memcpy_tofs(&name->release,&system_utsname.release, + sizeof (system_utsname.release)); + memcpy_tofs(&name->version,&system_utsname.version, + sizeof (system_utsname.version)); + memcpy_tofs(&name->machine,&system_utsname.machine, + sizeof (system_utsname.machine)); + return 0; +} + +asmlinkage int sys_olduname(struct oldold_utsname * name) +{ + int error; + if (!name) + return -EFAULT; + error = verify_area(VERIFY_WRITE, name,sizeof *name); + if (error) + return error; + memcpy_tofs(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + put_fs_byte(0,name->sysname+__OLD_UTS_LEN); + memcpy_tofs(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + put_fs_byte(0,name->nodename+__OLD_UTS_LEN); + memcpy_tofs(&name->release,&system_utsname.release,__OLD_UTS_LEN); + put_fs_byte(0,name->release+__OLD_UTS_LEN); + memcpy_tofs(&name->version,&system_utsname.version,__OLD_UTS_LEN); + put_fs_byte(0,name->version+__OLD_UTS_LEN); + memcpy_tofs(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + put_fs_byte(0,name->machine+__OLD_UTS_LEN); + return 0; +} + +/* + * Only sethostname; gethostname can be implemented by calling uname() + */ +asmlinkage int sys_sethostname(char *name, int len) +{ + int i; + + if (!suser()) + return -EPERM; + if (len > __NEW_UTS_LEN) + return -EINVAL; + for (i=0; i < len; i++) { + if ((system_utsname.nodename[i] = get_fs_byte(name+i)) == 0) + return 0; + } + system_utsname.nodename[i] = 0; + return 0; +} + +/* + * Only setdomainname; getdomainname can be implemented by calling + * uname() + */ +asmlinkage int sys_setdomainname(char *name, int len) +{ + int i; + + if (!suser()) + return -EPERM; + if (len > __NEW_UTS_LEN) + return -EINVAL; + for (i=0; i < len; i++) { + if ((system_utsname.domainname[i] = get_fs_byte(name+i)) == 0) + return 0; + } + system_utsname.domainname[i] = 0; + return 0; +} + +asmlinkage int sys_getrlimit(unsigned int resource, struct rlimit *rlim) +{ + int error; + + if (resource >= RLIM_NLIMITS) + return -EINVAL; + error = verify_area(VERIFY_WRITE,rlim,sizeof *rlim); + if (error) + return error; + put_fs_long(current->rlim[resource].rlim_cur, + (unsigned long *) rlim); + put_fs_long(current->rlim[resource].rlim_max, + ((unsigned long *) rlim)+1); + return 0; +} + +asmlinkage int sys_setrlimit(unsigned int resource, struct rlimit *rlim) +{ + struct rlimit new_rlim, *old_rlim; + + if (resource >= RLIM_NLIMITS) + return -EINVAL; + old_rlim = current->rlim + resource; + new_rlim.rlim_cur = get_fs_long((unsigned long *) rlim); + new_rlim.rlim_max = get_fs_long(((unsigned long *) rlim)+1); + if (((new_rlim.rlim_cur > old_rlim->rlim_max) || + (new_rlim.rlim_max > old_rlim->rlim_max)) && + !suser()) + return -EPERM; + *old_rlim = new_rlim; + return 0; +} + +/* + * It would make sense to put struct rusuage in the task_struct, + * except that would make the task_struct be *really big*. After + * task_struct gets moved into malloc'ed memory, it would + * make sense to do this. It will make moving the rest of the information + * a lot simpler! (Which we're not doing right now because we're not + * measuring them yet). + */ +int getrusage(struct task_struct *p, int who, struct rusage *ru) +{ + int error; + struct rusage r; + unsigned long *lp, *lpend, *dest; + + error = verify_area(VERIFY_WRITE, ru, sizeof *ru); + if (error) + return error; + memset((char *) &r, 0, sizeof(r)); + switch (who) { + case RUSAGE_SELF: + r.ru_utime.tv_sec = CT_TO_SECS(p->utime); + r.ru_utime.tv_usec = CT_TO_USECS(p->utime); + r.ru_stime.tv_sec = CT_TO_SECS(p->stime); + r.ru_stime.tv_usec = CT_TO_USECS(p->stime); + r.ru_minflt = p->min_flt; + r.ru_majflt = p->maj_flt; + break; + case RUSAGE_CHILDREN: + r.ru_utime.tv_sec = CT_TO_SECS(p->cutime); + r.ru_utime.tv_usec = CT_TO_USECS(p->cutime); + r.ru_stime.tv_sec = CT_TO_SECS(p->cstime); + r.ru_stime.tv_usec = CT_TO_USECS(p->cstime); + r.ru_minflt = p->cmin_flt; + r.ru_majflt = p->cmaj_flt; + break; + default: + r.ru_utime.tv_sec = CT_TO_SECS(p->utime + p->cutime); + r.ru_utime.tv_usec = CT_TO_USECS(p->utime + p->cutime); + r.ru_stime.tv_sec = CT_TO_SECS(p->stime + p->cstime); + r.ru_stime.tv_usec = CT_TO_USECS(p->stime + p->cstime); + r.ru_minflt = p->min_flt + p->cmin_flt; + r.ru_majflt = p->maj_flt + p->cmaj_flt; + break; + } + lp = (unsigned long *) &r; + lpend = (unsigned long *) (&r+1); + dest = (unsigned long *) ru; + for (; lp < lpend; lp++, dest++) + put_fs_long(*lp, dest); + return 0; +} + +asmlinkage int sys_getrusage(int who, struct rusage *ru) +{ + if (who != RUSAGE_SELF && who != RUSAGE_CHILDREN) + return -EINVAL; + return getrusage(current, who, ru); +} + +asmlinkage int sys_umask(int mask) +{ + int old = current->umask; + + current->umask = mask & S_IRWXUGO; + return (old); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys_call.S b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys_call.S new file mode 100644 index 000000000..b4d83738b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/sys_call.S @@ -0,0 +1,390 @@ +/* + * linux/kernel/sys_call.S + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * sys_call.S contains the system-call and fault low-level handling routines. + * This also contains the timer-interrupt handler, as well as all interrupts + * and faults that can result in a task-switch. + * + * NOTE: This code handles signal-recognition, which happens every time + * after a timer-interrupt and after each system call. + * + * I changed all the .align's to 4 (16 byte alignment), as that's faster + * on a 486. + * + * Stack layout in 'ret_from_system_call': + * ptrace needs to have all regs on the stack. + * if the order here is changed, it needs to be + * updated in fork.c:copy_process, signal.c:do_signal, + * ptrace.c and ptrace.h + * + * 0(%esp) - %ebx + * 4(%esp) - %ecx + * 8(%esp) - %edx + * C(%esp) - %esi + * 10(%esp) - %edi + * 14(%esp) - %ebp + * 18(%esp) - %eax + * 1C(%esp) - %ds + * 20(%esp) - %es + * 24(%esp) - %fs + * 28(%esp) - %gs + * 2C(%esp) - orig_eax + * 30(%esp) - %eip + * 34(%esp) - %cs + * 38(%esp) - %eflags + * 3C(%esp) - %oldesp + * 40(%esp) - %oldss + */ + +#include + +EBX = 0x00 +ECX = 0x04 +EDX = 0x08 +ESI = 0x0C +EDI = 0x10 +EBP = 0x14 +EAX = 0x18 +DS = 0x1C +ES = 0x20 +FS = 0x24 +GS = 0x28 +ORIG_EAX = 0x2C +EIP = 0x30 +CS = 0x34 +EFLAGS = 0x38 +OLDESP = 0x3C +OLDSS = 0x40 + +CF_MASK = 0x00000001 +IF_MASK = 0x00000200 +NT_MASK = 0x00004000 +VM_MASK = 0x00020000 + +/* + * these are offsets into the task-struct. + */ +state = 0 +counter = 4 +priority = 8 +signal = 12 +blocked = 16 +flags = 20 +errno = 24 +dbgreg6 = 52 +dbgreg7 = 56 + +ENOSYS = 38 + +.globl _system_call,_lcall7 +.globl _device_not_available, _coprocessor_error +.globl _divide_error,_debug,_nmi,_int3,_overflow,_bounds,_invalid_op +.globl _double_fault,_coprocessor_segment_overrun +.globl _invalid_TSS,_segment_not_present,_stack_segment +.globl _general_protection,_reserved +.globl _alignment_check,_page_fault +.globl ret_from_sys_call + +#define SAVE_ALL \ + cld; \ + push %gs; \ + push %fs; \ + push %es; \ + push %ds; \ + pushl %eax; \ + pushl %ebp; \ + pushl %edi; \ + pushl %esi; \ + pushl %edx; \ + pushl %ecx; \ + pushl %ebx; \ + movl $(KERNEL_DS),%edx; \ + mov %dx,%ds; \ + mov %dx,%es; \ + movl $(USER_DS),%edx; \ + mov %dx,%fs; + +#define RESTORE_ALL \ + 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; \ + popl %edi; \ + popl %ebp; \ + popl %eax; \ + pop %ds; \ + pop %es; \ + pop %fs; \ + pop %gs; \ + addl $4,%esp; \ + iret + +.align 4 +_lcall7: + pushfl # We get a different stack layout with call gates, + pushl %eax # which has to be cleaned up later.. + SAVE_ALL + movl EIP(%esp),%eax # due to call gates, this is eflags, not eip.. + movl CS(%esp),%edx # this is eip.. + movl EFLAGS(%esp),%ecx # and this is cs.. + movl %eax,EFLAGS(%esp) # + movl %edx,EIP(%esp) # Now we move them to their "normal" places + movl %ecx,CS(%esp) # + movl %esp,%eax + pushl %eax + call _iABI_emulate + popl %eax + jmp ret_from_sys_call + +.align 4 +handle_bottom_half: + pushfl + incl _intr_count + sti + call _do_bottom_half + popfl + decl _intr_count + jmp 9f +.align 4 +reschedule: + pushl $ret_from_sys_call + jmp _schedule +.align 4 +_system_call: + pushl %eax # save orig_eax + SAVE_ALL + movl $-ENOSYS,EAX(%esp) + cmpl _NR_syscalls,%eax + jae ret_from_sys_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) + movl %eax,EAX(%esp) # save the return value + movl errno(%ebx),%edx + negl %edx + je ret_from_sys_call + movl %edx,EAX(%esp) + orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error + jmp ret_from_sys_call +.align 4 +1: call _syscall_trace + movl ORIG_EAX(%esp),%eax + call _sys_call_table(,%eax,4) + movl %eax,EAX(%esp) # save the return value + movl _current,%eax + movl errno(%eax),%edx + negl %edx + je 1f + movl %edx,EAX(%esp) + orl $(CF_MASK),EFLAGS(%esp) # set carry to indicate error +1: call _syscall_trace + + .align 4,0x90 +ret_from_sys_call: + cmpl $0,_intr_count + jne 2f + movl _bh_mask,%eax + andl _bh_active,%eax + jne handle_bottom_half +9: movl EFLAGS(%esp),%eax # check VM86 flag: CS/SS are + testl $(VM_MASK),%eax # different then + jne 1f + cmpw $(KERNEL_CS),CS(%esp) # was old code segment supervisor ? + je 2f +1: sti + orl $(IF_MASK),%eax # these just try to make sure + andl $~NT_MASK,%eax # the program doesn't do anything + movl %eax,EFLAGS(%esp) # stupid + cmpl $0,_need_resched + jne reschedule + movl _current,%eax + cmpl _task,%eax # task[0] cannot have signals + je 2f + cmpl $0,state(%eax) # state + jne reschedule + cmpl $0,counter(%eax) # counter + je reschedule + movl blocked(%eax),%ecx + movl %ecx,%ebx # save blocked in %ebx for signal handling + notl %ecx + andl signal(%eax),%ecx + jne signal_return +2: RESTORE_ALL +.align 4 +signal_return: + movl %esp,%ecx + pushl %ecx + testl $(VM_MASK),EFLAGS(%ecx) + jne v86_signal_return + pushl %ebx + call _do_signal + popl %ebx + popl %ebx + RESTORE_ALL +.align 4 +v86_signal_return: + call _save_v86_state + movl %eax,%esp + pushl %eax + pushl %ebx + call _do_signal + popl %ebx + popl %ebx + RESTORE_ALL + +.align 4 +_divide_error: + pushl $0 # no error code + pushl $_do_divide_error +.align 4,0x90 +error_code: + push %fs + push %es + push %ds + pushl %eax + pushl %ebp + pushl %edi + pushl %esi + 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. ) + xorl %ebx,%ebx # zero ebx + mov %gs,%bx # get the lower order bits of gs + xchgl %ebx, GS(%esp) # get the address and save gs. + pushl %eax # push the error code + lea 4(%esp),%edx + pushl %edx + movl $(KERNEL_DS),%edx + mov %dx,%ds + 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 + +.align 4 +_coprocessor_error: + pushl $0 + pushl $_do_coprocessor_error + jmp error_code + +.align 4 +_device_not_available: + pushl $-1 # mark this as an int + SAVE_ALL + pushl $ret_from_sys_call + movl %cr0,%eax + testl $0x4,%eax # EM (math emulation bit) + je _math_state_restore + pushl $0 # temporary storage for ORIG_EIP + call _math_emulate + addl $4,%esp + ret + +.align 4 +_debug: + pushl $0 + pushl $_do_debug + jmp error_code + +.align 4 +_nmi: + pushl $0 + pushl $_do_nmi + jmp error_code + +.align 4 +_int3: + pushl $0 + pushl $_do_int3 + jmp error_code + +.align 4 +_overflow: + pushl $0 + pushl $_do_overflow + jmp error_code + +.align 4 +_bounds: + pushl $0 + pushl $_do_bounds + jmp error_code + +.align 4 +_invalid_op: + pushl $0 + pushl $_do_invalid_op + jmp error_code + +.align 4 +_coprocessor_segment_overrun: + pushl $0 + pushl $_do_coprocessor_segment_overrun + jmp error_code + +.align 4 +_reserved: + pushl $0 + pushl $_do_reserved + jmp error_code + +.align 4 +_double_fault: + pushl $_do_double_fault + jmp error_code + +.align 4 +_invalid_TSS: + pushl $_do_invalid_TSS + jmp error_code + +.align 4 +_segment_not_present: + pushl $_do_segment_not_present + jmp error_code + +.align 4 +_stack_segment: + pushl $_do_stack_segment + jmp error_code + +.align 4 +_general_protection: + pushl $_do_general_protection + jmp error_code + +.align 4 +_alignment_check: + pushl $_do_alignment_check + jmp error_code + +.align 4 +_page_fault: + pushl $_do_page_fault + jmp error_code diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/time.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/time.c new file mode 100644 index 000000000..3161e8f90 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/time.c @@ -0,0 +1,442 @@ +/* + * 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 +#include +#include +#include +#include +#include + +#include +#include + +#include +#define RTC_ALWAYS_BCD 1 + +#include +extern struct timeval xtime; + +#include +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; + + /* if the quartz is off by more than 10% something is VERY wrong ! */ + if (txc.mode & ADJ_TICK) + if (txc.tick < 900000/HZ || txc.tick > 1100000/HZ) + 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 << (SHIFT_KF - 16); + + 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) + if (txc.mode == ADJ_OFFSET_SINGLESHOT) + { + time_adjust = txc.offset; + } + else /* XXX should give an error if other bits set */ + { + 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; + } + if (txc.mode & ADJ_TICK) + tick = txc.tick; + + } + txc.offset = save_adjust; + txc.frequency = ((time_freq+1) >> (SHIFT_KF - 16)); + 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; + txc.tick = tick; + + 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/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/traps.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/traps.c new file mode 100644 index 000000000..7321836e3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/traps.c @@ -0,0 +1,211 @@ +/* + * linux/kernel/traps.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. Currently mostly a debugging-aid, will be extended + * to mainly kill the offending process (probably by giving it a signal, + * but possibly by killing it outright if necessary). + */ +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static inline void console_verbose(void) +{ + extern int console_loglevel; + console_loglevel = 15; +} + +#define DO_ERROR(trapnr, signr, str, name, tsk) \ +asmlinkage void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + tsk->tss.error_code = error_code; \ + tsk->tss.trap_no = trapnr; \ + if (signr == SIGTRAP && current->flags & PF_PTRACED) \ + current->blocked &= ~(1 << (SIGTRAP-1)); \ + send_sig(signr, tsk, 1); \ + die_if_kernel(str,regs,error_code); \ +} + +#define get_seg_byte(seg,addr) ({ \ +register char __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movb %%fs:%2,%%al;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define get_seg_long(seg,addr) ({ \ +register unsigned long __res; \ +__asm__("push %%fs;mov %%ax,%%fs;movl %%fs:%2,%%eax;pop %%fs" \ + :"=a" (__res):"0" (seg),"m" (*(addr))); \ +__res;}) + +#define _fs() ({ \ +register unsigned short __res; \ +__asm__("mov %%fs,%%ax":"=a" (__res):); \ +__res;}) + +void page_exception(void); + +asmlinkage void divide_error(void); +asmlinkage void debug(void); +asmlinkage void nmi(void); +asmlinkage void int3(void); +asmlinkage void overflow(void); +asmlinkage void bounds(void); +asmlinkage void invalid_op(void); +asmlinkage void device_not_available(void); +asmlinkage void double_fault(void); +asmlinkage void coprocessor_segment_overrun(void); +asmlinkage void invalid_TSS(void); +asmlinkage void segment_not_present(void); +asmlinkage void stack_segment(void); +asmlinkage void general_protection(void); +asmlinkage void page_fault(void); +asmlinkage void coprocessor_error(void); +asmlinkage void reserved(void); +asmlinkage void alignment_check(void); + +/*static*/ void die_if_kernel(char * str, struct pt_regs * regs, long err) +{ + int i; + + if ((regs->eflags & VM_MASK) || (3 & regs->cs) == 3) + return; + + console_verbose(); + printk("%s: %04lx\n", str, err & 0xffff); + printk("EIP: %04x:%08lx\nEFLAGS: %08lx\n", 0xffff & regs->cs,regs->eip,regs->eflags); + printk("eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk("esi: %08lx edi: %08lx ebp: %08lx\n", + regs->esi, regs->edi, regs->ebp); + printk("ds: %04x es: %04x fs: %04x gs: %04x\n", + regs->ds, regs->es, regs->fs, regs->gs); + store_TR(i); + printk("Pid: %d, process nr: %d (%s)\n", current->pid, 0xffff & i, current->comm); + for(i=0;i<20;i++) + printk("%02x ",0xff & get_seg_byte(regs->cs,(i+(char *)regs->eip))); + printk("\n"); + do_exit(SIGSEGV); +} + +DO_ERROR( 0, SIGFPE, "divide error", divide_error, current) +DO_ERROR( 3, SIGTRAP, "int3", int3, current) +DO_ERROR( 4, SIGSEGV, "overflow", overflow, current) +DO_ERROR( 5, SIGSEGV, "bounds", bounds, current) +DO_ERROR( 6, SIGILL, "invalid operand", invalid_op, current) +DO_ERROR( 7, SIGSEGV, "device not available", device_not_available, current) +DO_ERROR( 8, SIGSEGV, "double fault", double_fault, current) +DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun, last_task_used_math) +DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS, current) +DO_ERROR(11, SIGSEGV, "segment not present", segment_not_present, current) +DO_ERROR(12, SIGSEGV, "stack segment", stack_segment, current) +DO_ERROR(13, SIGSEGV, "general protection", general_protection, current) +DO_ERROR(15, SIGSEGV, "reserved", reserved, current) +DO_ERROR(17, SIGSEGV, "alignment check", alignment_check, current) + +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) +{ + if (current->flags & PF_PTRACED) + current->blocked &= ~(1 << (SIGTRAP-1)); + send_sig(SIGTRAP, current, 1); + current->tss.trap_no = 1; + current->tss.error_code = error_code; + 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); +} + +/* + * Allow the process which triggered the interrupt to recover the error + * condition. + * - the status word is saved in the cs selector. + * - the tag word is saved in the operand selector. + * - the status word is then cleared and the tags all set to Empty. + * + * This will give sufficient information for complete recovery provided that + * the affected process knows or can deduce the code and data segments + * which were in force when the exception condition arose. + * + * Note that we play around with the 'TS' bit to hopefully get + * the correct behaviour even in the presense of the asynchronous + * IRQ13 behaviour + */ +void math_error(void) +{ + struct i387_hard_struct * env; + + clts(); + if (!last_task_used_math) { + __asm__("fnclex"); + return; + } + env = &last_task_used_math->tss.i387.hard; + send_sig(SIGFPE, last_task_used_math, 1); + last_task_used_math->tss.trap_no = 16; + last_task_used_math->tss.error_code = 0; + __asm__ __volatile__("fnsave %0":"=m" (*env)); + last_task_used_math = NULL; + stts(); + env->fcs = (env->swd & 0x0000ffff) | (env->fcs & 0xffff0000); + env->fos = env->twd; + env->swd &= 0xffff3800; + env->twd = 0xffffffff; +} + +asmlinkage void do_coprocessor_error(struct pt_regs * regs, long error_code) +{ + ignore_irq13 = 1; + math_error(); +} + +void trap_init(void) +{ + int i; + + set_trap_gate(0,÷_error); + set_trap_gate(1,&debug); + set_trap_gate(2,&nmi); + set_system_gate(3,&int3); /* int3-5 can be called from all */ + set_system_gate(4,&overflow); + set_system_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_trap_gate(8,&double_fault); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_trap_gate(14,&page_fault); + set_trap_gate(15,&reserved); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); + for (i=18;i<48;i++) + set_trap_gate(i,&reserved); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/vsprintf.c b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/vsprintf.c new file mode 100644 index 000000000..ef449a2df --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/kernel/vsprintf.c @@ -0,0 +1,274 @@ +/* + * linux/kernel/vsprintf.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* vsprintf.c -- Lars Wirzenius & Linus Torvalds. */ +/* + * Wirzenius wrote this portably, Torvalds fucked it up :-) + */ + +#include +#include +#include +#include + +unsigned long simple_strtoul(const char *cp,char **endp,unsigned int base) +{ + unsigned long result = 0,value; + + if (!base) { + base = 10; + if (*cp == '0') { + base = 8; + cp++; + if ((*cp == 'x') && isxdigit(cp[1])) { + cp++; + base = 16; + } + } + } + while (isxdigit(*cp) && (value = isdigit(*cp) ? *cp-'0' : (islower(*cp) + ? toupper(*cp) : *cp)-'A'+10) < base) { + result = result*base + value; + cp++; + } + if (endp) + *endp = (char *)cp; + return result; +} + +/* we use this so that we can do without the ctype library */ +#define is_digit(c) ((c) >= '0' && (c) <= '9') + +static int skip_atoi(const char **s) +{ + int i=0; + + while (is_digit(**s)) + i = i*10 + *((*s)++) - '0'; + return i; +} + +#define ZEROPAD 1 /* pad with zero */ +#define SIGN 2 /* unsigned/signed long */ +#define PLUS 4 /* show plus */ +#define SPACE 8 /* space if plus */ +#define LEFT 16 /* left justified */ +#define SPECIAL 32 /* 0x */ +#define SMALL 64 /* use 'abcdef' instead of 'ABCDEF' */ + +#define do_div(n,base) ({ \ +int __res; \ +__asm__("divl %4":"=a" (n),"=d" (__res):"0" (n),"1" (0),"r" (base)); \ +__res; }) + +static char * number(char * str, int num, int base, int size, int precision + ,int type) +{ + char c,sign,tmp[36]; + const char *digits="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"; + int i; + + if (type&SMALL) digits="0123456789abcdefghijklmnopqrstuvwxyz"; + if (type&LEFT) type &= ~ZEROPAD; + if (base<2 || base>36) + return 0; + c = (type & ZEROPAD) ? '0' : ' ' ; + if (type&SIGN && num<0) { + sign='-'; + num = -num; + } else + sign=(type&PLUS) ? '+' : ((type&SPACE) ? ' ' : 0); + if (sign) size--; + if (type&SPECIAL) + if (base==16) size -= 2; + else if (base==8) size--; + i=0; + if (num==0) + tmp[i++]='0'; + else while (num!=0) + tmp[i++]=digits[do_div(num,base)]; + if (i>precision) precision=i; + size -= precision; + if (!(type&(ZEROPAD+LEFT))) + while(size-->0) + *str++ = ' '; + if (sign) + *str++ = sign; + if (type&SPECIAL) + if (base==8) + *str++ = '0'; + else if (base==16) { + *str++ = '0'; + *str++ = digits[33]; + } + if (!(type&LEFT)) + while(size-->0) + *str++ = c; + while(i0) + *str++ = tmp[i]; + while(size-->0) + *str++ = ' '; + return str; +} + +int vsprintf(char *buf, const char *fmt, va_list args) +{ + int len; + int i; + char * str; + char *s; + int *ip; + + int flags; /* flags to number() */ + + int field_width; /* width of output field */ + int precision; /* min. # of digits for integers; max + number of chars for from string */ + int qualifier; /* 'h', 'l', or 'L' for integer fields */ + + for (str=buf ; *fmt ; ++fmt) { + if (*fmt != '%') { + *str++ = *fmt; + continue; + } + + /* process flags */ + flags = 0; + repeat: + ++fmt; /* this also skips first '%' */ + switch (*fmt) { + case '-': flags |= LEFT; goto repeat; + case '+': flags |= PLUS; goto repeat; + case ' ': flags |= SPACE; goto repeat; + case '#': flags |= SPECIAL; goto repeat; + case '0': flags |= ZEROPAD; goto repeat; + } + + /* get field width */ + field_width = -1; + if (is_digit(*fmt)) + field_width = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + field_width = va_arg(args, int); + if (field_width < 0) { + field_width = -field_width; + flags |= LEFT; + } + } + + /* get the precision */ + precision = -1; + if (*fmt == '.') { + ++fmt; + if (is_digit(*fmt)) + precision = skip_atoi(&fmt); + else if (*fmt == '*') { + /* it's the next argument */ + precision = va_arg(args, int); + } + if (precision < 0) + precision = 0; + } + + /* get the conversion qualifier */ + qualifier = -1; + if (*fmt == 'h' || *fmt == 'l' || *fmt == 'L') { + qualifier = *fmt; + ++fmt; + } + + switch (*fmt) { + case 'c': + if (!(flags & LEFT)) + while (--field_width > 0) + *str++ = ' '; + *str++ = (unsigned char) va_arg(args, int); + while (--field_width > 0) + *str++ = ' '; + break; + + case 's': + s = va_arg(args, char *); + if (!s) + s = ""; + len = strlen(s); + if (precision < 0) + precision = len; + else if (len > precision) + len = precision; + + if (!(flags & LEFT)) + while (len < field_width--) + *str++ = ' '; + for (i = 0; i < len; ++i) + *str++ = *s++; + while (len < field_width--) + *str++ = ' '; + break; + + case 'o': + str = number(str, va_arg(args, unsigned long), 8, + field_width, precision, flags); + break; + + case 'p': + if (field_width == -1) { + field_width = 8; + flags |= ZEROPAD; + } + str = number(str, + (unsigned long) va_arg(args, void *), 16, + field_width, precision, flags); + break; + + case 'x': + flags |= SMALL; + case 'X': + str = number(str, va_arg(args, unsigned long), 16, + field_width, precision, flags); + break; + + case 'd': + case 'i': + flags |= SIGN; + case 'u': + str = number(str, va_arg(args, unsigned long), 10, + field_width, precision, flags); + break; + + case 'n': + ip = va_arg(args, int *); + *ip = (str - buf); + break; + + default: + if (*fmt != '%') + *str++ = '%'; + if (*fmt) + *str++ = *fmt; + else + --fmt; + break; + } + } + *str = '\0'; + return str-buf; +} + +int sprintf(char * buf, const char *fmt, ...) +{ + va_list args; + int i; + + va_start(args, fmt); + i=vsprintf(buf,fmt,args); + va_end(args); + return i; +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/Makefile new file mode 100644 index 000000000..d6b77ea4f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/Makefile @@ -0,0 +1,32 @@ +# +# Makefile for some libs needed in the kernel. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# + +.c.s: + $(CC) $(CFLAGS) -S $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c $< + +OBJS = ctype.o _exit.o open.o close.o errno.o write.o dup.o setsid.o \ + execve.o wait.o string.o + +lib.a: $(OBJS) + $(AR) rcs lib.a $(OBJS) + sync + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/_exit.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/_exit.c new file mode 100644 index 000000000..a46f1a2b6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/_exit.c @@ -0,0 +1,18 @@ +/* + * linux/lib/_exit.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +volatile void _exit(int exit_code) +{ +fake_volatile: + __asm__("movl %1,%%ebx\n\t" + "int $0x80" + : /* no outputs */ + :"a" (__NR_exit),"g" (exit_code)); + goto fake_volatile; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/close.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/close.c new file mode 100644 index 000000000..2c3f4363e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/close.c @@ -0,0 +1,11 @@ +/* + * linux/lib/close.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,close,int,fd) + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/ctype.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/ctype.c new file mode 100644 index 000000000..d3613be6f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/ctype.c @@ -0,0 +1,35 @@ +/* + * linux/lib/ctype.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#include + +char _ctmp; +unsigned char _ctype[] = {0x00, /* EOF */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 0-7 */ +_C,_C|_S,_C|_S,_C|_S,_C|_S,_C|_S,_C,_C, /* 8-15 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 16-23 */ +_C,_C,_C,_C,_C,_C,_C,_C, /* 24-31 */ +_S|_SP,_P,_P,_P,_P,_P,_P,_P, /* 32-39 */ +_P,_P,_P,_P,_P,_P,_P,_P, /* 40-47 */ +_D,_D,_D,_D,_D,_D,_D,_D, /* 48-55 */ +_D,_D,_P,_P,_P,_P,_P,_P, /* 56-63 */ +_P,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U|_X,_U, /* 64-71 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 72-79 */ +_U,_U,_U,_U,_U,_U,_U,_U, /* 80-87 */ +_U,_U,_U,_P,_P,_P,_P,_P, /* 88-95 */ +_P,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L|_X,_L, /* 96-103 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 104-111 */ +_L,_L,_L,_L,_L,_L,_L,_L, /* 112-119 */ +_L,_L,_L,_P,_P,_P,_P,_C, /* 120-127 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 128-143 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 144-159 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 160-175 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 176-191 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 192-207 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 208-223 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, /* 224-239 */ +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; /* 240-255 */ + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/dup.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/dup.c new file mode 100644 index 000000000..6d5ed119e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/dup.c @@ -0,0 +1,11 @@ +/* + * linux/lib/dup.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall1(int,dup,int,fd) + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/errno.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/errno.c new file mode 100644 index 000000000..41cb9d76c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/errno.c @@ -0,0 +1,7 @@ +/* + * linux/lib/errno.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +int errno; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/execve.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/execve.c new file mode 100644 index 000000000..32a93f0f1 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/execve.c @@ -0,0 +1,11 @@ +/* + * linux/lib/execve.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include + +_syscall3(int,execve,const char *,file,char **,argv,char **,envp) + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/malloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/malloc.c new file mode 100644 index 000000000..4cf52682f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/malloc.c @@ -0,0 +1,540 @@ +/* + * malloc.c --- a general purpose kernel memory allocator for Linux. + * + * Written by Theodore Ts'o (tytso@mit.edu), 11/29/91 + * + * This routine is written to be as fast as possible, so that it + * can be called from the interrupt level. + * + * Limitations: maximum size of memory we can allocate using this routine + * is 4k, the size of a page in Linux. + * + * The general game plan is that each page (called a bucket) will only hold + * objects of a given size. When all of the object on a page are released, + * the page can be returned to the general free pool. When kmalloc() is + * called, it looks for the smallest bucket size which will fulfill its + * request, and allocate a piece of memory from that bucket pool. + * + * Each bucket has as its control block a bucket descriptor which keeps + * track of how many objects are in use on that page, and the free list + * for that page. Like the buckets themselves, bucket descriptors are + * stored on pages requested from get_free_page(). However, unlike buckets, + * pages devoted to bucket descriptor pages are never released back to the + * system. Fortunately, a system should probably only need 1 or 2 bucket + * descriptor pages, since a page can hold 256 bucket descriptors (which + * corresponds to 1 megabyte worth of bucket pages.) If the kernel is using + * that much allocated memory, it's probably doing something wrong. :-) + * + * Note: kmalloc() and kfree() both call get_free_page() and free_page() + * in sections of code where interrupts are turned off, to allow + * kmalloc() and kfree() to be safely called from an interrupt routine. + * (We will probably need this functionality when networking code, + * particularily things like NFS, is added to Linux.) However, this + * presumes that get_free_page() and free_page() are interrupt-level + * safe, which they may not be once paging is added. If this is the + * case, we will need to modify kmalloc() to keep a few unused pages + * "pre-allocated" so that it can safely draw upon those pages if + * it is called from an interrupt routine. + * + * Another concern is that get_free_page() should not sleep; if it + * does, the code is carefully ordered so as to avoid any race + * conditions. The catch is that if kmalloc() is called re-entrantly, + * there is a chance that unecessary pages will be grabbed from the + * system. Except for the pages for the bucket descriptor page, the + * extra pages will eventually get released back to the system, though, + * so it isn't all that bad. + */ + +/* I'm going to modify it to keep some free pages around. Get free page + can sleep, and tcp/ip needs to call kmalloc at interrupt time (Or keep + big buffers around for itself.) I guess I'll have return from + syscall fill up the free page descriptors. -RAB */ + +/* since the advent of GFP_ATOMIC, I've changed the kmalloc code to + use it and return NULL if it can't get a page. -RAB */ +/* (mostly just undid the previous changes -RAB) */ + +/* I've added the priority argument to kmalloc so routines can + sleep on memory if they want. - RAB */ + +/* I've also got to make sure that kmalloc is reentrant now. */ + +/* Debugging support: add file/line info, add beginning+end markers. -M.U- */ + +#include +#include +#include +#include + +#include + +struct bucket_desc { /* 16 bytes */ + void *page; + struct bucket_desc *next; + void *freeptr; + unsigned short refcnt; + unsigned short bucket_size; +}; + +struct _bucket_dir { /* 8 bytes */ + unsigned int size; + struct bucket_desc *chain; +}; + +#ifdef CONFIG_DEBUG_MALLOC + +struct hdr_start { + const char *file; + const char *ok_file; + unsigned short line; + unsigned short ok_line; + unsigned short size; + int magic; +}; +struct hdr_end { + int magic; +}; + +#define DEB_MAGIC_FREE 0x13579BDF /* free block */ +#define DEB_MAGIC_ALLOC 0x2468ACE0 /* allocated block */ +#define DEB_MAGIC_USED 0x147AD036 /* allocated but bad */ +#define DEB_MAGIC_FREED 0x258BE169 /* free but abused */ + +#define DEB_MAGIC_END 0x369CF258 /* end marker */ + +#endif +/* + * The following is the where we store a pointer to the first bucket + * descriptor for a given size. + * + * If it turns out that the Linux kernel allocates a lot of objects of a + * specific size, then we may want to add that specific size to this list, + * since that will allow the memory to be allocated more efficiently. + * However, since an entire page must be dedicated to each specific size + * on this list, some amount of temperance must be exercised here. + * + * Note that this list *must* be kept in order. + */ +struct _bucket_dir bucket_dir[] = { +#ifndef CONFIG_DEBUG_MALLOC /* Debug headers have too much overhead */ + { 16, (struct bucket_desc *) 0}, +#endif + { 32, (struct bucket_desc *) 0}, + { 64, (struct bucket_desc *) 0}, + { 128, (struct bucket_desc *) 0}, + { 256, (struct bucket_desc *) 0}, + { 512, (struct bucket_desc *) 0}, + { 1024, (struct bucket_desc *) 0}, + { 2048, (struct bucket_desc *) 0}, + { 4096, (struct bucket_desc *) 0}, + { 0, (struct bucket_desc *) 0}}; /* End of list marker */ + +/* + * This contains a linked list of free bucket descriptor blocks + */ +static struct bucket_desc *free_bucket_desc = (struct bucket_desc *) 0; + +/* + * This routine initializes a bucket description page. + */ + +/* It assumes it is called with interrupts on. and will + return that way. It also can sleep if priority != GFP_ATOMIC. */ + +static inline void init_bucket_desc(unsigned long page) +{ + struct bucket_desc *bdesc; + int i; + + bdesc = (struct bucket_desc *) page; + for (i = PAGE_SIZE/sizeof(struct bucket_desc); --i > 0; bdesc++ ) + bdesc->next = bdesc+1; + /* + * This is done last, to avoid race conditions in case + * get_free_page() sleeps and this routine gets called again.... + */ + cli(); + bdesc->next = free_bucket_desc; + free_bucket_desc = (struct bucket_desc *) page; +} + +/* + * Re-organized some code to give cleaner assembly output for easier + * verification.. LBT + */ +#ifdef CONFIG_DEBUG_MALLOC +void * +deb_kmalloc(const char *deb_file, unsigned short deb_line, + unsigned int len, int priority) +#else +void * +kmalloc(unsigned int len, int priority) +#endif +{ + int i; + unsigned long flags; + unsigned long page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + void *retval; + +#ifdef CONFIG_DEBUG_MALLOC + len += sizeof(struct hdr_start)+sizeof(struct hdr_end); +#endif + /* + * First we search the bucket_dir to find the right bucket change + * for this request. + */ + + /* The sizes are static so there is no reentry problem here. */ + bdir = bucket_dir; + for (bdir = bucket_dir ; bdir->size < len ; bdir++) { + if (!bdir->size) + goto too_large; + } + + /* + * Now we search for a bucket descriptor which has free space + */ + save_flags(flags); + cli(); /* Avoid race conditions */ + for (bdesc = bdir->chain; bdesc != NULL; bdesc = bdesc->next) + if (bdesc->freeptr) + goto found_bdesc; + /* + * If we didn't find a bucket with free space, then we'll + * allocate a new one. + */ + + /* + * Note that init_bucket_descriptor() does its + * own cli() before returning, and guarantees that + * there is a bucket desc in the page. + */ + if (!free_bucket_desc) { + restore_flags(flags); + if(!(page=__get_free_page(priority))) + return NULL; + init_bucket_desc(page); + } + + bdesc = free_bucket_desc; + free_bucket_desc = bdesc->next; + restore_flags(flags); + + if(!(page=__get_free_page(priority))) { + /* + * Out of memory? Put the bucket descriptor back on the free list + */ + cli(); + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + restore_flags(flags); + return NULL; + } + + bdesc->refcnt = 0; + bdesc->bucket_size = bdir->size; + bdesc->page = bdesc->freeptr = (void *) page; + + /* Set up the chain of free objects */ + for (i=PAGE_SIZE/bdir->size; i > 0 ; i--) { +#ifdef CONFIG_DEBUG_MALLOC + struct hdr_start *hd; + struct hdr_end *he; + hd = (struct hdr_start *) page; + he = (struct hdr_end *)(page+(bdir->size-sizeof(struct hdr_end))); + hd->magic = DEB_MAGIC_FREE; + hd->file = hd->ok_file = "(expand)"; + hd->line = hd->ok_line = 0; + hd->size = bdir->size-sizeof(struct hdr_start)-sizeof(struct hdr_end); + he->magic = DEB_MAGIC_END; + + memset(hd+1,0xF8,hd->size); + + *((void **) (hd+1)) = (i==1) ? NULL : (void *)(page + bdir->size); +#else + *((void **) page) = (i==1) ? NULL : (void *)(page + bdir->size); +#endif + page += bdir->size; + } + + /* turn interrupts back off for putting the + thing onto the chain. */ + cli(); + /* remember bdir is not changed. */ + bdesc->next = bdir->chain; /* OK, link it in! */ + bdir->chain = bdesc; + +found_bdesc: + retval = (void *) bdesc->freeptr; +#ifdef CONFIG_DEBUG_MALLOC + bdesc->freeptr = *((void **) (((char *)retval)+sizeof(struct hdr_start))); +#else + bdesc->freeptr = *((void **) retval); +#endif + bdesc->refcnt++; + restore_flags(flags); /* OK, we're safe again */ +#ifdef CONFIG_DEBUG_MALLOC + { + struct hdr_start *hd; + struct hdr_end *he; + + hd = (struct hdr_start *) retval; + retval = hd+1; + len -= sizeof(struct hdr_start)+sizeof(struct hdr_end); + if(hd->magic != DEB_MAGIC_FREE && hd->magic != DEB_MAGIC_FREED) { + printk("DEB_MALLOC allocating %s block 0x%x (head 0x%x) from %s:%d, magic %x\n", + (hd->magic == DEB_MAGIC_ALLOC) ? "nonfree" : "trashed", + retval,hd,deb_file,deb_line,hd->magic); + return NULL; + } + if(len > hd->size || len > bdir->size-sizeof(struct hdr_start)-sizeof(struct hdr_end)) { + printk("DEB_MALLOC got %x:%x-byte block, wanted %x, from %s:%d, last %s:%d\n", + hd->size,bdir->size,len,hd->file,hd->line,deb_file,deb_line); + return NULL; + } + { + unsigned char *x = (unsigned char *) retval; + unsigned short pos = 4; + x += pos; + while(pos < hd->size) { + if(*x++ != 0xF8) { + printk("DEB_MALLOC used 0x%x:%x(%x) while free, from %s:%d\n", + retval,pos,hd->size,hd->file,hd->line); + return NULL; + } + pos++; + } + } + he = (struct hdr_end *)(((char *)retval)+hd->size); + if(he->magic != DEB_MAGIC_END) { + printk("DEB_MALLOC overran 0x%x:%d while free, from %s:%d\n",retval,hd->size,hd->file,hd->line); + } + memset(retval, 0xf0, len); + he = (struct hdr_end *)(((char *)retval)+len); + hd->file = hd->ok_file = deb_file; + hd->line = hd->ok_line = deb_line; + hd->size = len; + hd->magic = DEB_MAGIC_ALLOC; + he->magic = DEB_MAGIC_END; + } +#endif + return retval; + +too_large: + /* This should be changed for sizes > 1 page. */ + printk("kmalloc called with impossibly large argument (%d)\n", len); + return NULL; +} + +#ifdef CONFIG_DEBUG_MALLOC +void deb_kcheck_s(const char *deb_file, unsigned short deb_line, + void *obj, int size) +{ + struct hdr_start *hd; + struct hdr_end *he; + + if (!obj) + return; + hd = (struct hdr_start *) obj; + hd--; + + if(hd->magic != DEB_MAGIC_ALLOC) { + if(hd->magic == DEB_MAGIC_FREE) { + printk("DEB_MALLOC Using free block of 0x%x at %s:%d, by %s:%d, wasOK %s:%d\n", + obj,deb_file,deb_line,hd->file,hd->line,hd->ok_file,hd->ok_line); + /* For any other condition it is either superfluous or dangerous to print something. */ + hd->magic = DEB_MAGIC_FREED; + } + return; + } + if(hd->size != size) { + if(size != 0) { + printk("DEB_MALLOC size for 0x%x given as %d, stored %d, at %s:%d, wasOK %s:%d\n", + obj,size,hd->size,deb_file,deb_line,hd->ok_file,hd->ok_line); + } + size = hd->size; + } + he = (struct hdr_end *)(((char *)obj)+size); + if(he->magic != DEB_MAGIC_END) { + printk("DEB_MALLOC overran block 0x%x:%d, at %s:%d, wasOK %s:%d\n", + obj,hd->size,deb_file,deb_line,hd->ok_file,hd->ok_line); + hd->magic = DEB_MAGIC_USED; + return; + } + hd->ok_file = deb_file; + hd->ok_line = deb_line; +} +#endif + +/* + * Here is the kfree routine. If you know the size of the object that you + * are freeing, then kfree_s() will use that information to speed up the + * search for the bucket descriptor. + * + * We will #define a macro so that "kfree(x)" is becomes "kfree_s(x, 0)" + */ +#ifdef CONFIG_DEBUG_MALLOC +void deb_kfree_s(const char *deb_file, unsigned short deb_line, + void *obj, int size) +#else +void kfree_s(void *obj, int size) +#endif +{ + unsigned long flags; + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc, *prev; + + if (!obj) + return; +#ifdef CONFIG_DEBUG_MALLOC + { + struct hdr_start *hd; + struct hdr_end *he; + hd = (struct hdr_start *) obj; + hd--; + + if(hd->magic == DEB_MAGIC_FREE) { + printk("DEB_MALLOC dup free of 0x%x at %s:%d by %s:%d, wasOK %s:%d\n", + obj,deb_file,deb_line,hd->file,hd->line,hd->ok_file,hd->ok_line); + return; + } + if(hd->size != size) { + if(size != 0) { + if(hd->magic != DEB_MAGIC_USED) + printk("DEB_MALLOC size for 0x%x given as %d, stored %d, at %s:%d, wasOK %s:%d\n", + obj,size,hd->size,deb_file,deb_line,hd->ok_file,hd->ok_line); + } + size = hd->size; + } + he = (struct hdr_end *)(((char *)obj)+size); + if(he->magic != DEB_MAGIC_END) { + if(hd->magic != DEB_MAGIC_USED) + printk("DEB_MALLOC overran block 0x%x:%d, at %s:%d, from %s:%d, wasOK %s:%d\n", + obj,hd->size,deb_file,deb_line,hd->file,hd->line,hd->ok_file,hd->ok_line); + } + size += sizeof(struct hdr_start)+sizeof(struct hdr_end); + } +#endif + save_flags(flags); + /* Calculate what page this object lives in */ + page = (void *) ((unsigned long) obj & PAGE_MASK); + + /* Now search the buckets looking for that page */ + for (bdir = bucket_dir; bdir->size; bdir++) { + prev = 0; + /* If size is zero then this conditional is always true */ + if (bdir->size >= size) { + /* We have to turn off interrupts here because + we are descending the chain. If something + changes it in the middle we could suddenly + find ourselves descending the free list. + I think this would only cause a memory + leak, but better safe than sorry. */ + cli(); /* To avoid race conditions */ + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + if (bdesc->page == page) + goto found; + prev = bdesc; + } + } + } + + restore_flags(flags); + printk("Bad address passed to kernel kfree_s(%p, %d)\n",obj, size); +#ifdef CONFIG_DEBUG_MALLOC + printk("Offending code: %s:%d\n",deb_file,deb_line); +#else + printk("Offending eip: %08x\n",((unsigned long *) &obj)[-1]); +#endif + return; + +found: + /* interrupts are off here. */ +#ifdef CONFIG_DEBUG_MALLOC + + { + struct hdr_start *hd; + struct hdr_end *he; + hd = (struct hdr_start *) obj; + hd--; + + hd->file = deb_file; + hd->line = deb_line; + hd->magic = DEB_MAGIC_FREE; + hd->size = bdir->size-sizeof(struct hdr_start)-sizeof(struct hdr_end); + he = (struct hdr_end *)(((char *)obj)+hd->size); + memset(obj, 0xf8, hd->size); + he->magic = DEB_MAGIC_END; + *((void **)obj) = bdesc->freeptr; + obj = hd; + } +#else + *((void **)obj) = bdesc->freeptr; +#endif + + bdesc->freeptr = obj; + bdesc->refcnt--; + if (bdesc->refcnt == 0) { + /* + * We need to make sure that prev is still accurate. It + * may not be, if someone rudely interrupted us.... + */ + if ((prev && (prev->next != bdesc)) || + (!prev && (bdir->chain != bdesc))) + for (prev = bdir->chain; prev; prev = prev->next) + if (prev->next == bdesc) + break; + if (prev) + prev->next = bdesc->next; + else { + if (bdir->chain != bdesc) + panic("kmalloc bucket chains corrupted"); + bdir->chain = bdesc->next; + } + bdesc->next = free_bucket_desc; + free_bucket_desc = bdesc; + free_page((unsigned long) bdesc->page); + } + restore_flags(flags); + return; +} + +#ifdef CONFIG_DEBUG_MALLOC +int get_malloc(char *buffer) +{ + int len = 0; + int i; + unsigned long flags; + void *page; + struct _bucket_dir *bdir; + struct bucket_desc *bdesc; + + save_flags(flags); + cli(); /* To avoid race conditions */ + for (bdir = bucket_dir; bdir->size; bdir++) { + for (bdesc = bdir->chain; bdesc; bdesc = bdesc->next) { + page = bdesc->page; + for (i=PAGE_SIZE/bdir->size; i > 0 ; i--) { + struct hdr_start *hd; + hd = (struct hdr_start *)page; + if(hd->magic == DEB_MAGIC_ALLOC) { + if(len > PAGE_SIZE-80) { + restore_flags(flags); + len += sprintf(buffer+len,"...\n"); + return len; + } + len += sprintf(buffer+len,"%08x:%03x %s:%d %s:%d\n", + (long)(page+sizeof(struct hdr_start)),hd->size,hd->file,hd->line,hd->ok_file,hd->ok_line); + } + page += bdir->size; + } + } + } + + restore_flags(flags); + return len; +} +#endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/open.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/open.c new file mode 100644 index 000000000..b69d2b548 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/open.c @@ -0,0 +1,26 @@ +/* + * linux/lib/open.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +int open(const char * filename, int flag, ...) +{ + register int res; + va_list arg; + + va_start(arg,flag); + __asm__("movl %2,%%ebx\n\t" + "int $0x80" + :"=a" (res) + :"0" (__NR_open),"g" ((long)(filename)),"c" (flag), + "d" (va_arg(arg,int))); + if (res>=0) + return res; + errno = -res; + return -1; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/setsid.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/setsid.c new file mode 100644 index 000000000..c157b7135 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/setsid.c @@ -0,0 +1,12 @@ +/* + * linux/lib/setsid.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall0(pid_t,setsid) + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/string.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/string.c new file mode 100644 index 000000000..4f4722f77 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/string.c @@ -0,0 +1,16 @@ +/* + * linux/lib/string.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#ifndef __GNUC__ +#error I want gcc! +#endif + +#include + +#define extern +#define inline +#define __LIBRARY__ +#include diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/wait.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/wait.c new file mode 100644 index 000000000..727a27162 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/wait.c @@ -0,0 +1,17 @@ +/* + * linux/lib/wait.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(pid_t,waitpid,pid_t,pid,int *,wait_stat,int,options) + +pid_t wait(int * wait_stat) +{ + return waitpid(-1,wait_stat,0); +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/lib/write.c b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/write.c new file mode 100644 index 000000000..9336ed9d8 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/lib/write.c @@ -0,0 +1,12 @@ +/* + * linux/lib/write.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +#define __LIBRARY__ +#include +#include + +_syscall3(int,write,int,fd,const char *,buf,off_t,count) + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/makever.sh b/gems-kernel.git/source/THIRDPARTY/linux-old/makever.sh new file mode 100644 index 000000000..1b230e222 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/makever.sh @@ -0,0 +1,13 @@ +#! /bin/sh + +if [ ! -f .version ] +then + echo 0 > .version +fi +cycle=`cat .version` +cycle=`expr $cycle + 1` +if [ $cycle -gt 99 ] +then + cycle=0 +fi +echo $cycle > .version diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/mm/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/Makefile new file mode 100644 index 000000000..37bad3800 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/Makefile @@ -0,0 +1,30 @@ +# +# Makefile for the linux memory manager. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) -S $< + +OBJS = memory.o swap.o mmap.o kmalloc.o vmalloc.o + +mm.o: $(OBJS) + $(LD) -r -o mm.o $(OBJS) + +dep: + $(CPP) -M *.c > .depend + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/mm/kmalloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/kmalloc.c new file mode 100644 index 000000000..e75fa207d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/kmalloc.c @@ -0,0 +1,338 @@ +/* + * linux/mm/kmalloc.c + * + * Copyright (C) 1991, 1992 Linus Torvalds & Roger Wolff. + * + * Written by R.E. Wolff Sept/Oct '93. + * + */ + +#include +#include +#include + +#define GFP_LEVEL_MASK 0xf + +/* I want this low enough for a while to catch errors. + I want this number to be increased in the near future: + loadable device drivers should use this function to get memory */ + +#define MAX_KMALLOC_K 4 + + +/* This defines how many times we should try to allocate a free page before + giving up. Normally this shouldn't happen at all. */ +#define MAX_GET_FREE_PAGE_TRIES 4 + + +/* Private flags. */ + +#define MF_USED 0xffaa0055 +#define MF_FREE 0x0055ffaa + + +/* + * Much care has gone into making these routines in this file reentrant. + * + * The fancy bookkeeping of nbytesmalloced and the like are only used to + * report them to the user (oooohhhhh, aaaaahhhhh....) are not + * protected by cli(). (If that goes wrong. So what?) + * + * These routines restore the interrupt status to allow calling with ints + * off. + */ + +/* + * A block header. This is in front of every malloc-block, whether free or not. + */ +struct block_header { + unsigned long bh_flags; + union { + unsigned long ubh_length; + struct block_header *fbh_next; + } vp; +}; + + +#define bh_length vp.ubh_length +#define bh_next vp.fbh_next +#define BH(p) ((struct block_header *)(p)) + + +/* + * The page descriptor is at the front of every page that malloc has in use. + */ +struct page_descriptor { + struct page_descriptor *next; + struct block_header *firstfree; + int order; + int nfree; +}; + + +#define PAGE_DESC(p) ((struct page_descriptor *)(((unsigned long)(p)) & PAGE_MASK)) + + +/* + * A size descriptor describes a specific class of malloc sizes. + * Each class of sizes has its own freelist. + */ +struct size_descriptor { + struct page_descriptor *firstfree; + int size; + int nblocks; + + int nmallocs; + int nfrees; + int nbytesmalloced; + int npages; +}; + + +struct size_descriptor sizes[] = { + { NULL, 32,127, 0,0,0,0 }, + { NULL, 64, 63, 0,0,0,0 }, + { NULL, 128, 31, 0,0,0,0 }, + { NULL, 252, 16, 0,0,0,0 }, + { NULL, 508, 8, 0,0,0,0 }, + { NULL,1020, 4, 0,0,0,0 }, + { NULL,2040, 2, 0,0,0,0 }, + { NULL,4080, 1, 0,0,0,0 }, + { NULL, 0, 0, 0,0,0,0 } +}; + + +#define NBLOCKS(order) (sizes[order].nblocks) +#define BLOCKSIZE(order) (sizes[order].size) + + + +long kmalloc_init (long start_mem,long end_mem) +{ + int order; + +/* + * Check the static info array. Things will blow up terribly if it's + * incorrect. This is a late "compile time" check..... + */ +for (order = 0;BLOCKSIZE(order);order++) + { + if ((NBLOCKS (order)*BLOCKSIZE(order) + sizeof (struct page_descriptor)) > + PAGE_SIZE) + { + printk ("Cannot use %d bytes out of %d in order = %d block mallocs\n", + NBLOCKS (order) * BLOCKSIZE(order) + + sizeof (struct page_descriptor), + (int) PAGE_SIZE, + BLOCKSIZE (order)); + panic ("This only happens if someone messes with kmalloc"); + } + } +return start_mem; +} + + + +int get_order (int size) +{ + int order; + + /* Add the size of the header */ + size += sizeof (struct block_header); + for (order = 0;BLOCKSIZE(order);order++) + if (size <= BLOCKSIZE (order)) + return order; + return -1; +} + +void * kmalloc (size_t size, int priority) +{ + unsigned long flags; + int order,tries,i,sz; + struct block_header *p; + struct page_descriptor *page; + +/* Sanity check... */ +if (size > MAX_KMALLOC_K * 1024) + { + printk ("kmalloc: I refuse to allocate %d bytes (for now max = %d).\n", + size,MAX_KMALLOC_K*1024); + return (NULL); + } + +order = get_order (size); +if (order < 0) + { + printk ("kmalloc of too large a block (%d bytes).\n",size); + return (NULL); + } + +save_flags(flags); + +/* It seems VERY unlikely to me that it would be possible that this + loop will get executed more than once. */ +tries = MAX_GET_FREE_PAGE_TRIES; +while (tries --) + { + /* Try to allocate a "recently" freed memory block */ + cli (); + if ((page = sizes[order].firstfree) && + (p = page->firstfree)) + { + if (p->bh_flags == MF_FREE) + { + page->firstfree = p->bh_next; + page->nfree--; + if (!page->nfree) + { + sizes[order].firstfree = page->next; + page->next = NULL; + } + restore_flags(flags); + + sizes [order].nmallocs++; + sizes [order].nbytesmalloced += size; + p->bh_flags = MF_USED; /* As of now this block is officially in use */ + p->bh_length = size; + return p+1; /* Pointer arithmetic: increments past header */ + } + printk ("Problem: block on freelist at %08lx isn't free.\n",(long)p); + return (NULL); + } + restore_flags(flags); + + + /* Now we're in trouble: We need to get a new free page..... */ + + sz = BLOCKSIZE(order); /* sz is the size of the blocks we're dealing with */ + + /* This can be done with ints on: This is private to this invocation */ + page = (struct page_descriptor *) __get_free_page (priority & GFP_LEVEL_MASK); + if (!page) + { + printk ("Couldn't get a free page.....\n"); + return NULL; + } +#if 0 + printk ("Got page %08x to use for %d byte mallocs....",(long)page,sz); +#endif + sizes[order].npages++; + + /* Loop for all but last block: */ + for (i=NBLOCKS(order),p=BH (page+1);i > 1;i--,p=p->bh_next) + { + p->bh_flags = MF_FREE; + p->bh_next = BH ( ((long)p)+sz); + } + /* Last block: */ + p->bh_flags = MF_FREE; + p->bh_next = NULL; + + page->order = order; + page->nfree = NBLOCKS(order); + page->firstfree = BH(page+1); +#if 0 + printk ("%d blocks per page\n",page->nfree); +#endif + /* Now we're going to muck with the "global" freelist for this size: + this should be uniterruptible */ + cli (); + /* + * sizes[order].firstfree used to be NULL, otherwise we wouldn't be + * here, but you never know.... + */ + page->next = sizes[order].firstfree; + sizes[order].firstfree = page; + restore_flags(flags); + } + +/* Pray that printk won't cause this to happen again :-) */ + +printk ("Hey. This is very funny. I tried %d times to allocate a whole\n" + "new page for an object only %d bytes long, but some other process\n" + "beat me to actually allocating it. Also note that this 'error'\n" + "message is soooo very long to catch your attention. I'd appreciate\n" + "it if you'd be so kind as to report what conditions caused this to\n" + "the author of this kmalloc: wolff@dutecai.et.tudelft.nl.\n" + "(Executive summary: This can't happen)\n", + MAX_GET_FREE_PAGE_TRIES, + size); +return NULL; +} + + +void kfree_s (void *ptr,int size) +{ +unsigned long flags; +int order; +register struct block_header *p=((struct block_header *)ptr) -1; +struct page_descriptor *page,*pg2; + +page = PAGE_DESC (p); +order = page->order; +if ((order < 0) || + (order > sizeof (sizes)/sizeof (sizes[0])) || + (((long)(page->next)) & ~PAGE_MASK) || + (p->bh_flags != MF_USED)) + { + printk ("kfree of non-kmalloced memory: %p, next= %p, order=%d\n", + p, page->next, page->order); + return; + } +if (size && + size != p->bh_length) + { + printk ("Trying to free pointer at %p with wrong size: %d instead of %lu.\n", + p,size,p->bh_length); + return; + } +size = p->bh_length; +p->bh_flags = MF_FREE; /* As of now this block is officially free */ + +save_flags(flags); +cli (); +p->bh_next = page->firstfree; +page->firstfree = p; +page->nfree ++; + +if (page->nfree == 1) + { /* Page went from full to one free block: put it on the freelist */ + if (page->next) + { + printk ("Page %p already on freelist dazed and confused....\n", page); + } + else + { + page->next = sizes[order].firstfree; + sizes[order].firstfree = page; + } + } + +/* If page is completely free, free it */ +if (page->nfree == NBLOCKS (page->order)) + { +#if 0 + printk ("Freeing page %08x.\n", (long)page); +#endif + if (sizes[order].firstfree == page) + { + sizes[order].firstfree = page->next; + } + else + { + for (pg2=sizes[order].firstfree; + (pg2 != NULL) && (pg2->next != page); + pg2=pg2->next) + /* Nothing */; + if (pg2 != NULL) + pg2->next = page->next; + else + printk ("Ooops. page %p doesn't show on freelist.\n", page); + } + free_page ((long)page); + } +restore_flags(flags); + +sizes[order].nfrees++; /* Noncritical (monitoring) admin stuff */ +sizes[order].nbytesmalloced -= size; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/mm/memory.c b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/memory.c new file mode 100644 index 000000000..57cee25f0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/memory.c @@ -0,0 +1,1227 @@ +/* + * linux/mm/memory.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * demand-loading started 01.12.91 - seems it is high on the list of + * things wanted, and it should be easy to implement. - Linus + */ + +/* + * Ok, demand-loading was easy, shared pages a little bit tricker. Shared + * pages started 02.12.91, seems to work. - Linus. + * + * Tested sharing by executing about 30 /bin/sh: under the old kernel it + * would have taken more than the 6M I have free, but it worked well as + * far as I could see. + * + * Also corrected some "invalidate()"s - I wasn't doing enough of them. + */ + +/* + * Real VM (paging to/from disk) started 18.12.91. Much more work and + * thought has to go into this. Oh, well.. + * 19.12.91 - works, somewhat. Sometimes I get faults, don't know why. + * Found it. Everything seems to work now. + * 20.12.91 - Ok, making the swap-device changeable like the root. + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +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); + +int nr_swap_pages = 0; +int nr_free_pages = 0; +unsigned long free_page_list = 0; +/* + * The secondary free_page_list is used for malloc() etc things that + * may need pages during interrupts etc. Normal get_free_page() operations + * don't touch it, so it stays as a kind of "panic-list", that can be + * accessed when all other mm tricks have failed. + */ +int nr_secondary_pages = 0; +unsigned long secondary_page_list = 0; + +#define copy_page(from,to) \ +__asm__("cld ; rep ; movsl": :"S" (from),"D" (to),"c" (1024):"cx","di","si") + +unsigned short * mem_map = NULL; + +#define CODE_SPACE(addr,p) ((addr) < (p)->end_code) + +/* + * oom() prints a message (so that the user knows why the process died), + * and gives the process an untrappable SIGSEGV. + */ +void oom(struct task_struct * task) +{ + printk("\nout of memory\n"); + task->sigaction[SIGKILL-1].sa_handler = NULL; + task->blocked &= ~(1<<(SIGKILL-1)); + send_sig(SIGKILL,task,1); +} + +static void free_one_table(unsigned long * page_dir) +{ + int j; + unsigned long pg_table = *page_dir; + unsigned long * page_table; + + if (!pg_table) + return; + *page_dir = 0; + if (pg_table >= high_memory || !(pg_table & PAGE_PRESENT)) { + printk("Bad page table: [%p]=%08lx\n",page_dir,pg_table); + return; + } + if (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED) + return; + page_table = (unsigned long *) (pg_table & PAGE_MASK); + for (j = 0 ; j < PTRS_PER_PAGE ; j++,page_table++) { + unsigned long pg = *page_table; + + if (!pg) + continue; + *page_table = 0; + if (pg & PAGE_PRESENT) + free_page(PAGE_MASK & pg); + else + swap_free(pg); + } + free_page(PAGE_MASK & pg_table); +} + +/* + * This function clears all user-level page tables of a process - this + * is needed by execve(), so that old pages aren't in the way. Note that + * unlike 'free_page_tables()', this function still leaves a valid + * page-table-tree in memory: it just removes the user pages. The two + * functions are similar, but there is a fundamental difference. + */ +void clear_page_tables(struct task_struct * tsk) +{ + int i; + unsigned long pg_dir; + unsigned long * page_dir; + + if (!tsk) + return; + if (tsk == task[0]) + panic("task[0] (swapper) doesn't support exec()\n"); + pg_dir = tsk->tss.cr3; + page_dir = (unsigned long *) pg_dir; + if (!page_dir || page_dir == swapper_pg_dir) { + printk("Trying to clear kernel page-directory: not good\n"); + return; + } + if (mem_map[MAP_NR(pg_dir)] > 1) { + unsigned long * new_pg; + + if (!(new_pg = (unsigned long*) get_free_page(GFP_KERNEL))) { + oom(tsk); + return; + } + for (i = 768 ; i < 1024 ; i++) + new_pg[i] = page_dir[i]; + free_page(pg_dir); + tsk->tss.cr3 = (unsigned long) new_pg; + return; + } + for (i = 0 ; i < 768 ; i++,page_dir++) + free_one_table(page_dir); + invalidate(); + return; +} + +/* + * This function frees up all page tables of a process when it exits. + */ +void free_page_tables(struct task_struct * tsk) +{ + int i; + unsigned long pg_dir; + unsigned long * page_dir; + + if (!tsk) + return; + if (tsk == task[0]) { + printk("task[0] (swapper) killed: unable to recover\n"); + panic("Trying to free up swapper memory space"); + } + pg_dir = tsk->tss.cr3; + if (!pg_dir || pg_dir == (unsigned long) swapper_pg_dir) { + printk("Trying to free kernel page-directory: not good\n"); + return; + } + tsk->tss.cr3 = (unsigned long) swapper_pg_dir; + if (tsk == current) + __asm__ __volatile__("movl %0,%%cr3": :"a" (tsk->tss.cr3)); + if (mem_map[MAP_NR(pg_dir)] > 1) { + free_page(pg_dir); + return; + } + page_dir = (unsigned long *) pg_dir; + for (i = 0 ; i < PTRS_PER_PAGE ; i++,page_dir++) + free_one_table(page_dir); + free_page(pg_dir); + invalidate(); +} + +/* + * clone_page_tables() clones the page table for a process - both + * processes will have the exact same pages in memory. There are + * probably races in the memory management with cloning, but we'll + * see.. + */ +int clone_page_tables(struct task_struct * tsk) +{ + unsigned long pg_dir; + + pg_dir = current->tss.cr3; + mem_map[MAP_NR(pg_dir)]++; + tsk->tss.cr3 = pg_dir; + return 0; +} + +/* + * copy_page_tables() just copies the whole process memory range: + * note the special handling of RESERVED (ie kernel) pages, which + * means that they are always shared by all processes. + */ +int copy_page_tables(struct task_struct * tsk) +{ + int i; + unsigned long old_pg_dir, *old_page_dir; + unsigned long new_pg_dir, *new_page_dir; + + if (!(new_pg_dir = get_free_page(GFP_KERNEL))) + return -ENOMEM; + old_pg_dir = current->tss.cr3; + tsk->tss.cr3 = new_pg_dir; + old_page_dir = (unsigned long *) old_pg_dir; + new_page_dir = (unsigned long *) new_pg_dir; + for (i = 0 ; i < PTRS_PER_PAGE ; i++,old_page_dir++,new_page_dir++) { + int j; + unsigned long old_pg_table, *old_page_table; + unsigned long new_pg_table, *new_page_table; + + old_pg_table = *old_page_dir; + if (!old_pg_table) + continue; + if (old_pg_table >= high_memory || !(old_pg_table & PAGE_PRESENT)) { + printk("copy_page_tables: bad page table: " + "probable memory corruption"); + *old_page_dir = 0; + continue; + } + if (mem_map[MAP_NR(old_pg_table)] & MAP_PAGE_RESERVED) { + *new_page_dir = old_pg_table; + continue; + } + if (!(new_pg_table = get_free_page(GFP_KERNEL))) { + free_page_tables(tsk); + return -ENOMEM; + } + old_page_table = (unsigned long *) (PAGE_MASK & old_pg_table); + new_page_table = (unsigned long *) (PAGE_MASK & new_pg_table); + for (j = 0 ; j < PTRS_PER_PAGE ; j++,old_page_table++,new_page_table++) { + unsigned long pg; + pg = *old_page_table; + if (!pg) + continue; + if (!(pg & PAGE_PRESENT)) { + *new_page_table = swap_duplicate(pg); + continue; + } + if ((pg & (PAGE_RW | PAGE_COW)) == (PAGE_RW | PAGE_COW)) + pg &= ~PAGE_RW; + *new_page_table = pg; + if (mem_map[MAP_NR(pg)] & MAP_PAGE_RESERVED) + continue; + *old_page_table = pg; + mem_map[MAP_NR(pg)]++; + } + *new_page_dir = new_pg_table | PAGE_TABLE; + } + invalidate(); + return 0; +} + +/* + * a more complete version of free_page_tables which performs with page + * granularity. + */ +int unmap_page_range(unsigned long from, unsigned long size) +{ + unsigned long page, page_dir; + unsigned long *page_table, *dir; + unsigned long poff, pcnt, pc; + + if (from & ~PAGE_MASK) { + printk("unmap_page_range called with wrong alignment\n"); + return -EINVAL; + } + size = (size + ~PAGE_MASK) >> PAGE_SHIFT; + dir = PAGE_DIR_OFFSET(current->tss.cr3,from); + poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + if ((pcnt = PTRS_PER_PAGE - poff) > size) + pcnt = size; + + for ( ; size > 0; ++dir, size -= pcnt, + pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size)) { + if (!(page_dir = *dir)) { + poff = 0; + continue; + } + if (!(page_dir & PAGE_PRESENT)) { + printk("unmap_page_range: bad page directory."); + continue; + } + page_table = (unsigned long *)(PAGE_MASK & page_dir); + if (poff) { + page_table += poff; + poff = 0; + } + for (pc = pcnt; pc--; page_table++) { + if ((page = *page_table) != 0) { + *page_table = 0; + if (1 & page) { + if (!(mem_map[MAP_NR(page)] + & MAP_PAGE_RESERVED)) + --current->rss; + free_page(PAGE_MASK & page); + } else + swap_free(page); + } + } + if (pcnt == PTRS_PER_PAGE) { + *dir = 0; + free_page(PAGE_MASK & page_dir); + } + } + invalidate(); + return 0; +} + +int zeromap_page_range(unsigned long from, unsigned long size, int mask) +{ + unsigned long *page_table, *dir; + unsigned long poff, pcnt; + unsigned long page; + + if (mask) { + if ((mask & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT) { + printk("zeromap_page_range: mask = %08x\n",mask); + return -EINVAL; + } + mask |= ZERO_PAGE; + } + if (from & ~PAGE_MASK) { + printk("zeromap_page_range: from = %08lx\n",from); + return -EINVAL; + } + dir = PAGE_DIR_OFFSET(current->tss.cr3,from); + size = (size + ~PAGE_MASK) >> PAGE_SHIFT; + poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + if ((pcnt = PTRS_PER_PAGE - poff) > size) + pcnt = size; + + while (size > 0) { + if (!(PAGE_PRESENT & *dir)) { + /* clear page needed here? SRB. */ + if (!(page_table = (unsigned long*) get_free_page(GFP_KERNEL))) { + invalidate(); + return -ENOMEM; + } + if (PAGE_PRESENT & *dir) { + free_page((unsigned long) page_table); + page_table = (unsigned long *)(PAGE_MASK & *dir++); + } else + *dir++ = ((unsigned long) page_table) | PAGE_TABLE; + } else + page_table = (unsigned long *)(PAGE_MASK & *dir++); + page_table += poff; + poff = 0; + for (size -= pcnt; pcnt-- ;) { + if ((page = *page_table) != 0) { + *page_table = 0; + if (page & PAGE_PRESENT) { + if (!(mem_map[MAP_NR(page)] + & MAP_PAGE_RESERVED)) + --current->rss; + free_page(PAGE_MASK & page); + } else + swap_free(page); + } + *page_table++ = mask; + } + pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size); + } + invalidate(); + return 0; +} + +/* + * maps a range of physical memory into the requested pages. the old + * mappings are removed. any references to nonexistent pages results + * in null mappings (currently treated as "copy-on-access") + */ +int remap_page_range(unsigned long from, unsigned long to, unsigned long size, int mask) +{ + unsigned long *page_table, *dir; + unsigned long poff, pcnt; + unsigned long page; + + if (mask) { + if ((mask & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT) { + printk("remap_page_range: mask = %08x\n",mask); + return -EINVAL; + } + } + if ((from & ~PAGE_MASK) || (to & ~PAGE_MASK)) { + printk("remap_page_range: from = %08lx, to=%08lx\n",from,to); + return -EINVAL; + } + dir = PAGE_DIR_OFFSET(current->tss.cr3,from); + size = (size + ~PAGE_MASK) >> PAGE_SHIFT; + poff = (from >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + if ((pcnt = PTRS_PER_PAGE - poff) > size) + pcnt = size; + + while (size > 0) { + if (!(PAGE_PRESENT & *dir)) { + /* clearing page here, needed? SRB. */ + if (!(page_table = (unsigned long*) get_free_page(GFP_KERNEL))) { + invalidate(); + return -1; + } + *dir++ = ((unsigned long) page_table) | PAGE_TABLE; + } + else + page_table = (unsigned long *)(PAGE_MASK & *dir++); + if (poff) { + page_table += poff; + poff = 0; + } + + for (size -= pcnt; pcnt-- ;) { + if ((page = *page_table) != 0) { + *page_table = 0; + if (PAGE_PRESENT & page) { + if (!(mem_map[MAP_NR(page)] + & MAP_PAGE_RESERVED)) + --current->rss; + free_page(PAGE_MASK & page); + } else + swap_free(page); + } + + /* + * the first condition should return an invalid access + * when the page is referenced. current assumptions + * cause it to be treated as demand allocation in some + * cases. + */ + if (!mask) + *page_table++ = 0; /* not present */ + else if (to >= high_memory) + *page_table++ = (to | mask); + else if (!mem_map[MAP_NR(to)]) + *page_table++ = 0; /* not present */ + else { + *page_table++ = (to | mask); + if (!(mem_map[MAP_NR(to)] & MAP_PAGE_RESERVED)) { + ++current->rss; + mem_map[MAP_NR(to)]++; + } + } + to += PAGE_SIZE; + } + pcnt = (size > PTRS_PER_PAGE ? PTRS_PER_PAGE : size); + } + invalidate(); + return 0; +} + +/* + * This function puts a page in memory at the wanted address. + * It returns the physical address of the page gotten, 0 if + * out of memory (either when trying to access page-table or + * page.) + */ +unsigned long put_page(struct task_struct * tsk,unsigned long page, + unsigned long address,int prot) +{ + unsigned long *page_table; + + if ((prot & (PAGE_MASK|PAGE_PRESENT)) != PAGE_PRESENT) + printk("put_page: prot = %08x\n",prot); + if (page >= high_memory) { + printk("put_page: trying to put page %08lx at %08lx\n",page,address); + return 0; + } + page_table = PAGE_DIR_OFFSET(tsk->tss.cr3,address); + if ((*page_table) & PAGE_PRESENT) + page_table = (unsigned long *) (PAGE_MASK & *page_table); + else { + printk("put_page: bad page directory entry\n"); + oom(tsk); + *page_table = BAD_PAGETABLE | PAGE_TABLE; + return 0; + } + page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + if (*page_table) { + printk("put_page: page already exists\n"); + *page_table = 0; + invalidate(); + } + *page_table = page | prot; +/* no need for invalidate */ + return page; +} + +/* + * The previous function doesn't work very well if you also want to mark + * the page dirty: exec.c wants this, as it has earlier changed the page, + * and we want the dirty-status to be correct (for VM). Thus the same + * routine, but this time we mark it dirty too. + */ +unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsigned long address) +{ + unsigned long tmp, *page_table; + + if (page >= high_memory) + printk("put_dirty_page: trying to put page %08lx at %08lx\n",page,address); + if (mem_map[MAP_NR(page)] != 1) + printk("mem_map disagrees with %08lx at %08lx\n",page,address); + page_table = PAGE_DIR_OFFSET(tsk->tss.cr3,address); + if (PAGE_PRESENT & *page_table) + page_table = (unsigned long *) (PAGE_MASK & *page_table); + else { + if (!(tmp = get_free_page(GFP_KERNEL))) + return 0; + if (PAGE_PRESENT & *page_table) { + free_page(tmp); + page_table = (unsigned long *) (PAGE_MASK & *page_table); + } else { + *page_table = tmp | PAGE_TABLE; + page_table = (unsigned long *) tmp; + } + } + page_table += (address >> PAGE_SHIFT) & (PTRS_PER_PAGE-1); + if (*page_table) { + printk("put_dirty_page: page already exists\n"); + *page_table = 0; + invalidate(); + } + *page_table = page | (PAGE_DIRTY | PAGE_PRIVATE); +/* no need for invalidate */ + return page; +} + +/* + * This routine handles present pages, when users try to write + * to a shared page. It is done by copying the page to a new address + * and decrementing the shared-page counter for the old page. + * + * Note that we do many checks twice (look at do_wp_page()), as + * we have to be careful about race-conditions. + * + * Goto-purists beware: the only reason for goto's here is that it results + * in better assembly code.. The "default" path will see no jumps at all. + */ +static void __do_wp_page(unsigned long error_code, unsigned long address, + struct task_struct * tsk, unsigned long user_esp) +{ + unsigned long *pde, pte, old_page, prot; + unsigned long new_page; + + new_page = __get_free_page(GFP_KERNEL); + pde = PAGE_DIR_OFFSET(tsk->tss.cr3,address); + pte = *pde; + if (!(pte & PAGE_PRESENT)) + goto end_wp_page; + if ((pte & PAGE_TABLE) != PAGE_TABLE || pte >= high_memory) + goto bad_wp_pagetable; + pte &= PAGE_MASK; + pte += PAGE_PTR(address); + old_page = *(unsigned long *) pte; + if (!(old_page & PAGE_PRESENT)) + goto end_wp_page; + if (old_page >= high_memory) + goto bad_wp_page; + if (old_page & PAGE_RW) + goto end_wp_page; + tsk->min_flt++; + prot = (old_page & ~PAGE_MASK) | PAGE_RW; + old_page &= PAGE_MASK; + if (mem_map[MAP_NR(old_page)] != 1) { + if (new_page) { + if (mem_map[MAP_NR(old_page)] & MAP_PAGE_RESERVED) + ++tsk->rss; + copy_page(old_page,new_page); + *(unsigned long *) pte = new_page | prot; + free_page(old_page); + invalidate(); + return; + } + free_page(old_page); + oom(tsk); + *(unsigned long *) pte = BAD_PAGE | prot; + invalidate(); + return; + } + *(unsigned long *) pte |= PAGE_RW; + invalidate(); + if (new_page) + free_page(new_page); + return; +bad_wp_page: + printk("do_wp_page: bogus page at address %08lx (%08lx)\n",address,old_page); + *(unsigned long *) pte = BAD_PAGE | PAGE_SHARED; + send_sig(SIGKILL, tsk, 1); + goto end_wp_page; +bad_wp_pagetable: + printk("do_wp_page: bogus page-table at address %08lx (%08lx)\n",address,pte); + *pde = BAD_PAGETABLE | PAGE_TABLE; + send_sig(SIGKILL, tsk, 1); +end_wp_page: + if (new_page) + free_page(new_page); + return; +} + +/* + * check that a page table change is actually needed, and call + * the low-level function only in that case.. + */ +void do_wp_page(unsigned long error_code, unsigned long address, + struct task_struct * tsk, unsigned long user_esp) +{ + unsigned long page; + unsigned long * pg_table; + + pg_table = PAGE_DIR_OFFSET(tsk->tss.cr3,address); + page = *pg_table; + if (!page) + return; + if ((page & PAGE_PRESENT) && page < high_memory) { + pg_table = (unsigned long *) ((page & PAGE_MASK) + PAGE_PTR(address)); + page = *pg_table; + if (!(page & PAGE_PRESENT)) + return; + if (page & PAGE_RW) + return; + if (!(page & PAGE_COW)) { + if (user_esp && tsk == current) { + current->tss.cr2 = address; + current->tss.error_code = error_code; + current->tss.trap_no = 14; + send_sig(SIGSEGV, tsk, 1); + return; + } + } + if (mem_map[MAP_NR(page)] == 1) { + *pg_table |= PAGE_RW | PAGE_DIRTY; + invalidate(); + return; + } + __do_wp_page(error_code, address, tsk, user_esp); + return; + } + printk("bad page directory entry %08lx\n",page); + *pg_table = 0; +} + +int __verify_write(unsigned long start, unsigned long size) +{ + size--; + size += start & ~PAGE_MASK; + size >>= PAGE_SHIFT; + start &= PAGE_MASK; + do { + do_wp_page(1,start,current,0); + start += PAGE_SIZE; + } while (size--); + return 0; +} + +static inline void get_empty_page(struct task_struct * tsk, unsigned long address) +{ + unsigned long tmp; + + if (!(tmp = get_free_page(GFP_KERNEL))) { + oom(tsk); + tmp = BAD_PAGE; + } + if (!put_page(tsk,tmp,address,PAGE_PRIVATE)) + free_page(tmp); +} + +/* + * try_to_share() checks the page at address "address" in the task "p", + * to see if it exists, and if it is clean. If so, share it with the current + * task. + * + * NOTE! This assumes we have checked that p != current, and that they + * share the same executable or library. + * + * We may want to fix this to allow page sharing for PIC pages at different + * addresses so that ELF will really perform properly. As long as the vast + * majority of sharable libraries load at fixed addresses this is not a + * big concern. Any sharing of pages between the buffer cache and the + * code space reduces the need for this as well. - ERY + */ +static int try_to_share(unsigned long address, struct task_struct * tsk, + struct task_struct * p, unsigned long error_code, unsigned long newpage) +{ + unsigned long from; + unsigned long to; + unsigned long from_page; + unsigned long to_page; + + from_page = (unsigned long)PAGE_DIR_OFFSET(p->tss.cr3,address); + to_page = (unsigned long)PAGE_DIR_OFFSET(tsk->tss.cr3,address); +/* is there a page-directory at from? */ + from = *(unsigned long *) from_page; + if (!(from & PAGE_PRESENT)) + return 0; + from &= PAGE_MASK; + from_page = from + PAGE_PTR(address); + from = *(unsigned long *) from_page; +/* is the page clean and present? */ + if ((from & (PAGE_PRESENT | PAGE_DIRTY)) != PAGE_PRESENT) + return 0; + if (from >= high_memory) + return 0; + if (mem_map[MAP_NR(from)] & MAP_PAGE_RESERVED) + return 0; +/* is the destination ok? */ + to = *(unsigned long *) to_page; + if (!(to & PAGE_PRESENT)) + return 0; + to &= PAGE_MASK; + to_page = to + PAGE_PTR(address); + if (*(unsigned long *) to_page) + return 0; +/* share them if read - do COW immediately otherwise */ + if (error_code & PAGE_RW) { + if(!newpage) /* did the page exist? SRB. */ + return 0; + copy_page((from & PAGE_MASK),newpage); + to = newpage | PAGE_PRIVATE; + } else { + mem_map[MAP_NR(from)]++; + from &= ~PAGE_RW; + to = from; + if(newpage) /* only if it existed. SRB. */ + free_page(newpage); + } + *(unsigned long *) from_page = from; + *(unsigned long *) to_page = to; + invalidate(); + return 1; +} + +/* + * share_page() tries to find a process that could share a page with + * the current one. Address is the address of the wanted page relative + * to the current data space. + * + * We first check if it is at all feasible by checking executable->i_count. + * It should be >1 if there are other tasks sharing this inode. + */ +int share_page(struct vm_area_struct * area, struct task_struct * tsk, + struct inode * inode, + unsigned long address, unsigned long error_code, unsigned long newpage) +{ + struct task_struct ** p; + + if (!inode || inode->i_count < 2 || !area->vm_ops) + return 0; + for (p = &LAST_TASK ; p > &FIRST_TASK ; --p) { + if (!*p) + continue; + if (tsk == *p) + continue; + if (inode != (*p)->executable) { + if(!area) continue; + /* Now see if there is something in the VMM that + we can share pages with */ + if(area){ + struct vm_area_struct * mpnt; + for (mpnt = (*p)->mmap; mpnt; mpnt = mpnt->vm_next) { + if (mpnt->vm_ops == area->vm_ops && + mpnt->vm_inode->i_ino == area->vm_inode->i_ino&& + mpnt->vm_inode->i_dev == area->vm_inode->i_dev){ + if (mpnt->vm_ops->share(mpnt, area, address)) + break; + }; + }; + if (!mpnt) continue; /* Nope. Nuthin here */ + }; + } + if (try_to_share(address,tsk,*p,error_code,newpage)) + return 1; + } + return 0; +} + +/* + * fill in an empty page-table if none exists. + */ +static inline unsigned long get_empty_pgtable(struct task_struct * tsk,unsigned long address) +{ + unsigned long page; + unsigned long *p; + + p = PAGE_DIR_OFFSET(tsk->tss.cr3,address); + if (PAGE_PRESENT & *p) + return *p; + if (*p) { + printk("get_empty_pgtable: bad page-directory entry \n"); + *p = 0; + } + page = get_free_page(GFP_KERNEL); + p = PAGE_DIR_OFFSET(tsk->tss.cr3,address); + if (PAGE_PRESENT & *p) { + free_page(page); + return *p; + } + if (*p) { + printk("get_empty_pgtable: bad page-directory entry \n"); + *p = 0; + } + if (page) { + *p = page | PAGE_TABLE; + return *p; + } + oom(current); + *p = BAD_PAGETABLE | PAGE_TABLE; + return 0; +} + +void do_no_page(unsigned long error_code, unsigned long address, + struct task_struct *tsk, unsigned long user_esp) +{ + unsigned long tmp; + unsigned long page; + struct vm_area_struct * mpnt; + + page = get_empty_pgtable(tsk,address); + if (!page) + return; + page &= PAGE_MASK; + page += PAGE_PTR(address); + tmp = *(unsigned long *) page; + if (tmp & PAGE_PRESENT) + return; + ++tsk->rss; + if (tmp) { + ++tsk->maj_flt; + swap_in((unsigned long *) page); + return; + } + address &= 0xfffff000; + tmp = 0; + for (mpnt = tsk->mmap; mpnt != NULL; mpnt = mpnt->vm_next) { + if (address < mpnt->vm_start) + break; + if (address >= mpnt->vm_end) { + tmp = mpnt->vm_end; + continue; + } + if (!mpnt->vm_ops || !mpnt->vm_ops->nopage) { + ++tsk->min_flt; + get_empty_page(tsk,address); + return; + } + mpnt->vm_ops->nopage(error_code, mpnt, address); + return; + } + if (tsk != current) + goto ok_no_page; + if (address >= tsk->end_data && address < tsk->brk) + goto ok_no_page; + if (mpnt && mpnt == tsk->stk_vma && + address - tmp > mpnt->vm_start - address && + tsk->rlim[RLIMIT_STACK].rlim_cur > mpnt->vm_end - address) { + mpnt->vm_start = address; + goto ok_no_page; + } + tsk->tss.cr2 = address; + current->tss.error_code = error_code; + current->tss.trap_no = 14; + send_sig(SIGSEGV,tsk,1); + if (error_code & 4) /* user level access? */ + return; +ok_no_page: + ++tsk->min_flt; + get_empty_page(tsk,address); +} + +/* + * This routine handles page faults. It determines the address, + * and the problem, and then passes it off to one of the appropriate + * routines. + */ +asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +{ + unsigned long address; + unsigned long user_esp = 0; + unsigned int bit; + + /* get the address */ + __asm__("movl %%cr2,%0":"=r" (address)); + if (address < TASK_SIZE) { + if (error_code & 4) { /* user mode access? */ + if (regs->eflags & VM_MASK) { + bit = (address - 0xA0000) >> PAGE_SHIFT; + if (bit < 32) + current->screen_bitmap |= 1 << bit; + } else + user_esp = regs->esp; + } + if (error_code & 1) + do_wp_page(error_code, address, current, user_esp); + else + do_no_page(error_code, address, current, user_esp); + return; + } + address -= TASK_SIZE; + if (wp_works_ok < 0 && address == 0 && (error_code & PAGE_PRESENT)) { + wp_works_ok = 1; + pg0[0] = PAGE_SHARED; + printk("This processor honours the WP bit even when in supervisor mode. Good.\n"); + return; + } + 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 %08lx\n",address); + die_if_kernel("Oops", regs, error_code); + do_exit(SIGKILL); +} + +/* + * BAD_PAGE is the page that is used for page faults when linux + * is out-of-memory. Older versions of linux just did a + * do_exit(), but using this instead means there is less risk + * for a process dying in kernel mode, possibly leaving a inode + * unused etc.. + * + * BAD_PAGETABLE is the accompanying page-table: it is initialized + * to point to BAD_PAGE entries. + * + * ZERO_PAGE is a special page that is used for zero-initialized + * data and COW. + */ +unsigned long __bad_pagetable(void) +{ + extern char empty_bad_page_table[PAGE_SIZE]; + + __asm__ __volatile__("cld ; rep ; stosl": + :"a" (BAD_PAGE + PAGE_TABLE), + "D" ((long) empty_bad_page_table), + "c" (PTRS_PER_PAGE) + :"di","cx"); + return (unsigned long) empty_bad_page_table; +} + +unsigned long __bad_page(void) +{ + extern char empty_bad_page[PAGE_SIZE]; + + __asm__ __volatile__("cld ; rep ; stosl": + :"a" (0), + "D" ((long) empty_bad_page), + "c" (PTRS_PER_PAGE) + :"di","cx"); + return (unsigned long) empty_bad_page; +} + +unsigned long __zero_page(void) +{ + extern char empty_zero_page[PAGE_SIZE]; + + __asm__ __volatile__("cld ; rep ; stosl": + :"a" (0), + "D" ((long) empty_zero_page), + "c" (PTRS_PER_PAGE) + :"di","cx"); + return (unsigned long) empty_zero_page; +} + +void show_mem(void) +{ + int i,free = 0,total = 0,reserved = 0; + int shared = 0; + + printk("Mem-info:\n"); + printk("Free pages: %6dkB\n",nr_free_pages<<(PAGE_SHIFT-10)); + printk("Secondary pages: %6dkB\n",nr_secondary_pages<<(PAGE_SHIFT-10)); + printk("Free swap: %6dkB\n",nr_swap_pages<<(PAGE_SHIFT-10)); + printk("Buffer memory: %6dkB\n",buffermem>>10); + printk("Buffer heads: %6d\n",nr_buffer_heads); + printk("Buffer blocks: %6d\n",nr_buffers); + i = high_memory >> PAGE_SHIFT; + while (i-- > 0) { + total++; + if (mem_map[i] & MAP_PAGE_RESERVED) + reserved++; + else if (!mem_map[i]) + free++; + else + shared += mem_map[i]-1; + } + printk("%d pages of RAM\n",total); + printk("%d free pages\n",free); + printk("%d reserved pages\n",reserved); + printk("%d pages shared\n",shared); +} + +/* + * paging_init() sets up the page tables - note that the first 4MB are + * already mapped by head.S. + * + * This routines also unmaps the page at virtual kernel address 0, so + * that we can trap those pesky NULL-reference errors in the kernel. + */ +unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) +{ + unsigned long * pg_dir; + unsigned long * pg_table; + unsigned long tmp; + unsigned long address; + +/* + * Physical page 0 is special; it's not touched by Linux since BIOS + * and SMM (for laptops with [34]86/SL chips) may need it. It is read + * and write protected to detect null pointer references in the + * kernel. + */ +#if 0 + memset((void *) 0, 0, PAGE_SIZE); +#endif + start_mem = PAGE_ALIGN(start_mem); + address = 0; + pg_dir = swapper_pg_dir; + while (address < end_mem) { + tmp = *(pg_dir + 768); /* at virtual addr 0xC0000000 */ + if (!tmp) { + tmp = start_mem | PAGE_TABLE; + *(pg_dir + 768) = tmp; + start_mem += PAGE_SIZE; + } + *pg_dir = tmp; /* also map it in at 0x0000000 for init */ + pg_dir++; + pg_table = (unsigned long *) (tmp & PAGE_MASK); + for (tmp = 0 ; tmp < PTRS_PER_PAGE ; tmp++,pg_table++) { + if (address < end_mem) + *pg_table = address | PAGE_SHARED; + else + *pg_table = 0; + address += PAGE_SIZE; + } + } + invalidate(); + return start_mem; +} + +void mem_init(unsigned long start_low_mem, + unsigned long start_mem, unsigned long end_mem) +{ + int codepages = 0; + int reservedpages = 0; + int datapages = 0; + unsigned long tmp; + unsigned short * p; + extern int etext; + + cli(); + end_mem &= PAGE_MASK; + high_memory = end_mem; + start_mem += 0x0000000f; + start_mem &= ~0x0000000f; + tmp = MAP_NR(end_mem); + mem_map = (unsigned short *) start_mem; + p = mem_map + tmp; + start_mem = (unsigned long) p; + while (p > mem_map) + *--p = MAP_PAGE_RESERVED; + start_low_mem = PAGE_ALIGN(start_low_mem); + start_mem = PAGE_ALIGN(start_mem); + while (start_low_mem < 0xA0000) { + mem_map[MAP_NR(start_low_mem)] = 0; + start_low_mem += PAGE_SIZE; + } + while (start_mem < end_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) { + if (mem_map[MAP_NR(tmp)]) { + if (tmp >= 0xA0000 && tmp < 0x100000) + reservedpages++; + else if (tmp < (unsigned long) &etext) + codepages++; + else + datapages++; + continue; + } + *(unsigned long *) tmp = free_page_list; + free_page_list = tmp; + nr_free_pages++; + } + tmp = nr_free_pages << PAGE_SHIFT; + printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n", + tmp >> 10, + end_mem >> 10, + codepages << (PAGE_SHIFT-10), + reservedpages << (PAGE_SHIFT-10), + datapages << (PAGE_SHIFT-10)); +/* test if the WP bit is honoured in supervisor mode */ + wp_works_ok = -1; + pg0[0] = PAGE_READONLY; + invalidate(); + __asm__ __volatile__("movb 0,%%al ; movb %%al,0": : :"ax", "memory"); + pg0[0] = 0; + invalidate(); + if (wp_works_ok < 0) + wp_works_ok = 0; + return; +} + +void si_meminfo(struct sysinfo *val) +{ + int i; + + i = high_memory >> PAGE_SHIFT; + val->totalram = 0; + val->freeram = 0; + val->sharedram = 0; + val->bufferram = buffermem; + while (i-- > 0) { + if (mem_map[i] & MAP_PAGE_RESERVED) + continue; + val->totalram++; + if (!mem_map[i]) { + val->freeram++; + continue; + } + val->sharedram += mem_map[i]-1; + } + val->totalram <<= PAGE_SHIFT; + val->freeram <<= PAGE_SHIFT; + val->sharedram <<= PAGE_SHIFT; + return; +} + + +/* This handles a generic mmap of a disk file */ +void file_mmap_nopage(int error_code, struct vm_area_struct * area, unsigned long address) +{ + struct inode * inode = area->vm_inode; + unsigned int block; + unsigned long page; + int nr[8]; + int i, j; + int prot = area->vm_page_prot; + + address &= PAGE_MASK; + block = address - area->vm_start + area->vm_offset; + block >>= inode->i_sb->s_blocksize_bits; + + page = get_free_page(GFP_KERNEL); + if (share_page(area, area->vm_task, inode, address, error_code, page)) { + ++area->vm_task->min_flt; + return; + } + + ++area->vm_task->maj_flt; + if (!page) { + oom(current); + put_page(area->vm_task, BAD_PAGE, address, PAGE_PRIVATE); + return; + } + for (i=0, j=0; i< PAGE_SIZE ; j++, block++, i += inode->i_sb->s_blocksize) + nr[j] = bmap(inode,block); + 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 (!(prot & PAGE_RW)) { + if (share_page(area, area->vm_task, inode, address, error_code, page)) + return; + } + if (put_page(area->vm_task,page,address,prot)) + return; + free_page(page); + oom(current); +} + +void file_mmap_free(struct vm_area_struct * area) +{ + if (area->vm_inode) + iput(area->vm_inode); +#if 0 + if (area->vm_inode) + printk("Free inode %x:%d (%d)\n",area->vm_inode->i_dev, + area->vm_inode->i_ino, area->vm_inode->i_count); +#endif +} + +/* + * Compare the contents of the mmap entries, and decide if we are allowed to + * share the pages + */ +int file_mmap_share(struct vm_area_struct * area1, + struct vm_area_struct * area2, + unsigned long address) +{ + if (area1->vm_inode != area2->vm_inode) + return 0; + if (area1->vm_start != area2->vm_start) + return 0; + if (area1->vm_end != area2->vm_end) + return 0; + if (area1->vm_offset != area2->vm_offset) + return 0; + if (area1->vm_page_prot != area2->vm_page_prot) + return 0; + return 1; +} + +struct vm_operations_struct file_mmap = { + NULL, /* open */ + file_mmap_free, /* close */ + file_mmap_nopage, /* nopage */ + NULL, /* wppage */ + file_mmap_share, /* share */ + NULL, /* unmap */ +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/mm/mmap.c b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/mmap.c new file mode 100644 index 000000000..5fea243bd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/mmap.c @@ -0,0 +1,481 @@ +/* + * linux/mm/mmap.c + * + * Written by obz. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +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 + * behavior is in parens: + * + * map_type prot + * PROT_NONE PROT_READ PROT_WRITE PROT_EXEC + * MAP_SHARED r: (no) yes r: (yes) yes r: (no) yes r: (no) no + * w: (no) yes w: (no) copy w: (yes) yes w: (no) no + * x: (no) no x: (no) no x: (no) no x: (yes) no + * + * MAP_PRIVATE r: (no) yes r: (yes) yes r: (no) yes r: (no) no + * w: (no) copy w: (no) copy w: (copy) copy w: (no) no + * x: (no) no x: (no) no x: (no) no x: (yes) no + * + */ + +#define CODE_SPACE(addr) \ + (PAGE_ALIGN(addr) < current->start_code + current->end_code) + +int do_mmap(struct file * file, unsigned long addr, unsigned long len, + unsigned long prot, unsigned long flags, unsigned long off) +{ + int mask, error; + + if ((len = PAGE_ALIGN(len)) == 0) + return addr; + + if (addr > TASK_SIZE || len > TASK_SIZE || addr > TASK_SIZE-len) + return -EINVAL; + + /* + * do simple checking here so the lower-level routines won't have + * to. we assume access permissions have been handled by the open + * of the memory object, so we don't do any here. + */ + + 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. + */ + + if (flags & MAP_FIXED) { + if (addr & ~PAGE_MASK) + return -EINVAL; + if (len > TASK_SIZE || addr > TASK_SIZE - len) + return -EINVAL; + } else { + struct vm_area_struct * vmm; + + /* Maybe this works.. Ugly it is. */ + addr = SHM_RANGE_START; + while (addr+len < SHM_RANGE_END) { + for (vmm = current->mmap ; vmm ; vmm = vmm->vm_next) { + if (addr >= vmm->vm_end) + continue; + if (addr + len <= vmm->vm_start) + continue; + addr = PAGE_ALIGN(vmm->vm_end); + break; + } + if (!vmm) + break; + } + if (addr+len >= SHM_RANGE_END) + return -ENOMEM; + } + + /* + * determine the object being mapped and call the appropriate + * specific mapper. the address has already been validated, but + * not unmapped, but the maps are removed from the list. + */ + if (file && (!file->f_op || !file->f_op->mmap)) + return -ENODEV; + mask = 0; + if (prot & (PROT_READ | PROT_EXEC)) + mask |= PAGE_READONLY; + if (prot & PROT_WRITE) + if ((flags & MAP_TYPE) == MAP_PRIVATE) + mask |= PAGE_COW; + else + mask |= PAGE_RW; + if (!mask) + return -EINVAL; + + 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; + + if (!current->errno) + current->errno = -error; + return -1; +} + +asmlinkage int sys_mmap(unsigned long *buffer) +{ + int error; + unsigned long flags; + struct file * file = NULL; + + error = verify_area(VERIFY_READ, buffer, 6*4); + if (error) + return error; + flags = get_fs_long(buffer+3); + if (!(flags & MAP_ANONYMOUS)) { + unsigned long fd = get_fs_long(buffer+4); + if (fd >= NR_OPEN || !(file = current->filp[fd])) + return -EBADF; + } + return do_mmap(file, get_fs_long(buffer), get_fs_long(buffer+1), + get_fs_long(buffer+2), flags, 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=%lx-%lx, unmap %lx-%lx!!\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_offset += (end - area->vm_start); + 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_offset += (end - area->vm_start); + 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) +{ + 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 + */ +int do_munmap(unsigned long addr, size_t len) +{ + struct vm_area_struct *mpnt, **npp, *free; + + if ((addr & ~PAGE_MASK) || addr > TASK_SIZE || len > TASK_SIZE-addr) + return -EINVAL; + + if ((len = PAGE_ALIGN(len)) == 0) + return 0; + + /* + * Check if this memory area is ok - put it on the temporary + * 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. + */ + npp = ¤t->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; + } + + *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; + + 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; +} + +/* This is used for a general mmap of a disk file */ +int generic_mmap(struct inode * inode, struct file * file, + unsigned long addr, size_t len, int prot, unsigned long off) +{ + struct vm_area_struct * mpnt; + extern struct vm_operations_struct file_mmap; + struct buffer_head * bh; + + if (prot & PAGE_RW) /* only PAGE_COW or read-only supported right now */ + return -EINVAL; + if (off & (inode->i_sb->s_blocksize - 1)) + return -EINVAL; + if (!inode->i_sb || !S_ISREG(inode->i_mode)) + return -EACCES; + if (!inode->i_op || !inode->i_op->bmap) + return -ENOEXEC; + if (!(bh = bread(inode->i_dev,bmap(inode,0),inode->i_sb->s_blocksize))) + return -EACCES; + if (!IS_RDONLY(inode)) { + inode->i_atime = CURRENT_TIME; + inode->i_dirt = 1; + } + brelse(bh); + + mpnt = (struct vm_area_struct * ) kmalloc(sizeof(struct vm_area_struct), GFP_KERNEL); + if (!mpnt) + return -ENOMEM; + + unmap_page_range(addr, len); + 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 = &file_mmap; + 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 %lx-%lx in area %lx-%lx\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/gems-kernel.git/source/THIRDPARTY/linux-old/mm/swap.c b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/swap.c new file mode 100644 index 000000000..885abf1d7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/swap.c @@ -0,0 +1,851 @@ +/* + * linux/mm/swap.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This file should contain most things doing the swapping from/to disk. + * Started 18.12.91 + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#include /* for cli()/sti() */ +#include + +#define MAX_SWAPFILES 8 + +#define SWP_USED 1 +#define SWP_WRITEOK 3 + +#define SWP_TYPE(entry) (((entry) & 0xfe) >> 1) +#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT) +#define SWP_ENTRY(type,offset) (((type) << 1) | ((offset) << PAGE_SHIFT)) + +static int nr_swapfiles = 0; +static struct wait_queue * lock_queue = NULL; + +static struct swap_info_struct { + unsigned long flags; + struct inode * swap_file; + unsigned int swap_device; + unsigned char * swap_map; + unsigned char * swap_lockmap; + int pages; + int lowest_bit; + int highest_bit; + unsigned long max; +} swap_info[MAX_SWAPFILES]; + +extern unsigned long free_page_list; +extern int shm_swap (int); + +/* + * The following are used to make sure we don't thrash too much... + * NOTE!! NR_LAST_FREE_PAGES must be a power of 2... + */ +#define NR_LAST_FREE_PAGES 32 +static unsigned long last_free_pages[NR_LAST_FREE_PAGES] = {0,}; + +void rw_swap_page(int rw, unsigned long entry, char * buf) +{ + unsigned long type, offset; + struct swap_info_struct * p; + + type = SWP_TYPE(entry); + if (type >= nr_swapfiles) { + printk("Internal error: bad swap-device\n"); + return; + } + p = &swap_info[type]; + offset = SWP_OFFSET(entry); + if (offset >= p->max) { + printk("rw_swap_page: weirdness\n"); + return; + } + if (!(p->flags & SWP_USED)) { + printk("Trying to swap to unused swap-device\n"); + return; + } + while (set_bit(offset,p->swap_lockmap)) + sleep_on(&lock_queue); + if (rw == READ) + kstat.pswpin++; + else + kstat.pswpout++; + if (p->swap_device) { + ll_rw_page(rw,p->swap_device,offset,buf); + } else if (p->swap_file) { + unsigned int zones[8]; + unsigned int block; + int i, j; + + block = offset << (12 - p->swap_file->i_sb->s_blocksize_bits); + + for (i=0, j=0; j< PAGE_SIZE ; i++, j +=p->swap_file->i_sb->s_blocksize) + if (!(zones[i] = bmap(p->swap_file,block++))) { + printk("rw_swap_page: bad swap file\n"); + return; + } + 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 (offset && !clear_bit(offset,p->swap_lockmap)) + printk("rw_swap_page: lock already cleared\n"); + wake_up(&lock_queue); +} + +unsigned int get_swap_page(void) +{ + struct swap_info_struct * p; + unsigned int offset, type; + + p = swap_info; + for (type = 0 ; type < nr_swapfiles ; type++,p++) { + if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK) + continue; + for (offset = p->lowest_bit; offset <= p->highest_bit ; offset++) { + if (p->swap_map[offset]) + continue; + p->swap_map[offset] = 1; + nr_swap_pages--; + if (offset == p->highest_bit) + p->highest_bit--; + p->lowest_bit = offset; + return SWP_ENTRY(type,offset); + } + } + return 0; +} + +unsigned long swap_duplicate(unsigned long entry) +{ + struct swap_info_struct * p; + unsigned long offset, type; + + if (!entry) + return 0; + offset = SWP_OFFSET(entry); + type = SWP_TYPE(entry); + if (type == SHM_SWP_TYPE) + return entry; + if (type >= nr_swapfiles) { + printk("Trying to duplicate nonexistent swap-page\n"); + return 0; + } + p = type + swap_info; + if (offset >= p->max) { + printk("swap_free: weirdness\n"); + return 0; + } + if (!p->swap_map[offset]) { + printk("swap_duplicate: trying to duplicate unused page\n"); + return 0; + } + p->swap_map[offset]++; + return entry; +} + +void swap_free(unsigned long entry) +{ + struct swap_info_struct * p; + unsigned long offset, type; + + if (!entry) + return; + type = SWP_TYPE(entry); + if (type == SHM_SWP_TYPE) + return; + if (type >= nr_swapfiles) { + printk("Trying to free nonexistent swap-page\n"); + return; + } + p = & swap_info[type]; + offset = SWP_OFFSET(entry); + if (offset >= p->max) { + printk("swap_free: weirdness\n"); + return; + } + if (!(p->flags & SWP_USED)) { + printk("Trying to free swap from unused swap-device\n"); + return; + } + while (set_bit(offset,p->swap_lockmap)) + sleep_on(&lock_queue); + if (offset < p->lowest_bit) + p->lowest_bit = offset; + if (offset > p->highest_bit) + p->highest_bit = offset; + if (!p->swap_map[offset]) + printk("swap_free: swap-space map bad (entry %08lx)\n",entry); + else + if (!--p->swap_map[offset]) + nr_swap_pages++; + if (!clear_bit(offset,p->swap_lockmap)) + printk("swap_free: lock already cleared\n"); + wake_up(&lock_queue); +} + +void swap_in(unsigned long *table_ptr) +{ + unsigned long entry; + unsigned long page; + + entry = *table_ptr; + if (PAGE_PRESENT & entry) { + printk("trying to swap in present page\n"); + return; + } + if (!entry) { + printk("No swap page in swap_in\n"); + return; + } + if (SWP_TYPE(entry) == SHM_SWP_TYPE) { + shm_no_page ((unsigned long *) table_ptr); + return; + } + if (!(page = get_free_page(GFP_KERNEL))) { + oom(current); + page = BAD_PAGE; + } else + read_swap_page(entry, (char *) page); + if (*table_ptr != entry) { + free_page(page); + return; + } + *table_ptr = page | (PAGE_DIRTY | PAGE_PRIVATE); + swap_free(entry); +} + +static inline int try_to_swap_out(unsigned long * table_ptr) +{ + int i; + unsigned long page; + unsigned long entry; + + page = *table_ptr; + if (!(PAGE_PRESENT & page)) + return 0; + if (page >= high_memory) + return 0; + if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED) + return 0; + if (PAGE_ACCESSED & page) { + *table_ptr &= ~PAGE_ACCESSED; + return 0; + } + for (i = 0; i < NR_LAST_FREE_PAGES; i++) + if (last_free_pages[i] == (page & PAGE_MASK)) + return 0; + if (PAGE_DIRTY & page) { + page &= PAGE_MASK; + if (mem_map[MAP_NR(page)] != 1) + return 0; + if (!(entry = get_swap_page())) + return 0; + *table_ptr = entry; + invalidate(); + write_swap_page(entry, (char *) page); + free_page(page); + return 1; + } + page &= PAGE_MASK; + *table_ptr = 0; + invalidate(); + free_page(page); + return 1 + mem_map[MAP_NR(page)]; +} + +/* + * sys_idle() does nothing much: it just searches for likely candidates for + * swapping out or forgetting about. This speeds up the search when we + * actually have to swap. + */ +asmlinkage int sys_idle(void) +{ + need_resched = 1; + return 0; +} + +/* + * A new implementation of swap_out(). We do not swap complete processes, + * but only a small number of blocks, before we continue with the next + * process. The number of blocks actually swapped is determined on the + * number of page faults, that this process actually had in the last time, + * so we won't swap heavily used processes all the time ... + * + * Note: the priority argument is a hint on much CPU to waste with the + * swap block search, not a hint, of how much blocks to swap with + * each process. + * + * (C) 1993 Kai Petzke, wpp@marie.physik.tu-berlin.de + */ +#ifdef NEW_SWAP +/* + * These are the miminum and maximum number of pages to swap from one process, + * before proceeding to the next: + */ +#define SWAP_MIN 4 +#define SWAP_MAX 32 + +/* + * The actual number of pages to swap is determined as: + * SWAP_RATIO / (number of recent major page faults) + */ +#define SWAP_RATIO 128 + +static int swap_out(unsigned int priority) +{ + static int swap_task; + int table; + int page; + long pg_table; + int loop; + int counter = NR_TASKS * 2 >> priority; + struct task_struct *p; + + counter = NR_TASKS * 2 >> priority; + for(; counter >= 0; counter--, swap_task++) { + /* + * Check that swap_task is suitable for swapping. If not, look for + * the next suitable process. + */ + loop = 0; + while(1) { + if(swap_task >= NR_TASKS) { + swap_task = 1; + if(loop) + /* all processes are unswappable or already swapped out */ + return 0; + loop = 1; + } + + p = task[swap_task]; + if(p && p->swappable && p->rss) + break; + + swap_task++; + } + + /* + * Determine the number of pages to swap from this process. + */ + if(! p -> swap_cnt) { + p->dec_flt = (p->dec_flt * 3) / 4 + p->maj_flt - p->old_maj_flt; + p->old_maj_flt = p->maj_flt; + + if(p->dec_flt >= SWAP_RATIO / SWAP_MIN) { + p->dec_flt = SWAP_RATIO / SWAP_MIN; + p->swap_cnt = SWAP_MIN; + } else if(p->dec_flt <= SWAP_RATIO / SWAP_MAX) + p->swap_cnt = SWAP_MAX; + else + p->swap_cnt = SWAP_RATIO / p->dec_flt; + } + + /* + * Go through process' page directory. + */ + for(table = p->swap_table; table < 1024; table++) { + pg_table = ((unsigned long *) p->tss.cr3)[table]; + if(pg_table >= high_memory) + continue; + if(mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED) + continue; + if(!(PAGE_PRESENT & pg_table)) { + printk("swap_out: bad page-table at pg_dir[%d]: %08lx\n", + table, pg_table); + ((unsigned long *) p->tss.cr3)[table] = 0; + continue; + } + pg_table &= 0xfffff000; + + /* + * Go through this page table. + */ + for(page = p->swap_page; page < 1024; page++) { + switch(try_to_swap_out(page + (unsigned long *) pg_table)) { + case 0: + break; + + case 1: + p->rss--; + /* continue with the following page the next time */ + p->swap_table = table; + p->swap_page = page + 1; + if((--p->swap_cnt) == 0) + swap_task++; + return 1; + + default: + p->rss--; + break; + } + } + + p->swap_page = 0; + } + + /* + * Finish work with this process, if we reached the end of the page + * directory. Mark restart from the beginning the next time. + */ + p->swap_table = 0; + } + return 0; +} + +#else /* old swapping procedure */ + +/* + * Go through the page tables, searching for a user page that + * we can swap out. + * + * We now check that the process is swappable (normally only 'init' + * is un-swappable), allowing high-priority processes which cannot be + * swapped out (things like user-level device drivers (Not implemented)). + */ +static int swap_out(unsigned int priority) +{ + static int swap_task = 1; + static int swap_table = 0; + static int swap_page = 0; + int counter = NR_TASKS*8; + int pg_table; + struct task_struct * p; + + counter >>= priority; +check_task: + if (counter-- < 0) + return 0; + if (swap_task >= NR_TASKS) { + swap_task = 1; + goto check_task; + } + p = task[swap_task]; + if (!p || !p->swappable) { + swap_task++; + goto check_task; + } +check_dir: + if (swap_table >= PTRS_PER_PAGE) { + swap_table = 0; + swap_task++; + goto check_task; + } + pg_table = ((unsigned long *) p->tss.cr3)[swap_table]; + if (pg_table >= high_memory || (mem_map[MAP_NR(pg_table)] & MAP_PAGE_RESERVED)) { + swap_table++; + goto check_dir; + } + if (!(PAGE_PRESENT & pg_table)) { + printk("bad page-table at pg_dir[%d]: %08x\n", + swap_table,pg_table); + ((unsigned long *) p->tss.cr3)[swap_table] = 0; + swap_table++; + goto check_dir; + } + pg_table &= PAGE_MASK; +check_table: + if (swap_page >= PTRS_PER_PAGE) { + swap_page = 0; + swap_table++; + goto check_dir; + } + switch (try_to_swap_out(swap_page + (unsigned long *) pg_table)) { + case 0: break; + case 1: p->rss--; return 1; + default: p->rss--; + } + swap_page++; + goto check_table; +} + +#endif + +static int try_to_free_page(void) +{ + int i=6; + + while (i--) { + if (shrink_buffers(i)) + return 1; + if (shm_swap(i)) + return 1; + if (swap_out(i)) + return 1; + } + return 0; +} + +/* + * Note that this must be atomic, or bad things will happen when + * pages are requested in interrupts (as malloc can do). Thus the + * cli/sti's. + */ +static inline void add_mem_queue(unsigned long addr, unsigned long * queue) +{ + addr &= PAGE_MASK; + *(unsigned long *) addr = *queue; + *queue = addr; +} + +/* + * Free_page() adds the page to the free lists. This is optimized for + * fast normal cases (no error jumps taken normally). + * + * The way to optimize jumps for gcc-2.2.2 is to: + * - select the "normal" case and put it inside the if () { XXX } + * - no else-statements if you can avoid them + * + * With the above two rules, you get a straight-line execution path + * for the normal case, giving better asm-code. + */ +void free_page(unsigned long addr) +{ + if (addr < high_memory) { + unsigned short * map = mem_map + MAP_NR(addr); + + if (*map) { + if (!(*map & MAP_PAGE_RESERVED)) { + unsigned long flag; + + save_flags(flag); + cli(); + if (!--*map) { + if (nr_secondary_pages < MAX_SECONDARY_PAGES) { + add_mem_queue(addr,&secondary_page_list); + nr_secondary_pages++; + restore_flags(flag); + return; + } + add_mem_queue(addr,&free_page_list); + nr_free_pages++; + } + restore_flags(flag); + } + return; + } + printk("Trying to free free memory (%08lx): memory probabably corrupted\n",addr); + printk("PC = %08lx\n",*(((unsigned long *)&addr)-1)); + return; + } +} + +/* + * This is one ugly macro, but it simplifies checking, and makes + * this speed-critical place reasonably fast, especially as we have + * to do things with the interrupt flag etc. + * + * Note that this #define is heavily optimized to give fast code + * for the normal case - the if-statements are ordered so that gcc-2.2.2 + * will make *no* jumps for the normal code. Don't touch unless you + * know what you are doing. + */ +#define REMOVE_FROM_MEM_QUEUE(queue,nr) \ + cli(); \ + if ((result = queue) != 0) { \ + if (!(result & ~PAGE_MASK) && result < high_memory) { \ + queue = *(unsigned long *) result; \ + if (!mem_map[MAP_NR(result)]) { \ + mem_map[MAP_NR(result)] = 1; \ + nr--; \ +last_free_pages[index = (index + 1) & (NR_LAST_FREE_PAGES - 1)] = result; \ + restore_flags(flag); \ + return result; \ + } \ + printk("Free page %08lx has mem_map = %d\n", \ + result,mem_map[MAP_NR(result)]); \ + } else \ + printk("Result = 0x%08lx - memory map destroyed\n", result); \ + queue = 0; \ + nr = 0; \ + } else if (nr) { \ + printk(#nr " is %d, but " #queue " is empty\n",nr); \ + nr = 0; \ + } \ + restore_flags(flag) + +/* + * Get physical address of first (actually last :-) free page, and mark it + * used. If no free pages left, return 0. + * + * Note that this is one of the most heavily called functions in the kernel, + * so it's a bit timing-critical (especially as we have to disable interrupts + * in it). See the above macro which does most of the work, and which is + * optimized for a fast normal path of execution. + */ +unsigned long __get_free_page(int priority) +{ + unsigned long result, flag; + static unsigned long index = 0; + + /* this routine can be called at interrupt time via + malloc. We want to make sure that the critical + sections of code have interrupts disabled. -RAB + Is this code reentrant? */ + + save_flags(flag); +repeat: + REMOVE_FROM_MEM_QUEUE(free_page_list,nr_free_pages); + if (priority == GFP_BUFFER) + return 0; + if (priority != GFP_ATOMIC) + if (try_to_free_page()) + goto repeat; + REMOVE_FROM_MEM_QUEUE(secondary_page_list,nr_secondary_pages); + return 0; +} + +/* + * Trying to stop swapping from a file is fraught with races, so + * we repeat quite a bit here when we have to pause. swapoff() + * isn't exactly timing-critical, so who cares? + */ +static int try_to_unuse(unsigned int type) +{ + int nr, pgt, pg; + unsigned long page, *ppage; + unsigned long tmp = 0; + struct task_struct *p; + + nr = 0; +/* + * When we have to sleep, we restart the whole algorithm from the same + * task we stopped in. That at least rids us of all races. + */ +repeat: + for (; nr < NR_TASKS ; nr++) { + p = task[nr]; + if (!p) + continue; + for (pgt = 0 ; pgt < PTRS_PER_PAGE ; pgt++) { + ppage = pgt + ((unsigned long *) p->tss.cr3); + page = *ppage; + if (!page) + continue; + if (!(page & PAGE_PRESENT) || (page >= high_memory)) + continue; + if (mem_map[MAP_NR(page)] & MAP_PAGE_RESERVED) + continue; + ppage = (unsigned long *) (page & PAGE_MASK); + for (pg = 0 ; pg < PTRS_PER_PAGE ; pg++,ppage++) { + page = *ppage; + if (!page) + continue; + if (page & PAGE_PRESENT) + continue; + if (SWP_TYPE(page) != type) + continue; + if (!tmp) { + if (!(tmp = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + goto repeat; + } + read_swap_page(page, (char *) tmp); + if (*ppage == page) { + *ppage = tmp | (PAGE_DIRTY | PAGE_PRIVATE); + ++p->rss; + swap_free(page); + tmp = 0; + } + goto repeat; + } + } + } + free_page(tmp); + return 0; +} + +asmlinkage int sys_swapoff(const char * specialfile) +{ + struct swap_info_struct * p; + struct inode * inode; + unsigned int type; + int i; + + if (!suser()) + return -EPERM; + i = namei(specialfile,&inode); + if (i) + return i; + p = swap_info; + for (type = 0 ; type < nr_swapfiles ; type++,p++) { + if ((p->flags & SWP_WRITEOK) != SWP_WRITEOK) + continue; + if (p->swap_file) { + if (p->swap_file == inode) + break; + } else { + if (!S_ISBLK(inode->i_mode)) + continue; + if (p->swap_device == inode->i_rdev) + break; + } + } + iput(inode); + if (type >= nr_swapfiles) + return -EINVAL; + p->flags = SWP_USED; + i = try_to_unuse(type); + if (i) { + p->flags = SWP_WRITEOK; + return i; + } + nr_swap_pages -= p->pages; + iput(p->swap_file); + p->swap_file = NULL; + p->swap_device = 0; + vfree(p->swap_map); + p->swap_map = NULL; + free_page((long) p->swap_lockmap); + p->swap_lockmap = NULL; + p->flags = 0; + return 0; +} + +/* + * Written 01/25/92 by Simmule Turner, heavily changed by Linus. + * + * The swapon system call + */ +asmlinkage int sys_swapon(const char * specialfile) +{ + struct swap_info_struct * p; + struct inode * swap_inode; + unsigned int type; + int i,j; + int error; + + if (!suser()) + return -EPERM; + p = swap_info; + for (type = 0 ; type < nr_swapfiles ; type++,p++) + if (!(p->flags & SWP_USED)) + break; + if (type >= MAX_SWAPFILES) + return -EPERM; + if (type >= nr_swapfiles) + nr_swapfiles = type+1; + p->flags = SWP_USED; + p->swap_file = NULL; + p->swap_device = 0; + p->swap_map = NULL; + p->swap_lockmap = NULL; + p->lowest_bit = 0; + p->highest_bit = 0; + 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); + 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) + goto bad_swap; + } + } else if (S_ISREG(swap_inode->i_mode)) + p->swap_file = swap_inode; + else + goto bad_swap; + p->swap_lockmap = (unsigned char *) get_free_page(GFP_USER); + if (!p->swap_lockmap) { + printk("Unable to start swapping: out of memory :-)\n"); + 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"); + error = -EINVAL; + goto bad_swap; + } + memset(p->swap_lockmap+PAGE_SIZE-10,0,10); + j = 0; + p->lowest_bit = 0; + p->highest_bit = 0; + 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"); + error = -EINVAL; + goto bad_swap; + } + p->swap_map = (unsigned char *) 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 + 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) +{ + unsigned int i, j; + + val->freeswap = val->totalswap = 0; + for (i = 0; i < nr_swapfiles; i++) { + if (!(swap_info[i].flags & SWP_USED)) + continue; + for (j = 0; j < swap_info[i].max; ++j) + switch (swap_info[i].swap_map[j]) { + case 128: + continue; + case 0: + ++val->freeswap; + default: + ++val->totalswap; + } + } + val->freeswap <<= PAGE_SHIFT; + val->totalswap <<= PAGE_SHIFT; + return; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/mm/vmalloc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/vmalloc.c new file mode 100644 index 000000000..0dbd16d54 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/mm/vmalloc.c @@ -0,0 +1,202 @@ +/* + * linux/mm/vmalloc.c + * + * Copyright (C) 1993 Linus Torvalds + */ + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +struct vm_struct { + unsigned long flags; + void * addr; + unsigned long size; + struct vm_struct * next; +}; + +static struct vm_struct * vmlist = NULL; + +/* Just any arbitrary offset to the start of the vmalloc VM area: the + * current 8MB value just means that there will be a 8MB "hole" after the + * physical memory until the kernel virtual memory starts. That means that + * any out-of-bounds memory accesses will hopefully be caught. + * The vmalloc() routines leaves a hole of 4kB between each vmalloced + * area for the same reason. ;) + */ +#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; + do { + unsigned long pg = *pte; + *pte = 0; + if (pg & PAGE_PRESENT) + free_page(pg); + pte++; + } while (--nr); + pte = (unsigned long *) page; + for (nr = 0 ; nr < 1024 ; nr++, pte++) + if (*pte) + return 0; + set_pgdir(dindex,0); + mem_map[MAP_NR(page)] = 1; + free_page(page); + invalidate(); + 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() */ + do { + unsigned long pg = get_free_page(GFP_KERNEL); + + if (!pg) + return -ENOMEM; + *pte = pg | PAGE_SHARED; + pte++; + } while (--nr); + invalidate(); + 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; + nr -= i; + if (area_fn(dindex, index, i)) + return -1; + index = 0; + dindex++; + } + 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; +} + +int vread(char *buf, char *addr, int count) +{ + struct vm_struct **p, *tmp; + char *vaddr, *buf_start = buf; + int n; + + for (p = &vmlist; (tmp = *p) ; p = &tmp->next) { + vaddr = (char *) tmp->addr; + while (addr < vaddr) { + if (count == 0) + goto finished; + put_fs_byte('\0', buf++), addr++, count--; + } + n = tmp->size - PAGE_SIZE; + if (addr > vaddr) + n -= addr - vaddr; + while (--n >= 0) { + if (count == 0) + goto finished; + put_fs_byte(*addr++, buf++), count--; + } + } +finished: + return buf - buf_start; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/net/Makefile new file mode 100644 index 000000000..6478d1e33 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/Makefile @@ -0,0 +1,51 @@ +# +# Makefile for the linux networking. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +# only these two lines should need to be changed to remove inet sockets. +# (and the inet/tcpip.o in net.o) + +SUBDIRS := unix inet + +SUBOBJS := $(foreach f,$(SUBDIRS),$f/$f.o) + +.c.o: + $(CC) $(CFLAGS) -c $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) -S $< + +OBJS = Space.o ddi.o socket.o + +all: subdirs net.o + +net.o: $(OBJS) network.a + $(LD) -r -o net.o $(OBJS) network.a + +network.a: $(SUBOBJS) + rm -f $@ + ar rc $@ $(SUBOBJS) + ranlib $@ + +subdirs: dummy + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i; done + +dep: + $(CPP) -M *.c > .depend + set -e; for i in $(SUBDIRS); do $(MAKE) -C $$i dep; done + +dummy: + +# +# include a dependency file if one exists +# +ifeq (.depend,$(wildcard .depend)) +include .depend +endif + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/Space.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/Space.c new file mode 100644 index 000000000..b2cc011ad --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/Space.c @@ -0,0 +1,95 @@ +/* + * Space.c Defines which protocol modules and I/O device drivers get + * linked into the LINUX kernel. Currently, this is only used + * by the NET layer of LINUX, but it eventually might move to + * an upper directory of the system. + * + * Version: @(#)Space.c 1.0.2 04/22/93 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include + + +#define CONFIG_UNIX YES /* always present... */ + + +/* + * Section A: Networking Protocol Handlers. + * This section defines which networking protocols get + * linked into the SOCKET layer of the Linux kernel. + * Currently, these are AF_UNIX (always) and AF_INET. + */ +#ifdef CONFIG_UNIX +# include "unix/unix.h" +#endif +#ifdef CONFIG_INET +# include "inet/inet.h" +#endif +#ifdef CONFIG_IPX +#include "inet/ipxcall.h" +#endif +#ifdef CONFIG_AX25 +#include "inet/ax25call.h" +#endif + +struct ddi_proto protocols[] = { +#ifdef CONFIG_UNIX + { "UNIX", unix_proto_init }, +#endif +#ifdef CONFIG_IPX + { "IPX", ipx_proto_init }, +#endif +#ifdef CONFIG_AX25 + { "AX.25", ax25_proto_init }, +#endif +#ifdef CONFIG_INET + { "INET", inet_proto_init }, +#endif + { NULL, NULL } +}; + + +/* + * Section B: Device Driver Modules. + * This section defines which network device drivers + * get linked into the Linux kernel. It is currently + * only used by the INET protocol. Any takers for the + * other protocols like XNS or Novell? + * + * WARNING: THIS SECTION IS NOT YET USED BY THE DRIVERS !!!!! + */ +/*#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 */ + + +struct ddi_device devices[] = { +#if CONF_WE8003 + { "WD80x3[EBT]", + "", 0, 1, we8003_init, NULL, + 19, 0, DDI_FCHRDEV, + { 0x280, 0, 15, 0, 32768, 0xD0000 } }, +#endif +#if CONF_DP8390 + { "DP8390/WD80x3", + "", 0, 1, dpwd8003_init, NULL, + 20, 0, DDI_FCHRDEV, + { 0, 0, 0, 0, 0, 0, } }, + { "DP8390/NE-x000", + "", 0, 1, dpne2000_init, NULL, + 20, 8, DDI_FCHRDEV, + { 0, 0, 0, 0, 0, 0, } }, + { "DP8390/3C50x", + "", 0, 1, dpec503_init, NULL, + 20, 16, DDI_FCHRDEV, + { 0, 0, 0, 0, 0, 0, } }, +#endif + { NULL, + "", 0, 0, NULL, NULL, + 0, 0, 0, + { 0, 0, 0, 0, 0, 0 } } +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/ddi.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/ddi.c new file mode 100644 index 000000000..7ebd3bf29 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/ddi.c @@ -0,0 +1,91 @@ +/* + * ddi.c Implement the Device Driver Interface (DDI) routines. + * Currently, this is only used by the NET layer of LINUX, + * but it eventually might move to an upper directory of + * the system. + * + * Version: @(#)ddi.c 1.0.5 04/22/93 + * + * Author: Fred N. van Kempen, + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +#undef DDI_DEBUG +#ifdef DDI_DEBUG +# define PRINTK(x) printk x +#else +# define PRINTK(x) /**/ +#endif + + +extern struct ddi_device devices[]; /* device driver map */ +extern struct ddi_proto protocols[]; /* network protocols */ + + +/* + * This function gets called with an ASCII string representing the + * ID of some DDI driver. We loop through the DDI Devices table + * and return the address of the control block that has a matching + * "name" field. It is used by upper-level layers that want to + * dynamically bind some UNIX-domain "/dev/XXXX" file name to a + * DDI device driver. The "iflink(8)" program is an example of + * this behaviour. + */ +struct ddi_device * +ddi_map(const char *id) +{ + register struct ddi_device *dev; + + PRINTK (("DDI: MAP: looking for \"%s\": ", id)); + dev = devices; + while (dev->title != NULL) { + if (strncmp(dev->name, id, DDI_MAXNAME) == 0) { + PRINTK (("OK at 0x%X\n", dev)); + return(dev); + } + dev++; + } + PRINTK (("NOT FOUND\n")); + return(NULL); +} + + +/* + * This is the function that is called by a kernel routine during + * system startup. Its purpose is to walk trough the "devices" + * table (defined above), and to call all moduled defined in it. + */ +void +ddi_init(void) +{ + struct ddi_proto *pro; + struct ddi_device *dev; + + PRINTK (("DDI: Starting up!\n")); + + /* First off, kick all configured protocols. */ + pro = protocols; + while (pro->name != NULL) { + (*pro->init)(pro); + pro++; + } + + /* Done. Now kick all configured device drivers. */ + dev = devices; + while (dev->title != NULL) { + (*dev->init)(dev); + dev++; + } + + /* We're all done... */ +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/Makefile new file mode 100644 index 000000000..a10caa33e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/Makefile @@ -0,0 +1,46 @@ +# +# Makefile for the Linix TCP/IP (INET) layer. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< + + +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 +# ipx.o ax25.o ax25_in.o ax25_out.o ax25_subr.o ax25_timer.o + +ifdef CONFIG_INET + +inet.o: $(OBJS) + $(LD) -r -o inet.o $(OBJS) + +else + +inet.o: + echo | $(AS) -o inet.o + +endif + +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/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/README b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/README new file mode 100644 index 000000000..79f957ff2 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/README @@ -0,0 +1,44 @@ + +NET2Debugged 1.24 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. +o MSG_PEEK is faster again +o Minor TCP fixes. Hopefully no more TCP lockups (ha!) +o Donald's promiscuous mode. Go forth and write protocol analysers... +------------------------------------------------------------------------- +NOTE: + Drivers for this stack set must be using alloc_skb() not just +kmalloc. If you get millions of 'non sk_buff...' errors please check the +driver you are using. All Donald's drivers know about this. If you have +a problem driver replace all cases of + + .. =(struct sk_buff *)kmalloc(sizeof(struct sk_buff)+... + +With + ..=alloc_skb(sizeof(struct sk_buff)+... + +And if it uses kfree_s on the packet change that to use kfree_skbmem(). + +------------------------------------------------------------------------- +Bug fixes and improvements for this section of the code should be mailed to +iiitac@pyr.swan.ac.uk. + + +Alan diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.c new file mode 100644 index 000000000..71384af13 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.c @@ -0,0 +1,951 @@ +/* + * 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. + * + * This file implements the Address Resolution Protocol (ARP), + * which is used by TCP/IP to map the IP addresses from a host + * to a low-level hardware address (like an Ethernet address) + * which it can use to talk to that host. + * + * NOTE: This module will be rewritten completely in the near future, + * because I want it to become a multi-address-family address + * resolver, like it should be. It will be put in a separate + * directory under 'net', being a protocol of its own. -FvK + * + * Version: @(#)arp.c 1.0.15 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Stephen A. Wood, + * Arnt Gulbrandsen, + * + * 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 + * Alan Cox : Proxy arp. + * Alan Cox : skb->link3 maintained by letting the other xmit queue kill the packet. + * Alan Cox : Knows about type 3 devices (AX.25) using an AX.25 protocol ID not the ethernet + * one. + * Dominik Kubla : Better checking + * Tegge : Assorted corrections on cross port stuff + * Alan Cox : ATF_PERM was backwards! - might be useful now (sigh) + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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" + + +#define ARP_MAX_TRIES 3 + + +static char *unk_print(unsigned char *, int); +static char *eth_aprint(unsigned char *, int); + + +static char *arp_cmds[] = { + "0x%04X", + "REQUEST", + "REPLY", + "REVERSE REQUEST", + "REVERSE REPLY", + NULL +}; +#define ARP_MAX_CMDS (sizeof(arp_cmds) / sizeof(arp_cmds[0])) + +static struct { + char *name; + char *(*print)(unsigned char *ptr, int len); +} arp_types[] = { + { "0x%04X", unk_print }, + { "10 Mbps Ethernet", eth_aprint }, + { "3 Mbps Ethernet", eth_aprint }, + { "AX.25", unk_print }, + { "Pronet", unk_print }, + { "Chaos", unk_print }, + { "IEEE 802.2 Ethernet (?)", eth_aprint }, + { "Arcnet", unk_print }, + { "AppleTalk", unk_print }, + { NULL, NULL } +}; +#define ARP_MAX_TYPE (sizeof(arp_types) / sizeof(arp_types[0])) + + +struct arp_table *arp_tables[ARP_TABLE_SIZE] = { + NULL, +}; + +static int arp_proxies=0; /* So we can avoid the proxy arp + overhead with the usual case of + no proxy arps */ + +struct sk_buff * volatile arp_q = NULL; + +static struct arp_table *arp_lookup(unsigned long addr); +static struct arp_table *arp_lookup_proxy(unsigned long addr); + +/* Dump the ADDRESS bytes of an unknown hardware type. */ +static char * +unk_print(unsigned char *ptr, int len) +{ + static char buff[32]; + char *bufp = buff; + int i; + + for (i = 0; i < len; i++) + bufp += sprintf(bufp, "%02X ", (*ptr++ & 0377)); + return(buff); +} + + +/* Dump the ADDRESS bytes of an Ethernet hardware type. */ +static char * +eth_aprint(unsigned char *ptr, int len) +{ + if (len != ETH_ALEN) return(""); + return(eth_print(ptr)); +} + + +/* Dump an ARP packet. Not complete yet for non-Ethernet packets. */ +static void +arp_print(struct arphdr *arp) +{ + int len, idx; + unsigned char *ptr; + + if (inet_debug != DBG_ARP) return; + + printk("ARP: "); + if (arp == NULL) { + printk("(null)\n"); + return; + } + + /* Print the opcode name. */ + len = htons(arp->ar_op); + if (len < ARP_MAX_CMDS) idx = len; + else idx = 0; + printk("op "); + printk(arp_cmds[idx], len); + + /* Print the ARP header. */ + len = htons(arp->ar_hrd); + if (len < ARP_MAX_TYPE) idx = len; + else idx = 0; + printk(" hrd = "); printk(arp_types[idx].name, len); + printk(" pro = 0x%04X\n", htons(arp->ar_pro)); + printk(" hlen = %d plen = %d\n", arp->ar_hln, arp->ar_pln); + + /* + * Print the variable data. + * When ARP gets redone (after the formal introduction of NET-2), + * this part will be redone. ARP will then be a multi-family address + * resolver, and the code below will be made more general. -FvK + */ + ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); + printk(" sender HA = %s ", arp_types[idx].print(ptr, arp->ar_hln)); + ptr += arp->ar_hln; + printk(" PA = %s\n", in_ntoa(*(unsigned long *) ptr)); + ptr += arp->ar_pln; + printk(" target HA = %s ", arp_types[idx].print(ptr, arp->ar_hln)); + ptr += arp->ar_hln; + printk(" PA = %s\n", in_ntoa(*(unsigned long *) ptr)); +} + + +/* This will try to retransmit everything on the queue. */ +static void +arp_send_q(void) +{ + struct sk_buff *skb; + struct sk_buff *volatile work_q; + cli(); + work_q = arp_q; + skb_new_list_head(&work_q); + arp_q = NULL; + sti(); + while((skb=skb_dequeue(&work_q))!=NULL) + { + IS_SKB(skb); + skb->magic = 0; + skb->next = NULL; + skb->prev = NULL; + + /* Decrement the 'tries' counter. */ + cli(); + skb->tries--; + if (skb->tries == 0) { + /* + * Grmpf. + * We have tried ARP_MAX_TRIES to resolve the IP address + * from this datagram. This means that the machine does + * not listen to our ARP requests. Perhaps someone tur- + * ned off the thing? + * In any case, trying further is useless. So, we kill + * this packet from the queue. (grinnik) -FvK + */ + skb->sk = NULL; + if(skb->free) + kfree_skb(skb, FREE_WRITE); + /* If free was 0, magic is now 0, next is 0 and + the write queue will notice and kill */ + sti(); + continue; + } + + /* Can we now complete this packet? */ + sti(); + if (skb->arp || !skb->dev->rebuild_header(skb->data, skb->dev)) { + skb->arp = 1; + skb->dev->queue_xmit(skb, skb->dev, 0); + } else { + /* Alas. Re-queue it... */ + skb->magic = ARP_QUEUE_MAGIC; + skb_queue_head(&arp_q,skb); + } + } +} + + +/* Create and send our response to an ARP request. */ +static int +arp_response(struct arphdr *arp1, struct device *dev, int addrtype) +{ + struct arphdr *arp2; + struct sk_buff *skb; + unsigned long src, dst; + unsigned char *ptr1, *ptr2; + int hlen; + struct arp_table *apt = NULL;/* =NULL otherwise the compiler gives warnings */ + + /* Decode the source (REQUEST) message. */ + ptr1 = ((unsigned char *) &arp1->ar_op) + sizeof(u_short); + src = *((unsigned long *) (ptr1 + arp1->ar_hln)); + dst = *((unsigned long *) (ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln)); + + if(addrtype!=IS_MYADDR) + { + apt=arp_lookup_proxy(dst); + if(apt==NULL) + return(1); + } + + /* Get some mem and initialize it for the return trip. */ + skb = alloc_skb(sizeof(struct sk_buff) + + sizeof(struct arphdr) + + (2 * arp1->ar_hln) + (2 * arp1->ar_pln) + + dev->hard_header_len, GFP_ATOMIC); + if (skb == NULL) { + printk("ARP: no memory available for ARP REPLY!\n"); + return(1); + } + + skb->mem_addr = skb; + skb->len = sizeof(struct arphdr) + (2 * arp1->ar_hln) + + (2 * arp1->ar_pln) + dev->hard_header_len; + skb->mem_len = sizeof(struct sk_buff) + skb->len; + hlen = dev->hard_header(skb->data, 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); + } + + /* + * Fill in the ARP REPLY packet. + * This looks ugly, but we have to deal with the variable-length + * ARP packets and such. It is not as bad as it looks- FvK + */ + arp2 = (struct arphdr *) (skb->data + hlen); + ptr2 = ((unsigned char *) &arp2->ar_op) + sizeof(u_short); + arp2->ar_hrd = arp1->ar_hrd; + arp2->ar_pro = arp1->ar_pro; + arp2->ar_hln = arp1->ar_hln; + arp2->ar_pln = arp1->ar_pln; + arp2->ar_op = htons(ARPOP_REPLY); + if(addrtype==IS_MYADDR) + memcpy(ptr2, dev->dev_addr, arp2->ar_hln); + else /* Proxy arp, so pull from the table */ + memcpy(ptr2, apt->ha, arp2->ar_hln); + ptr2 += arp2->ar_hln; + memcpy(ptr2, ptr1 + (arp1->ar_hln * 2) + arp1->ar_pln, arp2->ar_pln); + ptr2 += arp2->ar_pln; + memcpy(ptr2, ptr1, arp2->ar_hln); + ptr2 += arp2->ar_hln; + memcpy(ptr2, ptr1 + arp1->ar_hln, arp2->ar_pln); + + skb->free = 1; + skb->arp = 1; + skb->sk = NULL; + skb->next = NULL; + + DPRINTF((DBG_ARP, ">>")); + arp_print(arp2); + + /* Queue the packet for transmission. */ + dev->queue_xmit(skb, dev, 0); + return(0); +} + + +/* This will find an entry in the ARP table by looking at the IP address. */ +static struct arp_table * +arp_lookup(unsigned long paddr) +{ + struct arp_table *apt; + unsigned long hash; + + DPRINTF((DBG_ARP, "ARP: lookup(%s)\n", in_ntoa(paddr))); + + /* We don't want to ARP ourselves. */ + if (chk_addr(paddr) == IS_MYADDR) { + printk("ARP: ARPing my own IP address %s !\n", in_ntoa(paddr)); + return(NULL); + } + + /* Loop through the table for the desired address. */ + hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); + cli(); + apt = arp_tables[hash]; + while(apt != NULL) { + if (apt->ip == paddr) { + sti(); + return(apt); + } + apt = apt->next; + } + sti(); + return(NULL); +} + + +/* This will find a proxy in the ARP table by looking at the IP address. */ +static struct arp_table *arp_lookup_proxy(unsigned long paddr) +{ + struct arp_table *apt; + unsigned long hash; + + DPRINTF((DBG_ARP, "ARP: lookup proxy(%s)\n", in_ntoa(paddr))); + + /* Loop through the table for the desired address. */ + hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); + cli(); + apt = arp_tables[hash]; + while(apt != NULL) { + if (apt->ip == paddr && (apt->flags & ATF_PUBL) ) { + sti(); + return(apt); + } + apt = apt->next; + } + sti(); + return(NULL); +} + + +/* Delete an ARP mapping entry in the cache. */ +void +arp_destructor(unsigned long paddr, int force) +{ + struct arp_table *apt; + struct arp_table **lapt; + unsigned long hash; + + DPRINTF((DBG_ARP, "ARP: destroy(%s)\n", in_ntoa(paddr))); + + /* We cannot destroy our own ARP entry. */ + if (chk_addr(paddr) == IS_MYADDR) { + DPRINTF((DBG_ARP, "ARP: Destroying my own IP address %s !\n", + in_ntoa(paddr))); + return; + } + hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); + + cli(); + lapt = &arp_tables[hash]; + while ((apt = *lapt) != NULL) { + if (apt->ip == paddr) { + if((apt->flags&ATF_PERM) && !force) + return; + *lapt = apt->next; + if(apt->flags&ATF_PUBL) + arp_proxies--; + kfree_s(apt, sizeof(struct arp_table)); + sti(); + return; + } + lapt = &apt->next; + } + sti(); +} + +/* + * Kill an entry - eg for ioctl() + */ + +void arp_destroy(unsigned long paddr) +{ + arp_destructor(paddr,1); +} + +/* + * Delete a possibly invalid entry (see timer.c) + */ + +void arp_destroy_maybe(unsigned long paddr) +{ + arp_destructor(paddr,0); +} + +/* Create an ARP entry. The caller should check for duplicates! */ +static struct arp_table * +arp_create(unsigned long paddr, unsigned char *addr, int hlen, int htype) +{ + struct arp_table *apt; + unsigned long hash; + + DPRINTF((DBG_ARP, "ARP: create(%s, ", in_ntoa(paddr))); + DPRINTF((DBG_ARP, "%s, ", eth_print(addr))); + DPRINTF((DBG_ARP, "%d, %d)\n", hlen, htype)); + + apt = (struct arp_table *) kmalloc(sizeof(struct arp_table), GFP_ATOMIC); + if (apt == NULL) { + printk("ARP: no memory available for new ARP entry!\n"); + return(NULL); + } + + /* Fill in the allocated ARP cache entry. */ + hash = htonl(paddr) & (ARP_TABLE_SIZE - 1); + apt->ip = paddr; + apt->hlen = hlen; + apt->htype = htype; + apt->flags = (ATF_INUSE | ATF_COM); /* USED and COMPLETED entry */ + memcpy(apt->ha, addr, hlen); + apt->last_used = jiffies; + cli(); + apt->next = arp_tables[hash]; + arp_tables[hash] = apt; + sti(); + return(apt); +} + + +/* + * An ARP REQUEST packet has arrived. + * We try to be smart here, and fetch the data of the sender of the + * packet- we might need it later, so fetching it now can save us a + * broadcast later. + * Then, if the packet was meant for us (i.e. the TARGET address was + * one of our own IP addresses), we set up and send out an ARP REPLY + * packet to the sender. + */ +int +arp_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct arphdr *arp; + struct arp_table *tbl; + unsigned long src, dst; + unsigned char *ptr; + int ret; + int addr_hint; + + DPRINTF((DBG_ARP, "<<\n")); + arp = skb->h.arp; + arp_print(arp); + + /* 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(0x00CC) && dev->type==3) || (arp->ar_pro != NET16(ETH_P_IP) && dev->type!=3) ) || arp->ar_pln != 4) + { + if (arp->ar_op != NET16(ARPOP_REQUEST)) + DPRINTF((DBG_ARP,"ARP: Non-IP request on device \"%s\" !\n", dev->name)); + kfree_skb(skb, FREE_READ); + return(0); + } + + /* + * As said before, we try to be smart by using the + * info already present in the packet: the sender's + * IP and hardware address. + */ + ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); + memcpy(&src, ptr + arp->ar_hln, arp->ar_pln); + tbl = arp_lookup(src); + if (tbl != NULL) { + DPRINTF((DBG_ARP, "ARP: udating entry for %s\n", in_ntoa(src))); + memcpy(tbl->ha, ptr, arp->ar_hln); + tbl->hlen = arp->ar_hln; + tbl->flags |= ATF_COM; + tbl->last_used = jiffies; + } else { + memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); + if (chk_addr(dst) != IS_MYADDR && arp_proxies == 0) { + kfree_skb(skb, FREE_READ); + return(0); + } else { + tbl = arp_create(src, ptr, arp->ar_hln, arp->ar_hrd); + if (tbl == NULL) { + kfree_skb(skb, FREE_READ); + return(0); + } + } + } + + /* + * Since we updated the ARP cache, we might have enough + * information to send out some previously queued IP + * datagrams.... + */ + arp_send_q(); + + /* + * OK, we used that part of the info. Now check if the + * 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(chk_addr(dst)==IS_BROADCAST) + { + kfree_skb(skb, FREE_READ); + return 0; + } + + memcpy(&dst, ptr + (arp->ar_hln * 2) + arp->ar_pln, arp->ar_pln); + if ((addr_hint=chk_addr(dst)) != IS_MYADDR && arp_proxies==0) { + DPRINTF((DBG_ARP, "ARP: request was not for me!\n")); + kfree_skb(skb, FREE_READ); + return(0); + } + + /* + * Yes, it is for us. + * Allocate, fill in and send an ARP REPLY packet. + */ + ret = arp_response(arp, dev, addr_hint); + kfree_skb(skb, FREE_READ); + return(ret); +} + + +/* Create and send an ARP REQUEST packet. */ +void +arp_send(unsigned long paddr, struct device *dev, unsigned long saddr) +{ + struct sk_buff *skb; + struct arphdr *arp; + unsigned char *ptr; + int tmp; + + DPRINTF((DBG_ARP, "ARP: send(paddr=%s, ", in_ntoa(paddr))); + DPRINTF((DBG_ARP, "dev=%s, ", dev->name)); + DPRINTF((DBG_ARP, "saddr=%s)\n", in_ntoa(saddr))); + + skb = alloc_skb(sizeof(struct sk_buff) + + sizeof(struct arphdr) + (2 * dev->addr_len) + + dev->hard_header_len + + (2 * 4 /* arp->plen */), GFP_ATOMIC); + if (skb == NULL) { + printk("ARP: No memory available for REQUEST %s\n", in_ntoa(paddr)); + return; + } + + /* Fill in the request. */ + skb->sk = NULL; + skb->mem_addr = skb; + skb->len = sizeof(struct arphdr) + + dev->hard_header_len + (2 * dev->addr_len) + 8; + skb->mem_len = sizeof(struct sk_buff) + skb->len; + skb->arp = 1; + skb->dev = dev; + skb->next = NULL; + skb->free = 1; + tmp = dev->hard_header(skb->data, dev, ETH_P_ARP, 0, saddr, skb->len); + if (tmp < 0) { + kfree_skb(skb,FREE_WRITE); + return; + } + arp = (struct arphdr *) (skb->data + tmp); + arp->ar_hrd = htons(dev->type); + if(dev->type!=3) /* AX.25 */ + arp->ar_pro = htons(ETH_P_IP); + else + arp->ar_pro = htons(0xCC); + arp->ar_hln = dev->addr_len; + arp->ar_pln = 4; + arp->ar_op = htons(ARPOP_REQUEST); + + ptr = ((unsigned char *) &arp->ar_op) + sizeof(u_short); + memcpy(ptr, dev->dev_addr, arp->ar_hln); + ptr += arp->ar_hln; + memcpy(ptr, &saddr, arp->ar_pln); + ptr += arp->ar_pln; + /*memcpy(ptr, dev->broadcast, arp->ar_hln);*/ + memset(ptr,0,arp->ar_hln); + ptr += arp->ar_hln; + memcpy(ptr, &paddr, arp->ar_pln); + + DPRINTF((DBG_ARP, ">>\n")); + arp_print(arp); + dev->queue_xmit(skb, dev, 0); +} + + +/* Find an ARP mapping in the cache. If not found, post a REQUEST. */ +int +arp_find(unsigned char *haddr, unsigned long paddr, struct device *dev, + unsigned long saddr) +{ + struct arp_table *apt; + + DPRINTF((DBG_ARP, "ARP: find(haddr=%s, ", eth_print(haddr))); + DPRINTF((DBG_ARP, "paddr=%s, ", in_ntoa(paddr))); + DPRINTF((DBG_ARP, "dev=%s, saddr=%s)\n", dev->name, in_ntoa(saddr))); + + switch(chk_addr(paddr)) { + case IS_MYADDR: + memcpy(haddr, dev->dev_addr, dev->addr_len); + return(0); + case IS_BROADCAST: + memcpy(haddr, dev->broadcast, dev->addr_len); + return(0); + } + + apt = arp_lookup(paddr); + if (apt != NULL) { + /* + * Make sure it's not too old. If it is too old, we will + * just pretend we did not find it, and then arp_send will + * verify the address for us. + */ + if ((apt->flags & ATF_PERM) || + (apt->last_used < jiffies+ARP_TIMEOUT && apt->hlen != 0)) { + apt->last_used = jiffies; + memcpy(haddr, apt->ha, dev->addr_len); + return(0); + } else { + DPRINTF((DBG_ARP, "ARP: find: found expired entry for %s\n", + in_ntoa(apt->ip))); + } + } + + /* + * This assume haddr are at least 4 bytes. + * If this isn't true we can use a lookup table, one for every dev. + * NOTE: this bit of code still looks fishy to me- FvK + */ + *(unsigned long *)haddr = paddr; + + /* If we didn't find an entry, we will try to send an ARP packet. */ + arp_send(paddr, dev, saddr); + + return(1); +} + + +/* Add an entry to the ARP cache. Check for dupes! */ +void +arp_add(unsigned long addr, unsigned char *haddr, struct device *dev) +{ + struct arp_table *apt; + + DPRINTF((DBG_ARP, "ARP: add(%s, ", in_ntoa(addr))); + DPRINTF((DBG_ARP, "%s, ", eth_print(haddr))); + DPRINTF((DBG_ARP, "%d, %d)\n", dev->hard_header_len, dev->type)); + + /* This is probably a good check... */ + if (addr == 0) { + printk("ARP: add: will not add entry for 0.0.0.0 !\n"); + return; + } + + /* First see if the address is already in the table. */ + apt = arp_lookup(addr); + if (apt != NULL) { + DPRINTF((DBG_ARP, "ARP: updating entry for %s\n", in_ntoa(addr))); + apt->last_used = jiffies; + memcpy(apt->ha, haddr , dev->addr_len); + return; + } + arp_create(addr, haddr, dev->addr_len, dev->type); +} + + +/* Create an ARP entry for a device's broadcast address. */ +void +arp_add_broad(unsigned long addr, struct device *dev) +{ + struct arp_table *apt; + + arp_add(addr, dev->broadcast, dev); + apt = arp_lookup(addr); + if (apt != NULL) { + apt->flags |= ATF_PERM; + } +} + + +/* Queue an IP packet, while waiting for the ARP reply packet. */ +void +arp_queue(struct sk_buff *skb) +{ + cli(); + skb->tries = ARP_MAX_TRIES; + + if (skb->next != NULL) { + sti(); + printk("ARP: arp_queue skb already on queue magic=%X.\n", skb->magic); + return; + } + skb_queue_tail(&arp_q,skb); + skb->magic = ARP_QUEUE_MAGIC; + sti(); +} + + +/* + * Write the contents of the ARP cache to a PROCfs file. + * This is not by long perfect, as the internal ARP table doesn't + * have all the info we would like to have. Oh well, it works for + * now, eh? - FvK + * Also note, that due to space limits, we cannot generate more than + * 4Kbyte worth of data. This usually is enough, but I have seen + * machines die from under me because of a *very* large ARP cache. + * This can be simply tested by doing: + * + * # ping 255.255.255.255 + * # arp -a + * + * Perhaps we should redo PROCfs to handle larger buffers? Michael? + */ +int +arp_get_info(char *buffer) +{ + struct arpreq *req; + struct arp_table *apt; + int i; + char *pos; + + /* Loop over the ARP table and copy structures to the buffer. */ + pos = buffer; + i = 0; + for (i = 0; i < ARP_TABLE_SIZE; i++) { + cli(); + apt = arp_tables[i]; + sti(); + while (apt != NULL) { + if (pos < (buffer + 4000)) { + req = (struct arpreq *) pos; + memset((char *) req, 0, sizeof(struct arpreq)); + req->arp_pa.sa_family = AF_INET; + memcpy((char *) req->arp_pa.sa_data, (char *) &apt->ip, 4); + req->arp_ha.sa_family = apt->htype; + memcpy((char *) req->arp_ha.sa_data, + (char *) &apt->ha, apt->hlen); + req->arp_flags = apt->flags; + } + pos += sizeof(struct arpreq); + cli(); + apt = apt->next; + sti(); + } + } + return(pos - buffer); +} + + +/* Set (create) an ARP cache entry. */ +static int +arp_req_set(struct arpreq *req) +{ + struct arpreq r; + struct arp_table *apt; + struct sockaddr_in *si; + int htype, hlen; + + /* We only understand about IP addresses... */ + memcpy_fromfs(&r, req, sizeof(r)); + if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT); + + /* + * Find out about the hardware type. + * We have to be compatible with BSD UNIX, so we have to + * assume that a "not set" value (i.e. 0) means Ethernet. + */ + si = (struct sockaddr_in *) &r.arp_pa; + switch(r.arp_ha.sa_family) { + case 0: + case ARPHRD_ETHER: + htype = ARPHRD_ETHER; + hlen = ETH_ALEN; + break; + case ARPHRD_AX25: + htype = ARPHRD_AX25; + hlen = 7; + break; + + default: + return(-EPFNOSUPPORT); + } + + /* Is there an existing entry for this address? */ + if (si->sin_addr.s_addr == 0) { + printk("ARP: SETARP: requested PA is 0.0.0.0 !\n"); + return(-EINVAL); + } + apt = arp_lookup(si->sin_addr.s_addr); + if (apt == NULL) { + apt = arp_create(si->sin_addr.s_addr, + (unsigned char *) r.arp_ha.sa_data, hlen, htype); + if (apt == NULL) return(-ENOMEM); + } + + /* We now have a pointer to an ARP entry. Update it! */ + memcpy((char *) &apt->ha, (char *) &r.arp_ha.sa_data, hlen); + apt->last_used = jiffies; + apt->flags = r.arp_flags; + if(apt->flags&ATF_PUBL) + arp_proxies++; /* Count proxy arps so we know if to use it */ + + return(0); +} + + +/* Get an ARP cache entry. */ +static int +arp_req_get(struct arpreq *req) +{ + struct arpreq r; + struct arp_table *apt; + struct sockaddr_in *si; + + /* We only understand about IP addresses... */ + memcpy_fromfs(&r, req, sizeof(r)); + if (r.arp_pa.sa_family != AF_INET) return(-EPFNOSUPPORT); + + /* Is there an existing entry for this address? */ + si = (struct sockaddr_in *) &r.arp_pa; + apt = arp_lookup(si->sin_addr.s_addr); + if (apt == NULL) return(-ENXIO); + + /* We found it; copy into structure. */ + memcpy((char *) r.arp_ha.sa_data, (char *) &apt->ha, apt->hlen); + r.arp_ha.sa_family = apt->htype; + + /* Copy the information back */ + memcpy_tofs(req, &r, sizeof(r)); + return(0); +} + + +/* Delete an ARP cache entry. */ +static int +arp_req_del(struct arpreq *req) +{ + struct arpreq r; + struct sockaddr_in *si; + + /* We only understand about IP addresses... */ + memcpy_fromfs(&r, req, sizeof(r)); + 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); +} + + +/* Handle an ARP layer I/O control request. */ +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); + } + /*NOTREACHED*/ + return(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.h new file mode 100644 index 000000000..57f41ac1b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/arp.h @@ -0,0 +1,64 @@ +/* + * 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 ARP protocol module. + * + * Version: @(#)arp.h 1.0.6 05/21/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _ARP_H +#define _ARP_H + +#define ARP_TABLE_SIZE 16 /* size of ARP table */ +#define ARP_TIMEOUT 30000 /* five minutes */ +#define ARP_RES_TIME 250 /* 2.5 seconds */ + +#define ARP_MAX_TRIES 3 /* max # of tries to send ARP */ +#define ARP_QUEUE_MAGIC 0x0432447A /* magic # for queues */ + + +/* This structure defines the ARP mapping cache. */ +struct arp_table { + struct arp_table *next; + volatile unsigned long last_used; + unsigned int flags; +#if 1 + unsigned long ip; +#else + unsigned char pa[MAX_ADDR_LEN]; + unsigned char plen; + unsigned char ptype; +#endif + unsigned char ha[MAX_ADDR_LEN]; + unsigned char hlen; + unsigned char htype; +}; + + +/* This is also used in "sock.c" and "tcp.c" - YUCK! - FvK */ +extern struct sk_buff *arp_q; + + +extern void arp_destroy(unsigned long paddr); +extern int arp_rcv(struct sk_buff *skb, struct device *dev, + struct packet_type *pt); +extern int arp_find(unsigned char *haddr, unsigned long paddr, + struct device *dev, unsigned long saddr); +extern void arp_add(unsigned long addr, unsigned char *haddr, + struct device *dev); +extern void arp_add_broad(unsigned long addr, struct device *dev); +extern void arp_queue(struct sk_buff *skb); +extern int arp_get_info(char *buffer); +extern int arp_ioctl(unsigned int cmd, void *arg); +extern void arp_destroy_maybe(unsigned long paddr); + +#endif /* _ARP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/datagram.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/datagram.c new file mode 100644 index 000000000..7d0687eed --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/datagram.c @@ -0,0 +1,205 @@ +/* + * 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 . (datagram_select() from old udp.c code) + * + * Fixes: + * Alan Cox : NULL return from skb_peek_copy() understood + * Alan Cox : Rewrote skb_read_datagram to avoid the skb_peek_copy stuff. + * Alan Cox : Added support for SOCK_SEQPACKET. IPX can no longer use the SO_TYPE hack but + * AX.25 now works right, and SPX is feasible. + * Alan Cox : Fixed write select of non IP protocol crash. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 */ +restart: + 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; + } + + if(sk->err) + { + release_sock(sk); + *err=-sk->err; + sk->err=0; + return NULL; + } + + /* Sequenced packets can come disconnected. If so we report the problem */ + if(sk->type==SOCK_SEQPACKET && sk->state!=TCP_ESTABLISHED) + { + release_sock(sk); + *err=-ENOTCONN; + 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); + if(skb!=NULL) + skb->users++; + else + goto restart; /* Avoid race if someone beats us to the data */ + } + else + { + cli(); + skb=skb_peek(&sk->rqueue); + if(skb!=NULL) + skb->users++; + sti(); + if(skb==NULL) /* shouldn't happen but .. */ + *err=-EAGAIN; + } + return skb; +} + +void skb_free_datagram(struct sk_buff *skb) +{ + unsigned long flags; + + save_flags(flags); + cli(); + skb->users--; + if(skb->users>0) + { + restore_flags(flags); + return; + } + /* See if it needs destroying */ + if(skb->list == NULL) /* Been dequeued by someone - ie its read */ + kfree_skb(skb,FREE_READ); + restore_flags(flags); +} + +void skb_copy_datagram(struct sk_buff *skb, int offset, char *to, int size) +{ + /* We will know all about the fraglist options to allow >4K receives + but not this release */ + memcpy_tofs(to,skb->h.raw+offset,size); +} + +/* + * Datagram select: Again totally generic. Moved from udp.c + * Now does seqpacket. + */ + +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->type==SOCK_SEQPACKET && sk->state==TCP_CLOSE) + { + /* Connection closed: Wake up */ + return(1); + } + 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); + } + if (sk->prot==NULL && sk->sndbuf-sk->wmem_alloc >= 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/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.c new file mode 100644 index 000000000..22002f0f4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.c @@ -0,0 +1,1073 @@ +/* + * 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. + * + * Interface (streams) handling functions. + * + * Version: @(#)dev.c 1.0.19 05/31/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * + * 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. + * Alan Cox: ip_addr_match problems with class A/B nets. + * C.E.Hawkins IP 0.0.0.0 and also same net route fix. [FIXME: Ought to cause ICMP_REDIRECT] + * Alan Cox: Removed bogus subnet check now the subnet code + * a) actually works for all A/B nets + * b) doesn't forward off the same interface. + * Alan Cox: Multiple extra protocols + * Alan Cox: Fixed ifconfig up of dud device setting the up flag + * Alan Cox: Fixed verify_area errors + * Alan Cox: Removed IP_SET_DEV as per Fred's comment. I hope this doesn't give + * anything away 8) + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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" +#ifdef CONFIG_AX25 +#include "ax25.h" +#endif + + +#ifdef CONFIG_IPX + +static struct packet_type ipx_8023_type = { + NET16(ETH_P_802_3), + 0, + ipx_rcv, + NULL, + NULL +}; + +static struct packet_type ipx_packet_type = { + NET16(ETH_P_IPX), + 0, + ipx_rcv, + NULL, + &ipx_8023_type +}; + +#endif + +#ifdef CONFIG_AX25 + +static struct packet_type ax25_packet_type = { + NET16(ETH_P_AX25), + 0, + ax25_rcv, + NULL, +#ifdef CONFIG_IPX + &ipx_packet_type +#else + NULL +#endif +}; +#endif + + +static struct packet_type arp_packet_type = { + NET16(ETH_P_ARP), + 0, /* copy */ + arp_rcv, + NULL, +#ifdef CONFIG_IPX +#ifndef CONFIG_AX25 + &ipx_packet_type +#else + &ax25_packet_type +#endif +#else +#ifdef CONFIG_AX25 + &ax25_packet_type +#else + NULL /* next */ +#endif +#endif +}; + + +static struct packet_type ip_packet_type = { + NET16(ETH_P_IP), + 0, /* copy */ + ip_rcv, + NULL, + &arp_packet_type +}; + + +struct packet_type *ptype_base = &ip_packet_type; +static struct sk_buff *volatile backlog = NULL; +static unsigned long ip_bcast = 0; + + +/* Return the lesser of the two values. */ +static unsigned long +min(unsigned long a, unsigned long b) +{ + if (a < b) return(a); + return(b); +} + + +/* Determine a default network mask, based on the IP address. */ +static unsigned long +get_mask(unsigned long addr) +{ + unsigned long dst; + + 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)); + + /* Something else, probably a subnet. */ + return(0); +} + + +int +ip_addr_match(unsigned long me, unsigned long him) +{ + int i; + unsigned long mask=0xFFFFFFFF; + DPRINTF((DBG_DEV, "ip_addr_match(%s, ", in_ntoa(me))); + DPRINTF((DBG_DEV, "%s)\n", in_ntoa(him))); + + if (me == him) + return(1); + for (i = 0; i < 4; i++, me >>= 8, him >>= 8, mask >>= 8) { + if ((me & 0xFF) != (him & 0xFF)) { + /* + * The only way this could be a match is for + * the rest of addr1 to be 0 or 255. + */ + if (me != 0 && me != mask) return(0); + return(1); + } + } + return(1); +} + + +/* Check the address for our address, broadcasts, etc. */ +int +chk_addr(unsigned long addr) +{ + struct device *dev; + unsigned long dst; + + DPRINTF((DBG_DEV, "chk_addr(%s) --> ", in_ntoa(addr))); + dst = ntohl(addr); + + /* Accept both `all ones' and `all zeros' as BROADCAST. */ + if (dst == INADDR_ANY || dst == INADDR_BROADCAST) { + DPRINTF((DBG_DEV, "BROADCAST\n")); + return(IS_BROADCAST); + } + + /* Accept all of the `loopback' class A net. */ + if ((dst & IN_CLASSA_NET) == 0x7F000000L) { + DPRINTF((DBG_DEV, "LOOPBACK\n")); + + /* + * We force `loopback' to be equal to MY_ADDR. + */ + return(IS_MYADDR); + /* return(IS_LOOPBACK); */ + } + + /* OK, now check the interface addresses. */ + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (!(dev->flags&IFF_UP)) + continue; + if ((dev->pa_addr == 0)/* || (dev->flags&IFF_PROMISC)*/) + return(IS_MYADDR); + /* Is it the exact IP address? */ + if (addr == dev->pa_addr) { + DPRINTF((DBG_DEV, "MYADDR\n")); + return(IS_MYADDR); + } + + /* Nope. Check for a subnetwork broadcast. */ + if ((addr & dev->pa_mask) == (dev->pa_addr & dev->pa_mask)) { + if ((addr & ~dev->pa_mask) == 0) { + DPRINTF((DBG_DEV, "SUBBROADCAST-0\n")); + return(IS_BROADCAST); + } + if (((addr & ~dev->pa_mask) | dev->pa_mask) + == INADDR_BROADCAST) { + DPRINTF((DBG_DEV, "SUBBROADCAST-1\n")); + return(IS_BROADCAST); + } + } + + /* Nope. Check for Network broadcast. */ + if(IN_CLASSA(dst)) { + if( addr == (dev->pa_addr | 0xffffff00)) { + DPRINTF((DBG_DEV, "CLASS A BROADCAST-1\n")); + return(IS_BROADCAST); + } + } + else if(IN_CLASSB(dst)) { + if( addr == (dev->pa_addr | 0xffff0000)) { + DPRINTF((DBG_DEV, "CLASS B BROADCAST-1\n")); + return(IS_BROADCAST); + } + } + else { /* IN_CLASSC */ + if( addr == (dev->pa_addr | 0xff000000)) { + DPRINTF((DBG_DEV, "CLASS C BROADCAST-1\n")); + return(IS_BROADCAST); + } + } + } + + DPRINTF((DBG_DEV, "NONE\n")); + + return(0); /* no match at all */ +} + + +/* + * Retrieve our own address. + * Because the loopback address (127.0.0.1) is already recognized + * automatically, we can use the loopback interface's address as + * our "primary" interface. This is the addressed used by IP et + * al when it doesn't know which address to use (i.e. it does not + * yet know from or to which interface to go...). + */ +unsigned long +my_addr(void) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (dev->flags & IFF_LOOPBACK) return(dev->pa_addr); + } + return(0); +} + + +static int dev_nit=0; /* Number of network taps running */ + +/* Add a protocol ID to the list. This will change soon. */ +void +dev_add_pack(struct packet_type *pt) +{ + struct packet_type *p1; + pt->next = ptype_base; + + /* Don't use copy counts on ETH_P_ALL. Instead keep a global + count of number of these and use it and pt->copy to decide + copies */ + pt->copy=0; + if(pt->type==NET16(ETH_P_ALL)) + dev_nit++; /* I'd like a /dev/nit too one day 8) */ + else + { + /* See if we need to copy it. */ + for (p1 = ptype_base; p1 != NULL; p1 = p1->next) { + if (p1->type == pt->type) { + pt->copy = 1; + break; + } + } + } + + /* + * NIT taps must go at the end or inet_bh will leak! + */ + + if(pt->type==NET16(ETH_P_ALL)) + { + pt->next=NULL; + if(ptype_base==NULL) + ptype_base=pt; + else + { + for(p1=ptype_base;p1->next!=NULL;p1=p1->next); + p1->next=pt; + } + } + else + ptype_base = pt; +} + + +/* Remove a protocol ID from the list. This will change soon. */ +void +dev_remove_pack(struct packet_type *pt) +{ + struct packet_type *lpt, *pt1; + + if (pt->type == NET16(ETH_P_ALL)) + dev_nit--; + if (pt == ptype_base) { + ptype_base = pt->next; + return; + } + + lpt = NULL; + for (pt1 = ptype_base; pt1->next != NULL; pt1 = pt1->next) { + if (pt1->next == pt ) { + cli(); + if (!pt->copy && lpt) + lpt->copy = 0; + pt1->next = pt->next; + sti(); + return; + } + + if (pt1->next -> type == pt ->type && pt->type != NET16(ETH_P_ALL)) { + lpt = pt1->next; + } + } +} + + +/* Find an interface in the list. This will change soon. */ +struct device * +dev_get(char *name) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (strcmp(dev->name, name) == 0) + return(dev); + } + return(NULL); +} + + +/* Find an interface that can handle addresses for a certain address. */ +struct device * dev_check(unsigned long addr) +{ + struct device *dev; + + for (dev = dev_base; dev; dev = dev->next) { + if (!(dev->flags & IFF_UP)) + continue; + if (!(dev->flags & IFF_POINTOPOINT)) + continue; + if (addr != dev->pa_dstaddr) + continue; + return dev; + } + for (dev = dev_base; dev; dev = dev->next) { + if (!(dev->flags & IFF_UP)) + continue; + if (dev->flags & IFF_POINTOPOINT) + continue; + if (dev->pa_mask & (addr ^ dev->pa_addr)) + continue; + return dev; + } + return NULL; +} + + +/* Prepare an interface for use. */ +int +dev_open(struct device *dev) +{ + int ret = 0; + + if (dev->open) + ret = dev->open(dev); + if (ret == 0) + dev->flags |= (IFF_UP | IFF_RUNNING); + + return(ret); +} + + +/* Completely shutdown an interface. */ +int +dev_close(struct device *dev) +{ + if (dev->flags != 0) { + int ct=0; + dev->flags = 0; + 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(ctbuffs[ct]))!=NULL) + if(skb->free) + kfree_skb(skb,FREE_WRITE); + ct++; + } + } + + return(0); +} + + +/* Send (or queue for sending) a packet. */ +void +dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) +{ + int where = 0; /* used to say if the packet should go */ + /* at the front or the back of the */ + /* queue. */ + + DPRINTF((DBG_DEV, "dev_queue_xmit(skb=%X, dev=%X, pri = %d)\n", + skb, dev, pri)); + + if (dev == NULL) { + 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. */ + dev->hard_start_xmit(NULL, dev); + return; + } + + if (pri < 0) { + pri = -pri-1; + where = 1; + } + + if (pri >= DEV_NUMBUFFS) { + printk("bad priority in dev_queue_xmit.\n"); + pri = 1; + } + + if (dev->hard_start_xmit(skb, dev) == 0) { + return; + } + + /* Put skb into a bidirectional circular linked list. */ + DPRINTF((DBG_DEV, "dev_queue_xmit dev->buffs[%d]=%X\n", + pri, dev->buffs[pri])); + + /* Interrupts should already be cleared by hard_start_xmit. */ + cli(); + 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(); +} + +/* + * Receive a packet from a device driver and queue it for the upper + * (protocol) levels. It always succeeds. + */ +void +netif_rx(struct sk_buff *skb) +{ + /* Set any necessary flags. */ + skb->sk = NULL; + skb->free = 1; + + /* and add it to the "backlog" queue. */ + IS_SKB(skb); + skb_queue_tail(&backlog,skb); + + /* If any packet arrived, mark it for processing. */ + if (backlog != NULL) mark_bh(INET_BH); + + return; +} + + +/* + * The old interface to fetch a packet from a device driver. + * This function is the base level entry point for all drivers that + * want to send a packet to the upper (protocol) levels. It takes + * care of de-multiplexing the packet to the various modules based + * on their protocol ID. + * + * Return values: 1 <- exit I can't do any more + * 0 <- feed me more (i.e. "done", "OK"). + */ +int +dev_rint(unsigned char *buff, long len, int flags, struct device *dev) +{ + static int dropping = 0; + struct sk_buff *skb = NULL; + unsigned char *to; + int amount, left; + int len2; + + if (dev == NULL || buff == NULL || len <= 0) return(1); + if (flags & IN_SKBUFF) { + skb = (struct sk_buff *) buff; + } else { + if (dropping) { + if (backlog != NULL) + return(1); + printk("INET: dev_rint: no longer dropping packets.\n"); + dropping = 0; + } + + 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->mem_len = sizeof(*skb) + len; + skb->mem_addr = (struct sk_buff *) skb; + + /* First we copy the packet into a buffer, and save it for later. */ + to = skb->data; + left = len; + len2 = len; + while (len2 > 0) { + amount = min(len2, (unsigned long) dev->rmem_end - + (unsigned long) buff); + memcpy(to, buff, amount); + len2 -= amount; + left -= amount; + buff += amount; + to += amount; + if ((unsigned long) buff == dev->rmem_end) + buff = (unsigned char *) dev->rmem_start; + } + } + skb->len = len; + skb->dev = dev; + skb->free = 1; + + netif_rx(skb); + /* OK, all done. */ + return(0); +} + + +/* This routine causes all interfaces to try to send some data. */ +void +dev_transmit(void) +{ + struct device *dev; + + for (dev = dev_base; dev != NULL; dev = dev->next) { + if (!dev->tbusy) { + dev_tint(dev); + } + } +} + +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) +{ + struct sk_buff *skb; + struct packet_type *ptype; + unsigned short type; + unsigned char flag = 0; + int nitcount; + + /* Atomically check and mark our BUSY state. */ + if (set_bit(1, (void*)&in_bh)) + return; + + /* Can we send anything now? */ + dev_transmit(); + + /* Any data left to process? */ + while((skb=skb_dequeue(&backlog))!=NULL) + { + nitcount=dev_nit; + flag=0; + sti(); + /* + * Bump the pointer to the next structure. + * This assumes that the basic 'skb' pointer points to + * the MAC header, if any (as indicated by its "length" + * field). Take care now! + */ + skb->h.raw = skb->data + skb->dev->hard_header_len; + skb->len -= skb->dev->hard_header_len; + + /* + * Fetch the packet protocol ID. This is also quite ugly, as + * it depends on the protocol driver (the interface itself) to + * know what the type is, or where to get it from. The Ethernet + * interfaces fetch the ID from the two bytes in the Ethernet MAC + * 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 + */ + type = skb->dev->type_trans(skb, skb->dev); + + /* + * We got a packet ID. Now loop over the "known protocols" + * table (which is actually a linked list, but this will + * change soon if I get my way- FvK), and forward the packet + * to anyone who wants it. + */ + for (ptype = ptype_base; ptype != NULL; ptype = ptype->next) { + if (ptype->type == type || ptype->type == NET16(ETH_P_ALL)) { + struct sk_buff *skb2; + + if (ptype->type==NET16(ETH_P_ALL)) + nitcount--; + if (ptype->copy || nitcount) { /* copy if we need to */ + 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->h.raw = (unsigned char *)( + (unsigned long) skb2 + + (unsigned long) skb->h.raw - + (unsigned long) skb + ); + skb2->free = 1; + } else { + skb2 = skb; + } + + /* This used to be in the 'else' part, but then + * we don't have this flag set when we get a + * protocol that *does* require copying... -FvK + */ + flag = 1; + + /* Kick the protocol handler. */ + ptype->func(skb2, skb->dev, ptype); + } + } + + /* + * That's odd. We got an unknown packet. Who's using + * stuff like Novell or Amoeba on this network?? + */ + if (!flag) { + DPRINTF((DBG_DEV, + "INET: unknown packet type 0x%04X (ignored)\n", type)); + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + } + + /* Again, see if we can transmit anything now. */ + dev_transmit(); + cli(); + } + in_bh = 0; + sti(); + dev_transmit(); +} + + +/* + * This routine is called when an device driver (i.e. an + * interface) is * ready to transmit a packet. + */ + +void dev_tint(struct device *dev) +{ + 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; + } + } +} + + +/* Perform a SIOCGIFCONF call. */ +static int +dev_ifconf(char *arg) +{ + struct ifconf ifc; + struct ifreq ifr; + struct device *dev; + char *pos; + int len; + int err; + + /* Fetch the caller's info block. */ + err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifconf)); + if(err) + return err; + memcpy_fromfs(&ifc, arg, sizeof(struct ifconf)); + len = ifc.ifc_len; + pos = ifc.ifc_buf; + + /* 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; + (*(struct sockaddr_in *) &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; + + /* Write this block to the caller's space. */ + memcpy_tofs(pos, &ifr, sizeof(struct ifreq)); + pos += sizeof(struct ifreq); + len -= sizeof(struct ifreq); + if (len < sizeof(struct ifreq)) break; + } + + /* All done. Write the updated control block back to the caller. */ + ifc.ifc_len = (pos - ifc.ifc_buf); + ifc.ifc_req = (struct ifreq *) ifc.ifc_buf; + memcpy_tofs(arg, &ifc, sizeof(struct ifconf)); + return(pos - arg); +} + +/* Print device statistics. */ +char *sprintf_stats(char *buffer, struct device *dev) +{ + char *pos = buffer; + struct enet_statistics *stats = (dev->get_stats ? dev->get_stats(dev): NULL); + + if (stats) + pos += sprintf(pos, "%6s:%7d %4d %4d %4d %4d %8d %4d %4d %4d %5d %4d\n", + dev->name, + stats->rx_packets, stats->rx_errors, + stats->rx_dropped + stats->rx_missed_errors, + stats->rx_fifo_errors, + stats->rx_length_errors + stats->rx_over_errors + + stats->rx_crc_errors + stats->rx_frame_errors, + stats->tx_packets, stats->tx_errors, stats->tx_dropped, + stats->tx_fifo_errors, stats->collisions, + stats->tx_carrier_errors + stats->tx_aborted_errors + + stats->tx_window_errors + stats->tx_heartbeat_errors); + else + pos += sprintf(pos, "%6s: No statistics available.\n", dev->name); + + return pos; +} + +/* Called from the PROCfs module. */ +int +dev_get_info(char *buffer) +{ + char *pos = buffer; + struct device *dev; + + pos += + sprintf(pos, + "Inter-| Receive | Transmit\n" + " face |packets errs drop fifo frame|packets errs drop fifo colls carrier\n"); + for (dev = dev_base; dev != NULL; dev = dev->next) { + pos = sprintf_stats(pos, dev); + } + return pos - buffer; +} + +static inline int bad_mask(unsigned long mask, unsigned long addr) +{ + if (addr & (mask = ~mask)) + return 1; + mask = ntohl(mask); + if (mask & (mask+1)) + return 1; + return 0; +} + + +/* Perform the SIOCxIFxxx calls. */ +static int +dev_ifsioc(void *arg, unsigned int getset) +{ + struct ifreq ifr; + struct device *dev; + int ret; + + /* Fetch the caller's info block. */ + int err=verify_area(VERIFY_WRITE, arg, sizeof(struct ifreq)); + if(err) + return err; + memcpy_fromfs(&ifr, arg, sizeof(struct ifreq)); + + /* See which interface the caller is talking about. */ + if ((dev = dev_get(ifr.ifr_name)) == NULL) return(-EINVAL); + + switch(getset) { + case SIOCGIFFLAGS: + ifr.ifr_flags = dev->flags; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFFLAGS: + { + int old_flags = dev->flags; + dev->flags = ifr.ifr_flags & ( + 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 + { + ret = (! (old_flags & IFF_UP) && (dev->flags & IFF_UP)) + ? dev_open(dev) : 0; + if(ret<0) + dev->flags&=~IFF_UP; /* Didnt open so down the if */ + } + } + break; + case SIOCGIFADDR: + (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_addr.s_addr = dev->pa_addr; + (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFADDR: + dev->pa_addr = (*(struct sockaddr_in *) + &ifr.ifr_addr).sin_addr.s_addr; + dev->family = ifr.ifr_addr.sa_family; + dev->pa_mask = get_mask(dev->pa_addr); + dev->pa_brdaddr = dev->pa_addr | ~dev->pa_mask; + ret = 0; + break; + case SIOCGIFBRDADDR: + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_addr.s_addr = dev->pa_brdaddr; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFBRDADDR: + dev->pa_brdaddr = (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_addr.s_addr; + ret = 0; + break; + case SIOCGIFDSTADDR: + (*(struct sockaddr_in *) + &ifr.ifr_dstaddr).sin_addr.s_addr = dev->pa_dstaddr; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_broadaddr).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFDSTADDR: + dev->pa_dstaddr = (*(struct sockaddr_in *) + &ifr.ifr_dstaddr).sin_addr.s_addr; + ret = 0; + break; + case SIOCGIFNETMASK: + (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_addr.s_addr = dev->pa_mask; + (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_family = dev->family; + (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_port = 0; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFNETMASK: { + unsigned long mask = (*(struct sockaddr_in *) + &ifr.ifr_netmask).sin_addr.s_addr; + ret = -EINVAL; + if (bad_mask(mask,0)) + break; + dev->pa_mask = mask; + ret = 0; + break; + } + case SIOCGIFMETRIC: + ifr.ifr_metric = dev->metric; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFMETRIC: + dev->metric = ifr.ifr_metric; + ret = 0; + break; + case SIOCGIFMTU: + ifr.ifr_mtu = dev->mtu; + memcpy_tofs(arg, &ifr, sizeof(struct ifreq)); + ret = 0; + break; + case SIOCSIFMTU: + dev->mtu = ifr.ifr_mtu; + ret = 0; + break; + case SIOCGIFMEM: + printk("NET: ioctl(SIOCGIFMEM, 0x%08X)\n", (int)arg); + ret = -EINVAL; + break; + case SIOCSIFMEM: + 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; + } + return(ret); +} + + +/* This function handles all "interface"-type I/O control requests. */ +int +dev_ioctl(unsigned int cmd, void *arg) +{ + struct iflink iflink; + struct ddi_device *dev; + int ret; + + switch(cmd) { + case IP_SET_DEV: + printk("Your network configuration program needs upgrading.\n"); + return -EINVAL; + case SIOCGIFCONF: + (void) dev_ifconf((char *) arg); + ret = 0; + break; + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFHWADDR: + if (!suser()) return(-EPERM); + ret = dev_ifsioc(arg, cmd); + break; + case SIOCSIFLINK: + if (!suser()) return(-EPERM); + memcpy_fromfs(&iflink, arg, sizeof(iflink)); + dev = ddi_map(iflink.id); + if (dev == NULL) return(-EINVAL); + + /* Now allocate an interface and connect it. */ + printk("AF_INET: DDI \"%s\" linked to stream \"%s\"\n", + dev->name, iflink.stream); + ret = 0; + break; + default: + ret = -EINVAL; + } + + return(ret); +} + + +/* Initialize the DEV module. */ +void +dev_init(void) +{ + struct device *dev, *dev2; + + /* Add the devices. + * If the call to dev->init fails, the dev is removed + * from the chain disconnecting the device until the + * next reboot. + */ + dev2 = NULL; + for (dev = dev_base; dev != NULL; dev=dev->next) { + if (dev->init && dev->init(dev)) { + if (dev2 == NULL) dev_base = dev->next; + else dev2->next = dev->next; + } else { + dev2 = dev; + } + } + + /* Set up some IP addresses. */ + ip_bcast = in_aton("255.255.255.255"); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.h new file mode 100644 index 000000000..551426314 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/dev.h @@ -0,0 +1,191 @@ +/* + * 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 Interfaces handler. + * + * Version: @(#)dev.h 1.0.10 08/12/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Corey Minyard + * Donald J. Becker, + * + * 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. + */ +#ifndef _DEV_H +#define _DEV_H + +#include +#include + + +/* for future expansion when we will have different priorities. */ +#define DEV_NUMBUFFS 3 +#define MAX_ADDR_LEN 7 +#define MAX_HEADER 18 + +#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. + * Actually, this whole structure is a big mistake. It mixes I/O + * data with strictly "high-level" data, and it has to know about + * almost every data structure used in the INET module. We will + * gradually phase out this structure, and replace it with the + * more general (but stolen :-) BSD "ifnet" structure. -FvK + */ +struct device { + + /* + * This is the first field of the "visible" part of this structure + * (i.e. as seen by users in the "Space.c" file). It is the name + * the interface. + */ + char *name; + + /* I/O specific fields. These will be moved to DDI soon. */ + unsigned long rmem_end; /* shmem "recv" end */ + unsigned long rmem_start; /* shmem "recv" start */ + unsigned long mem_end; /* sahared mem end */ + unsigned long mem_start; /* shared mem start */ + unsigned short base_addr; /* device I/O address */ + unsigned char irq; /* device IRQ number */ + + /* Low-level status flags. */ + volatile unsigned char start, /* start an operation */ + tbusy, /* transmitter busy */ + interrupt; /* interrupt arrived */ + + /* + * Another mistake. + * This points to the next device in the "dev" chain. It will + * be moved to the "invisible" part of the structure as soon as + * it has been cleaned up. -FvK + */ + struct device *next; + + /* The device initialization function. Called only once. */ + int (*init)(struct device *dev); + + /* Some hardware also needs these fields, but they are not part of the + usual set specified in Space.c. */ + unsigned char if_port; /* Selectable AUI, TP,..*/ + unsigned char dma; /* DMA channel */ + + struct enet_statistics* (*get_stats)(struct device *dev); + + /* + * This marks the end of the "visible" part of the structure. All + * fields hereafter are internal to the system, and may change at + * will (read: may be cleaned up at will). + */ + + /* These may be needed for future network-power-down code. */ + unsigned long trans_start; /* Time (in jiffies) of last Tx */ + unsigned long last_rx; /* Time of last Rx */ + + unsigned short flags; /* interface flags (a la BSD) */ + unsigned short family; /* address family ID (AF_INET) */ + unsigned short metric; /* routing metric (not used) */ + unsigned short mtu; /* interface MTU value */ + unsigned short type; /* interface hardware type */ + unsigned short hard_header_len; /* hardware hdr length */ + void *priv; /* pointer to private data */ + + /* Interface address info. */ + unsigned char broadcast[MAX_ADDR_LEN]; /* hw bcast add */ + unsigned char dev_addr[MAX_ADDR_LEN]; /* hw address */ + unsigned char addr_len; /* harfware address length */ + unsigned long pa_addr; /* protocol address */ + unsigned long pa_brdaddr; /* protocol broadcast addr */ + unsigned long pa_dstaddr; /* protocol P-P other side addr */ + unsigned long pa_mask; /* protocol netmask */ + unsigned short pa_alen; /* protocol address length */ + + /* Pointer to the interface buffers. */ + struct sk_buff *volatile buffs[DEV_NUMBUFFS]; + + /* Pointers to interface service routines. */ + int (*open)(struct device *dev); + int (*stop)(struct device *dev); + int (*hard_start_xmit) (struct sk_buff *skb, + struct device *dev); + int (*hard_header) (unsigned char *buff, + struct device *dev, + unsigned short type, + unsigned long daddr, + unsigned long saddr, + unsigned len); + void (*add_arp) (unsigned long addr, + struct sk_buff *skb, + struct device *dev); + void (*queue_xmit)(struct sk_buff *skb, + struct device *dev, int pri); + 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); +#define HAVE_SET_MAC_ADDR + int (*set_mac_address)(struct device *dev, void *addr); +}; + + +struct packet_type { + unsigned short type; /* This is really NET16(ether_type) other + * devices will have to translate + * appropriately. + */ + unsigned short copy:1; + int (*func) (struct sk_buff *, struct device *, + struct packet_type *); + void *data; + struct packet_type *next; +}; + + +/* Used by dev_rint */ +#define IN_SKBUFF 1 +#define DEV_QUEUE_MAGIC 0x17432895 + + +extern struct device *dev_base; +extern struct packet_type *ptype_base; + + +extern int ip_addr_match(unsigned long addr1, unsigned long addr2); +extern int chk_addr(unsigned long addr); +extern struct device *dev_check(unsigned long daddr); +extern unsigned long my_addr(void); + +extern void dev_add_pack(struct packet_type *pt); +extern void dev_remove_pack(struct packet_type *pt); +extern struct device *dev_get(char *name); +extern int dev_open(struct device *dev); +extern int dev_close(struct device *dev); +extern void dev_queue_xmit(struct sk_buff *skb, struct device *dev, + int pri); +#define HAVE_NETIF_RX 1 +extern void netif_rx(struct sk_buff *skb); +/* The old interface to netif_rx(). */ +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); +extern int dev_ioctl(unsigned int cmd, void *); + +extern void dev_init(void); + +#endif /* _DEV_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.c new file mode 100644 index 000000000..e9f374fb9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.c @@ -0,0 +1,187 @@ +/* + * 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. + * + * Ethernet-type device handling. + * + * Version: @(#)eth.c 1.0.7 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * + * 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. + * Tegge : Arp bug fixes. + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#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 +#include "arp.h" + + +/* Display an Ethernet address in readable format. */ +char *eth_print(unsigned char *ptr) +{ + static char buff[64]; + + if (ptr == NULL) return("[NONE]"); + sprintf(buff, "%02X:%02X:%02X:%02X:%02X:%02X", + (ptr[0] & 255), (ptr[1] & 255), (ptr[2] & 255), + (ptr[3] & 255), (ptr[4] & 255), (ptr[5] & 255) + ); + return(buff); +} + +void eth_setup(char *str, int *ints) +{ + struct device *d = dev_base; + + if (!str || !*str) + return; + while (d) { + if (!strcmp(str,d->name)) { + if (ints[0] > 0) + d->irq=ints[1]; + if (ints[0] > 1) + d->base_addr=ints[2]; + if (ints[0] > 2) + d->mem_start=ints[3]; + if (ints[0] > 3) + d->mem_end=ints[4]; + break; + } + d=d->next; + } +} + +/* Display the contents of the Ethernet MAC header. */ +void +eth_dump(struct ethhdr *eth) +{ + if (inet_debug != DBG_ETH) return; + + printk("eth: SRC = %s ", eth_print(eth->h_source)); + printk("DST = %s ", eth_print(eth->h_dest)); + printk("TYPE = %04X\n", ntohs(eth->h_proto)); +} + + +/* Create the Ethernet MAC header. */ +int +eth_header(unsigned char *buff, struct device *dev, unsigned short type, + unsigned long daddr, unsigned long saddr, unsigned len) +{ + struct ethhdr *eth; + + DPRINTF((DBG_DEV, "ETH: header(%s, ", in_ntoa(saddr))); + DPRINTF((DBG_DEV, "%s, 0x%X)\n", in_ntoa(daddr), type)); + + /* Fill in the basic Ethernet MAC header. */ + eth = (struct ethhdr *) buff; + 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); + } + + /* 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, dev->pa_addr)) + { + sti(); + if(type!=ETH_P_IP) + printk("Erk: protocol %X got into an arp request state!\n",type); + 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); + } +} + + +/* Rebuild the Ethernet MAC header. */ +int +eth_rebuild_header(void *buff, struct device *dev) +{ + struct ethhdr *eth; + unsigned long src, dst; + + DPRINTF((DBG_DEV, "ETH: Using MAC Broadcast\n")); + eth = (struct ethhdr *) buff; + src = *(unsigned long *) eth->h_source; + 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))); + if(eth->h_proto!=htons(ETH_P_ARP)) /* This ntohs kind of helps a bit! */ + if (arp_find(eth->h_dest, dst, dev, dev->pa_addr /* src */)) return(1); + memcpy(eth->h_source, dev->dev_addr, dev->addr_len); + return(0); +} + + +/* Add an ARP entry for a host on this interface. */ +void +eth_add_arp(unsigned long addr, struct sk_buff *skb, struct device *dev) +{ + struct ethhdr *eth; + + eth = (struct ethhdr *) skb->data; + arp_add(addr, eth->h_source, dev); +} + + +/* Determine the packet's protocol ID. */ +unsigned short +eth_type_trans(struct sk_buff *skb, struct device *dev) +{ + struct ethhdr *eth; + + eth = (struct ethhdr *) skb->data; + + if(ntohs(eth->h_proto)<1536) + return(htons(ETH_P_802_3)); + return(eth->h_proto); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.h new file mode 100644 index 000000000..f8fed44ed --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/eth.h @@ -0,0 +1,35 @@ +/* + * INET An implementation of the TCP/IP protocol suite for the LINUX + * operating system. NET is implemented using the BSD Socket + * interface as the means of communication with the user level. + * + * Definitions for the Ethernet handlers. + * + * Version: @(#)eth.h 1.0.4 05/13/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _ETH_H +#define _ETH_H + + +#include + + +extern char *eth_print(unsigned char *ptr); +extern void eth_dump(struct ethhdr *eth); +extern int eth_header(unsigned char *buff, struct device *dev, + unsigned short type, unsigned long daddr, + unsigned long saddr, unsigned len); +extern int eth_rebuild_header(void *buff, struct device *dev); +extern void eth_add_arp(unsigned long addr, struct sk_buff *skb, + struct device *dev); +extern unsigned short eth_type_trans(struct sk_buff *skb, struct device *dev); + +#endif /* _ETH_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.c new file mode 100644 index 000000000..f6ae64ccd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.c @@ -0,0 +1,441 @@ +/* + * 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. + * + * Internet Control Message Protocol (ICMP) + * + * Version: @(#)icmp.c 1.0.11 06/02/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * + * Fixes: + * Alan Cox : Generic queue usage. + * Gerhard Koerting: ICMP addressing corrected + * Alan Cox : Use tos/ttl settings + * + * + * 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 +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "route.h" +#include "protocol.h" +#include "icmp.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include +#include +#include +#include + + +#define min(a,b) ((a)<(b)?(a):(b)) + + +/* An array of errno for error messages from dest unreach. */ +struct icmp_err icmp_err_convert[] = { + { 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 */ +}; + + +/* Display the contents of an ICMP header. */ +static void +print_icmp(struct icmphdr *icmph) +{ + if (inet_debug != DBG_ICMP) return; + + printk("ICMP: type = %d, code = %d, checksum = %X\n", + icmph->type, icmph->code, icmph->checksum); + printk(" gateway = %s\n", in_ntoa(icmph->un.gateway)); +} + + +/* Send an ICMP message. */ +void +icmp_send(struct sk_buff *skb_in, int type, int code, struct device *dev) +{ + struct sk_buff *skb; + struct iphdr *iph; + int offset; + struct icmphdr *icmph; + int len; + + DPRINTF((DBG_ICMP, "icmp_send(skb_in = %X, type = %d, code = %d, dev=%X)\n", + skb_in, type, code, dev)); + + /* Get some memory for the reply. */ + len = sizeof(struct sk_buff) + dev->hard_header_len + + sizeof(struct iphdr) + sizeof(struct icmphdr) + + sizeof(struct iphdr) + 8; /* amount of header to return */ + + skb = (struct sk_buff *) alloc_skb(len, GFP_ATOMIC); + if (skb == NULL) + return; + + skb->sk = NULL; + skb->mem_addr = skb; + skb->mem_len = len; + len -= sizeof(struct sk_buff); + + /* Find the IP header. */ + iph = (struct iphdr *) (skb_in->data + dev->hard_header_len); + + /* Build Layer 2-3 headers for message back to source. */ + offset = ip_build_header(skb, dev->pa_addr, iph->saddr, + &dev, IPPROTO_ICMP, NULL, len, skb_in->ip_hdr->tos,255); + if (offset < 0) { + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return; + } + + /* Re-adjust length according to actual IP header size. */ + skb->len = offset + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8; + icmph = (struct icmphdr *) (skb->data + offset); + icmph->type = type; + icmph->code = code; + icmph->checksum = 0; + icmph->un.gateway = 0; + memcpy(icmph + 1, iph, sizeof(struct iphdr) + 8); + + icmph->checksum = ip_compute_csum((unsigned char *)icmph, + sizeof(struct icmphdr) + sizeof(struct iphdr) + 8); + + DPRINTF((DBG_ICMP, ">>\n")); + print_icmp(icmph); + + /* Send it and free it. */ + ip_queue_xmit(NULL, dev, skb, 1); +} + + +/* Handle ICMP_UNREACH and ICMP_QUENCH. */ +static void +icmp_unreach(struct icmphdr *icmph, struct sk_buff *skb) +{ + struct inet_protocol *ipprot; + struct iphdr *iph; + unsigned char hash; + int err; + + err = (icmph->type << 8) | icmph->code; + iph = (struct iphdr *) (icmph + 1); + switch(icmph->code & 7) { + case ICMP_NET_UNREACH: + DPRINTF((DBG_ICMP, "ICMP: %s: network unreachable.\n", + in_ntoa(iph->daddr))); + break; + case ICMP_HOST_UNREACH: + DPRINTF((DBG_ICMP, "ICMP: %s: host unreachable.\n", + in_ntoa(iph->daddr))); + break; + case ICMP_PROT_UNREACH: + printk("ICMP: %s:%d: protocol unreachable.\n", + in_ntoa(iph->daddr), ntohs(iph->protocol)); + break; + case ICMP_PORT_UNREACH: + DPRINTF((DBG_ICMP, "ICMP: %s:%d: port unreachable.\n", + in_ntoa(iph->daddr), -1 /* FIXME: ntohs(iph->port) */)); + break; + case ICMP_FRAG_NEEDED: + printk("ICMP: %s: fragmentation needed and DF set.\n", + in_ntoa(iph->daddr)); + break; + case ICMP_SR_FAILED: + printk("ICMP: %s: Source Route Failed.\n", in_ntoa(iph->daddr)); + break; + default: + DPRINTF((DBG_ICMP, "ICMP: Unreachable: CODE=%d from %s\n", + (icmph->code & 7), in_ntoa(iph->daddr))); + break; + } + + /* Get the protocol(s). */ + hash = iph->protocol & (MAX_INET_PROTOS -1); + + /* This can change while we are doing it. */ + ipprot = (struct inet_protocol *) inet_protos[hash]; + while(ipprot != NULL) { + struct inet_protocol *nextip; + + nextip = (struct inet_protocol *) ipprot->next; + + /* Pass it off to everyone who wants it. */ + if (iph->protocol == ipprot->protocol && ipprot->err_handler) { + ipprot->err_handler(err, (unsigned char *)(icmph + 1), + iph->daddr, iph->saddr, ipprot); + } + + ipprot = nextip; + } + skb->sk = NULL; + kfree_skb(skb, FREE_READ); +} + + +/* Handle ICMP_REDIRECT. */ +static void +icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev) +{ + struct iphdr *iph; + unsigned long ip; + + iph = (struct iphdr *) (icmph + 1); + ip = iph->daddr; + switch(icmph->code & 7) { + case ICMP_REDIR_NET: + rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), + ip, 0, icmph->un.gateway, dev); + break; + case ICMP_REDIR_HOST: + rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_HOST | RTF_GATEWAY), + ip, 0, icmph->un.gateway, dev); + break; + case ICMP_REDIR_NETTOS: + case ICMP_REDIR_HOSTTOS: + printk("ICMP: cannot handle TOS redirects yet!\n"); + break; + default: + DPRINTF((DBG_ICMP, "ICMP: Unreach: CODE=%d\n", + (icmph->code & 7))); + break; + } + skb->sk = NULL; + kfree_skb(skb, FREE_READ); +} + + +/* Handle ICMP_ECHO ("ping") requests. */ +static void +icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, + unsigned long saddr, unsigned long daddr, int len, + struct options *opt) +{ + struct icmphdr *icmphr; + struct sk_buff *skb2; + int size, offset; + + size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; + skb2 = alloc_skb(size, GFP_ATOMIC); + if (skb2 == NULL) { + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return; + } + skb2->sk = NULL; + 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, skb->ip_hdr->tos,255); + if (offset < 0) { + printk("ICMP: Could not build IP Header for ICMP ECHO Response\n"); + kfree_skb(skb2,FREE_WRITE); + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return; + } + + /* Re-adjust length according to actual IP header size. */ + skb2->len = offset + len; + + /* Build ICMP_ECHO Response message. */ + icmphr = (struct icmphdr *) (skb2->data + offset); + memcpy((char *) icmphr, (char *) icmph, len); + icmphr->type = ICMP_ECHOREPLY; + icmphr->code = 0; + icmphr->checksum = 0; + 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); + + skb->sk = NULL; + kfree_skb(skb, FREE_READ); +} + + +/* Handle the ICMP INFORMATION REQUEST. */ +static void +icmp_info(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, + unsigned long saddr, unsigned long daddr, int len, + struct options *opt) +{ + /* NOT YET */ + skb->sk = NULL; + kfree_skb(skb, FREE_READ); +} + + +/* Handle ICMP_ADRESS_MASK requests. */ +static void +icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, + unsigned long saddr, unsigned long daddr, int len, + struct options *opt) +{ + struct icmphdr *icmphr; + struct sk_buff *skb2; + int size, offset; + + size = sizeof(struct sk_buff) + dev->hard_header_len + 64 + len; + skb2 = alloc_skb(size, GFP_ATOMIC); + if (skb2 == NULL) { + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return; + } + skb2->sk = NULL; + 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, skb->ip_hdr->tos,255); + if (offset < 0) { + printk("ICMP: Could not build IP Header for ICMP ADDRESS Response\n"); + kfree_skb(skb2,FREE_WRITE); + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return; + } + + /* Re-adjust length according to actual IP header size. */ + skb2->len = offset + len; + + /* Build ICMP ADDRESS MASK Response message. */ + icmphr = (struct icmphdr *) (skb2->data + offset); + icmphr->type = ICMP_ADDRESSREPLY; + icmphr->code = 0; + icmphr->checksum = 0; + icmphr->un.echo.id = icmph->un.echo.id; + icmphr->un.echo.sequence = icmph->un.echo.sequence; + memcpy((char *) (icmphr + 1), (char *) &dev->pa_mask, sizeof(dev->pa_mask)); + + 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); + + skb->sk = NULL; + kfree_skb(skb, FREE_READ); +} + + +/* Deal with incoming ICMP packets. */ +int +icmp_rcv(struct sk_buff *skb1, struct device *dev, struct options *opt, + unsigned long daddr, unsigned short len, + unsigned long saddr, int redo, struct inet_protocol *protocol) +{ + struct icmphdr *icmph; + unsigned char *buff; + + /* Drop broadcast packets. */ + if (chk_addr(daddr) == IS_BROADCAST) { + DPRINTF((DBG_ICMP, "ICMP: Discarded broadcast from %s\n", + in_ntoa(saddr))); + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(0); + } + + buff = skb1->h.raw; + icmph = (struct icmphdr *) buff; + + /* Validate the packet first */ + 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); + + /* Parse the ICMP message */ + switch(icmph->type) { + case ICMP_TIME_EXCEEDED: + case ICMP_DEST_UNREACH: + case ICMP_SOURCE_QUENCH: + icmp_unreach(icmph, skb1); + return(0); + case ICMP_REDIRECT: + icmp_redirect(icmph, skb1, dev); + return(0); + case ICMP_ECHO: + icmp_echo(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_ECHOREPLY: + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(0); + case ICMP_INFO_REQUEST: + icmp_info(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_INFO_REPLY: + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(0); + case ICMP_ADDRESS: + icmp_address(icmph, skb1, dev, saddr, daddr, len, opt); + return 0; + case ICMP_ADDRESSREPLY: + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(0); + default: + DPRINTF((DBG_ICMP, + "ICMP: Unsupported ICMP from %s, type = 0x%X\n", + in_ntoa(saddr), icmph->type)); + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(0); + } + /*NOTREACHED*/ + skb1->sk = NULL; + kfree_skb(skb1, FREE_READ); + return(-1); +} + + +/* Perform any ICMP-related I/O control requests. */ +int +icmp_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + switch(cmd) { + case DDIOCSDBG: + return(dbg_ioctl((void *) arg, DBG_ICMP)); + default: + return(-EINVAL); + } + return(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.h new file mode 100644 index 000000000..1e2ec5228 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/icmp.h @@ -0,0 +1,36 @@ +/* + * 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 ICMP module. + * + * Version: @(#)icmp.h 1.0.4 05/13/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _ICMP_H +#define _ICMP_H + +#include + + +extern struct icmp_err icmp_err_convert[]; + +extern void icmp_send(struct sk_buff *skb_in, int type, int code, + struct device *dev); +extern int icmp_rcv(struct sk_buff *skb1, struct device *dev, + struct options *opt, unsigned long daddr, + unsigned short len, unsigned long saddr, + int redo, struct inet_protocol *protocol); + +extern int icmp_ioctl(struct sock *sk, int cmd, + unsigned long arg); + +#endif /* _ICMP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/inet.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/inet.h new file mode 100644 index 000000000..bda8f3465 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/inet.h @@ -0,0 +1,97 @@ +/* + * 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. + * + * General Definitions for the TCP/IP (INET) module. This is + * mostly a bunch of "general" macros, plus the PROTOCOL link + * code and data. + * + * Version: @(#)inet.h 1.0.6 05/25/93 + * + * Author: Fred N. van Kempen, + * + * This work was derived friom Ross Biro's inspirational work + * for the LINUX operating system. His version numbers were: + * + * $Id: Space.c,v 0.8.4.5 1992/12/12 19:25:04 bir7 Exp $ + * $Id: arp.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ + * $Id: arp.h,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ + * $Id: dev.c,v 0.8.4.13 1993/01/23 18:00:11 bir7 Exp $ + * $Id: dev.h,v 0.8.4.7 1993/01/23 18:00:11 bir7 Exp $ + * $Id: eth.c,v 0.8.4.4 1993/01/22 23:21:38 bir7 Exp $ + * $Id: eth.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ + * $Id: icmp.c,v 0.8.4.9 1993/01/23 18:00:11 bir7 Exp $ + * $Id: icmp.h,v 0.8.4.2 1992/11/15 14:55:30 bir7 Exp $ + * $Id: ip.c,v 0.8.4.8 1992/12/12 19:25:04 bir7 Exp $ + * $Id: ip.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ + * $Id: loopback.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ + * $Id: packet.c,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ + * $Id: protocols.c,v 0.8.4.3 1992/11/15 14:55:30 bir7 Exp $ + * $Id: raw.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ + * $Id: sock.c,v 0.8.4.6 1993/01/28 22:30:00 bir7 Exp $ + * $Id: sock.h,v 0.8.4.7 1993/01/26 22:04:00 bir7 Exp $ + * $Id: tcp.c,v 0.8.4.16 1993/01/26 22:04:00 bir7 Exp $ + * $Id: tcp.h,v 0.8.4.7 1993/01/22 22:58:08 bir7 Exp $ + * $Id: timer.c,v 0.8.4.8 1993/01/23 18:00:11 bir7 Exp $ + * $Id: timer.h,v 0.8.4.2 1993/01/23 18:00:11 bir7 Exp $ + * $Id: udp.c,v 0.8.4.12 1993/01/26 22:04:00 bir7 Exp $ + * $Id: udp.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 Exp $ + * $Id: we.c,v 0.8.4.10 1993/01/23 18:00:11 bir7 Exp $ + * $Id: wereg.h,v 0.8.4.1 1992/11/10 00:17:18 bir7 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 Free Software Foundation; either version + * 2 of the License, or (at your option) any later version. + */ +#ifndef _INET_H +#define _INET_H + + +#include + + +#define NET16(x) ((((x) >> 8) & 0x00FF) | (((x) << 8) & 0xFF00)) + + +#undef INET_DEBUG +#ifdef INET_DEBUG +# define DPRINTF(x) dprintf x +#else +# define DPRINTF(x) do ; while (0) +#endif + +/* Debug levels. One per module. */ +#define DBG_OFF 0 /* no debugging */ +#define DBG_INET 1 /* sock.c */ +#define DBG_RT 2 /* route.c */ +#define DBG_DEV 3 /* dev.c */ +#define DBG_ETH 4 /* eth.c */ +#define DBG_PROTO 5 /* protocol.c */ +#define DBG_TMR 6 /* timer.c */ +#define DBG_PKT 7 /* packet.c */ +#define DBG_RAW 8 /* raw.c */ + +#define DBG_LOOPB 10 /* loopback.c */ +#define DBG_SLIP 11 /* slip.c */ + +#define DBG_ARP 20 /* arp.c */ +#define DBG_IP 21 /* ip.c */ +#define DBG_ICMP 22 /* icmp.c */ +#define DBG_TCP 23 /* tcp.c */ +#define DBG_UDP 24 /* udp.c */ + + +extern int inet_debug; + + +extern void inet_proto_init(struct ddi_proto *pro); +extern char *in_ntoa(unsigned long in); +extern unsigned long in_aton(char *str); + +extern void dprintf(int level, char *fmt, ...); + +extern int dbg_ioctl(void *arg, int level); + +#endif /* _INET_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.c new file mode 100644 index 000000000..fdef4c640 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.c @@ -0,0 +1,1584 @@ +/* + * 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. + * + * The Internet Protocol (IP) module. + * + * Version: @(#)ip.c 1.0.16b 9/1/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Donald Becker, + * + * 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. + * Fred Van Kempen : IP fragment support (borrowed from NET2E) + * Gerhard Koerting: Forward fragmented frames correctly. + * Gerhard Koerting: Fixes to my fix of the above 8-). + * Gerhard Koerting: IP interface addressing fix. + * Linus Torvalds : More robustness checks + * Alan Cox : Even more checks: Still not as robust as it ought to be + * Alan Cox : Save IP header pointer for later + * Alan Cox : ip option setting + * Alan Cox : Use ip_tos/ip_ttl settings + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "eth.h" +#include "ip.h" +#include "protocol.h" +#include "route.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" +#include "icmp.h" + +#define CONFIG_IP_FORWARD +#define CONFIG_IP_DEFRAG + +extern int last_retran; +extern void sort_send(struct sock *sk); + +#define min(a,b) ((a)<(b)?(a):(b)) + +void +ip_print(struct iphdr *ip) +{ + unsigned char buff[32]; + unsigned char *ptr; + int addr, len, i; + + if (inet_debug != DBG_IP) return; + + /* Dump the IP header. */ + printk("IP: ihl=%d, version=%d, tos=%d, tot_len=%d\n", + ip->ihl, ip->version, ip->tos, ntohs(ip->tot_len)); + printk(" id=%X, ttl=%d, prot=%d, check=%X\n", + ip->id, ip->ttl, ip->protocol, ip->check); + printk(" frag_off=%d\n", ip->frag_off); + printk(" soucre=%s ", in_ntoa(ip->saddr)); + printk("dest=%s\n", in_ntoa(ip->daddr)); + printk(" ----\n"); + + /* Dump the data. */ + ptr = (unsigned char *)(ip + 1); + addr = 0; + len = ntohs(ip->tot_len) - (4 * ip->ihl); + while (len > 0) { + printk(" %04X: ", addr); + for(i = 0; i < 16; i++) { + if (len > 0) { + printk("%02X ", (*ptr & 0xFF)); + buff[i] = *ptr++; + if (buff[i] < 32 || buff[i] > 126) buff[i] = '.'; + } else { + printk(" "); + buff[i] = ' '; + } + addr++; + len--; + }; + buff[i] = '\0'; + printk(" \"%s\"\n", buff); + } + printk(" ----\n\n"); +} + + +int +ip_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + switch(cmd) { + case DDIOCSDBG: + return(dbg_ioctl((void *) arg, DBG_IP)); + default: + return(-EINVAL); + } +} + + +/* these two routines will do routining. */ +static void +strict_route(struct iphdr *iph, struct options *opt) +{ +} + + +static void +loose_route(struct iphdr *iph, struct options *opt) +{ +} + + +static void +print_ipprot(struct inet_protocol *ipprot) +{ + DPRINTF((DBG_IP, "handler = %X, protocol = %d, copy=%d \n", + ipprot->handler, ipprot->protocol, ipprot->copy)); +} + + +/* This routine will check to see if we have lost a gateway. */ +void +ip_route_check(unsigned long daddr) +{ +} + + +#if 0 +/* this routine puts the options at the end of an ip header. */ +static int +build_options(struct iphdr *iph, struct options *opt) +{ + unsigned char *ptr; + /* currently we don't support any options. */ + ptr = (unsigned char *)(iph+1); + *ptr = 0; + return (4); +} +#endif + + +/* Take an skb, and fill in the MAC header. */ +static int +ip_send(struct sk_buff *skb, unsigned long daddr, int len, struct device *dev, + unsigned long saddr) +{ + unsigned char *ptr; + int mac; + + ptr = skb->data; + mac = 0; + skb->arp = 1; + if (dev->hard_header) { + mac = dev->hard_header(ptr, dev, ETH_P_IP, daddr, saddr, len); + } + if (mac < 0) { + mac = -mac; + skb->arp = 0; + } + skb->dev = dev; + return(mac); +} + + +/* + * This routine builds the appropriate hardware/IP headers for + * the routine. It assumes that if *dev != NULL then the + * protocol knows what it's doing, otherwise it uses the + * routing/ARP tables to select a device struct. + */ +int +ip_build_header(struct sk_buff *skb, unsigned long saddr, unsigned long daddr, + struct device **dev, int type, struct options *opt, int len, int tos, int ttl) +{ + static struct options optmem; + struct iphdr *iph; + struct rtable *rt; + unsigned char *buff; + unsigned long raddr; + static int count = 0; + int tmp; + + 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 = skb->data; + + /* See if we need to look up the device. */ + if (*dev == NULL) { + rt = rt_route(daddr, &optmem); + if (rt == NULL) + return(-ENETUNREACH); + + *dev = rt->rt_dev; + if (saddr == 0x0100007FL && 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))); + opt = &optmem; + } else { + /* We still need the address of the first hop. */ + rt = rt_route(daddr, &optmem); + raddr = (rt == NULL) ? 0 : rt->rt_gateway; + } + if (raddr == 0) + raddr = daddr; + + /* Now build the MAC header. */ + tmp = ip_send(skb, raddr, len, *dev, saddr); + buff += tmp; + len -= tmp; + + skb->dev = *dev; + skb->saddr = saddr; + if (skb->sk) skb->sk->saddr = saddr; + + /* Now build the IP header. */ + + /* If we are using IPPROTO_RAW, then we don't need an IP header, since + one is being supplied to us by the user */ + + if(type == IPPROTO_RAW) return (tmp); + + iph = (struct iphdr *)buff; + iph->version = 4; + iph->tos = tos; + iph->frag_off = 0; + iph->ttl = ttl; + iph->daddr = daddr; + iph->saddr = saddr; + iph->protocol = type; + iph->ihl = 5; + iph->id = htons(count++); + + /* Setup the IP options. */ +#ifdef Not_Yet_Avail + build_options(iph, opt); +#endif + + return(20 + tmp); /* IP header plus MAC header size */ +} + + +static int +do_options(struct iphdr *iph, struct options *opt) +{ + unsigned char *buff; + int done = 0; + int i, len = sizeof(struct iphdr); + + /* Zero out the options. */ + opt->record_route.route_size = 0; + opt->loose_route.route_size = 0; + opt->strict_route.route_size = 0; + opt->tstamp.ptr = 0; + opt->security = 0; + opt->compartment = 0; + opt->handling = 0; + opt->stream = 0; + opt->tcc = 0; + return(0); + + /* Advance the pointer to start at the options. */ + buff = (unsigned char *)(iph + 1); + + /* Now start the processing. */ + while (!done && len < iph->ihl*4) switch(*buff) { + case IPOPT_END: + done = 1; + break; + case IPOPT_NOOP: + buff++; + len++; + break; + case IPOPT_SEC: + buff++; + if (*buff != 11) return(1); + buff++; + opt->security = ntohs(*(unsigned short *)buff); + buff += 2; + opt->compartment = ntohs(*(unsigned short *)buff); + buff += 2; + opt->handling = ntohs(*(unsigned short *)buff); + buff += 2; + opt->tcc = ((*buff) << 16) + ntohs(*(unsigned short *)(buff+1)); + buff += 3; + len += 11; + break; + case IPOPT_LSRR: + buff++; + if ((*buff - 3)% 4 != 0) return(1); + len += *buff; + opt->loose_route.route_size = (*buff -3)/4; + buff++; + if (*buff % 4 != 0) return(1); + opt->loose_route.pointer = *buff/4 - 1; + 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; + } + break; + case IPOPT_SSRR: + buff++; + if ((*buff - 3)% 4 != 0) return(1); + len += *buff; + opt->strict_route.route_size = (*buff -3)/4; + buff++; + if (*buff % 4 != 0) return(1); + opt->strict_route.pointer = *buff/4 - 1; + 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; + } + break; + case IPOPT_RR: + buff++; + if ((*buff - 3)% 4 != 0) return(1); + len += *buff; + opt->record_route.route_size = (*buff -3)/4; + buff++; + if (*buff % 4 != 0) return(1); + opt->record_route.pointer = *buff/4 - 1; + 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; + } + break; + case IPOPT_SID: + len += 4; + buff +=2; + opt->stream = *(unsigned short *)buff; + buff += 2; + break; + case IPOPT_TIMESTAMP: + buff++; + len += *buff; + if (*buff % 4 != 0) return(1); + opt->tstamp.len = *buff / 4 - 1; + buff++; + if ((*buff - 1) % 4 != 0) return(1); + opt->tstamp.ptr = (*buff-1)/4; + buff++; + opt->tstamp.x.full_char = *buff; + buff++; + for (i = 0; i < opt->tstamp.len; i++) { + opt->tstamp.data[i] = *(unsigned long *)buff; + buff += 4; + } + break; + default: + return(1); + } + + if (opt->record_route.route_size == 0) { + if (opt->strict_route.route_size != 0) { + memcpy(&(opt->record_route), &(opt->strict_route), + sizeof(opt->record_route)); + } else if (opt->loose_route.route_size != 0) { + memcpy(&(opt->record_route), &(opt->loose_route), + sizeof(opt->record_route)); + } + } + + if (opt->strict_route.route_size != 0 && + opt->strict_route.route_size != opt->strict_route.pointer) { + strict_route(iph, opt); + return(0); + } + + if (opt->loose_route.route_size != 0 && + opt->loose_route.route_size != opt->loose_route.pointer) { + loose_route(iph, opt); + return(0); + } + + return(0); +} + +/* This is a version of ip_compute_csum() optimized for IP headers, which + always checksum on 4 octet boundaries. */ +static inline unsigned short +ip_fast_csum(unsigned char * buff, int wlen) +{ + unsigned long sum = 0; + + if (wlen) { + unsigned long bogus; + __asm__("clc\n" + "1:\t" + "lodsl\n\t" + "adcl %3, %0\n\t" + "decl %2\n\t" + "jne 1b\n\t" + "adcl $0, %0\n\t" + "movl %0, %3\n\t" + "shrl $16, %3\n\t" + "addw %w3, %w0\n\t" + "adcw $0, %w0" + : "=r" (sum), "=S" (buff), "=r" (wlen), "=a" (bogus) + : "0" (sum), "1" (buff), "2" (wlen)); + } + return (~sum) & 0xffff; +} + +/* + * This routine does all the checksum computations that don't + * require anything special (like copying or special headers). + */ +unsigned short +ip_compute_csum(unsigned char * buff, int len) +{ + unsigned long sum = 0; + + /* Do the first multiple of 4 bytes and convert to 16 bits. */ + if (len > 3) { + __asm__("clc\n" + "1:\t" + "lodsl\n\t" + "adcl %%eax, %%ebx\n\t" + "loop 1b\n\t" + "adcl $0, %%ebx\n\t" + "movl %%ebx, %%eax\n\t" + "shrl $16, %%eax\n\t" + "addw %%ax, %%bx\n\t" + "adcw $0, %%bx" + : "=b" (sum) , "=S" (buff) + : "0" (sum), "c" (len >> 2) ,"1" (buff) + : "ax", "cx", "si", "bx" ); + } + if (len & 2) { + __asm__("lodsw\n\t" + "addw %%ax, %%bx\n\t" + "adcw $0, %%bx" + : "=b" (sum), "=S" (buff) + : "0" (sum), "1" (buff) + : "bx", "ax", "si"); + } + if (len & 1) { + __asm__("lodsb\n\t" + "movb $0, %%ah\n\t" + "addw %%ax, %%bx\n\t" + "adcw $0, %%bx" + : "=b" (sum), "=S" (buff) + : "0" (sum), "1" (buff) + : "bx", "ax", "si"); + } + sum =~sum; + return(sum & 0xffff); +} + +/* Check the header of an incoming IP datagram. This version is still used in slhc.c. */ +int +ip_csum(struct iphdr *iph) +{ + return ip_fast_csum((unsigned char *)iph, iph->ihl); +} + +/* Generate a checksym for an outgoing IP datagram. */ +static void +ip_send_check(struct iphdr *iph) +{ + iph->check = 0; + iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); +} + +/************************ Fragment Handlers From NET2E not yet with tweaks to beat 4K **********************************/ + +static struct ipq *ipqueue = NULL; /* IP fragment queue */ + /* Create a new fragment entry. */ +static struct ipfrag *ip_frag_create(int offset, int end, struct sk_buff *skb, unsigned char *ptr) +{ + struct ipfrag *fp; + + fp = (struct ipfrag *) kmalloc(sizeof(struct ipfrag), GFP_ATOMIC); + if (fp == NULL) + { + printk("IP: frag_create: no memory left !\n"); + return(NULL); + } + memset(fp, 0, sizeof(struct ipfrag)); + + /* Fill in the structure. */ + fp->offset = offset; + fp->end = end; + fp->len = end - offset; + fp->skb = skb; + fp->ptr = ptr; + + return(fp); +} + + +/* + * Find the correct entry in the "incomplete datagrams" queue for + * this IP datagram, and return the queue entry address if found. + */ +static struct ipq *ip_find(struct iphdr *iph) +{ + struct ipq *qp; + struct ipq *qplast; + + cli(); + qplast = NULL; + for(qp = ipqueue; qp != NULL; qplast = qp, qp = qp->next) + { + if (iph->id== qp->iph->id && iph->saddr == qp->iph->saddr && + iph->daddr == qp->iph->daddr && iph->protocol == qp->iph->protocol) + { + del_timer(&qp->timer); /* So it doesnt vanish on us. The timer will be reset anyway */ + sti(); + return(qp); + } + } + sti(); + return(NULL); +} + + +/* + * Remove an entry from the "incomplete datagrams" queue, either + * because we completed, reassembled and processed it, or because + * it timed out. + */ + +static void ip_free(struct ipq *qp) +{ + struct ipfrag *fp; + struct ipfrag *xp; + + /* Stop the timer for this entry. */ +/* printk("ip_free\n");*/ + del_timer(&qp->timer); + + /* Remove this entry from the "incomplete datagrams" queue. */ + cli(); + if (qp->prev == NULL) + { + ipqueue = qp->next; + if (ipqueue != NULL) + ipqueue->prev = NULL; + } + else + { + qp->prev->next = qp->next; + if (qp->next != NULL) + qp->next->prev = qp->prev; + } + + /* Release all fragment data. */ +/* printk("ip_free: kill frag data\n");*/ + fp = qp->fragments; + while (fp != NULL) + { + xp = fp->next; + IS_SKB(fp->skb); + kfree_skb(fp->skb,FREE_READ); + kfree_s(fp, sizeof(struct ipfrag)); + fp = xp; + } + +/* printk("ip_free: cleanup\n");*/ + + /* Release the MAC header. */ + kfree_s(qp->mac, qp->maclen); + + /* Release the IP header. */ + kfree_s(qp->iph, qp->ihlen + 8); + + /* Finally, release the queue descriptor itself. */ + kfree_s(qp, sizeof(struct ipq)); +/* printk("ip_free:done\n");*/ + sti(); + } + + + /* Oops- a fragment queue timed out. Kill it and send an ICMP reply. */ + +static void ip_expire(unsigned long arg) +{ + struct ipq *qp; + + qp = (struct ipq *)arg; + DPRINTF((DBG_IP, "IP: queue_expire: fragment queue 0x%X timed out!\n", qp)); + + /* Send an ICMP "Fragment Reassembly Timeout" message. */ +#if 0 + icmp_send(qp->iph->ip_src.s_addr, ICMP_TIME_EXCEEDED, + ICMP_EXC_FRAGTIME, qp->iph); +#endif + if(qp->fragments!=NULL) + icmp_send(qp->fragments->skb,ICMP_TIME_EXCEEDED, + ICMP_EXC_FRAGTIME, qp->dev); + + /* Nuke the fragment queue. */ + ip_free(qp); +} + + +/* + * Add an entry to the 'ipq' queue for a newly received IP datagram. + * We will (hopefully :-) receive all other fragments of this datagram + * in time, so we just create a queue for this datagram, in which we + * will insert the received fragments at their respective positions. + */ + +static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct device *dev) +{ + struct ipq *qp; + int maclen; + int ihlen; + + qp = (struct ipq *) kmalloc(sizeof(struct ipq), GFP_ATOMIC); + if (qp == NULL) + { + printk("IP: create: no memory left !\n"); + return(NULL); + } + memset(qp, 0, sizeof(struct ipq)); + + /* Allocate memory for the MAC header. */ + maclen = ((unsigned long) iph) - ((unsigned long) skb->data); + qp->mac = (unsigned char *) kmalloc(maclen, GFP_ATOMIC); + if (qp->mac == NULL) + { + printk("IP: create: no memory left !\n"); + kfree_s(qp, sizeof(struct ipq)); + return(NULL); + } + + /* Allocate memory for the IP header (plus 8 octects for ICMP). */ + ihlen = (iph->ihl * sizeof(unsigned long)); + qp->iph = (struct iphdr *) kmalloc(ihlen + 8, GFP_ATOMIC); + if (qp->iph == NULL) + { + printk("IP: create: no memory left !\n"); + kfree_s(qp->mac, maclen); + kfree_s(qp, sizeof(struct ipq)); + return(NULL); + } + + /* Fill in the structure. */ + memcpy(qp->mac, skb->data, maclen); + memcpy(qp->iph, iph, ihlen + 8); + qp->len = 0; + qp->ihlen = ihlen; + qp->maclen = maclen; + qp->fragments = NULL; + qp->dev = dev; +/* printk("Protocol = %d\n",qp->iph->protocol);*/ + + /* Start a timer for this entry. */ + qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ + qp->timer.data = (unsigned long) qp; /* pointer to queue */ + qp->timer.function = ip_expire; /* expire function */ + add_timer(&qp->timer); + + /* Add this entry to the queue. */ + qp->prev = NULL; + cli(); + qp->next = ipqueue; + if (qp->next != NULL) + qp->next->prev = qp; + ipqueue = qp; + sti(); + return(qp); +} + + + /* See if a fragment queue is complete. */ +static int ip_done(struct ipq *qp) +{ + struct ipfrag *fp; + int offset; + + /* Only possible if we received the final fragment. */ + if (qp->len == 0) + return(0); + + /* Check all fragment offsets to see if they connect. */ + fp = qp->fragments; + offset = 0; + while (fp != NULL) + { + if (fp->offset > offset) + return(0); /* fragment(s) missing */ + offset = fp->end; + fp = fp->next; + } + + /* All fragments are present. */ + return(1); + } + + +/* Build a new IP datagram from all its fragments. */ +static struct sk_buff *ip_glue(struct ipq *qp) +{ + struct sk_buff *skb; + struct iphdr *iph; + struct ipfrag *fp; + unsigned char *ptr; + int count, len; + + /* Allocate a new buffer for the datagram. */ + len = sizeof(struct sk_buff)+qp->maclen + qp->ihlen + qp->len; + if ((skb = alloc_skb(len,GFP_ATOMIC)) == NULL) + { + printk("IP: queue_glue: no memory for glueing queue 0x%X\n", (int) qp); + ip_free(qp); + return(NULL); + } + + /* Fill in the basic details. */ + skb->len = (len - qp->maclen); + skb->h.raw = skb->data; + skb->free = 1; + skb->lock = 1; + + /* Copy the original MAC and IP headers into the new buffer. */ + ptr = (unsigned char *) skb->h.raw; + memcpy(ptr, ((unsigned char *) qp->mac), qp->maclen); +/* printk("Copied %d bytes of mac header.\n",qp->maclen);*/ + ptr += qp->maclen; + memcpy(ptr, ((unsigned char *) qp->iph), qp->ihlen); +/* printk("Copied %d byte of ip header.\n",qp->ihlen);*/ + ptr += qp->ihlen; + skb->h.raw += qp->maclen; + +/* printk("Protocol = %d\n",skb->h.iph->protocol);*/ + count = 0; + + /* Copy the data portions of all fragments into the new buffer. */ + fp = qp->fragments; + while(fp != NULL) + { + if(count+fp->len>skb->len) + { + printk("Invalid fragment list: Fragment over size.\n"); + kfree_skb(skb,FREE_WRITE); + return NULL; + } +/* printk("Fragment %d size %d\n",fp->offset,fp->len);*/ + memcpy((ptr + fp->offset), fp->ptr, fp->len); + count += fp->len; + fp = fp->next; + } + + /* We glued together all fragments, so remove the queue entry. */ + ip_free(qp); + + /* Done with all fragments. Fixup the new IP header. */ + iph = skb->h.iph; + iph->frag_off = 0; + iph->tot_len = htons((iph->ihl * sizeof(unsigned long)) + count); + skb->ip_hdr = iph; + return(skb); +} + + +/* Process an incoming IP datagram fragment. */ +static struct sk_buff *ip_defrag(struct iphdr *iph, struct sk_buff *skb, struct device *dev) +{ + struct ipfrag *prev, *next; + struct ipfrag *tfp; + struct ipq *qp; + struct sk_buff *skb2; + unsigned char *ptr; + int flags, offset; + int i, ihl, end; + + /* Find the entry of this IP datagram in the "incomplete datagrams" queue. */ + qp = ip_find(iph); + + /* Is this a non-fragmented datagram? */ + offset = ntohs(iph->frag_off); + flags = offset & ~IP_OFFSET; + offset &= IP_OFFSET; + if (((flags & IP_MF) == 0) && (offset == 0)) + { + if (qp != NULL) + ip_free(qp); /* Huh? How could this exist?? */ + return(skb); + } + offset <<= 3; /* offset is in 8-byte chunks */ + + /* + * If the queue already existed, keep restarting its timer as long + * as we still are receiving fragments. Otherwise, create a fresh + * queue entry. + */ + if (qp != NULL) + { + del_timer(&qp->timer); + qp->timer.expires = IP_FRAG_TIME; /* about 30 seconds */ + qp->timer.data = (unsigned long) qp; /* pointer to queue */ + qp->timer.function = ip_expire; /* expire function */ + add_timer(&qp->timer); + } + else + { + if ((qp = ip_create(skb, iph, dev)) == NULL) + return(NULL); + } + + /* Determine the position of this fragment. */ + ihl = (iph->ihl * sizeof(unsigned long)); + end = offset + ntohs(iph->tot_len) - ihl; + + /* Point into the IP datagram 'data' part. */ + ptr = skb->data + dev->hard_header_len + ihl; + + /* Is this the final fragment? */ + if ((flags & IP_MF) == 0) + qp->len = end; + + /* + * Find out which fragments are in front and at the back of us + * in the chain of fragments so far. We must know where to put + * this fragment, right? + */ + prev = NULL; + for(next = qp->fragments; next != NULL; next = next->next) + { + if (next->offset > offset) + break; /* bingo! */ + prev = next; + } + + /* + * We found where to put this one. + * Check for overlap with preceeding fragment, and, if needed, + * align things so that any overlaps are eliminated. + */ + if (prev != NULL && offset < prev->end) + { + i = prev->end - offset; + offset += i; /* ptr into datagram */ + ptr += i; /* ptr into fragment data */ + DPRINTF((DBG_IP, "IP: defrag: fixed low overlap %d bytes\n", i)); + } + + /* + * Look for overlap with succeeding segments. + * If we can merge fragments, do it. + */ + + for(; next != NULL; next = tfp) + { + tfp = next->next; + if (next->offset >= end) + break; /* no overlaps at all */ + + i = end - next->offset; /* overlap is 'i' bytes */ + next->len -= i; /* so reduce size of */ + next->offset += i; /* next fragment */ + next->ptr += i; + + /* If we get a frag size of <= 0, remove it. */ + if (next->len <= 0) + { + DPRINTF((DBG_IP, "IP: defrag: removing frag 0x%X (len %d)\n", + next, next->len)); + if (next->prev != NULL) + next->prev->next = next->next; + else + qp->fragments = next->next; + + if (tfp->next != NULL) + next->next->prev = next->prev; + + kfree_s(next, sizeof(struct ipfrag)); + } + DPRINTF((DBG_IP, "IP: defrag: fixed high overlap %d bytes\n", i)); + } + + /* Insert this fragment in the chain of fragments. */ + tfp = NULL; + tfp = ip_frag_create(offset, end, skb, ptr); + tfp->prev = prev; + tfp->next = next; + if (prev != NULL) + prev->next = tfp; + else + qp->fragments = tfp; + + if (next != NULL) + next->prev = tfp; + + /* + * OK, so we inserted this new fragment into the chain. + * Check if we now have a full IP datagram which we can + * bump up to the IP layer... + */ + + if (ip_done(qp)) + { + skb2 = ip_glue(qp); /* glue together the fragments */ + return(skb2); + } + return(NULL); + } + + + /* + * This IP datagram is too large to be sent in one piece. Break it up into + * smaller pieces (each of size equal to the MAC header plus IP header plus + * a block of the data of the original IP data part) that will yet fit in a + * single device frame, and queue such a frame for sending by calling the + * ip_queue_xmit(). Note that this is recursion, and bad things will happen + * if this function causes a loop... + */ + void ip_fragment(struct sock *sk, struct sk_buff *skb, struct device *dev, int is_frag) + { + struct iphdr *iph; + unsigned char *raw; + unsigned char *ptr; + struct sk_buff *skb2; + int left, mtu, hlen, len; + int offset; + + /* Point into the IP datagram header. */ + raw = skb->data; + iph = (struct iphdr *) (raw + dev->hard_header_len); + + /* Setup starting values. */ + hlen = (iph->ihl * sizeof(unsigned long)); + left = ntohs(iph->tot_len) - hlen; + hlen += dev->hard_header_len; + mtu = (dev->mtu - hlen); + ptr = (raw + hlen); + + DPRINTF((DBG_IP, "IP: Fragmentation Desired\n")); + DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s", + dev->name, dev->mtu, left, in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr))); + + /* Check for any "DF" flag. */ + if (ntohs(iph->frag_off) & IP_DF) + { + DPRINTF((DBG_IP, "IP: Fragmentation Desired, but DF set !\n")); + DPRINTF((DBG_IP, " DEV=%s, MTU=%d, LEN=%d SRC=%s", + dev->name, dev->mtu, left, in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, " DST=%s\n", in_ntoa(iph->daddr))); + + /* + * FIXME: + * We should send an ICMP warning message here! + */ + + icmp_send(skb,ICMP_DEST_UNREACH, ICMP_FRAG_NEEDED, dev); + return; + } + + /* Fragment the datagram. */ + if (is_frag & 2) + offset = (ntohs(iph->frag_off) & 0x1fff) << 3; + else + offset = 0; + while(left > 0) + { + len = left; + if (len+8 > mtu) + len = (dev->mtu - hlen - 8); + if ((left - len) >= 8) + { + len /= 8; + len *= 8; + } + DPRINTF((DBG_IP,"IP: frag: creating fragment of %d bytes (%d total)\n", + len, len + hlen)); + + /* Allocate buffer. */ + if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len + hlen,GFP_KERNEL)) == NULL) + { + printk("IP: frag: no memory for new fragment!\n"); + return; + } + skb2->arp = skb->arp; + skb2->free = skb->free; + skb2->len = len + hlen; + skb2->h.raw=(char *) skb2->data; + + if (sk) + sk->wmem_alloc += skb2->mem_len; + + /* Copy the packet header into the new buffer. */ + memcpy(skb2->h.raw, raw, hlen); + + /* Copy a block of the IP datagram. */ + memcpy(skb2->h.raw + hlen, ptr, len); + left -= len; + + skb2->h.raw+=dev->hard_header_len; + /* Fill in the new header fields. */ + iph = (struct iphdr *)(skb2->h.raw/*+dev->hard_header_len*/); + iph->frag_off = htons((offset >> 3)); + /* Added AC : If we are fragmenting a fragment thats not the + last fragment then keep MF on each bit */ + if (left > 0 || (is_frag & 1)) + iph->frag_off |= htons(IP_MF); + ptr += len; + offset += len; +/* printk("Queue frag\n");*/ + + /* Put this fragment into the sending queue. */ + ip_queue_xmit(sk, dev, skb2, 1); +/* printk("Queued\n");*/ + } + } + + + +#ifdef CONFIG_IP_FORWARD + +/* Forward an IP datagram to its next destination. */ +static void +ip_forward(struct sk_buff *skb, struct device *dev, int is_frag) +{ + struct device *dev2; + struct iphdr *iph; + struct sk_buff *skb2; + struct rtable *rt; + unsigned char *ptr; + unsigned long raddr; + + /* + * Only forward packets that were fired at us when we are in promiscuous + * mode. In standard mode we rely on the driver to filter for us. + */ + + if(dev->flags&IFF_PROMISC) + { + if(memcmp((char *)&skb[1],dev->dev_addr,dev->addr_len)) + return; + } + + /* + * According to the RFC, we must first decrease the TTL field. If + * that reaches zero, we must reply an ICMP control message telling + * that the packet's lifetime expired. + */ + iph = skb->h.iph; + iph->ttl--; + if (iph->ttl <= 0) { + DPRINTF((DBG_IP, "\nIP: *** datagram expired: TTL=0 (ignored) ***\n")); + DPRINTF((DBG_IP, " SRC = %s ", in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, " DST = %s (ignored)\n", in_ntoa(iph->daddr))); + + /* Tell the sender its packet died... */ + icmp_send(skb, ICMP_TIME_EXCEEDED, ICMP_EXC_TTL, dev); + return; + } + + /* Re-compute the IP header checksum. */ + ip_send_check(iph); + + /* + * OK, the packet is still valid. Fetch its destination address, + * and give it to the IP sender for further processing. + */ + rt = rt_route(iph->daddr, NULL); + if (rt == NULL) { + DPRINTF((DBG_IP, "\nIP: *** routing (phase I) failed ***\n")); + + /* Tell the sender its packet cannot be delivered... */ + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_NET_UNREACH, dev); + return; + } + + + /* + * Gosh. Not only is the packet valid; we even know how to + * forward it onto its final destination. Can we say this + * is being plain lucky? + * If the router told us that there is no GW, use the dest. + * IP address itself- we seem to be connected directly... + */ + raddr = rt->rt_gateway; + if (raddr != 0) { + rt = rt_route(raddr, NULL); + if (rt == NULL) { + DPRINTF((DBG_IP, "\nIP: *** routing (phase II) failed ***\n")); + + /* Tell the sender its packet cannot be delivered... */ + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_HOST_UNREACH, dev); + return; + } + if (rt->rt_gateway != 0) raddr = rt->rt_gateway; + } else raddr = iph->daddr; + dev2 = rt->rt_dev; + + + if (dev == dev2) + return; + /* + * We now allocate a new buffer, and copy the datagram into it. + * If the indicated interface is up and running, kick it. + */ + DPRINTF((DBG_IP, "\nIP: *** fwd %s -> ", in_ntoa(iph->saddr))); + DPRINTF((DBG_IP, "%s (via %s), LEN=%d\n", + in_ntoa(raddr), dev2->name, skb->len)); + + if (dev2->flags & IFF_UP) { + 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 = skb2->data; + 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; + skb2->next = NULL; + skb2->h.raw = ptr; + + /* Copy the packet data into the new buffer. */ + memcpy(ptr + dev2->hard_header_len, skb->h.raw, skb->len); + + /* Now build the MAC header. */ + (void) ip_send(skb2, raddr, skb->len, dev2, dev2->pa_addr); + + if(skb2->len > dev2->mtu) + { + ip_fragment(NULL,skb2,dev2, is_frag); + kfree_skb(skb2,FREE_WRITE); + } + else + dev2->queue_xmit(skb2, dev2, SOPRI_NORMAL); + } +} + + +#endif + +/* This function receives all incoming IP datagrams. */ +int +ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct iphdr *iph = skb->h.iph; + unsigned char hash; + unsigned char flag = 0; + unsigned char opts_p = 0; /* Set iff the packet has options. */ + struct inet_protocol *ipprot; + static struct options opt; /* since we don't use these yet, and they + take up stack space. */ + int brd; + int is_frag=0; + + DPRINTF((DBG_IP, "<<\n")); + + skb->ip_hdr = iph; /* Fragments can cause ICMP errors too! */ + /* Is the datagram acceptable? */ + if (skb->lenihl<5 || 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))); + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + return(0); + } + + if (iph->ihl != 5) { /* Fast path for the typical optionless IP packet. */ + ip_print(iph); /* Bogus, only for debugging. */ + memset((char *) &opt, 0, sizeof(opt)); + if (do_options(iph, &opt) != 0) + return 0; + opts_p = 1; + } + + if (iph->frag_off & 0x0020) + is_frag|=1; + if (ntohs(iph->frag_off) & 0x1fff) + is_frag|=2; + + /* Do any IP forwarding required. chk_addr() is expensive -- avoid it someday. */ + if ((brd = chk_addr(iph->daddr)) == 0) { +#ifdef CONFIG_IP_FORWARD + ip_forward(skb, dev, is_frag); +#else + printk("Machine %x tried to use us as a forwarder to %x but we have forwarding disabled!\n", + iph->saddr,iph->daddr); +#endif + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + return(0); + } + + /* + * Reassemble IP fragments. + */ + + if(is_frag) + { +#ifdef CONFIG_IP_DEFRAG + skb=ip_defrag(iph,skb,dev); + if(skb==NULL) + { + return 0; + } + iph=skb->h.iph; +#else + printk("\nIP: *** datagram fragmentation not yet implemented ***\n"); + printk(" SRC = %s ", in_ntoa(iph->saddr)); + printk(" DST = %s (ignored)\n", in_ntoa(iph->daddr)); + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + return(0); +#endif + } + + + + 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); + } + + /* Point into the IP datagram, just past the header. */ + + skb->ip_hdr = iph; + skb->h.raw += iph->ihl*4; + hash = iph->protocol & (MAX_INET_PROTOS -1); + for (ipprot = (struct inet_protocol *)inet_protos[hash]; + ipprot != NULL; + ipprot=(struct inet_protocol *)ipprot->next) + { + struct sk_buff *skb2; + + if (ipprot->protocol != iph->protocol) continue; + DPRINTF((DBG_IP, "Using protocol = %X:\n", ipprot)); + print_ipprot(ipprot); + + /* + * See if we need to make a copy of it. This will + * only be set if more than one protocol wants it. + * and then not for the last one. + */ + if (ipprot->copy) { + skb2 = alloc_skb(skb->mem_len, GFP_ATOMIC); + if (skb2 == NULL) + continue; + memcpy(skb2, skb, skb->mem_len); + skb2->mem_addr = skb2; + skb2->ip_hdr = (struct iphdr *)( + (unsigned long)skb2 + + (unsigned long) skb->ip_hdr - + (unsigned long)skb); + skb2->h.raw = (unsigned char *)( + (unsigned long)skb2 + + (unsigned long) skb->h.raw - + (unsigned long)skb); + skb2->free=1; + } else { + skb2 = skb; + } + flag = 1; + + /* + * Pass on the datagram to each protocol that wants it, + * based on the datagram protocol. We should really + * check the protocol handler's return values here... + */ + ipprot->handler(skb2, dev, opts_p ? &opt : 0, iph->daddr, + (ntohs(iph->tot_len) - (iph->ihl * 4)), + iph->saddr, 0, ipprot); + + } + + /* + * All protocols checked. + * If this packet was a broadcast, we may *not* reply to it, since that + * causes (proven, grin) ARP storms and a leakage of memory (i.e. all + * ICMP reply messages get queued up for transmission...) + */ + if (!flag) { + if (brd != IS_BROADCAST) + icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PROT_UNREACH, dev); + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + } + + return(0); +} + + +/* + * Queues a packet to be sent, and starts the transmitter + * if necessary. if free = 1 then we free the block after + * transmit, otherwise we don't. + * This routine also needs to put in the total length, and + * compute the checksum. + */ +void +ip_queue_xmit(struct sock *sk, struct device *dev, + struct sk_buff *skb, int free) +{ + struct iphdr *iph; + unsigned char *ptr; + + if (sk == NULL) free = 1; + if (dev == NULL) { + 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 = skb->data; + ptr += dev->hard_header_len; + iph = (struct iphdr *)ptr; + iph->tot_len = ntohs(skb->len-dev->hard_header_len); + + if(skb->len > dev->mtu) + { +/* printk("Fragment!\n");*/ + ip_fragment(sk,skb,dev,0); + IS_SKB(skb); + kfree_skb(skb,FREE_WRITE); + return; + } + + ip_send_check(iph); + ip_print(iph); + skb->next = NULL; + + /* See if this is the one trashing our queue. Ross? */ + skb->magic = 1; + if (!free) { + skb->link3 = NULL; + sk->packets_out++; + cli(); + if (sk->send_head == NULL) { + sk->send_tail = skb; + sk->send_head = skb; + } else { + /* See if we've got a problem. */ + if (sk->send_tail == NULL) { + printk("IP: ***bug sk->send_tail == NULL != sk->send_head\n"); + sort_send(sk); + } else { + sk->send_tail->link3 = skb; + sk->send_tail = skb; + } + } + sti(); + reset_timer(sk, TIME_WRITE, sk->rto); + } else { + skb->sk = sk; + } + + /* If the indicated interface is up and running, kick it. */ + if (dev->flags & IFF_UP) { + if (sk != NULL) { + dev->queue_xmit(skb, dev, sk->priority); + } + else { + dev->queue_xmit(skb, dev, SOPRI_NORMAL); + } + } else { + if (free) kfree_skb(skb, FREE_WRITE); + } +} + + +void +ip_do_retransmit(struct sock *sk, int all) +{ + struct sk_buff * skb; + struct proto *prot; + struct device *dev; + int retransmits; + + prot = sk->prot; + skb = sk->send_head; + retransmits = sk->retransmits; + while (skb != NULL) { + dev = skb->dev; + /* I know this can't happen but as it does.. */ + if(dev==NULL) + { + 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(skb->data, 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 && !skb_device_locked(skb)) + dev->queue_xmit(skb, dev, sk->priority); + /* else dev->queue_xmit(skb, dev, SOPRI_NORMAL ); CANNOT HAVE SK=NULL HERE */ + } + +oops: retransmits++; + sk->prot->retransmits ++; + if (!all) break; + + /* This should cut it off before we send too many packets. */ + if (sk->retransmits > sk->cong_window) break; + skb = (struct sk_buff *)skb->link3; + } +} + +/* + * This is the normal code called for timeouts. It does the retransmission + * and then does backoff. ip_do_retransmit is separated out because + * tcp_ack needs to send stuff from the retransmit queue without + * initiating a backoff. + */ + +void +ip_retransmit(struct sock *sk, int all) +{ + ip_do_retransmit(sk, all); + + /* + * Increase the timeout each time we retransmit. Note that + * we do not increase the rtt estimate. rto is initialized + * from rtt, but increases here. Jacobson (SIGCOMM 88) suggests + * that doubling rto each time is the least we can get away with. + * In KA9Q, Karns uses this for the first few times, and then + * goes to quadratic. netBSD doubles, but only goes up to *64, + * and clamps at 1 to 64 sec afterwards. Note that 120 sec is + * defined in the protocol as the maximum possible RTT. I guess + * we'll have to use something other than TCP to talk to the + * University of Mars. + */ + + sk->retransmits++; + sk->backoff++; + sk->rto = min(sk->rto << 1, 120*HZ); + reset_timer(sk, TIME_WRITE, sk->rto); +} + +/* + * Socket option code for IP. This is the end of the line after any TCP,UDP etc options on + * an IP socket. + */ + +int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) +{ + int val,err; + + if (optval == NULL) + return(-EINVAL); + + err=verify_area(VERIFY_READ, optval, sizeof(int)); + if(err) + return err; + + val = get_fs_long((unsigned long *)optval); + + if(level!=SOL_IP) + return -EOPNOTSUPP; + + switch(optname) + { + case IP_TOS: + if(val<0||val>255) + return -EINVAL; + sk->ip_tos=val; + return 0; + case IP_TTL: + if(val<1||val>255) + return -EINVAL; + sk->ip_ttl=val; + return 0; + /* IP_OPTIONS and friends go here eventually */ + default: + return(-ENOPROTOOPT); + } +} + +int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) +{ + int val,err; + + if(level!=SOL_IP) + return -EOPNOTSUPP; + + switch(optname) + { + case IP_TOS: + val=sk->ip_tos; + break; + case IP_TTL: + val=sk->ip_ttl; + break; + default: + return(-ENOPROTOOPT); + } + err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); + if(err) + return err; + put_fs_long(sizeof(int),(unsigned long *) optlen); + + err=verify_area(VERIFY_WRITE, optval, sizeof(int)); + if(err) + return err; + put_fs_long(val,(unsigned long *)optval); + + return(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.h new file mode 100644 index 000000000..7f2ecc00d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/ip.h @@ -0,0 +1,84 @@ +/* + * 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 IP module. + * + * Version: @(#)ip.h 1.0.2 05/07/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _IP_H +#define _IP_H + + +#include + + +#include "sock.h" /* struct sock */ + +/* IP flags. */ +#define IP_CE 0x8000 /* Flag: "Congestion" */ +#define IP_DF 0x4000 /* Flag: "Don't Fragment" */ +#define IP_MF 0x2000 /* Flag: "More Fragments" */ +#define IP_OFFSET 0x1FFF /* "Fragment Offset" part */ + +#define IP_FRAG_TIME (30 * HZ) /* fragment lifetime */ + + +/* Describe an IP fragment. */ +struct ipfrag { + int offset; /* offset of fragment in IP datagram */ + int end; /* last byte of data in datagram */ + int len; /* length of this fragment */ + struct sk_buff *skb; /* complete received fragment */ + unsigned char *ptr; /* pointer into real fragment data */ + struct ipfrag *next; /* linked list pointers */ + struct ipfrag *prev; +}; + +/* Describe an entry in the "incomplete datagrams" queue. */ +struct ipq { + unsigned char *mac; /* pointer to MAC header */ + struct iphdr *iph; /* pointer to IP header */ + int len; /* total length of original datagram */ + short ihlen; /* length of the IP header */ + short maclen; /* length of the MAC header */ + struct timer_list timer; /* when will this queue expire? */ + struct ipfrag *fragments; /* linked list of received fragments */ + struct ipq *next; /* linked list pointers */ + struct ipq *prev; + struct device *dev; /* Device - for icmp replies */ +}; + + +extern int backoff(int n); + +extern void ip_print(struct iphdr *ip); +extern int ip_ioctl(struct sock *sk, int cmd, + unsigned long arg); +extern void ip_route_check(unsigned long daddr); +extern int ip_build_header(struct sk_buff *skb, + unsigned long saddr, + unsigned long daddr, + struct device **dev, int type, + struct options *opt, int len, + int tos,int ttl); +extern unsigned short ip_compute_csum(unsigned char * buff, int len); +extern int ip_rcv(struct sk_buff *skb, struct device *dev, + struct packet_type *pt); +extern void ip_queue_xmit(struct sock *sk, + struct device *dev, struct sk_buff *skb, + int free); +extern void ip_retransmit(struct sock *sk, int all); +extern int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen); +extern int ip_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen); + +#endif /* _IP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/loopback.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/loopback.c new file mode 100644 index 000000000..a7e69e389 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/loopback.c @@ -0,0 +1,137 @@ +/* + * 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. + * + * Pseudo-driver for the loopback interface. + * + * Version: @(#)loopback.c 1.0.4b 08/16/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Donald Becker, + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include /* For the statistics structure. */ + +#include +#include +#include + +#include "inet.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" + + +static int +loopback_xmit(struct sk_buff *skb, struct device *dev) +{ + struct enet_statistics *stats = (struct enet_statistics *)dev->priv; + int done; + + DPRINTF((DBG_LOOPB, "loopback_xmit(dev=%X, skb=%X)\n", dev, skb)); + if (skb == NULL || dev == NULL) return(0); + + cli(); + if (dev->tbusy != 0) { + sti(); + stats->tx_errors++; + return(1); + } + dev->tbusy = 1; + sti(); + + done = dev_rint(skb->data, skb->len, 0, dev); + if (skb->free) kfree_skb(skb, FREE_WRITE); + + while (done != 1) { + done = dev_rint(NULL, 0, 0, dev); + } + stats->tx_packets++; + + dev->tbusy = 0; + +#if 1 + __asm__("cmpl $0,_intr_count\n\t" + "jne 1f\n\t" + "movl _bh_active,%%eax\n\t" + "testl _bh_mask,%%eax\n\t" + "je 1f\n\t" + "incl _intr_count\n\t" + "call _do_bottom_half\n\t" + "decl _intr_count\n" + "1:" + : + : + : "ax", "dx", "cx"); +#endif + + return(0); +} + +static struct enet_statistics * +get_stats(struct device *dev) +{ + return (struct enet_statistics *)dev->priv; +} + +/* Initialize the rest of the LOOPBACK device. */ +int +loopback_init(struct device *dev) +{ + dev->mtu = 2000; /* MTU */ + dev->tbusy = 0; + dev->hard_start_xmit = loopback_xmit; + dev->open = NULL; +#if 1 + dev->hard_header = eth_header; + dev->add_arp = NULL; + dev->hard_header_len = ETH_HLEN; /* 14 */ + dev->addr_len = ETH_ALEN; /* 6 */ + dev->type = ARPHRD_ETHER; /* 0x0001 */ + dev->type_trans = eth_type_trans; + dev->rebuild_header = eth_rebuild_header; +#else + dev->hard_header_length = 0; + dev->add_arp = NULL; + dev->addr_len = 0; + dev->type = 0; /* loopback_type (0) */ + dev->hard_header = NULL; + dev->type_trans = NULL; + dev->rebuild_header = NULL; +#endif + dev->queue_xmit = dev_queue_xmit; + + /* New-style flags. */ + dev->flags = IFF_LOOPBACK; + dev->family = AF_INET; + dev->pa_addr = in_aton("127.0.0.1"); + dev->pa_brdaddr = in_aton("127.255.255.255"); + dev->pa_mask = in_aton("255.0.0.0"); + dev->pa_alen = sizeof(unsigned long); + dev->priv = kmalloc(sizeof(struct enet_statistics), GFP_KERNEL); + memset(dev->priv, 0, sizeof(struct enet_statistics)); + dev->get_stats = get_stats; + + return(0); +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/packet.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/packet.c new file mode 100644 index 000000000..c81209a47 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/packet.c @@ -0,0 +1,275 @@ +/* + * 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. + * + * PACKET - implements raw packet sockets. + * + * Version: @(#)packet.c 1.0.6 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + * Alan Cox : Uses the improved datagram code. + * Alan Cox : Added NULL's for socket options. + * + * + * 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 +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include +#include +#include +#include +#include "udp.h" +#include "raw.h" + + +static unsigned long +min(unsigned long a, unsigned long b) +{ + if (a < b) return(a); + return(b); +} + + +/* This should be the easiest of all, all we do is copy it into a buffer. */ +int +packet_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) +{ + struct sock *sk; + + sk = (struct sock *) pt->data; + skb->dev = dev; + skb->len += dev->hard_header_len; + + skb->sk = sk; + + /* Charge it too the socket. */ + 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; + skb_queue_tail(&sk->rqueue,skb); + wake_up_interruptible(sk->sleep); + release_sock(sk); + return(0); +} + + +/* This will do terrible things if len + ipheader + devheader > dev->mtu */ +static int +packet_sendto(struct sock *sk, unsigned char *from, int len, + int noblock, unsigned flags, struct sockaddr_in *usin, + int addr_len) +{ + struct sk_buff *skb; + struct device *dev; + struct sockaddr saddr; + int err; + + /* Check the flags. */ + if (flags) return(-EINVAL); + if (len < 0) return(-EINVAL); + + /* Get and verify the address. */ + if (usin) { + if (addr_len < sizeof(saddr)) return(-EINVAL); + 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 = 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(-ENOMEM); + } + /* Fill it in */ + skb->mem_addr = skb; + skb->mem_len = len + sizeof(*skb); + skb->sk = sk; + skb->free = 1; + memcpy_fromfs(skb->data, from, len); + skb->len = len; + skb->next = NULL; + skb->arp = 1; + if (dev->flags & IFF_UP) dev->queue_xmit(skb, dev, sk->priority); + else kfree_skb(skb, FREE_WRITE); + return(len); +} + + +static int +packet_write(struct sock *sk, unsigned char *buff, + int len, int noblock, unsigned flags) +{ + return(packet_sendto(sk, buff, len, noblock, flags, NULL, 0)); +} + + +static void +packet_close(struct sock *sk, int timeout) +{ + sk->inuse = 1; + sk->state = TCP_CLOSE; + dev_remove_pack((struct packet_type *)sk->pair); + kfree_s((void *)sk->pair, sizeof(struct packet_type)); + sk->pair = NULL; + release_sock(sk); +} + + +static int +packet_init(struct sock *sk) +{ + struct packet_type *p; + + p = (struct packet_type *) kmalloc(sizeof(*p), GFP_KERNEL); + if (p == NULL) return(-ENOMEM); + + p->func = packet_rcv; + p->type = sk->num; + p->data = (void *)sk; + dev_add_pack(p); + + /* We need to remember this somewhere. */ + sk->pair = (struct sock *)p; + + return(0); +} + + +/* + * This should be easy, if there is something there + * we return it, otherwise we block. + */ +int +packet_recvfrom(struct sock *sk, unsigned char *to, int len, + int noblock, unsigned flags, struct sockaddr_in *sin, + int *addr_len) +{ + int copied=0; + struct sk_buff *skb; + struct sockaddr *saddr; + int err; + + saddr = (struct sockaddr *)sin; + if (len == 0) return(0); + if (len < 0) return(-EINVAL); + + if (sk->shutdown & RCV_SHUTDOWN) return(0); + if (addr_len) { + err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); + if(err) + return err; + put_fs_long(sizeof(*saddr), addr_len); + } + + 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); + + memcpy_tofs(to, skb->data, copied); /* Don't use skb_copy_datagram here: We can't get frag chains */ + + /* Copy the address. */ + if (saddr) { + struct sockaddr addr; + + addr.sa_family = skb->dev->type; + memcpy(addr.sa_data,skb->dev->name, 14); + verify_area(VERIFY_WRITE, saddr, sizeof(*saddr)); + memcpy_tofs(saddr, &addr, sizeof(*saddr)); + } + + skb_free_datagram(skb); /* Its either been used up, or its a peek_copy anyway */ + + release_sock(sk); + return(copied); +} + + +int +packet_read(struct sock *sk, unsigned char *buff, + int len, int noblock, unsigned flags) +{ + return(packet_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); +} + + +struct proto packet_prot = { + sock_wmalloc, + sock_rmalloc, + sock_wfree, + sock_rfree, + sock_rspace, + sock_wspace, + packet_close, + packet_read, + packet_write, + packet_sendto, + packet_recvfrom, + ip_build_header, + udp_connect, + NULL, + ip_queue_xmit, + ip_retransmit, + NULL, + NULL, + NULL, + datagram_select, + NULL, + packet_init, + NULL, + NULL, /* No set/get socket options */ + NULL, + 128, + 0, + {NULL,}, + "PACKET" +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/proc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/proc.c new file mode 100644 index 000000000..d5bc16e91 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/proc.c @@ -0,0 +1,133 @@ +/* + * 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. + * + * This file implements the various access functions for the + * PROC file system. It is mainly used for debugging and + * statistics. + * + * Version: @(#)proc.c 1.0.5 05/27/93 + * + * Authors: Fred N. van Kempen, + * Gerald J. Heim, + * Fred Baumgarten, + * + * Fixes: + * Alan Cox : UDP sockets show the rxqueue/txqueue + * using hint flag for the netinfo. + * Pauline Middelink : Pidentd support + * Alan Cox : Make /proc safer. + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "udp.h" +#include "skbuff.h" +#include "sock.h" +#include "raw.h" + +/* + * Get__netinfo returns the length of that string. + * + * KNOWN BUGS + * As in get_unix_netinfo, the buffer might be too small. If this + * happens, get__netinfo returns only part of the available infos. + */ +static int +get__netinfo(struct proto *pro, char *buffer, int format) +{ + struct sock **s_array; + struct sock *sp; + char *pos=buffer; + int i; + int timer_active; + unsigned long dest, src; + 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 uid\n"); +/* + * This was very pretty but didn't work when a socket is destroyed at the wrong moment + * (eg a syn recv socket getting a reset), or a memory timer destroy. Instead of playing + * with timers we just concede defeat and cli(). + */ + for(i = 0; i < SOCK_ARRAY_SIZE; i++) { + cli(); + sp = s_array[i]; + while(sp != NULL) { + dest = sp->daddr; + src = sp->saddr; + destp = sp->dummy_th.dest; + srcp = sp->dummy_th.source; + + /* Since we are Little Endian we need to swap the bytes :-( */ + destp = ntohs(destp); + srcp = ntohs(srcp); + timer_active = del_timer(&sp->timer); + if (!timer_active) + sp->timer.expires = 0; + pos+=sprintf(pos, "%2d: %08lX:%04X %08lX:%04X %02X %08lX:%08lX %02X:%08lX %08X %d\n", + i, src, srcp, dest, destp, sp->state, + 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, (unsigned) sp->retransmits, + SOCK_INODE(sp->socket)->i_uid); + if (timer_active) + add_timer(&sp->timer); + /* Is place in buffer too rare? then abort. */ + if (pos > buffer+PAGE_SIZE-80) { + printk("oops, too many %s sockets for netinfo.\n", + pro->name); + return(strlen(buffer)); + } + + /* + * All sockets with (port mod SOCK_ARRAY_SIZE) = i + * are kept in sock_array[i], so we must follow the + * 'next' link to get them all. + */ + sp = sp->next; + } + sti(); /* We only turn interrupts back on for a moment, but because the interrupt queues anything built up + before this will clear before we jump back and cli, so its not as bad as it looks */ + } + return(strlen(buffer)); +} + + +int tcp_get_info(char *buffer) +{ + return get__netinfo(&tcp_prot, buffer,0); +} + + +int udp_get_info(char *buffer) +{ + return get__netinfo(&udp_prot, buffer,1); +} + + +int raw_get_info(char *buffer) +{ + return get__netinfo(&raw_prot, buffer,1); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.c new file mode 100644 index 000000000..569026787 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.c @@ -0,0 +1,161 @@ +/* + * 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. + * + * INET protocol dispatch tables. + * + * Version: @(#)protocol.c 1.0.5 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "icmp.h" +#include "udp.h" + + +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 */ + "TCP" /* name */ +}; + + +static struct inet_protocol udp_protocol = { + udp_rcv, /* UDP handler */ + NULL, /* Will be UDP fraglist handler */ + udp_err, /* UDP error control */ + &tcp_protocol, /* next */ + IPPROTO_UDP, /* protocol ID */ + 0, /* copy */ + 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 */ + "ICMP" /* name */ +}; + + +struct inet_protocol *inet_protocol_base = &icmp_protocol; +struct inet_protocol *inet_protos[MAX_INET_PROTOS] = { + NULL +}; + + +struct inet_protocol * +inet_get_protocol(unsigned char prot) +{ + unsigned char hash; + struct inet_protocol *p; + + DPRINTF((DBG_PROTO, "get_protocol (%d)\n ", prot)); + hash = prot & (MAX_INET_PROTOS - 1); + for (p = inet_protos[hash] ; p != NULL; p=p->next) { + DPRINTF((DBG_PROTO, "trying protocol %d\n", p->protocol)); + if (p->protocol == prot) return((struct inet_protocol *) p); + } + return(NULL); +} + + +void +inet_add_protocol(struct inet_protocol *prot) +{ + unsigned char hash; + struct inet_protocol *p2; + + hash = prot->protocol & (MAX_INET_PROTOS - 1); + prot ->next = inet_protos[hash]; + inet_protos[hash] = prot; + prot->copy = 0; + + /* Set the copy bit if we need to. */ + p2 = (struct inet_protocol *) prot->next; + while(p2 != NULL) { + if (p2->protocol == prot->protocol) { + prot->copy = 1; + break; + } + p2 = (struct inet_protocol *) prot->next; + } +} + + +int +inet_del_protocol(struct inet_protocol *prot) +{ + struct inet_protocol *p; + struct inet_protocol *lp = NULL; + unsigned char hash; + + hash = prot->protocol & (MAX_INET_PROTOS - 1); + if (prot == inet_protos[hash]) { + inet_protos[hash] = (struct inet_protocol *) inet_protos[hash]->next; + return(0); + } + + p = (struct inet_protocol *) inet_protos[hash]; + while(p != NULL) { + /* + * We have to worry if the protocol being deleted is + * the last one on the list, then we may need to reset + * someones copied bit. + */ + if (p->next != NULL && p->next == prot) { + /* + * if we are the last one with this protocol and + * there is a previous one, reset its copy bit. + */ + if (p->copy == 0 && lp != NULL) lp->copy = 0; + p->next = prot->next; + return(0); + } + + if (p->next != NULL && p->next->protocol == prot->protocol) { + lp = p; + } + + p = (struct inet_protocol *) p->next; + } + return(-1); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.h new file mode 100644 index 000000000..3e0b6fb3c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/protocol.h @@ -0,0 +1,59 @@ +/* + * 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 protocol dispatcher. + * + * Version: @(#)protocol.h 1.0.2 05/07/93 + * + * Author: Fred N. van Kempen, + * + * 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. + * + * Changes: + * Alan Cox : Added a name field and a frag handler + * field for later. + */ + +#ifndef _PROTOCOL_H +#define _PROTOCOL_H + + +#define MAX_INET_PROTOS 32 /* Must be a power of 2 */ + + +/* This is used to register protocols. */ +struct inet_protocol { + int (*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); + 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, + struct inet_protocol *protocol); + struct inet_protocol *next; + unsigned char protocol; + unsigned char copy:1; + void *data; + char *name; +}; + + +extern struct inet_protocol *inet_protocol_base; +extern struct inet_protocol *inet_protos[MAX_INET_PROTOS]; + + +extern void inet_add_protocol(struct inet_protocol *prot); +extern int inet_del_protocol(struct inet_protocol *prot); + + +#endif /* _PROTOCOL_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.c new file mode 100644 index 000000000..91563d7f6 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.c @@ -0,0 +1,410 @@ +/* + * 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. + * + * RAW - implementation of IP "raw" sockets. + * + * Version: @(#)raw.c 1.0.4 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + * Alan Cox : Uses skb_free_datagram/skb_copy_datagram + * Alan Cox : Raw passes ip options too + * Alan Cox : Setsocketopt added + * Alan Cox : Fixed error return for broadcasts + * Alan Cox : Removed wake_up calls + * Alan Cox : Use ttl/tos + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "icmp.h" +#include "udp.h" + + +static unsigned long +min(unsigned long a, unsigned long b) +{ + if (a < b) return(a); + return(b); +} + + +/* raw_err gets called by the icmp module. */ +void +raw_err (int err, unsigned char *header, unsigned long daddr, + unsigned long saddr, struct inet_protocol *protocol) +{ + struct sock *sk; + + DPRINTF((DBG_RAW, "raw_err(err=%d, hdr=%X, daddr=%X, saddr=%X, protocl=%X)\n", + err, header, daddr, saddr, protocol)); + + if (protocol == NULL) return; + sk = (struct sock *) protocol->data; + if (sk == NULL) return; + + /* This is meaningless in raw sockets. */ + if (err & 0xff00 == (ICMP_SOURCE_QUENCH << 8)) { + if (sk->cong_window > 1) sk->cong_window = sk->cong_window/2; + return; + } + + sk->err = icmp_err_convert[err & 0xff].errno; + sk->error_report(sk); + + return; +} + + +/* + * This should be the easiest of all, all we do is\ + * copy it into a buffer. + */ +int +raw_rcv(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) +{ + struct sock *sk; + + DPRINTF((DBG_RAW, "raw_rcv(skb=%X, dev=%X, opt=%X, daddr=%X,\n" + " len=%d, saddr=%X, redo=%d, protocol=%X)\n", + skb, dev, opt, daddr, len, saddr, redo, protocol)); + + if (skb == NULL) return(0); + if (protocol == NULL) { + kfree_skb(skb, FREE_READ); + return(0); + } + sk = (struct sock *) protocol->data; + if (sk == NULL) { + kfree_skb(skb, FREE_READ); + return(0); + } + + /* Now we need to copy this into memory. */ + skb->sk = sk; + skb->len = len + skb->ip_hdr->ihl*sizeof(long); + skb->h.raw = skb->ip_hdr; + skb->dev = dev; + skb->saddr = daddr; + skb->daddr = saddr; + + /* Charge it too the socket. */ + 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; + skb_queue_tail(&sk->rqueue,skb); + sk->data_ready(sk,skb->len); + release_sock(sk); + return(0); +} + + +/* This will do terrible things if len + ipheader + devheader > dev->mtu */ +static int +raw_sendto(struct sock *sk, unsigned char *from, int len, + int noblock, + unsigned flags, struct sockaddr_in *usin, int addr_len) +{ + struct sk_buff *skb; + 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, + flags, usin, addr_len)); + + /* Check the flags. */ + 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); + 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 { + if (sk->state != TCP_ESTABLISHED) return(-EINVAL); + sin.sin_family = AF_INET; + sin.sin_port = sk->protocol; + 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 -EACCES; + + sk->inuse = 1; + skb = NULL; + while (skb == NULL) { + if(sk->err!=0) + { + err= -sk->err; + sk->err=0; + release_sock(sk); + return(err); + } + + skb = sk->prot->wmalloc(sk, + len+sizeof(*skb) + sk->prot->max_header, + 0, GFP_KERNEL); + if (skb == NULL) { + int tmp; + + DPRINTF((DBG_RAW, "raw_sendto: write buffer full?\n")); + if (noblock) + return(-EAGAIN); + tmp = sk->wmem_alloc; + release_sock(sk); + cli(); + if (tmp <= sk->wmem_alloc) { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + return(-ERESTARTSYS); + } + } + sk->inuse = 1; + sti(); + } + } + skb->mem_addr = skb; + skb->mem_len = len + sizeof(*skb) +sk->prot->max_header; + skb->sk = sk; + + skb->free = 1; /* these two should be unecessary. */ + skb->arp = 0; + + tmp = sk->prot->build_header(skb, sk->saddr, + sin.sin_addr.s_addr, &dev, + sk->protocol, sk->opt, skb->mem_len, sk->ip_tos,sk->ip_ttl); + if (tmp < 0) { + DPRINTF((DBG_RAW, "raw_sendto: error building ip header.\n")); + kfree_skb(skb,FREE_WRITE); + release_sock(sk); + return(tmp); + } + + /* verify_area(VERIFY_WRITE, from, len);*/ + memcpy_fromfs(skb->data + tmp, from, len); + + /* If we are using IPPROTO_RAW, we need to fill in the source address in + the IP header */ + + if(sk->protocol==IPPROTO_RAW) { + unsigned char *buff; + struct iphdr *iph; + + buff = skb->data; + buff += tmp; + iph = (struct iphdr *)buff; + iph->saddr = sk->saddr; + } + + skb->len = tmp + len; + + if(dev!=NULL && skb->len > 4095) + { + kfree_skb(skb, FREE_WRITE); + release_sock(sk); + return(-EMSGSIZE); + } + + sk->prot->queue_xmit(sk, dev, skb, 1); + release_sock(sk); + return(len); +} + + +static int +raw_write(struct sock *sk, unsigned char *buff, int len, int noblock, + unsigned flags) +{ + return(raw_sendto(sk, buff, len, noblock, flags, NULL, 0)); +} + + +static void +raw_close(struct sock *sk, int timeout) +{ + sk->inuse = 1; + sk->state = TCP_CLOSE; + + DPRINTF((DBG_RAW, "raw_close: deleting protocol %d\n", + ((struct inet_protocol *)sk->pair)->protocol)); + + if (inet_del_protocol((struct inet_protocol *)sk->pair) < 0) + DPRINTF((DBG_RAW, "raw_close: del_protocol failed.\n")); + kfree_s((void *)sk->pair, sizeof (struct inet_protocol)); + sk->pair = NULL; + release_sock(sk); +} + + +static int +raw_init(struct sock *sk) +{ + struct inet_protocol *p; + + p = (struct inet_protocol *) kmalloc(sizeof (*p), GFP_KERNEL); + if (p == NULL) return(-ENOMEM); + + p->handler = raw_rcv; + 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. */ + sk->pair = (struct sock *)p; + + DPRINTF((DBG_RAW, "raw init added protocol %d\n", sk->protocol)); + + return(0); +} + + +/* + * This should be easy, if there is something there + * we return it, otherwise we block. + */ +int +raw_recvfrom(struct sock *sk, unsigned char *to, int len, + int noblock, unsigned flags, struct sockaddr_in *sin, + int *addr_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", + sk, to, len, noblock, flags, sin, addr_len)); + + if (len == 0) return(0); + if (len < 0) return(-EINVAL); + + if (sk->shutdown & RCV_SHUTDOWN) return(0); + if (addr_len) { + err=verify_area(VERIFY_WRITE, addr_len, sizeof(*addr_len)); + if(err) + return err; + put_fs_long(sizeof(*sin), addr_len); + } + if(sin) + { + err=verify_area(VERIFY_WRITE, sin, sizeof(*sin)); + if(err) + return err; + } + + 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); + + skb_copy_datagram(skb, 0, to, copied); + + /* Copy the address. */ + if (sin) { + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_addr.s_addr = skb->daddr; + memcpy_tofs(sin, &addr, sizeof(*sin)); + } + + skb_free_datagram(skb); + release_sock(sk); + return (copied); +} + + +int +raw_read (struct sock *sk, unsigned char *buff, int len, int noblock, + unsigned flags) +{ + return(raw_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); +} + + +struct proto raw_prot = { + sock_wmalloc, + sock_rmalloc, + sock_wfree, + sock_rfree, + sock_rspace, + sock_wspace, + raw_close, + raw_read, + raw_write, + raw_sendto, + raw_recvfrom, + ip_build_header, + udp_connect, + NULL, + ip_queue_xmit, + ip_retransmit, + NULL, + NULL, + raw_rcv, + datagram_select, + NULL, + raw_init, + NULL, + ip_setsockopt, + ip_getsockopt, + 128, + 0, + {NULL,}, + "RAW" +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.h new file mode 100644 index 000000000..80cb4b4bf --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/raw.h @@ -0,0 +1,36 @@ +/* + * 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 RAW-IP module. + * + * Version: @(#)raw.h 1.0.2 05/07/93 + * + * Author: Fred N. van Kempen, + * + * 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. + */ +#ifndef _RAW_H +#define _RAW_H + + +extern struct proto raw_prot; + + +extern void raw_err(int err, unsigned char *header, unsigned long daddr, + unsigned long saddr, struct inet_protocol *protocol); +extern int raw_rcv(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); +extern int raw_recvfrom(struct sock *sk, unsigned char *to, + int len, int noblock, unsigned flags, + struct sockaddr_in *sin, int *addr_len); +extern int raw_read(struct sock *sk, unsigned char *buff, + int len, int noblock, unsigned flags); + +#endif /* _RAW_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.c new file mode 100644 index 000000000..9624d5aa9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.c @@ -0,0 +1,384 @@ +/* + * 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. + * + * ROUTE - implementation of the IP router. + * + * Version: @(#)route.c 1.0.14 05/31/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * Fixes: + * Alan Cox : Verify area fixes. + * Alan Cox : cli() protects routing changes + * Rui Oliveira : ICMP routing table updates + * (rco@di.uminho.pt) Routing table insertion and update + * Linus Torvalds : Rewrote bits to be sensible + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "route.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" +#include "icmp.h" + + +static struct rtable *rt_base = NULL; +static struct rtable *rt_loopback = NULL; + +/* Dump the contents of a routing table entry. */ +static void +rt_print(struct rtable *rt) +{ + if (rt == NULL || inet_debug != DBG_RT) return; + + printk("RT: %06lx NXT=%06lx FLAGS=0x%02x\n", + (long) rt, (long) rt->rt_next, rt->rt_flags); + printk(" TARGET=%s ", in_ntoa(rt->rt_dst)); + printk("GW=%s ", in_ntoa(rt->rt_gateway)); + printk(" DEV=%s USE=%ld REF=%d\n", + (rt->rt_dev == NULL) ? "NONE" : rt->rt_dev->name, + rt->rt_use, rt->rt_refcnt); +} + + +/* + * Remove a routing table entry. + */ +static void rt_del(unsigned long dst) +{ + struct rtable *r, **rp; + unsigned long flags; + + DPRINTF((DBG_RT, "RT: flushing for dst %s\n", in_ntoa(dst))); + rp = &rt_base; + save_flags(flags); + cli(); + while((r = *rp) != NULL) { + if (r->rt_dst != dst) { + rp = &r->rt_next; + continue; + } + *rp = r->rt_next; + if (rt_loopback == r) + rt_loopback = NULL; + kfree_s(r, sizeof(struct rtable)); + } + restore_flags(flags); +} + + +/* + * Remove all routing table entries for a device. + */ +void rt_flush(struct device *dev) +{ + struct rtable *r; + struct rtable **rp; + unsigned long flags; + + DPRINTF((DBG_RT, "RT: flushing for dev 0x%08lx (%s)\n", (long)dev, dev->name)); + rp = &rt_base; + cli(); + save_flags(flags); + while ((r = *rp) != NULL) { + if (r->rt_dev != dev) { + rp = &r->rt_next; + continue; + } + *rp = r->rt_next; + if (rt_loopback == r) + rt_loopback = NULL; + kfree_s(r, sizeof(struct rtable)); + } + restore_flags(flags); +} + +/* + * Used by 'rt_add()' when we can't get the netmask any other way.. + * + * If the lower byte or two are zero, we guess the mask based on the + * number of zero 8-bit net numbers, otherwise we use the "default" + * masks judging by the destination address and our device netmask. + */ +static inline unsigned long default_mask(unsigned long dst) +{ + dst = ntohl(dst); + if (IN_CLASSA(dst)) + return htonl(IN_CLASSA_NET); + if (IN_CLASSB(dst)) + return htonl(IN_CLASSB_NET); + return htonl(IN_CLASSC_NET); +} + +static unsigned long guess_mask(unsigned long dst, struct device * dev) +{ + unsigned long mask; + + if (!dst) + return 0; + mask = default_mask(dst); + if ((dst ^ dev->pa_addr) & mask) + return mask; + return dev->pa_mask; +} + +static inline struct device * get_gw_dev(unsigned long gw) +{ + struct rtable * rt; + + for (rt = rt_base ; ; rt = rt->rt_next) { + if (!rt) + return NULL; + if ((gw ^ rt->rt_dst) & rt->rt_mask) + continue; + /* gateways behind gateways are a no-no */ + if (rt->rt_flags & RTF_GATEWAY) + return NULL; + return rt->rt_dev; + } +} + +/* + * rewrote rt_add(), as the old one was weird. Linus + */ +void rt_add(short flags, unsigned long dst, unsigned long mask, + unsigned long gw, struct device *dev) +{ + struct rtable *r, *rt; + struct rtable **rp; + unsigned long cpuflags; + + if (flags & RTF_HOST) { + mask = 0xffffffff; + } else if (!mask) { + if (!((dst ^ dev->pa_addr) & dev->pa_mask)) { + mask = dev->pa_mask; + flags &= ~RTF_GATEWAY; + if (flags & RTF_DYNAMIC) { + /*printk("Dynamic route to my own net rejected\n");*/ + return; + } + } else + mask = guess_mask(dst, dev); + dst &= mask; + } + if (gw == dev->pa_addr) + flags &= ~RTF_GATEWAY; + if (flags & RTF_GATEWAY) { + /* don't try to add a gateway we can't reach.. */ + if (dev != get_gw_dev(gw)) + return; + flags |= RTF_GATEWAY; + } else + gw = 0; + /* Allocate an entry. */ + rt = (struct rtable *) kmalloc(sizeof(struct rtable), GFP_ATOMIC); + if (rt == NULL) { + DPRINTF((DBG_RT, "RT: no memory for new route!\n")); + return; + } + memset(rt, 0, sizeof(struct rtable)); + rt->rt_flags = flags | RTF_UP; + rt->rt_dst = dst; + rt->rt_dev = dev; + rt->rt_gateway = gw; + rt->rt_mask = mask; + rt->rt_mtu = dev->mtu; + rt_print(rt); + /* + * What we have to do is loop though this until we have + * found the first address which has a higher generality than + * the one in rt. Then we can put rt in right before it. + */ + save_flags(cpuflags); + cli(); + /* remove old route if we are getting a duplicate. */ + rp = &rt_base; + while ((r = *rp) != NULL) { + if (r->rt_dst != dst) { + rp = &r->rt_next; + continue; + } + *rp = r->rt_next; + if (rt_loopback == r) + rt_loopback = NULL; + kfree_s(r, sizeof(struct rtable)); + } + /* add the new route */ + rp = &rt_base; + while ((r = *rp) != NULL) { + if ((r->rt_mask & mask) != mask) + break; + rp = &r->rt_next; + } + rt->rt_next = r; + *rp = rt; + if (rt->rt_dev->flags & IFF_LOOPBACK) + rt_loopback = rt; + restore_flags(cpuflags); + return; +} + +static inline int bad_mask(unsigned long mask, unsigned long addr) +{ + if (addr & (mask = ~mask)) + return 1; + mask = ntohl(mask); + if (mask & (mask+1)) + return 1; + return 0; +} + +static int rt_new(struct rtentry *r) +{ + struct device *dev; + unsigned long flags, daddr, mask, gw; + + if (r->rt_dst.sa_family != AF_INET) + return -EAFNOSUPPORT; + + flags = r->rt_flags; + daddr = ((struct sockaddr_in *) &r->rt_dst)->sin_addr.s_addr; + mask = r->rt_genmask; + gw = ((struct sockaddr_in *) &r->rt_gateway)->sin_addr.s_addr; + dev = (struct device *) r->rt_dev; + + if (flags & RTF_GATEWAY) { + if (r->rt_gateway.sa_family != AF_INET) + return -EAFNOSUPPORT; + if (!dev) + dev = get_gw_dev(gw); + } else if (!dev) + dev = dev_check(daddr); + + if (dev == NULL) + return -ENETUNREACH; + + if (bad_mask(mask, daddr)) + mask = 0; + + rt_add(flags, daddr, mask, gw, dev); + return 0; +} + + +static int rt_kill(struct rtentry *r) +{ + struct sockaddr_in *trg; + + trg = (struct sockaddr_in *) &r->rt_dst; + rt_del(trg->sin_addr.s_addr); + return 0; +} + + +/* Called from the PROCfs module. */ +int +rt_get_info(char *buffer) +{ + struct rtable *r; + char *pos; + + pos = buffer; + + pos += sprintf(pos, + "Iface\tDestination\tGateway \tFlags\tRefCnt\tUse\tMetric\tMask\n"); + + /* This isn't quite right -- r->rt_dst is a struct! */ + for (r = rt_base; r != NULL; r = r->rt_next) { + pos += sprintf(pos, "%s\t%08lX\t%08lX\t%02X\t%d\t%lu\t%d\t%08lX\n", + r->rt_dev->name, r->rt_dst, r->rt_gateway, + r->rt_flags, r->rt_refcnt, r->rt_use, r->rt_metric, + r->rt_mask); + } + return(pos - buffer); +} + +/* + * This is hackish, but results in better code. Use "-S" to see why. + */ +#define early_out ({ goto no_route; 1; }) + +struct rtable * rt_route(unsigned long daddr, struct options *opt) +{ + struct rtable *rt; + + for (rt = rt_base; rt != NULL || early_out ; rt = rt->rt_next) { + if (!((rt->rt_dst ^ daddr) & rt->rt_mask)) + break; + /* broadcast addresses can be special cases.. */ + if ((rt->rt_dev->flags & IFF_BROADCAST) && + rt->rt_dev->pa_brdaddr == daddr) + break; + } + if (daddr == rt->rt_dev->pa_addr) { + if ((rt = rt_loopback) == NULL) + goto no_route; + } + rt->rt_use++; + return rt; +no_route: + return NULL; +} + + +int rt_ioctl(unsigned int cmd, void *arg) +{ + struct device *dev; + struct rtentry rt; + char *devname; + int ret; + int err; + + switch(cmd) { + case DDIOCSDBG: + ret = dbg_ioctl(arg, DBG_RT); + break; + case SIOCADDRT: + case SIOCDELRT: + if (!suser()) + return -EPERM; + err=verify_area(VERIFY_READ, arg, sizeof(struct rtentry)); + if (err) + return err; + memcpy_fromfs(&rt, arg, sizeof(struct rtentry)); + if ((devname = (char *) rt.rt_dev) != NULL) { + err = getname(devname, &devname); + if (err) + return err; + dev = dev_get(devname); + putname(devname); + if (!dev) + return -EINVAL; + rt.rt_dev = dev; + } + ret = (cmd == SIOCDELRT) ? rt_kill(&rt) : rt_new(&rt); + break; + default: + ret = -EINVAL; + } + + return ret; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.h new file mode 100644 index 000000000..1972e89ab --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/route.h @@ -0,0 +1,47 @@ +/* + * 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 IP router. + * + * Version: @(#)route.h 1.0.4 05/27/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _ROUTE_H +#define _ROUTE_H + + +#include + + +/* This is an entry in the IP routing table. */ +struct rtable { + struct rtable *rt_next; + unsigned long rt_dst; + unsigned long rt_mask; + unsigned long rt_gateway; + unsigned char rt_flags; + unsigned char rt_metric; + short rt_refcnt; + unsigned long rt_use; + unsigned short rt_mss, rt_mtu; + struct device *rt_dev; +}; + + +extern void rt_flush(struct device *dev); +extern void rt_add(short flags, unsigned long addr, unsigned long mask, + unsigned long gw, struct device *dev); +extern struct rtable *rt_route(unsigned long daddr, struct options *opt); +extern int rt_get_info(char * buffer); +extern int rt_ioctl(unsigned int cmd, void *arg); + +#endif /* _ROUTE_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.c new file mode 100644 index 000000000..7886e5c55 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.c @@ -0,0 +1,489 @@ +/* + * 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 + * + * Fixes: + * Alan Cox : Tracks memory and number of buffers for kernel memory report + * and memory leak hunting. + * Alan Cox : More generic kfree handler + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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=%d, 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=%d, 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=%d, 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 *newsk) +{ + unsigned long flags; + + IS_SKB(newsk); + if(newsk->list) + printk("Suspicious queue head: sk_buff on list!\n"); + save_flags(flags); + cli(); + newsk->list=list; + + newsk->next=*list; + + if(*list) + newsk->prev=(*list)->prev; + else + newsk->prev=newsk; + newsk->prev->next=newsk; + newsk->next->prev=newsk; + IS_SKB(newsk->prev); + IS_SKB(newsk->next); + *list=newsk; + 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 *newsk) +{ + unsigned long flags; + + if(newsk->list) + printk("Suspicious queue tail: sk_buff on list!\n"); + + IS_SKB(newsk); + save_flags(flags); + cli(); + + newsk->list=list; + if(*list) + { + (*list)->prev->next=newsk; + newsk->prev=(*list)->prev; + newsk->next=*list; + (*list)->prev=newsk; + } + else + { + newsk->next=newsk; + newsk->prev=newsk; + *list=newsk; + } + IS_SKB(newsk->prev); + IS_SKB(newsk->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 *newsk) +{ + unsigned long flags; + + IS_SKB(old); + IS_SKB(newsk); + + if(!old->list) + printk("insert before unlisted item!\n"); + if(newsk->list) + printk("inserted item is already on a list.\n"); + + save_flags(flags); + cli(); + newsk->list=old->list; + newsk->next=old; + newsk->prev=old->prev; + newsk->next->prev=newsk; + newsk->prev->next=newsk; + + restore_flags(flags); +} + +/* + * Place a packet after a given packet in a list. + */ + +void skb_append(struct sk_buff *old, struct sk_buff *newsk) +{ + unsigned long flags; + + IS_SKB(old); + IS_SKB(newsk); + + if(!old->list) + printk("append before unlisted item!\n"); + if(newsk->list) + printk("append item is already on a list.\n"); + + save_flags(flags); + cli(); + newsk->list=old->list; + newsk->prev=old; + newsk->next=old->next; + newsk->next->prev=newsk; + newsk->prev->next=newsk; + + 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,*newsk; + 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); + + newsk=alloc_skb(len,GFP_KERNEL); /* May sleep */ + + if(newsk==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(flags); + newsk->sk=NULL; + newsk->free=1; + newsk->mem_addr=newsk; + newsk->mem_len=len; + kfree_skb(newsk, FREE_WRITE); + continue; + } + + IS_SKB(orig); + IS_SKB(newsk); + memcpy(newsk,orig,len); + newsk->list=NULL; + newsk->magic=0; + newsk->next=NULL; + newsk->prev=NULL; + newsk->mem_addr=newsk; + newsk->h.raw+=((char *)newsk-(char *)orig); + newsk->link3=NULL; + newsk->sk=NULL; + newsk->free=1; + } + while(0); + + restore_flags(flags); + return(newsk); +} + +/* + * 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->lock) + { + skb->free=1; /* Free when unlocked */ + return; + } + + 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(skb->sk->prot!=NULL) + { + 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 + { + /* Non INET - default wmalloc/rmalloc handler */ + if (rw) + skb->sk->rmem_alloc-=skb->mem_len; + else + skb->sk->wmem_alloc-=skb->mem_len; + if(!skb->sk->dead) + wake_up_interruptible(skb->sk->sleep); + kfree_skbmem(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->lock= 0; + skb->truesize=size; + skb->mem_len=size; + skb->mem_addr=skb; + skb->fraglist=NULL; + net_memory+=size; + net_skbcount++; + skb->magic_debug_cookie=SK_GOOD_SKB; + skb->users=0; + 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; + } +} + +/* + * Skbuff device locking + */ + +void skb_kept_by_device(struct sk_buff *skb) +{ + skb->lock++; +} + +void skb_device_release(struct sk_buff *skb, int mode) +{ + unsigned long flags; + + save_flags(flags); + cli(); + if (!--skb->lock) { + if (skb->free==1) + kfree_skb(skb,mode); + } + restore_flags(flags); +} + +int skb_device_locked(struct sk_buff *skb) +{ + if(skb->lock) + return 1; + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.h new file mode 100644 index 000000000..e976385de --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/skbuff.h @@ -0,0 +1,112 @@ +/* + * 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 'struct sk_buff' memory handlers. + * + * Version: @(#)skbuff.h 1.0.4 05/20/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Corey Minyard + * + * Fixes: + * Alan Cox : Volatiles (this makes me unhappy - we want proper asm linked list stuff) + * Alan Cox : Declaration for new primitives + * Alan Cox : Fraglist support (idea by Donald Becker) + * Alan Cox : 'users' counter. Combines with datagram changes to avoid skb_peek_copy + * being used. + * + * 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. + */ +#ifndef _SKBUFF_H +#define _SKBUFF_H +#include + +#ifdef CONFIG_IPX +#include "ipx.h" +#endif + +#define HAVE_ALLOC_SKB /* For the drivers to know */ + + +#define FREE_READ 1 +#define FREE_WRITE 0 + + +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; + void *mem_addr; + union { + struct tcphdr *th; + struct ethhdr *eth; + struct iphdr *iph; + struct udphdr *uh; + struct arphdr *arp; + unsigned char *raw; + unsigned long seq; +#ifdef CONFIG_IPX + ipx_packet *ipx; +#endif + } h; + struct iphdr *ip_hdr; /* For IPPROTO_RAW */ + unsigned long mem_len; + unsigned long len; + unsigned long fraglen; + struct sk_buff *fraglist; /* Fragment list */ + unsigned long truesize; + unsigned long saddr; + unsigned long daddr; + int magic; + volatile char acked, + used, + free, + arp, + urg_used; + unsigned char tries,lock; /* Lock is now unused */ + unsigned short users; /* User count - see datagram.c (and soon seqpacket.c/stream.c) */ + unsigned long padding[0]; + unsigned char data[0]; +}; + +#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 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 *newsk); +extern void skb_append(struct sk_buff *old,struct sk_buff *newsk); +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_kept_by_device(struct sk_buff *skb); +extern void skb_device_release(struct sk_buff *skb, int mode); +extern int skb_device_locked(struct sk_buff *skb); +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); +extern void skb_copy_datagram(struct sk_buff *from, int offset, char *to,int size); +extern void skb_free_datagram(struct sk_buff *skb); +#endif /* _SKBUFF_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.c new file mode 100644 index 000000000..3de12e38f --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.c @@ -0,0 +1,1886 @@ +/* + * 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. + * + * SOCK - AF_INET protocol family socket handler. + * + * Version: @(#)sock.c 1.0.17 06/02/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Florian La Roche, + * + * 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 + * Alan Cox : Fixed connect() taking signals I think. + * Alan Cox : SO_LINGER supported + * Alan Cox : Error reporting fixes + * Anonymous : inet_create tidied up (sk->reuse setting) + * Alan Cox : inet sockets don't set sk->type! + * Alan Cox : Split socket option code + * Alan Cox : Callbacks + * Alan Cox : Nagle flag for Charles & Johannes stuff + * + * 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 + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#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" +#include "raw.h" +#include "icmp.h" + + +int inet_debug = DBG_OFF; /* INET module debug flag */ + + +#define min(a,b) ((a)<(b)?(a):(b)) + +extern struct proto packet_prot; + + +void +print_sk(struct sock *sk) +{ + if (!sk) { + printk(" print_sk(NULL)\n"); + return; + } + printk(" wmem_alloc = %lu\n", sk->wmem_alloc); + printk(" rmem_alloc = %lu\n", sk->rmem_alloc); + printk(" send_head = %p\n", sk->send_head); + printk(" state = %d\n",sk->state); + printk(" wback = %p, rqueue = %p\n", sk->wback, sk->rqueue); + printk(" wfront = %p\n", sk->wfront); + printk(" daddr = %lX, saddr = %lX\n", sk->daddr,sk->saddr); + printk(" num = %d", sk->num); + printk(" next = %p\n", sk->next); + printk(" send_seq = %ld, acked_seq = %ld, copied_seq = %ld\n", + sk->send_seq, sk->acked_seq, sk->copied_seq); + printk(" rcv_ack_seq = %ld, window_seq = %ld, fin_seq = %ld\n", + sk->rcv_ack_seq, sk->window_seq, sk->fin_seq); + printk(" prot = %p\n", sk->prot); + printk(" pair = %p, back_log = %p\n", sk->pair,sk->back_log); + printk(" inuse = %d , blog = %d\n", sk->inuse, sk->blog); + printk(" dead = %d delay_acks=%d\n", sk->dead, sk->delay_acks); + printk(" retransmits = %ld, timeout = %d\n", sk->retransmits, sk->timeout); + printk(" cong_window = %d, packets_out = %d\n", sk->cong_window, + sk->packets_out); + printk(" urg = %d shutdown=%d\n", sk->urg, sk->shutdown); +} + + +void +print_skb(struct sk_buff *skb) +{ + if (!skb) { + printk(" print_skb(NULL)\n"); + return; + } + printk(" prev = %p, next = %p\n", skb->prev, skb->next); + printk(" sk = %p link3 = %p\n", skb->sk, skb->link3); + printk(" mem_addr = %p, mem_len = %lu\n", skb->mem_addr, skb->mem_len); + printk(" used = %d free = %d\n", skb->used,skb->free); +} + + + +static int +sk_inuse(struct proto *prot, int num) +{ + struct sock *sk; + + for(sk = prot->sock_array[num & (SOCK_ARRAY_SIZE -1 )]; + sk != NULL; + sk=sk->next) { + if (sk->num == num) return(1); + } + return(0); +} + + +unsigned short +get_new_socknum(struct proto *prot, unsigned short base) +{ + static int start=0; + + /* + * Used to cycle through the port numbers so the + * chances of a confused connection drop. + */ + int i, j; + int best = 0; + int size = 32767; /* a big num. */ + struct sock *sk; + + if (base == 0) base = PROT_SOCK+1+(start % 1024); + if (base <= PROT_SOCK) { + base += PROT_SOCK+(start % 1024); + } + + /* Now look through the entire array and try to find an empty ptr. */ + for(i=0; i < SOCK_ARRAY_SIZE; i++) { + j = 0; + sk = prot->sock_array[(i+base+1) &(SOCK_ARRAY_SIZE -1)]; + while(sk != NULL) { + sk = sk->next; + j++; + } + if (j == 0) { + start =(i+1+start )%1024; + DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n", + i + base + 1, start)); + return(i+base+1); + } + if (j < size) { + best = i; + size = j; + } + } + + /* Now make sure the one we want is not in use. */ + while(sk_inuse(prot, base +best+1)) { + best += SOCK_ARRAY_SIZE; + } + DPRINTF((DBG_INET, "get_new_socknum returning %d, start = %d\n", + best + base + 1, start)); + return(best+base+1); +} + + +void +put_sock(unsigned short num, struct sock *sk) +{ + struct sock *sk1; + struct sock *sk2; + int mask; + + DPRINTF((DBG_INET, "put_sock(num = %d, sk = %X\n", num, sk)); + sk->num = num; + sk->next = NULL; + num = num &(SOCK_ARRAY_SIZE -1); + + /* We can't have an interupt re-enter here. */ + cli(); + if (sk->prot->sock_array[num] == NULL) { + sk->prot->sock_array[num] = sk; + sti(); + return; + } + sti(); + for(mask = 0xff000000; mask != 0xffffffff; mask = (mask >> 8) | mask) { + if ((mask & sk->saddr) && + (mask & sk->saddr) != (mask & 0xffffffff)) { + mask = mask << 8; + break; + } + } + DPRINTF((DBG_INET, "mask = %X\n", mask)); + + cli(); + sk1 = sk->prot->sock_array[num]; + for(sk2 = sk1; sk2 != NULL; sk2=sk2->next) { + if (!(sk2->saddr & mask)) { + if (sk2 == sk1) { + sk->next = sk->prot->sock_array[num]; + sk->prot->sock_array[num] = sk; + sti(); + return; + } + sk->next = sk2; + sk1->next= sk; + sti(); + return; + } + sk1 = sk2; + } + + /* Goes at the end. */ + sk->next = NULL; + sk1->next = sk; + sti(); +} + + +static void +remove_sock(struct sock *sk1) +{ + struct sock *sk2; + + DPRINTF((DBG_INET, "remove_sock(sk1=%X)\n", sk1)); + if (!sk1) { + printk("sock.c: remove_sock: sk1 == NULL\n"); + return; + } + + if (!sk1->prot) { + printk("sock.c: remove_sock: sk1->prot == NULL\n"); + return; + } + + /* We can't have this changing out from under us. */ + cli(); + sk2 = sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)]; + if (sk2 == sk1) { + sk1->prot->sock_array[sk1->num &(SOCK_ARRAY_SIZE -1)] = sk1->next; + sti(); + return; + } + + while(sk2 && sk2->next != sk1) { + sk2 = sk2->next; + } + + if (sk2) { + sk2->next = sk1->next; + sti(); + return; + } + sti(); + + if (sk1->num != 0) DPRINTF((DBG_INET, "remove_sock: sock not found.\n")); +} + + +void +destroy_sock(struct sock *sk) +{ + struct sk_buff *skb; + + DPRINTF((DBG_INET, "destroying socket %X\n", sk)); + sk->inuse = 1; /* just to be safe. */ + + /* Incase it's sleeping somewhere. */ + if (!sk->dead) + sk->write_space(sk); + + remove_sock(sk); + + /* Now we can no longer get new packets. */ + delete_timer(sk); + + + while ((skb = tcp_dequeue_partial(sk)) != NULL) + { + IS_SKB(skb); + kfree_skb(skb, FREE_WRITE); + } + + /* Cleanup up the write buffer. */ + 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", + skb->magic); + break; + } + IS_SKB(skb); + kfree_skb(skb, FREE_WRITE); + skb = skb2; + } + + 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) + { + IS_SKB(skb); + skb->sk->dead = 1; + skb->sk->prot->close(skb->sk, 0); + } + IS_SKB(skb); + kfree_skb(skb, FREE_READ); + } + } + 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) + { + IS_SKB(skb); + skb_unlink(skb); + } + skb->dev = NULL; + sti(); + skb2 = (struct sk_buff *)skb->link3; + kfree_skb(skb, FREE_WRITE); + skb = skb2; + } + 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; + } + + /* + * 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")); +} + + +static int +inet_fcntl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + switch(cmd) { + case F_SETOWN: + /* + * This is a little restrictive, but it's the only + * way to make sure that you can't send a sigurg to + * another process. + */ + if (!suser() && current->pgrp != -arg && + current->pid != arg) return(-EPERM); + sk->proc = arg; + return(0); + case F_GETOWN: + return(sk->proc); + default: + return(-EINVAL); + } +} + +/* + * Set socket options on an inet socket. + */ + +static int inet_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + struct sock *sk = (struct sock *) sock->data; + if (level == SOL_SOCKET) + return sock_setsockopt(sk,level,optname,optval,optlen); + if (sk->prot->setsockopt==NULL) + return(-EOPNOTSUPP); + else + return sk->prot->setsockopt(sk,level,optname,optval,optlen); +} + + + + +static int inet_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + struct sock *sk = sock->data; + if (level == SOL_SOCKET) + return sock_getsockopt(sk,level,optname,optval,optlen); + if(sk->prot->getsockopt==NULL) + return(-EOPNOTSUPP); + else + return sk->prot->getsockopt(sk,level,optname,optval,optlen); +} + +/* + * This is meant for all protocols to use and covers goings on + * at the socket level. Everything here is generic. + */ + +int sock_setsockopt(struct sock *sk, int level, int optname, + char *optval, int optlen) +{ + int val; + int err; + struct linger ling; + + if (optval == NULL) + return(-EINVAL); + + 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: + 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_LINGER: + err=verify_area(VERIFY_READ,optval,sizeof(ling)); + if(err) + return err; + memcpy_fromfs(&ling,optval,sizeof(ling)); + if(ling.l_onoff==0) + sk->linger=0; + else + { + sk->lingertime=ling.l_linger; + sk->linger=1; + } + return 0; + case SO_RCVBUF: + if(val>32767) + val=32767; + if(val<256) + val=256; + sk->rcvbuf=val; + return(0); + + case SO_REUSEADDR: + if (val) + sk->reuse = 1; + else + sk->reuse = 0; + return(0); + + case SO_KEEPALIVE: + if (val) + sk->keepopen = 1; + else + sk->keepopen = 0; + return(0); + + case SO_OOBINLINE: + if (val) + sk->urginline = 1; + else + sk->urginline = 0; + return(0); + + case SO_NO_CHECK: + if (val) + sk->no_check = 1; + else + sk->no_check = 0; + return(0); + + case SO_PRIORITY: + if (val >= 0 && val < DEV_NUMBUFFS) + { + sk->priority = val; + } + else + { + return(-EINVAL); + } + return(0); + + default: + return(-ENOPROTOOPT); + } +} + + +int sock_getsockopt(struct sock *sk, int level, int optname, + char *optval, int *optlen) +{ + int val; + int err; + struct linger ling; + + switch(optname) + { + case SO_DEBUG: + val = sk->debug; + break; + + case SO_DONTROUTE: /* One last option to implement */ + val = 0; + break; + + case SO_BROADCAST: + val= sk->broadcast; + break; + + case SO_LINGER: + err=verify_area(VERIFY_WRITE,optval,sizeof(ling)); + if(err) + return err; + err=verify_area(VERIFY_WRITE,optlen,sizeof(int)); + if(err) + return err; + put_fs_long(sizeof(ling),(unsigned long *)optlen); + ling.l_onoff=sk->linger; + ling.l_linger=sk->lingertime; + memcpy_tofs(optval,&ling,sizeof(ling)); + return 0; + + case SO_SNDBUF: + val=sk->sndbuf; + break; + + case SO_RCVBUF: + val =sk->rcvbuf; + break; + + case SO_REUSEADDR: + val = sk->reuse; + break; + + case SO_KEEPALIVE: + val = sk->keepopen; + break; + + case SO_TYPE: + if (sk->prot == &tcp_prot) + val = SOCK_STREAM; + else + val = SOCK_DGRAM; + break; + + case SO_ERROR: + val = sk->err; + sk->err = 0; + break; + + case SO_OOBINLINE: + val = sk->urginline; + break; + + case SO_NO_CHECK: + val = sk->no_check; + break; + + case SO_PRIORITY: + val = sk->priority; + break; + + default: + return(-ENOPROTOOPT); + } + err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); + if(err) + return err; + put_fs_long(sizeof(int),(unsigned long *) optlen); + + err=verify_area(VERIFY_WRITE, optval, sizeof(int)); + if(err) + return err; + put_fs_long(val,(unsigned long *)optval); + + return(0); +} + + + + +static int +inet_listen(struct socket *sock, int backlog) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + /* We might as well re use these. */ + sk->max_ack_backlog = backlog; + if (sk->state != TCP_LISTEN) { + sk->ack_backlog = 0; + sk->state = TCP_LISTEN; + } + return(0); +} + +/* + * Default callbacks for user INET sockets. These just wake up + * the user owning the socket. + */ + +static void def_callback1(struct sock *sk) +{ + if(!sk->dead) + wake_up_interruptible(sk->sleep); +} + +static void def_callback2(struct sock *sk,int len) +{ + if(!sk->dead) + wake_up_interruptible(sk->sleep); +} + + +static int +inet_create(struct socket *sock, int protocol) +{ + struct sock *sk; + struct proto *prot; + int err; + + sk = (struct sock *) kmalloc(sizeof(*sk), GFP_KERNEL); + if (sk == NULL) + return(-ENOMEM); + sk->num = 0; + sk->reuse = 0; + switch(sock->type) { + case SOCK_STREAM: + case SOCK_SEQPACKET: + if (protocol && protocol != IPPROTO_TCP) { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + protocol = IPPROTO_TCP; + sk->no_check = TCP_NO_CHECK; + prot = &tcp_prot; + break; + + case SOCK_DGRAM: + if (protocol && protocol != IPPROTO_UDP) { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + protocol = IPPROTO_UDP; + sk->no_check = UDP_NO_CHECK; + prot=&udp_prot; + break; + + case SOCK_RAW: + if (!suser()) { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPERM); + } + if (!protocol) { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + prot = &raw_prot; + sk->reuse = 1; + sk->no_check = 0; /* + * Doesn't matter no checksum is + * preformed anyway. + */ + sk->num = protocol; + break; + + case SOCK_PACKET: + if (!suser()) { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPERM); + } + if (!protocol) { + kfree_s((void *)sk, sizeof(*sk)); + return(-EPROTONOSUPPORT); + } + prot = &packet_prot; + sk->reuse = 1; + sk->no_check = 0; /* Doesn't matter no checksum is + * preformed anyway. + */ + sk->num = protocol; + break; + + default: + kfree_s((void *)sk, sizeof(*sk)); + return(-ESOCKTNOSUPPORT); + } + sk->socket = sock; +#ifdef CONFIG_TCP_NAGLE_OFF + sk->nonagle = 1; +#else + sk->nonagle = 0; +#endif + sk->type = sock->type; + 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; + sk->acked_seq = 0; + sk->copied_seq = 0; + sk->fin_seq = 0; + sk->proc = 0; + sk->rtt = TCP_WRITE_TIME << 3; + sk->rto = TCP_WRITE_TIME; + sk->mdev = 0; + sk->backoff = 0; + sk->packets_out = 0; + sk->cong_window = 1; /* start with only sending one packet at a time. */ + sk->cong_count = 0; + sk->ssthresh = 0; + sk->max_window = 0; + sk->urginline = 0; + sk->intr = 0; + sk->linger = 0; + sk->destroy = 0; + + sk->priority = 1; + sk->shutdown = 0; + sk->urg = 0; + sk->keepopen = 0; + sk->zapped = 0; + sk->done = 0; + sk->ack_backlog = 0; + sk->window = 0; + sk->bytes_rcv = 0; + sk->state = TCP_CLOSE; + sk->dead = 0; + sk->ack_timed = 0; + sk->partial = NULL; + sk->user_mss = 0; + sk->debug = 0; + + /* this is how many unacked bytes we will accept for this socket. */ + sk->max_unacked = 2048; /* needs to be at most 2 full packets. */ + + /* how many packets we should send before forcing an ack. + if this is set to zero it is the same as sk->delay_acks = 0 */ + sk->max_ack_backlog = 0; + sk->inuse = 0; + sk->delay_acks = 0; + sk->wback = NULL; + sk->wfront = NULL; + sk->rqueue = NULL; + sk->mtu = 576; + sk->prot = prot; + sk->sleep = sock->wait; + sk->daddr = 0; + sk->saddr = my_addr(); + sk->err = 0; + sk->next = NULL; + sk->pair = NULL; + 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; + sk->blog = 0; + sock->data =(void *) sk; + sk->dummy_th.doff = sizeof(sk->dummy_th)/4; + sk->dummy_th.res1=0; + sk->dummy_th.res2=0; + sk->dummy_th.urg_ptr = 0; + sk->dummy_th.fin = 0; + sk->dummy_th.syn = 0; + sk->dummy_th.rst = 0; + sk->dummy_th.psh = 0; + sk->dummy_th.ack = 0; + sk->dummy_th.urg = 0; + sk->dummy_th.dest = 0; + + sk->ip_tos=0; + sk->ip_ttl=64; + + sk->state_change = def_callback1; + sk->data_ready = def_callback2; + sk->write_space = def_callback1; + sk->error_report = def_callback1; + + if (sk->num) { + /* + * It assumes that any protocol which allows + * the user to assign a number at socket + * creation time automatically + * shares. + */ + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + if (sk->prot->init) { + err = sk->prot->init(sk); + if (err != 0) { + destroy_sock(sk); + return(err); + } + } + return(0); +} + + +static int +inet_dup(struct socket *newsock, struct socket *oldsock) +{ + return(inet_create(newsock, + ((struct sock *)(oldsock->data))->protocol)); +} + + +/* The peer socket should always be NULL. */ +static int +inet_release(struct socket *sock, struct socket *peer) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) return(0); + + DPRINTF((DBG_INET, "inet_release(sock = %X, peer = %X)\n", sock, peer)); + sk->state_change(sk); + + /* Start closing the connection. This may take a while. */ + /* + * If linger is set, we don't return until the close + * is complete. Other wise we return immediately. The + * actually closing is done the same either way. + */ + if (sk->linger == 0) { + sk->prot->close(sk,0); + sk->dead = 1; + } else { + DPRINTF((DBG_INET, "sk->linger set.\n")); + sk->prot->close(sk, 0); + cli(); + if (sk->lingertime) + current->timeout = jiffies + HZ*sk->lingertime; + while(sk->state != TCP_CLOSE && current->timeout>0) { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + current->timeout=0; + return(-ERESTARTSYS); + } + } + current->timeout=0; + sti(); + sk->dead = 1; + } + sk->inuse = 1; + + /* This will destroy it. */ + release_sock(sk); + sock->data = NULL; + DPRINTF((DBG_INET, "inet_release returning\n")); + return(0); +} + + +/* this needs to be changed to dissallow + the rebinding of sockets. What error + should it return? */ + +static int +inet_bind(struct socket *sock, struct sockaddr *uaddr, + int addr_len) +{ + struct sockaddr_in addr; + struct sock *sk, *sk2; + unsigned short snum; + int err; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + /* check this error. */ + if (sk->state != TCP_CLOSE) return(-EIO); + if (sk->num != 0) return(-EINVAL); + + err=verify_area(VERIFY_READ, uaddr, addr_len); + if(err) + return err; + memcpy_fromfs(&addr, uaddr, min(sizeof(addr), addr_len)); + + snum = ntohs(addr.sin_port); + DPRINTF((DBG_INET, "bind sk =%X to port = %d\n", sk, snum)); + sk = (struct sock *) sock->data; + + /* + * We can't just leave the socket bound wherever it is, it might + * be bound to a privileged port. However, since there seems to + * be a bug here, we will leave it if the port is not privileged. + */ + if (snum == 0) { + snum = get_new_socknum(sk->prot, 0); + } + 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; + + DPRINTF((DBG_INET, "sock_array[%d] = %X:\n", snum &(SOCK_ARRAY_SIZE -1), + sk->prot->sock_array[snum &(SOCK_ARRAY_SIZE -1)])); + + /* Make sure we are allowed to bind here. */ + cli(); +outside_loop: + for(sk2 = sk->prot->sock_array[snum & (SOCK_ARRAY_SIZE -1)]; + sk2 != NULL; sk2 = sk2->next) { +#if 1 /* should be below! */ + if (sk2->num != snum) continue; +/* if (sk2->saddr != sk->saddr) continue; */ +#endif + if (sk2->dead) { + destroy_sock(sk2); + goto outside_loop; + } + if (!sk->reuse) { + sti(); + return(-EADDRINUSE); + } + if (sk2->num != snum) continue; /* more than one */ + if (sk2->saddr != sk->saddr) continue; /* socket per slot ! -FB */ + if (!sk2->reuse) { + sti(); + return(-EADDRINUSE); + } + } + sti(); + + remove_sock(sk); + put_sock(snum, sk); + sk->dummy_th.source = ntohs(sk->num); + sk->daddr = 0; + sk->dummy_th.dest = 0; + return(0); +} + + +static int +inet_connect(struct socket *sock, struct sockaddr * uaddr, + int addr_len, int flags) +{ + struct sock *sk; + int err; + + sock->conn = NULL; + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) + { + sock->state = SS_CONNECTED; + /* Connection completing after a connect/EINPROGRESS/select/connect */ + return 0; /* Rock and roll */ + } + + if (sock->state == SS_CONNECTING && sk->protocol == IPPROTO_TCP && + (flags & O_NONBLOCK)) + 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); + put_sock(sk->num, sk); + sk->dummy_th.source = htons(sk->num); + } + + if (sk->prot->connect == NULL) + return(-EOPNOTSUPP); + + err = sk->prot->connect(sk, (struct sockaddr_in *)uaddr, addr_len); + if (err < 0) return(err); + + sock->state = SS_CONNECTING; + } + + 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) + { + 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) + { + sti(); + sock->state = SS_UNCONNECTED; + err = -sk->err; + sk->err=0; + return err; /* set by tcp_err() */ + } + } + sti(); + sock->state = SS_CONNECTED; + + if (sk->state != TCP_ESTABLISHED && sk->err) { + sock->state = SS_UNCONNECTED; + err=sk->err; + sk->err=0; + return(-err); + } + return(0); +} + + +static int +inet_socketpair(struct socket *sock1, struct socket *sock2) +{ + return(-EOPNOTSUPP); +} + + +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) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + /* + * We've been passed an extra socket. + * We need to free it up because the tcp module creates + * it's own when it accepts one. + */ + if (newsock->data) kfree_s(newsock->data, sizeof(struct sock)); + newsock->data = NULL; + + if (sk1->prot->accept == NULL) return(-EOPNOTSUPP); + + /* Restore the state if we have been interrupted, and then returned. */ + if (sk1->pair != NULL ) { + sk2 = sk1->pair; + sk1->pair = NULL; + } else { + sk2 = sk1->prot->accept(sk1,flags); + if (sk2 == NULL) { + if (sk1->err <= 0) + printk("Warning sock.c:sk1->err <= 0. Returning non-error.\n"); + err=sk1->err; + sk1->err=0; + return(-err); + } + } + newsock->data = (void *)sk2; + sk2->sleep = newsock->wait; + newsock->conn = NULL; + if (flags & O_NONBLOCK) return(0); + + cli(); /* avoid the race. */ + while(sk2->state == TCP_SYN_RECV) { + interruptible_sleep_on(sk2->sleep); + if (current->signal & ~current->blocked) { + sti(); + sk1->pair = sk2; + sk2->sleep = NULL; + newsock->data = NULL; + return(-ERESTARTSYS); + } + } + sti(); + + if (sk2->state != TCP_ESTABLISHED && sk2->err > 0) { + + err = -sk2->err; + sk2->err=0; + destroy_sock(sk2); + newsock->data = NULL; + return(err); + } + newsock->state = SS_CONNECTED; + return(0); +} + + +static int +inet_getname(struct socket *sock, struct sockaddr *uaddr, + int *uaddr_len, int peer) +{ + struct sockaddr_in sin; + struct sock *sk; + int 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); + + sin.sin_family = AF_INET; + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + if (peer) { + if (!tcp_connected(sk->state)) return(-ENOTCONN); + sin.sin_port = sk->dummy_th.dest; + sin.sin_addr.s_addr = sk->daddr; + } else { + sin.sin_port = sk->dummy_th.source; + if (sk->saddr == 0) sin.sin_addr.s_addr = my_addr(); + else sin.sin_addr.s_addr = sk->saddr; + } + len = sizeof(sin); +/* verify_area(VERIFY_WRITE, uaddr, len); NOW DONE ABOVE */ + memcpy_tofs(uaddr, &sin, sizeof(sin)); +/* verify_area(VERIFY_WRITE, uaddr_len, sizeof(len)); NOW DONE ABOVE */ + put_fs_long(len, uaddr_len); + return(0); +} + + +static int +inet_read(struct socket *sock, char *ubuf, int size, int noblock) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock,0)); +} + + +static int +inet_recv(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + return(sk->prot->read(sk, (unsigned char *) ubuf, size, noblock, flags)); +} + + +static int +inet_write(struct socket *sock, char *ubuf, int size, int noblock) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + if (sk->shutdown & SEND_SHUTDOWN) { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, 0)); +} + + +static int +inet_send(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + if (sk->shutdown & SEND_SHUTDOWN) { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + return(sk->prot->write(sk, (unsigned char *) ubuf, size, noblock, flags)); +} + + +static int +inet_sendto(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags, struct sockaddr *sin, int addr_len) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + if (sk->shutdown & SEND_SHUTDOWN) { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + + if (sk->prot->sendto == NULL) return(-EOPNOTSUPP); + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + return(sk->prot->sendto(sk, (unsigned char *) ubuf, size, noblock, flags, + (struct sockaddr_in *)sin, addr_len)); +} + + +static int +inet_recvfrom(struct socket *sock, void *ubuf, int size, int noblock, + unsigned flags, struct sockaddr *sin, int *addr_len ) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + if (sk->prot->recvfrom == NULL) return(-EOPNOTSUPP); + + /* 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); + put_sock(sk->num, sk); + sk->dummy_th.source = ntohs(sk->num); + } + + return(sk->prot->recvfrom(sk, (unsigned char *) ubuf, size, noblock, flags, + (struct sockaddr_in*)sin, addr_len)); +} + + +static int +inet_shutdown(struct socket *sock, int how) +{ + struct sock *sk; + + /* + * This should really check to make sure + * the socket is a TCP socket. + */ + how++; /* maps 0->1 has the advantage of making bit 1 rcvs and + 1->2 bit 2 snds. + 2->3 */ + if (how & ~SHUTDOWN_MASK) return(-EINVAL); + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + if (sock->state == SS_CONNECTING && sk->state == TCP_ESTABLISHED) + sock->state = SS_CONNECTED; + + if (!tcp_connected(sk->state)) return(-ENOTCONN); + sk->shutdown |= how; + if (sk->prot->shutdown) sk->prot->shutdown(sk, how); + return(0); +} + + +static int +inet_select(struct socket *sock, int sel_type, select_table *wait ) +{ + struct sock *sk; + + sk = (struct sock *) sock->data; + if (sk == NULL) { + printk("Warning: sock->data = NULL: %d\n" ,__LINE__); + return(0); + } + + if (sk->prot->select == NULL) { + DPRINTF((DBG_INET, "select on non-selectable socket.\n")); + return(0); + } + return(sk->prot->select(sk, sel_type, wait)); +} + + +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; + if (sock && (sk = (struct sock *) sock->data) == NULL) { + printk("AF_INET: Warning: sock->data = NULL: %d\n" , __LINE__); + return(0); + } + + 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) { + err=verify_area(VERIFY_WRITE,(void *) arg, sizeof(long)); + if(err) + return err; + put_fs_long(sk->proc,(int *)arg); + } + return(0); +#if 0 /* FIXME: */ + case SIOCATMARK: + printk("AF_INET: ioctl(SIOCATMARK, 0x%08X)\n",(void *) arg); + return(-EINVAL); +#endif + + case DDIOCSDBG: + return(dbg_ioctl((void *) arg, DBG_INET)); + + case SIOCADDRT: + case SIOCDELRT: + return(rt_ioctl(cmd,(void *) arg)); + + case SIOCDARP: + case SIOCGARP: + case SIOCSARP: + return(arp_ioctl(cmd,(void *) arg)); + + case IP_SET_DEV: + case SIOCGIFCONF: + case SIOCGIFFLAGS: + case SIOCSIFFLAGS: + case SIOCGIFADDR: + case SIOCSIFADDR: + case SIOCGIFDSTADDR: + case SIOCSIFDSTADDR: + case SIOCGIFBRDADDR: + case SIOCSIFBRDADDR: + case SIOCGIFNETMASK: + case SIOCSIFNETMASK: + case SIOCGIFMETRIC: + case SIOCSIFMETRIC: + case SIOCGIFMEM: + case SIOCSIFMEM: + case SIOCGIFMTU: + case SIOCSIFMTU: + case SIOCSIFLINK: + case SIOCGIFHWADDR: + return(dev_ioctl(cmd,(void *) arg)); + + default: + if (!sk || !sk->prot->ioctl) return(-EINVAL); + return(sk->prot->ioctl(sk, cmd, arg)); + } + /*NOTREACHED*/ + return(0); +} + + +struct sk_buff * +sock_wmalloc(struct sock *sk, unsigned long size, int force, + int priority) +{ + if (sk) { + if (sk->wmem_alloc + size < sk->sndbuf || force) { + cli(); + sk->wmem_alloc+= size; + sti(); + return(alloc_skb(size, priority)); + } + DPRINTF((DBG_INET, "sock_wmalloc(%X,%d,%d,%d) returning NULL\n", + sk, size, force, priority)); + return(NULL); + } + return(alloc_skb(size, priority)); +} + + +struct sk_buff * +sock_rmalloc(struct sock *sk, unsigned long size, int force, int priority) +{ + if (sk) { + if (sk->rmem_alloc + size < sk->rcvbuf || force) { + void *c = alloc_skb(size, priority); + cli(); + if (c) sk->rmem_alloc += size; + sti(); + return(c); + } + DPRINTF((DBG_INET, "sock_rmalloc(%X,%d,%d,%d) returning NULL\n", + sk,size,force, priority)); + return(NULL); + } + return(alloc_skb(size, priority)); +} + + +unsigned long +sock_rspace(struct sock *sk) +{ + int amt; + + if (sk != NULL) { + 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); + } + return(0); +} + + +unsigned long +sock_wspace(struct sock *sk) +{ + if (sk != NULL) { + if (sk->shutdown & SEND_SHUTDOWN) return(0); + if (sk->wmem_alloc >= sk->sndbuf) return(0); + return(sk->sndbuf-sk->wmem_alloc ); + } + return(0); +} + + +void +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)); + + IS_SKB(mem); + kfree_skbmem(mem, size); + if (sk) { + sk->wmem_alloc -= size; + + /* In case it might be waiting for more memory. */ + if (!sk->dead) sk->write_space(sk); + if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) { + DPRINTF((DBG_INET, + "recovered lost memory, sock = %X\n", sk)); + } + return; + } +} + + +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)); + IS_SKB(mem); + kfree_skbmem(mem, size); + if (sk) { + sk->rmem_alloc -= size; + if (sk->destroy && sk->wmem_alloc == 0 && sk->rmem_alloc == 0) { + DPRINTF((DBG_INET, + "recovered lot memory, sock = %X\n", sk)); + } + } +} + + +/* + * This routine must find a socket given a TCP or UDP header. + * Everyhting is assumed to be in net order. + */ +struct sock *get_sock(struct proto *prot, unsigned short num, + unsigned long raddr, + unsigned short rnum, unsigned long laddr) +{ + struct sock *s; + unsigned short hnum; + + hnum = ntohs(num); + DPRINTF((DBG_INET, "get_sock(prot=%X, num=%d, raddr=%X, rnum=%d, laddr=%X)\n", + prot, num, raddr, rnum, laddr)); + + /* + * SOCK_ARRAY_SIZE must be a power of two. This will work better + * than a prime unless 3 or more sockets end up using the same + * array entry. This should not be a problem because most + * well known sockets don't overlap that much, and for + * the other ones, we can just be careful about picking our + * 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) + 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); +} + + +void release_sock(struct sock *sk) +{ + if (!sk) { + printk("sock.c: release_sock sk == NULL\n"); + return; + } + if (!sk->prot) { +/* printk("sock.c: release_sock sk->prot == NULL\n"); */ + return; + } + + if (sk->blog) return; + + /* See if we have any packets built up. */ + cli(); + sk->inuse = 1; + while(sk->back_log != NULL) { + struct sk_buff *skb; + + sk->blog = 1; + skb =(struct sk_buff *)sk->back_log; + DPRINTF((DBG_INET, "release_sock: skb = %X:\n", skb)); + if (skb->next != skb) { + sk->back_log = skb->next; + skb->prev->next = skb->next; + skb->next->prev = skb->prev; + } else { + sk->back_log = NULL; + } + sti(); + DPRINTF((DBG_INET, "sk->back_log = %X\n", sk->back_log)); + if (sk->prot->rcv) sk->prot->rcv(skb, skb->dev, sk->opt, + skb->saddr, skb->len, skb->daddr, 1, + + /* Only used for/by raw sockets. */ + (struct inet_protocol *)sk->pair); + cli(); + } + sk->blog = 0; + sk->inuse = 0; + sti(); + if (sk->dead && sk->state == TCP_CLOSE) { + /* Should be about 2 rtt's */ + reset_timer(sk, TIME_DONE, min(sk->rtt * 2, TCP_DONE_TIME)); + } +} + + +static int +inet_fioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int minor, ret; + + /* Extract the minor number on which we work. */ + minor = MINOR(inode->i_rdev); + if (minor != 0) return(-ENODEV); + + /* Now dispatch on the minor device. */ + switch(minor) { + case 0: /* INET */ + ret = inet_ioctl(NULL, cmd, arg); + break; + case 1: /* IP */ + ret = ip_ioctl(NULL, cmd, arg); + break; + case 2: /* ICMP */ + ret = icmp_ioctl(NULL, cmd, arg); + break; + case 3: /* TCP */ + ret = tcp_ioctl(NULL, cmd, arg); + break; + case 4: /* UDP */ + ret = udp_ioctl(NULL, cmd, arg); + break; + default: + ret = -ENODEV; + } + + return(ret); +} + + + + +static struct file_operations inet_fops = { + NULL, /* LSEEK */ + NULL, /* READ */ + NULL, /* WRITE */ + NULL, /* READDIR */ + NULL, /* SELECT */ + inet_fioctl, /* IOCTL */ + NULL, /* MMAP */ + NULL, /* OPEN */ + NULL /* CLOSE */ +}; + + +static struct proto_ops inet_proto_ops = { + AF_INET, + + inet_create, + inet_dup, + inet_release, + inet_bind, + inet_connect, + inet_socketpair, + inet_accept, + inet_getname, + inet_read, + inet_write, + inet_select, + inet_ioctl, + inet_listen, + inet_send, + inet_recv, + inet_sendto, + inet_recvfrom, + inet_shutdown, + inet_setsockopt, + inet_getsockopt, + inet_fcntl, +}; + +extern unsigned long seq_offset; + +/* Called by ddi.c on kernel startup. */ +void inet_proto_init(struct ddi_proto *pro) +{ + struct inet_protocol *p; + int i; + + printk("Swansea University Computer Society Net2Debugged [1.27]\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", + pro->name, AF_INET_MAJOR); + return; + } + + /* Tell SOCKET that we are alive... */ + (void) sock_register(inet_proto_ops.family, &inet_proto_ops); + + seq_offset = CURRENT_TIME*250; + + /* Add all the protocols. */ + for(i = 0; i < SOCK_ARRAY_SIZE; i++) { + tcp_prot.sock_array[i] = NULL; + 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; + } + + /* Initialize the DEV module. */ + dev_init(); + + /* Initialize the "Buffer Head" pointers. */ + bh_base[INET_BH].routine = inet_bh; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.h new file mode 100644 index 000000000..3fb08a9a0 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/sock.h @@ -0,0 +1,278 @@ +/* + * 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 AF_INET socket handler. + * + * Version: @(#)sock.h 1.0.4 05/13/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Corey Minyard + * Florian La Roche + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#ifndef _SOCK_H +#define _SOCK_H + +#include +#include /* struct options */ +#include /* struct tcphdr */ + +#include "skbuff.h" /* struct sk_buff */ +#include "protocol.h" /* struct inet_protocol */ +#ifdef CONFIG_AX25 +#include "ax25.h" +#endif +#ifdef CONFIG_IPX +#include "ipx.h" +#endif + +#define SOCK_ARRAY_SIZE 64 + + +/* + * This structure really needs to be cleaned up. + * Most of it is for TCP, and not used by any of + * the other protocols. + */ +struct sock { + struct options *opt; + volatile unsigned long wmem_alloc; + volatile unsigned long rmem_alloc; + unsigned long send_seq; + unsigned long acked_seq; + unsigned long copied_seq; + unsigned long rcv_ack_seq; + unsigned long window_seq; + unsigned long fin_seq; + + /* + * Not all are volatile, but some are, so we + * might as well say they all are. + */ + volatile char inuse, + dead, + urginline, + intr, + blog, + done, + reuse, + keepopen, + linger, + delay_acks, + destroy, + ack_timed, + no_check, + zapped, /* In ax25 & ipx means not linked */ + broadcast, + nonagle; + unsigned long lingertime; + int proc; + struct sock *next; + struct sock *pair; + struct sk_buff *volatile send_tail; + struct sk_buff *volatile send_head; + struct sk_buff *volatile back_log; + struct sk_buff *partial; + struct timer_list partial_timer; + long retransmits; + struct sk_buff *volatile wback, + *volatile wfront, + *volatile rqueue; + struct proto *prot; + struct wait_queue **sleep; + unsigned long daddr; + unsigned long saddr; + unsigned short max_unacked; + unsigned short window; + unsigned short bytes_rcv; +/* mss is min(mtu, max_window) */ + unsigned short mtu; /* mss negotiated in the syn's */ + volatile unsigned short mss; /* current eff. mss - can change */ + volatile unsigned short user_mss; /* mss requested by user in ioctl */ + volatile unsigned short max_window; + unsigned short num; + volatile unsigned short cong_window; + volatile unsigned short cong_count; + volatile unsigned short ssthresh; + volatile unsigned short packets_out; + volatile unsigned short urg; + volatile unsigned short shutdown; + volatile unsigned long rtt; + volatile unsigned long mdev; + volatile unsigned long rto; +/* currently backoff isn't used, but I'm maintaining it in case + * we want to go back to a backoff formula that needs it + */ + volatile unsigned short backoff; + volatile short err; + unsigned char protocol; + volatile unsigned char state; + 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; +#ifdef CONFIG_IPX + ipx_address ipx_source_addr,ipx_dest_addr; + unsigned short ipx_type; +#endif +#ifdef CONFIG_AX25 +/* Really we want to add a per protocol private area */ + ax25_address ax25_source_addr,ax25_dest_addr; + struct sk_buff *volatile ax25_retxq[8]; + char ax25_state,ax25_vs,ax25_vr,ax25_lastrxnr,ax25_lasttxnr; + char ax25_condition; + char ax25_retxcnt; + char ax25_xx; + char ax25_retxqi; + char ax25_rrtimer; + char ax25_timer; + ax25_digi *ax25_digipeat; +#endif +/* IP 'private area' or will be eventually */ + int ip_ttl; /* TTL setting */ + int ip_tos; /* TOS */ + 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; + + /* Callbacks */ + void (*state_change)(struct sock *sk); + void (*data_ready)(struct sock *sk,int bytes); + void (*write_space)(struct sock *sk); + void (*error_report)(struct sock *sk); + +}; + +struct proto { + struct sk_buff * (*wmalloc)(struct sock *sk, + unsigned long size, int force, + int priority); + struct sk_buff * (*rmalloc)(struct sock *sk, + unsigned long size, int force, + int priority); + void (*wfree)(struct sock *sk, void *mem, + unsigned long size); + void (*rfree)(struct sock *sk, void *mem, + unsigned long size); + unsigned long (*rspace)(struct sock *sk); + unsigned long (*wspace)(struct sock *sk); + void (*close)(struct sock *sk, int timeout); + int (*read)(struct sock *sk, unsigned char *to, + int len, int nonblock, unsigned flags); + int (*write)(struct sock *sk, unsigned char *to, + int len, int nonblock, unsigned flags); + int (*sendto)(struct sock *sk, + unsigned char *from, int len, int noblock, + unsigned flags, struct sockaddr_in *usin, + int addr_len); + int (*recvfrom)(struct sock *sk, + unsigned char *from, int len, int noblock, + unsigned flags, struct sockaddr_in *usin, + int *addr_len); + int (*build_header)(struct sk_buff *skb, + unsigned long saddr, + unsigned long daddr, + struct device **dev, int type, + struct options *opt, int len, int tos, int ttl); + int (*connect)(struct sock *sk, + struct sockaddr_in *usin, int addr_len); + struct sock * (*accept) (struct sock *sk, int flags); + void (*queue_xmit)(struct sock *sk, + struct device *dev, struct sk_buff *skb, + int free); + void (*retransmit)(struct sock *sk, int all); + void (*write_wakeup)(struct sock *sk); + void (*read_wakeup)(struct sock *sk); + int (*rcv)(struct sk_buff *buff, struct device *dev, + struct options *opt, unsigned long daddr, + unsigned short len, unsigned long saddr, + int redo, struct inet_protocol *protocol); + int (*select)(struct sock *sk, int which, + select_table *wait); + int (*ioctl)(struct sock *sk, int cmd, + unsigned long arg); + int (*init)(struct sock *sk); + void (*shutdown)(struct sock *sk, int how); + int (*setsockopt)(struct sock *sk, int level, int optname, + char *optval, int optlen); + int (*getsockopt)(struct sock *sk, int level, int optname, + char *optval, int *option); + unsigned short max_header; + unsigned long retransmits; + struct sock * sock_array[SOCK_ARRAY_SIZE]; + char name[80]; +}; + +#define TIME_WRITE 1 +#define TIME_CLOSE 2 +#define TIME_KEEPOPEN 3 +#define TIME_DESTROY 4 +#define TIME_DONE 5 /* used to absorb those last few packets */ +#define TIME_PROBE0 6 +#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 SHUTDOWN_MASK 3 +#define RCV_SHUTDOWN 1 +#define SEND_SHUTDOWN 2 + + +extern void destroy_sock(struct sock *sk); +extern unsigned short get_new_socknum(struct proto *, unsigned short); +extern void put_sock(unsigned short, struct sock *); +extern void release_sock(struct sock *sk); +extern struct sock *get_sock(struct proto *, unsigned short, + unsigned long, unsigned short, + unsigned long); +extern void print_sk(struct sock *); +extern struct sk_buff *sock_wmalloc(struct sock *sk, + unsigned long size, int force, + int priority); +extern struct sk_buff *sock_rmalloc(struct sock *sk, + unsigned long size, int force, + int priority); +extern void sock_wfree(struct sock *sk, void *mem, + unsigned long size); +extern void sock_rfree(struct sock *sk, void *mem, + unsigned long size); +extern unsigned long sock_rspace(struct sock *sk); +extern unsigned long sock_wspace(struct sock *sk); + +extern int sock_setsockopt(struct sock *sk,int level,int op,char *optval,int optlen); +extern int sock_getsockopt(struct sock *sk,int level,int op,char *optval,int *optlen); + +/* declarations from timer.c */ +extern struct sock *timer_base; + +void delete_timer (struct sock *); +void reset_timer (struct sock *, int, unsigned long); +void net_timer (unsigned long); + + +#endif /* _SOCK_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.c new file mode 100644 index 000000000..0133e1830 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.c @@ -0,0 +1,3918 @@ +/* + * 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. + * + * Implementation of the Transmission Control Protocol(TCP). + * + * Version: @(#)tcp.c 1.0.16 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Mark Evans, + * Corey Minyard + * Florian La Roche, + * + * 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 + * Alan Cox : sk->keepopen now seems to work + * Alan Cox : Pulls options out correctly on accepts + * Alan Cox : Fixed assorted sk->rqueue->next errors + * Alan Cox : PSH doesn't end a TCP read. Switched a bit to skb ops. + * Alan Cox : Tidied tcp_data to avoid a potential nasty. + * Alan Cox : Added some beter commenting, as the tcp is hard to follow + * Alan Cox : Removed incorrect check for 20 * psh + * Michael O'Reilly : ack < copied bug fix. + * Johannes Stille : Misc tcp fixes (not all in yet). + * Alan Cox : FIN with no memory -> CRASH + * Alan Cox : Added socket option proto entries. Also added awareness of them to accept. + * Alan Cox : Added TCP options (SOL_TCP) + * Alan Cox : Switched wakeup calls to callbacks, so the kernel can layer network sockets. + * Alan Cox : Use ip_tos/ip_ttl settings. + * Alan Cox : Handle FIN (more) properly (we hope). + * Alan Cox : RST frames sent on unsynchronised state ack error/ + * Alan Cox : Put in missing check for SYN bit. + * Alan Cox : Added tcp_select_window() aka NET2E + * window non shrink trick. + * Alan Cox : Added a couple of small NET2E timer fixes + * Charles Hedrick : TCP fixes + * Toomas Tamm : TCP window fixes + * + * + * 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). + * 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 + * 2 of the License, or(at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "icmp.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" +#include +#include +#include +#include +#include + +#define SEQ_TICK 3 +unsigned long seq_offset; +#define SUBNETSARELOCAL + +static __inline__ int +min(unsigned int a, unsigned int b) +{ + if (a < b) return(a); + return(b); +} + + +void +print_th(struct tcphdr *th) +{ + unsigned char *ptr; + + if (inet_debug != DBG_TCP) return; + + printk("TCP header:\n"); + ptr =(unsigned char *)(th + 1); + printk(" source=%d, dest=%d, seq =%ld, ack_seq = %ld\n", + ntohs(th->source), ntohs(th->dest), + ntohl(th->seq), ntohl(th->ack_seq)); + printk(" fin=%d, syn=%d, rst=%d, psh=%d, ack=%d, urg=%d res1=%d res2=%d\n", + th->fin, th->syn, th->rst, th->psh, th->ack, + th->urg, th->res1, th->res2); + printk(" window = %d, check = %d urg_ptr = %d\n", + ntohs(th->window), ntohs(th->check), ntohs(th->urg_ptr)); + printk(" doff = %d\n", th->doff); + printk(" options = %d %d %d %d\n", ptr[0], ptr[1], ptr[2], ptr[3]); + } + + + +/* This routine grabs the first thing off of a rcv queue. */ +static struct sk_buff * +get_firstr(struct sock *sk) +{ + return skb_dequeue(&sk->rqueue); +} + +/* + * Difference between two values in tcp ack terms. + */ + +static long +diff(unsigned long seq1, unsigned long seq2) +{ + long d; + + d = seq1 - seq2; + if (d > 0) return(d); + + /* I hope this returns what I want. */ + return(~d+1); +} + +/* This routine picks a TCP windows for a socket based on + the following constraints + + 1. The window can never be shrunk once it is offered (RFC 793) + 2. We limit memory per socket + + For now we use NET2E3's heuristic of offering half the memory + we have handy. All is not as bad as this seems however because + of two things. Firstly we will bin packets even within the window + in order to get the data we are waiting for into the memory limit. + Secondly we bin common duplicate forms at receive time + + Better heuristics welcome +*/ + +static int tcp_select_window(struct sock *sk) +{ + int new_window = sk->prot->rspace(sk); + +/* + * two things are going on here. First, we don't ever offer a + * window less than min(sk->mss, MAX_WINDOW/2). This is the + * receiver side of SWS as specified in RFC1122. + * Second, we always give them at least the window they + * had before, in order to avoid retracting window. This + * is technically allowed, but RFC1122 advises against it and + * in practice it causes trouble. + */ + if (new_window < min(sk->mss, MAX_WINDOW/2) || + new_window < sk->window) + return(sk->window); + return(new_window); +} + +/* Enter the time wait state. */ + +static void tcp_time_wait(struct sock *sk) +{ + sk->state = TCP_TIME_WAIT; + sk->shutdown = SHUTDOWN_MASK; + if (!sk->dead) + sk->state_change(sk); + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); +} + +/* + * A timer event has trigger a tcp retransmit timeout. The + * socket xmit queue is ready and set up to send. Because + * the ack receive code keeps the queue straight we do + * nothing clever here. + */ + +static void +tcp_retransmit(struct sock *sk, int all) +{ + if (all) { + ip_retransmit(sk, all); + return; + } + + sk->ssthresh = sk->cong_window >> 1; /* remember window where we lost */ + /* sk->ssthresh in theory can be zero. I guess that's OK */ + sk->cong_count = 0; + + sk->cong_window = 1; + + /* Do the actual retransmit. */ + ip_retransmit(sk, 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. After adjustment + * header points to the first 8 bytes of the tcp header. We need + * to find the appropriate port. + */ +void +tcp_err(int err, unsigned char *header, unsigned long daddr, + unsigned long saddr, struct inet_protocol *protocol) +{ + 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->source/*dest*/, daddr, th->dest/*source*/, saddr); + print_th(th); + + if (sk == NULL) return; + + if(err<0) + { + sk->err = -err; + sk->error_report(sk); + return; + } + + if ((err & 0xff00) == (ICMP_SOURCE_QUENCH << 8)) { + /* + * FIXME: + * For now we will just trigger a linear backoff. + * The slow start code should cause a real backoff here. + */ + if (sk->cong_window > 4) sk->cong_window--; + return; + } + + DPRINTF((DBG_TCP, "TCP: icmp_err got error\n")); + sk->err = icmp_err_convert[err & 0xff].errno; + + /* + * If we've already connected we will keep trying + * until we time out, or the user gives up. + */ + if (icmp_err_convert[err & 0xff].fatal) { + if (sk->state == TCP_SYN_SENT) { + sk->state = TCP_CLOSE; + sk->error_report(sk); /* Wake people up to see the error (see connect in sock.c) */ + } + } + return; +} + + +/* + * Walk down the receive queue counting readable data until we hit the end or we find a gap + * in the received data queue (ie a frame missing that needs sending to us) + */ + +static int +tcp_readable(struct sock *sk) +{ + unsigned long counted; + unsigned long amount; + struct sk_buff *skb; + int count=0; + int sum; + unsigned long flags; + + DPRINTF((DBG_TCP, "tcp_readable(sk=%X)\n", sk)); + if(sk && sk->debug) + printk("tcp_readable: %p - ",sk); + + if (sk == NULL || skb_peek(&sk->rqueue) == NULL) /* Empty sockets are easy! */ + { + if(sk && sk->debug) + printk("empty\n"); + return(0); + } + + counted = sk->copied_seq+1; /* Where we are at the moment */ + amount = 0; + + save_flags(flags); /* So nobody adds things at the wrong moment */ + cli(); + skb =(struct sk_buff *)sk->rqueue; + + /* Do until a push or until we are out of data. */ + do { + count++; +#ifdef OLD + /* This is wrong: It breaks Chameleon amongst other stacks */ + if (count > 20) { + restore_flags(flags); + DPRINTF((DBG_TCP, "tcp_readable, more than 20 packets without a psh\n")); + printk("tcp_read: possible read_queue corruption.\n"); + return(amount); + } +#endif + if (before(counted, skb->h.th->seq)) /* Found a hole so stops here */ + break; + sum = skb->len -(counted - skb->h.th->seq); /* Length - header but start from where we are up to (avoid overlaps) */ + if (skb->h.th->syn) sum++; + if (skb->h.th->urg) { + sum -= ntohs(skb->h.th->urg_ptr); /* Dont count urg data */ + } + if (sum >= 0) { /* Add it up, move on */ + amount += sum; + if (skb->h.th->syn) amount--; + counted += sum; + } + if (amount && skb->h.th->psh) break; + skb =(struct sk_buff *)skb->next; /* Move along */ + } while(skb != sk->rqueue); + restore_flags(flags); + DPRINTF((DBG_TCP, "tcp readable returning %d bytes\n", amount)); + if(sk->debug) + printk("got %lu bytes.\n",amount); + return(amount); +} + + +/* + * Wait for a TCP event. Note the oddity with SEL_IN and reading. The + * listening socket has a receive queue of sockets to accept. + */ + +static int +tcp_select(struct sock *sk, int sel_type, select_table *wait) +{ + DPRINTF((DBG_TCP, "tcp_select(sk=%X, sel_type = %d, wait = %X)\n", + sk, sel_type, wait)); + + sk->inuse = 1; + switch(sel_type) { + case SEL_IN: + if(sk->debug) + printk("select in"); + select_wait(sk->sleep, wait); + if(sk->debug) + printk("-select out"); + if (skb_peek(&sk->rqueue) != NULL) { + if (sk->state == TCP_LISTEN || tcp_readable(sk)) { + release_sock(sk); + if(sk->debug) + printk("-select ok data\n"); + return(1); + } + } + if (sk->err != 0) /* Receiver error */ + { + release_sock(sk); + if(sk->debug) + printk("-select ok error"); + return(1); + } + if (sk->shutdown & RCV_SHUTDOWN) { + release_sock(sk); + if(sk->debug) + printk("-select ok down\n"); + return(1); + } else { + release_sock(sk); + if(sk->debug) + printk("-select fail\n"); + return(0); + } + case SEL_OUT: + select_wait(sk->sleep, wait); + if (sk->shutdown & SEND_SHUTDOWN) { + DPRINTF((DBG_TCP, + "write select on shutdown socket.\n")); + + /* FIXME: should this return an error? */ + release_sock(sk); + return(0); + } + + /* + * FIXME: + * Hack so it will probably be able to write + * something if it says it's ok to write. + */ + if (sk->prot->wspace(sk) >= sk->mss) { + release_sock(sk); + /* This should cause connect to work ok. */ + if (sk->state == TCP_SYN_RECV || + sk->state == TCP_SYN_SENT) return(0); + return(1); + } + DPRINTF((DBG_TCP, + "tcp_select: sleeping on write sk->wmem_alloc = %d, " + "sk->packets_out = %d\n" + "sk->wback = %X, sk->wfront = %X\n" + "sk->send_seq = %u, sk->window_seq=%u\n", + sk->wmem_alloc, sk->packets_out, + sk->wback, sk->wfront, + sk->send_seq, sk->window_seq)); + + release_sock(sk); + return(0); + case SEL_EX: + select_wait(sk->sleep,wait); + if (sk->err) { + release_sock(sk); + return(1); + } + release_sock(sk); + return(0); + } + + release_sock(sk); + return(0); +} + + +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: + return(dbg_ioctl((void *) arg, DBG_TCP)); + + case TIOCINQ: +#ifdef FIXME /* FIXME: */ + case FIONREAD: +#endif + { + unsigned long amount; + + if (sk->state == TCP_LISTEN) return(-EINVAL); + + sk->inuse = 1; + amount = tcp_readable(sk); + release_sock(sk); + DPRINTF((DBG_TCP, "returning %d\n", amount)); + err=verify_area(VERIFY_WRITE,(void *)arg, + sizeof(unsigned long)); + if(err) + return err; + put_fs_long(amount,(unsigned long *)arg); + return(0); + } + case SIOCATMARK: + { + struct sk_buff *skb; + int answ = 0; + + /* + * Try to figure out if we need to read + * some urgent data. + */ + sk->inuse = 1; + if ((skb=skb_peek(&sk->rqueue)) != NULL) + { + if (sk->copied_seq+1 == skb->h.th->seq && skb->h.th->urg) + answ = 1; + } + release_sock(sk); + err=verify_area(VERIFY_WRITE,(void *) arg, + sizeof(unsigned long)); + if(err) + return err; + put_fs_long(answ,(int *) arg); + return(0); + } + case TIOCOUTQ: + { + unsigned long amount; + + if (sk->state == TCP_LISTEN) return(-EINVAL); + amount = sk->prot->wspace(sk); + err=verify_area(VERIFY_WRITE,(void *)arg, + sizeof(unsigned long)); + if(err) + return err; + put_fs_long(amount,(unsigned long *)arg); + return(0); + } + default: + return(-EINVAL); + } +} + + +/* This routine computes a TCP checksum. */ +unsigned short +tcp_check(struct tcphdr *th, int len, + unsigned long saddr, unsigned long daddr) +{ + unsigned long sum; + + if (saddr == 0) saddr = my_addr(); + print_th(th); + __asm__("\t addl %%ecx,%%ebx\n" + "\t adcl %%edx,%%ebx\n" + "\t adcl $0, %%ebx\n" + : "=b"(sum) + : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_TCP*256) + : "cx","bx","dx" ); + + if (len > 3) { + __asm__("\tclc\n" + "1:\n" + "\t lodsl\n" + "\t adcl %%eax, %%ebx\n" + "\t loop 1b\n" + "\t adcl $0, %%ebx\n" + : "=b"(sum) , "=S"(th) + : "0"(sum), "c"(len/4) ,"1"(th) + : "ax", "cx", "bx", "si" ); + } + + /* Convert from 32 bits to 16 bits. */ + __asm__("\t movl %%ebx, %%ecx\n" + "\t shrl $16,%%ecx\n" + "\t addw %%cx, %%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum) + : "0"(sum) + : "bx", "cx"); + + /* Check for an extra word. */ + if ((len & 2) != 0) { + __asm__("\t lodsw\n" + "\t addw %%ax,%%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum), "=S"(th) + : "0"(sum) ,"1"(th) + : "si", "ax", "bx"); + } + + /* Now check for the extra byte. */ + if ((len & 1) != 0) { + __asm__("\t lodsb\n" + "\t movb $0,%%ah\n" + "\t addw %%ax,%%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum) + : "0"(sum) ,"S"(th) + : "si", "ax", "bx"); + } + + /* We only want the bottom 16 bits, but we never cleared the top 16. */ + return((~sum) & 0xffff); +} + + +void tcp_send_check(struct tcphdr *th, unsigned long saddr, + unsigned long daddr, int len, struct sock *sk) +{ + th->check = 0; + th->check = tcp_check(th, len, saddr, daddr); + return; +} + +static void tcp_send_skb(struct sock *sk, struct sk_buff *skb) +{ + int size; + + /* length of packet (not counting length of pre-tcp headers) */ + size = skb->len - ((unsigned char *) skb->h.th - skb->data); + + /* sanity check it.. */ + if (size < sizeof(struct tcphdr) || size > skb->len) { + printk("tcp_send_skb: bad skb (skb = %p, data = %p, th = %p, len = %lu)\n", + skb, skb->data, skb->h.th, skb->len); + kfree_skb(skb, FREE_WRITE); + return; + } + + /* If we have queued a header size packet.. */ + if (size == sizeof(struct tcphdr)) { + /* If its got a syn or fin its notionally included in the size..*/ + if(!skb->h.th->syn && !skb->h.th->fin) { + printk("tcp_send_skb: attempt to queue a bogon.\n"); + kfree_skb(skb,FREE_WRITE); + return; + } + } + + /* We need to complete and send the packet. */ + tcp_send_check(skb->h.th, sk->saddr, sk->daddr, size, sk); + + skb->h.seq = sk->send_seq; + if (after(sk->send_seq , sk->window_seq) || + (sk->retransmits && sk->timeout == TIME_WRITE) || + sk->packets_out >= sk->cong_window) { + DPRINTF((DBG_TCP, "sk->cong_window = %d, sk->packets_out = %d\n", + sk->cong_window, sk->packets_out)); + DPRINTF((DBG_TCP, "sk->send_seq = %d, sk->window_seq = %d\n", + sk->send_seq, sk->window_seq)); + skb->next = NULL; + skb->magic = TCP_WRITE_QUEUE_MAGIC; + if (sk->wback == NULL) { + sk->wfront = skb; + } else { + sk->wback->next = skb; + } + sk->wback = skb; + if (before(sk->window_seq, sk->wfront->h.seq) && + sk->send_head == NULL && + sk->ack_backlog == 0) + reset_timer(sk, TIME_PROBE0, sk->rto); + } else { + sk->prot->queue_xmit(sk, skb->dev, skb, 0); + } +} + +struct sk_buff * tcp_dequeue_partial(struct sock * sk) +{ + struct sk_buff * skb; + unsigned long flags; + + save_flags(flags); + cli(); + skb = sk->partial; + if (skb) { + sk->partial = NULL; + del_timer(&sk->partial_timer); + } + restore_flags(flags); + return skb; +} + +static void tcp_send_partial(struct sock *sk) +{ + struct sk_buff *skb; + + if (sk == NULL) + return; + while ((skb = tcp_dequeue_partial(sk)) != NULL) + tcp_send_skb(sk, skb); +} + +void tcp_enqueue_partial(struct sk_buff * skb, struct sock * sk) +{ + struct sk_buff * tmp; + unsigned long flags; + + save_flags(flags); + cli(); + tmp = sk->partial; + if (tmp) + del_timer(&sk->partial_timer); + sk->partial = skb; + sk->partial_timer.expires = HZ; + sk->partial_timer.function = (void (*)(unsigned long)) tcp_send_partial; + sk->partial_timer.data = (unsigned long) sk; + add_timer(&sk->partial_timer); + restore_flags(flags); + if (tmp) + tcp_send_skb(sk, tmp); +} + + +/* This routine sends an ack and also updates the window. */ +static void +tcp_send_ack(unsigned long sequence, unsigned long ack, + struct sock *sk, + struct tcphdr *th, unsigned long daddr) +{ + struct sk_buff *buff; + struct tcphdr *t1; + 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. + */ + buff = sk->prot->wmalloc(sk, MAX_ACK_SIZE, 1, GFP_ATOMIC); + if (buff == NULL) { + /* Force it to send an ack. */ + sk->ack_backlog++; + if (sk->timeout != TIME_WRITE && tcp_connected(sk->state)) { + reset_timer(sk, TIME_WRITE, 10); + } +if (inet_debug == DBG_SLIP) printk("\rtcp_ack: malloc failed\n"); + return; + } + + buff->mem_addr = buff; + buff->mem_len = MAX_ACK_SIZE; + buff->len = sizeof(struct tcphdr); + buff->sk = sk; + t1 =(struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + tmp = sk->prot->build_header(buff, sk->saddr, daddr, &dev, + IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); + 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; + } + buff->len += tmp; + t1 =(struct tcphdr *)((char *)t1 +tmp); + + /* FIXME: */ + memcpy(t1, th, sizeof(*t1)); /* this should probably be removed */ + + /* swap the send and the receive. */ + t1->dest = th->source; + t1->source = th->dest; + t1->seq = ntohl(sequence); + t1->ack = 1; + sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ + t1->window = ntohs(sk->window); + t1->res1 = 0; + t1->res2 = 0; + t1->rst = 0; + t1->urg = 0; + t1->syn = 0; + t1->psh = 0; + t1->fin = 0; + if (ack == sk->acked_seq) { + sk->ack_backlog = 0; + sk->bytes_rcv = 0; + sk->ack_timed = 0; + if (sk->send_head == NULL && sk->wfront == NULL && sk->timeout == TIME_WRITE) + { + if(sk->keepopen) + reset_timer(sk,TIME_KEEPOPEN,TCP_TIMEOUT_LEN); + else + delete_timer(sk); + } + } + t1->ack_seq = ntohl(ack); + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, daddr, sizeof(*t1), sk); + if (sk->debug) + printk("\rtcp_ack: seq %lx ack %lx\n", sequence, ack); + sk->prot->queue_xmit(sk, dev, buff, 1); +} + + +/* This routine builds a generic TCP header. */ +static int +tcp_build_header(struct tcphdr *th, struct sock *sk, int push) +{ + + /* FIXME: want to get rid of this. */ + memcpy(th,(void *) &(sk->dummy_th), sizeof(*th)); + th->seq = htonl(sk->send_seq); + th->psh =(push == 0) ? 1 : 0; + th->doff = sizeof(*th)/4; + th->ack = 1; + th->fin = 0; + sk->ack_backlog = 0; + sk->bytes_rcv = 0; + sk->ack_timed = 0; + th->ack_seq = htonl(sk->acked_seq); + sk->window = tcp_select_window(sk)/*sk->prot->rspace(sk)*/; + th->window = htons(sk->window); + + return(sizeof(*th)); +} + +/* + * This routine copies from a user buffer into a socket, + * and starts the transmit system. + */ +static int +tcp_write(struct sock *sk, unsigned char *from, + int len, int nonblock, unsigned flags) +{ + int copied = 0; + int copy; + int tmp; + struct sk_buff *skb; + struct sk_buff *send_tmp; + unsigned char *buff; + struct proto *prot; + struct device *dev = NULL; + + 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) { /* Stop on an error */ + release_sock(sk); + if (copied) return(copied); + tmp = -sk->err; + sk->err = 0; + return(tmp); + } + + /* First thing we do is make sure that we are established. */ + if (sk->shutdown & SEND_SHUTDOWN) { + release_sock(sk); + sk->err = EPIPE; + if (copied) return(copied); + sk->err = 0; + return(-EPIPE); + } + + + /* Wait for a connection to finish. */ + + 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; + return(tmp); + } + + if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) { + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 1\n")); + if (copied) return(copied); + + if (sk->err) { + tmp = -sk->err; + sk->err = 0; + return(tmp); + } + + if (sk->keepopen) { + send_sig(SIGPIPE, current, 0); + } + return(-EPIPE); + } + + if (nonblock || copied) { + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 2\n")); + if (copied) return(copied); + return(-EAGAIN); + } + + release_sock(sk); + cli(); + if (sk->state != TCP_ESTABLISHED && + sk->state != TCP_CLOSE_WAIT && sk->err == 0) { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + DPRINTF((DBG_TCP, "tcp_write: return 3\n")); + if (copied) return(copied); + return(-ERESTARTSYS); + } + } + sk->inuse = 1; + sti(); + } + +/* + * The following code can result in copy <= if sk->mss is ever + * decreased. It shouldn't be. sk->mss is min(sk->mtu, sk->max_window). + * sk->mtu is constant once SYN processing is finished. I.e. we + * had better not get here until we've seen his SYN and at least one + * valid ack. (The SYN sets sk->mtu and the ack sets sk->max_window.) + * But ESTABLISHED should guarantee that. sk->max_window is by definition + * non-decreasing. Note that any ioctl to set user_mss must be done + * before the exchange of SYN's. If the initial ack from the other + * end has a window of 0, max_window and thus mss will both be 0. + */ + + /* Now we need to check if we have a half built packet. */ + if ((skb = tcp_dequeue_partial(sk)) != NULL) { + int hdrlen; + + /* IP header + TCP header */ + hdrlen = ((unsigned long)skb->h.th - (unsigned long)skb->data) + + sizeof(struct tcphdr); + + /* Add more stuff to the end of skb->len */ + if (!(flags & MSG_OOB)) { + copy = min(sk->mss - (skb->len - hdrlen), len); + /* FIXME: this is really a bug. */ + if (copy <= 0) { + printk("TCP: **bug**: \"copy\" <= 0!!\n"); + copy = 0; + } + + memcpy_fromfs(skb->data + skb->len, from, copy); + skb->len += copy; + from += copy; + copied += copy; + len -= copy; + sk->send_seq += copy; + } + if ((skb->len - hdrlen) >= sk->mss || + (flags & MSG_OOB) || + !sk->packets_out) + tcp_send_skb(sk, skb); + else + tcp_enqueue_partial(skb, sk); + continue; + } + + /* + * We also need to worry about the window. + * If window < 1/2 the maximum window we've seen from this + * host, don't use it. This is sender side + * silly window prevention, as specified in RFC1122. + * (Note that this is diffferent than earlier versions of + * SWS prevention, e.g. RFC813.). What we actually do is + * use the whole MSS. Since the results in the right + * edge of the packet being outside the window, it will + * be queued for later rather than sent. + */ + + copy = diff(sk->window_seq, sk->send_seq); + /* what if max_window == 1? In that case max_window >> 1 is 0. + * however in that case copy == max_window, so it's OK to use + * the window */ + if (copy < (sk->max_window >> 1)) + copy = sk->mss; + copy = min(copy, sk->mss); + copy = min(copy, len); + + /* We should really check the window here also. */ + send_tmp = NULL; + if (copy < sk->mss && !(flags & MSG_OOB)) { + /* We will release the socket incase we sleep here. */ + release_sock(sk); + /* NB: following must be mtu, because mss can be increased. + * mss is always <= mtu */ + skb = prot->wmalloc(sk, sk->mtu + 128 + prot->max_header + sizeof(*skb), 0, GFP_KERNEL); + sk->inuse = 1; + send_tmp = skb; + } else { + /* We will release the socket incase we sleep here. */ + release_sock(sk); + skb = prot->wmalloc(sk, copy + prot->max_header + sizeof(*skb), 0, GFP_KERNEL); + sk->inuse = 1; + } + + /* If we didn't get any memory, we need to sleep. */ + if (skb == NULL) { + if (nonblock /* || copied */) { + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 4\n")); + if (copied) return(copied); + return(-EAGAIN); + } + + /* FIXME: here is another race condition. */ + tmp = sk->wmem_alloc; + release_sock(sk); + 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) { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + DPRINTF((DBG_TCP, "tcp_write: return 5\n")); + if (copied) return(copied); + return(-ERESTARTSYS); + } + } + sk->inuse = 1; + sti(); + continue; + } + + skb->len = 0; + skb->sk = sk; + skb->free = 0; + + buff = skb->data; + + /* + * FIXME: we need to optimize this. + * Perhaps some hints here would be good. + */ + tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev, + IPPROTO_TCP, sk->opt, skb->mem_len,sk->ip_tos,sk->ip_ttl); + if (tmp < 0 ) { + prot->wfree(sk, skb->mem_addr, skb->mem_len); + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 6\n")); + if (copied) return(copied); + return(tmp); + } + skb->len += tmp; + skb->dev = dev; + buff += tmp; + skb->h.th =(struct tcphdr *) buff; + tmp = tcp_build_header((struct tcphdr *)buff, sk, len-copy); + if (tmp < 0) { + prot->wfree(sk, skb->mem_addr, skb->mem_len); + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 7\n")); + if (copied) return(copied); + return(tmp); + } + + if (flags & MSG_OOB) { + ((struct tcphdr *)buff)->urg = 1; + ((struct tcphdr *)buff)->urg_ptr = ntohs(copy); + } + skb->len += tmp; + memcpy_fromfs(buff+tmp, from, copy); + + from += copy; + copied += copy; + len -= copy; + skb->len += copy; + skb->free = 0; + sk->send_seq += copy; + + if (send_tmp != NULL && sk->packets_out) { + tcp_enqueue_partial(send_tmp, sk); + continue; + } + tcp_send_skb(sk, skb); + } + sk->err = 0; + +/* + * Nagles rule. Turn Nagle off with TCP_NODELAY for highly + * interactive fast network servers. It's meant to be on and + * it really improves the throughput though not the echo time + * on my slow slip link - Alan + */ + + /* Avoid possible race on send_tmp - c/o Johannes Stille */ + if(sk->partial && + ((!sk->packets_out) + /* If not nagling we can send on the before case too.. */ + || (sk->nonagle && before(sk->send_seq , sk->window_seq)) + )) + tcp_send_partial(sk); + /* -- */ + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_write: return 8\n")); + return(copied); +} + + +static int +tcp_sendto(struct sock *sk, unsigned char *from, + int len, int nonblock, unsigned flags, + struct sockaddr_in *addr, int addr_len) +{ + struct sockaddr_in sin; + + if (addr_len < sizeof(sin)) return(-EINVAL); + memcpy_fromfs(&sin, addr, sizeof(sin)); + if (sin.sin_family && sin.sin_family != AF_INET) return(-EINVAL); + if (sin.sin_port != sk->dummy_th.dest) return(-EINVAL); + if (sin.sin_addr.s_addr != sk->daddr) return(-EINVAL); + return(tcp_write(sk, from, len, nonblock, flags)); +} + + +static void +tcp_read_wakeup(struct sock *sk) +{ + int tmp; + struct device *dev = NULL; + struct tcphdr *t1; + struct sk_buff *buff; + + DPRINTF((DBG_TCP, "in tcp read wakeup\n")); + if (!sk->ack_backlog) return; + + /* + * FIXME: we need to put code here to prevent this routine from + * being called. Being called once in a while is ok, so only check + * if this is the second time in a row. + */ + + /* + * We need to grab some memory, and put together an ack, + * and then put it into the queue to be sent. + */ + buff = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); + if (buff == NULL) { + /* Try again real soon. */ + reset_timer(sk, TIME_WRITE, 10); + return; + } + + buff->mem_addr = buff; + buff->mem_len = MAX_ACK_SIZE; + buff->len = sizeof(struct tcphdr); + buff->sk = sk; + + /* Put in the IP header and routing stuff. */ + tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, + IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); + if (tmp < 0) { + buff->free=1; + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + return; + } + + buff->len += tmp; + t1 =(struct tcphdr *)(buff->data +tmp); + + memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); + t1->seq = ntohl(sk->send_seq); + t1->ack = 1; + t1->res1 = 0; + t1->res2 = 0; + t1->rst = 0; + t1->urg = 0; + t1->syn = 0; + t1->psh = 0; + sk->ack_backlog = 0; + sk->bytes_rcv = 0; + sk->window = tcp_select_window(sk);/*sk->prot->rspace(sk);*/ + t1->window = ntohs(sk->window); + t1->ack_seq = ntohl(sk->acked_seq); + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + sk->prot->queue_xmit(sk, dev, buff, 1); +} + + +/* + * FIXME: + * This routine frees used buffers. + * It should consider sending an ACK to let the + * other end know we now have a bigger window. + */ +static void +cleanup_rbuf(struct sock *sk) +{ + unsigned long flags; + int left; + struct sk_buff *skb; + + if(sk->debug) + printk("cleaning rbuf for sk=%p\n", sk); + + save_flags(flags); + cli(); + + left = sk->prot->rspace(sk); + + /* + * We have to loop through all the buffer headers, + * and try to free up all the space we can. + */ + while((skb=skb_peek(&sk->rqueue)) != NULL ) + { + if (!skb->used) + break; + skb_unlink(skb); + skb->sk = sk; + kfree_skb(skb, FREE_READ); + } + + restore_flags(flags); + + /* + * FIXME: + * At this point we should send an ack if the difference + * in the window, and the amount of space is bigger than + * TCP_WINDOW_DIFF. + */ + DPRINTF((DBG_TCP, "sk->window left = %d, sk->prot->rspace(sk)=%d\n", + sk->window - sk->bytes_rcv, sk->prot->rspace(sk))); + + if(sk->debug) + printk("sk->rspace = %lu, was %d\n", sk->prot->rspace(sk), + left); + if (sk->prot->rspace(sk) != left) + { + /* + * This area has caused the most trouble. The current strategy + * is to simply do nothing if the other end has room to send at + * least 3 full packets, because the ack from those will auto- + * matically update the window. If the other end doesn't think + * we have much space left, but we have room for atleast 1 more + * complete packet than it thinks we do, we will send an ack + * immediatedly. Otherwise we will wait up to .5 seconds in case + * the user reads some more. + */ + sk->ack_backlog++; +/* + * It's unclear whether to use sk->mtu or sk->mss here. They differ only + * if the other end is offering a window smaller than the agreed on MSS + * (called sk->mtu here). In theory there's no connection between send + * and receive, and so no reason to think that they're going to send + * small packets. For the moment I'm using the hack of reducing the mss + * only on the send side, so I'm putting mtu here. + */ + if ((sk->prot->rspace(sk) > (sk->window - sk->bytes_rcv + sk->mtu))) { + /* Send an ack right now. */ + tcp_read_wakeup(sk); + } else { + /* Force it to send an ack soon. */ + int was_active = del_timer(&sk->timer); + if (!was_active || TCP_ACK_TIME < sk->timer.expires) { + reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); + } else + add_timer(&sk->timer); + } + } +} + + +/* Handle reading urgent data. */ +static int +tcp_read_urg(struct sock * sk, int nonblock, + unsigned char *to, int len, unsigned flags) +{ + int copied = 0; + struct sk_buff *skb; + + DPRINTF((DBG_TCP, "tcp_read_urg(sk=%X, to=%X, len=%d, flags=%X)\n", + sk, to, len, flags)); + + while(len > 0) + { + sk->inuse = 1; + while(sk->urg==0 || skb_peek(&sk->rqueue) == NULL) { + if (sk->err) { + int tmp; + + release_sock(sk); + if (copied) return(copied); + tmp = -sk->err; + sk->err = 0; + return(tmp); + } + + if (sk->state == TCP_CLOSE || sk->done) { + release_sock(sk); + if (copied) return(copied); + if (!sk->done) { + sk->done = 1; + return(0); + } + return(-ENOTCONN); + } + + if (sk->shutdown & RCV_SHUTDOWN) { + release_sock(sk); + if (copied == 0) + sk->done = 1; + return(copied); + } + + if (nonblock || copied) { + release_sock(sk); + if (copied) return(copied); + return(-EAGAIN); + } + + /* Now at this point, we may have gotten some data. */ + release_sock(sk); + cli(); + if ((sk->urg == 0 || skb_peek(&sk->rqueue) == NULL) && + sk->err == 0 && !(sk->shutdown & RCV_SHUTDOWN)) { + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + if (copied) return(copied); + return(-ERESTARTSYS); + } + } + sk->inuse = 1; + sti(); + } + + skb = skb_peek(&sk->rqueue); + do { + int amt; + + if (skb->h.th->urg && !skb->urg_used) { + if (skb->h.th->urg_ptr == 0) { + skb->h.th->urg_ptr = ntohs(skb->len); + } + amt = min(ntohs(skb->h.th->urg_ptr),len); + if(amt) + { + memcpy_tofs(to,(unsigned char *)(skb->h.th) + + skb->h.th->doff*4, amt); + } + + if (!(flags & MSG_PEEK)) { + skb->urg_used = 1; + sk->urg--; + } + release_sock(sk); + copied += amt; + return(copied); + } + skb =(struct sk_buff *)skb->next; + } while(skb != sk->rqueue); + } +/*sk->urg = 0;*/ + release_sock(sk); + return(0); +} + + +/* This routine copies from a sock struct into the user buffer. */ +static int +tcp_read(struct sock *sk, unsigned char *to, + int len, int nonblock, unsigned flags) +{ + int copied=0; /* will be used to say how much has been copied. */ + 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); + + /* Urgent data needs to be handled specially. */ + if ((flags & MSG_OOB)) + return(tcp_read_urg(sk, nonblock, to, len, flags)); + + /* So no-one else will use this socket. */ + sk->inuse = 1; + + skb=skb_peek(&sk->rqueue); + + DPRINTF((DBG_TCP, "tcp_read(sk=%X, to=%X, len=%d, nonblock=%d, flags=%X)\n", + sk, to, len, nonblock, flags)); + + while(len > 0) { + /* skb->used just checks to see if we've gone all the way around. */ + + /* While no data, or first data indicates some is missing, or data is used */ + while(skb == NULL || + before(sk->copied_seq+1, skb->h.th->seq) || skb->used) { + DPRINTF((DBG_TCP, "skb = %X:\n", skb)); + cleanup_rbuf(sk); + if (sk->err) + { + int tmp; + + release_sock(sk); + if (copied) + { + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", + copied)); + return(copied); + } + tmp = -sk->err; + sk->err = 0; + return(tmp); + } + + if (sk->state == TCP_CLOSE) + { + release_sock(sk); + if (copied) { + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", + copied)); + return(copied); + } + if (!sk->done) { + sk->done = 1; + return(0); + } + return(-ENOTCONN); + } + + if (sk->shutdown & RCV_SHUTDOWN) + { + release_sock(sk); + if (copied == 0) sk->done = 1; + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); + return(copied); + } + + if (nonblock || copied) + { + release_sock(sk); + if(sk->debug) + printk("read: EAGAIN\n"); + if (copied) + { + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", + copied)); + return(copied); + } + return(-EAGAIN); + } + + if ((flags & MSG_PEEK) && copied != 0) + { + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); + return(copied); + } + + DPRINTF((DBG_TCP, "tcp_read about to sleep. state = %d\n", + sk->state)); + release_sock(sk); + + /* + * Now we may have some data waiting or we could + * have changed state. + */ + cli(); + if (sk->shutdown & RCV_SHUTDOWN || sk->err != 0) { + sk->inuse = 1; + sti(); + continue; + } + + if (skb_peek(&sk->rqueue) == NULL || + before(sk->copied_seq+1, sk->rqueue->h.th->seq)) { + if(sk->debug) + printk("Read wait sleep\n"); + interruptible_sleep_on(sk->sleep); + if(sk->debug) + printk("Read wait wakes\n"); + if (current->signal & ~current->blocked) { + sti(); + if (copied) { + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", + copied)); + return(copied); + } + return(-ERESTARTSYS); + } + } + sk->inuse = 1; + sti(); + DPRINTF((DBG_TCP, "tcp_read woke up. \n")); + + + skb=skb_peek(&sk->rqueue); + /* That may have been null if we were beaten, if so we loop again */ + } + + /* + * Copy anything from the current block that needs + * 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) /* Some of the packet is useful */ + { + /* + * If there is urgent data we must either + * return or skip over it. + */ + if (skb->h.th->urg) + { + if (skb->urg_used) + { + sk->copied_seq += ntohs(skb->h.th->urg_ptr); + offset += ntohs(skb->h.th->urg_ptr); + if (offset >= skb->len) + { + skb->used = 1; + skb =(struct sk_buff *)skb->next; + continue; + } + } + else + { + release_sock(sk); + if (copied) + return(copied); + send_sig(SIGURG, current, 0); + return(-EINTR); + } + } + /* Ok so how much can we use ? */ + used = min(skb->len - offset, len); + /* Copy it */ + memcpy_tofs(to,((unsigned char *)skb->h.th) + + skb->h.th->doff*4 + offset, used); + copied += used; + len -= used; + to += used; + + /* If we were reading the data is 'eaten' */ + if (!(flags & MSG_PEEK)) + sk->copied_seq += used; + + /* + * Mark this data used if we are really reading it, + * and if it doesn't contain any urgent data. And we + * have used all the data. + */ + if (!(flags & MSG_PEEK) && + (!skb->h.th->urg || skb->urg_used) && + (used + offset >= skb->len)) + skb->used = 1; + + /* + * See if this is the end of a message or if the + * remaining data is urgent. + */ + if (/*skb->h.th->psh || */skb->h.th->urg) + { + break; + } + } + else + { /* already used this data, must be a retransmit */ + skb->used = 1; + } + /* Move along a packet */ + skb =(struct sk_buff *)skb->next; + } + /* Clean up data we have read: This will do ACK frames */ + cleanup_rbuf(sk); + release_sock(sk); + DPRINTF((DBG_TCP, "tcp_read: returning %d\n", copied)); + if (copied == 0 && nonblock) + return(-EAGAIN); + return(copied); +} + + +/* + * Send a FIN without closing the connection. + * Not called at interrupt time. + */ +void +tcp_shutdown(struct sock *sk, int how) +{ + struct sk_buff *buff; + struct tcphdr *t1, *th; + struct proto *prot; + int tmp; + struct device *dev = NULL; + + /* + * We need to grab some memory, and put together a FIN, + * and then put it into the queue to be sent. + * FIXME: + * Tim MacKenzie(tym@dibbler.cs.monash.edu.au) 4 Dec '92. + * Most of this is guesswork, so maybe it will work... + */ + /* If we've already sent a FIN, return. */ + if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) return; + if (!(how & SEND_SHUTDOWN)) return; + sk->inuse = 1; + + /* Clear out any half completed packets. */ + if (sk->partial) + tcp_send_partial(sk); + + prot =(struct proto *)sk->prot; + th =(struct tcphdr *)&sk->dummy_th; + release_sock(sk); /* incase the malloc sleeps. */ + buff = prot->wmalloc(sk, MAX_RESET_SIZE,1 , GFP_KERNEL); + if (buff == NULL) return; + sk->inuse = 1; + + DPRINTF((DBG_TCP, "tcp_shutdown_send buff = %X\n", buff)); + buff->mem_addr = buff; + buff->mem_len = MAX_RESET_SIZE; + buff->sk = sk; + buff->len = sizeof(*t1); + t1 =(struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, + IPPROTO_TCP, sk->opt, + sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); + if (tmp < 0) { + buff->free=1; + prot->wfree(sk,buff->mem_addr, buff->mem_len); + release_sock(sk); + DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); + return; + } + + t1 =(struct tcphdr *)((char *)t1 +tmp); + buff->len += tmp; + buff->dev = dev; + memcpy(t1, th, sizeof(*t1)); + t1->seq = ntohl(sk->send_seq); + sk->send_seq++; + buff->h.seq = sk->send_seq; + t1->ack = 1; + t1->ack_seq = ntohl(sk->acked_seq); + t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->fin = 1; + t1->rst = 0; + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + + /* + * Can't just queue this up. + * It should go at the end of the write queue. + */ + if (sk->wback != NULL) { + buff->free=0; + buff->next = NULL; + sk->wback->next = buff; + sk->wback = buff; + buff->magic = TCP_WRITE_QUEUE_MAGIC; + } else { + sk->prot->queue_xmit(sk, dev, buff, 0); + } + + if (sk->state == TCP_ESTABLISHED) sk->state = TCP_FIN_WAIT1; + else sk->state = TCP_FIN_WAIT2; + + release_sock(sk); +} + + +static int +tcp_recvfrom(struct sock *sk, unsigned char *to, + int to_len, int nonblock, unsigned flags, + struct sockaddr_in *addr, int *addr_len) +{ + struct sockaddr_in sin; + int len; + 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); + + sin.sin_family = AF_INET; + sin.sin_port = sk->dummy_th.dest; + sin.sin_addr.s_addr = sk->daddr; + + memcpy_tofs(addr, &sin, len); + put_fs_long(len, addr_len); + return(result); +} + + +/* This routine will send an RST to the other tcp. */ +static void +tcp_reset(unsigned long saddr, unsigned long daddr, struct tcphdr *th, + struct proto *prot, struct options *opt, struct device *dev, int tos, int ttl) +{ + struct sk_buff *buff; + struct tcphdr *t1; + int tmp; + + /* + * We need to grab some memory, and put together an RST, + * and then put it into the queue to be sent. + */ + buff = prot->wmalloc(NULL, MAX_RESET_SIZE, 1, GFP_ATOMIC); + if (buff == NULL) + return; + + DPRINTF((DBG_TCP, "tcp_reset buff = %X\n", buff)); + buff->mem_addr = buff; + buff->mem_len = MAX_RESET_SIZE; + buff->len = sizeof(*t1); + buff->sk = NULL; + buff->dev = dev; + + t1 =(struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + tmp = prot->build_header(buff, saddr, daddr, &dev, IPPROTO_TCP, opt, + sizeof(struct tcphdr),tos,ttl); + if (tmp < 0) { + buff->free = 1; + prot->wfree(NULL, buff->mem_addr, buff->mem_len); + return; + } + t1 =(struct tcphdr *)((char *)t1 +tmp); + buff->len += tmp; + memcpy(t1, th, sizeof(*t1)); + + /* Swap the send and the receive. */ + t1->dest = th->source; + t1->source = th->dest; + 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; + t1->psh = 0; + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, saddr, daddr, sizeof(*t1), NULL); + prot->queue_xmit(NULL, dev, buff, 1); +} + + +/* + * Look for tcp options. Parses everything but only knows about MSS. + * This routine is always called with the packet containing the SYN. + * However it may also be called with the ack to the SYN. So you + * can't assume this is always the SYN. It's always called after + * we have set up sk->mtu to our own MTU. + */ + +static void +tcp_options(struct sock *sk, struct tcphdr *th) +{ + unsigned char *ptr; + int length=(th->doff*4)-sizeof(struct tcphdr); + int mss_seen = 0; + + ptr = (unsigned char *)(th + 1); + + 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 && th->syn) + { + sk->mtu=min(sk->mtu,ntohs(*(unsigned short *)ptr)); + mss_seen = 1; + } + break; + /* Add other options here as people feel the urge to implement stuff like large windows */ + } + ptr+=opsize-2; + length-=opsize; + } + } + if (th->syn) { + if (! mss_seen) + sk->mtu=min(sk->mtu, 536); /* default MSS if none sent */ + } + sk->mss = min(sk->max_window, sk->mtu); +} + +static inline unsigned long default_mask(unsigned long dst) +{ + dst = ntohl(dst); + if (IN_CLASSA(dst)) + return htonl(IN_CLASSA_NET); + if (IN_CLASSB(dst)) + return htonl(IN_CLASSB_NET); + return htonl(IN_CLASSC_NET); +} + +/* + * This routine handles a connection request. + * It should make sure we haven't already responded. + * Because of the way BSD works, we have to send a syn/ack now. + * This also means it will be harder to close a socket which is + * listening. + */ +static void +tcp_conn_request(struct sock *sk, struct sk_buff *skb, + unsigned long daddr, unsigned long saddr, + struct options *opt, struct device *dev) +{ + struct sk_buff *buff; + struct tcphdr *t1; + unsigned char *ptr; + struct sock *newsk; + struct tcphdr *th; + int tmp; + + DPRINTF((DBG_TCP, "tcp_conn_request(sk = %X, skb = %X, daddr = %X, sadd4= %X, \n" + " opt = %X, dev = %X)\n", + sk, skb, daddr, saddr, opt, dev)); + + th = skb->h.th; + + /* If the socket is dead, don't accept the connection. */ + if (!sk->dead) { + sk->data_ready(sk,0); + } else { + DPRINTF((DBG_TCP, "tcp_conn_request on dead socket\n")); + tcp_reset(daddr, saddr, th, sk->prot, opt, dev, sk->ip_tos,sk->ip_ttl); + kfree_skb(skb, FREE_READ); + return; + } + + /* + * Make sure we can accept more. This will prevent a + * flurry of syns from eating up all our memory. + */ + if (sk->ack_backlog >= sk->max_ack_backlog) { + kfree_skb(skb, FREE_READ); + return; + } + + /* + * We need to build a new sock struct. + * It is sort of bad to have a socket without an inode attached + * to it, but the wake_up's will just wake up the listening socket, + * and if the listening socket is destroyed before this is taken + * off of the queue, this will take care of it. + */ + newsk = (struct sock *) kmalloc(sizeof(struct sock), GFP_ATOMIC); + if (newsk == NULL) { + /* just ignore the syn. It will get retransmitted. */ + kfree_skb(skb, FREE_READ); + return; + } + + DPRINTF((DBG_TCP, "newsk = %X\n", newsk)); + memcpy((void *)newsk,(void *)sk, sizeof(*newsk)); + newsk->wback = NULL; + newsk->wfront = NULL; + newsk->rqueue = NULL; + newsk->send_head = NULL; + newsk->send_tail = NULL; + newsk->back_log = NULL; + newsk->rtt = TCP_CONNECT_TIME << 3; + newsk->rto = TCP_CONNECT_TIME; + newsk->mdev = 0; + newsk->max_window = 0; + newsk->cong_window = 1; + newsk->cong_count = 0; + newsk->ssthresh = 0; + newsk->backoff = 0; + newsk->blog = 0; + newsk->intr = 0; + newsk->proc = 0; + newsk->done = 0; + newsk->partial = NULL; + newsk->pair = NULL; + newsk->wmem_alloc = 0; + newsk->rmem_alloc = 0; + + newsk->max_unacked = MAX_WINDOW - TCP_WINDOW_DIFF; + + newsk->err = 0; + newsk->shutdown = 0; + newsk->ack_backlog = 0; + newsk->acked_seq = skb->h.th->seq+1; + newsk->fin_seq = skb->h.th->seq; + newsk->copied_seq = skb->h.th->seq; + newsk->state = TCP_SYN_RECV; + newsk->timeout = 0; + newsk->send_seq = jiffies * SEQ_TICK - seq_offset; + newsk->window_seq = newsk->send_seq; + newsk->rcv_ack_seq = newsk->send_seq; + newsk->urg =0; + newsk->retransmits = 0; + newsk->destroy = 0; + newsk->timer.data = (unsigned long)newsk; + newsk->timer.function = &net_timer; + newsk->dummy_th.source = skb->h.th->dest; + newsk->dummy_th.dest = skb->h.th->source; + + /* Swap these two, they are from our point of view. */ + newsk->daddr = saddr; + newsk->saddr = daddr; + + put_sock(newsk->num,newsk); + newsk->dummy_th.res1 = 0; + newsk->dummy_th.doff = 6; + newsk->dummy_th.fin = 0; + newsk->dummy_th.syn = 0; + newsk->dummy_th.rst = 0; + newsk->dummy_th.psh = 0; + newsk->dummy_th.ack = 0; + newsk->dummy_th.urg = 0; + newsk->dummy_th.res2 = 0; + newsk->acked_seq = skb->h.th->seq + 1; + newsk->copied_seq = skb->h.th->seq; + + /* Grab the ttl and tos values and use them */ + newsk->ip_ttl=sk->ip_ttl; + newsk->ip_tos=skb->ip_hdr->tos; + +/* use 512 or whatever user asked for */ +/* note use of sk->user_mss, since user has no direct access to newsk */ + if (sk->user_mss) + newsk->mtu = sk->user_mss; + else { +#ifdef SUBNETSARELOCAL + if ((saddr ^ daddr) & default_mask(saddr)) +#else + if ((saddr ^ daddr) & dev->pa_mask) +#endif + newsk->mtu = 576 - HEADER_SIZE; + else + newsk->mtu = MAX_WINDOW; + } +/* but not bigger than device MTU */ + newsk->mtu = min(newsk->mtu, dev->mtu - HEADER_SIZE); + +/* this will min with what arrived in the packet */ + tcp_options(newsk,skb->h.th); + + buff = newsk->prot->wmalloc(newsk, MAX_SYN_SIZE, 1, GFP_ATOMIC); + if (buff == NULL) { + sk->err = -ENOMEM; + newsk->dead = 1; + release_sock(newsk); + kfree_skb(skb, FREE_READ); + return; + } + + buff->mem_addr = buff; + buff->mem_len = MAX_SYN_SIZE; + buff->len = sizeof(struct tcphdr)+4; + buff->sk = newsk; + + t1 =(struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + tmp = sk->prot->build_header(buff, newsk->saddr, newsk->daddr, &dev, + IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl); + + /* Something went wrong. */ + if (tmp < 0) { + sk->err = tmp; + buff->free=1; + kfree_skb(buff,FREE_WRITE); + newsk->dead = 1; + release_sock(newsk); + skb->sk = sk; + kfree_skb(skb, FREE_READ); + return; + } + + buff->len += tmp; + t1 =(struct tcphdr *)((char *)t1 +tmp); + + memcpy(t1, skb->h.th, sizeof(*t1)); + buff->h.seq = newsk->send_seq; + + /* Swap the send and the receive. */ + t1->dest = skb->h.th->source; + t1->source = newsk->dummy_th.source; + t1->seq = ntohl(newsk->send_seq++); + t1->ack = 1; + newsk->window = tcp_select_window(newsk);/*newsk->prot->rspace(newsk);*/ + t1->window = ntohs(newsk->window); + t1->res1 = 0; + t1->res2 = 0; + t1->rst = 0; + t1->urg = 0; + t1->psh = 0; + t1->syn = 1; + t1->ack_seq = ntohl(skb->h.th->seq+1); + t1->doff = sizeof(*t1)/4+1; + + ptr =(unsigned char *)(t1+1); + ptr[0] = 2; + ptr[1] = 4; + ptr[2] = ((newsk->mtu) >> 8) & 0xff; + ptr[3] =(newsk->mtu) & 0xff; + + tcp_send_check(t1, daddr, saddr, sizeof(*t1)+4, newsk); + newsk->prot->queue_xmit(newsk, dev, buff, 0); + + reset_timer(newsk, TIME_WRITE /* -1 ? FIXME ??? */, TCP_CONNECT_TIME); + skb->sk = newsk; + + /* Charge the sock_buff to newsk. */ + sk->rmem_alloc -= skb->mem_len; + newsk->rmem_alloc += skb->mem_len; + + skb_queue_tail(&sk->rqueue,skb); + sk->ack_backlog++; + release_sock(newsk); +} + + +static void +tcp_close(struct sock *sk, int timeout) +{ + struct sk_buff *buff; + int need_reset = 0; + struct tcphdr *t1, *th; + struct proto *prot; + struct device *dev=NULL; + int tmp; + + /* + * We need to grab some memory, and put together a FIN, + * and then put it into the queue to be sent. + */ + DPRINTF((DBG_TCP, "tcp_close((struct sock *)%X, %d)\n",sk, timeout)); + sk->inuse = 1; + sk->keepopen = 1; + sk->shutdown = SHUTDOWN_MASK; + + if (!sk->dead) + sk->state_change(sk); + + /* We need to flush the recv. buffs. */ + if (skb_peek(&sk->rqueue) != NULL) + { + struct sk_buff *skb; + if(sk->debug) + printk("Clean rcv queue\n"); + while((skb=skb_dequeue(&sk->rqueue))!=NULL) + { + if(skb->len > 0 && after(skb->h.th->seq + skb->len + 1 , sk->copied_seq)) + need_reset = 1; + kfree_skb(skb, FREE_READ); + } + if(sk->debug) + printk("Cleaned.\n"); + } + sk->rqueue = NULL; + + /* Get rid off any half-completed packets. */ + if (sk->partial) { + tcp_send_partial(sk); + } + + switch(sk->state) { + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + case TCP_LAST_ACK: + /* start a timer. */ + /* original code was 4 * sk->rtt. In converting to the + * new rtt representation, we can't quite use that. + * it seems to make most sense to use the backed off value + */ + reset_timer(sk, TIME_CLOSE, 4 * sk->rto); + if (timeout) tcp_time_wait(sk); + release_sock(sk); + return; /* break causes a double release - messy */ + case TCP_TIME_WAIT: + if (timeout) { + sk->state = TCP_CLOSE; + } + release_sock(sk); + return; + case TCP_LISTEN: + sk->state = TCP_CLOSE; + release_sock(sk); + return; + case TCP_CLOSE: + release_sock(sk); + return; + case TCP_CLOSE_WAIT: + case TCP_ESTABLISHED: + case TCP_SYN_SENT: + case TCP_SYN_RECV: + prot =(struct proto *)sk->prot; + th =(struct tcphdr *)&sk->dummy_th; + buff = prot->wmalloc(sk, MAX_FIN_SIZE, 1, GFP_ATOMIC); + if (buff == NULL) { + /* This will force it to try again later. */ + /* Or it would have if someone released the socket + first. Anyway it might work now */ + release_sock(sk); + if (sk->state != TCP_CLOSE_WAIT) + sk->state = TCP_ESTABLISHED; + reset_timer(sk, TIME_CLOSE, 100); + return; + } + buff->mem_addr = buff; + buff->mem_len = MAX_FIN_SIZE; + buff->sk = sk; + buff->free = 1; + buff->len = sizeof(*t1); + t1 =(struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + tmp = prot->build_header(buff,sk->saddr, sk->daddr, &dev, + IPPROTO_TCP, sk->opt, + sizeof(struct tcphdr),sk->ip_tos,sk->ip_ttl); + if (tmp < 0) { + kfree_skb(buff,FREE_WRITE); + DPRINTF((DBG_TCP, "Unable to build header for fin.\n")); + release_sock(sk); + return; + } + + t1 =(struct tcphdr *)((char *)t1 +tmp); + buff->len += tmp; + buff->dev = dev; + memcpy(t1, th, sizeof(*t1)); + t1->seq = ntohl(sk->send_seq); + sk->send_seq++; + buff->h.seq = sk->send_seq; + t1->ack = 1; + + /* Ack everything immediately from now on. */ + sk->delay_acks = 0; + t1->ack_seq = ntohl(sk->acked_seq); + t1->window = ntohs(sk->window=tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->fin = 1; + t1->rst = need_reset; + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + + if (sk->wfront == NULL) { + prot->queue_xmit(sk, dev, buff, 0); + } else { + reset_timer(sk, TIME_WRITE, sk->rto); + buff->next = NULL; + if (sk->wback == NULL) { + sk->wfront = buff; + } else { + sk->wback->next = buff; + } + sk->wback = buff; + buff->magic = TCP_WRITE_QUEUE_MAGIC; + } + + if (sk->state == TCP_CLOSE_WAIT) { + sk->state = TCP_FIN_WAIT2; + } else { + sk->state = TCP_FIN_WAIT1; + } + } + release_sock(sk); +} + + +/* + * This routine takes stuff off of the write queue, + * and puts it in the xmit queue. + */ +static void +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 +1) && + (sk->retransmits == 0 || + sk->timeout != TIME_WRITE || + before(sk->wfront->h.seq, sk->rcv_ack_seq +1)) + && sk->packets_out < sk->cong_window) { + skb = sk->wfront; + IS_SKB(skb); + sk->wfront = skb->next; + if (sk->wfront == NULL) sk->wback = NULL; + skb->next = NULL; + if (skb->magic != TCP_WRITE_QUEUE_MAGIC) { + printk("tcp.c skb with bad magic(%X) on write queue. Squashing " + "queue\n", skb->magic); + sk->wfront = NULL; + sk->wback = NULL; + return; + } + skb->magic = 0; + DPRINTF((DBG_TCP, "Sending a packet.\n")); + + /* See if we really need to send the packet. */ + if (before(skb->h.seq, sk->rcv_ack_seq +1)) { + sk->retransmits = 0; + kfree_skb(skb, FREE_WRITE); + if (!sk->dead) sk->write_space(sk); + } else { + sk->prot->queue_xmit(sk, skb->dev, skb, skb->free); + } + } +} + + +/* + * This routine sorts the send list, and resets the + * sk->send_head and sk->send_tail pointers. + */ +void +sort_send(struct sock *sk) +{ + struct sk_buff *list = NULL; + struct sk_buff *skb,*skb2,*skb3; + + for (skb = sk->send_head; skb != NULL; skb = skb2) { + skb2 = (struct sk_buff *)skb->link3; + if (list == NULL || before (skb2->h.seq, list->h.seq)) { + skb->link3 = list; + sk->send_tail = skb; + list = skb; + } else { + for (skb3 = list; ; skb3 = (struct sk_buff *)skb3->link3) { + if (skb3->link3 == NULL || + before(skb->h.seq, skb3->link3->h.seq)) { + skb->link3 = skb3->link3; + skb3->link3 = skb; + if (skb->link3 == NULL) sk->send_tail = skb; + break; + } + } + } + } + sk->send_head = list; +} + + +/* This routine deals with incoming acks, but not outgoing ones. */ +static int +tcp_ack(struct sock *sk, struct tcphdr *th, unsigned long saddr, int len) +{ + unsigned long ack; + int flag = 0; + /* + * 1 - there was data in packet as well as ack or new data is sent or + * in shutdown state + * 2 - data from retransmit queue was acked and removed + * 4 - window shrunk or data from retransmit queue was acked and removed + */ + + 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", + ack, ntohs(th->window), sk->rcv_ack_seq, sk->window_seq)); + + if (ntohs(th->window) > sk->max_window) { + sk->max_window = ntohs(th->window); + sk->mss = min(sk->max_window, sk->mtu); + } + + if (sk->retransmits && sk->timeout == TIME_KEEPOPEN) + sk->retransmits = 0; + + if (after(ack, sk->send_seq+1) || before(ack, sk->rcv_ack_seq-1)) { + if (after(ack, sk->send_seq) || + (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT)) { + return(0); + } + if (sk->keepopen) { + reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); + } + return(1); + } + + if (len != th->doff*4) flag |= 1; + + /* See if our window has been shrunk. */ + if (after(sk->window_seq, ack+ntohs(th->window))) { + /* + * We may need to move packets from the send queue + * to the write queue, if the window has been shrunk on us. + * The RFC says you are not allowed to shrink your window + * like this, but if the other end does, you must be able + * to deal with it. + */ + struct sk_buff *skb; + struct sk_buff *skb2; + struct sk_buff *wskb = NULL; + + skb2 = sk->send_head; + sk->send_head = NULL; + sk->send_tail = NULL; + + flag |= 4; + + sk->window_seq = ack + ntohs(th->window); + cli(); + while (skb2 != NULL) { + skb = skb2; + skb2 = (struct sk_buff *)skb->link3; + skb->link3 = NULL; + if (after(skb->h.seq, sk->window_seq)) { + if (sk->packets_out > 0) sk->packets_out--; + /* We may need to remove this from the dev send list. */ + if (skb->next != NULL) { + skb_unlink(skb); + } + /* Now add it to the write_queue. */ + skb->magic = TCP_WRITE_QUEUE_MAGIC; + if (wskb == NULL) { + skb->next = sk->wfront; + sk->wfront = skb; + } else { + skb->next = wskb->next; + wskb->next = skb; + } + if (sk->wback == wskb) sk->wback = skb; + wskb = skb; + } else { + if (sk->send_head == NULL) { + sk->send_head = skb; + sk->send_tail = skb; + } else { + sk->send_tail->link3 = skb; + sk->send_tail = skb; + } + skb->link3 = NULL; + } + } + sti(); + } + + if (sk->send_tail == NULL || sk->send_head == NULL) { + sk->send_head = NULL; + sk->send_tail = NULL; + sk->packets_out= 0; + } + + sk->window_seq = ack + ntohs(th->window); + + /* We don't want too many packets out there. */ + if (sk->timeout == TIME_WRITE && + sk->cong_window < 2048 && after(ack, sk->rcv_ack_seq)) { +/* + * This is Jacobson's slow start and congestion avoidance. + * SIGCOMM '88, p. 328. Because we keep cong_window in integral + * mss's, we can't do cwnd += 1 / cwnd. Instead, maintain a + * counter and increment it once every cwnd times. It's possible + * that this should be done only if sk->retransmits == 0. I'm + * interpreting "new data is acked" as including data that has + * been retransmitted but is just now being acked. + */ + if (sk->cong_window < sk->ssthresh) + /* in "safe" area, increase */ + sk->cong_window++; + else { + /* in dangerous area, increase slowly. In theory this is + sk->cong_window += 1 / sk->cong_window + */ + if (sk->cong_count >= sk->cong_window) { + sk->cong_window++; + sk->cong_count = 0; + } else + sk->cong_count++; + } + } + + DPRINTF((DBG_TCP, "tcp_ack: Updating rcv ack sequence.\n")); + sk->rcv_ack_seq = ack; + + /* + * if this ack opens up a zero window, clear backoff. It was + * being used to time the probes, and is probably far higher than + * it needs to be for normal retransmission + */ + if (sk->timeout == TIME_PROBE0) { + if (sk->wfront != NULL && /* should always be non-null */ + ! before (sk->window_seq, sk->wfront->h.seq)) { + sk->retransmits = 0; + sk->backoff = 0; + /* recompute rto from rtt. this eliminates any backoff */ + sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; + if (sk->rto > 120*HZ) + sk->rto = 120*HZ; + if (sk->rto < 1*HZ) + sk->rto = 1*HZ; + } + } + + /* See if we can take anything off of the retransmit queue. */ + while(sk->send_head != NULL) { + /* Check for a bug. */ + if (sk->send_head->link3 && + after(sk->send_head->h.seq, sk->send_head->link3->h.seq)) { + printk("INET: tcp.c: *** bug send_list out of order.\n"); + sort_send(sk); + } + + if (before(sk->send_head->h.seq, ack+1)) { + struct sk_buff *oskb; + + if (sk->retransmits) { + + /* we were retransmitting. don't count this in RTT est */ + flag |= 2; + + /* + * even though we've gotten an ack, we're still + * retransmitting as long as we're sending from + * the retransmit queue. Keeping retransmits non-zero + * prevents us from getting new data interspersed with + * retransmissions. + */ + + if (sk->send_head->link3) + sk->retransmits = 1; + else + sk->retransmits = 0; + + } + + /* + * Note that we only reset backoff and rto in the + * rtt recomputation code. And that doesn't happen + * if there were retransmissions in effect. So the + * first new packet after the retransmissions is + * sent with the backoff still in effect. Not until + * we get an ack from a non-retransmitted packet do + * we reset the backoff and rto. This allows us to deal + * with a situation where the network delay has increased + * suddenly. I.e. Karn's algorithm. (SIGCOMM '87, p5.) + */ + + /* We have one less packet out there. */ + if (sk->packets_out > 0) sk->packets_out --; + DPRINTF((DBG_TCP, "skb=%X skb->h.seq = %d acked ack=%d\n", + sk->send_head, sk->send_head->h.seq, ack)); + + /* Wake up the process, it can probably write more. */ + if (!sk->dead) sk->write_space(sk); + + oskb = sk->send_head; + + if (!(flag&2)) { + long m; + + /* The following amusing code comes from Jacobson's + * article in SIGCOMM '88. Note that rtt and mdev + * are scaled versions of rtt and mean deviation. + * This is designed to be as fast as possible + * m stands for "measurement". + */ + + m = jiffies - oskb->when; /* RTT */ + m -= (sk->rtt >> 3); /* m is now error in rtt est */ + sk->rtt += m; /* rtt = 7/8 rtt + 1/8 new */ + if (m < 0) + m = -m; /* m is now abs(error) */ + m -= (sk->mdev >> 2); /* similar update on mdev */ + sk->mdev += m; /* mdev = 3/4 mdev + 1/4 new */ + + /* now update timeout. Note that this removes any backoff */ + sk->rto = ((sk->rtt >> 2) + sk->mdev) >> 1; + if (sk->rto > 120*HZ) + sk->rto = 120*HZ; + if (sk->rto < 1*HZ) + sk->rto = 1*HZ; + sk->backoff = 0; + + } + flag |= (2|4); + + 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. */ + skb_unlink(oskb); /* Much easier! */ + sti(); + oskb->magic = 0; + kfree_skb(oskb, FREE_WRITE); /* write. */ + if (!sk->dead) sk->write_space(sk); + } else { + break; + } + } + + /* + * Maybe we can take some stuff off of the write queue, + * and put it onto the xmit queue. + */ + if (sk->wfront != NULL) { + if (after (sk->window_seq+1, sk->wfront->h.seq) && + (sk->retransmits == 0 || + sk->timeout != TIME_WRITE || + before(sk->wfront->h.seq, sk->rcv_ack_seq +1)) + && sk->packets_out < sk->cong_window) { + flag |= 1; + tcp_write_xmit(sk); + } else if (before(sk->window_seq, sk->wfront->h.seq) && + sk->send_head == NULL && + sk->ack_backlog == 0 && + sk->state != TCP_TIME_WAIT) { + reset_timer(sk, TIME_PROBE0, sk->rto); + } + } else { + if (sk->send_head == NULL && sk->ack_backlog == 0 && + sk->state != TCP_TIME_WAIT && !sk->keepopen) { + DPRINTF((DBG_TCP, "Nothing to do, going to sleep.\n")); + if (!sk->dead) sk->write_space(sk); + + if (sk->keepopen) + reset_timer(sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); + else + delete_timer(sk); + } else { + if (sk->state != (unsigned char) sk->keepopen) { + reset_timer(sk, TIME_WRITE, sk->rto); + } + if (sk->state == TCP_TIME_WAIT) { + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + } + } + } + + if (sk->packets_out == 0 && sk->partial != NULL && + sk->wfront == NULL && sk->send_head == NULL) { + flag |= 1; + tcp_send_partial(sk); + } + + /* See if we are done. */ + if (sk->state == TCP_TIME_WAIT) { + if (!sk->dead) + sk->state_change(sk); + if (sk->rcv_ack_seq == sk->send_seq && sk->acked_seq == sk->fin_seq) { + flag |= 1; + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + } + } + + if (sk->state == TCP_LAST_ACK || sk->state == TCP_FIN_WAIT2) { + if (!sk->dead) sk->state_change(sk); + if (sk->rcv_ack_seq == sk->send_seq) { + flag |= 1; + if (sk->acked_seq != sk->fin_seq) { + tcp_time_wait(sk); + } else { + DPRINTF((DBG_TCP, "tcp_ack closing socket - %X\n", sk)); + tcp_send_ack(sk->send_seq, sk->acked_seq, sk, + th, sk->daddr); + sk->shutdown = SHUTDOWN_MASK; + sk->state = TCP_CLOSE; + } + } + } + +/* + * I make no guarantees about the first clause in the following + * test, i.e. "(!flag) || (flag&4)". I'm not entirely sure under + * what conditions "!flag" would be true. However I think the rest + * of the conditions would prevent that from causing any + * unnecessary retransmission. + * Clearly if the first packet has expired it should be + * retransmitted. The other alternative, "flag&2 && retransmits", is + * harder to explain: You have to look carefully at how and when the + * timer is set and with what timeout. The most recent transmission always + * sets the timer. So in general if the most recent thing has timed + * out, everything before it has as well. So we want to go ahead and + * retransmit some more. If we didn't explicitly test for this + * condition with "flag&2 && retransmits", chances are "when + rto < jiffies" + * would not be true. If you look at the pattern of timing, you can + * show that rto is increased fast enough that the next packet would + * almost never be retransmitted immediately. Then you'd end up + * waiting for a timeout to send each packet on the retranmission + * queue. With my implementation of the Karn sampling algorithm, + * the timeout would double each time. The net result is that it would + * take a hideous amount of time to recover from a single dropped packet. + * It's possible that there should also be a test for TIME_WRITE, but + * I think as long as "send_head != NULL" and "retransmit" is on, we've + * got to be in real retransmission mode. + * Note that ip_do_retransmit is called with all==1. Setting cong_window + * back to 1 at the timeout will cause us to send 1, then 2, etc. packets. + * As long as no further losses occur, this seems reasonable. + */ + + if (((!flag) || (flag&4)) && sk->send_head != NULL && + (((flag&2) && sk->retransmits) || + (sk->send_head->when + sk->rto < jiffies))) { + ip_do_retransmit(sk, 1); + reset_timer(sk, TIME_WRITE, sk->rto); + } + + DPRINTF((DBG_TCP, "leaving tcp_ack\n")); + return(1); +} + + +/* + * This routine handles the data. If there is room in the buffer, + * it will be have already been moved into it. If there is no + * room, then we will just have to discard the packet. + */ +static int +tcp_data(struct sk_buff *skb, struct sock *sk, + unsigned long saddr, unsigned short len) +{ + struct sk_buff *skb1, *skb2; + struct tcphdr *th; + int dup_dumped=0; + + th = skb->h.th; + print_th(th); + skb->len = len -(th->doff*4); + + DPRINTF((DBG_TCP, "tcp_data len = %d sk = %X:\n", skb->len, 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 forth. */ + if (!th->ack) tcp_send_ack(sk->send_seq, sk->acked_seq,sk, th, saddr); + kfree_skb(skb, FREE_READ); + return(0); + } + + if (sk->shutdown & RCV_SHUTDOWN) { + sk->acked_seq = th->seq + skb->len + th->syn + th->fin; + tcp_reset(sk->saddr, sk->daddr, skb->h.th, + sk->prot, NULL, skb->dev, sk->ip_tos, sk->ip_ttl); + sk->state = TCP_CLOSE; + sk->err = EPIPE; + sk->shutdown = SHUTDOWN_MASK; + DPRINTF((DBG_TCP, "tcp_data: closing socket - %X\n", sk)); + kfree_skb(skb, FREE_READ); + if (!sk->dead) sk->state_change(sk); + return(0); + } + + /* + * Now we have to walk the chain, and figure out where this one + * goes into it. This is set up so that the last packet we received + * will be the first one we look at, that way if everything comes + * in order, there will be no performance loss, and if they come + * out of order we will be able to fit things in nicely. + */ + + /* This should start at the last one, and then go around forwards. */ + if (sk->rqueue == NULL) { + DPRINTF((DBG_TCP, "tcp_data: skb = %X:\n", skb)); +#ifdef OLDWAY + sk->rqueue = skb; + skb->next = skb; + skb->prev = skb; + skb->list = &sk->rqueue; +#else + skb_queue_head(&sk->rqueue,skb); +#endif + skb1= NULL; + } else { + DPRINTF((DBG_TCP, "tcp_data adding to chain sk = %X:\n", sk)); + for(skb1=sk->rqueue->prev; ; skb1 =(struct sk_buff *)skb1->prev) { + if(sk->debug) + { + printk("skb1=%p :", skb1); + printk("skb1->h.th->seq = %ld: ", skb1->h.th->seq); + printk("skb->h.th->seq = %ld\n",skb->h.th->seq); + printk("copied_seq = %ld acked_seq = %ld\n", sk->copied_seq, + sk->acked_seq); + } +#ifdef OLD + if (after(th->seq+1, skb1->h.th->seq)) { + skb->prev = skb1; + skb->next = skb1->next; + skb->next->prev = skb; + skb1->next = skb; + if (skb1 == sk->rqueue) sk->rqueue = skb; + break; + } + if (skb1->prev == sk->rqueue) { + skb->next= skb1; + skb->prev = skb1->prev; + skb->prev->next = skb; + skb1->prev = skb; + skb1 = NULL; /* so we know we might be able + to ack stuff. */ + break; + } +#else + if (th->seq==skb1->h.th->seq && skb->len>= skb1->len) + { + skb_append(skb1,skb); + skb_unlink(skb1); + kfree_skb(skb1,FREE_READ); + dup_dumped=1; + skb1=NULL; + break; + } + if (after(th->seq+1, skb1->h.th->seq)) + { + skb_append(skb1,skb); + break; + } + if (skb1 == sk->rqueue) + { + skb_queue_head(&sk->rqueue, skb); + break; + } +#endif + } + DPRINTF((DBG_TCP, "skb = %X:\n", skb)); + } + + th->ack_seq = th->seq + skb->len; + if (th->syn) th->ack_seq++; + if (th->fin) th->ack_seq++; + + if (before(sk->acked_seq, sk->copied_seq)) { + printk("*** tcp.c:tcp_data bug acked < copied\n"); + sk->acked_seq = sk->copied_seq; + } + + /* Now figure out if we can ack anything. */ + if ((!dup_dumped && (skb1 == NULL || skb1->acked)) || before(th->seq, sk->acked_seq+1)) { + if (before(th->seq, sk->acked_seq+1)) { + if (after(th->ack_seq, sk->acked_seq)) + sk->acked_seq = th->ack_seq; + skb->acked = 1; + + /* When we ack the fin, we turn on the RCV_SHUTDOWN flag. */ + if (skb->h.th->fin) { + if (!sk->dead) sk->state_change(sk); + sk->shutdown |= RCV_SHUTDOWN; + } + + for(skb2 = (struct sk_buff *)skb->next; + skb2 !=(struct sk_buff *) sk->rqueue; + skb2 = (struct sk_buff *)skb2->next) { + if (before(skb2->h.th->seq, sk->acked_seq+1)) { + if (after(skb2->h.th->ack_seq, sk->acked_seq)) + { + long old_acked_seq = sk->acked_seq; + sk->acked_seq = skb2->h.th->ack_seq; + if((int)(sk->acked_seq - old_acked_seq) >0) + { + int new_window=sk->window-sk->acked_seq+ + old_acked_seq; + if(new_window<0) + new_window=0; + sk->window = new_window; + } + } + skb2->acked = 1; + + /* + * When we ack the fin, we turn on + * the RCV_SHUTDOWN flag. + */ + if (skb2->h.th->fin) { + sk->shutdown |= RCV_SHUTDOWN; + if (!sk->dead) sk->state_change(sk); + } + + /* Force an immediate ack. */ + sk->ack_backlog = sk->max_ack_backlog; + } else { + break; + } + } + + /* + * This also takes care of updating the window. + * This if statement needs to be simplified. + */ + if (!sk->delay_acks || + sk->ack_backlog >= sk->max_ack_backlog || + sk->bytes_rcv > sk->max_unacked || th->fin) { +/* tcp_send_ack(sk->send_seq, sk->acked_seq,sk,th, saddr); */ + } else { + sk->ack_backlog++; + if(sk->debug) + printk("Ack queued.\n"); + reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); + } + } + } + + /* + * If we've missed a packet, send an ack. + * Also start a timer to send another. + */ + if (!skb->acked) { + /* + * This is important. If we don't have much room left, + * we need to throw out a few packets so we have a good + * window. Note that mtu is used, not mss, because mss is really + * for the send side. He could be sending us stuff as large as mtu. + */ + while (sk->prot->rspace(sk) < sk->mtu) { + skb1 = skb_peek(&sk->rqueue); + if (skb1 == NULL) { + printk("INET: tcp.c:tcp_data memory leak detected.\n"); + break; + } + + /* Don't throw out something that has been acked. */ + if (skb1->acked) { + break; + } + + skb_unlink(skb1); +#ifdef OLDWAY + if (skb1->prev == skb1) { + sk->rqueue = NULL; + } else { + sk->rqueue = (struct sk_buff *)skb1->prev; + skb1->next->prev = skb1->prev; + skb1->prev->next = skb1->next; + } +#endif + kfree_skb(skb1, FREE_READ); + } + tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); + sk->ack_backlog++; + reset_timer(sk, TIME_WRITE, TCP_ACK_TIME); + } else { + /* We missed a packet. Send an ack to try to resync things. */ + tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); + } + + /* Now tell the user we may have some data. */ + if (!sk->dead) { + if(sk->debug) + printk("Data wakeup.\n"); + sk->data_ready(sk,0); + } else { + DPRINTF((DBG_TCP, "data received on dead socket.\n")); + } + + if (sk->state == TCP_FIN_WAIT2 && + sk->acked_seq == sk->fin_seq && sk->rcv_ack_seq == sk->send_seq) { + DPRINTF((DBG_TCP, "tcp_data: entering last_ack state sk = %X\n", sk)); + +/* tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); */ + sk->shutdown = SHUTDOWN_MASK; + sk->state = TCP_LAST_ACK; + if (!sk->dead) sk->state_change(sk); + } + + return(0); +} + + +static int +tcp_urg(struct sock *sk, struct tcphdr *th, unsigned long saddr) +{ + extern int kill_pg(int pg, int sig, int priv); + extern int kill_proc(int pid, int sig, int priv); + + if (!sk->dead) + sk->data_ready(sk,0); + + if (sk->urginline) { + th->urg = 0; + th->psh = 1; + return(0); + } + + if (!sk->urg) { + /* So if we get more urgent data, we don't signal the user again. */ + if (sk->proc != 0) { + if (sk->proc > 0) { + kill_proc(sk->proc, SIGURG, 1); + } else { + kill_pg(-sk->proc, SIGURG, 1); + } + } + } + sk->urg++; + return(0); +} + + +/* This deals with incoming fins. 'Linus at 9 O'clock' 8-) */ +static int +tcp_fin(struct sock *sk, struct tcphdr *th, + unsigned long saddr, struct device *dev) +{ + DPRINTF((DBG_TCP, "tcp_fin(sk=%X, th=%X, saddr=%X, dev=%X)\n", + sk, th, saddr, dev)); + + if (!sk->dead) { + sk->state_change(sk); + } + + switch(sk->state) { + case TCP_SYN_RECV: + case TCP_SYN_SENT: + case TCP_ESTABLISHED: + /* Contains the one that needs to be acked */ + sk->fin_seq = th->seq+1; + sk->state = TCP_CLOSE_WAIT; + if (th->rst) sk->shutdown = SHUTDOWN_MASK; + break; + + case TCP_CLOSE_WAIT: + case TCP_FIN_WAIT2: + break; /* we got a retransmit of the fin. */ + + case TCP_FIN_WAIT1: + /* Contains the one that needs to be acked */ + sk->fin_seq = th->seq+1; + sk->state = TCP_FIN_WAIT2; + break; + + default: + case TCP_TIME_WAIT: + sk->state = TCP_LAST_ACK; + + /* Start the timers. */ + reset_timer(sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + return(0); + } + sk->ack_backlog++; + + return(0); +} + + +/* This will accept the next outstanding connection. */ +static struct sock * +tcp_accept(struct sock *sk, int flags) +{ + struct sock *newsk; + struct sk_buff *skb; + + DPRINTF((DBG_TCP, "tcp_accept(sk=%X, flags=%X, addr=%s)\n", + sk, flags, in_ntoa(sk->saddr))); + + /* + * We need to make sure that this socket is listening, + * and that it has something pending. + */ + if (sk->state != TCP_LISTEN) { + sk->err = EINVAL; + return(NULL); + } + + /* avoid the race. */ + cli(); + sk->inuse = 1; + while((skb = get_firstr(sk)) == NULL) { + if (flags & O_NONBLOCK) { + sti(); + release_sock(sk); + sk->err = EAGAIN; + return(NULL); + } + + release_sock(sk); + interruptible_sleep_on(sk->sleep); + if (current->signal & ~current->blocked) { + sti(); + sk->err = ERESTARTSYS; + return(NULL); + } + sk->inuse = 1; + } + sti(); + + /* Now all we need to do is return skb->sk. */ + newsk = skb->sk; + + kfree_skb(skb, FREE_READ); + sk->ack_backlog--; + release_sock(sk); + return(newsk); +} + + +/* This will initiate an outgoing connection. */ +static int +tcp_connect(struct sock *sk, struct sockaddr_in *usin, int addr_len) +{ + struct sk_buff *buff; + struct sockaddr_in sin; + struct device *dev=NULL; + unsigned char *ptr; + int tmp; + struct tcphdr *t1; + int err; + + if (sk->state != TCP_CLOSE) return(-EISCONN); + if (addr_len < 8) return(-EINVAL); + + 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); + + DPRINTF((DBG_TCP, "TCP connect daddr=%s\n", in_ntoa(sin.sin_addr.s_addr))); + + /* Don't want a TCP connection going to a broadcast address */ + if (chk_addr(sin.sin_addr.s_addr) == IS_BROADCAST) { + DPRINTF((DBG_TCP, "TCP connection to broadcast address not allowed\n")); + return(-ENETUNREACH); + } + + /* Connect back to the same socket: Blows up so disallow it */ + if(sk->saddr == sin.sin_addr.s_addr && sk->num==ntohs(sin.sin_port)) + return -EBUSY; + + sk->inuse = 1; + sk->daddr = sin.sin_addr.s_addr; + sk->send_seq = jiffies * SEQ_TICK - seq_offset; + sk->window_seq = sk->send_seq; + sk->rcv_ack_seq = sk->send_seq -1; + sk->err = 0; + sk->dummy_th.dest = sin.sin_port; + release_sock(sk); + + buff = sk->prot->wmalloc(sk,MAX_SYN_SIZE,0, GFP_KERNEL); + if (buff == NULL) { + return(-ENOMEM); + } + sk->inuse = 1; + buff->mem_addr = buff; + buff->mem_len = MAX_SYN_SIZE; + buff->len = 24; + buff->sk = sk; + buff->free = 1; + t1 = (struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + /* We need to build the routing stuff fromt the things saved in skb. */ + tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, + IPPROTO_TCP, NULL, MAX_SYN_SIZE,sk->ip_tos,sk->ip_ttl); + if (tmp < 0) { + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + release_sock(sk); + return(-ENETUNREACH); + } + buff->len += tmp; + t1 = (struct tcphdr *)((char *)t1 +tmp); + + memcpy(t1,(void *)&(sk->dummy_th), sizeof(*t1)); + t1->seq = ntohl(sk->send_seq++); + buff->h.seq = sk->send_seq; + t1->ack = 0; + t1->window = 2; + t1->res1=0; + t1->res2=0; + t1->rst = 0; + t1->urg = 0; + t1->psh = 0; + t1->syn = 1; + t1->urg_ptr = 0; + t1->doff = 6; + +/* use 512 or whatever user asked for */ + if (sk->user_mss) + sk->mtu = sk->user_mss; + else { +#ifdef SUBNETSARELOCAL + if ((sk->saddr ^ sk->daddr) & default_mask(sk->saddr)) +#else + if ((sk->saddr ^ sk->daddr) & dev->pa_mask) +#endif + sk->mtu = 576 - HEADER_SIZE; + else + sk->mtu = MAX_WINDOW; + } +/* but not bigger than device MTU */ + sk->mtu = min(sk->mtu, dev->mtu - HEADER_SIZE); + + /* Put in the TCP options to say MTU. */ + ptr = (unsigned char *)(t1+1); + ptr[0] = 2; + ptr[1] = 4; + ptr[2] = (sk->mtu) >> 8; + ptr[3] = (sk->mtu) & 0xff; + tcp_send_check(t1, sk->saddr, sk->daddr, + sizeof(struct tcphdr) + 4, sk); + + /* This must go first otherwise a really quick response will get reset. */ + sk->state = TCP_SYN_SENT; + sk->rtt = 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); +} + + +/* This functions checks to see if the tcp header is actually acceptible. */ +static int +tcp_sequence(struct sock *sk, struct tcphdr *th, short len, + struct options *opt, unsigned long saddr, struct device *dev) +{ + /* + * This isn't quite right. sk->acked_seq could be more recent + * than sk->window. This is however close enough. We will accept + * slightly more packets than we should, but it should not cause + * problems unless someone is trying to forge packets. + */ + DPRINTF((DBG_TCP, "tcp_sequence(sk=%X, th=%X, len = %d, opt=%d, saddr=%X)\n", + sk, th, len, opt, saddr)); + + if (between(th->seq, sk->acked_seq, sk->acked_seq + sk->window)|| + between(th->seq + len-(th->doff*4), sk->acked_seq + 1, + sk->acked_seq + sk->window) || + (before(th->seq, sk->acked_seq) && + after(th->seq + len -(th->doff*4), sk->acked_seq + sk->window))) { + return(1); + } + DPRINTF((DBG_TCP, "tcp_sequence: rejecting packet.\n")); + + /* + * Send a reset if we get something not ours and we are + * unsynchronized. Note: We don't do anything to our end. We + * are just killing the bogus remote connection then we will + * connect again and it will work (with luck). + */ + + if(sk->state==TCP_SYN_SENT||sk->state==TCP_SYN_RECV) + { + tcp_reset(sk->saddr,sk->daddr,th,sk->prot,NULL,dev, sk->ip_tos,sk->ip_ttl); + return(1); + } + + /* + * If it's too far ahead, send an ack to let the + * other end know what we expect. + */ + if (after(th->seq, sk->acked_seq + sk->window)) { + if(!th->rst) + tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); + return(0); + } + +#ifdef undef +/* + * if we do this, we won't respond to keepalive packets, since those + * are slightly out of window, and we have to generate an ack + * a late ack out still not to have a sequence number less than + * one we've seen before. Berkeley doesn't seem to do this, but it's + * always hard to be sure. + */ + /* In case it's just a late ack, let it through. */ + if (th->ack && len == (th->doff * 4) && + after(th->seq, sk->acked_seq - 32767) && + !th->fin && !th->syn) return(1); +#endif + + if (!th->rst) { + /* Try to resync things. */ + tcp_send_ack(sk->send_seq, sk->acked_seq, sk, th, saddr); + } + return(0); +} + + + + + +int +tcp_rcv(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) +{ + struct tcphdr *th; + struct sock *sk; + + if (!skb) { + DPRINTF((DBG_TCP, "tcp.c: tcp_rcv skb = NULL\n")); + return(0); + } +#if 0 /* FIXME: it's ok for protocol to be NULL */ + if (!protocol) { + DPRINTF((DBG_TCP, "tcp.c: tcp_rcv protocol = NULL\n")); + return(0); + } + + if (!opt) { /* FIXME: it's ok for opt to be NULL */ + DPRINTF((DBG_TCP, "tcp.c: tcp_rcv opt = NULL\n")); + } +#endif + if (!dev) { + DPRINTF((DBG_TCP, "tcp.c: tcp_rcv dev = NULL\n")); + return(0); + } + th = skb->h.th; + + /* Find the socket. */ + 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 (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: bad checksum\n"); + kfree_skb(skb,FREE_READ); + /* + * We don't release the socket because it was + * never marked in use. + */ + return(0); + } + + /* See if we know about the socket. */ + if (sk == NULL) { + 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->ip_hdr->tos,255); + } + skb->sk = NULL; + kfree_skb(skb, FREE_READ); + return(0); + } + + skb->len = len; + skb->sk = sk; + skb->acked = 0; + skb->used = 0; + skb->free = 0; + skb->urg_used = 0; + skb->saddr = daddr; + skb->daddr = saddr; + + th->seq = ntohl(th->seq); + + /* We may need to add it to the backlog here. */ + 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(); + } else { + if (!sk) { + DPRINTF((DBG_TCP, "tcp.c: tcp_rcv bug sk=NULL redo = 1\n")); + return(0); + } + } + + if (!sk->prot) { + DPRINTF((DBG_TCP, "tcp.c: tcp_rcv sk->prot = NULL \n")); + return(0); + } + + /* Charge the memory to the socket. */ + 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, FREE_READ); + release_sock(sk); + return(0); + } + sk->rmem_alloc += skb->mem_len; + + DPRINTF((DBG_TCP, "About to do switch.\n")); + + /* Now deal with it. */ + switch(sk->state) { + /* + * This should close the system down if it's waiting + * for an ack that is never going to be sent. + */ + case TCP_LAST_ACK: + if (th->rst) { + sk->zapped=1; + sk->err = ECONNRESET; + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + if (!sk->dead) { + sk->state_change(sk); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + case TCP_ESTABLISHED: + case TCP_CLOSE_WAIT: + case TCP_FIN_WAIT1: + case TCP_FIN_WAIT2: + case TCP_TIME_WAIT: + if (!tcp_sequence(sk, th, len, opt, saddr,dev)) { +if (inet_debug == DBG_SLIP) printk("\rtcp_rcv: not in seq\n"); +#ifdef undef +/* nice idea, but tcp_sequence already does this. Maybe it shouldn't?? */ + if(!th->rst) + tcp_send_ack(sk->send_seq, sk->acked_seq, + sk, th, saddr); +#endif + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + if (th->rst) { + sk->zapped=1; + /* This means the thing should really be closed. */ + sk->err = ECONNRESET; + + if (sk->state == TCP_CLOSE_WAIT) { + sk->err = EPIPE; + } + + /* + * A reset with a fin just means that + * the data was not all read. + */ + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + if (!sk->dead) { + sk->state_change(sk); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + if ( +#if 0 + if ((opt && (opt->security != 0 || + opt->compartment != 0)) || +#endif + th->syn) { + sk->err = ECONNRESET; + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + tcp_reset(daddr, saddr, th, sk->prot, opt,dev, sk->ip_tos,sk->ip_ttl); + if (!sk->dead) { + sk->state_change(sk); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + if (th->ack) { + if (!tcp_ack(sk, th, saddr, len)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + } + if (th->urg) { + if (tcp_urg(sk, th, saddr)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + } + + if (tcp_data(skb, sk, saddr, len)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + /* Moved: you must do data then fin bit */ + if (th->fin && tcp_fin(sk, th, saddr, dev)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + release_sock(sk); + return(0); + + case TCP_CLOSE: + if (sk->dead || sk->daddr) { + DPRINTF((DBG_TCP, "packet received for closed,dead socket\n")); + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + if (!th->rst) { + if (!th->ack) + th->ack_seq = 0; + tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + + case TCP_LISTEN: + if (th->rst) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + if (th->ack) { + tcp_reset(daddr, saddr, th, sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + if (th->syn) { +#if 0 + if (opt->security != 0 || opt->compartment != 0) { + tcp_reset(daddr, saddr, th, prot, opt,dev); + release_sock(sk); + return(0); + } +#endif + + /* + * Now we just put the whole thing including + * the header and saddr, and protocol pointer + * into the buffer. We can't respond until the + * user tells us to accept the connection. + */ + tcp_conn_request(sk, skb, daddr, saddr, opt, dev); + release_sock(sk); + return(0); + } + + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + + default: + if (!tcp_sequence(sk, th, len, opt, saddr,dev)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + case TCP_SYN_SENT: + if (th->rst) { + sk->err = ECONNREFUSED; + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + sk->zapped = 1; + if (!sk->dead) { + sk->state_change(sk); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } +#if 0 + if (opt->security != 0 || opt->compartment != 0) { + sk->err = ECONNRESET; + sk->state = TCP_CLOSE; + sk->shutdown = SHUTDOWN_MASK; + tcp_reset(daddr, saddr, th, sk->prot, opt, dev); + if (!sk->dead) { + wake_up_interruptible(sk->sleep); + } + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } +#endif + if (!th->ack) { + if (th->syn) { + sk->state = TCP_SYN_RECV; + } + + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + switch(sk->state) { + case TCP_SYN_SENT: + if (!tcp_ack(sk, th, saddr, len)) { + tcp_reset(daddr, saddr, th, + sk->prot, opt,dev,sk->ip_tos,sk->ip_ttl); + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + /* + * If the syn bit is also set, switch to + * tcp_syn_recv, and then to established. + */ + if (!th->syn) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + /* Ack the syn and fall through. */ + sk->acked_seq = th->seq+1; + sk->fin_seq = th->seq; + tcp_send_ack(sk->send_seq, th->seq+1, + sk, th, sk->daddr); + + case TCP_SYN_RECV: + if (!tcp_ack(sk, th, saddr, len)) { + tcp_reset(daddr, saddr, th, + sk->prot, opt, dev,sk->ip_tos,sk->ip_ttl); + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + sk->state = TCP_ESTABLISHED; + + /* + * Now we need to finish filling out + * some of the tcp header. + */ + /* We need to check for mtu info. */ + tcp_options(sk, th); + sk->dummy_th.dest = th->source; + sk->copied_seq = sk->acked_seq-1; + if (!sk->dead) { + sk->state_change(sk); + } + + /* + * We've already processed his first + * ack. In just about all cases that + * will have set max_window. This is + * to protect us against the possibility + * that the initial window he sent was 0. + * This must occur after tcp_options, which + * sets sk->mtu. + */ + if (sk->max_window == 0) { + sk->max_window = 32; + sk->mss = min(sk->max_window, sk->mtu); + } + + /* + * Now process the rest like we were + * already in the established state. + */ + if (th->urg) { + if (tcp_urg(sk, th, saddr)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + } + if (tcp_data(skb, sk, saddr, len)) + kfree_skb(skb, FREE_READ); + + if (th->fin) tcp_fin(sk, th, saddr, dev); + release_sock(sk); + return(0); + } + + if (th->urg) { + if (tcp_urg(sk, th, saddr)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + } + + if (tcp_data(skb, sk, saddr, len)) { + kfree_skb(skb, FREE_READ); + release_sock(sk); + return(0); + } + + if (!th->fin) { + release_sock(sk); + return(0); + } + tcp_fin(sk, th, saddr, dev); + release_sock(sk); + return(0); + } +} + + +/* + * This routine sends a packet with an out of date sequence + * number. It assumes the other end will try to ack it. + */ +static void +tcp_write_wakeup(struct sock *sk) +{ + struct sk_buff *buff; + struct tcphdr *t1; + 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 = sk->prot->wmalloc(sk,MAX_ACK_SIZE,1, GFP_ATOMIC); + if (buff == NULL) return; + + buff->mem_addr = buff; + buff->mem_len = MAX_ACK_SIZE; + buff->len = sizeof(struct tcphdr); + buff->free = 1; + buff->sk = sk; + DPRINTF((DBG_TCP, "in tcp_write_wakeup\n")); + t1 = (struct tcphdr *) buff->data; + + /* Put in the IP header and routing stuff. */ + tmp = sk->prot->build_header(buff, sk->saddr, sk->daddr, &dev, + IPPROTO_TCP, sk->opt, MAX_ACK_SIZE,sk->ip_tos,sk->ip_ttl); + if (tmp < 0) { + sk->prot->wfree(sk, buff->mem_addr, buff->mem_len); + return; + } + + buff->len += tmp; + t1 = (struct tcphdr *)((char *)t1 +tmp); + + memcpy(t1,(void *) &sk->dummy_th, sizeof(*t1)); + + /* + * Use a previous sequence. + * This should cause the other end to send an ack. + */ + t1->seq = ntohl(sk->send_seq-1); + t1->ack = 1; + t1->res1= 0; + t1->res2= 0; + t1->rst = 0; + t1->urg = 0; + t1->psh = 0; + t1->fin = 0; + t1->syn = 0; + t1->ack_seq = ntohl(sk->acked_seq); + t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->doff = sizeof(*t1)/4; + tcp_send_check(t1, sk->saddr, sk->daddr, sizeof(*t1), sk); + + /* Send it and free it. + * This will prevent the timer from automatically being restarted. + */ + sk->prot->queue_xmit(sk, dev, buff, 1); +} + +/* + * This routine probes a zero window. It makes a copy of the first + * packet in the write queue, but with just one byte of data. + */ +void +tcp_send_probe0(struct sock *sk) +{ + unsigned char *raw; + struct iphdr *iph; + struct sk_buff *skb2, *skb; + int len, hlen, data; + struct tcphdr *t1; + struct device *dev; + + if (sk->zapped) + return; /* Afer a valid reset we can send no more */ + + if (sk -> state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT && + sk -> state != TCP_FIN_WAIT1 && sk->state != TCP_FIN_WAIT2) + return; + + skb = sk->wfront; + if (skb == NULL) + return; + + dev = skb->dev; + /* I know this can't happen but as it does.. */ + if(dev==NULL) + { + printk("tcp_send_probe0: NULL device bug!\n"); + return; + } + IS_SKB(skb); + + raw = skb->data; + iph = (struct iphdr *) (raw + dev->hard_header_len); + + hlen = (iph->ihl * sizeof(unsigned long)) + dev->hard_header_len; + data = skb->len - hlen - sizeof(struct tcphdr); + len = hlen + sizeof(struct tcphdr) + (data ? 1 : 0); + + /* Allocate buffer. */ + if ((skb2 = alloc_skb(sizeof(struct sk_buff) + len, GFP_ATOMIC)) == NULL) { +/* printk("alloc failed raw %x th %x hlen %d data %d len %d\n", + raw, skb->h.th, hlen, data, len); */ + reset_timer (sk, TIME_PROBE0, 10); /* try again real soon */ + return; + } + + skb2->arp = skb->arp; + skb2->len = len; + skb2->h.raw = (char *)(skb2->data); + + sk->wmem_alloc += skb2->mem_len; + + /* Copy the packet header into the new buffer. */ + memcpy(skb2->h.raw, raw, len); + + skb2->h.raw += hlen; /* it's now h.th -- pointer to the tcp header */ + t1 = skb2->h.th; + +/* source, dest, seq, from existing packet */ + t1->ack_seq = ntohl(sk->acked_seq); + t1->res1 = 0; +/* doff, fin, from existing packet. Fin is safe because Linux always + * sends fin in a separate packet + * syn, rst, had better be zero in original */ + t1->ack = 1; + t1->urg = 0; /* urgent pointer might be beyond this fragment */ + t1->res2 = 0; + t1->window = ntohs(tcp_select_window(sk)/*sk->prot->rspace(sk)*/); + t1->urg_ptr = 0; + tcp_send_check(t1, sk->saddr, sk->daddr, len - hlen, sk); + /* Send it and free it. + * This will prevent the timer from automatically being restarted. + */ + sk->prot->queue_xmit(sk, dev, skb2, 1); + sk->backoff++; + /* + * in the case of retransmissions, there's good reason to limit + * rto to 120 sec, as that's the maximum legal RTT on the Internet. + * For probes it could reasonably be longer. However making it + * much longer could cause unacceptable delays in some situation, + * so we might as well use the same value + */ + sk->rto = min(sk->rto << 1, 120*HZ); + reset_timer (sk, TIME_PROBE0, sk->rto); + sk->retransmits++; + sk->prot->retransmits ++; +} + +/* + * Socket option code for TCP. + */ + +int tcp_setsockopt(struct sock *sk, int level, int optname, char *optval, int optlen) +{ + int val,err; + + if(level!=SOL_TCP) + return ip_setsockopt(sk,level,optname,optval,optlen); + + if (optval == NULL) + return(-EINVAL); + + err=verify_area(VERIFY_READ, optval, sizeof(int)); + if(err) + return err; + + val = get_fs_long((unsigned long *)optval); + + switch(optname) + { + case TCP_MAXSEG: +/* if(val<200||val>2048 || val>sk->mtu) */ +/* + * values greater than interface MTU won't take effect. however at + * the point when this call is done we typically don't yet know + * which interface is going to be used + */ + if(val<1||val>MAX_WINDOW) + return -EINVAL; + sk->user_mss=val; + return 0; + case TCP_NODELAY: + sk->nonagle=(val==0)?0:1; + return 0; + default: + return(-ENOPROTOOPT); + } +} + +int tcp_getsockopt(struct sock *sk, int level, int optname, char *optval, int *optlen) +{ + int val,err; + + if(level!=SOL_TCP) + return ip_getsockopt(sk,level,optname,optval,optlen); + + switch(optname) + { + case TCP_MAXSEG: + val=sk->user_mss; + break; + case TCP_NODELAY: + val=sk->nonagle; /* Until Johannes stuff is in */ + break; + default: + return(-ENOPROTOOPT); + } + err=verify_area(VERIFY_WRITE, optlen, sizeof(int)); + if(err) + return err; + put_fs_long(sizeof(int),(unsigned long *) optlen); + + err=verify_area(VERIFY_WRITE, optval, sizeof(int)); + if(err) + return err; + put_fs_long(val,(unsigned long *)optval); + + return(0); +} + + +struct proto tcp_prot = { + sock_wmalloc, + sock_rmalloc, + sock_wfree, + sock_rfree, + sock_rspace, + sock_wspace, + tcp_close, + tcp_read, + tcp_write, + tcp_sendto, + tcp_recvfrom, + ip_build_header, + tcp_connect, + tcp_accept, + ip_queue_xmit, + tcp_retransmit, + tcp_write_wakeup, + tcp_read_wakeup, + tcp_rcv, + tcp_select, + tcp_ioctl, + NULL, + tcp_shutdown, + tcp_setsockopt, + tcp_getsockopt, + 128, + 0, + {NULL,}, + "TCP" +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.h new file mode 100644 index 000000000..007f3eee4 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/tcp.h @@ -0,0 +1,131 @@ +/* + * 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 TCP module. + * + * Version: @(#)tcp.h 1.0.5 05/23/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ +#ifndef _TCP_H +#define _TCP_H + +#include + +#define MAX_SYN_SIZE 44 + sizeof (struct sk_buff) + MAX_HEADER +#define MAX_FIN_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER +#define MAX_ACK_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER +#define MAX_RESET_SIZE 40 + sizeof (struct sk_buff) + MAX_HEADER +#define MAX_WINDOW 4096 +#define MIN_WINDOW 2048 +#define MAX_ACK_BACKLOG 2 +#define MIN_WRITE_SPACE 2048 +#define TCP_WINDOW_DIFF 2048 + +#define TCP_RETR1 7 /* + * This is howmany retries it does before it + * tries to figure out if the gateway is + * down. + */ + +#define TCP_RETR2 15 /* + * This should take at least + * 90 minutes to time out. + */ + +#define TCP_TIMEOUT_LEN (15*60*HZ) /* should be about 15 mins */ +#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to sucessfully + * close the socket, about 60 seconds */ +#define TCP_ACK_TIME 3000 /* time to delay before sending an ACK */ +#define TCP_DONE_TIME 250 /* maximum time to wait before actually + * destroying a socket */ +#define TCP_WRITE_TIME 3000 /* initial time to wait for an ACK, + * after last transmit */ +#define TCP_CONNECT_TIME 2000 /* time to retransmit first SYN */ +#define TCP_SYN_RETRIES 5 /* number of times to retry openning a + * connection */ +#define TCP_PROBEWAIT_LEN 100 /* time to wait between probes when + * I've got something to write and + * there is no window */ + +#define TCP_NO_CHECK 0 /* turn to one if you want the default + * to be no checksum */ + +#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 (automatic with unsigned arithmetic). + */ +static inline int before(unsigned long seq1, unsigned long seq2) +{ + /* this inequality is strict. */ + if (seq1 == seq2) + return 0; + seq2 -= seq1; + return (seq2 < 65536); +} + +static inline int after(unsigned long seq1, unsigned long seq2) +{ + return before(seq2, seq1); +} + + +/* is s2<=s1<=s3 ? */ +static inline int between(unsigned long seq1, unsigned long seq2, unsigned long seq3) +{ + return (after(seq1+1, seq2) && before(seq1, seq3+1)); +} + + +/* + * List all states of a TCP socket that can be viewed as a "connected" + * state. This now includes TCP_SYN_RECV, although I am not yet fully + * convinced that this is the solution for the 'getpeername(2)' + * problem. Thanks to Stephen A. Wood -FvK + */ +static inline const int +tcp_connected(const int state) +{ + return(state == TCP_ESTABLISHED || state == TCP_CLOSE_WAIT || + state == TCP_FIN_WAIT1 || state == TCP_FIN_WAIT2 || + state == TCP_SYN_RECV); +} + + +extern struct proto tcp_prot; + + +extern void print_th(struct tcphdr *); +extern void tcp_err(int err, unsigned char *header, unsigned long daddr, + unsigned long saddr, struct inet_protocol *protocol); +extern void tcp_shutdown (struct sock *sk, int how); +extern int tcp_rcv(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); + +extern int tcp_ioctl(struct sock *sk, int cmd, unsigned long arg); + +extern void tcp_enqueue_partial(struct sk_buff *, struct sock *); +extern struct sk_buff * tcp_dequeue_partial(struct sock *); + + +#endif /* _TCP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/timer.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/timer.c new file mode 100644 index 000000000..4cd451581 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/timer.c @@ -0,0 +1,237 @@ +/* + * 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. + * + * TIMER - implementation of software timers. + * + * Version: @(#)timer.c 1.0.7 05/25/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Corey Minyard + * Fred Baumgarten, + * Florian La Roche, + * + * 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 + * 2 of the License, or (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "arp.h" + +void +delete_timer (struct sock *t) +{ + unsigned long flags; + + save_flags (flags); + cli(); + + t->timeout = 0; + del_timer (&t->timer); + + restore_flags (flags); +} + +void +reset_timer (struct sock *t, int timeout, unsigned long len) +{ + delete_timer (t); + + if (timeout != -1) + t->timeout = timeout; + +#if 1 + /* FIXME: ??? */ + if ((int) len < 0) /* prevent close to infinite timers. THEY _DO_ */ + len = 3; /* happen (negative values ?) - don't ask me why ! -FB */ +#endif + t->timer.expires = len; + add_timer (&t->timer); +} + + +/* + * Now we will only be called whenever we need to do + * something, but we must be sure to process all of the + * sockets that need it. + */ +void +net_timer (unsigned long data) +{ + struct sock *sk = (struct sock*)data; + int why = sk->timeout; + /* timeout is overwritten by 'delete_timer' and 'reset_timer' */ + + if (sk->inuse || in_inet_bh()) { + sk->timer.expires = 10; + add_timer(&sk->timer); + return; + } + sk->inuse = 1; + + DPRINTF ((DBG_TMR, "net_timer: found sk=%X why = %d\n", sk, why)); + if (sk->wfront && + before(sk->window_seq, sk->wfront->h.seq) && + sk->send_head == NULL && + sk->ack_backlog == 0 && + sk->state != TCP_TIME_WAIT) + reset_timer(sk, TIME_PROBE0, sk->rto); + else if (sk->keepopen) + reset_timer (sk, TIME_KEEPOPEN, TCP_TIMEOUT_LEN); + + /* Always see if we need to send an ack. */ + if (sk->ack_backlog) { + sk->prot->read_wakeup (sk); + if (! sk->dead) + wake_up_interruptible (sk->sleep); + } + + /* Now we need to figure out why the socket was on the timer. */ + switch (why) { + case TIME_DONE: + if (! sk->dead || sk->state != TCP_CLOSE) { + printk ("non dead socket in time_done\n"); + release_sock (sk); + break; + } + destroy_sock (sk); + break; + case TIME_DESTROY: + /* We've waited for a while for all the memory associated with + * the socket to be freed. We need to print an error message. + */ + 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. */ + sk->state = TCP_CLOSE; + delete_timer (sk); + /* Kill the ARP entry in case the hardware has changed. */ + arp_destroy_maybe (sk->daddr); + if (!sk->dead) + wake_up_interruptible (sk->sleep); + sk->shutdown = SHUTDOWN_MASK; + reset_timer (sk, TIME_DESTROY, TCP_DONE_TIME); + release_sock (sk); + break; + case TIME_PROBE0: + tcp_send_probe0(sk); + release_sock (sk); + break; + case TIME_WRITE: /* try to retransmit. */ + /* It could be we got here because we needed to send an ack. + * So we need to check for that. + */ + if (sk->send_head) { + if (jiffies < (sk->send_head->when + sk->rto)) { + reset_timer (sk, TIME_WRITE, + (sk->send_head->when + sk->rto - jiffies)); + release_sock (sk); + break; + } + /* printk("timer: seq %d retrans %d out %d cong %d\n", sk->send_head->h.seq, + sk->retransmits, sk->packets_out, sk->cong_window); */ + DPRINTF ((DBG_TMR, "retransmitting.\n")); + sk->prot->retransmit (sk, 0); + if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) + || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { + DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 1\n")); + arp_destroy_maybe (sk->daddr); + ip_route_check (sk->daddr); + } + if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { + DPRINTF ((DBG_TMR, "timer.c TIME_WRITE time-out 2\n")); + sk->err = ETIMEDOUT; + if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2 + || sk->state == TCP_LAST_ACK) { + sk->state = TCP_TIME_WAIT; + reset_timer (sk, TIME_CLOSE, TCP_TIMEWAIT_LEN); + } else { + sk->prot->close (sk, 1); + break; + } + } + } + release_sock (sk); + break; + case TIME_KEEPOPEN: + /* Send something to keep the connection open. */ + if (sk->prot->write_wakeup) + sk->prot->write_wakeup (sk); + sk->retransmits++; + if (sk->shutdown == SHUTDOWN_MASK) { + sk->prot->close (sk, 1); + sk->state = TCP_CLOSE; + } + + if ((sk->state == TCP_ESTABLISHED && sk->retransmits && !(sk->retransmits & 7)) + || (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR1)) { + DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 1\n")); + arp_destroy_maybe (sk->daddr); + ip_route_check (sk->daddr); + release_sock (sk); + break; + } + if (sk->state != TCP_ESTABLISHED && sk->retransmits > TCP_RETR2) { + DPRINTF ((DBG_TMR, "timer.c TIME_KEEPOPEN time-out 2\n")); + arp_destroy_maybe (sk->daddr); + sk->err = ETIMEDOUT; + if (sk->state == TCP_FIN_WAIT1 || sk->state == TCP_FIN_WAIT2) { + sk->state = TCP_TIME_WAIT; + if (!sk->dead) + wake_up_interruptible (sk->sleep); + release_sock (sk); + } else { + sk->prot->close (sk, 1); + } + break; + } + release_sock (sk); + break; + default: + printk ("net timer expired - reason unknown, sk=%08X\n", (int)sk); + release_sock (sk); + break; + } +} + diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.c new file mode 100644 index 000000000..d9175fc3d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.c @@ -0,0 +1,646 @@ +/* + * 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. + * + * The User Datagram Protocol (UDP). + * + * Version: @(#)udp.c 1.0.13 06/02/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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. + * Alan Cox : Uses skb_free_datagram + * Alan Cox : Added get/set sockopt support. + * Alan Cox : Broadcasting without option set returns EACCES. + * Alan Cox : No wakeup calls. Instead we now use the callbacks. + * Alan Cox : Use ip_tos and ip_ttl + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "sock.h" +#include "udp.h" +#include "icmp.h" + + +#define min(a,b) ((a)<(b)?(a):(b)) + + +static void +print_udp(struct udphdr *uh) +{ + if (inet_debug != DBG_UDP) return; + + if (uh == NULL) { + printk("(NULL)\n"); + return; + } + printk("UDP: source = %d, dest = %d\n", ntohs(uh->source), ntohs(uh->dest)); + printk(" len = %d, check = %d\n", ntohs(uh->len), ntohs(uh->check)); +} + + +/* + * 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 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 +udp_err(int err, unsigned char *header, unsigned long daddr, + unsigned long saddr, struct inet_protocol *protocol) +{ + 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\ +sport=%d,dport=%d", err, header, daddr, saddr, protocol, (int)th->source,(int)th->dest)); + + sk = get_sock(&udp_prot, th->source, daddr, th->dest, saddr); + + if (sk == NULL) + return; /* No socket for error */ + + if (err < 0) /* As per the calling spec */ + { + sk->err = -err; + sk->error_report(sk); /* 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; + } + + sk->err = icmp_err_convert[err & 0xff].errno; + + /* It's only fatal if we have connected to them. */ + if (icmp_err_convert[err & 0xff].fatal && sk->state == TCP_ESTABLISHED) { + sk->err=ECONNREFUSED; + } + sk->error_report(sk); +} + + +static unsigned short +udp_check(struct udphdr *uh, int len, + unsigned long saddr, unsigned long daddr) +{ + unsigned long sum; + + DPRINTF((DBG_UDP, "UDP: check(uh=%X, len = %d, saddr = %X, daddr = %X)\n", + uh, len, saddr, daddr)); + + print_udp(uh); + + __asm__("\t addl %%ecx,%%ebx\n" + "\t adcl %%edx,%%ebx\n" + "\t adcl $0, %%ebx\n" + : "=b"(sum) + : "0"(daddr), "c"(saddr), "d"((ntohs(len) << 16) + IPPROTO_UDP*256) + : "cx","bx","dx" ); + + if (len > 3) { + __asm__("\tclc\n" + "1:\n" + "\t lodsl\n" + "\t adcl %%eax, %%ebx\n" + "\t loop 1b\n" + "\t adcl $0, %%ebx\n" + : "=b"(sum) , "=S"(uh) + : "0"(sum), "c"(len/4) ,"1"(uh) + : "ax", "cx", "bx", "si" ); + } + + /* Convert from 32 bits to 16 bits. */ + __asm__("\t movl %%ebx, %%ecx\n" + "\t shrl $16,%%ecx\n" + "\t addw %%cx, %%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum) + : "0"(sum) + : "bx", "cx"); + + /* Check for an extra word. */ + if ((len & 2) != 0) { + __asm__("\t lodsw\n" + "\t addw %%ax,%%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum), "=S"(uh) + : "0"(sum) ,"1"(uh) + : "si", "ax", "bx"); + } + + /* Now check for the extra byte. */ + if ((len & 1) != 0) { + __asm__("\t lodsb\n" + "\t movb $0,%%ah\n" + "\t addw %%ax,%%bx\n" + "\t adcw $0, %%bx\n" + : "=b"(sum) + : "0"(sum) ,"S"(uh) + : "si", "ax", "bx"); + } + + /* We only want the bottom 16 bits, but we never cleared the top 16. */ + return((~sum) & 0xffff); +} + + +static void +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; + uh->check = udp_check(uh, len, saddr, daddr); + if (uh->check == 0) uh->check = 0xffff; +} + + +static int +udp_send(struct sock *sk, struct sockaddr_in *sin, + unsigned char *from, int len) +{ + struct sk_buff *skb; + struct device *dev; + struct udphdr *uh; + unsigned char *buff; + unsigned long saddr; + int size, tmp; + int err; + + DPRINTF((DBG_UDP, "UDP: send(dst=%s:%d buff=%X len=%d)\n", + 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 = sk->prot->wmalloc(sk, size, 0, GFP_KERNEL); + if (skb == NULL) return(-ENOMEM); + + skb->mem_addr = skb; + skb->mem_len = size; + skb->sk = NULL; /* to avoid changing sk->saddr */ + skb->free = 1; + skb->arp = 0; + + /* Now build the IP and MAC header. */ + buff = skb->data; + saddr = 0; + dev = NULL; + DPRINTF((DBG_UDP, "UDP: >> IP_Header: %X -> %X dev=%X prot=%X len=%d\n", + 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,sk->ip_tos,sk->ip_ttl); + skb->sk=sk; /* So memory is freed correctly */ + + if (tmp < 0 ) { + sk->prot->wfree(sk, skb->mem_addr, skb->mem_len); + return(tmp); + } + buff += tmp; + saddr = dev->pa_addr; + DPRINTF((DBG_UDP, "UDP: >> MAC+IP len=%d\n", tmp)); + + skb->len = tmp + sizeof(struct udphdr) + len; /* len + UDP + IP + MAC */ + skb->dev = dev; +#ifdef OLD + /* + * This code used to hack in some form of fragmentation. + * I removed that, since it didn't work anyway, and it made the + * code a bad thing to read and understand. -FvK + */ + if (len > dev->mtu) { +#else + if (skb->len > 4095) + { +#endif + printk("UDP: send: length %d > mtu %d (ignored)\n", len, dev->mtu); + sk->prot->wfree(sk, skb->mem_addr, skb->mem_len); + return(-EMSGSIZE); + } + + /* Fill in the UDP header. */ + uh = (struct udphdr *) buff; + uh->len = htons(len + sizeof(struct udphdr)); + uh->source = sk->dummy_th.source; + uh->dest = sin->sin_port; + buff = (unsigned char *) (uh + 1); + + /* Copy the user data. */ + memcpy_fromfs(buff, from, len); + + /* Set up the UDP checksum. */ + udp_send_check(uh, saddr, sin->sin_addr.s_addr, skb->len - tmp, sk); + + /* Send the datagram to the interface. */ + sk->prot->queue_xmit(sk, dev, skb, 1); + + return(len); +} + + +static int +udp_sendto(struct sock *sk, unsigned char *from, int len, int noblock, + unsigned flags, struct sockaddr_in *usin, int addr_len) +{ + struct sockaddr_in sin; + int tmp; + int err; + + 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); + + /* Get and verify the address. */ + if (usin) { + if (addr_len < sizeof(sin)) return(-EINVAL); + 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); + 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 -EACCES; /* Must turn broadcast on first */ + sk->inuse = 1; + + /* Send the packet. */ + tmp = udp_send(sk, &sin, from, len); + + /* The datagram has been sent off. Release the socket. */ + release_sock(sk); + return(tmp); +} + + +static int +udp_write(struct sock *sk, unsigned char *buff, int len, int noblock, + unsigned flags) +{ + return(udp_sendto(sk, buff, len, noblock, flags, NULL, 0)); +} + + +int +udp_ioctl(struct sock *sk, int cmd, unsigned long arg) +{ + int err; + switch(cmd) { + case DDIOCSDBG: + { + int val; + + if (!suser()) return(-EPERM); + err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); + if(err) + return err; + val = get_fs_long((int *)arg); + switch(val) { + case 0: + inet_debug = 0; + break; + case 1: + inet_debug = DBG_UDP; + break; + default: + return(-EINVAL); + } + } + break; + case TIOCOUTQ: + { + unsigned long amount; + + if (sk->state == TCP_LISTEN) return(-EINVAL); + amount = sk->prot->wspace(sk)/*/2*/; + err=verify_area(VERIFY_WRITE,(void *)arg, + sizeof(unsigned long)); + if(err) + return(err); + put_fs_long(amount,(unsigned long *)arg); + return(0); + } + + case TIOCINQ: + { + struct sk_buff *skb; + unsigned long amount; + + if (sk->state == TCP_LISTEN) return(-EINVAL); + amount = 0; + skb = sk->rqueue; + if (skb != NULL) { + /* + * We will only return the amount + * of this packet since that is all + * that will be read. + */ + amount = skb->len; + } + err=verify_area(VERIFY_WRITE,(void *)arg, + sizeof(unsigned long)); + if(err) + return(err); + put_fs_long(amount,(unsigned long *)arg); + return(0); + } + + default: + return(-EINVAL); + } + return(0); +} + + +/* + * This should be easy, if there is something there we\ + * return it, otherwise we block. + */ +int +udp_recvfrom(struct sock *sk, unsigned char *to, int len, + int noblock, unsigned flags, struct sockaddr_in *sin, + int *addr_len) +{ + int copied = 0; + struct sk_buff *skb; + int er; + + + /* + * This will pick up errors that occured while the program + * was doing something else. + */ + if (sk->err) { + int err; + + err = -sk->err; + 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) + return(er); + put_fs_long(sizeof(*sin), addr_len); + } + if(sin) + { + er=verify_area(VERIFY_WRITE, sin, sizeof(*sin)); + if(er) + return(er); + } + er=verify_area(VERIFY_WRITE,to,len); + if(er) + return er; + skb=skb_recv_datagram(sk,flags,noblock,&er); + if(skb==NULL) + return er; + copied = min(len, skb->len); + + /* FIXME : should use udp header size info value */ + skb_copy_datagram(skb,sizeof(struct udphdr),to,copied); + + /* Copy the address. */ + if (sin) { + struct sockaddr_in addr; + + addr.sin_family = AF_INET; + addr.sin_port = skb->h.uh->source; + addr.sin_addr.s_addr = skb->daddr; + memcpy_tofs(sin, &addr, sizeof(*sin)); + } + + skb_free_datagram(skb); + release_sock(sk); + return(copied); +} + + +int +udp_read(struct sock *sk, unsigned char *buff, int len, int noblock, + unsigned flags) +{ + return(udp_recvfrom(sk, buff, len, noblock, flags, NULL, NULL)); +} + + +int +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); + + 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(!sk->broadcast && chk_addr(sin.sin_addr.s_addr)==IS_BROADCAST) + return -EACCES; /* Must turn broadcast on first */ + + sk->daddr = sin.sin_addr.s_addr; + sk->dummy_th.dest = sin.sin_port; + sk->state = TCP_ESTABLISHED; + return(0); +} + + +static void +udp_close(struct sock *sk, int timeout) +{ + sk->inuse = 1; + sk->state = TCP_CLOSE; + if (sk->dead) destroy_sock(sk); + else release_sock(sk); +} + + +/* All we need to do is get the socket, and then do a checksum. */ +int +udp_rcv(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) +{ + struct sock *sk; + struct udphdr *uh; + + uh = (struct udphdr *) skb->h.uh; + 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 + * to ignore the packet... -FvK + */ + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + return(0); + } + + if (uh->check && udp_check(uh, len, saddr, daddr)) { + DPRINTF((DBG_UDP, "UDP: bad checksum\n")); + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + return(0); + } + + skb->sk = sk; + skb->dev = dev; + skb->len = len; + +/* These are supposed to be switched. */ + skb->daddr = saddr; + skb->saddr = daddr; + + + /* Charge it to the socket. */ + if (sk->rmem_alloc + skb->mem_len >= sk->rcvbuf) + { + skb->sk = NULL; + kfree_skb(skb, FREE_WRITE); + release_sock(sk); + return(0); + } + sk->rmem_alloc += skb->mem_len; + + /* At this point we should print the thing out. */ + DPRINTF((DBG_UDP, "<< \n")); + print_udp(uh); + + /* Now add it to the data chain and wake things up. */ + + skb_queue_tail(&sk->rqueue,skb); + + skb->len = len - sizeof(*uh); + + if (!sk->dead) + sk->data_ready(sk,skb->len); + + release_sock(sk); + return(0); +} + + +struct proto udp_prot = { + sock_wmalloc, + sock_rmalloc, + sock_wfree, + sock_rfree, + sock_rspace, + sock_wspace, + udp_close, + udp_read, + udp_write, + udp_sendto, + udp_recvfrom, + ip_build_header, + udp_connect, + NULL, + ip_queue_xmit, + ip_retransmit, + NULL, + NULL, + udp_rcv, + datagram_select, + udp_ioctl, + NULL, + NULL, + ip_setsockopt, + ip_getsockopt, + 128, + 0, + {NULL,}, + "UDP" +}; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.h new file mode 100644 index 000000000..6bfbb3cb7 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/udp.h @@ -0,0 +1,50 @@ +/* + * 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 UDP module. + * + * Version: @(#)udp.h 1.0.2 05/07/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#ifndef _UDP_H +#define _UDP_H + +#include + + +#define UDP_NO_CHECK 0 + + +extern struct proto udp_prot; + + +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, + int len, int noblock, unsigned flags, + struct sockaddr_in *sin, int *addr_len); +extern int udp_read(struct sock *sk, unsigned char *buff, + int len, int noblock, unsigned flags); +extern int udp_connect(struct sock *sk, + struct sockaddr_in *usin, int addr_len); +extern int udp_rcv(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); +extern int udp_ioctl(struct sock *sk, int cmd, unsigned long arg); + + +#endif /* _UDP_H */ diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/utils.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/utils.c new file mode 100644 index 000000000..f9e81e3dc --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/inet/utils.c @@ -0,0 +1,147 @@ +/* + * 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. + * + * Various kernel-resident INET utility functions; mainly + * for format conversion and debugging output. + * + * Version: @(#)utils.c 1.0.7 05/18/93 + * + * Author: Fred N. van Kempen, + * + * 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 + * 2 of the License, or (at your option) any later version. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "inet.h" +#include "dev.h" +#include "eth.h" +#include "ip.h" +#include "protocol.h" +#include "tcp.h" +#include "skbuff.h" +#include "arp.h" + + +/* Display an IP address in readable format. */ +char *in_ntoa(unsigned long in) +{ + static char buff[18]; + register char *p; + + p = (char *) ∈ + sprintf(buff, "%d.%d.%d.%d", + (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255)); + return(buff); +} + + +/* Convert an ASCII string to binary IP. */ +unsigned long +in_aton(char *str) +{ + unsigned long l; + unsigned int val; + int i; + + l = 0; + for (i = 0; i < 4; i++) { + l <<= 8; + if (*str != '\0') { + val = 0; + while (*str != '\0' && *str != '.') { + val *= 10; + val += *str - '0'; + str++; + } + l |= val; + if (*str != '\0') str++; + } + } + return(htonl(l)); +} + + +void +dprintf(int level, char *fmt, ...) +{ + va_list args; + char *buff; + extern int vsprintf(char * buf, const char * fmt, va_list args); + + if (level != inet_debug) return; + + buff = (char *) kmalloc(256, GFP_ATOMIC); + if (buff != NULL) { + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + printk(buff); + kfree(buff); + } +} + + +int +dbg_ioctl(void *arg, int level) +{ + int val; + int err; + + if (!suser()) return(-EPERM); + err=verify_area(VERIFY_READ, (void *)arg, sizeof(int)); + if(err) + return err; + val = get_fs_long((int *)arg); + switch(val) { + case 0: /* OFF */ + inet_debug = DBG_OFF; + break; + case 1: /* ON, INET */ + inet_debug = level; + break; + + case DBG_RT: /* modules */ + case DBG_DEV: + case DBG_ETH: + case DBG_PROTO: + case DBG_TMR: + case DBG_PKT: + case DBG_RAW: + + case DBG_LOOPB: /* drivers */ + case DBG_SLIP: + + case DBG_ARP: /* protocols */ + case DBG_IP: + case DBG_ICMP: + case DBG_TCP: + case DBG_UDP: + + inet_debug = val; + break; + + default: + return(-EINVAL); + } + + return(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/socket.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/socket.c new file mode 100644 index 000000000..805e7c6ec --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/socket.c @@ -0,0 +1,1094 @@ +/* + * NET An implementation of the SOCKET network access protocol. + * + * Version: @(#)socket.c 1.0.5 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * Fixes: + * Anonymous : NOTSOCK/BADF cleanup. Error fix in + * shutdown() + * Alan Cox : verify_area() fixes + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#undef SOCK_DEBUG + +#ifdef SOCK_DEBUG +#include +#define DPRINTF(x) dprintf x +#else +#define DPRINTF(x) /**/ +#endif + +static int sock_lseek(struct inode *inode, struct file *file, off_t offset, + int whence); +static int sock_read(struct inode *inode, struct file *file, char *buf, + int size); +static int sock_write(struct inode *inode, struct file *file, char *buf, + int size); +static int sock_readdir(struct inode *inode, struct file *file, + struct dirent *dirent, int count); +static void sock_close(struct inode *inode, struct file *file); +static int sock_select(struct inode *inode, struct file *file, int which, select_table *seltable); +static int sock_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg); + + +static struct file_operations socket_file_ops = { + sock_lseek, + sock_read, + sock_write, + sock_readdir, + sock_select, + sock_ioctl, + NULL, /* mmap */ + NULL, /* no special open code... */ + sock_close +}; + +static struct socket sockets[NSOCKETS]; +static struct wait_queue *socket_wait_free = NULL; +static struct proto_ops *pops[NPROTO]; +static int net_debug = 0; + +#define last_socket (sockets + NSOCKETS - 1) + +#ifdef SOCK_DEBUG +/* Module debugging. */ +static void +dprintf(int level, char *fmt, ...) +{ + char buff[1024]; + va_list args; + extern int vsprintf(char * buf, const char * fmt, va_list args); + + if (level == 0) return; + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + printk(buff); +} +#endif + +/* Obtains the first available file descriptor and sets it up for use. */ +static int +get_fd(struct inode *inode) +{ + int fd; + struct file *file; + + /* Find a file descriptor suitable for return to the user. */ + file = get_empty_filp(); + if (!file) return(-1); + for (fd = 0; fd < NR_OPEN; ++fd) + if (!current->filp[fd]) break; + if (fd == NR_OPEN) { + file->f_count = 0; + return(-1); + } + FD_CLR(fd, ¤t->close_on_exec); + current->filp[fd] = file; + file->f_op = &socket_file_ops; + file->f_mode = 3; + file->f_flags = 0; + file->f_count = 1; + file->f_inode = inode; + if (inode) inode->i_count++; + file->f_pos = 0; + return(fd); +} + + +/* + * Reverses the action of get_fd() by releasing the file. it closes + * the descriptor, but makes sure it does nothing more. Called when + * an incomplete socket must be closed, along with sock_release(). + */ +static inline void +toss_fd(int fd) +{ + sys_close(fd); /* the count protects us from iput */ +} + + +struct socket * +socki_lookup(struct inode *inode) +{ + struct socket *sock; + + if ((sock = inode->i_socket) != NULL) { + if (sock->state != SS_FREE && SOCK_INODE(sock) == inode) + return sock; + printk("socket.c: uhhuh. stale inode->i_socket pointer\n"); + } + for (sock = sockets; sock <= last_socket; ++sock) + if (sock->state != SS_FREE && SOCK_INODE(sock) == inode) { + printk("socket.c: uhhuh. Found socket despite no inode->i_socket pointer\n"); + return(sock); + } + return(NULL); +} + + +static inline struct socket * +sockfd_lookup(int fd, struct file **pfile) +{ + struct file *file; + + if (fd < 0 || fd >= NR_OPEN || !(file = current->filp[fd])) return(NULL); + if (pfile) *pfile = file; + return(socki_lookup(file->f_inode)); +} + + +static struct socket * +sock_alloc(int wait) +{ + struct socket *sock; + + while (1) { + cli(); + for (sock = sockets; sock <= last_socket; ++sock) { + if (sock->state == SS_FREE) { + sock->state = SS_UNCONNECTED; + sti(); + sock->flags = 0; + sock->ops = NULL; + sock->data = NULL; + sock->conn = NULL; + sock->iconn = NULL; + + /* + * This really shouldn't be necessary, but everything + * else depends on inodes, so we grab it. + * Sleeps are also done on the i_wait member of this + * inode. The close system call will iput this inode + * for us. + */ + if (!(SOCK_INODE(sock) = get_empty_inode())) { + printk("NET: sock_alloc: no more inodes\n"); + sock->state = SS_FREE; + return(NULL); + } + SOCK_INODE(sock)->i_mode = S_IFSOCK; + SOCK_INODE(sock)->i_uid = current->euid; + SOCK_INODE(sock)->i_gid = current->egid; + SOCK_INODE(sock)->i_socket = sock; + + sock->wait = &SOCK_INODE(sock)->i_wait; + DPRINTF((net_debug, + "NET: sock_alloc: sk 0x%x, ino 0x%x\n", + sock, SOCK_INODE(sock))); + return(sock); + } + } + sti(); + if (!wait) return(NULL); + DPRINTF((net_debug, "NET: sock_alloc: no free sockets, sleeping...\n")); + interruptible_sleep_on(&socket_wait_free); + if (current->signal & ~current->blocked) { + DPRINTF((net_debug, "NET: sock_alloc: sleep was interrupted\n")); + return(NULL); + } + DPRINTF((net_debug, "NET: sock_alloc: wakeup... trying again...\n")); + } +} + + +static inline void +sock_release_peer(struct socket *peer) +{ + peer->state = SS_DISCONNECTING; + wake_up_interruptible(peer->wait); +} + + +static void +sock_release(struct socket *sock) +{ + int oldstate; + struct inode *inode; + struct socket *peersock, *nextsock; + + DPRINTF((net_debug, "NET: sock_release: socket 0x%x, inode 0x%x\n", + sock, SOCK_INODE(sock))); + if ((oldstate = sock->state) != SS_UNCONNECTED) + sock->state = SS_DISCONNECTING; + + /* Wake up anyone waiting for connections. */ + for (peersock = sock->iconn; peersock; peersock = nextsock) { + nextsock = peersock->next; + sock_release_peer(peersock); + } + + /* + * Wake up anyone we're connected to. First, we release the + * protocol, to give it a chance to flush data, etc. + */ + peersock = (oldstate == SS_CONNECTED) ? sock->conn : NULL; + if (sock->ops) sock->ops->release(sock, peersock); + if (peersock) sock_release_peer(peersock); + inode = SOCK_INODE(sock); + sock->state = SS_FREE; /* this really releases us */ + wake_up_interruptible(&socket_wait_free); + + /* We need to do this. If sock alloc was called we already have an inode. */ + iput(inode); +} + + +static int +sock_lseek(struct inode *inode, struct file *file, off_t offset, int whence) +{ + DPRINTF((net_debug, "NET: sock_lseek: huh?\n")); + return(-ESPIPE); +} + + +static int +sock_read(struct inode *inode, struct file *file, char *ubuf, int size) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_read: buf=0x%x, size=%d\n", ubuf, size)); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_read: can't find socket for inode!\n"); + return(-EBADF); + } + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + return(sock->ops->read(sock, ubuf, size, (file->f_flags & O_NONBLOCK))); +} + + +static int +sock_write(struct inode *inode, struct file *file, char *ubuf, int size) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_write: buf=0x%x, size=%d\n", ubuf, size)); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_write: can't find socket for inode!\n"); + return(-EBADF); + } + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + return(sock->ops->write(sock, ubuf, size,(file->f_flags & O_NONBLOCK))); +} + + +static int +sock_readdir(struct inode *inode, struct file *file, struct dirent *dirent, + int count) +{ + DPRINTF((net_debug, "NET: sock_readdir: huh?\n")); + return(-EBADF); +} + + +int +sock_ioctl(struct inode *inode, struct file *file, unsigned int cmd, + unsigned long arg) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_ioctl: inode=0x%x cmd=0x%x arg=%d\n", + inode, cmd, arg)); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_ioctl: can't find socket for inode!\n"); + return(-EBADF); + } + return(sock->ops->ioctl(sock, cmd, arg)); +} + + +static int +sock_select(struct inode *inode, struct file *file, int sel_type, select_table * wait) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_select: inode = 0x%x, kind = %s\n", inode, + (sel_type == SEL_IN) ? "in" : + (sel_type == SEL_OUT) ? "out" : "ex")); + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_select: can't find socket for inode!\n"); + return(0); + } + + /* We can't return errors to select, so its either yes or no. */ + if (sock->ops && sock->ops->select) + return(sock->ops->select(sock, sel_type, wait)); + return(0); +} + + +void +sock_close(struct inode *inode, struct file *file) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_close: inode=0x%x (cnt=%d)\n", + inode, inode->i_count)); + + /* It's possible the inode is NULL if we're closing an unfinished socket. */ + if (!inode) return; + if (!(sock = socki_lookup(inode))) { + printk("NET: sock_close: can't find socket for inode!\n"); + return; + } + sock_release(sock); +} + + +int +sock_awaitconn(struct socket *mysock, struct socket *servsock) +{ + struct socket *last; + + DPRINTF((net_debug, + "NET: sock_awaitconn: trying to connect socket 0x%x to 0x%x\n", + mysock, servsock)); + if (!(servsock->flags & SO_ACCEPTCON)) { + DPRINTF((net_debug, + "NET: sock_awaitconn: server not accepting connections\n")); + return(-EINVAL); + } + + /* Put ourselves on the server's incomplete connection queue. */ + mysock->next = NULL; + cli(); + if (!(last = servsock->iconn)) servsock->iconn = mysock; + else { + while (last->next) last = last->next; + last->next = mysock; + } + mysock->state = SS_CONNECTING; + mysock->conn = servsock; + sti(); + + /* + * Wake up server, then await connection. server will set state to + * SS_CONNECTED if we're connected. + */ + wake_up_interruptible(servsock->wait); + if (mysock->state != SS_CONNECTED) { + interruptible_sleep_on(mysock->wait); + if (mysock->state != SS_CONNECTED && + mysock->state != SS_DISCONNECTING) { + /* + * if we're not connected we could have been + * 1) interrupted, so we need to remove ourselves + * from the server list + * 2) rejected (mysock->conn == NULL), and have + * already been removed from the list + */ + if (mysock->conn == servsock) { + cli(); + if ((last = servsock->iconn) == mysock) + servsock->iconn = mysock->next; + else { + while (last->next != mysock) last = last->next; + last->next = mysock->next; + } + sti(); + } + return(mysock->conn ? -EINTR : -EACCES); + } + } + return(0); +} + + +/* + * Perform the socket system call. we locate the appropriate + * family, then create a fresh socket. + */ +static int +sock_socket(int family, int type, int protocol) +{ + int i, fd; + struct socket *sock; + struct proto_ops *ops; + + DPRINTF((net_debug, + "NET: sock_socket: family = %d, type = %d, protocol = %d\n", + family, type, protocol)); + + /* Locate the correct protocol family. */ + for (i = 0; i < NPROTO; ++i) { + if (pops[i] == NULL) continue; + if (pops[i]->family == family) break; + } + if (i == NPROTO) { + DPRINTF((net_debug, "NET: sock_socket: family not found\n")); + return(-EINVAL); + } + ops = pops[i]; + + /* + * Check that this is a type that we know how to manipulate and + * the protocol makes sense here. The family can still reject the + * protocol later. + */ + if ((type != SOCK_STREAM && type != SOCK_DGRAM && + type != SOCK_SEQPACKET && type != SOCK_RAW && + type != SOCK_PACKET) || protocol < 0) + return(-EINVAL); + + /* + * allocate the socket and allow the family to set things up. if + * the protocol is 0, the family is instructed to select an appropriate + * default. + */ + if (!(sock = sock_alloc(1))) { + printk("sock_socket: no more sockets\n"); + return(-EAGAIN); + } + sock->type = type; + sock->ops = ops; + if ((i = sock->ops->create(sock, protocol)) < 0) { + sock_release(sock); + return(i); + } + + if ((fd = get_fd(SOCK_INODE(sock))) < 0) { + sock_release(sock); + return(-EINVAL); + } + + return(fd); +} + + +static int +sock_socketpair(int family, int type, int protocol, unsigned long usockvec[2]) +{ + int fd1, fd2, i; + struct socket *sock1, *sock2; + int er; + + DPRINTF((net_debug, + "NET: sock_socketpair: family = %d, type = %d, protocol = %d\n", + family, type, protocol)); + + /* + * Obtain the first socket and check if the underlying protocol + * supports the socketpair call. + */ + if ((fd1 = sock_socket(family, type, protocol)) < 0) return(fd1); + sock1 = sockfd_lookup(fd1, NULL); + if (!sock1->ops->socketpair) { + sys_close(fd1); + return(-EINVAL); + } + + /* Now grab another socket and try to connect the two together. */ + if ((fd2 = sock_socket(family, type, protocol)) < 0) { + sys_close(fd1); + return(-EINVAL); + } + sock2 = sockfd_lookup(fd2, NULL); + if ((i = sock1->ops->socketpair(sock1, sock2)) < 0) { + sys_close(fd1); + sys_close(fd2); + return(i); + } + sock1->conn = sock2; + sock2->conn = sock1; + sock1->state = SS_CONNECTED; + sock2->state = SS_CONNECTED; + + er=verify_area(VERIFY_WRITE, usockvec, 2 * sizeof(int)); + if(er) + return er; + put_fs_long(fd1, &usockvec[0]); + put_fs_long(fd2, &usockvec[1]); + + return(0); +} + + +/* + * Bind a name to a socket. Nothing much to do here since its + * the protocol's responsibility to handle the local address. + */ +static int +sock_bind(int fd, struct sockaddr *umyaddr, int addrlen) +{ + struct socket *sock; + int i; + + DPRINTF((net_debug, "NET: sock_bind: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + if ((i = sock->ops->bind(sock, umyaddr, addrlen)) < 0) { + DPRINTF((net_debug, "NET: sock_bind: bind failed\n")); + return(i); + } + return(0); +} + + +/* + * Perform a listen. Basically, we allow the protocol to do anything + * necessary for a listen, and if that works, we mark the socket as + * ready for listening. + */ +static int +sock_listen(int fd, int backlog) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_listen: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + if (sock->state != SS_UNCONNECTED) { + DPRINTF((net_debug, "NET: sock_listen: socket isn't unconnected\n")); + return(-EINVAL); + } + if (sock->ops && sock->ops->listen) sock->ops->listen(sock, backlog); + sock->flags |= SO_ACCEPTCON; + return(0); +} + + +/* + * For accept, we attempt to create a new socket, set up the link + * with the client, wake up the client, then return the new + * connected fd. + */ +static int +sock_accept(int fd, struct sockaddr *upeer_sockaddr, int *upeer_addrlen) +{ + struct file *file; + struct socket *sock, *newsock; + int i; + + DPRINTF((net_debug, "NET: sock_accept: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + + if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK); + if (sock->state != SS_UNCONNECTED) { + DPRINTF((net_debug, "NET: sock_accept: socket isn't unconnected\n")); + return(-EINVAL); + } + if (!(sock->flags & SO_ACCEPTCON)) { + DPRINTF((net_debug, + "NET: sock_accept: socket not accepting connections!\n")); + return(-EINVAL); + } + + if (!(newsock = sock_alloc(0))) { + printk("NET: sock_accept: no more sockets\n"); + return(-EAGAIN); + } + newsock->type = sock->type; + newsock->ops = sock->ops; + if ((i = sock->ops->dup(newsock, sock)) < 0) { + sock_release(newsock); + return(i); + } + + i = newsock->ops->accept(sock, newsock, file->f_flags); + if ( i < 0) { + sock_release(newsock); + return(i); + } + + if ((fd = get_fd(SOCK_INODE(newsock))) < 0) { + sock_release(newsock); + return(-EINVAL); + } + + DPRINTF((net_debug, "NET: sock_accept: connected socket 0x%x via 0x%x\n", + sock, newsock)); + + if (upeer_sockaddr) + newsock->ops->getname(newsock, upeer_sockaddr, upeer_addrlen, 1); + + return(fd); +} + + +/* Attempt to connect to a socket with the server address. */ +static int +sock_connect(int fd, struct sockaddr *uservaddr, int addrlen) +{ + struct socket *sock; + struct file *file; + int i; + + DPRINTF((net_debug, "NET: sock_connect: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || (file=current->filp[fd]) == NULL) + return(-EBADF); + + if (!(sock = sockfd_lookup(fd, &file))) return(-ENOTSOCK); + switch(sock->state) { + case SS_UNCONNECTED: + /* This is ok... continue with connect */ + break; + case SS_CONNECTED: + /* Socket is already connected */ + return -EISCONN; + case SS_CONNECTING: + /* Not yet connected... we will check this. */ + return(sock->ops->connect(sock, uservaddr, + addrlen, file->f_flags)); + default: + DPRINTF((net_debug, + "NET: sock_connect: socket not unconnected\n")); + return(-EINVAL); + } + i = sock->ops->connect(sock, uservaddr, addrlen, file->f_flags); + if (i < 0) { + DPRINTF((net_debug, "NET: sock_connect: connect failed\n")); + return(i); + } + return(0); +} + + +static int +sock_getsockname(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_getsockname: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + return(sock->ops->getname(sock, usockaddr, usockaddr_len, 0)); +} + + +static int +sock_getpeername(int fd, struct sockaddr *usockaddr, int *usockaddr_len) +{ + struct socket *sock; + + DPRINTF((net_debug, "NET: sock_getpeername: fd = %d\n", fd)); + if (fd < 0 || fd >= NR_OPEN || current->filp[fd] == NULL) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + return(sock->ops->getname(sock, usockaddr, usockaddr_len, 1)); +} + + +static int +sock_send(int fd, void * buff, int len, unsigned flags) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_send(fd = %d, buff = %X, len = %d, flags = %X)\n", + fd, buff, len, flags)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->send(sock, buff, len, (file->f_flags & O_NONBLOCK), flags)); +} + + +static int +sock_sendto(int fd, void * buff, int len, unsigned flags, + struct sockaddr *addr, int addr_len) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_sendto(fd = %d, buff = %X, len = %d, flags = %X," + " addr=%X, alen = %d\n", fd, buff, len, flags, addr, addr_len)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->sendto(sock, buff, len, (file->f_flags & O_NONBLOCK), + flags, addr, addr_len)); +} + + +static int +sock_recv(int fd, void * buff, int len, unsigned flags) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_recv(fd = %d, buff = %X, len = %d, flags = %X)\n", + fd, buff, len, flags)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->recv(sock, buff, len,(file->f_flags & O_NONBLOCK), flags)); +} + + +static int +sock_recvfrom(int fd, void * buff, int len, unsigned flags, + struct sockaddr *addr, int *addr_len) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, + "NET: sock_recvfrom(fd = %d, buff = %X, len = %d, flags = %X," + " addr=%X, alen=%X\n", fd, buff, len, flags, addr, addr_len)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->recvfrom(sock, buff, len, (file->f_flags & O_NONBLOCK), + flags, addr, addr_len)); +} + + +static int +sock_setsockopt(int fd, int level, int optname, char *optval, int optlen) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, "NET: sock_setsockopt(fd=%d, level=%d, optname=%d,\n", + fd, level, optname)); + DPRINTF((net_debug, " optval = %X, optlen = %d)\n", + optval, optlen)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->setsockopt(sock, level, optname, optval, optlen)); +} + + +static int +sock_getsockopt(int fd, int level, int optname, char *optval, int *optlen) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, "NET: sock_getsockopt(fd=%d, level=%d, optname=%d,\n", + fd, level, optname)); + DPRINTF((net_debug, " optval = %X, optlen = %X)\n", + optval, optlen)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + if (!sock->ops || !sock->ops->getsockopt) return(0); + return(sock->ops->getsockopt(sock, level, optname, optval, optlen)); +} + + +static int +sock_shutdown(int fd, int how) +{ + struct socket *sock; + struct file *file; + + DPRINTF((net_debug, "NET: sock_shutdown(fd = %d, how = %d)\n", fd, how)); + + if (fd < 0 || fd >= NR_OPEN || ((file = current->filp[fd]) == NULL)) + return(-EBADF); + + if (!(sock = sockfd_lookup(fd, NULL))) return(-ENOTSOCK); + + return(sock->ops->shutdown(sock, how)); +} + + +int +sock_fcntl(struct file *filp, unsigned int cmd, unsigned long arg) +{ + struct socket *sock; + + sock = socki_lookup (filp->f_inode); + if (sock != NULL && sock->ops != NULL && sock->ops->fcntl != NULL) + return(sock->ops->fcntl(sock, cmd, arg)); + return(-EINVAL); +} + + +/* + * System call vectors. Since I (RIB) want to rewrite sockets as streams, + * we have this level of indirection. Not a lot of overhead, since more of + * the work is done via read/write/select directly. + */ +asmlinkage int +sys_socketcall(int call, unsigned long *args) +{ + int er; + switch(call) { + case SYS_SOCKET: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_socket(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2))); + case SYS_BIND: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_bind(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + get_fs_long(args+2))); + case SYS_CONNECT: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_connect(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + get_fs_long(args+2))); + case SYS_LISTEN: + er=verify_area(VERIFY_READ, args, 2 * sizeof(long)); + if(er) + return er; + return(sock_listen(get_fs_long(args+0), + get_fs_long(args+1))); + case SYS_ACCEPT: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_accept(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + (int *)get_fs_long(args+2))); + case SYS_GETSOCKNAME: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_getsockname(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + (int *)get_fs_long(args+2))); + case SYS_GETPEERNAME: + er=verify_area(VERIFY_READ, args, 3 * sizeof(long)); + if(er) + return er; + return(sock_getpeername(get_fs_long(args+0), + (struct sockaddr *)get_fs_long(args+1), + (int *)get_fs_long(args+2))); + case SYS_SOCKETPAIR: + er=verify_area(VERIFY_READ, args, 4 * sizeof(long)); + if(er) + return er; + return(sock_socketpair(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2), + (unsigned long *)get_fs_long(args+3))); + case SYS_SEND: + er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); + if(er) + return er; + return(sock_send(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3))); + case SYS_SENDTO: + er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); + if(er) + return er; + return(sock_sendto(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3), + (struct sockaddr *)get_fs_long(args+4), + get_fs_long(args+5))); + case SYS_RECV: + er=verify_area(VERIFY_READ, args, 4 * sizeof(unsigned long)); + if(er) + return er; + return(sock_recv(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3))); + case SYS_RECVFROM: + er=verify_area(VERIFY_READ, args, 6 * sizeof(unsigned long)); + if(er) + return er; + return(sock_recvfrom(get_fs_long(args+0), + (void *)get_fs_long(args+1), + get_fs_long(args+2), + get_fs_long(args+3), + (struct sockaddr *)get_fs_long(args+4), + (int *)get_fs_long(args+5))); + case SYS_SHUTDOWN: + er=verify_area(VERIFY_READ, args, 2* sizeof(unsigned long)); + if(er) + return er; + return(sock_shutdown(get_fs_long(args+0), + get_fs_long(args+1))); + case SYS_SETSOCKOPT: + er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); + if(er) + return er; + return(sock_setsockopt(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2), + (char *)get_fs_long(args+3), + get_fs_long(args+4))); + case SYS_GETSOCKOPT: + er=verify_area(VERIFY_READ, args, 5*sizeof(unsigned long)); + if(er) + return er; + return(sock_getsockopt(get_fs_long(args+0), + get_fs_long(args+1), + get_fs_long(args+2), + (char *)get_fs_long(args+3), + (int *)get_fs_long(args+4))); + default: + return(-EINVAL); + } +} + + +static int +net_ioctl(unsigned int cmd, unsigned long arg) +{ + int er; + switch(cmd) { + case DDIOCSDBG: + er=verify_area(VERIFY_READ, (void *)arg, sizeof(long)); + if(er) + return er; + net_debug = get_fs_long((long *)arg); + if (net_debug != 0 && net_debug != 1) { + net_debug = 0; + return(-EINVAL); + } + return(0); + default: + return(-EINVAL); + } + /*NOTREACHED*/ + return(0); +} + + +/* + * Handle the IOCTL system call for the NET devices. This basically + * means I/O control for the SOCKET layer (future expansions could be + * a variable number of socket table entries, et al), and for the more + * general protocols like ARP. The latter currently lives in the INET + * module, so we have to get ugly a tiny little bit. Later... -FvK + */ +static int +net_fioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + extern int arp_ioctl(unsigned int, void *); + + /* Dispatch on the minor device. */ + switch(MINOR(inode->i_rdev)) { + case 0: /* NET (SOCKET) */ + DPRINTF((net_debug, "NET: SOCKET level I/O control request.\n")); + return(net_ioctl(cmd, arg)); +#ifdef CONFIG_INET + case 1: /* ARP */ + DPRINTF((net_debug, "NET: ARP level I/O control request.\n")); + return(arp_ioctl(cmd, (void *) arg)); +#endif + default: + return(-ENODEV); + } + /*NOTREACHED*/ + return(-EINVAL); +} + + +static struct file_operations net_fops = { + NULL, /* LSEEK */ + NULL, /* READ */ + NULL, /* WRITE */ + NULL, /* READDIR */ + NULL, /* SELECT */ + net_fioctl, /* IOCTL */ + NULL, /* MMAP */ + NULL, /* OPEN */ + NULL /* CLOSE */ +}; + + +/* + * This function is called by a protocol handler that wants to + * advertise its address family, and have it linked into the + * SOCKET module. + */ +int +sock_register(int family, struct proto_ops *ops) +{ + int i; + + cli(); + for(i = 0; i < NPROTO; i++) { + if (pops[i] != NULL) continue; + pops[i] = ops; + pops[i]->family = family; + sti(); + DPRINTF((net_debug, "NET: Installed protocol %d in slot %d (0x%X)\n", + family, i, (long)ops)); + return(i); + } + sti(); + return(-ENOMEM); +} + + +void +sock_init(void) +{ + struct socket *sock; + int i; + + /* Set up our SOCKET VFS major device. */ + if (register_chrdev(SOCKET_MAJOR, "socket", &net_fops) < 0) { + printk("NET: cannot register major device %d!\n", SOCKET_MAJOR); + return; + } + + /* Release all sockets. */ + for (sock = sockets; sock <= last_socket; ++sock) sock->state = SS_FREE; + + /* Initialize all address (protocol) families. */ + for (i = 0; i < NPROTO; ++i) pops[i] = NULL; + + /* Initialize the DDI module. */ + ddi_init(); + + /* Initialize the ARP module. */ +#if 0 + arp_init(); +#endif +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/Makefile new file mode 100644 index 000000000..ceb8aadda --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/Makefile @@ -0,0 +1,35 @@ +# +# Makefile for the UNIX Protocol Family. +# +# Note! Dependencies are done automagically by 'make dep', which also +# removes any old dependencies. DON'T put your own dependencies here +# unless it's something special (ie not a .c file). +# +# Note 2! The CFLAGS definition is now in the main makefile... + +.c.o: + $(CC) $(CFLAGS) \ + -c -o $*.o $< +.s.o: + $(AS) -o $*.o $< +.c.s: + $(CC) $(CFLAGS) \ + -S -o $*.s $< + +OBJS = sock.o proc.o + +unix.o: $(OBJS) + $(LD) -r -o unix.o $(OBJS) + +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/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/proc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/proc.c new file mode 100644 index 000000000..8a80ad55b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/proc.c @@ -0,0 +1,77 @@ +/* + * UNIX An implementation of the AF_UNIX network domain for the + * LINUX operating system. UNIX is implemented using the + * BSD Socket interface as the means of communication with + * the user level. + * + * The functions in this file provide an interface between + * the PROC file system and the "unix" family of networking + * protocols. It is mainly used for debugging and statistics. + * + * Version: @(#)proc.c 1.0.4 05/23/93 + * + * Authors: Ross Biro, + * Fred N. van Kempen, + * Gerald J. Heim, + * Fred Baumgarten, + * + * Fixes: + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include "unix.h" + + +/* Called from PROCfs. */ +int unix_get_info(char *buffer) +{ + char *pos; + int i; + + pos = buffer; + pos += sprintf(pos, "Num RefCount Protocol Flags Type St Path\n"); + + for(i = 0; i < NSOCKETS; i++) { + if (unix_datas[i].refcnt) { + pos += sprintf(pos, "%2d: %08X %08X %08lX %04X %02X", i, + unix_datas[i].refcnt, + unix_datas[i].protocol, + unix_datas[i].socket->flags, + unix_datas[i].socket->type, + unix_datas[i].socket->state + ); + + /* If socket is bound to a filename, we'll print it. */ + if(unix_datas[i].sockaddr_len>0) { + pos += sprintf(pos, " %s\n", + unix_datas[i].sockaddr_un.sun_path); + } else { /* just add a newline */ + *pos='\n'; + pos++; + *pos='\0'; + } + + /* + * Check whether buffer _may_ overflow in the next loop. + * Since sockets may have very very long paths, we make + * PATH_MAX+80 the minimum space left for a new line. + */ + if (pos > buffer+PAGE_SIZE-80-PATH_MAX) { + printk("UNIX: netinfo: oops, too many sockets.\n"); + return(pos - buffer); + } + } + } + return(pos - buffer); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/sock.c b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/sock.c new file mode 100644 index 000000000..6ab4e835d --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/sock.c @@ -0,0 +1,944 @@ +/* + * UNIX An implementation of the AF_UNIX network domain for the + * LINUX operating system. UNIX is implemented using the + * BSD Socket interface as the means of communication with + * the user level. + * + * Version: @(#)sock.c 1.0.5 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * Fixes: + * Alan Cox : Verify Area + * NET2E Team : Page fault locks + * + * To Do: + * + * Change to the NET2E3 code for Unix domain sockets in general. The + * read/write logic is much better and cleaner. + * + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include "unix.h" + +struct unix_proto_data unix_datas[NSOCKETS]; +static int unix_debug = 0; + + +static int unix_proto_create(struct socket *sock, int protocol); +static int unix_proto_dup(struct socket *newsock, struct socket *oldsock); +static int unix_proto_release(struct socket *sock, struct socket *peer); +static int unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, + int sockaddr_len); +static int unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags); +static int unix_proto_socketpair(struct socket *sock1, struct socket *sock2); +static int unix_proto_accept(struct socket *sock, struct socket *newsock, + int flags); +static int unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, + int *usockaddr_len, int peer); +static int unix_proto_read(struct socket *sock, char *ubuf, int size, + int nonblock); +static int unix_proto_write(struct socket *sock, char *ubuf, int size, + int nonblock); +static int unix_proto_select(struct socket *sock, int sel_type, select_table * wait); +static int unix_proto_ioctl(struct socket *sock, unsigned int cmd, + unsigned long arg); +static int unix_proto_listen(struct socket *sock, int backlog); +static int unix_proto_send(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags); +static int unix_proto_recv(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags); +static int unix_proto_sendto(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags, + struct sockaddr *addr, int addr_len); +static int unix_proto_recvfrom(struct socket *sock, void *buff, int len, + int nonblock, unsigned flags, + struct sockaddr *addr, int *addr_len); + +static int unix_proto_shutdown(struct socket *sock, int how); + +static int unix_proto_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen); +static int unix_proto_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen); + + +static void +dprintf(int level, char *fmt, ...) +{ + va_list args; + char *buff; + extern int vsprintf(char * buf, const char * fmt, va_list args); + + if (level != unix_debug) return; + + buff = (char *) kmalloc(256, GFP_KERNEL); + if (buff != NULL) { + va_start(args, fmt); + vsprintf(buff, fmt, args); + va_end(args); + printk(buff); + kfree(buff); + } +} + + +static inline int +min(int a, int b) +{ + if (a < b) return(a); + return(b); +} + + +void +sockaddr_un_printk(struct sockaddr_un *sockun, int sockaddr_len) +{ + char buf[sizeof(sockun->sun_path) + 1]; + + if (unix_debug == 0) return; + + sockaddr_len -= UN_PATH_OFFSET; + if (sockun->sun_family != AF_UNIX) + printk("UNIX: Badd addr family %d>\n", sockun->sun_family); + else if (sockaddr_len <= 0 || sockaddr_len >= sizeof(buf)) + printk("UNIX: Bad addr len %d>\n", sockaddr_len); + else { + memcpy(buf, sockun->sun_path, sockaddr_len); + buf[sockaddr_len] = '\0'; + printk("\"%s\"[%lu]\n", buf, sockaddr_len + UN_PATH_OFFSET); + } +} + + +/* Support routines doing anti page fault locking + * FvK & Matt Dillon (borrowed From NET2E3) + */ + +/* + * Locking for unix-domain sockets. We don't use the socket structure's + * wait queue because it is allowed to 'go away' outside of our control, + * whereas unix_proto_data structures stick around. + */ +void unix_lock(struct unix_proto_data *upd) +{ + while (upd->lock_flag) + sleep_on(&upd->wait); + upd->lock_flag = 1; +} + + +void unix_unlock(struct unix_proto_data *upd) +{ + upd->lock_flag = 0; + wake_up(&upd->wait); +} + +/* don't have to do anything. */ +static int +unix_proto_listen(struct socket *sock, int backlog) +{ + return(0); +} + + +static int +unix_proto_setsockopt(struct socket *sock, int level, int optname, + char *optval, int optlen) +{ + return(-EOPNOTSUPP); +} + + +static int +unix_proto_getsockopt(struct socket *sock, int level, int optname, + char *optval, int *optlen) +{ + return(-EOPNOTSUPP); +} + +static int +unix_proto_sendto(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags, struct sockaddr *addr, int addr_len) +{ + return(-EOPNOTSUPP); +} + +static int +unix_proto_recvfrom(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags, struct sockaddr *addr, int *addr_len) +{ + return(-EOPNOTSUPP); +} + + +static int +unix_proto_shutdown(struct socket *sock, int how) +{ + return(-EOPNOTSUPP); +} + + +/* This error needs to be checked. */ +static int +unix_proto_send(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags) +{ + if (flags != 0) return(-EINVAL); + return(unix_proto_write(sock, (char *) buff, len, nonblock)); +} + + +/* This error needs to be checked. */ +static int +unix_proto_recv(struct socket *sock, void *buff, int len, int nonblock, + unsigned flags) +{ + if (flags != 0) return(-EINVAL); + return(unix_proto_read(sock, (char *) buff, len, nonblock)); +} + + +static struct unix_proto_data * +unix_data_lookup(struct sockaddr_un *sockun, int sockaddr_len, + struct inode *inode) +{ + struct unix_proto_data *upd; + + for(upd = unix_datas; upd <= last_unix_data; ++upd) { + if (upd->refcnt && upd->socket && + upd->socket->state == SS_UNCONNECTED && + upd->sockaddr_un.sun_family == sockun->sun_family && + upd->inode == inode) return(upd); + } + return(NULL); +} + + +static struct unix_proto_data * +unix_data_alloc(void) +{ + struct unix_proto_data *upd; + + cli(); + for(upd = unix_datas; upd <= last_unix_data; ++upd) { + if (!upd->refcnt) { + upd->refcnt = 1; + sti(); + upd->socket = NULL; + upd->sockaddr_len = 0; + upd->sockaddr_un.sun_family = 0; + upd->buf = NULL; + upd->bp_head = upd->bp_tail = 0; + upd->inode = NULL; + upd->peerupd = NULL; + return(upd); + } + } + sti(); + return(NULL); +} + + +static inline void +unix_data_ref(struct unix_proto_data *upd) +{ + if (!upd) { + dprintf(1, "UNIX: data_ref: upd = NULL\n"); + return; + } + ++upd->refcnt; + dprintf(1, "UNIX: data_ref: refing data 0x%x(%d)\n", upd, upd->refcnt); +} + + +static void +unix_data_deref(struct unix_proto_data *upd) +{ + if (!upd) { + dprintf(1, "UNIX: data_deref: upd = NULL\n"); + return; + } + if (upd->refcnt == 1) { + dprintf(1, "UNIX: data_deref: releasing data 0x%x\n", upd); + if (upd->buf) { + free_page((unsigned long)upd->buf); + upd->buf = NULL; + upd->bp_head = upd->bp_tail = 0; + } + } + --upd->refcnt; +} + + +/* + * Upon a create, we allocate an empty protocol data, + * and grab a page to buffer writes. + */ +static int +unix_proto_create(struct socket *sock, int protocol) +{ + struct unix_proto_data *upd; + + dprintf(1, "UNIX: create: socket 0x%x, proto %d\n", sock, protocol); + if (protocol != 0) { + dprintf(1, "UNIX: create: protocol != 0\n"); + return(-EINVAL); + } + if (!(upd = unix_data_alloc())) { + printk("UNIX: create: can't allocate buffer\n"); + return(-ENOMEM); + } + if (!(upd->buf = (char*) get_free_page(GFP_USER))) { + printk("UNIX: create: can't get page!\n"); + unix_data_deref(upd); + return(-ENOMEM); + } + upd->protocol = protocol; + upd->socket = sock; + UN_DATA(sock) = upd; + dprintf(1, "UNIX: create: allocated data 0x%x\n", upd); + return(0); +} + + +static int +unix_proto_dup(struct socket *newsock, struct socket *oldsock) +{ + struct unix_proto_data *upd = UN_DATA(oldsock); + + return(unix_proto_create(newsock, upd->protocol)); +} + + +static int +unix_proto_release(struct socket *sock, struct socket *peer) +{ + struct unix_proto_data *upd = UN_DATA(sock); + + dprintf(1, "UNIX: release: socket 0x%x, unix_data 0x%x\n", sock, upd); + if (!upd) return(0); + if (upd->socket != sock) { + printk("UNIX: release: socket link mismatch!\n"); + return(-EINVAL); + } + if (upd->inode) { + dprintf(1, "UNIX: release: releasing inode 0x%x\n", upd->inode); + iput(upd->inode); + upd->inode = NULL; + } + UN_DATA(sock) = NULL; + upd->socket = NULL; + if (upd->peerupd) unix_data_deref(upd->peerupd); + unix_data_deref(upd); + return(0); +} + + +/* + * Bind a name to a socket. + * This is where much of the work is done: we allocate a fresh page for + * the buffer, grab the appropriate inode and set things up. + * + * FIXME: what should we do if an address is already bound? + * Here we return EINVAL, but it may be necessary to re-bind. + * I think thats what BSD does in the case of datagram sockets... + */ +static int +unix_proto_bind(struct socket *sock, struct sockaddr *umyaddr, + int sockaddr_len) +{ + char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; + struct unix_proto_data *upd = UN_DATA(sock); + unsigned long old_fs; + int i; + int er; + + dprintf(1, "UNIX: bind: socket 0x%x, len=%d\n", sock, sockaddr_len); + if (sockaddr_len <= UN_PATH_OFFSET || + sockaddr_len > sizeof(struct sockaddr_un)) { + dprintf(1, "UNIX: bind: bad length %d\n", sockaddr_len); + return(-EINVAL); + } + if (upd->sockaddr_len || upd->inode) { + printk("UNIX: bind: already bound!\n"); + return(-EINVAL); + } + er=verify_area(VERIFY_WRITE, umyaddr, sockaddr_len); + if(er) + return er; + memcpy_fromfs(&upd->sockaddr_un, umyaddr, sockaddr_len); + upd->sockaddr_un.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; + if (upd->sockaddr_un.sun_family != AF_UNIX) { + dprintf(1, "UNIX: bind: family is %d, not AF_UNIX(%d)\n", + upd->sockaddr_un.sun_family, AF_UNIX); + return(-EINVAL); + } + + memcpy(fname, upd->sockaddr_un.sun_path, sockaddr_len-UN_PATH_OFFSET); + fname[sockaddr_len-UN_PATH_OFFSET] = '\0'; + old_fs = get_fs(); + set_fs(get_ds()); + i = do_mknod(fname, S_IFSOCK | S_IRWXUGO, 0); + if (i == 0) i = open_namei(fname, 0, S_IFSOCK, &upd->inode, NULL); + set_fs(old_fs); + if (i < 0) { + printk("UNIX: bind: can't open socket %s\n", fname); + return(i); + } + upd->sockaddr_len = sockaddr_len; /* now its legal */ + + dprintf(1, "UNIX: bind: bound socket address: "); + sockaddr_un_printk(&upd->sockaddr_un, upd->sockaddr_len); + dprintf(1, "to inode 0x%x\n", upd->inode); + return(0); +} + + +/* + * Perform a connection. we can only connect to unix sockets + * (I can't for the life of me find an application where that + * wouldn't be the case!) + */ +static int +unix_proto_connect(struct socket *sock, struct sockaddr *uservaddr, + int sockaddr_len, int flags) +{ + char fname[sizeof(((struct sockaddr_un *)0)->sun_path) + 1]; + struct sockaddr_un sockun; + struct unix_proto_data *serv_upd; + struct inode *inode; + unsigned long old_fs; + int i; + int er; + + dprintf(1, "UNIX: connect: socket 0x%x, servlen=%d\n", sock, sockaddr_len); + + if (sockaddr_len <= UN_PATH_OFFSET || + sockaddr_len > sizeof(struct sockaddr_un)) { + dprintf(1, "UNIX: connect: bad length %d\n", sockaddr_len); + return(-EINVAL); + } + if (sock->state == SS_CONNECTING) return(-EINPROGRESS); + if (sock->state == SS_CONNECTED) return(-EISCONN); + + er=verify_area(VERIFY_READ, uservaddr, sockaddr_len); + if(er) + return er; + memcpy_fromfs(&sockun, uservaddr, sockaddr_len); + sockun.sun_path[sockaddr_len-UN_PATH_OFFSET] = '\0'; + if (sockun.sun_family != AF_UNIX) { + dprintf(1, "UNIX: connect: family is %d, not AF_UNIX(%d)\n", + sockun.sun_family, AF_UNIX); + return(-EINVAL); + } + + /* + * Try to open the name in the filesystem - this is how we + * identify ourselves and our server. Note that we don't + * hold onto the inode that long, just enough to find our + * server. When we're connected, we mooch off the server. + */ + memcpy(fname, sockun.sun_path, sockaddr_len-UN_PATH_OFFSET); + fname[sockaddr_len-UN_PATH_OFFSET] = '\0'; + old_fs = get_fs(); + set_fs(get_ds()); + i = open_namei(fname, 0, S_IFSOCK, &inode, NULL); + set_fs(old_fs); + if (i < 0) { + dprintf(1, "UNIX: connect: can't open socket %s\n", fname); + return(i); + } + serv_upd = unix_data_lookup(&sockun, sockaddr_len, inode); + iput(inode); + if (!serv_upd) { + dprintf(1, "UNIX: connect: can't locate peer %s at inode 0x%x\n", + fname, inode); + return(-EINVAL); + } + if ((i = sock_awaitconn(sock, serv_upd->socket)) < 0) { + dprintf(1, "UNIX: connect: can't await connection\n"); + return(i); + } + if (sock->conn) { + unix_data_ref(UN_DATA(sock->conn)); + UN_DATA(sock)->peerupd = UN_DATA(sock->conn); /* ref server */ + } + return(0); +} + + +/* + * To do a socketpair, we just connect the two datas, easy! + * Since we always wait on the socket inode, they're no contention + * for a wait area, and deadlock prevention in the case of a process + * writing to itself is, ignored, in true unix fashion! + */ +static int +unix_proto_socketpair(struct socket *sock1, struct socket *sock2) +{ + struct unix_proto_data *upd1 = UN_DATA(sock1), *upd2 = UN_DATA(sock2); + + unix_data_ref(upd1); + unix_data_ref(upd2); + upd1->peerupd = upd2; + upd2->peerupd = upd1; + return(0); +} + + +/* On accept, we ref the peer's data for safe writes. */ +static int +unix_proto_accept(struct socket *sock, struct socket *newsock, int flags) +{ + struct socket *clientsock; + + dprintf(1, "UNIX: accept: socket 0x%x accepted via socket 0x%x\n", + sock, newsock); + + /* + * If there aren't any sockets awaiting connection, + * then wait for one, unless nonblocking. + */ + while(!(clientsock = sock->iconn)) { + if (flags & O_NONBLOCK) return(-EAGAIN); + interruptible_sleep_on(sock->wait); + if (current->signal & ~current->blocked) { + dprintf(1, "UNIX: accept: sleep was interrupted\n"); + return(-ERESTARTSYS); + } + } + + /* + * Great. Finish the connection relative to server and client, + * wake up the client and return the new fd to the server. + */ + sock->iconn = clientsock->next; + clientsock->next = NULL; + newsock->conn = clientsock; + clientsock->conn = newsock; + clientsock->state = SS_CONNECTED; + newsock->state = SS_CONNECTED; + unix_data_ref(UN_DATA(clientsock)); + UN_DATA(newsock)->peerupd = UN_DATA(clientsock); + UN_DATA(newsock)->sockaddr_un = UN_DATA(sock)->sockaddr_un; + UN_DATA(newsock)->sockaddr_len = UN_DATA(sock)->sockaddr_len; + wake_up_interruptible(clientsock->wait); + return(0); +} + + +/* Gets the current name or the name of the connected socket. */ +static int +unix_proto_getname(struct socket *sock, struct sockaddr *usockaddr, + int *usockaddr_len, int peer) +{ + struct unix_proto_data *upd; + int len; + int er; + + dprintf(1, "UNIX: getname: socket 0x%x for %s\n", sock, peer?"peer":"self"); + if (peer) { + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: getname: socket not connected\n"); + return(-EINVAL); + } + upd = UN_DATA(sock->conn); + } else + upd = UN_DATA(sock); + + er=verify_area(VERIFY_WRITE, usockaddr_len, sizeof(*usockaddr_len)); + if(er) + return er; + if ((len = get_fs_long(usockaddr_len)) <= 0) return(-EINVAL); + if (len > upd->sockaddr_len) len = upd->sockaddr_len; + if (len) { + er=verify_area(VERIFY_WRITE, usockaddr, len); + if(er) + return er; + memcpy_tofs(usockaddr, &upd->sockaddr_un, len); + } + put_fs_long(len, usockaddr_len); + return(0); +} + + +/* We read from our own buf. */ +static int +unix_proto_read(struct socket *sock, char *ubuf, int size, int nonblock) +{ + struct unix_proto_data *upd; + int todo, avail; + int er; + + if ((todo = size) <= 0) return(0); + upd = UN_DATA(sock); + while(!(avail = UN_BUF_AVAIL(upd))) { + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: read: socket not connected\n"); + return((sock->state == SS_DISCONNECTING) ? 0 : -EINVAL); + } + dprintf(1, "UNIX: read: no data available...\n"); + if (nonblock) return(-EAGAIN); + interruptible_sleep_on(sock->wait); + if (current->signal & ~current->blocked) { + dprintf(1, "UNIX: read: interrupted\n"); + return(-ERESTARTSYS); + } + } + + /* + * Copy from the read buffer into the user's buffer, + * watching for wraparound. Then we wake up the writer. + */ + + unix_lock(upd); + do { + int part, cando; + + if (avail <= 0) { + printk("UNIX: read: AVAIL IS NEGATIVE!!!\n"); + send_sig(SIGKILL, current, 1); + return(-EPIPE); + } + + if ((cando = todo) > avail) cando = avail; + if (cando >(part = BUF_SIZE - upd->bp_tail)) cando = part; + dprintf(1, "UNIX: read: avail=%d, todo=%d, cando=%d\n", + avail, todo, cando); + if((er=verify_area(VERIFY_WRITE,ubuf,cando))<0) + { + unix_unlock(upd); + return er; + } + memcpy_tofs(ubuf, upd->buf + upd->bp_tail, cando); + upd->bp_tail =(upd->bp_tail + cando) &(BUF_SIZE-1); + ubuf += cando; + todo -= cando; + if (sock->state == SS_CONNECTED) + wake_up_interruptible(sock->conn->wait); + avail = UN_BUF_AVAIL(upd); + } while(todo && avail); + unix_unlock(upd); + return(size - todo); +} + + +/* + * We write to our peer's buf. When we connected we ref'd this + * peer so we are safe that the buffer remains, even after the + * peer has disconnected, which we check other ways. + */ +static int +unix_proto_write(struct socket *sock, char *ubuf, int size, int nonblock) +{ + struct unix_proto_data *pupd; + int todo, space; + int er; + + if ((todo = size) <= 0) return(0); + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: write: socket not connected\n"); + if (sock->state == SS_DISCONNECTING) { + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + return(-EINVAL); + } + pupd = UN_DATA(sock)->peerupd; /* safer than sock->conn */ + + while(!(space = UN_BUF_SPACE(pupd))) { + dprintf(1, "UNIX: write: no space left...\n"); + if (nonblock) return(-EAGAIN); + interruptible_sleep_on(sock->wait); + if (current->signal & ~current->blocked) { + dprintf(1, "UNIX: write: interrupted\n"); + return(-ERESTARTSYS); + } + if (sock->state == SS_DISCONNECTING) { + dprintf(1, "UNIX: write: disconnected(SIGPIPE)\n"); + send_sig(SIGPIPE, current, 1); + return(-EPIPE); + } + } + + /* + * Copy from the user's buffer to the write buffer, + * watching for wraparound. Then we wake up the reader. + */ + + unix_lock(pupd); + + do { + int part, cando; + + if (space <= 0) { + printk("UNIX: write: SPACE IS NEGATIVE!!!\n"); + send_sig(SIGKILL, current, 1); + return(-EPIPE); + } + + /* + * We may become disconnected inside this loop, so watch + * for it (peerupd is safe until we close). + */ + if (sock->state == SS_DISCONNECTING) { + send_sig(SIGPIPE, current, 1); + unix_unlock(pupd); + return(-EPIPE); + } + if ((cando = todo) > space) cando = space; + if (cando >(part = BUF_SIZE - pupd->bp_head)) cando = part; + dprintf(1, "UNIX: write: space=%d, todo=%d, cando=%d\n", + space, todo, cando); + er=verify_area(VERIFY_READ, ubuf, cando); + if(er) + { + unix_unlock(pupd); + return er; + } + memcpy_fromfs(pupd->buf + pupd->bp_head, ubuf, cando); + pupd->bp_head =(pupd->bp_head + cando) &(BUF_SIZE-1); + ubuf += cando; + todo -= cando; + if (sock->state == SS_CONNECTED) + wake_up_interruptible(sock->conn->wait); + space = UN_BUF_SPACE(pupd); + } while(todo && space); + unix_unlock(pupd); + return(size - todo); +} + + +static int +unix_proto_select(struct socket *sock, int sel_type, select_table * wait) +{ + struct unix_proto_data *upd, *peerupd; + + /* Handle server sockets specially. */ + if (sock->flags & SO_ACCEPTCON) { + if (sel_type == SEL_IN) { + dprintf(1, "UNIX: select: %sconnections pending\n", + sock->iconn ? "" : "no "); + if (sock->iconn) return(1); + select_wait(sock->wait, wait); + return(sock->iconn ? 1 : 0); + } + dprintf(1, "UNIX: select: nothing else for server socket\n"); + select_wait(sock->wait, wait); + return(0); + } + + if (sel_type == SEL_IN) { + upd = UN_DATA(sock); + dprintf(1, "UNIX: select: there is%s data available\n", + UN_BUF_AVAIL(upd) ? "" : " no"); + if (UN_BUF_AVAIL(upd)) /* even if disconnected */ + return(1); + else if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: select: socket not connected(read EOF)\n"); + return(1); + } + select_wait(sock->wait,wait); + return(0); + } + if (sel_type == SEL_OUT) { + if (sock->state != SS_CONNECTED) { + dprintf(1, "UNIX: select: socket not connected(write EOF)\n"); + return(1); + } + peerupd = UN_DATA(sock->conn); + dprintf(1, "UNIX: select: there is%s space available\n", + UN_BUF_SPACE(peerupd) ? "" : " no"); + if (UN_BUF_SPACE(peerupd) > 0) return(1); + select_wait(sock->wait,wait); + return(0); + } + + /* SEL_EX */ + dprintf(1, "UNIX: select: there are no exceptions here?!\n"); + return(0); +} + + +static int +unix_proto_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg) +{ + struct unix_proto_data *upd, *peerupd; + int er; + + upd = UN_DATA(sock); + peerupd = (sock->state == SS_CONNECTED) ? UN_DATA(sock->conn) : NULL; + + switch(cmd) { + case TIOCINQ: + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); + if(er) + return er; + if (UN_BUF_AVAIL(upd) || peerupd) + put_fs_long(UN_BUF_AVAIL(upd),(unsigned long *)arg); + else + put_fs_long(0,(unsigned long *)arg); + break; + case TIOCOUTQ: + if (sock->flags & SO_ACCEPTCON) return(-EINVAL); + er=verify_area(VERIFY_WRITE,(void *)arg, sizeof(unsigned long)); + if(er) + return er; + if (peerupd) put_fs_long(UN_BUF_SPACE(peerupd), + (unsigned long *)arg); + else + put_fs_long(0,(unsigned long *)arg); + break; + default: + return(-EINVAL); + } + return(0); +} + + +static int +unix_open(struct inode * inode, struct file * file) +{ + int minor; + + dprintf(1, "UNIX: open\n"); + minor = MINOR(inode->i_rdev); + if (minor != 0) return(-ENODEV); + + return(0); +} + + +static void +unix_close(struct inode * inode, struct file * file) +{ + dprintf(1, "UNIX: close\n"); +} + + +static int +unix_ioctl(struct inode *inode, struct file *file, + unsigned int cmd, unsigned long arg) +{ + int minor, ret; + int er; + + dprintf(1, "UNIX: ioctl(0x%X, 0x%X)\n", cmd, arg); + minor = MINOR(inode->i_rdev); + if (minor != 0) return(-ENODEV); + + ret = -EINVAL; + switch(cmd) { + case DDIOCSDBG: + er=verify_area(VERIFY_READ,(void *)arg, sizeof(int)); + if(er) + return er; + unix_debug = get_fs_long((int *)arg); + if (unix_debug != 0 && unix_debug != 1) { + unix_debug = 0; + return(-EINVAL); + } + return(0); + case SIOCSIFLINK: + printk("UNIX: cannot link streams!\n"); + break; + default: + break; + } + return(ret); +} + + + + +static struct file_operations unix_fops = { + NULL, /* LSEEK */ + NULL, /* READ */ + NULL, /* WRITE */ + NULL, /* READDIR */ + NULL, /* SELECT */ + unix_ioctl, /* IOCTL */ + NULL, /* MMAP */ + unix_open, /* OPEN */ + unix_close /* CLOSE */ +}; + + +static struct proto_ops unix_proto_ops = { + AF_UNIX, + unix_proto_create, + unix_proto_dup, + unix_proto_release, + unix_proto_bind, + unix_proto_connect, + unix_proto_socketpair, + unix_proto_accept, + unix_proto_getname, + unix_proto_read, + unix_proto_write, + unix_proto_select, + unix_proto_ioctl, + unix_proto_listen, + unix_proto_send, + unix_proto_recv, + unix_proto_sendto, + unix_proto_recvfrom, + unix_proto_shutdown, + unix_proto_setsockopt, + unix_proto_getsockopt, + NULL /* unix_proto_fcntl */ +}; + + +void +unix_proto_init(struct ddi_proto *pro) +{ + struct unix_proto_data *upd; + + dprintf(1, "%s: init: initializing...\n", pro->name); + if (register_chrdev(AF_UNIX_MAJOR, "af_unix", &unix_fops) < 0) { + printk("%s: cannot register major device %d!\n", + pro->name, AF_UNIX_MAJOR); + return; + } + + /* Tell SOCKET that we are alive... */ + (void) sock_register(unix_proto_ops.family, &unix_proto_ops); + + for(upd = unix_datas; upd <= last_unix_data; ++upd) { + upd->refcnt = 0; + } +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/unix.h b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/unix.h new file mode 100644 index 000000000..74b17778e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/net/unix/unix.h @@ -0,0 +1,65 @@ +/* + * UNIX An implementation of the AF_UNIX network domain for the + * LINUX operating system. UNIX is implemented using the + * BSD Socket interface as the means of communication with + * the user level. + * + * This file descibes some things of the UNIX protocol family + * module. It is mainly used for the "proc" sub-module now, + * but it may be useful for cleaning up the UNIX module as a + * whole later. + * + * Version: @(#)unix.h 1.0.3 05/25/93 + * + * Authors: Orest Zborowski, + * Ross Biro, + * Fred N. van Kempen, + * + * 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. + */ + + +#ifdef _LINUX_UN_H + + +struct unix_proto_data { + int refcnt; /* cnt of reference 0=free */ + struct socket *socket; /* socket we're bound to */ + int protocol; + struct sockaddr_un sockaddr_un; + short sockaddr_len; /* >0 if name bound */ + char *buf; + int bp_head, bp_tail; + struct inode *inode; + struct unix_proto_data *peerupd; + struct wait_queue *wait; /* Lock across page faults (FvK) */ + int lock_flag; +}; + +extern struct unix_proto_data unix_datas[NSOCKETS]; + + +#define last_unix_data (unix_datas + NSOCKETS - 1) + + +#define UN_DATA(SOCK) ((struct unix_proto_data *)(SOCK)->data) +#define UN_PATH_OFFSET ((unsigned long)((struct sockaddr_un *)0) \ + ->sun_path) + +/* + * Buffer size must be power of 2. buffer mgmt inspired by pipe code. + * note that buffer contents can wraparound, and we can write one byte less + * than full size to discern full vs empty. + */ +#define BUF_SIZE PAGE_SIZE +#define UN_BUF_AVAIL(UPD) (((UPD)->bp_head - (UPD)->bp_tail) & \ + (BUF_SIZE-1)) +#define UN_BUF_SPACE(UPD) ((BUF_SIZE-1) - UN_BUF_AVAIL(UPD)) + +#endif /* _LINUX_UN_H */ + + +extern void unix_proto_init(struct ddi_proto *pro); diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/tools/build.c b/gems-kernel.git/source/THIRDPARTY/linux-old/tools/build.c new file mode 100644 index 000000000..cddaaa21c --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/tools/build.c @@ -0,0 +1,227 @@ +/* + * linux/tools/build.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + */ + +/* + * This file builds a disk-image from three different files: + * + * - bootsect: max 510 bytes of 8086 machine code, loads the rest + * - setup: max 4 sectors of 8086 machine code, sets up system parm + * - system: 80386 code for actual system + * + * It does some checking that all files are of the correct type, and + * just writes the result to stdout, removing headers and padding to + * the right amount. It also writes some system data to stderr. + */ + +/* + * Changes by tytso to allow root device specification + */ + +#include /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include +#include +#include + +#define MINIX_HEADER 32 +#define GCC_HEADER 1024 + +#define SYS_SIZE DEF_SYSSIZE + +#define DEFAULT_MAJOR_ROOT 0 +#define DEFAULT_MINOR_ROOT 0 + +/* max nr of sectors of setup: don't change unless you also change + * bootsect etc */ +#define SETUP_SECTS 4 + +#define STRINGIFY(x) #x + +typedef union { + long l; + short s[2]; + char b[4]; +} conv; + +long intel_long(long l) +{ + conv t; + + t.b[0] = l & 0xff; l >>= 8; + t.b[1] = l & 0xff; l >>= 8; + t.b[2] = l & 0xff; l >>= 8; + t.b[3] = l & 0xff; l >>= 8; + return t.l; +} + +short intel_short(short l) +{ + conv t; + + t.b[0] = l & 0xff; l >>= 8; + t.b[1] = l & 0xff; l >>= 8; + return t.s[0]; +} + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: build bootsect setup system [rootdev] [> image]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id, sz; + unsigned long sys_size; + char buf[1024]; + struct exec *ex = (struct exec *)buf; + char major_root, minor_root; + struct stat sb; + + if ((argc < 4) || (argc > 5)) + usage(); + if (argc > 4) { + if (!strcmp(argv[4], "CURRENT")) { + if (stat("/", &sb)) { + perror("/"); + die("Couldn't stat /"); + } + major_root = major(sb.st_dev); + minor_root = minor(sb.st_dev); + } else if (strcmp(argv[4], "FLOPPY")) { + if (stat(argv[4], &sb)) { + perror(argv[4]); + die("Couldn't stat root device."); + } + major_root = major(sb.st_rdev); + minor_root = minor(sb.st_rdev); + } else { + major_root = 0; + minor_root = 0; + } + } else { + major_root = DEFAULT_MAJOR_ROOT; + minor_root = DEFAULT_MINOR_ROOT; + } + fprintf(stderr, "Root device is (%d, %d)\n", major_root, minor_root); + for (i=0;i0 ; i+=c ) + if (write(1,buf,c)!=c) + die("Write call failed"); + if (c != 0) + die("read-error on 'setup'"); + close (id); + if (i > SETUP_SECTS*512) + die("Setup exceeds " STRINGIFY(SETUP_SECTS) + " sectors - rewrite build/boot/setup"); + fprintf(stderr,"Setup is %d bytes.\n",i); + for (c=0 ; c sizeof(buf)) + c = sizeof(buf); + if (write(1,buf,c) != c) + die("Write call failed"); + i += c; + } + + if ((id=open(argv[3],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (N_MAGIC(*ex) != ZMAGIC) + die("Non-GCC header of 'system'"); + fprintf(stderr,"System is %d kB (%d kB code, %d kB data and %d kB bss)\n", + (ex->a_text+ex->a_data+ex->a_bss)/1024, + ex->a_text /1024, + ex->a_data /1024, + ex->a_bss /1024); + sz = N_SYMOFF(*ex) - GCC_HEADER + 4; + sys_size = (sz + 15) / 16; + if (sys_size > SYS_SIZE) + die("System is too big"); + while (sz > 0) { + int l, n; + + l = sz; + if (l > sizeof(buf)) + l = sizeof(buf); + if ((n=read(id, buf, l)) != l) { + if (n == -1) + perror(argv[1]); + else + fprintf(stderr, "Unexpected EOF\n"); + die("Can't read 'system'"); + } + if (write(1, buf, l) != l) + die("Write failed"); + sz -= l; + } + close(id); + if (lseek(1,500,0) == 500) { + buf[0] = (sys_size & 0xff); + buf[1] = ((sys_size >> 8) & 0xff); + if (write(1, buf, 2) != 2) + die("Write failed"); + } + return(0); +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/tools/version.c b/gems-kernel.git/source/THIRDPARTY/linux-old/tools/version.c new file mode 100644 index 000000000..1802cf545 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/tools/version.c @@ -0,0 +1,21 @@ +/* + * linux/version.c + * + * Copyright (C) 1992 Theodore Ts'o + * + * May be freely distributed as part of Linux. + */ + +#include +#include + +#include "./version.h" + +struct new_utsname system_utsname = { + UTS_SYSNAME, UTS_NODENAME, UTS_RELEASE, UTS_VERSION, + UTS_MACHINE, UTS_DOMAINNAME +}; + +char *linux_banner = + "Linux version " UTS_RELEASE " (" LINUX_COMPILE_BY "@" + LINUX_COMPILE_HOST ") " UTS_VERSION "\n"; diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/Makefile b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/Makefile new file mode 100644 index 000000000..f4fc25b90 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/Makefile @@ -0,0 +1,32 @@ + +HEAD = head.o +SYSTEM = ../tools/zSystem +#LD = gcc +#TEST = -DTEST_DRIVER + +zOBJECTS = $(HEAD) inflate.o unzip.o misc.o + +CFLAGS = -O6 -DSTDC_HEADERS $(TEST) + +.c.s: + $(CC) $(CFLAGS) -S -o $*.s $< +.s.o: + $(AS) -c -o $*.o $< +.c.o: + $(CC) $(CFLAGS) -c -o $*.o $< + +all: zSystem + +zSystem: piggy.o $(zOBJECTS) + $(LD) $(LDFLAGS) -o zSystem -T 1000 $(zOBJECTS) piggy.o + +head.o: head.s + +head.s: head.S ../include/linux/tasks.h + $(CPP) -traditional head.S -o head.s + +piggy.o: $(SYSTEM) xtract piggyback + ./xtract $(SYSTEM) | gzip -9 | ./piggyback > piggy.o + +$(SYSTEM): + $(MAKE) -C .. tools/zSystem diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/crypt.h b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/crypt.h new file mode 100644 index 000000000..f4aac50c3 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/crypt.h @@ -0,0 +1,12 @@ +/* crypt.h (dummy version) -- do not perform encrytion + * Hardly worth copyrighting :-) + */ + +#ifdef CRYPT +# undef CRYPT /* dummy version */ +#endif + +#define RAND_HEAD_LEN 12 /* length of encryption random header */ + +#define zencode +#define zdecode diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/gzip.h b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/gzip.h new file mode 100644 index 000000000..2f738b945 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/gzip.h @@ -0,0 +1,284 @@ +/* gzip.h -- common declarations for all gzip modules + * Copyright (C) 1992-1993 Jean-loup Gailly. + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +#if defined(__STDC__) || defined(PROTO) +# define OF(args) args +#else +# define OF(args) () +#endif + +#ifdef __STDC__ + typedef void *voidp; +#else + typedef char *voidp; +#endif + +/* I don't like nested includes, but the string functions are used too often */ +#if defined(HAVE_STRING_H) || defined(STDC_HEADERS) +# include +# define memzero(s, n) memset ((s), 0, (n)) +#else +# include +# define strchr index +# define strrchr rindex +# define memcpy(d, s, n) bcopy((s), (d), (n)) +# define memcmp(s1, s2, n) bcmp((s1), (s2), (n)) +# define memzero(s, n) bzero((s), (n)) +#endif + +#if !defined(STDC_HEADERS) && defined(HAVE_MEMORY_H) +# include +#endif + +#ifndef RETSIGTYPE +# define RETSIGTYPE void +#endif + +#define local static + +typedef unsigned char uch; +typedef unsigned short ush; +typedef unsigned long ulg; + +/* Return codes from gzip */ +#define OK 0 +#define ERROR 1 +#define WARNING 2 + +/* Compression methods (see algorithm.doc) */ +#define STORED 0 +#define COMPRESSED 1 +#define PACKED 2 +/* methods 3 to 7 reserved */ +#define DEFLATED 8 +extern int method; /* compression method */ + +/* To save memory for 16 bit systems, some arrays are overlayed between + * the various modules: + * deflate: prev+head window d_buf l_buf outbuf + * unlzw: tab_prefix tab_suffix stack inbuf outbuf + * inflate: window inbuf + * unpack: window inbuf + * For compression, input is done in window[]. For decompression, output + * is done in window except for unlzw. + */ + +#ifndef INBUFSIZ +# define INBUFSIZ 0x8000 /* input buffer size */ +#endif +#define INBUF_EXTRA 64 /* required by unlzw() */ + +#ifndef OUTBUFSIZ +# define OUTBUFSIZ 16384 /* output buffer size */ +#endif +#define OUTBUF_EXTRA 2048 /* required by unlzw() */ + +#define DIST_BUFSIZE 0x8000 /* buffer for distances, see trees.c */ + +#ifdef DYN_ALLOC +# define EXTERN(type, array) extern type * near array +# define DECLARE(type, array, size) type * near array +# define ALLOC(type, array, size) { \ + array = (type*)fcalloc((unsigned)(((size)+1L)/2), 2*sizeof(type)); \ + if (array == NULL) error("insufficient memory"); \ + } +# define FREE(array) {if (array != NULL) fcfree(array), array=NULL;} +#else +# define EXTERN(type, array) extern type array[] +# define DECLARE(type, array, size) type array[size] +# define ALLOC(type, array, size) +# define FREE(array) +#endif + +EXTERN(uch, inbuf); /* input buffer */ +EXTERN(uch, outbuf); /* output buffer */ +EXTERN(ush, d_buf); /* buffer for distances, see trees.c */ +EXTERN(uch, window); /* Sliding window and suffix table (unlzw) */ +#define tab_suffix window +#ifndef MAXSEG_64K +# define tab_prefix prev /* hash link (see deflate.c) */ +# define head (prev+WSIZE) /* hash head (see deflate.c) */ + EXTERN(ush, tab_prefix); /* prefix code (see unlzw.c) */ +#else +# define tab_prefix0 prev +# define head tab_prefix1 + EXTERN(ush, tab_prefix0); /* prefix for even codes */ + EXTERN(ush, tab_prefix1); /* prefix for odd codes */ +#endif + +extern unsigned insize; /* valid bytes in inbuf */ +extern unsigned inptr; /* index of next byte to be processed in inbuf */ +extern unsigned outcnt; /* bytes in output buffer */ + +extern long bytes_in; /* number of input bytes */ +extern long bytes_out; /* number of output bytes */ +extern long overhead; /* number of bytes in gzip header */ + +#define isize bytes_in +/* for compatibility with old zip sources (to be cleaned) */ + +extern int ifd; /* input file descriptor */ +extern int ofd; /* output file descriptor */ +extern char ifname[]; /* input filename or "stdin" */ +extern char ofname[]; /* output filename or "stdout" */ + +extern ulg time_stamp; /* original time stamp (modification time) */ +extern long ifile_size; /* input file size, -1 for devices (debug only) */ + +extern int exit_code; /* program exit code */ + +typedef int file_t; /* Do not use stdio */ +#define NO_FILE (-1) /* in memory compression */ + + +#define GZIP_MAGIC "\037\213" /* Magic header for gzip files, 1F 8B */ +#define OLD_GZIP_MAGIC "\037\236" /* Magic header for gzip 0.5 = freeze 1.x */ +#define PKZIP_MAGIC "PK\003\004" /* Magic header for pkzip files */ +#define PACK_MAGIC "\037\036" /* Magic header for packed files */ + +/* gzip flag byte */ +#define ASCII_FLAG 0x01 /* bit 0 set: file probably ascii text */ +#define CONTINUATION 0x02 /* bit 1 set: continuation of multi-part gzip file */ +#define EXTRA_FIELD 0x04 /* bit 2 set: extra field present */ +#define ORIG_NAME 0x08 /* bit 3 set: original file name present */ +#define COMMENT 0x10 /* bit 4 set: file comment present */ +#define ENCRYPTED 0x20 /* bit 5 set: file is encrypted */ +#define RESERVED 0xC0 /* bit 6,7: reserved */ + +/* internal file attribute */ +#define UNKNOWN (-1) +#define BINARY 0 +#define ASCII 1 + +#ifndef WSIZE +# define WSIZE 0x8000 /* window size--must be a power of two, and */ +#endif /* at least 32K for zip's deflate method */ + +#define MIN_MATCH 3 +#define MAX_MATCH 258 +/* The minimum and maximum match lengths */ + +#define MIN_LOOKAHEAD (MAX_MATCH+MIN_MATCH+1) +/* Minimum amount of lookahead, except at the end of the input file. + * See deflate.c for comments about the MIN_MATCH+1. + */ + +#define MAX_DIST (WSIZE-MIN_LOOKAHEAD) +/* In order to simplify the code, particularly on 16 bit machines, match + * distances are limited to MAX_DIST instead of WSIZE. + */ + +extern int decrypt; /* flag to turn on decryption */ +extern int save_orig_name; /* set if original name must be saved */ +extern int verbose; /* be verbose (-v) */ +extern int level; /* compression level */ +extern int test; /* check .z file integrity */ +extern int to_stdout; /* output to stdout (-c) */ + +#define get_byte() (inptr < insize ? inbuf[inptr++] : fill_inbuf()) + +/* put_byte is used for the compressed output, put_char for the + * uncompressed output. However unlzw() uses window for its + * suffix table instead of its output buffer, so it does not use put_char. + * (to be cleaned up). + */ +#define put_byte(c) {outbuf[outcnt++]=(uch)(c); if (outcnt==OUTBUFSIZ)\ + flush_outbuf();} +#define put_char(c) {window[outcnt++]=(uch)(c); if (outcnt==WSIZE)\ + flush_window();} + +/* Output a 16 bit value, lsb first */ +#define put_short(w) \ +{ if (outcnt < OUTBUFSIZ-2) { \ + outbuf[outcnt++] = (uch) ((w) & 0xff); \ + outbuf[outcnt++] = (uch) ((ush)(w) >> 8); \ + } else { \ + put_byte((uch)((w) & 0xff)); \ + put_byte((uch)((ush)(w) >> 8)); \ + } \ +} + +/* Output a 32 bit value to the bit stream, lsb first */ +#define put_long(n) { \ + put_short((n) & 0xffff); \ + put_short(((ulg)(n)) >> 16); \ +} + +#define seekable() 0 /* force sequential output */ +#define translate_eol 0 /* no option -a yet */ + +#define tolow(c) (isupper(c) ? (c)-'A'+'a' : (c)) /* force to lower case */ + +/* Macros for getting two-byte and four-byte header values */ +#define SH(p) ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)) +#define LG(p) ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)) + +/* Diagnostic functions */ +#ifdef DEBUG +# define Assert(cond,msg) {if(!(cond)) error(msg);} +# define Trace(x) fprintf x +# define Tracev(x) {if (verbose) fprintf x ;} +# define Tracevv(x) {if (verbose>1) fprintf x ;} +# define Tracec(c,x) {if (verbose && (c)) fprintf x ;} +# define Tracecv(c,x) {if (verbose>1 && (c)) fprintf x ;} +#else +# define Assert(cond,msg) +# define Trace(x) +# define Tracev(x) +# define Tracevv(x) +# define Tracec(c,x) +# define Tracecv(c,x) +#endif + + /* in zip.c: */ +extern void zip OF((int in, int out)); +extern int file_read OF((char *buf, unsigned size)); + + /* in unzip.c */ +extern void unzip OF((int in, int out)); +extern int check_zipfile OF((int in)); + + /* in unpack.c */ +extern void unpack OF((int in, int out)); + + /* in gzip.c */ +RETSIGTYPE abort_gzip OF((void)); + + /* in deflate.c */ +void lm_init OF((int pack_level, ush *flags)); +ulg deflate OF((void)); + + /* in trees.c */ +void ct_init OF((ush *attr, int *method)); +int ct_tally OF((int dist, int lc)); +ulg flush_block OF((char *buf, ulg stored_len, int eof)); + + /* in bits.c */ +void bi_init OF((file_t zipfile)); +void send_bits OF((int value, int length)); +unsigned bi_reverse OF((unsigned value, int length)); +void bi_windup OF((void)); +void copy_block OF((char *buf, unsigned len, int header)); +extern int (*read_buf) OF((char *buf, unsigned size)); + + /* in util.c: */ +extern ulg updcrc OF((uch *s, unsigned n)); +extern void clear_bufs OF((void)); +extern int fill_inbuf OF((void)); +extern void flush_outbuf OF((void)); +extern void flush_window OF((void)); +extern char *strlwr OF((char *s)); +extern char *basename OF((char *fname)); +extern char *add_envopt OF((int *argcp, char ***argvp, char *env)); +extern void error OF((char *m)); +extern void warn OF((char *a, char *b)); +extern void read_error OF((void)); +extern void write_error OF((void)); +extern void display_ratio OF((long num, long den)); +extern voidp xmalloc OF((unsigned int size)); + + /* in inflate.c */ +extern int inflate OF((void)); diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/head.S b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/head.S new file mode 100644 index 000000000..47cfd1cc9 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/head.S @@ -0,0 +1,58 @@ +/* + * linux/boot/head.S + * + * Copyright (C) 1991, 1992, 1993 Linus Torvalds + */ + +/* + * head.S contains the 32-bit startup code. + * + * NOTE!!! Startup happens at absolute address 0x00001000, which is also where + * the page directory will exist. The startup code will be overwritten by + * the page directory. + * + * Page 0 is deliberately kept safe, since System Management Mode code in + * laptops may need to access the BIOS data stored there. This is also + * useful for future device drivers that either access the BIOS via VM86 + * mode. + */ +.text + +#include + +startup_32: + cld + cli + movl $(KERNEL_DS),%eax + mov %ax,%ds + mov %ax,%es + mov %ax,%fs + mov %ax,%gs + lss _stack_start,%esp + xorl %eax,%eax +1: incl %eax # check that A20 really IS enabled + movl %eax,0x000000 # loop forever if it isn't + cmpl %eax,0x100000 + je 1b +/* + * Initialize eflags. Some BIOS's leave bits like NT set. This would + * confuse the debugger if this code is traced. + * XXX - best to initialize before switching to protected mode. + */ + pushl $0 + popfl +/* + * Clear BSS + */ + xorl %eax,%eax + movl $__edata,%edi + movl $__end,%ecx + subl %edi,%ecx + cld + rep + stosb +/* + * Do the decompression, and jump to the new kernel.. + */ + call _decompress_kernel + ljmp $(KERNEL_CS), $0x100000 diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/inflate.c b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/inflate.c new file mode 100644 index 000000000..7c230cb0b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/inflate.c @@ -0,0 +1,818 @@ +#define DEBG(x) +#define DEBG1(x) +/* inflate.c -- Not copyrighted 1992 by Mark Adler + version c10p1, 10 January 1993 */ + +/* + * Adapted for booting Linux by Hannu Savolainen 1993 + * based on gzip-1.0.3 + */ + +#ifndef lint +static char rcsid[] = "$Id: inflate.c,v 0.10 1993/02/04 13:21:06 jloup Exp $"; +#endif + +#include "gzip.h" +#define slide window + +#if defined(STDC_HEADERS) || defined(HAVE_STDLIB_H) +# include +# include +#endif + +struct huft { + uch e; /* number of extra bits or operation */ + uch b; /* number of bits in this code or subcode */ + union { + ush n; /* literal, length base, or distance base */ + struct huft *t; /* pointer to next level of table */ + } v; +}; + + +/* Function prototypes */ +int huft_build OF((unsigned *, unsigned, unsigned, ush *, ush *, + struct huft **, int *)); +int huft_free OF((struct huft *)); +int inflate_codes OF((struct huft *, struct huft *, int, int)); +int inflate_stored OF((void)); +int inflate_fixed OF((void)); +int inflate_dynamic OF((void)); +int inflate_block OF((int *)); +int inflate OF((void)); + + +#define wp outcnt +#define flush_output(w) (wp=(w),flush_window()) + +/* Tables for deflate from PKZIP's appnote.txt. */ +static unsigned border[] = { /* Order of the bit length code lengths */ + 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15}; +static ush cplens[] = { /* Copy lengths for literal codes 257..285 */ + 3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, + 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258, 0, 0}; + /* note: see note #13 above about the 258 in this list. */ +static ush cplext[] = { /* Extra bits for literal codes 257..285 */ + 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, + 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0, 99, 99}; /* 99==invalid */ +static ush cpdist[] = { /* Copy offsets for distance codes 0..29 */ + 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, + 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, + 8193, 12289, 16385, 24577}; +static ush cpdext[] = { /* Extra bits for distance codes */ + 0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, + 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, + 12, 12, 13, 13}; + + +ulg bb; /* bit buffer */ +unsigned bk; /* bits in bit buffer */ + +ush mask_bits[] = { + 0x0000, + 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, + 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff +}; + +#ifdef CRYPT + uch cc; +# define NEXTBYTE() \ + (decrypt ? (cc = get_byte(), zdecode(cc), cc) : get_byte()) +#else +# define NEXTBYTE() (uch)get_byte() +#endif +#define NEEDBITS(n) {while(k<(n)){b|=((ulg)NEXTBYTE())<>=(n);k-=(n);} + +int lbits = 9; /* bits in base literal/length lookup table */ +int dbits = 6; /* bits in base distance lookup table */ + + +/* If BMAX needs to be larger than 16, then h and x[] should be ulg. */ +#define BMAX 16 /* maximum bit length of any code (16 for explode) */ +#define N_MAX 288 /* maximum number of codes in any set */ + + +unsigned hufts; /* track memory usage */ + + +int huft_build(b, n, s, d, e, t, m) +unsigned *b; /* code lengths in bits (all assumed <= BMAX) */ +unsigned n; /* number of codes (assumed <= N_MAX) */ +unsigned s; /* number of simple-valued codes (0..s-1) */ +ush *d; /* list of base values for non-simple codes */ +ush *e; /* list of extra bits for non-simple codes */ +struct huft **t; /* result: starting table */ +int *m; /* maximum lookup bits, returns actual */ +/* Given a list of code lengths and a maximum table size, make a set of + tables to decode that set of codes. Return zero on success, one if + the given code set is incomplete (the tables are still built in this + case), two if the input is invalid (all zero length codes or an + oversubscribed set of lengths), and three if not enough memory. */ +{ + unsigned a; /* counter for codes of length k */ + unsigned c[BMAX+1]; /* bit length count table */ + unsigned f; /* i repeats in table every f entries */ + int g; /* maximum code length */ + int h; /* table level */ + register unsigned i; /* counter, current code */ + register unsigned j; /* counter */ + register int k; /* number of bits in current code */ + int l; /* bits per table (returned in m) */ + register unsigned *p; /* pointer into c[], b[], or v[] */ + register struct huft *q; /* points to current table */ + struct huft r; /* table entry for structure assignment */ + struct huft *u[BMAX]; /* table stack */ + unsigned v[N_MAX]; /* values in order of bit length */ + register int w; /* bits before this table == (l * h) */ + unsigned x[BMAX+1]; /* bit offsets, then code stack */ + unsigned *xp; /* pointer into x */ + int y; /* number of dummy codes added */ + unsigned z; /* number of entries in current table */ + +DEBG("huft1 "); + + /* Generate counts for each bit length */ + memzero(c, sizeof(c)); + p = b; i = n; + do { + c[*p++]++; /* assume all entries <= BMAX */ + } while (--i); + if (c[0] == n) /* null input--all zero length codes */ + { + *t = (struct huft *)NULL; + *m = 0; + return 0; + } + +DEBG("huft2 "); + + /* Find minimum and maximum length, bound *m by those */ + l = *m; + for (j = 1; j <= BMAX; j++) + if (c[j]) + break; + k = j; /* minimum code length */ + if ((unsigned)l < j) + l = j; + for (i = BMAX; i; i--) + if (c[i]) + break; + g = i; /* maximum code length */ + if ((unsigned)l > i) + l = i; + *m = l; + +DEBG("huft3 "); + + /* Adjust last length count to fill out codes, if needed */ + for (y = 1 << j; j < i; j++, y <<= 1) + if ((y -= c[j]) < 0) + return 2; /* bad input: more codes than bits */ + if ((y -= c[i]) < 0) + return 2; + c[i] += y; + +DEBG("huft4 "); + + /* Generate starting offsets into the value table for each length */ + x[1] = j = 0; + p = c + 1; xp = x + 2; + while (--i) { /* note that i == g from above */ + *xp++ = (j += *p++); + } + +DEBG("huft5 "); + + /* Make a table of values in order of bit lengths */ + p = b; i = 0; + do { + if ((j = *p++) != 0) + v[x[j]++] = i; + } while (++i < n); + +DEBG("h6 "); + + /* Generate the Huffman codes and for each, make the table entries */ + x[0] = i = 0; /* first Huffman code is zero */ + p = v; /* grab values in bit order */ + h = -1; /* no tables yet--level -1 */ + w = -l; /* bits decoded == (l * h) */ + u[0] = (struct huft *)NULL; /* just to keep compilers happy */ + q = (struct huft *)NULL; /* ditto */ + z = 0; /* ditto */ +DEBG("h6a "); + + /* go through the bit lengths (k already is bits in shortest code) */ + for (; k <= g; k++) + { +DEBG("h6b "); + a = c[k]; + while (a--) + { +DEBG("h6b1 "); + /* here i is the Huffman code of length k bits for value *p */ + /* make tables up to required level */ + while (k > w + l) + { +DEBG1("1 "); + h++; + w += l; /* previous table always l bits */ + + /* compute minimum size table less than or equal to l bits */ + z = (z = g - w) > (unsigned)l ? l : z; /* upper limit on table size */ + if ((f = 1 << (j = k - w)) > a + 1) /* try a k-w bit table */ + { /* too few codes for k-w bit table */ +DEBG1("2 "); + f -= a + 1; /* deduct codes from patterns left */ + xp = c + k; + while (++j < z) /* try smaller tables up to z bits */ + { + if ((f <<= 1) <= *++xp) + break; /* enough codes to use up j bits */ + f -= *xp; /* else deduct codes from patterns */ + } + } +DEBG1("3 "); + z = 1 << j; /* table entries for j-bit table */ + + /* allocate and link in new table */ + if ((q = (struct huft *)malloc((z + 1)*sizeof(struct huft))) == + (struct huft *)NULL) + { +DEBG1("31 "); + error("malloc failed\n"); + if (h) + huft_free(u[0]); + return 3; /* not enough memory */ + } +DEBG1("4 "); + hufts += z + 1; /* track memory usage */ + *t = q + 1; /* link to list for huft_free() */ + *(t = &(q->v.t)) = (struct huft *)NULL; + u[h] = ++q; /* table starts after link */ + +DEBG1("5 "); + /* connect to last table, if there is one */ + if (h) + { + x[h] = i; /* save pattern for backing up */ + r.b = (uch)l; /* bits to dump before this table */ + r.e = (uch)(16 + j); /* bits in this table */ + r.v.t = q; /* pointer to this table */ + j = i >> (w - l); /* (get around Turbo C bug) */ + u[h-1][j] = r; /* connect to last table */ + } +DEBG1("6 "); + } +DEBG("h6c "); + + /* set up table entry in r */ + r.b = (uch)(k - w); + if (p >= v + n) + r.e = 99; /* out of values--invalid code */ + else if (*p < s) + { + r.e = (uch)(*p < 256 ? 16 : 15); /* 256 is end-of-block code */ + r.v.n = *p++; /* simple code is just the value */ + } + else + { + r.e = (uch)e[*p - s]; /* non-simple--look up in lists */ + r.v.n = d[*p++ - s]; + } +DEBG("h6d "); + + /* fill code-like entries with r */ + f = 1 << (k - w); + for (j = i >> w; j < z; j += f) + q[j] = r; + + /* backwards increment the k-bit code i */ + for (j = 1 << (k - 1); i & j; j >>= 1) + i ^= j; + i ^= j; + + /* backup over finished tables */ + while ((i & ((1 << w) - 1)) != x[h]) + { + h--; /* don't need to update q */ + w -= l; + } +DEBG("h6e "); + } +DEBG("h6f "); + } + +DEBG("huft7 "); + + /* Return true (1) if we were given an incomplete table */ + return y != 0 && g != 1; +} + + + +int huft_free(t) +struct huft *t; /* table to free */ +/* Free the malloc'ed tables built by huft_build(), which makes a linked + list of the tables it made, with the links in a dummy first entry of + each table. */ +{ + register struct huft *p, *q; + + + /* Go through linked list, freeing from the malloced (t[-1]) address. */ + p = t; + while (p != (struct huft *)NULL) + { + q = (--p)->v.t; + free(p); + p = q; + } + return 0; +} + + +int inflate_codes(tl, td, bl, bd) +struct huft *tl, *td; /* literal/length and distance decoder tables */ +int bl, bd; /* number of bits decoded by tl[] and td[] */ +/* inflate (decompress) the codes in a deflated (compressed) block. + Return an error code or zero if it all goes ok. */ +{ + register unsigned e; /* table entry flag/number of extra bits */ + unsigned n, d; /* length and index for copy */ + unsigned w; /* current window position */ + struct huft *t; /* pointer to table entry */ + unsigned ml, md; /* masks for bl and bd bits */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + + /* make local copies of globals */ + b = bb; /* initialize bit buffer */ + k = bk; + w = wp; /* initialize window position */ + + /* inflate the coded data */ + ml = mask_bits[bl]; /* precompute masks for speed */ + md = mask_bits[bd]; + for (;;) /* do until end of block */ + { + NEEDBITS((unsigned)bl) + if ((e = (t = tl + ((unsigned)b & ml))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + if (e == 16) /* then it's a literal */ + { + slide[w++] = (uch)t->v.n; + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } + else /* it's an EOB or a length */ + { + /* exit if end of block */ + if (e == 15) + break; + + /* get length of block to copy */ + NEEDBITS(e) + n = t->v.n + ((unsigned)b & mask_bits[e]); + DUMPBITS(e); + + /* decode distance of block to copy */ + NEEDBITS((unsigned)bd) + if ((e = (t = td + ((unsigned)b & md))->e) > 16) + do { + if (e == 99) + return 1; + DUMPBITS(t->b) + e -= 16; + NEEDBITS(e) + } while ((e = (t = t->v.t + ((unsigned)b & mask_bits[e]))->e) > 16); + DUMPBITS(t->b) + NEEDBITS(e) + d = w - t->v.n - ((unsigned)b & mask_bits[e]); + DUMPBITS(e) + + /* do the copy */ + do { + n -= (e = (e = WSIZE - ((d &= WSIZE-1) > w ? d : w)) > n ? n : e); +#if !defined(NOMEMCPY) && !defined(DEBUG) + if (w - d >= e) /* (this test assumes unsigned comparison) */ + { + memcpy(slide + w, slide + d, e); + w += e; + d += e; + } + else /* do it slow to avoid memcpy() overlap */ +#endif /* !NOMEMCPY */ + do { + slide[w++] = slide[d++]; + } while (--e); + if (w == WSIZE) + { + flush_output(w); + w = 0; + } + } while (n); + } + } + + + /* restore the globals from the locals */ + wp = w; /* restore global window pointer */ + bb = b; /* restore global bit buffer */ + bk = k; + + /* done */ + return 0; +} + + + +int inflate_stored() +/* "decompress" an inflated type 0 (stored) block. */ +{ + unsigned n; /* number of bytes in block */ + unsigned w; /* current window position */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG(""); + return 0; +} + + + +int inflate_fixed() +/* decompress an inflated type 1 (fixed Huffman codes) block. We should + either replace this with a custom decoder, or at least precompute the + Huffman tables. */ +{ + int i; /* temporary variable */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned l[288]; /* length list for huft_build */ + +DEBG(" 1) + { + huft_free(tl); + + DEBG(">"); + return i; + } + + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + return 0; +} + + + +int inflate_dynamic() +/* decompress an inflated type 2 (dynamic Huffman codes) block. */ +{ + int i; /* temporary variables */ + unsigned j; + unsigned l; /* last length */ + unsigned m; /* mask for bit lengths table */ + unsigned n; /* number of lengths to get */ + struct huft *tl; /* literal/length code table */ + struct huft *td; /* distance code table */ + int bl; /* lookup bits for tl */ + int bd; /* lookup bits for td */ + unsigned nb; /* number of bit length codes */ + unsigned nl; /* number of literal/length codes */ + unsigned nd; /* number of distance codes */ +#ifdef PKZIP_BUG_WORKAROUND + unsigned ll[288+32]; /* literal/length and distance code lengths */ +#else + unsigned ll[286+30]; /* literal/length and distance code lengths */ +#endif + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + +DEBG(" 288 || nd > 32) +#else + if (nl > 286 || nd > 30) +#endif + return 1; /* bad lengths */ + +DEBG("dyn1 "); + + /* read in bit-length-code lengths */ + for (j = 0; j < nb; j++) + { + NEEDBITS(3) + ll[border[j]] = (unsigned)b & 7; + DUMPBITS(3) + } + for (; j < 19; j++) + ll[border[j]] = 0; + +DEBG("dyn2 "); + + /* build decoding table for trees--single level, 7 bit lookup */ + bl = 7; + if ((i = huft_build(ll, 19, 19, NULL, NULL, &tl, &bl)) != 0) + { + if (i == 1) + huft_free(tl); + return i; /* incomplete code set */ + } + +DEBG("dyn3 "); + + /* read in literal and distance code lengths */ + n = nl + nd; + m = mask_bits[bl]; + i = l = 0; + while ((unsigned)i < n) + { + NEEDBITS((unsigned)bl) + j = (td = tl + ((unsigned)b & m))->b; + DUMPBITS(j) + j = td->v.n; + if (j < 16) /* length of code in bits (0..15) */ + ll[i++] = l = j; /* save last length in l */ + else if (j == 16) /* repeat last length 3 to 6 times */ + { + NEEDBITS(2) + j = 3 + ((unsigned)b & 3); + DUMPBITS(2) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = l; + } + else if (j == 17) /* 3 to 10 zero length codes */ + { + NEEDBITS(3) + j = 3 + ((unsigned)b & 7); + DUMPBITS(3) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + else /* j == 18: 11 to 138 zero length codes */ + { + NEEDBITS(7) + j = 11 + ((unsigned)b & 0x7f); + DUMPBITS(7) + if ((unsigned)i + j > n) + return 1; + while (j--) + ll[i++] = 0; + l = 0; + } + } + +DEBG("dyn4 "); + + /* free decoding table for trees */ + huft_free(tl); + +DEBG("dyn5 "); + + /* restore the global bit buffer */ + bb = b; + bk = k; + +DEBG("dyn5a "); + + /* build the decoding tables for literal/length and distance codes */ + bl = lbits; + if ((i = huft_build(ll, nl, 257, cplens, cplext, &tl, &bl)) != 0) + { +DEBG("dyn5b "); + if (i == 1) { + error(" incomplete literal tree\n"); + huft_free(tl); + } + return i; /* incomplete code set */ + } +DEBG("dyn5c "); + bd = dbits; + if ((i = huft_build(ll + nl, nd, 0, cpdist, cpdext, &td, &bd)) != 0) + { +DEBG("dyn5d "); + if (i == 1) { + error(" incomplete distance tree\n"); +#ifdef PKZIP_BUG_WORKAROUND + i = 0; + } +#else + huft_free(td); + } + huft_free(tl); + return i; /* incomplete code set */ +#endif + } + +DEBG("dyn6 "); + + /* decompress until an end-of-block code */ + if (inflate_codes(tl, td, bl, bd)) + return 1; + +DEBG("dyn7 "); + + /* free the decoding tables, return */ + huft_free(tl); + huft_free(td); + + DEBG(">"); + return 0; +} + + + +int inflate_block(e) +int *e; /* last block flag */ +/* decompress an inflated block */ +{ + unsigned t; /* block type */ + register ulg b; /* bit buffer */ + register unsigned k; /* number of bits in bit buffer */ + + DEBG(""); + + /* bad block type */ + return 2; +} + + + +int inflate() +/* decompress an inflated entry */ +{ + int e; /* last block flag */ + int r; /* result code */ + unsigned h; /* maximum struct huft's malloc'ed */ + + + /* initialize window, bit buffer */ + wp = 0; + bk = 0; + bb = 0; + + + /* decompress until the last block */ + h = 0; + do { + hufts = 0; + if ((r = inflate_block(&e)) != 0) + return r; + if (hufts > h) + h = hufts; + } while (!e); + + /* Undo too much lookahead. The next read will be byte aligned so we + * can discard unused bits in the last meaningful byte. + */ + while (bk >= 8) { + bk -= 8; + inptr--; + } + + /* flush out slide */ + flush_output(wp); + + + /* return success */ +#ifdef DEBUG + fprintf(stderr, "<%u> ", h); +#endif /* DEBUG */ + return 0; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/lzw.h b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/lzw.h new file mode 100644 index 000000000..b1901f796 --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/lzw.h @@ -0,0 +1,42 @@ +/* lzw.h -- define the lzw functions. + * Copyright (C) 1992-1993 Jean-loup Gailly. + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + */ + +#if !defined(OF) && defined(lint) +# include "gzip.h" +#endif + +#ifndef BITS +# define BITS 16 +#endif +#define INIT_BITS 9 /* Initial number of bits per code */ + +#define LZW_MAGIC "\037\235" /* Magic header for lzw files, 1F 9D */ + +#define BIT_MASK 0x1f /* Mask for 'number of compresssion bits' */ +/* Mask 0x20 is reserved to mean a fourth header byte, and 0x40 is free. + * It's a pity that old uncompress does not check bit 0x20. That makes + * extension of the format actually undesirable because old compress + * would just crash on the new format instead of giving a meaningful + * error message. It does check the number of bits, but it's more + * helpful to say "unsupported format, get a new version" than + * "can only handle 16 bits". + */ + +#define BLOCK_MODE 0x80 +/* Block compresssion: if table is full and compression rate is dropping, + * clear the dictionary. + */ + +#define LZW_RESERVED 0x60 /* reserved bits */ + +#define CLEAR 256 /* flush the dictionary */ +#define FIRST (CLEAR+1) /* first free entry */ + +extern int maxbits; /* max bits per code for LZW */ +extern int block_mode; /* block compress mode -C compatible with 2.0 */ + +extern void lzw OF((int in, int out)); +extern void unlzw OF((int in, int out)); diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/misc.c b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/misc.c new file mode 100644 index 000000000..3b6835b4a --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/misc.c @@ -0,0 +1,437 @@ +/* + * misc.c + * + * This is a collection of several routines from gzip-1.0.3 + * adapted for Linux. + * + * malloc by Hannu Savolainen 1993 + * puts by Nick Holloway 1993 + */ + +#include "gzip.h" +#include "lzw.h" + +#include + +/* + * These are set up by the setup-routine at boot-time: + */ + +struct screen_info { + unsigned char orig_x; + unsigned char orig_y; + unsigned char unused1[2]; + unsigned short orig_video_page; + unsigned char orig_video_mode; + unsigned char orig_video_cols; + unsigned short orig_video_ega_ax; + unsigned short orig_video_ega_bx; + unsigned short orig_video_ega_cx; + unsigned char orig_video_lines; +}; + +/* + * This is set up by the setup-routine at boot-time + */ +#define EXT_MEM_K (*(unsigned short *)0x90002) +#define DRIVE_INFO (*(struct drive_info *)0x90080) +#define SCREEN_INFO (*(struct screen_info *)0x90000) +#define RAMDISK_SIZE (*(unsigned short *)0x901F8) +#define ORIG_ROOT_DEV (*(unsigned short *)0x901FC) +#define AUX_DEVICE_INFO (*(unsigned char *)0x901FF) + +#define EOF -1 + +DECLARE(uch, inbuf, INBUFSIZ); +DECLARE(uch, outbuf, OUTBUFSIZ+OUTBUF_EXTRA); +DECLARE(uch, window, WSIZE); + +unsigned outcnt; +unsigned insize; +unsigned inptr; + +extern char input_data[]; +extern int input_len; + +int input_ptr; + +int method, exit_code, part_nb, last_member; +int test = 0; +int force = 0; +int verbose = 1; +long bytes_in, bytes_out; + +char *output_data; +unsigned long output_ptr; + +extern int end; +long free_mem_ptr = (long)&end; + +int to_stdout = 0; +int hard_math = 0; + +void (*work)(int inf, int outf); +void makecrc(void); + +local int get_method(int); + +char *vidmem = (char *)0xb8000; +int lines, cols; + +void *malloc(int size) +{ + void *p; + + if (size <0) error("Malloc error\n"); + if (free_mem_ptr <= 0) error("Memory error\n"); + + free_mem_ptr = (free_mem_ptr + 3) & ~3; /* Align */ + + p = (void *)free_mem_ptr; + + free_mem_ptr += size; + + if (free_mem_ptr > 0x90000) error("\nOut of memory\n"); + + if (p == NULL) error("malloc = NULL\n"); + return p; +} + +void free(void *where) +{ /* Don't care */ +} + +static void scroll() +{ + int i; + + memcpy ( vidmem, vidmem + cols * 2, ( lines - 1 ) * cols * 2 ); + for ( i = ( lines - 1 ) * cols * 2; i < lines * cols * 2; i += 2 ) + vidmem[i] = ' '; +} + +static void puts(char *s) +{ + int x,y; + char c; + + x = SCREEN_INFO.orig_x; + y = SCREEN_INFO.orig_y; + + while ( ( c = *s++ ) != '\0' ) { + if ( c == '\n' ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } else { + vidmem [ ( x + cols * y ) * 2 ] = c; + if ( ++x >= cols ) { + x = 0; + if ( ++y >= lines ) { + scroll(); + y--; + } + } + } + } + + SCREEN_INFO.orig_x = x; + SCREEN_INFO.orig_y = y; +} + +__ptr_t memset(__ptr_t s, int c, size_t n) +{ + int i; + char *ss = (char*)s; + + for (i=0;i> 8); + } + } + crc = c; + return c ^ 0xffffffffL; /* (instead of ~c for 64-bit machines) */ +} + +/* =========================================================================== + * Clear input and output buffers + */ +void clear_bufs() +{ + outcnt = 0; + insize = inptr = 0; + bytes_in = bytes_out = 0L; +} + +/* =========================================================================== + * Fill the input buffer. This is called only when the buffer is empty + * and at least one byte is really needed. + */ +int fill_inbuf() +{ + int len, i; + + /* Read as much as possible */ + insize = 0; + do { + len = INBUFSIZ-insize; + if (len > (input_len-input_ptr+1)) len=input_len-input_ptr+1; + if (len == 0 || len == EOF) break; + + for (i=0;i>= 1) + { + c = c & 1 ? (c >> 1) ^ e : c >> 1; + if (k & 1) + c ^= e; + } + crc_32_tab[i] = c; + } +} + +void error(char *x) +{ + puts("\n\n"); + puts(x); + puts("\n\n -- System halted"); + + while(1); /* Halt */ +} + +#define STACK_SIZE (4096) + +long user_stack [STACK_SIZE]; + +struct { + long * a; + short b; + } stack_start = { & user_stack [STACK_SIZE] , KERNEL_DS }; + +void decompress_kernel() +{ + if (SCREEN_INFO.orig_video_mode == 7) + vidmem = (char *) 0xb0000; + else + vidmem = (char *) 0xb8000; + + lines = SCREEN_INFO.orig_video_lines; + cols = SCREEN_INFO.orig_video_cols; + + if (EXT_MEM_K < 1024) error("<2M of mem\n"); + + output_data = (char *)1048576; /* Points to 1M */ + output_ptr = 0; + + exit_code = 0; + test = 0; + input_ptr = 0; + part_nb = 0; + + clear_bufs(); + makecrc(); + + puts("Uncompressing Linux..."); + + method = get_method(0); + + work(0, 0); + + puts("done.\n"); + + puts("Now booting the kernel\n"); +} + +/* ======================================================================== + * Check the magic number of the input file and update ofname if an + * original name was given and to_stdout is not set. + * Return the compression method, -1 for error, -2 for warning. + * Set inptr to the offset of the next byte to be processed. + * This function may be called repeatedly for an input file consisting + * of several contiguous gzip'ed members. + * IN assertions: there is at least one remaining compressed member. + * If the member is a zip file, it must be the only one. + */ +local int get_method(in) + int in; /* input file descriptor */ +{ + uch flags; + char magic[2]; /* magic header */ + + magic[0] = (char)get_byte(); + magic[1] = (char)get_byte(); + + method = -1; /* unknown yet */ + part_nb++; /* number of parts in gzip file */ + last_member = 0; + /* assume multiple members in gzip file except for record oriented I/O */ + + if (memcmp(magic, GZIP_MAGIC, 2) == 0 + || memcmp(magic, OLD_GZIP_MAGIC, 2) == 0) { + + work = unzip; + method = (int)get_byte(); + flags = (uch)get_byte(); + if ((flags & ENCRYPTED) != 0) { + error("Input is encrypted\n"); + exit_code = ERROR; + return -1; + } + if ((flags & CONTINUATION) != 0) { + error("Multi part input\n"); + exit_code = ERROR; + if (force <= 1) return -1; + } + if ((flags & RESERVED) != 0) { + error("Input has invalid flags\n"); + exit_code = ERROR; + if (force <= 1) return -1; + } + (ulg)get_byte(); /* Get timestamp */ + ((ulg)get_byte()) << 8; + ((ulg)get_byte()) << 16; + ((ulg)get_byte()) << 24; + + (void)get_byte(); /* Ignore extra flags for the moment */ + (void)get_byte(); /* Ignore OS type for the moment */ + + if ((flags & CONTINUATION) != 0) { + unsigned part = (unsigned)get_byte(); + part |= ((unsigned)get_byte())<<8; + if (verbose) { + error("Input is not part number 1\n"); + } + } + if ((flags & EXTRA_FIELD) != 0) { + unsigned len = (unsigned)get_byte(); + len |= ((unsigned)get_byte())<<8; + while (len--) (void)get_byte(); + } + + /* Get original file name if it was truncated */ + if ((flags & ORIG_NAME) != 0) { + if (to_stdout || part_nb > 1) { + /* Discard the old name */ + while (get_byte() != 0) /* null */ ; + } else { + } /* to_stdout */ + } /* orig_name */ + + /* Discard file comment if any */ + if ((flags & COMMENT) != 0) { + while (get_byte() != 0) /* null */ ; + } + + } else if (memcmp(magic, PKZIP_MAGIC, 2) == 0 && inptr == 2 + && memcmp(inbuf, PKZIP_MAGIC, 4) == 0) { + /* To simplify the code, we support a zip file when alone only. + * We are thus guaranteed that the entire local header fits in inbuf. + */ + inptr = 0; + work = unzip; + if (check_zipfile(in) == -1) return -1; + /* check_zipfile may get ofname from the local header */ + last_member = 1; + + } else if (memcmp(magic, PACK_MAGIC, 2) == 0) { + error("packed input"); + } else if (memcmp(magic, LZW_MAGIC, 2) == 0) { + error("compressed input"); + last_member = 1; + } + if (method == -1) { + error("Corrupted input\n"); + if (exit_code != ERROR) exit_code = part_nb == 1 ? ERROR : WARNING; + return part_nb == 1 ? -1 : -2; + } + return method; +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/piggyback.c b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/piggyback.c new file mode 100644 index 000000000..40284118b --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/piggyback.c @@ -0,0 +1,81 @@ +/* + * linux/zBoot/piggyback.c + * + * (C) 1993 Hannu Savolainen + */ + +/* + * This program reads the compressed system image from stdin and + * encapsulates it into an object file written to the stdout. + */ + +#include +#include +#include + +int main(int argc, char *argv[]) +{ + int c, n=0, len=0; + char tmp_buf[512*1024]; + + struct exec obj = {0x00640107}; /* object header */ + char string_names[] = {"_input_data\0_input_len\0"}; + + struct nlist var_names[2] = /* Symbol table */ + { + { /* _input_data */ + (char *)4, 7, 0, 0, 0 + }, + { /* _input_len */ + (char *)16, 7, 0, 0, 0 + } + }; + + + len = 0; + while ((n = read(0, &tmp_buf[len], sizeof(tmp_buf)-len+1)) > 0) + len += n; + + if (n==-1) + { + perror("stdin"); + exit(-1); + } + + if (len >= sizeof(tmp_buf)) + { + fprintf(stderr, "%s: Input too large\n", argv[0]); + exit(-1); + } + + fprintf(stderr, "Compressed size %d.\n", len); + +/* + * Output object header + */ + obj.a_data = len + sizeof(long); + obj.a_syms = sizeof(var_names); + write(1, (char *)&obj, sizeof(obj)); + +/* + * Output data segment (compressed system & len) + */ + write(1, tmp_buf, len); + write(1, (char *)&len, sizeof(len)); + +/* + * Output symbol table + */ + var_names[1].n_value = len; + write(1, (char *)&var_names, sizeof(var_names)); + +/* + * Output string table + */ + len = sizeof(string_names) + sizeof(len); + write(1, (char *)&len, sizeof(len)); + write(1, string_names, sizeof(string_names)); + + exit(0); + +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/unzip.c b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/unzip.c new file mode 100644 index 000000000..d4a6617cd --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/unzip.c @@ -0,0 +1,180 @@ +/* unzip.c -- decompress files in gzip or pkzip format. + * Copyright (C) 1992-1993 Jean-loup Gailly + * + * Adapted for Linux booting by Hannu Savolainen 1993 + * + * This is free software; you can redistribute it and/or modify it under the + * terms of the GNU General Public License, see the file COPYING. + * + * The code in this file is derived from the file funzip.c written + * and put in the public domain by Mark Adler. + */ + +/* + This version can extract files in gzip or pkzip format. + For the latter, only the first entry is extracted, and it has to be + either deflated or stored. + */ + +#ifndef lint +static char rcsid[] = "$Id: unzip.c,v 0.9 1993/02/10 16:07:22 jloup Exp $"; +#endif + +#include "gzip.h" +#include "crypt.h" + +#include + +/* PKZIP header definitions */ +#define LOCSIG 0x04034b50L /* four-byte lead-in (lsb first) */ +#define LOCFLG 6 /* offset of bit flag */ +#define CRPFLG 1 /* bit for encrypted entry */ +#define EXTFLG 8 /* bit for extended local header */ +#define LOCHOW 8 /* offset of compression method */ +#define LOCTIM 10 /* file mod time (for decryption) */ +#define LOCCRC 14 /* offset of crc */ +#define LOCSIZ 18 /* offset of compressed size */ +#define LOCLEN 22 /* offset of uncompressed length */ +#define LOCFIL 26 /* offset of file name field length */ +#define LOCEXT 28 /* offset of extra field length */ +#define LOCHDR 30 /* size of local header, including sig */ +#define EXTHDR 16 /* size of extended local header, inc sig */ + + +/* Globals */ + +int decrypt; /* flag to turn on decryption */ +char *key; /* not used--needed to link crypt.c */ +int pkzip = 0; /* set for a pkzip file */ +int extended = 0; /* set if extended local header */ + +/* =========================================================================== + * Check zip file and advance inptr to the start of the compressed data. + * Get ofname from the local header if necessary. + */ +int check_zipfile(in) + int in; /* input file descriptors */ +{ + uch *h = inbuf + inptr; /* first local header */ + + /* ifd = in; */ + + /* Check validity of local header, and skip name and extra fields */ + inptr += LOCHDR + SH(h + LOCFIL) + SH(h + LOCEXT); + + if (inptr > insize || LG(h) != LOCSIG) { + error("input not a zip"); + } + method = h[LOCHOW]; + if (method != STORED && method != DEFLATED) { + error("first entry not deflated or stored--can't extract"); + } + + /* If entry encrypted, decrypt and validate encryption header */ + if ((decrypt = h[LOCFLG] & CRPFLG) != 0) { + error("encrypted file\n"); + exit_code = ERROR; + return -1; + } + + /* Save flags for unzip() */ + extended = (h[LOCFLG] & EXTFLG) != 0; + pkzip = 1; + + /* Get ofname and time stamp from local header (to be done) */ + return 0; +} + +/* =========================================================================== + * Unzip in to out. This routine works on both gzip and pkzip files. + * + * IN assertions: the buffer inbuf contains already the beginning of + * the compressed data, from offsets inptr to insize-1 included. + * The magic header has already been checked. The output buffer is cleared. + */ +void unzip(in, out) + int in, out; /* input and output file descriptors */ +{ + ulg orig_crc = 0; /* original crc */ + ulg orig_len = 0; /* original uncompressed length */ + int n; + uch buf[EXTHDR]; /* extended local header */ + + /* ifd = in; + ofd = out; */ + + updcrc(NULL, 0); /* initialize crc */ + + if (pkzip && !extended) { /* crc and length at the end otherwise */ + orig_crc = LG(inbuf + LOCCRC); + orig_len = LG(inbuf + LOCLEN); + } + + /* Decompress */ + if (method == DEFLATED) { + + int res = inflate(); + + if (res == 3) { + error("out of memory"); + } else if (res != 0) { + error("invalid compressed format"); + } + + } else if (pkzip && method == STORED) { + + register ulg n = LG(inbuf + LOCLEN); + + if (n != LG(inbuf + LOCSIZ) - (decrypt ? RAND_HEAD_LEN : 0)) { + + error("length mismatch"); + } + while (n--) { + uch c = (uch)get_byte(); +#ifdef CRYPT + if (decrypt) zdecode(c); +#endif + if (!test) put_char(c); + } + } else { + error("internal error, invalid method"); + } + + /* Get the crc and original length */ + if (!pkzip) { + /* crc32 (see algorithm.doc) + * uncompressed input size modulo 2^32 + */ + for (n = 0; n < 8; n++) { + buf[n] = (uch)get_byte(); /* may cause an error if EOF */ + } + orig_crc = LG(buf); + orig_len = LG(buf+4); + + } else if (extended) { /* If extended header, check it */ + /* signature - 4bytes: 0x50 0x4b 0x07 0x08 + * CRC-32 value + * compressed size 4-bytes + * uncompressed size 4-bytes + */ + for (n = 0; n < EXTHDR; n++) { + buf[n] = (uch)get_byte(); /* may cause an error if EOF */ + } + orig_crc = LG(buf+4); + orig_len = LG(buf+12); + } + + /* Validate decompression */ + if (orig_crc != updcrc(outbuf, 0)) { + error("crc error"); + } + if (orig_len != bytes_out) { + error("length error"); + } + + /* Check if there are more entries in a pkzip file */ + if (pkzip && inptr + 4 < insize && LG(inbuf+inptr) == LOCSIG) { + error("zip file has more than one entry"); + } + extended = pkzip = 0; /* for next file */ +} diff --git a/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/xtract.c b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/xtract.c new file mode 100644 index 000000000..c698a5c6e --- /dev/null +++ b/gems-kernel.git/source/THIRDPARTY/linux-old/zBoot/xtract.c @@ -0,0 +1,82 @@ +/* + * linux/zBoot/xtract.c + * + * Copyright (C) 1993 Hannu Savolainen + * + * Extracts the system image and writes it to the stdout. + * based on tools/build.c by Linus Torvalds + */ + +#include /* fprintf */ +#include +#include /* contains exit */ +#include /* unistd.h needs this */ +#include +#include +#include /* contains read/write */ +#include +#include +#include + +#define GCC_HEADER 1024 + +#define STRINGIFY(x) #x + +void die(char * str) +{ + fprintf(stderr,"%s\n",str); + exit(1); +} + +void usage(void) +{ + die("Usage: xtract system [ | gzip | piggyback > piggy.s]"); +} + +int main(int argc, char ** argv) +{ + int i,c,id, sz; + char buf[1024]; + char major_root, minor_root; + struct stat sb; + + struct exec *ex = (struct exec *)buf; + + if (argc != 2) + usage(); + + if ((id=open(argv[1],O_RDONLY,0))<0) + die("Unable to open 'system'"); + if (read(id,buf,GCC_HEADER) != GCC_HEADER) + die("Unable to read header of 'system'"); + if (N_MAGIC(*ex) != ZMAGIC) + die("Non-GCC header of 'system'"); + + sz = N_SYMOFF(*ex) - GCC_HEADER + 4; /* +4 to get the same result than tools/build */ + + fprintf(stderr, "System size is %d\n", sz); + + while (sz) + { + int l, n; + + l = sz; + if (l > sizeof(buf)) l = sizeof(buf); + + if ((n=read(id, buf, l)) !=l) + { + if (n == -1) + perror(argv[1]); + else + fprintf(stderr, "Unexpected EOF\n"); + + die("Can't read system"); + } + + write(1, buf, l); + sz -= l; + } + + close(id); + return(0); +}