From aab94e608561d27884c3b95514c307292a124122 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:10:54 -0500 Subject: [PATCH] Import 1.3.96 --- CREDITS | 4 + Documentation/Changes | 81 +- Documentation/Configure.help | 228 ++- Documentation/filesystems/affs.txt | 23 + Documentation/ramdisk.txt | 18 +- Documentation/riscom8.txt | 2 +- Makefile | 10 +- arch/alpha/kernel/entry.S | 14 +- arch/alpha/kernel/traps.c | 18 +- arch/alpha/mm/fault.c | 2 +- arch/i386/kernel/traps.c | 14 +- arch/i386/mm/fault.c | 2 +- arch/m68k/amiga/amifb.c | 16 +- arch/m68k/amiga/config.c | 4 +- arch/m68k/amiga/ksyms.c | 2 +- arch/m68k/atari/atafb.c | 10 +- arch/m68k/atari/ataints.c | 4 +- arch/m68k/atari/atakeyb.c | 4 +- arch/m68k/atari/atapart.c | 4 +- arch/m68k/atari/atasound.c | 2 +- arch/m68k/atari/config.c | 4 +- arch/m68k/atari/stdma.c | 8 +- arch/m68k/boot/amiga/bootstrap.c | 2 +- arch/m68k/boot/atari/bootstrap.c | 6 +- arch/m68k/console/fbcon.c | 192 ++- arch/m68k/defconfig | 1 + arch/m68k/fpsp040/bindec.S | 4 +- arch/m68k/fpsp040/decbin.S | 10 +- arch/m68k/fpsp040/fpsp.h | 2 +- arch/m68k/fpsp040/gen_except.S | 2 +- arch/m68k/fpsp040/get_op.S | 6 +- arch/m68k/fpsp040/res_func.S | 12 +- arch/m68k/fpsp040/round.S | 8 +- arch/m68k/fpsp040/satan.S | 2 +- arch/m68k/fpsp040/scale.S | 2 +- arch/m68k/fpsp040/sint.S | 6 +- arch/m68k/fpsp040/skeleton.S | 2 +- arch/m68k/fpsp040/slogn.S | 2 +- arch/m68k/fpsp040/ssin.S | 6 +- arch/m68k/fpsp040/stan.S | 4 +- arch/m68k/fpsp040/tbldo.S | 2 +- arch/m68k/fpsp040/util.S | 4 +- arch/m68k/fpsp040/x_bsun.S | 2 +- arch/m68k/fpsp040/x_operr.S | 4 +- arch/m68k/fpsp040/x_ovfl.S | 2 +- arch/m68k/fpsp040/x_snan.S | 2 +- arch/m68k/fpsp040/x_store.S | 2 +- arch/m68k/fpsp040/x_unfl.S | 4 +- arch/m68k/ifpsp060/TEST.DOC | 4 +- arch/m68k/ifpsp060/fpsp.doc | 2 +- arch/m68k/ifpsp060/iskeleton.S | 2 +- arch/m68k/kernel/console.c | 17 +- arch/m68k/kernel/entry.S | 4 - arch/m68k/kernel/head.S | 6 +- arch/m68k/kernel/sys_m68k.c | 2 +- arch/m68k/kernel/traps.c | 2 +- arch/m68k/mm/init.c | 4 +- arch/m68k/mm/memory.c | 37 +- arch/sparc/boot/bare.S | 2 +- arch/sparc/boot/empirical.h | 2 +- arch/sparc/config.in | 51 +- arch/sparc/defconfig | 8 +- arch/sparc/kernel/Makefile | 4 +- arch/sparc/kernel/entry.S | 69 +- arch/sparc/kernel/etrap.S | 2 +- arch/sparc/kernel/head.S | 2 +- arch/sparc/kernel/idprom.c | 2 +- arch/sparc/kernel/ioport.c | 2 +- arch/sparc/kernel/irq.c | 2 +- arch/sparc/kernel/process.c | 5 +- arch/sparc/kernel/ptrace.c | 801 ++++++++++ arch/sparc/kernel/setup.c | 13 +- arch/sparc/kernel/signal.c | 18 +- arch/sparc/kernel/smp.c | 4 +- arch/sparc/kernel/sparc-stub.c | 2 +- arch/sparc/kernel/sunos_ioctl.c | 41 +- arch/sparc/kernel/sys_sparc.c | 2 +- arch/sparc/kernel/sys_sunos.c | 37 +- arch/sparc/kernel/systbls.S | 6 +- arch/sparc/kernel/traps.c | 7 +- arch/sparc/kernel/wuf.S | 2 +- arch/sparc/mm/fault.c | 2 +- arch/sparc/mm/generic.c | 3 +- arch/sparc/mm/init.c | 2 +- arch/sparc/mm/srmmu.c | 10 +- arch/sparc/prom/memory.c | 2 +- arch/sparc/prom/palloc.c | 2 +- drivers/block/amiflop.c | 6 +- drivers/block/ataflop.c | 30 +- drivers/block/floppy.c | 2 +- drivers/block/genhd.c | 75 +- drivers/block/rd.c | 14 +- drivers/char/Makefile | 24 +- drivers/char/amigamouse.c | 2 +- drivers/char/lp_intern.c | 2 +- drivers/char/lp_m68k.c | 4 +- drivers/char/mem.c | 6 +- drivers/char/misc.c | 10 + drivers/char/pty.c | 8 +- drivers/char/riscom8.c | 24 +- drivers/char/riscom8.h | 2 +- drivers/char/riscom8_reg.h | 2 +- drivers/net/3c509.c | 5 - drivers/net/Config.in | 2 +- drivers/net/Makefile | 24 + drivers/net/Space.c | 12 + drivers/net/a2065.c | 2 +- drivers/net/ariadne.c | 2 +- drivers/net/ariadne.h | 4 +- drivers/net/atarilance.c | 4 +- drivers/net/de4x5.c | 784 ++++++---- drivers/net/de4x5.h | 44 +- drivers/sbus/Makefile | 11 + drivers/sbus/char/Makefile | 13 + drivers/{ => sbus}/char/suncons.c | 126 +- drivers/sbus/char/sunkbd.c | 1317 +++++++++++++++++ drivers/sbus/char/sunkeymap.c | 262 ++++ drivers/sbus/char/sunkeymap.map | 372 +++++ drivers/{ => sbus}/char/sunmouse.c | 0 drivers/sbus/char/sunserial.c | 2196 ++++++++++++++++++++++++++++ drivers/sbus/char/sunserial.h | 420 ++++++ drivers/scsi/Makefile | 40 + drivers/scsi/NCR5380.h | 2 +- drivers/scsi/a2091.c | 1 + drivers/scsi/a2091.h | 4 +- drivers/scsi/a3000.c | 1 + drivers/scsi/a3000.h | 4 +- drivers/scsi/atari_NCR5380.c | 22 +- drivers/scsi/atari_scsi.c | 26 +- drivers/scsi/atari_scsi.h | 4 +- drivers/scsi/gvp11.c | 1 + drivers/scsi/gvp11.h | 4 +- drivers/scsi/hosts.c | 36 +- drivers/scsi/scsi.c | 2 +- drivers/scsi/wd33c93.c | 887 ++++++++--- drivers/scsi/wd33c93.h | 78 +- drivers/sound/dmasound.c | 12 +- fs/Config.in | 8 +- fs/Makefile | 8 + fs/affs/amigaffs.c | 24 +- fs/affs/amigaffs.h | 2 +- fs/affs/file.c | 2 +- fs/affs/inode.c | 6 +- fs/binfmt_aout.c | 2 +- fs/buffer.c | 32 +- fs/fat/buffer.c | 6 +- fs/fat/cache.c | 21 +- fs/fat/misc.c | 4 +- fs/fat/msbuffer.h | 2 + fs/fcntl.c | 4 + fs/filesystems.c | 5 + fs/isofs/inode.c | 10 +- fs/locks.c | 9 + fs/nfs/README | 2 +- fs/nfs/dir.c | 59 +- fs/nfs/inode.c | 1 + fs/proc/array.c | 7 +- fs/proc/inode.c | 2 +- fs/proc/mem.c | 18 +- fs/ufs/ufs_dir.c | 29 +- fs/ufs/ufs_file.c | 17 +- fs/ufs/ufs_inode.c | 2 +- fs/ufs/ufs_namei.c | 6 +- fs/ufs/ufs_super.c | 39 +- fs/ufs/ufs_symlink.c | 8 +- include/asm-i386/smp.h | 2 +- include/asm-m68k/atarihw.h | 8 +- include/asm-m68k/atariints.h | 4 +- include/asm-m68k/atomic.h | 17 +- include/asm-m68k/bitops.h | 21 +- include/asm-m68k/bootinfo.h | 4 +- include/asm-m68k/dma.h | 2 +- include/asm-m68k/font.h | 5 +- include/asm-m68k/pgtable.h | 33 +- include/asm-m68k/system.h | 2 +- include/asm-m68k/traps.h | 2 +- include/asm-sparc/asi.h | 2 +- include/asm-sparc/auxio.h | 2 +- include/asm-sparc/bsderrno.h | 2 +- include/asm-sparc/cache.h | 2 +- include/asm-sparc/cypress.h | 2 +- include/asm-sparc/dma.h | 2 +- include/asm-sparc/ecc.h | 2 +- include/asm-sparc/elf.h | 4 +- include/asm-sparc/head.h | 2 +- include/asm-sparc/irq.h | 2 +- include/asm-sparc/mbus.h | 2 +- include/asm-sparc/memreg.h | 2 +- include/asm-sparc/mman.h | 2 +- include/asm-sparc/mostek.h | 2 +- include/asm-sparc/mp.h | 32 - include/asm-sparc/mpmbox.h | 2 +- include/asm-sparc/mxcc.h | 2 +- include/asm-sparc/openprom.h | 2 +- include/asm-sparc/oplib.h | 2 +- include/asm-sparc/pconf.h | 2 +- include/asm-sparc/pgtsrmmu.h | 2 +- include/asm-sparc/ptrace.h | 10 +- include/asm-sparc/signal.h | 2 +- include/asm-sparc/solerrno.h | 2 +- include/asm-sparc/traps.h | 2 +- include/asm-sparc/unistd.h | 2 +- include/asm-sparc/vac-ops.h | 2 +- include/asm-sparc/vaddrs.h | 2 +- include/asm-sparc/viking.h | 2 +- include/linux/blk.h | 2 +- include/linux/config.h | 2 + include/linux/console.h | 2 + include/linux/fb.h | 89 +- include/linux/genhd.h | 59 +- include/linux/if_arp.h | 1 + include/linux/major.h | 6 +- include/linux/miscdevice.h | 2 + include/linux/mm.h | 5 +- include/linux/proc_fs.h | 4 + include/linux/sched.h | 3 + include/linux/skbuff.h | 6 +- include/linux/timex.h | 34 +- include/linux/ufs_fs.h | 2 +- include/net/tcp.h | 5 - init/main.c | 39 + ipc/shm.c | 2 +- kernel/exit.c | 37 +- kernel/sched.c | 34 +- kernel/time.c | 8 +- mm/filemap.c | 6 +- mm/memory.c | 2 +- net/README | 4 +- net/ax25/af_ax25.c | 25 +- net/ax25/ax25_in.c | 7 +- net/ax25/ax25_out.c | 24 +- net/ax25/ax25_timer.c | 4 +- net/bridge/br.c | 2 + net/core/dev.c | 18 +- net/core/iovec.c | 2 +- net/core/skbuff.c | 10 +- net/ipv4/Config.in | 2 +- net/ipv4/icmp.c | 356 ++++- net/ipv4/ip_fragment.c | 1 - net/ipv4/ip_sockglue.c | 26 +- net/ipv4/tcp.c | 229 ++- net/socket.c | 36 +- scripts/lxdialog/menubox.c | 2 +- scripts/lxdialog/util.c | 4 +- 244 files changed, 9005 insertions(+), 1515 deletions(-) create mode 100644 Documentation/filesystems/affs.txt create mode 100644 arch/sparc/kernel/ptrace.c create mode 100644 drivers/sbus/char/Makefile rename drivers/{ => sbus}/char/suncons.c (95%) create mode 100644 drivers/sbus/char/sunkbd.c create mode 100644 drivers/sbus/char/sunkeymap.c create mode 100644 drivers/sbus/char/sunkeymap.map rename drivers/{ => sbus}/char/sunmouse.c (100%) create mode 100644 drivers/sbus/char/sunserial.c create mode 100644 drivers/sbus/char/sunserial.h delete mode 100644 include/asm-sparc/mp.h diff --git a/CREDITS b/CREDITS index 918ed4877179..aee049e9f0ec 100644 --- a/CREDITS +++ b/CREDITS @@ -1372,3 +1372,7 @@ D: Miscellaneous kernel fixes S: 3078 Sulphur Spring Court S: San Jose, California 95148 S: USA + +# Don't add your name here, unless you really _are_ after Leonard +# alphabetically. Leonard is very proud of being the last entry, +# and this file really _is_ supposed to be in alphabetic order. diff --git a/Documentation/Changes b/Documentation/Changes index 667dd82b5202..d8c525eb1aec 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -2,9 +2,9 @@ This document contains a list of the latest releases of the most important packages for Linux as well as instructions for newcomers to the 1.3.x series of kernels. -Last updated: Apr 17, 1996. -Authors: Alessandro Sigala (ssigala@globalnet.it) and Chris Ricker -(gt1355b@prism.gatech.edu). +Last updated: Apr 27, 1996. +Author: Chris Ricker (gt1355b@prism.gatech.edu), based on the original by +Alessandro Sigala (ssigala@globalnet.it. Note: Due to time constraints, Alessandro is getting out of the Changes business and I'll be picking up the job. Be gentle while I get my feet @@ -14,11 +14,11 @@ Current Releases **************** - Kernel modules Stable: 1.3.57, Exp: 1.3.69f -- PPP daemon Stable: 2.2.0e, Exp: 2.2.0f-BETA6 +- PPP daemon Stable: 2.2.0f - Dynamic linker (ld.so) 1.7.14 - GNU CC 2.7.2 - Binutils 2.6.0.12 -- Linux C Library Stable: 5.2.18, Exp: 5.3.9, Alpha: 5.3.11 +- Linux C Library Stable: 5.2.18, Exp: 5.3.9, Alpha: 5.3.12 - Linux C++ Library 2.7.1.4 - Termcap 2.0.8 - Procps 0.99a @@ -45,13 +45,17 @@ PPP daemon and utilities ======================== To use the PPP protocol with the 1.3.x linux kernel, you need to -upgrade the PPP package to version 2.2.0e or the experimental 2.2.0f. +upgrade the PPP package to version 2.2.0f. Procps utilities ================ In the latest 1.3.x kernel releases the /proc filesystem structure -was changed, so you need to upgrade the Procps package to version 0.99a. +was changed, so you need to upgrade the Procps package to version +0.99a. In the very latest kernels, /proc has changed again. There's +not yet an officially updated version of procps, so make due with +0.99a; you might want to look for one of the patches floating around to +update 0.99a for use with 1.3.94 and later kernels. Installation notes ****************** @@ -83,6 +87,27 @@ and recompile those programs (a patch for make is included in the file `release.libc-.5.3.9', and the address to obtain a precompiled binary is at the end of this file). + Also, the libc-5.3.x line has a known security hole relating to +rlogin. Unless you really need to upgrade for some reason, just stick +with 5.2.18 for now. + + If you're getting an error message that is something to the effect of + + `fcntl_setlk() called by process 123 with broken flock() emulation' + + then you need to upgrade to libc-5.2.18 as well. A proper (in other +words, BSD-style ;-) flock system call was added in 1.3.x, and older +libc's will now give this error. It doesn't *really* matter, so you +can just ignore it. If it really annoys you, upgrade libc (and +recompile any static binaries you might have that are linked against +the old libc). If you're feeling lazy, just comment out + + ` printk(KERN_WARNING +"fcntl_setlk() called by process %d with broken flock() + emulation\n", current->pid);' + + in linux/fs/locks.c and recompile. + The Termcap Library =================== @@ -152,9 +177,8 @@ PPP driver ========== You need to be running a pppd from ppp-2.2.0.tar.gz or greater. The -latest stable release is 2.2.0e and is available at -ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz, -along with a patch necessary to make it compile. +latest stable release is 2.2.0f and is available at +ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz. Named pipes =========== @@ -168,6 +192,16 @@ words to that effect scroll across your screen hundreds of times. To fix, upgrade to ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.60.tar.gz. + If you're trying to run NCSA httpd, you have to set pre-spawning of +daemons to zero, as it incorrectly assumes SunOS behavior. Some people +have said that the Apache httpd has problems with the new named pipes, +but I've never noticed any. + + The new named pipe behavior also causes problems with Hylafax. If +you're running the hylafax daemon, it will just keep eating up CPU time +until you have no idle time free. I'm not currently aware of any +patches that eliminate this behavior. + Uugetty ======= @@ -283,6 +317,25 @@ ftp://ftp.funet.fi/pub/Linux/PEOPLE/Linus/subsystems/quota/all.tar.gz. This will compile just fine after you copy its mntent.h over to /usr/include/mntent.h. +APM support +=========== + + Advanced Power Management (APM) support has been added to the kernel +as well. APM, which is primarily of use in laptops, provides access to +battery status information and may help to conserve battery power. The +support files can be found in +ftp://tsx-11.mit.edu/pub/linux/packages/laptops/apm/apmd-2.2.tar.gz + +iBCS and Dosemu +=============== + + For a version of iBCS that works with 1.3.x kernels, grab +ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz + + For a version of Dosemu that works (well, at least as well as DOS +ever works ;-), get +ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz. + Please send info about any other packages that 1.3.x "broke" or about any new features of 1.3.x that require extra packages for use to Chris Ricker (gt1355b@prism.gatech.edu). @@ -333,7 +386,7 @@ ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74.patched.tar.gz Patched make binary: ftp://sunsite.unc.edu/pub/Linux/devel/make/make-3.74-direntfix-elf.tgz -The 5.2.18 release: +The stable 5.2.18 release: ftp://sunsite.unc.edu/pub/Linux/GCC/libc-5.2.18.bin.tar.gz Installation notes: ftp://sunsite.unc.edu/pub/Linux/GCC/release.libc-5.2.18 @@ -367,9 +420,7 @@ PPP Daemon and utilities ======================== The latest public release: -ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp-2.2.0e.tar.gz -The latest experimental release: -ftp://ftp.sii.com/pub/linux/ppp-2.2/ppp-2.2.0f.BETA6.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz Procps utilities ================ @@ -386,8 +437,6 @@ SysVinit utilities ================== At the time of writing: -ftp://sunsite.unc.edu/pub/Linux/Incoming/sysvinit-2.60.tar.gz -Next location: ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.60.tar.gz Util-linux diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 9cdc643e1d0e..8e5850e69251 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1155,7 +1155,8 @@ CONFIG_SCSI_MULTI_LUN Unit Number), e.g. a CD jukebox, you should say Y here so that all will be found by the SCSI driver. An SCSI device with multiple LUNs acts logically like multiple SCSI devices. The vast majority of SCSI - devices have only one LUN, and so most people can say N here. + devices have only one LUN, and so most people can say N here and + should in fact do so, because it is safer. Verbose SCSI error reporting (kernel size +=12K) CONFIG_SCSI_CONSTANTS @@ -1163,16 +1164,6 @@ CONFIG_SCSI_CONSTANTS understand if you enable this; it will enlarge your kernel by about 12KB. If in doubt, say Y. -Automatic Disk Geometry Translation -CONFIG_SCSI_AUTO_BIOSP - When this is set to Y, Linux will examine the partition table to - determine the mapping used under the other operating systems (e.g. - DOS), and set these parameters to the determined values, or if the - disk has no valid partition table, to an optimal value. -### -### What are the advantages/disadvantages? What is a safe value? -### - AdvanSys SCSI support CONFIG_SCSI_ADVANSYS This is a driver for all SCSI host adaptors manufactured by @@ -1607,18 +1598,19 @@ CONFIG_PPP_LOTS STRIP (Starmode Radio IP) support CONFIG_STRIP - Say Y if you have a Metricom radio and intend to use Starmode Radio IP. - STRIP is a radio protocol developed for the MosquitoNet project - (http://mosquitonet.stanford.edu/) to send Internet traffic using Metricom - radios. Metricom radios are small, battery powered, 100kbit/sec packet - radio transceivers, about the size and weight of a cellular telephone. - (You may also have heard them called "Metricom modems" but we avoid the - term "modem" because it misleads many people into thinking that you can - plug a Metricom modem into a phone line and use it as a modem.) - You can use STRIP on any Linux machine with a serial port, although - it is obviously most useful for people with laptop computers. If you - think you might get a Metricom radio in the future, there is no harm in - saying yes to STRIP now, except that it makes the kernel a bit bigger. + Say Y if you have a Metricom radio and intend to use Starmode Radio + IP. STRIP is a radio protocol developed for the MosquitoNet project + (http://mosquitonet.stanford.edu/) to send Internet traffic using + Metricom radios. Metricom radios are small, battery powered, + 100kbit/sec packet radio transceivers, about the size and weight of + a cellular telephone. (You may also have heard them called + "Metricom modems" but we avoid the term "modem" because it misleads + many people into thinking that you can plug a Metricom modem into a + phone line and use it as a modem.) You can use STRIP on any Linux + machine with a serial port, although it is obviously most useful for + people with laptop computers. If you think you might get a Metricom + radio in the future, there is no harm in saying yes to STRIP now, + except that it makes the kernel a bit bigger. WIC (Radio IP bridge) CONFIG_WIC @@ -1632,37 +1624,51 @@ Z8530 SCC kiss emulation driver for AX.2 CONFIG_SCC These cards are used to connect your Linux box to an amateur radio and communicate with other computers. If you want to use this, read - Documentation/networking/z8530drv.txt and the HAM-HOWTO, available via - ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. + Documentation/networking/z8530drv.txt and the HAM-HOWTO, available + via ftp (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. PLIP (parallel port) support CONFIG_PLIP - PLIP (Parallel Line Internet Protocol) is mainly used to create a - mini network consisting of two local machines. The parallel ports - are connected using a "null printer" or "Turbo Laplink" cable (you - can find the wiring in drivers/net/README?.plip). This works also - if one of the two machines runs DOS and has some PLIP software - installed, e.g. NCSA telnet. If you want to use this, say Y and - read the NET-2-HOWTO, available via ftp (user: anonymous) in - sunsite.unc.edu:/pub/Linux/docs/HOWTO. You need to say N or M to - "parallel printer support" below if you say Y here. Also, you might - have to edit the file drivers/net/Space.c and adjust the parallel - port's IRQ (there is a small number of Interrupt ReQuest lines in - your computer that are used by the periphery to gain the CPU's - attention - often a source of trouble if two different devices are - mistakenly configured to use the same IRQ. If you have the /proc - filesystem installed (see below), you can say "cat /proc/interrupts" - to see what the different IRQs are currently used for.) This option - enlarges your kernel by about 8kB. If unsure, say N. If you want to - compile this as a module ( = code which can be inserted in and - removed from the running kernel whenever you want), say M here and - read Documentation/modules.txt as well as - Documentation/networking/net-modules.txt. If you want to use both a - parallel printer and PLIP, it is best to compile both drivers as - modules. + PLIP (Parallel Line Internet Protocol) is used to create a mini + network consisting of two (or, rarely, more) local machines. The + parallel ports (the connectors at the computers with 25 holes) are + connected using "null printer" or "Turbo Laplink" cables which can + transmit 4 bits at a time or using special PLIP cables, to be used + on bidirectional parallel ports only, which can transmit 8 bits at a + time (you can find the wiring of these cables in + drivers/net/README?.plip). The cables can be up to 15m long. This + works also if one of the machines runs DOS and has some PLIP + software installed, e.g. NCSA telnet. If you want to use this, say + Y and read the PLIP mini-HOWTO, available via ftp (user: anonymous) + in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the + NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the + PLIP protocol was changed and this PLIP driver won't work together + with the PLIP support in Linux versions 1.0.x. This option enlarges + your kernel by about 8kB. If you want to compile this as a module ( + = code which can be inserted in and removed from the running kernel + whenever you want), say M here and read Documentation/modules.txt as + well as Documentation/networking/net-modules.txt. If you want to use + both a parallel printer and PLIP, there are two cases: 1) If the + printer and the PLIP cable are to use the same parallel port + (presumably because you have just one), it is best to compile both + drivers as modules and load and unload them as needed. 2) To use + different parallel ports for the printer and the PLIP cable, you can + say Y to the printer driver, specify the base address of the + parallel port(s) to use for the printer(s) with the "lp" kernel + command line option. (See the documentation of your boot loader + (lilo or loadlin) about how to pass options to the kernel at boot + time. The lilo procedure is also explained in the SCSI-HOWTO, + available via ftp (user: anonymous) in + sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses + as well as the syntax of the "lp" command line option can be found + in drivers/char/lp.c. You can then say Y to this PLIP driver or, + preferably, M in which case Documentation/networking/net-modules.txt + tells you how to specify the port and IRQ to be used by PLIP at + module load time. + It's safe to say N here. EQL (serial line load balancing) support CONFIG_EQUALIZER @@ -2052,8 +2058,8 @@ CONFIG_EEXPRESS_PRO EtherExpress support CONFIG_EEXPRESS - If you have a network (ethernet) card of this type, say Y and read - the Ethernet-HOWTO, available via ftp (user: anonymous) in + If you have an EtherExpress16 network (ethernet) card, say Y and + read the Ethernet-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the Intel EtherExpress16 card used to be regarded as a very poor choice because the driver was very unreliable. We now have a new driver @@ -2523,7 +2529,7 @@ CONFIG_QUOTA usage (also called diskquotas). Currently, it works only for the ext2 filesystem; you need the software available via ftp (user: anonymous) in - ftp.funet.fi:/pub/Linux/People/Linux/subsystems/quota/ in order to + ftp.funet.fi:/pub/Linux/PEOPLE/Linus/subsystems/quota/ in order to use it. Probably this is only useful for multi user systems. If unsure, say N. @@ -2784,6 +2790,61 @@ CONFIG_SYSV_FS Documentation/modules.txt. If you haven't heard about all of this before, it's safe to say N. +BSD UFS filesystem support (read only) +CONFIG_UFS_FS + BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD + and NeXTstep) use a filesystem called UFS. Some System V Unixes can + create and mount partitions and diskettes using this filesystem + as well. Enabling this option allows you to mount these partitions + and diskettes read-only. If you only intend to mount files from + some other Unix over the network using NFS, you don't need the + UFS filesystem support (but you need nfs filesystem support + obviously). Note that this option is generally not needed for + floppies, since a good portable way to transport files and + directories between unixes (and even other operating systems) + is given by the tar program ("man tar"). When accessing NeXTstep + files, you may need to convert them from the NeXT character set + to the Latin1 character set; use GNU recode for this purpose. + Say Y to build UFS support into your kernel. If you want to compile + this as a module ( = code which can be inserted in and removed from + the running kernel whenever you want), say M here and read + Documentation/modules.txt. If you haven't heard about all of this + before, it's safe to say N. + +BSD disklabel (FreeBSD partition tables) support +CONFIG_BSD_DISKLABEL + FreeBSD uses its own partition scheme on your PC. It requires only + one entry in the primary partition table of your disk and manages it + similarly to DOS extended partitions, putting in its first sector a + new partition table in disklabel format. Enabling this option allow + you to read these disklabels and further mount FreeBSD partitions on + your Linux box if you also have configured BSD ufs filesystem + support. If you don't know what all this is about, say N. + +SMD disklabel (Sun partition tables) support +CONFIG_SMD_DISKLABEL + Like most systems, SunOS uses its own partition table format, + incompatible with each other. Enabling this option allow you to read + these partition tables and further mount SunOS disks on your Linux + box if you also have configured BSD ufs filesystem support. This is + mainly used to carry data from a Sparc under SunOS to your Linux box + via a removable medium like magneto-optical or ZIP drives. If you + don't know what all this is about, say N. + +AFFS filesystem support +CONFIG_AFFS_FS + AFFS is the filesystem used on Commodore Amiga computers. People + running Linux on other systems can say N here. + +UFS filesystem support (read only) +CONFIG_UFS_FS + UFS (Unix File System) is the way files are organized on Sun Solaris + harddisks and floppies. If you want to be able to read those, say Y + here. Note that this option is generally not needed for floppies, + since a good portable way to transport files and directories between + unixes (and even other operating systems) is given by the tar + program ("man tar"). + SMB filesystem support (to mount WfW shares etc..) CONFIG_SMB_FS SMB (Server Message Buffer) is the protocol Windows for Workgroups @@ -2817,6 +2878,24 @@ CONFIG_NCP_FS removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. +Amiga FFS filesystem support (read only) +CONFIG_AFFS_FS + The Fast File System (FFS) is the common filesystem used on harddisks + by Amiga (tm) Systems since AmigaOS Version 1.3 (34.20). It's also + possible to mount Diskfiles used by the Un*X Amiga Emulator by Bernd + Schmidt (http://www-users.informatik.rwth-aachen.de/~crux/uae.html) + If you want to do this, you will also need the loopback device + support. Because it's in an early development state, the AFFS is + read only. Say Y if you want to be able to read files from an Amiga + FFS partition of your harddrive. Amiga floppies however cannot be + read with this driver due to an incompatibility of the floppy + controller used in an Amiga and the standard floppy controller in + PCs and workstations. Read Documentation/filesystems/affs.txt. This + filesystem is also available as a module ( = code which can be + inserted in and removed from the running kernel whenever you + want). If you want to compile it as a module, say M here and read + Documentation/modules.txt. If unsure, say N. + Standard/generic serial support CONFIG_SERIAL This selects whether you want to include the driver for the standard @@ -2896,12 +2975,23 @@ CONFIG_PRINTER sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile this as a module ( = code which can be inserted in and removed from the running kernel whenever you want), say M here and read - Documentation/modules.txt. If you intend to use PLIP (Parallel Line - Internet Protocol is mainly used to create a mini network by - connecting the parallel ports of two local machines) or a ethernet - network pocket adaptor attaching to the parallel port and a parallel - printer as well, you should compile both drivers as modules because - the drivers both want the same resources. + Documentation/modules.txt. If you want to use both a parallel + printer and PLIP, there are two cases: 1) If the printer and the + PLIP cable are to use the same parallel port (presumably because you + have just one), it is best to compile both drivers as modules and + load and unload them as needed. 2) To use different parallel ports + for the printer and the PLIP cable, you can say Y to this printer + driver, specify the base address of the parallel port(s) to use for + the printer(s) with the "lp" kernel command line option. (See the + documentation of your boot loader (lilo or loadlin) about how to + pass options to the kernel at boot time. The lilo procedure is also + explained in the SCSI-HOWTO, available via ftp (user: anonymous) in + sunsite.unc.edu:/pub/Linux/docs/HOWTO.) The standard base addresses + as well as the syntax of the "lp" command line option can be found + in drivers/char/lp.c. You can then say Y to the PLIP driver or, + preferably, M in which case Documentation/networking/net-modules.txt + tells you how to specify the port and IRQ to be used by PLIP at + module load time. Logitech busmouse support CONFIG_BUSMOUSE @@ -2975,10 +3065,11 @@ CONFIG_ATIXL_BUSMOUSE Support for user miscellaneous modules CONFIG_UMISC - This option forces generic miscellaneous minor device support in the - kernel, and allows later loading of user miscellaneous device modules, - such as drivers for optic pens and touchscreens. Unless you need such - specific modules, or are willing to write/test one, just say N. + This option forces generic miscellaneous minor device support in the + kernel, and allows later loading of user miscellaneous device + modules, such as drivers for optic pens and touchscreens. Unless you + need such specific modules, or are willing to write/test one, just + say N. QIC-02 tape support CONFIG_QIC02_TAPE @@ -3196,7 +3287,8 @@ CONFIG_ISDN_PPP This enables synchronous PPP via ISDN. This protocol is used by Cisco or Sun for example. You will need a special version of pppd (called ipppd) for using this feature. See - Documentation/isdn/README.syncppp for more information. + Documentation/isdn/README.syncppp and Documentation/isdn/syncPPP.FAQ + for more information. Support generic MP (RFC 1717) CONFIG_ISDN_MPP @@ -3230,10 +3322,11 @@ CONFIG_ISDN_DRV_TELES PCBIT-D support CONFIG_ISDN_DRV_PCBIT This enables support for the PCBIT ISDN-cards. This card is - manufactured in Portugal by Octal. For running this card, - additional firmware is necessary, which has to be downloaded into - the card using a utility which is distributed separately. - See Documentation/isdn/README for more information. + manufactured in Portugal by Octal. For running this card, additional + firmware is necessary, which has to be downloaded into the card + using a utility which is distributed separately. See + Documentation/isdn/README and Documentation/isdn/README.pcbit for + more information. Support for AP1000 multicomputer CONFIG_AP1000 @@ -3311,4 +3404,5 @@ CONFIG_AP1000 # LocalWords: Starmode Metricom MosquitoNet mosquitonet kbit nfsroot Digiboard # LocalWords: DIGI Xe Xeve digiboard UMISC touchscreens mtu ethernets HBAs MEX # LocalWords: Shifflett netcom js jshiffle WIC DECchip ELCP EtherPower dst RTC -# LocalWords: rtc SMP +# LocalWords: rtc SMP lp Digi Intl RightSwitch DGRS dgrs AFFS Amiga UFS SDL AP +# LocalWords: Solaris RISCom riscom syncPPP PCBIT pcbit sparc anu au diff --git a/Documentation/filesystems/affs.txt b/Documentation/filesystems/affs.txt new file mode 100644 index 000000000000..996769f7b851 --- /dev/null +++ b/Documentation/filesystems/affs.txt @@ -0,0 +1,23 @@ +Linux can read, but not write, Amiga FFS partitions. + +Mount options are + size has the size in 512 byte blocks of the mounted medium. + +Case is significant in filename matching, different to real AFFS. + + +Command line example + mount Archive/Amiga/Workbench3.1.adf /mnt -t affs -o loop,size=1760 + mount /dev/sda3 /Amiga -t affs + +/etc/fstab example + /dev/sdb5 /d/f affs ro + +This file system will probably be writeable in future releases. + +It's not possible to read floppy disks with a normal PC or workstation +due to an incompatibility to the Amiga floppy controller. + +If you are interested in an Amiga Emulator for Linux, look at + +http://www-users.informatik.rwth-aachen.de/~crux/uae.html diff --git a/Documentation/ramdisk.txt b/Documentation/ramdisk.txt index eacc911bd58f..05a42ee9fa0a 100644 --- a/Documentation/ramdisk.txt +++ b/Documentation/ramdisk.txt @@ -28,10 +28,15 @@ is no longer used, new command line parameters exist, and the behavior of the "rdev -r" or "ramsize" (usually a symbolic link to "rdev") command has changed. -The old "ramdisk=" is now obsolete. The kernel will ignore -such old commands, and thus they will be passed on through to the init -program, which will then complain. You should remove any of these old -style commands from config files such as "/etc/lilo.config". +Also, the new ramdisk supports up to 16 ramdisks out of the box, and can +be reconfigured in rd.c to support up to 255 ramdisks. To use multiple +ramdisk support with your system, run 'mknod /dev/ramX b 1 X' and chmod +(to change it's permissions) it to your liking. The default /dev/ram(disk) +uses minor #1, so start with ram2 and go from there. + +The old "ramdisk=" has been changed to "ramdisk_size=" +to make it clearer. The original "ramdisk=" has been kept around +for compatiblity reasons, but it will probably be removed in 2.1.x. The new ramdisk also has the ability to load compressed ramdisk images, allowing one to squeeze more programs onto an average installation or @@ -92,6 +97,11 @@ two floppy configuration, you will need the chance to switch disks, and thus "prompt_ramdisk=1" can be used. Since this is the default value, it doesn't really need to be specified. + ramdisk_size=N + ============== + +This parameter tells the ramdisk driver to set up ramdisks of Nk size. The +default is 4096 (4MB). 3) Using "rdev -r" With New Kernels ----------------------------------- diff --git a/Documentation/riscom8.txt b/Documentation/riscom8.txt index 69ed969bbf9d..6157bb11d70f 100644 --- a/Documentation/riscom8.txt +++ b/Documentation/riscom8.txt @@ -5,7 +5,7 @@ NOTE: English is not my native language. I'm sorry for any mistakes in this text. -Misc. notes for RISCom/8 serial driver, in no particule order :) +Misc. notes for RISCom/8 serial driver, in no particular order :) 1) This driver can support up to 4 boards at time. Use string "riscom8=0xXXX,0xXXX,0xXXX,0xXXX" at LILO prompt, for diff --git a/Makefile b/Makefile index 19718a2e015c..5224ca1e6ed6 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 3 -SUBLEVEL = 95 +SUBLEVEL = 96 ARCH = i386 @@ -142,6 +142,10 @@ ifdef CONFIG_PCI DRIVERS := $(DRIVERS) drivers/pci/pci.a endif +ifdef CONFIG_SBUS +DRIVERS := $(DRIVERS) drivers/sbus/sbus.a +endif + include arch/$(ARCH)/Makefile ifdef SMP @@ -202,7 +206,7 @@ newversion: @if [ ! -f .version ]; then \ echo 1 > .version; \ else \ - expr `cat .version` + 1 > .version; \ + expr 0`cat .version` + 1 > .version; \ fi include/linux/compile.h: $(CONFIGURATION) include/linux/version.h newversion @@ -326,7 +330,7 @@ mrproper: clean rm -f .hdepend rm -f $(TOPDIR)/include/linux/modversions.h rm -f $(TOPDIR)/include/linux/modules/* - + distclean: mrproper rm -f core `find . \( -name '*.orig' -o -name '*.rej' -o -name '*~' \ diff --git a/arch/alpha/kernel/entry.S b/arch/alpha/kernel/entry.S index 1eb9c84169b8..a483e41af6d0 100644 --- a/arch/alpha/kernel/entry.S +++ b/arch/alpha/kernel/entry.S @@ -541,7 +541,7 @@ strace: jsr $26,($27),syscall_trace bsr $1,undo_switch_stack - /* get the system call number and the argments back.. */ + /* get the system call number and the arguments back.. */ ldq $0,0($30) ldq $16,SP_OFF+24($30) ldq $17,SP_OFF+32($30) @@ -574,9 +574,9 @@ strace_success: .align 3 strace_error: - ldq $9,0($30) /* old syscall nr (zero if success) */ - beq $9,strace_success - ldq $10,72($30) /* .. and this a3 */ + ldq $19,0($30) /* old syscall nr (zero if success) */ + beq $19,strace_success + ldq $20,72($30) /* .. and this a3 */ subq $31,$0,$0 /* with error in v0 */ addq $31,1,$1 /* set a3 for errno return */ @@ -584,13 +584,15 @@ strace_error: stq $1,72($30) /* a3 for return */ bsr $1,do_switch_stack + bis $19,$19,$9 /* save old syscall number */ + bis $20,$20,$10 /* save old a3 */ lda $27,syscall_trace jsr $26,($27),syscall_trace + bis $9,$9,$19 + bis $10,$10,$20 bsr $1,undo_switch_stack bis $31,$31,$26 /* tell "ret_from_sys_call" that we can restart */ - bis $9,$9,$19 /* .. old syscall nr */ - bis $10,$10,$20 /* .. old a3 */ br $31,ret_from_sys_call .align 3 diff --git a/arch/alpha/kernel/traps.c b/arch/alpha/kernel/traps.c index 45bc114f8698..fd4575af7a0e 100644 --- a/arch/alpha/kernel/traps.c +++ b/arch/alpha/kernel/traps.c @@ -67,7 +67,7 @@ asmlinkage void do_entArith(unsigned long summary, unsigned long write_mask, printk("%s: arithmetic trap at %016lx: %02lx %016lx\n", current->comm, regs.pc, summary, write_mask); die_if_kernel("Arithmetic fault", ®s, 0); - send_sig(SIGFPE, current, 1); + force_sig(SIGFPE, current); } asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, @@ -82,7 +82,7 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, if (ptrace_cancel_bpt(current)) { regs.pc -= 4; /* make pc point to former bpt */ } - send_sig(SIGTRAP, current, 1); + force_sig(SIGTRAP, current); break; case 2: /* gentrap */ @@ -97,7 +97,7 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, case GEN_INTOVF: case GEN_INTDIV: case GEN_FLTOVF: case GEN_FLTDIV: case GEN_FLTUND: case GEN_FLTINV: case GEN_FLTINE: - send_sig(SIGFPE, current, 1); + force_sig(SIGFPE, current); break; case GEN_DECOVF: @@ -118,14 +118,14 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, case GEN_SUBRNG5: case GEN_SUBRNG6: case GEN_SUBRNG7: - send_sig(SIGILL, current, 1); + force_sig(SIGILL, current); break; } break; case 1: /* bugcheck */ case 3: /* FEN fault */ - send_sig(SIGILL, current, 1); + force_sig(SIGILL, current); break; case 4: /* opDEC */ @@ -142,12 +142,12 @@ asmlinkage void do_entIF(unsigned long type, unsigned long a1, unsigned long a2, * (we don't do no stinkin' VAX fp...) */ if (!alpha_fp_emul(regs.pc - 4)) - send_sig(SIGFPE, current, 1); + force_sig(SIGFPE, current); break; } } #endif - send_sig(SIGILL, current, 1); + force_sig(SIGILL, current); break; default: @@ -314,7 +314,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg } if (verify_area(dir, va, size)) { *pc_addr -= 4; /* make pc point to faulting insn */ - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } @@ -362,7 +362,7 @@ asmlinkage void do_entUnaUser(void * va, unsigned long opcode, unsigned long reg case 0x2d: stq_u(*reg_addr, va); break; /* stq */ default: *pc_addr -= 4; /* make pc point to faulting insn */ - send_sig(SIGBUS, current, 1); + force_sig(SIGBUS, current); return; } diff --git a/arch/alpha/mm/fault.c b/arch/alpha/mm/fault.c index 33331dca03a5..ba4d99e51626 100644 --- a/arch/alpha/mm/fault.c +++ b/arch/alpha/mm/fault.c @@ -97,7 +97,7 @@ bad_area: printk("%s: memory violation at pc=%08lx rp=%08lx (bad address = %08lx)\n", current->comm, regs.pc, regs.r26, address); die_if_kernel("oops", ®s, cause); - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } /* diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 4557b285f519..31210b5b3276 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c @@ -40,9 +40,7 @@ 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); \ + force_sig(signr, tsk); \ die_if_kernel(str,regs,error_code); \ } @@ -187,7 +185,7 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code) die_if_kernel("general protection",regs,error_code); current->tss.error_code = error_code; current->tss.trap_no = 13; - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); } asmlinkage void do_nmi(struct pt_regs * regs, long error_code) @@ -209,9 +207,7 @@ asmlinkage void do_debug(struct pt_regs * regs, long error_code) handle_vm86_debug((struct vm86_regs *) regs, error_code); return; } - if (current->flags & PF_PTRACED) - current->blocked &= ~(1 << (SIGTRAP-1)); - send_sig(SIGTRAP, current, 1); + force_sig(SIGTRAP, current); current->tss.trap_no = 1; current->tss.error_code = error_code; if ((regs->cs & 3) == 0) { @@ -260,7 +256,7 @@ void math_error(void) __asm__ __volatile__("fnsave %0":"=m" (task->tss.i387.hard)); task->flags&=~PF_USEDFPU; - send_sig(SIGFPE, task, 1); + force_sig(SIGFPE, task); task->tss.trap_no = 16; task->tss.error_code = 0; @@ -327,7 +323,7 @@ asmlinkage void math_emulate(long arg) { printk("math-emulation not enabled and no coprocessor found.\n"); printk("killing %s.\n",current->comm); - send_sig(SIGFPE,current,1); + force_sig(SIGFPE,current); schedule(); } diff --git a/arch/i386/mm/fault.c b/arch/i386/mm/fault.c index 623344bee839..76556f8cfc54 100644 --- a/arch/i386/mm/fault.c +++ b/arch/i386/mm/fault.c @@ -104,7 +104,7 @@ bad_area: current->tss.cr2 = address; current->tss.error_code = error_code; current->tss.trap_no = 14; - send_sig(SIGSEGV, current, 1); + force_sig(SIGSEGV, current); return; } /* diff --git a/arch/m68k/amiga/amifb.c b/arch/m68k/amiga/amifb.c index 7efd8143ca5b..0e74040f98f3 100644 --- a/arch/m68k/amiga/amifb.c +++ b/arch/m68k/amiga/amifb.c @@ -184,7 +184,7 @@ ------------------------------------------- Since there are much more parameters for the Amiga display than for the - frame buffer interface, there must be some depencies among the Amiga display + frame buffer interface, there must be some dependencies among the Amiga display parameters. Here's what I found out: - ddfstrt and ddfstop are best aligned to 64 pixels. @@ -1138,13 +1138,13 @@ static void check_default_mode(void); * * History: * - 03 Jan 95: Original version my Martin Schaller: The TT driver and - * all the device independant stuff + * all the device independent stuff * - 09 Jan 95: Roman: I've added the hardware abstraction (hw_switch) * and wrote the Falcon, ST(E), and External drivers * based on the original TT driver. * - 26 Jan 95: Geert: Amiga version * - 19 Feb 95: Hamish: added Jes Sorensen's ECS patches to the Amiga - * frame buffer device. This provdes ECS support and the + * frame buffer device. This provides ECS support and the * following screen-modes: multiscan, multiscan-lace, * super72, super72-lace, dblntsc, dblpal & euro72. * He suggests that we remove the old AGA screenmodes, @@ -1255,7 +1255,7 @@ static __inline__ void mono_init_vblank(void) * bplcon0, diwstrt, diwstop, ddfstrt, ddfstop registers (a few others could * be used as well). -wjr * - * The code now supports ECS aswell, except for FMODE all control registers + * The code now supports ECS as well, except for FMODE all control registers * are the same under ECS. A special color-table has to be generated though. * -Jes */ @@ -1782,7 +1782,7 @@ static void mono_video_setup (char *options, int *ints) * 0x02c -> 0x12c. NTSC overscan uses values > 256 too. However counter * is 8 bit, will wrap. RKM 1.1 suggests use of a WAIT(0x00,0xff), * WAIT(x,y-0x100) pair to handle this case. This is WRONG - must use - * WAIT(0xe2,0xff) to ensure that wrap occures by next copper + * WAIT(0xe2,0xff) to ensure that wrap occurred by next copper * instruction. Argghh! * * 4. RKM 1.1 suggests Copper-wait x positions are in range [0,0xe2]. @@ -2392,7 +2392,7 @@ static void mono_amifb_interrupt(int irq, struct pt_regs *fp, void *data) static ushort cursorstate = 0; /* I *think* that you should only change display lists on long frame. - * At least it goes awfully perculiar on my A500 without the following + * At least it goes awfully peculiar on my A500 without the following * test. Not really in a position to test this hypothesis, so sorry * for the slow scrolling, all you flicker-fixed souls */ @@ -2490,6 +2490,7 @@ static int mono_amiga_fb_get_fix(struct fb_fix_screeninfo *fix, int con) fix->ypanstep = 0; fix->ywrapstep = 1; + fix->line_length = 0; for (i = 0; i < arraysize(fix->reserved); i++) fix->reserved[i] = 0; return(0); @@ -2567,6 +2568,7 @@ static void mono_amiga_fb_set_disp(int con) disp[con].type_aux = fix.type_aux; disp[con].ypanstep = fix.ypanstep; disp[con].ywrapstep = fix.ywrapstep; + disp[con].line_length = fix.line_length; disp[con].can_soft_blank = 1; disp[con].inverse = mono_amifb_inverse; } @@ -3164,6 +3166,7 @@ static int aga_encode_fix(struct fb_fix_screeninfo *fix, else fix->ywrapstep = 0; + fix->line_length = 0; for (i = 0; i < arraysize(fix->reserved); i++) fix->reserved[i] = 0; @@ -4460,6 +4463,7 @@ static void amiga_fb_set_disp(int con) disp[con].type_aux = fix.type_aux; disp[con].ypanstep = fix.ypanstep; disp[con].ywrapstep = fix.ywrapstep; + disp[con].line_length = fix.line_length; disp[con].can_soft_blank = 1; disp[con].inverse = amifb_inverse; } diff --git a/arch/m68k/amiga/config.c b/arch/m68k/amiga/config.c index a4e4f01e8ce5..6637407d2803 100644 --- a/arch/m68k/amiga/config.c +++ b/arch/m68k/amiga/config.c @@ -370,7 +370,7 @@ void amiga_sched_init (isrfunc timer_routine) time_finetune = finetune+0.5; #endif - ciab.cra &= 0xC0; /* turn off timer A, continous mode, from Eclk */ + ciab.cra &= 0xC0; /* turn off timer A, continuous mode, from Eclk */ ciab.talo = jiffy_ticks % 256; ciab.tahi = jiffy_ticks / 256; /* CIA interrupts when counter underflows, so adjust ticks by 1 */ @@ -378,7 +378,7 @@ void amiga_sched_init (isrfunc timer_routine) /* install interrupt service routine for CIAB Timer A */ /* - * Please don't change this to use ciaa, as it interfers with the + * Please don't change this to use ciaa, as it interferes with the * SCSI code. We'll have to take a look at this later */ #if 0 diff --git a/arch/m68k/amiga/ksyms.c b/arch/m68k/amiga/ksyms.c index d100f668f573..2dd68450b3ca 100644 --- a/arch/m68k/amiga/ksyms.c +++ b/arch/m68k/amiga/ksyms.c @@ -7,7 +7,7 @@ static struct symbol_table mach_amiga_symbol_table = { * Add things here when you find the need for it. */ - /* examble + /* example X(something_you_need), */ diff --git a/arch/m68k/atari/atafb.c b/arch/m68k/atari/atafb.c index 34cccce532c1..3320795e0eaa 100644 --- a/arch/m68k/atari/atafb.c +++ b/arch/m68k/atari/atafb.c @@ -118,7 +118,7 @@ static struct atari_fb_par { } hw; } current_par; -/* Don't calculate an own resoltion, and thus don't change the one found when +/* Don't calculate an own resolution, and thus don't change the one found when * booting (currently used for the Falcon to keep settings for internal video * hardware extensions (e.g. ScreenBlaster) */ static int DontCalcRes = 0; @@ -786,7 +786,7 @@ static struct pixel_clock { short right, hsync, left; /* standard timing in clock cycles, not pixel */ /* hsync initialized in falcon_detect() */ short sync_mask; /* or-mask for hw.falcon.sync to set this clock */ - short control_mask; /* dito, for hw.falcon.vid_control */ + short control_mask; /* ditto, for hw.falcon.vid_control */ } f25 = {25175000, 39722, 18, 0, 42, 0x0, VCO_CLOCK25}, f32 = {32000000, 31250, 18, 0, 42, 0x0, 0}, @@ -1683,7 +1683,7 @@ static int falcon_detect( void ) falcon_get_par(&par); falcon_encode_var(&atari_fb_predefined[0], &par); - /* Detectet mode is always the "autodetect" slot */ + /* Detected mode is always the "autodetect" slot */ return 1; } @@ -2303,7 +2303,7 @@ static void atari_fb_set_par( struct atari_fb_par *par ) /* =========================================================== */ -/* ============== Hardware Independant Functions ============= */ +/* ============== Hardware Independent Functions ============= */ /* =========================================================== */ @@ -2992,7 +2992,7 @@ void atari_video_setup( char *options, int *ints ) } if (*int_str) { - /* Format to config extendet internal video hardware like OverScan: + /* Format to config extended internal video hardware like OverScan: ",internal:;;;;" Explanation: type to switch on higher resolution diff --git a/arch/m68k/atari/ataints.c b/arch/m68k/atari/ataints.c index 3e9e6a3e986e..497d17603985 100644 --- a/arch/m68k/atari/ataints.c +++ b/arch/m68k/atari/ataints.c @@ -5,7 +5,7 @@ * Added support for TT interrupts; setup for TT SCU (may someone has * twiddled there and we won't get the right interrupts :-() * - * Major change: The device-independant code in m68k/ints.c didn't know + * Major change: The device-independent code in m68k/ints.c didn't know * about non-autovec ints yet. It hardcoded the number of possible ints to * 7 (IRQ1...IRQ7). But the Atari has lots of non-autovec ints! I made the * number of possible ints a constant defined in interrupt.h, which is @@ -321,7 +321,7 @@ SYMBOL_NAME_STR(falcon_hblhandler) ": movel %sp@+,%d0 rte"); -/* Defined in entry.S; only increments 'num_suprious' */ +/* Defined in entry.S; only increments 'num_spurious' */ asmlinkage void bad_interrupt(void); extern void atari_microwire_cmd( int cmd ); diff --git a/arch/m68k/atari/atakeyb.c b/arch/m68k/atari/atakeyb.c index 337f2700e138..124eb403ce7b 100644 --- a/arch/m68k/atari/atakeyb.c +++ b/arch/m68k/atari/atakeyb.c @@ -302,7 +302,7 @@ static void atakeyb_rep( unsigned long ignore ) * it's really hard to decide whether they're mouse or keyboard bytes. Since * overruns usually occur when moving the Atari mouse rapidly, they're seen as * mouse bytes here. If this is wrong, only a make code of the keyboard gets - * lost, which isn't too bad. Loosing a break code would be desasterous, + * lost, which isn't too bad. Loosing a break code would be disastrous, * because then the keyboard repeat strikes... */ @@ -541,7 +541,7 @@ void ikbd_reset(void) ikbd_write(cmd, 2); - /* if allswell code 0xF1 is returned, else the break codes of + /* if all's well code 0xF1 is returned, else the break codes of all keys making contact */ } diff --git a/arch/m68k/atari/atapart.c b/arch/m68k/atari/atapart.c index 64e3bdb65a5a..72ba09b975d6 100644 --- a/arch/m68k/atari/atapart.c +++ b/arch/m68k/atari/atapart.c @@ -98,7 +98,7 @@ atari_check_partition (struct gendisk *hd, unsigned int dev) break; } if (memcmp( xrs->part[1].id, "XGM", 3 ) != 0) { - printk( "\nID of extended partion is not XGM!\n" ); + printk( "\nID of extended partition is not XGM!\n" ); brelse( xbh ); break; } @@ -128,7 +128,7 @@ atari_check_partition (struct gendisk *hd, unsigned int dev) if ( part_fmt!=1 ) /* no extended partitions -> test ICD-format */ { pi = &rs->icdpart[0]; - /* sanity check: no ICD format if first partion invalid */ + /* sanity check: no ICD format if first partition invalid */ if (memcmp (pi->id, "GEM", 3) == 0 || memcmp (pi->id, "BGM", 3) == 0 || memcmp (pi->id, "RAW", 3) == 0 ) diff --git a/arch/m68k/atari/atasound.c b/arch/m68k/atari/atasound.c index 555cf30bb00d..0d8df381d070 100644 --- a/arch/m68k/atari/atasound.c +++ b/arch/m68k/atari/atasound.c @@ -81,7 +81,7 @@ void atari_mksound (unsigned int count, unsigned int ticks) if (count == 750 && ticks == HZ/8) { /* Special case: These values are used by console.c to - * generate the console bell. They are catched here and the + * generate the console bell. They are cached here and the * sound actually generated is somehow special: it uses the * generator B and an envelope. No timer is needed therefore * and the bell doesn't disturb an other ongoing sound. diff --git a/arch/m68k/atari/config.c b/arch/m68k/atari/config.c index a8ac7cdb89b8..fc7ad0cd65aa 100644 --- a/arch/m68k/atari/config.c +++ b/arch/m68k/atari/config.c @@ -650,7 +650,7 @@ int atari_hwclk( int op, struct hwclk_time *t ) tos_version = is_medusa ? 0xfff : *(unsigned short *)0xff000002; ctrl = RTC_READ(RTC_CONTROL); /* control registers are - * independant from the UIP */ + * independent from the UIP */ if (op) { /* write: prepare values */ @@ -1109,7 +1109,7 @@ void atari_get_model(char *model) int atari_get_hardware_list(char *buffer) { - int len = 0; + int len = 0, i; for (i = 0; i < boot_info.num_memory; i++) len += sprintf (buffer+len, "\t%3ld MB at 0x%08lx (%s)\n", diff --git a/arch/m68k/atari/stdma.c b/arch/m68k/atari/stdma.c index af387a9340c9..356068b62263 100644 --- a/arch/m68k/atari/stdma.c +++ b/arch/m68k/atari/stdma.c @@ -59,13 +59,13 @@ static void stdma_int (int irq, struct pt_regs *fp, void *dummy); /* * Function: void stdma_lock( isrfunc isr, void *data ) * - * Purpose: Trys to get a lock on the ST-DMA chip that is used by more + * Purpose: Tries to get a lock on the ST-DMA chip that is used by more * then one device driver. Waits on stdma_wait until lock is free. * stdma_lock() may not be called from an interrupt! You have to * get the lock in your main routine and release it when your * request is finished. * - * Inputs: A interupt function that is called until the lock is + * Inputs: A interrupt function that is called until the lock is * released. * * Returns: nothing @@ -126,7 +126,7 @@ void stdma_release(void) * * Inputs: none * - * Returns: 0 if noone is waiting, != 0 otherwise + * Returns: 0 if no one is waiting, != 0 otherwise * */ @@ -182,7 +182,7 @@ void stdma_init(void) /* * Function: void stdma_int() * - * Purpose: The interupt routine for the ST-DMA. It calls the isr + * Purpose: The interrupt routine for the ST-DMA. It calls the isr * registered by stdma_lock(). * */ diff --git a/arch/m68k/boot/amiga/bootstrap.c b/arch/m68k/boot/amiga/bootstrap.c index ffd38365214c..54b2534d9c4e 100644 --- a/arch/m68k/boot/amiga/bootstrap.c +++ b/arch/m68k/boot/amiga/bootstrap.c @@ -290,7 +290,7 @@ int main(int argc, char *argv[]) } /* if we suspect that Kickstart is zkicked, - modify the entry to show 512K more at the botton of RAM */ + modify the entry to show 512K more at the bottom of RAM */ if (mh.mh_Lower == (void *)0x00280020) { mh.mh_Lower = (void *)0x00200000; printf("ZKick detected.\n"); diff --git a/arch/m68k/boot/atari/bootstrap.c b/arch/m68k/boot/atari/bootstrap.c index 6ace8d2a0c88..fc0a7473ee60 100644 --- a/arch/m68k/boot/atari/bootstrap.c +++ b/arch/m68k/boot/atari/bootstrap.c @@ -15,7 +15,7 @@ ** (Andreas) ** 14 Nov 1994 YANML (Yet Another New Memory Layout :-) kernel ** start address is KSTART_ADDR + PAGE_SIZE, this -** does not need the ugly klugde with +** does not need the ugly kludge with ** -fwritable-strings (++andreas) ** 09 Sep 1994 Adapted to the new memory layout: All the boot_info entry ** mentions all ST-Ram and the mover is located somewhere @@ -684,7 +684,7 @@ int main(int argc, char *argv[]) && memcmp (&kexec_elf.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0) { elf_kernel = 1; - /* A few plausability checks */ + /* A few plausibility checks */ if (kexec_elf.e_type != ET_EXEC || kexec_elf.e_machine != EM_68K || kexec_elf.e_version != EV_CURRENT) { @@ -703,7 +703,7 @@ int main(int argc, char *argv[]) kexec_elf.e_phnum * sizeof (*kernel_phdrs)) != kexec_elf.e_phnum * sizeof (*kernel_phdrs)) { - fprintf (stderr, "Unable to read programm headers from %s\n", + fprintf (stderr, "Unable to read program headers from %s\n", kernel_name); boot_exit (EXIT_FAILURE); } diff --git a/arch/m68k/console/fbcon.c b/arch/m68k/console/fbcon.c index 347db0330175..77e81b2172dd 100644 --- a/arch/m68k/console/fbcon.c +++ b/arch/m68k/console/fbcon.c @@ -47,6 +47,7 @@ #include #include #include +#include #include #include @@ -578,7 +579,7 @@ static void fbcon_setup(int con, int setcol, int cls) if (p->fontwidth != 8) panic("fbcon_setup: No support for fontwidth != 8"); - if (divides(p->ywrapstep, p->fontheight)) + if (divides(p->ywrapstep, p->fontheight) && divides(p->fontheight, p->var.yres_virtual)) p->scrollmode = SCROLL_YWRAP; else if (divides(p->ypanstep, p->fontheight) && p->var.yres_virtual >= p->var.yres+p->fontheight) @@ -588,11 +589,15 @@ static void fbcon_setup(int con, int setcol, int cls) conp->vc_cols = p->var.xres/p->fontwidth; conp->vc_rows = p->var.yres/p->fontheight; + p->vrows = p->var.yres_virtual/p->fontheight; conp->vc_can_do_color = p->var.bits_per_pixel != 1; #ifdef CONFIG_FBCON_MONO if (p->var.bits_per_pixel == 1) { - p->next_line = p->var.xres_virtual>>3; + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; p->next_plane = 0; p->dispsw = &dispsw_mono; } else @@ -621,14 +626,22 @@ static void fbcon_setup(int con, int setcol, int cls) #endif /* CONFIG_FBCON_IPLAN2 */ #ifdef CONFIG_FBCON_ILBM if (p->type == FB_TYPE_INTERLEAVED_PLANES && p->type_aux != 2) { - p->next_line = p->type_aux; - p->next_plane = p->type_aux/p->var.bits_per_pixel; + if (p->line_length) { + p->next_line = p->line_length*p->var.bits_per_pixel; + p->next_plane = p->line_length; + } else { + p->next_line = p->type_aux; + p->next_plane = p->type_aux/p->var.bits_per_pixel; + } p->dispsw = &dispsw_ilbm; } else #endif /* CONFIG_FBCON_ILBM */ #ifdef CONFIG_FBCON_PLANES if (p->type == FB_TYPE_PLANES) { - p->next_line = p->var.xres_virtual>>3; + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; p->next_plane = p->var.yres_virtual*p->next_line; p->dispsw = &dispsw_plan; } else @@ -670,7 +683,10 @@ fail: #ifdef CONFIG_FBCON_MONO printk("fbcon_setup: type %d (aux %d) not supported, trying mono\n", p->type, p->type_aux); - p->next_line = (p->var.xres_virtual)>>3; + if (p->line_length) + p->next_line = p->line_length; + else + p->next_line = p->var.xres_virtual>>3; p->next_plane = 0; p->var.bits_per_pixel = 1; p->dispsw = &dispsw_mono; @@ -708,7 +724,7 @@ fail: * equivalents for large blits, and thats important to the lowest level of * a graphics driver. Question is whether some scheme with the blitter * would be faster. I suspect not for simple text system - not much - * asynchronisity. + * asynchrony. * * Code is very simple, just gruesome expansion. Basic strategy is to * increase data moved/cleared at each step to 16 bytes to reduce @@ -732,7 +748,7 @@ fail: subl #65536,d0 replaced by clrw d0; subql #1,d0 for dbcc addal is faster than addaw movep is rather expensive compared to ordinary move's - some functions rewritten in C for clearity, no speed loss */ + some functions rewritten in C for clarity, no speed loss */ static __inline__ void *mymemclear_small(void *s, size_t count) { @@ -1375,10 +1391,10 @@ static __inline__ u_short dup2w(u_char c) static __inline__ int real_y(struct display *p, int y) { - int rows = p->conp->vc_rows; + int rows = p->vrows; y += p->yscroll; - return(y < rows || p->scrollmode != SCROLL_YWRAP ? y : y-rows); + return(y < rows ? y : y-rows); } @@ -1398,7 +1414,7 @@ static int fbcon_clear(struct vc_data *conp, int sy, int sx, int height, /* Split blits that cross physical y_wrap boundary */ - y_break = conp->vc_rows-p->yscroll; + y_break = p->vrows-p->yscroll; if (sy < y_break && sy+height-1 >= y_break) { u_int b = y_break-sy; p->dispsw->clear(conp, p, real_y(p, sy), sx, b, width); @@ -1513,8 +1529,8 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) switch (p->scrollmode) { case SCROLL_YWRAP: p->yscroll += count; - if (p->yscroll >= conp->vc_rows) /* Deal with wrap */ - p->yscroll -= conp->vc_rows; + if (p->yscroll >= p->vrows) /* Deal with wrap */ + p->yscroll -= p->vrows; p->var.xoffset = 0; p->var.yoffset = p->yscroll*p->fontheight; p->var.vmode |= FB_VMODE_YWRAP; @@ -1523,8 +1539,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) case SCROLL_YPAN: p->yscroll += count; - if (p->yscroll*p->fontheight+p->var.yres > - p->var.yres_virtual) { + if (p->yscroll+conp->vc_rows > p->vrows) { p->dispsw->bmove(p, p->yscroll, 0, 0, 0, b-count, conp->vc_cols); p->yscroll = 0; @@ -1553,7 +1568,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) case SCROLL_YWRAP: p->yscroll -= count; if (p->yscroll < 0) /* Deal with wrap */ - p->yscroll += conp->vc_rows; + p->yscroll += p->vrows; p->var.xoffset = 0; p->var.yoffset = p->yscroll*p->fontheight; p->var.vmode |= FB_VMODE_YWRAP; @@ -1563,8 +1578,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) case SCROLL_YPAN: p->yscroll -= count; if (p->yscroll < 0) { - p->yscroll = (p->var.yres_virtual-p->var.yres)/ - p->fontheight; + p->yscroll = p->vrows-conp->vc_rows; p->dispsw->bmove(p, 0, 0, p->yscroll+count, 0, b-count, conp->vc_cols); } @@ -1582,7 +1596,7 @@ static int fbcon_scroll(struct vc_data *conp, int t, int b, int dir, int count) fbcon_bmove(conp, t, 0, t+count, 0, b-t-count, conp->vc_cols); /* Fixed bmove() should end Arno's frustration with copying? - * Confusius says: + * Confucius says: * Man who copies in wrong direction, end up with trashed data */ fbcon_clear(conp, t, 0, count, conp->vc_cols); @@ -1625,7 +1639,7 @@ static int fbcon_bmove(struct vc_data *conp, int sy, int sx, int dy, int dx, * Recursive invocations don't need to erase the cursor over and * over again, so we use fbcon_bmove_rec() */ - fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, conp->vc_rows-p->yscroll); + fbcon_bmove_rec(p, sy, sx, dy, dx, height, width, p->vrows-p->yscroll); return(0); } @@ -1695,6 +1709,134 @@ static int fbcon_blank(int blank) } +static int fbcon_get_font(struct vc_data *conp, int *w, int *h, char *data) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + int i, size, alloc; + + size = (p->fontwidth+7)/8 * p->fontheight * 256; + alloc = (*w+7)/8 * *h * 256; + *w = p->fontwidth; + *h = p->fontheight; + + if (alloc < size) + /* allocation length not sufficient */ + return( -ENAMETOOLONG ); + + if ((i = verify_area( VERIFY_WRITE, (void *)data, size ))) + return i; + + memcpy_tofs( data, p->fontdata, size ); + return( 0 ); +} + + +#define REFCOUNT(fd) (((int *)(fd))[-1]) + +static int fbcon_set_font(struct vc_data *conp, int w, int h, char *data) +{ + int unit = conp->vc_num; + struct display *p = &disp[unit]; + int i, size, userspace = 1, resize; + char *old_data = NULL, *new_data; + + if (w < 0) + w = p->fontwidth; + if (h < 0) + h = p->fontheight; + + if (w == 0) { + /* engage predefined font, name in 'data' */ + char name[MAX_FONT_NAME+1]; + + if ((i = verify_area( VERIFY_READ, (void *)data, MAX_FONT_NAME ))) + return i; + memcpy_fromfs( name, data, MAX_FONT_NAME ); + name[sizeof(name)-1] = 0; + + if (!findsoftfont( name, &w, &h, (u_char **)&data )) + return( -ENOENT ); + userspace = 0; + } + else if (w == 1) { + /* copy font from some other console in 'h'*/ + struct display *op; + + if (h < 0 || !vc_cons_allocated( h )) + return( -ENOTTY ); + if (h == unit) + return( 0 ); /* nothing to do */ + op = &disp[h]; + if (op->fontdata == p->fontdata) + return( 0 ); /* already the same font... */ + + resize = (op->fontwidth != p->fontwidth) || + (op->fontheight != p->fontheight); + if (p->userfont) + old_data = p->fontdata; + p->fontdata = op->fontdata; + w = p->fontwidth = op->fontwidth; + h = p->fontheight = op->fontheight; + if ((p->userfont = op->userfont)) + REFCOUNT(p->fontdata)++; /* increment usage counter */ + goto activate; + } + + if (w != 8) + /* Currently only fontwidth == 8 supported */ + return( -ENXIO ); + + resize = (w != p->fontwidth) || (h != p->fontheight); + size = (w+7)/8 * h * 256; + + if (p->userfont) + old_data = p->fontdata; + + if (userspace) { + if ((i = verify_area( VERIFY_READ, (void *)data, size ))) + return i; + if (!(new_data = kmalloc( sizeof(int)+size, GFP_USER ))) + return( -ENOMEM ); + new_data += sizeof(int); + REFCOUNT(new_data) = 1; /* usage counter */ + memcpy_fromfs( new_data, data, size ); + p->fontdata = new_data; + p->userfont = 1; + } + else { + p->fontdata = data; + p->userfont = 0; + } + p->fontwidth = w; + p->fontheight = h; + + activate: + if (resize) { + p->var.xoffset = p->var.yoffset = p->yscroll = 0; /* reset wrap/pan */ + if (divides(p->ywrapstep, p->fontheight)) + p->scrollmode = SCROLL_YWRAP; + else if (divides(p->ypanstep, p->fontheight) && + p->var.yres_virtual >= p->var.yres+p->fontheight) + p->scrollmode = SCROLL_YPAN; + else + p->scrollmode = SCROLL_YMOVE; + + vc_resize_con( p->var.yres/h, p->var.xres/w, unit ); + } + else if (unit == fg_console) + update_screen( unit ); + + if (old_data) { + if (--REFCOUNT(old_data) == 0) { + kfree( old_data - sizeof(int) ); + } + } + + return( 0 ); +} + + /* ====================================================================== */ /* @@ -1946,7 +2088,7 @@ static void putc_ilbm(struct vc_data *conp, struct display *p, int c, int y, /* - * I splitted the console character loop in two parts: + * I split the console character loop in two parts: * * - slow version: this blits one character at a time * @@ -2179,7 +2321,7 @@ static void putc_plan(struct vc_data *conp, struct display *p, int c, int y, /* - * I splitted the console character loop in two parts + * I split the console character loop in two parts * (cfr. fbcon_putcs_ilbm()) */ @@ -2326,7 +2468,7 @@ static void bmove_2_plane(struct display *p, int sy, int sx, int dy, int dx, * destination, start at even addresses or both are at odd * addresses, just the first odd and last even column (if present) * require special treatment (memmove_col()). The rest between - * then can be copied by normal operations, because all adjancent + * then can be copied by normal operations, because all adjacent * bytes are affected and are to be stored in the same order. * The pathological case is when the move should go from an odd * address to an even or vice versa. Since the bytes in the plane @@ -2590,7 +2732,7 @@ static void bmove_4_plane(struct display *p, int sy, int sx, int dy, int dx, * destination, start at even addresses or both are at odd * addresses, just the first odd and last even column (if present) * require special treatment (memmove_col()). The rest between - * then can be copied by normal operations, because all adjancent + * then can be copied by normal operations, because all adjacent * bytes are affected and are to be stored in the same order. * The pathological case is when the move should go from an odd * address to an even or vice versa. Since the bytes in the plane @@ -3614,5 +3756,5 @@ static void rev_char_cyber(struct display *p, int x, int y) struct consw fb_con = { fbcon_startup, fbcon_init, fbcon_deinit, fbcon_clear, fbcon_putc, fbcon_putcs, fbcon_cursor, fbcon_scroll, fbcon_bmove, fbcon_switch, - fbcon_blank + fbcon_blank, fbcon_get_font, fbcon_set_font }; diff --git a/arch/m68k/defconfig b/arch/m68k/defconfig index bdf989533b5d..8f23f7ea3c9c 100644 --- a/arch/m68k/defconfig +++ b/arch/m68k/defconfig @@ -123,6 +123,7 @@ CONFIG_NFS_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set +# CONFIG_UFS_FS is not set # # Character devices diff --git a/arch/m68k/fpsp040/bindec.S b/arch/m68k/fpsp040/bindec.S index 6321ca22ab8d..ef3a627bf895 100644 --- a/arch/m68k/fpsp040/bindec.S +++ b/arch/m68k/fpsp040/bindec.S @@ -70,7 +70,7 @@ | in INEX2. | | A10. Or in INEX. -| If INEX is set, round error occured. This is +| If INEX is set, round error occurred. This is | compensated for by 'or-ing' in the INEX2 flag to | the lsb of Y. | @@ -518,7 +518,7 @@ A9_con: | A10. Or in INEX. -| If INEX is set, round error occured. This is compensated +| If INEX is set, round error occurred. This is compensated | for by 'or-ing' in the INEX2 flag to the lsb of Y. | | Register usage: diff --git a/arch/m68k/fpsp040/decbin.S b/arch/m68k/fpsp040/decbin.S index f09b5146feba..af1279a4ab6e 100644 --- a/arch/m68k/fpsp040/decbin.S +++ b/arch/m68k/fpsp040/decbin.S @@ -63,7 +63,7 @@ | in an inex2 exception. If so, set inex1 in the fpsr and | check if the inex1 exception is enabled. If so, set d7 upper | word to $0100. This will signal unimp.sa that an enabled inex1 -| exception occured. Unimp will fix the stack. +| exception occurred. Unimp will fix the stack. | | Copyright (C) Motorola, Inc. 1990 @@ -204,7 +204,7 @@ calc_m: | Get the rest of the mantissa. | loadlw: - movel (%a0,%d1.L*4),%d4 |load mantissa lonqword into d4 + movel (%a0,%d1.L*4),%d4 |load mantissa longword into d4 moveql #FSTRT,%d3 |counter to pick up digits moveql #FNIBS,%d2 |reset number of digits per a0 ptr md2b: @@ -245,21 +245,21 @@ m_sign: | | 1. Branch on the sign of the adjusted exponent. | 2p.(positive exp) -| 2. Check M16 and the digits in lwords 2 and 3 in decending order. +| 2. Check M16 and the digits in lwords 2 and 3 in descending order. | 3. Add one for each zero encountered until a non-zero digit. | 4. Subtract the count from the exp. | 5. Check if the exp has crossed zero in #3 above; make the exp abs | and set SE. | 6. Multiply the mantissa by 10**count. | 2n.(negative exp) -| 2. Check the digits in lwords 3 and 2 in decending order. +| 2. Check the digits in lwords 3 and 2 in descending order. | 3. Add one for each zero encountered until a non-zero digit. | 4. Add the count to the exp. | 5. Check if the exp has crossed zero in #3 above; clear SE. | 6. Divide the mantissa by 10**count. | | *Why 27? If the adjusted exponent is within -28 < expA < 28, than -| any adjustment due to append/strip zeros will drive the resultane +| any adjustment due to append/strip zeros will drive the resultant | exponent towards zero. Since all pwrten constants with a power | of 27 or less are exact, there is no need to use this routine to | attempt to lessen the resultant exponent. diff --git a/arch/m68k/fpsp040/fpsp.h b/arch/m68k/fpsp040/fpsp.h index 512912f14da4..9ebe3c490439 100644 --- a/arch/m68k/fpsp040/fpsp.h +++ b/arch/m68k/fpsp040/fpsp.h @@ -161,7 +161,7 @@ .set guard_bit,1 | guard bit is bit number 1 .set round_bit,0 | round bit is bit number 0 .set stag_mask,0xE0 | upper 3 bits are source tag type - .set denorm_bit,7 | bit determins if denorm or unnorm + .set denorm_bit,7 | bit determines if denorm or unnorm .set etemp15_bit,4 | etemp exponent bit #15 .set wbtemp66_bit,2 | wbtemp mantissa bit #66 .set wbtemp1_bit,1 | wbtemp mantissa bit #1 diff --git a/arch/m68k/fpsp040/gen_except.S b/arch/m68k/fpsp040/gen_except.S index 0fd6a52cf191..edd8108d02ec 100644 --- a/arch/m68k/fpsp040/gen_except.S +++ b/arch/m68k/fpsp040/gen_except.S @@ -296,7 +296,7 @@ loop1: moveb #BUSY_SIZE-4,1(%a7) |write busy fmt word. busy_fr: movel FP_SCR1(%a6),WBTEMP_EX(%a6) |write - movel FP_SCR1+4(%a6),WBTEMP_HI(%a6) |execptional op to + movel FP_SCR1+4(%a6),WBTEMP_HI(%a6) |exceptional op to movel FP_SCR1+8(%a6),WBTEMP_LO(%a6) |wbtemp bsetb #E3,E_BYTE(%a6) |set E3 flag bclrb #E1,E_BYTE(%a6) |make sure E1 is clear diff --git a/arch/m68k/fpsp040/get_op.S b/arch/m68k/fpsp040/get_op.S index 0aa01f316087..2bd236d455f6 100644 --- a/arch/m68k/fpsp040/get_op.S +++ b/arch/m68k/fpsp040/get_op.S @@ -14,7 +14,7 @@ | UNIMPLEMENTED instructions (exception vector 11) the following | applies: | -| - For unnormormalized numbers (opclass 0, 2, or 3) the +| - For unnormalized numbers (opclass 0, 2, or 3) the | number(s) is normalized and the operand type tag is updated. | | - For a packed number (opclass 2) the number is unpacked and the @@ -48,7 +48,7 @@ | detects this and tags the number as a denorm. The routine | res_func sees the denorm tag and converts the denorm to a | norm. The instruction is then restored back into the '040 -| which re_executess the instruction. +| which re_executes the instruction. | | | Copyright (C) Motorola, Inc. 1990 @@ -354,7 +354,7 @@ end_getop: | | Sets the DY_MO_FLG correctly. This is used only on if it is an -| unuspported data type exception. Set if dyadic. +| unsupported data type exception. Set if dyadic. | chk_dy_mo: movew CMDREG1B(%a6),%d0 diff --git a/arch/m68k/fpsp040/res_func.S b/arch/m68k/fpsp040/res_func.S index 87ff571c205b..9a81bde1deb8 100644 --- a/arch/m68k/fpsp040/res_func.S +++ b/arch/m68k/fpsp040/res_func.S @@ -83,7 +83,7 @@ monadic: btstb #direction_bit,CMDREG1B(%a6) |check direction bne opclass3 |it is a mv out | -| At this point, only oplcass 0 and 2 possible +| At this point, only opclass 0 and 2 possible | btstb #7,STAG(%a6) |if sop = norm=000, zero=001, | ;inf=010 or nan=011 @@ -299,7 +299,7 @@ cu_nuninx: bnes cu_nunzro | | The mantissa is zero from the denorm loop. Check sign and rmode -| to see if rounding should have occured which would leave the lsb. +| to see if rounding should have occurred which would leave the lsb. | movel USER_FPCR(%a6),%d0 andil #0x30,%d0 |isolate rmode @@ -413,7 +413,7 @@ fix_stk: | | cu_dnrm handles all cu-only instructions (fmove, fabs, fneg, and -| ftst) completly in software without an frestore to the 040. +| ftst) completely in software without an frestore to the 040. | cu_dnrm: st CU_ONLY(%a6) @@ -610,7 +610,7 @@ cu_sndr: | DNRM_FLG contains $00 for neither op denormalized | $0f for the destination op denormalized | $f0 for the source op denormalized -| $ff for both ops denormalzed +| $ff for both ops denormalized | | The wrap-around condition occurs for add, sub, div, and cmp | when @@ -828,7 +828,7 @@ add_srcd: | precision. We can then call round with no sticky and the result | will be correct for the user's rounding mode and precision. If | the signs are the same, we call round with the sticky bit set -| and the result will be correctfor the user's rounding mode and +| and the result will be correct for the user's rounding mode and | precision. | add_wrap: @@ -1003,7 +1003,7 @@ sub_srcd: | precision. We can then call round with no sticky and the result | will be correct for the user's rounding mode and precision. If | the signs are unlike, we call round with the sticky bit set -| and the result will be correctfor the user's rounding mode and +| and the result will be correct for the user's rounding mode and | precision. | sub_wrap: diff --git a/arch/m68k/fpsp040/round.S b/arch/m68k/fpsp040/round.S index 1479e246619f..b1030fde7ae0 100644 --- a/arch/m68k/fpsp040/round.S +++ b/arch/m68k/fpsp040/round.S @@ -212,7 +212,7 @@ sgl_done: add_ext: addql #1,LOCAL_LO(%a0) |add 1 to l-bit bccs xcc_clr |test for carry out - addql #1,LOCAL_HI(%a0) |propogate carry + addql #1,LOCAL_HI(%a0) |propagate carry bccs xcc_clr roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit @@ -231,7 +231,7 @@ add_ext_done: add_dbl: addl #ad_1_dbl,LOCAL_LO(%a0) bccs dcc_clr - addql #1,LOCAL_HI(%a0) |propogate carry + addql #1,LOCAL_HI(%a0) |propagate carry bccs dcc_clr roxrw LOCAL_HI(%a0) |mant is 0 so restore v-bit roxrw LOCAL_HI+2(%a0) |mant is 0 so restore v-bit @@ -483,7 +483,7 @@ no_inex: rts | -| dnrm_lp --- normalize exponent/mantissa to specified threshhold +| dnrm_lp --- normalize exponent/mantissa to specified threshold | | Input: | a0 points to the operand to be denormalized @@ -506,7 +506,7 @@ dnrm_lp: beqs not_E3 |not type E3 exception bfextu WBTEMP_GRS(%a6){#6:#3},%d2 |extract guard,round, sticky bit movel #29,%d0 - lsll %d0,%d2 |shift g,r,s to their postions + lsll %d0,%d2 |shift g,r,s to their positions movel %d2,%d0 not_E3: movel (%sp)+,%d2 |restore d2 diff --git a/arch/m68k/fpsp040/satan.S b/arch/m68k/fpsp040/satan.S index c38ab6969d64..282c462b08db 100644 --- a/arch/m68k/fpsp040/satan.S +++ b/arch/m68k/fpsp040/satan.S @@ -1,7 +1,7 @@ | | satan.sa 3.3 12/19/90 | -| The entry point satan computes the arctagent of an +| The entry point satan computes the arctangent of an | input value. satand does the same except the input value is a | denormalized number. | diff --git a/arch/m68k/fpsp040/scale.S b/arch/m68k/fpsp040/scale.S index 808e76276170..1f01fb1d509c 100644 --- a/arch/m68k/fpsp040/scale.S +++ b/arch/m68k/fpsp040/scale.S @@ -2,7 +2,7 @@ | scale.sa 3.3 7/30/91 | | The entry point sSCALE computes the destination operand -| scaled by the source operand. If the absoulute value of +| scaled by the source operand. If the absolute value of | the source operand is (>= 2^14) an overflow or underflow | is returned. | diff --git a/arch/m68k/fpsp040/sint.S b/arch/m68k/fpsp040/sint.S index 7e3603a7fc43..9ca3fb6c4d67 100644 --- a/arch/m68k/fpsp040/sint.S +++ b/arch/m68k/fpsp040/sint.S @@ -77,7 +77,7 @@ .global sint sint: bfextu FPCR_MODE(%a6){#2:#2},%d1 |use user's mode for rounding -| ;implicity has extend precision +| ;implicitly has extend precision | ;in upper word. movel %d1,L_SCR1(%a6) |save mode bits bras sintexc @@ -114,7 +114,7 @@ sintmz: .global sintrz sintrz: movel #1,L_SCR1(%a6) |use rz mode for rounding -| ;implicity has extend precision +| ;implicitly has extend precision | ;in upper word. bras sintexc | @@ -123,7 +123,7 @@ sintrz: | Input: a0 points to an IEEE extended format operand | Output: fp0 has the result | -| Exeptions: +| Exceptions: | | If the subroutine results in an inexact operation, the inx2 and | ainx bits in the USER_FPSR are set. diff --git a/arch/m68k/fpsp040/skeleton.S b/arch/m68k/fpsp040/skeleton.S index 74d2ac379b42..7dbf253bea6a 100644 --- a/arch/m68k/fpsp040/skeleton.S +++ b/arch/m68k/fpsp040/skeleton.S @@ -107,7 +107,7 @@ real_dz: | necessary for E1 exceptions. | | Code following the 'inex' label is to handle bug #1232. In this -| bug, if an E1 snan, ovfl, or unfl occured, and the process was +| bug, if an E1 snan, ovfl, or unfl occurred, and the process was | swapped out before taking the exception, the exception taken on | return was inex, rather than the correct exception. The snan, ovfl, | and unfl exception to be taken must not have been enabled. The diff --git a/arch/m68k/fpsp040/slogn.S b/arch/m68k/fpsp040/slogn.S index 4e7dddcb03fc..b660acd0d162 100644 --- a/arch/m68k/fpsp040/slogn.S +++ b/arch/m68k/fpsp040/slogn.S @@ -383,7 +383,7 @@ LP1CONT1: fmulx LOGOF2,%fp1 | ...GET K*LOG2 WHILE FP0 IS NOT READY fmovex %fp0,%fp2 fmulx %fp2,%fp2 | ...FP2 IS V=U*U - fmovex %fp1,KLOG2(%a6) | ...PUT K*LOG2 IN MEMEORY, FREE FP1 + fmovex %fp1,KLOG2(%a6) | ...PUT K*LOG2 IN MEMORY, FREE FP1 |--LOG(1+U) IS APPROXIMATED BY |--U + V*(A1+U*(A2+U*(A3+U*(A4+U*(A5+U*A6))))) WHICH IS diff --git a/arch/m68k/fpsp040/ssin.S b/arch/m68k/fpsp040/ssin.S index 5c0c1dd5fd5b..978941f4e97d 100644 --- a/arch/m68k/fpsp040/ssin.S +++ b/arch/m68k/fpsp040/ssin.S @@ -9,7 +9,7 @@ | Input: Double-extended number X in location pointed to | by address register a0. | -| Output: The funtion value sin(X) or cos(X) returned in Fp0 if SIN or +| Output: The function value sin(X) or cos(X) returned in Fp0 if SIN or | COS is requested. Otherwise, for SINCOS, sin(X) is returned | in Fp0, and cos(X) is returned in Fp1. | @@ -32,7 +32,7 @@ | 2. If |X| >= 15Pi or |X| < 2**(-40), go to 7. | | 3. Decompose X as X = N(Pi/2) + r where |r| <= Pi/4. Let -| k = N mod 4, so in particular, k = 0,1,2,or 3. Overwirte +| k = N mod 4, so in particular, k = 0,1,2,or 3. Overwrite | k by k := k + AdjN. | | 4. If k is even, go to 6. @@ -409,7 +409,7 @@ red_neg: |--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. |--integer quotient will be stored in N -|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) +|--Intermediate remainder is 66-bit long; (R,r) in (FP0,FP1) LOOP: fmovex %fp0,INARG(%a6) | ...+-2**K * F, 1 <= F < 2 diff --git a/arch/m68k/fpsp040/stan.S b/arch/m68k/fpsp040/stan.S index d0729140f683..b7a880a2a0e3 100644 --- a/arch/m68k/fpsp040/stan.S +++ b/arch/m68k/fpsp040/stan.S @@ -299,7 +299,7 @@ TANSM: fmovex %fp0,-(%sp) fmovel %d1,%fpcr |restore users exceptions - fmovex (%sp)+,%fp0 |last inst - posibble exception set + fmovex (%sp)+,%fp0 |last inst - possible exception set bra t_frcinx @@ -340,7 +340,7 @@ red_neg: |--ON ENTRY, FP0 IS X, ON RETURN, FP0 IS X REM PI/2, |X| <= PI/4. |--integer quotient will be stored in N -|--Intermeditate remainder is 66-bit long; (R,r) in (FP0,FP1) +|--Intermediate remainder is 66-bit long; (R,r) in (FP0,FP1) LOOP: fmovex %fp0,INARG(%a6) | ...+-2**K * F, 1 <= F < 2 diff --git a/arch/m68k/fpsp040/tbldo.S b/arch/m68k/fpsp040/tbldo.S index 4db8126a28f7..b80bef99e655 100644 --- a/arch/m68k/fpsp040/tbldo.S +++ b/arch/m68k/fpsp040/tbldo.S @@ -3,7 +3,7 @@ | | Modified: | 8/16/90 chinds The table was constructed to use only one level -| of indirection in do_func for monoadic +| of indirection in do_func for monadic | functions. Dyadic functions require two | levels, and the tables are still contained | in do_func. The table is arranged for diff --git a/arch/m68k/fpsp040/util.S b/arch/m68k/fpsp040/util.S index a73baeaff636..e59b352ab7dc 100644 --- a/arch/m68k/fpsp040/util.S +++ b/arch/m68k/fpsp040/util.S @@ -256,7 +256,7 @@ SGL_RN: bsetb #inf_bit,FPSR_CC(%a6) bras set_sign SGL_RZ: - leal SGL_PLRG,%a1 |anwer is +/- large number + leal SGL_PLRG,%a1 |answer is +/- large number bras set_sign SGL_RM: tstb LOCAL_SGN(%a0) |if negative overflow @@ -276,7 +276,7 @@ s_rp_neg: bsetb #neg_bit,FPSR_CC(%a6) bras end_ovfr s_rp_pos: - leal EXT_PINF,%a1 |answer is postive infinity + leal EXT_PINF,%a1 |answer is positive infinity bsetb #inf_bit,FPSR_CC(%a6) bras end_ovfr diff --git a/arch/m68k/fpsp040/x_bsun.S b/arch/m68k/fpsp040/x_bsun.S index e13cb7ced0a9..42faf9bf08f6 100644 --- a/arch/m68k/fpsp040/x_bsun.S +++ b/arch/m68k/fpsp040/x_bsun.S @@ -3,7 +3,7 @@ | | fpsp_bsun --- FPSP handler for branch/set on unordered exception | -| Copy the PC to FPIAR to maintain 881/882 compatability +| Copy the PC to FPIAR to maintain 881/882 compatibility | | The real_bsun handler will need to perform further corrective | measures as outlined in the 040 User's Manual on pages diff --git a/arch/m68k/fpsp040/x_operr.S b/arch/m68k/fpsp040/x_operr.S index cfe0621bd7ef..99d1a843052b 100644 --- a/arch/m68k/fpsp040/x_operr.S +++ b/arch/m68k/fpsp040/x_operr.S @@ -25,7 +25,7 @@ | | where exp = (true exp) - 1 | -| So, wbtemp and fptemp will contain the following on erroneoulsy +| So, wbtemp and fptemp will contain the following on erroneously | signalled operr: | fpts = 1 | fpte = $4000 (15 bit externally) @@ -321,7 +321,7 @@ not_enabled: | | It is possible to have either inex2 or inex1 exceptions with the | operr. If the inex enable bit is set in the FPCR, and either -| inex2 or inex1 occured, we must clean up and branch to the +| inex2 or inex1 occurred, we must clean up and branch to the | real inex handler. | ck_inex: diff --git a/arch/m68k/fpsp040/x_ovfl.S b/arch/m68k/fpsp040/x_ovfl.S index f0818a2c5613..e311508cac7d 100644 --- a/arch/m68k/fpsp040/x_ovfl.S +++ b/arch/m68k/fpsp040/x_ovfl.S @@ -92,7 +92,7 @@ no_e3_1: | | It is possible to have either inex2 or inex1 exceptions with the | ovfl. If the inex enable bit is set in the FPCR, and either -| inex2 or inex1 occured, we must clean up and branch to the +| inex2 or inex1 occurred, we must clean up and branch to the | real inex handler. | ck_inex: diff --git a/arch/m68k/fpsp040/x_snan.S b/arch/m68k/fpsp040/x_snan.S index cc73c848e523..aaba75c1803d 100644 --- a/arch/m68k/fpsp040/x_snan.S +++ b/arch/m68k/fpsp040/x_snan.S @@ -57,7 +57,7 @@ fpsp_snan: | | It is possible to have an inex1 exception with the | snan. If the inex enable bit is set in the FPCR, and either -| inex2 or inex1 occured, we must clean up and branch to the +| inex2 or inex1 occurred, we must clean up and branch to the | real inex handler. | ck_inex: diff --git a/arch/m68k/fpsp040/x_store.S b/arch/m68k/fpsp040/x_store.S index 782acb28cbf2..a3468f3386e9 100644 --- a/arch/m68k/fpsp040/x_store.S +++ b/arch/m68k/fpsp040/x_store.S @@ -138,7 +138,7 @@ dest_dbl: swap %d0 |d0 now in upper word lsll #4,%d0 |d0 now in proper place for dbl prec exp tstb LOCAL_SGN(%a1) - beqs get_mant |if postive, go process mantissa + beqs get_mant |if positive, go process mantissa bsetl #31,%d0 |if negative, put in sign information | ; before continuing bras get_mant |go process mantissa diff --git a/arch/m68k/fpsp040/x_unfl.S b/arch/m68k/fpsp040/x_unfl.S index b3acda0edeca..f9bd1d0d6493 100644 --- a/arch/m68k/fpsp040/x_unfl.S +++ b/arch/m68k/fpsp040/x_unfl.S @@ -9,7 +9,7 @@ | by taking the intermediate result (which is always normalized) and | shifting the mantissa right while incrementing the exponent until | it is equal to the denormalized exponent for the destination -| format. After denormalizatoin, the result is rounded to the +| format. After denormalization, the result is rounded to the | destination format. | | Trap enabled results @@ -80,7 +80,7 @@ no_e3_1: | | It is possible to have either inex2 or inex1 exceptions with the | unfl. If the inex enable bit is set in the FPCR, and either -| inex2 or inex1 occured, we must clean up and branch to the +| inex2 or inex1 occurred, we must clean up and branch to the | real inex handler. | ck_inex: diff --git a/arch/m68k/ifpsp060/TEST.DOC b/arch/m68k/ifpsp060/TEST.DOC index aa06cec29073..3a96b4b2060f 100644 --- a/arch/m68k/ifpsp060/TEST.DOC +++ b/arch/m68k/ifpsp060/TEST.DOC @@ -45,7 +45,7 @@ converted to other assembly syntaxes by using any word processor with a global search and replace function. To assist in assembling and linking these modules with other modules, -the instaler should add symbolic labels to the top of the files. +the installer should add symbolic labels to the top of the files. This will allow the calling routines to access the entry points of these packages. @@ -159,7 +159,7 @@ FP unimplemented: tests FP unimplemented exception. this one is FP enabled: tests enabled snan/operr/ovfl/unfl/dz/inex. basically, it enables each of these exceptions and forces each using an implemented FP instruction. this process - exercizes _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and + exercises _fpsp_{snan,operr,ovfl,unfl,dz,inex}() and _real_{snan,operr,ovfl,unfl,dz,inex}(). the test expects _real_XXXX() to do nothing except clear the exception and "rte". if a system's _real_XXXX() handler creates an diff --git a/arch/m68k/ifpsp060/fpsp.doc b/arch/m68k/ifpsp060/fpsp.doc index 96878dd6fe0b..1a66c16c4ed6 100644 --- a/arch/m68k/ifpsp060/fpsp.doc +++ b/arch/m68k/ifpsp060/fpsp.doc @@ -254,7 +254,7 @@ _060_fpsp_fline: | |----> may exit through _060_real_trap | - |----> may exit thorugh _060_real_bsun + |----> may exit through _060_real_bsun | |----> may exit through _060_fpsp_done diff --git a/arch/m68k/ifpsp060/iskeleton.S b/arch/m68k/ifpsp060/iskeleton.S index a01de1c0649f..a355e2904bf3 100644 --- a/arch/m68k/ifpsp060/iskeleton.S +++ b/arch/m68k/ifpsp060/iskeleton.S @@ -71,7 +71,7 @@ _060_isp_done: | This is an alternate exit point for the Unimplemented Integer | Instruction exception handler. If the instruction was a "chk2" | and the operand was out of bounds, then _isp_unimp() creates -| a CHK exception stack frame from the Unimplemented Integer Instrcution +| a CHK exception stack frame from the Unimplemented Integer Instruction | stack frame and branches to this routine. | .global _060_real_chk diff --git a/arch/m68k/kernel/console.c b/arch/m68k/kernel/console.c index 47774ecad669..d922a14a968e 100644 --- a/arch/m68k/kernel/console.c +++ b/arch/m68k/kernel/console.c @@ -1561,7 +1561,7 @@ static int con_write(struct tty_struct * tty, int from_user, where we really draw the chars */ if (count > 2 && - !decim && currcons == fg_console) { + !decim && !utf && currcons == fg_console) { static char putcs_buf[256]; char *p = putcs_buf; int putcs_count = 1; @@ -1582,14 +1582,25 @@ static int con_write(struct tty_struct * tty, int from_user, while (count) { + enable_bh(CONSOLE_BH); c = from_user ? get_user(buf) : *buf; + disable_bh(CONSOLE_BH); tc = translate[toggle_meta ? (c|0x80) : c]; if (!tc || !(c >= 32 - || (disp_ctrl && c != 0x1b) - || !((CTRL_ACTION >> c) & 1))) + || !(((disp_ctrl ? CTRL_ALWAYS + : CTRL_ACTION) >> c) & 1))) break; + tc = conv_uni_to_pc(tc); + if (tc == -4) + tc = conv_uni_to_pc(0xfffd); + else if (tc == -3) + tc = c; + buf++; n++; count--; + if (tc & ~console_charmask) + continue; /* Conversion failed */ + *p++ = tc; *pos++ = tc | (attr << 8); ++putcs_count; diff --git a/arch/m68k/kernel/entry.S b/arch/m68k/kernel/entry.S index 26e76f6101c5..58f4e06fe450 100644 --- a/arch/m68k/kernel/entry.S +++ b/arch/m68k/kernel/entry.S @@ -234,7 +234,6 @@ SYMBOL_NAME_LABEL(ret_from_exception) cmpl %a0@(LTASK_COUNTER),%d0 | counter jeq SYMBOL_NAME(reschedule) - .word 0xf4f8 movel %a0@(LTASK_BLOCKED),%d0 movel %d0,%d1 | save blocked in d1 for sig handling notl %d0 @@ -356,9 +355,6 @@ SYMBOL_NAME_LABEL(resume) /* offset of tss struct (processor state) from beginning of task struct */ -/* - movel %sp@(8),%a1 -*/ addl %a1,%a0 /* save sr */ diff --git a/arch/m68k/kernel/head.S b/arch/m68k/kernel/head.S index 75ce89a86b88..8c90db20918c 100644 --- a/arch/m68k/kernel/head.S +++ b/arch/m68k/kernel/head.S @@ -313,7 +313,7 @@ ENTRY(_start) * on the 68040, pages used to hold mmu tables should * be initialized as noncachable; the '060 allows write-through. * Do this for the root table page (which also contains - * all pointer tables utilitized thus far) and the + * all pointer tables utilized thus far) and the * kernel page table. */ lea %pc@(SYMBOL_NAME(_stext)-PAGESIZE:w),%a0 @@ -469,9 +469,9 @@ Lnotami: /* other machines specific mappings go here! */ is done by writing to the byte at phys. 0x0. This should result in a bus error on all other machines. - ...should, but doesn't. The Atferburner040 for the Falcon has the + ...should, but doesn't. The Afterburner040 for the Falcon has the same behaviour (0x0..0x7 are no ROM shadow). So we have to do - another test to distinuish Medusa and AB040. This is a + another test to distinguish Medusa and AB040. This is a read attempt for 0x00ff82fe phys. that should bus error on a Falcon (+AB040), but is in the range where the Medusa always asserts DTACK. */ diff --git a/arch/m68k/kernel/sys_m68k.c b/arch/m68k/kernel/sys_m68k.c index 4ea117b6bf9e..4db18f142b72 100644 --- a/arch/m68k/kernel/sys_m68k.c +++ b/arch/m68k/kernel/sys_m68k.c @@ -20,7 +20,7 @@ /* * sys_pipe() is the normal C calling standard for creating - * a pipe. It's not the way unix tranditionally does this, though. + * a pipe. It's not the way unix traditionally does this, though. */ asmlinkage int sys_pipe(unsigned long * fildes) { diff --git a/arch/m68k/kernel/traps.c b/arch/m68k/kernel/traps.c index a67a8d14246e..97e010dbae8f 100644 --- a/arch/m68k/kernel/traps.c +++ b/arch/m68k/kernel/traps.c @@ -261,7 +261,7 @@ static void do_040writeback (unsigned short ssw, /* * No special handling for the second writeback anymore. * It misinterpreted the misaligned status sometimes. - * This way an extra pgae-fault may be caused (Martin Apel). + * This way an extra page-fault may be caused (Martin Apel). */ mmusr = probe040 (1, wbs & WBTM_040, wba); diff --git a/arch/m68k/mm/init.c b/arch/m68k/mm/init.c index 86304e7faea1..dbdfa1516023 100644 --- a/arch/m68k/mm/init.c +++ b/arch/m68k/mm/init.c @@ -448,7 +448,6 @@ unsigned long paging_init(unsigned long start_mem, unsigned long end_mem) void mem_init(unsigned long start_mem, unsigned long end_mem) { int codepages = 0; - int reservedpages = 0; int datapages = 0; unsigned long tmp; extern int _etext; @@ -514,11 +513,10 @@ void mem_init(unsigned long start_mem, unsigned long end_mem) free_page(tmp); } tmp = nr_free_pages << PAGE_SHIFT; - printk("Memory: %luk/%luk available (%dk kernel code, %dk reserved, %dk data)\n", + printk("Memory: %luk/%luk available (%dk kernel code, %dk data)\n", tmp >> 10, high_memory >> 10, codepages << (PAGE_SHIFT-10), - reservedpages << (PAGE_SHIFT-10), datapages << (PAGE_SHIFT-10)); } diff --git a/arch/m68k/mm/memory.c b/arch/m68k/mm/memory.c index fb3e9eff9176..49aa454b9689 100644 --- a/arch/m68k/mm/memory.c +++ b/arch/m68k/mm/memory.c @@ -378,7 +378,7 @@ void cache_clear (unsigned long paddr, int len) { if (m68k_is040or060) { /* ++roman: There have been too many problems with the CINV, it seems - * to break the cache maintainance of DMAing drivers. I don't expect + * to break the cache maintenance of DMAing drivers. I don't expect * too much overhead by using CPUSH instead. */ while (len > PAGE_SIZE) { @@ -461,7 +461,7 @@ void cache_push (unsigned long paddr, int len) "movec %/d0,%/cacr" : : "i" (FLUSH_I) : "d0"); - } +} void cache_push_v (unsigned long vaddr, int len) { @@ -489,15 +489,44 @@ void cache_push_v (unsigned long vaddr, int len) pushv060(vaddr); len -= PAGE_SIZE; vaddr += PAGE_SIZE; - } + } if (len > 0) { pushv060(vaddr); if (((vaddr + len - 1) ^ vaddr) & PAGE_MASK) { /* a page boundary gets crossed at the end */ pushv060(vaddr + len - 1); - } } } + } + /* 68030/68020 have no writeback cache; still need to clear icache. */ + else /* 68030 or 68020 */ + asm volatile ("movec %/cacr,%/d0\n\t" + "oriw %0,%/d0\n\t" + "movec %/d0,%/cacr" + : : "i" (FLUSH_I) + : "d0"); +} + +void flush_cache_all(void) +{ + if (m68k_is040or060 >= 4) + __asm__ __volatile__ (".word 0xf478\n" ::); + else /* 68030 or 68020 */ + asm volatile ("movec %/cacr,%/d0\n\t" + "oriw %0,%/d0\n\t" + "movec %/d0,%/cacr" + : : "i" (FLUSH_I) + : "d0"); +} + +void flush_page_to_ram (unsigned long addr) +{ + if (m68k_is040or060 == 4) + pushv040(addr); + + else if (m68k_is040or060 == 6) + push040(VTOP(addr)); /* someone mentioned that pushv060 doesn't work */ + /* 68030/68020 have no writeback cache; still need to clear icache. */ else /* 68030 or 68020 */ asm volatile ("movec %/cacr,%/d0\n\t" diff --git a/arch/sparc/boot/bare.S b/arch/sparc/boot/bare.S index 046b276431a6..ab350859193d 100644 --- a/arch/sparc/boot/bare.S +++ b/arch/sparc/boot/bare.S @@ -1,4 +1,4 @@ -/* $Id: bare.S,v 1.3 1995/11/27 02:42:50 davem Exp $ +/* $Id: bare.S,v 1.4 1996/04/23 01:53:40 davem Exp $ * base.S: Ugly low-level boot program entry code. The job of this * module is to parse the boot flags, try to mount the remote * root filesystem and load the kernel into virtual memory. diff --git a/arch/sparc/boot/empirical.h b/arch/sparc/boot/empirical.h index aaa16f57785d..e13b8c80aa06 100644 --- a/arch/sparc/boot/empirical.h +++ b/arch/sparc/boot/empirical.h @@ -1,4 +1,4 @@ -/* $Id: empirical.h,v 1.1 1996/04/21 10:17:46 davem Exp $ +/* $Id: empirical.h,v 1.2 1996/04/23 01:53:42 davem Exp $ * empirical.h: Nasty hacks.... * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/config.in b/arch/sparc/config.in index 0d5d042b9601..9829bbb17ad5 100644 --- a/arch/sparc/config.in +++ b/arch/sparc/config.in @@ -1,4 +1,4 @@ -# $Id: config.in,v 1.9 1996/04/04 16:30:03 tridge Exp $ +# $Id: config.in,v 1.12 1996/04/24 03:15:38 davem Exp $ # For a description of the syntax of this configuration file, # see the Configure script. # @@ -12,6 +12,7 @@ bool 'Support for AP1000 multicomputer' CONFIG_AP1000 if [ "$CONFIG_AP1000" = "n" ]; then # Global things across all Sun machines. define_bool CONFIG_SBUS y + define_bool CONFIG_SBUSCHAR y define_bool CONFIG_SUN_MOUSE y define_bool CONFIG_SERIAL y define_bool CONFIG_SUN_SERIAL y @@ -30,7 +31,23 @@ bool 'System V IPC' CONFIG_SYSVIPC tristate 'Kernel support for ELF binaries' CONFIG_BINFMT_ELF endmenu -source drivers/block/Config.in +mainmenu_option next_comment +comment 'Floppy, IDE, and other block devices' + +tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD + +bool 'Multiple devices driver support' CONFIG_BLK_DEV_MD +if [ "$CONFIG_BLK_DEV_MD" = "y" ]; then + tristate ' Linear (append) mode' CONFIG_MD_LINEAR + tristate ' RAID-0 (striping) mode' CONFIG_MD_STRIPED +fi + +tristate 'RAM disk support' CONFIG_BLK_DEV_RAM +if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then + bool ' Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD +fi + +tristate 'Loopback device support' CONFIG_BLK_DEV_LOOP if [ "$CONFIG_NET" = "y" ]; then source net/Config.in @@ -42,7 +59,23 @@ comment 'SCSI support' tristate 'SCSI support' CONFIG_SCSI if [ "$CONFIG_SCSI" != "n" ]; then - source drivers/scsi/Config.in + comment 'SCSI support type (disk, tape, CDrom)' + + dep_tristate 'SCSI disk support' CONFIG_BLK_DEV_SD $CONFIG_SCSI + dep_tristate 'SCSI tape support' CONFIG_CHR_DEV_ST $CONFIG_SCSI + dep_tristate 'SCSI CDROM support' CONFIG_BLK_DEV_SR $CONFIG_SCSI + dep_tristate 'SCSI generic support' CONFIG_CHR_DEV_SG $CONFIG_SCSI + + comment 'Some SCSI devices (e.g. CD jukebox) support multiple LUNs' + + bool 'Probe all LUNs on each SCSI device' CONFIG_SCSI_MULTI_LUN + + bool 'Verbose SCSI error reporting (kernel size +=12K)' CONFIG_SCSI_CONSTANTS + + mainmenu_option next_comment + comment 'SCSI low-level drivers' + + dep_tristate 'Sparc ESP Scsi Driver' CONFIG_SCSI_SUNESP $CONFIG_SCSI fi endmenu @@ -52,7 +85,17 @@ if [ "$CONFIG_NET" = "y" ]; then bool 'Network device support' CONFIG_NETDEVICES if [ "$CONFIG_NETDEVICES" = "y" ]; then - source drivers/net/Config.in + tristate 'Dummy net driver support' CONFIG_DUMMY + tristate 'SLIP (serial line) support' CONFIG_SLIP + if [ "$CONFIG_SLIP" != "n" ]; then + bool ' CSLIP compressed headers' CONFIG_SLIP_COMPRESSED + bool ' Keepalive and linefill' CONFIG_SLIP_SMART + fi + tristate 'PPP (point-to-point) support' CONFIG_PPP + if [ ! "$CONFIG_PPP" = "n" ]; then + comment 'CCP compressors for PPP are only built as modules.' + fi + bool 'Sun LANCE support' CONFIG_SUNLANCE fi endmenu fi diff --git a/arch/sparc/defconfig b/arch/sparc/defconfig index e6f2b3ccd7ae..df03b88d6f57 100644 --- a/arch/sparc/defconfig +++ b/arch/sparc/defconfig @@ -7,6 +7,7 @@ # # CONFIG_AP1000 is not set CONFIG_SBUS=y +CONFIG_SBUSCHAR=y CONFIG_SUN_MOUSE=y CONFIG_SERIAL=y CONFIG_SUN_SERIAL=y @@ -23,7 +24,8 @@ CONFIG_BINFMT_ELF=y # # Floppy, IDE, and other block devices # -# CONFIG_BLK_DEV_FD is not set +CONFIG_BLK_DEV_FD=y +# CONFIG_BLK_DEV_MD is not set CONFIG_BLK_DEV_RAM=y # CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_LOOP is not set @@ -32,6 +34,7 @@ CONFIG_BLK_DEV_RAM=y # Networking options # # CONFIG_FIREWALL is not set +# CONFIG_NET_ALIAS is not set CONFIG_INET=y # CONFIG_IP_FORWARD is not set # CONFIG_IP_MULTICAST is not set @@ -74,7 +77,6 @@ CONFIG_BLK_DEV_SR=y # # CONFIG_SCSI_MULTI_LUN is not set CONFIG_SCSI_CONSTANTS=y -# CONFIG_SCSI_AUTO_BIOSP is not set # # SCSI low-level drivers @@ -111,6 +113,8 @@ CONFIG_RNFS_RARP=y CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set +# CONFIG_AFFS_FS is not set +CONFIG_UFS_FS=y # # Kernel hacking diff --git a/arch/sparc/kernel/Makefile b/arch/sparc/kernel/Makefile index 41de109291b0..0078fcb1ad4d 100644 --- a/arch/sparc/kernel/Makefile +++ b/arch/sparc/kernel/Makefile @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.29 1996/04/04 16:30:17 tridge Exp $ +# $Id: Makefile,v 1.30 1996/04/22 10:37:53 davem Exp $ # Makefile for the linux kernel. # # Note! Dependencies are done automagically by 'make dep', which also @@ -35,7 +35,7 @@ O_OBJS := entry.o wof.o wuf.o etrap.o rtrap.o switch.o traps.o ${IRQ_OBJS} \ process.o signal.o ioport.o setup.o idprom.o \ sys_sparc.o sunos_asm.o sparc-stub.o systbls.o sys_sunos.o \ sunos_ioctl.o time.o windows.o cpu.o devices.o ksyms.o \ - sclow.o solaris.o tadpole.o tick14.o + sclow.o solaris.o tadpole.o tick14.o ptrace.o ifdef SMP O_OBJS += trampoline.o smp.o rirq.o diff --git a/arch/sparc/kernel/entry.S b/arch/sparc/kernel/entry.S index 2028470c9c6c..758b73a7372f 100644 --- a/arch/sparc/kernel/entry.S +++ b/arch/sparc/kernel/entry.S @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.90 1996/04/18 01:00:37 davem Exp $ +/* $Id: entry.S,v 1.93 1996/04/25 06:08:32 davem Exp $ * arch/sparc/kernel/entry.S: Sparc trap low-level entry points. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -990,15 +990,27 @@ C_LABEL(sunos_indir): jmp %l5 + 0x8 /* so stupid... */ nop -#if 0 /* work in progress */ + /* Note how we really return to ret_syscall because we share the + * register window with our caller. + */ + .align 4 .globl C_LABEL(sys_ptrace) C_LABEL(sys_ptrace): call C_LABEL(do_ptrace) add %sp, REGWIN_SZ, %o0 + LOAD_CURRENT(l4, l5) + ld [%l4 + 0x14], %l5 + andcc %l5, 0x20, %g0 + be 1f + nop + + call C_LABEL(syscall_trace) + nop + +1: RESTORE_ALL -#endif .align 4 .globl C_LABEL(sys_execve) @@ -1028,6 +1040,16 @@ C_LABEL(sys_sigpause): call C_LABEL(do_sigpause) add %sp, REGWIN_SZ, %o1 + LOAD_CURRENT(l4, l5) + ld [%l4 + 0x14], %l5 + andcc %l5, 0x20, %g0 + be 1f + nop + + call C_LABEL(syscall_trace) + nop + +1: /* We are returning to a signal handler. */ RESTORE_ALL @@ -1037,6 +1059,16 @@ C_LABEL(sys_sigsuspend): call C_LABEL(do_sigsuspend) add %sp, REGWIN_SZ, %o0 + LOAD_CURRENT(l4, l5) + ld [%l4 + 0x14], %l5 + andcc %l5, 0x20, %g0 + be 1f + nop + + call C_LABEL(syscall_trace) + nop + +1: /* We are returning to a signal handler. */ RESTORE_ALL @@ -1046,6 +1078,16 @@ C_LABEL(sys_sigreturn): call C_LABEL(do_sigreturn) add %sp, REGWIN_SZ, %o0 + LOAD_CURRENT(l4, l5) + ld [%l4 + 0x14], %l5 + andcc %l5, 0x20, %g0 + be 1f + nop + + call C_LABEL(syscall_trace) + nop + +1: /* We don't want to muck with user registers like a * normal syscall, just return. */ @@ -1153,6 +1195,15 @@ syscall_is_too_hard: wr %l0, PSR_ET, %psr WRITE_PAUSE + LOAD_CURRENT(l4, l5) + ld [%l4 + 0x14], %l5 + andcc %l5, 0x20, %g0 + be 2f + nop + + call C_LABEL(syscall_trace) + nop + 2: ldd [%sp + REGWIN_SZ + PT_I0], %o0 st %o0, [%sp + REGWIN_SZ + PT_G0] ! for restarting syscalls @@ -1184,8 +1235,18 @@ C_LABEL(ret_sys_call): or %l5, %l6, %l5 st %l5, [%sp + REGWIN_SZ + PT_PSR] - /* Advance the pc and npc over the trap instruction. */ 2: + LOAD_CURRENT(l4, l5) + ld [%l4 + 0x14], %l5 + andcc %l5, 0x20, %g0 + be 3f + nop + + call C_LABEL(syscall_trace) + nop + + /* Advance the pc and npc over the trap instruction. */ +3: ld [%sp + REGWIN_SZ + PT_NPC], %l1 /* pc = npc */ add %l1, 0x4, %l2 /* npc = npc+4 */ st %l1, [%sp + REGWIN_SZ + PT_PC] diff --git a/arch/sparc/kernel/etrap.S b/arch/sparc/kernel/etrap.S index 71928330fca5..43494a556251 100644 --- a/arch/sparc/kernel/etrap.S +++ b/arch/sparc/kernel/etrap.S @@ -1,4 +1,4 @@ -/* $Id: etrap.S,v 1.17 1996/03/07 06:26:43 davem Exp $ +/* $Id: etrap.S,v 1.18 1996/04/25 06:08:35 davem Exp $ * etrap.S: Sparc trap window preparation for entry into the * Linux kernel. * diff --git a/arch/sparc/kernel/head.S b/arch/sparc/kernel/head.S index b57190b28f43..c6cffe4258b7 100644 --- a/arch/sparc/kernel/head.S +++ b/arch/sparc/kernel/head.S @@ -1,4 +1,4 @@ -/* $Id: head.S,v 1.56 1996/04/04 16:30:22 tridge Exp $ +/* $Id: head.S,v 1.57 1996/04/25 06:08:38 davem Exp $ * head.S: The initial boot code for the Sparc port of Linux. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/kernel/idprom.c b/arch/sparc/kernel/idprom.c index 5c6b63a48b66..cc7c085cee0f 100644 --- a/arch/sparc/kernel/idprom.c +++ b/arch/sparc/kernel/idprom.c @@ -1,4 +1,4 @@ -/* $Id: idprom.c,v 1.18 1995/11/25 00:58:05 davem Exp $ +/* $Id: idprom.c,v 1.19 1996/04/25 06:08:41 davem Exp $ * idprom.c: Routines to load the idprom into kernel addresses and * interpret the data contained within. * diff --git a/arch/sparc/kernel/ioport.c b/arch/sparc/kernel/ioport.c index 93ae2ffa53b0..cb2990d1840b 100644 --- a/arch/sparc/kernel/ioport.c +++ b/arch/sparc/kernel/ioport.c @@ -1,4 +1,4 @@ -/* $Id: ioport.c,v 1.17 1996/03/23 02:39:13 davem Exp $ +/* $Id: ioport.c,v 1.18 1996/04/25 06:08:44 davem Exp $ * ioport.c: Simple io mapping allocator. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/kernel/irq.c b/arch/sparc/kernel/irq.c index a00f93831562..edf500152b2d 100644 --- a/arch/sparc/kernel/irq.c +++ b/arch/sparc/kernel/irq.c @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.43 1996/04/17 12:37:45 zaitcev Exp $ +/* $Id: irq.c,v 1.44 1996/04/25 06:08:46 davem Exp $ * arch/sparc/kernel/irq.c: Interrupt request handling routines. On the * Sparc the IRQ's are basically 'cast in stone' * and you are supposed to probe the prom's device diff --git a/arch/sparc/kernel/process.c b/arch/sparc/kernel/process.c index 26b2dd02204b..cee3e95b31eb 100644 --- a/arch/sparc/kernel/process.c +++ b/arch/sparc/kernel/process.c @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.49 1996/04/20 07:37:20 davem Exp $ +/* $Id: process.c,v 1.51 1996/04/25 06:08:49 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -78,12 +78,9 @@ int cpu_idle(void *unused) volatile int *spap = &smp_process_available; volatile int cval; - current->priority = -50; while(1) { if(0==read_smp_counter(spap)) continue; - while(*spap == -1) - ; cli(); /* Acquire exclusive access. */ while((cval = smp_swap(spap, -1)) == -1) diff --git a/arch/sparc/kernel/ptrace.c b/arch/sparc/kernel/ptrace.c new file mode 100644 index 000000000000..ceb464aafa74 --- /dev/null +++ b/arch/sparc/kernel/ptrace.c @@ -0,0 +1,801 @@ +/* ptrace.c: Sparc process tracing support. + * + * Copyright (C) 1996 David S. Miller (davem@caipfs.rutgers.edu) + * + * Based upon code written by Ross Biro, Linus Torvalds, Bob Manson, + * and David Mosberger. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +/* 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 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. + */ +static unsigned long get_long(struct task_struct * tsk, + struct vm_area_struct * vma, unsigned long addr) +{ + pgd_t * pgdir; + pmd_t * pgmiddle; + pte_t * pgtable; + unsigned long page, retval; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (pgd_none(*pgdir)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return 0; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return 0; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + do_no_page(tsk, vma, addr, 0); + goto repeat; + } + page = pte_page(*pgtable); +/* this is a hack for non-kernel-mapped video buffers and similar */ + if (page >= high_memory) + return 0; + page += addr & ~PAGE_MASK; + retval = *(unsigned long *) page; + flush_page_to_ram(page); + return retval; +} + +/* + * 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, struct vm_area_struct * vma, + unsigned long addr, unsigned long data) +{ + pgd_t *pgdir; + pmd_t *pgmiddle; + pte_t *pgtable; + unsigned long page; + +repeat: + pgdir = pgd_offset(vma->vm_mm, addr); + if (!pgd_present(*pgdir)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + if (pgd_bad(*pgdir)) { + printk("ptrace: bad page directory %08lx\n", pgd_val(*pgdir)); + pgd_clear(pgdir); + return; + } + pgmiddle = pmd_offset(pgdir, addr); + if (pmd_none(*pgmiddle)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + if (pmd_bad(*pgmiddle)) { + printk("ptrace: bad page middle %08lx\n", pmd_val(*pgmiddle)); + pmd_clear(pgmiddle); + return; + } + pgtable = pte_offset(pgmiddle, addr); + if (!pte_present(*pgtable)) { + do_no_page(tsk, vma, addr, 1); + goto repeat; + } + page = pte_page(*pgtable); + if (!pte_write(*pgtable)) { + do_wp_page(tsk, vma, addr, 1); + goto repeat; + } +/* this is a hack for non-kernel-mapped video buffers and similar */ + flush_cache_page(vma, page); + if (page < high_memory) { + *(unsigned long *) (page + (addr & ~PAGE_MASK)) = data; + flush_page_to_ram(page); + } +/* we're bypassing pagetables, so we have to set the dirty bit ourselves */ +/* this should also re-instate whatever read-only mode there was before */ + set_pte(pgtable, pte_mkdirty(mk_pte(page, vma->vm_page_prot))); + flush_tlb_page(vma, page); +} + +static struct vm_area_struct * find_extend_vma(struct task_struct * tsk, + unsigned long addr) +{ + struct vm_area_struct * vma; + + addr &= PAGE_MASK; + vma = find_vma(tsk,addr); + if (!vma) + return NULL; + if (vma->vm_start <= addr) + return vma; + if (!(vma->vm_flags & VM_GROWSDOWN)) + return NULL; + if (vma->vm_end - addr > tsk->rlim[RLIMIT_STACK].rlim_cur) + return NULL; + vma->vm_offset -= vma->vm_start - addr; + vma->vm_start = addr; + return vma; +} + +/* + * 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) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + *result = get_long(tsk, vma, addr); + return 0; +} + +static int read_byte(struct task_struct *tsk, unsigned long addr, + unsigned char *result) +{ + struct vm_area_struct *vma = find_extend_vma(tsk, addr&~3); + unsigned long tmp; + + if(!vma) + return -EIO; + tmp = get_long(tsk, vma, (addr & ~3)); + switch(addr & 3) { + case 0: + *result = (tmp & 0xff000000)>>24; + break; + case 1: + *result = (tmp & 0x00ff0000)>>16; + break; + case 2: + *result = (tmp & 0x0000ff00)>>8; + break; + case 3: + *result = (tmp & 0x000000ff); + break; + } + 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) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, addr); + + if (!vma) + return -EIO; + put_long(tsk, vma, addr, data); + return 0; +} + +static int write_byte(struct task_struct * tsk, unsigned long addr, + unsigned char data) +{ + struct vm_area_struct * vma = find_extend_vma(tsk, (addr & ~3)); + unsigned long tmp; + + if (!vma) + return -EIO; + tmp = get_long(tsk, vma, (addr & ~3)); + switch(addr & 3) { + case 0: + tmp &= 0x00ffffff; + tmp |= (data << 24); + break; + case 1: + tmp &= 0xff00ffff; + tmp |= ((data << 16) & 0x00ff0000); + break; + case 2: + tmp &= 0xffff00ff; + tmp |= ((data << 8) & 0x0000ff00); + break; + case 3: + tmp &= 0xffffff00; + tmp |= (data & 0x000000ff); + break; + } + put_long(tsk, vma, (addr & ~3), tmp); + return 0; +} + +/* Returning from ptrace is a bit tricky because the syscall return + * low level code assumes any value returned which is negative and + * is a valid errno will mean setting the condition codes to indicate + * an error return. This doesn't work, so we have this hook. + */ +static inline void pt_error_return(struct pt_regs *regs, unsigned long error) +{ + regs->u_regs[UREG_I0] = error; + regs->psr |= PSR_C; + regs->pc = regs->npc; + regs->npc += 4; +} + +static inline void pt_succ_return(struct pt_regs *regs, unsigned long value) +{ + regs->u_regs[UREG_I0] = value; + regs->psr &= ~PSR_C; + regs->pc = regs->npc; + regs->npc += 4; +} + +/* Fuck me gently with a chainsaw... */ +static inline void read_sunos_user(struct pt_regs *regs, unsigned long offset, + struct task_struct *tsk) +{ + struct pt_regs *cregs = tsk->tss.kregs; + struct thread_struct *t = &tsk->tss; + + if(offset >= 1024) + offset -= 1024; /* whee... */ + if(offset & ((sizeof(unsigned long) - 1))) { + pt_error_return(regs, EIO); + return; + } + if(offset >= 16 && offset < 784) { + offset -= 16; offset >>= 2; + pt_succ_return(regs, *(((unsigned long *)(&t->reg_window[0]))+offset)); + return; + } + if(offset >= 784 && offset < 832) { + offset -= 784; offset >>= 2; + pt_succ_return(regs, *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset)); + return; + } + switch(offset) { + case 0: + regs->u_regs[UREG_I0] = t->ksp; + break; + case 4: + regs->u_regs[UREG_I0] = t->kpc; + break; + case 8: + regs->u_regs[UREG_I0] = t->kpsr; + break; + case 12: + regs->u_regs[UREG_I0] = t->uwinmask; + break; + case 832: + regs->u_regs[UREG_I0] = t->w_saved; + break; + case 896: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0]; + break; + case 900: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1]; + break; + case 904: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I2]; + break; + case 908: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I3]; + break; + case 912: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I4]; + break; + case 916: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I5]; + break; + case 920: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I6]; + break; + case 924: + if(tsk->tss.flags & 0x80000000) + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_G1]; + else + regs->u_regs[UREG_I0] = 0; + break; + case 940: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0]; + break; + case 944: + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I1]; + break; + + case 948: + /* Isn't binary compatability _fun_??? */ + if(cregs->psr & PSR_C) + regs->u_regs[UREG_I0] = cregs->u_regs[UREG_I0] << 24; + else + regs->u_regs[UREG_I0] = 0; + break; + + /* Rest of them are completely unsupported. */ + default: + printk("%s [%d]: Wants to read user offset %d\n", + current->comm, current->pid, offset); + pt_error_return(regs, EIO); + return; + } + regs->psr &= ~PSR_C; + regs->pc = regs->npc; + regs->npc += 4; + return; +} + +static inline void write_sunos_user(struct pt_regs *regs, unsigned long offset, + struct task_struct *tsk) +{ + struct pt_regs *cregs = tsk->tss.kregs; + struct thread_struct *t = &tsk->tss; + unsigned long value = regs->u_regs[UREG_I3]; + + if(offset >= 1024) + offset -= 1024; /* whee... */ + if(offset & ((sizeof(unsigned long) - 1))) + goto failure; + if(offset >= 16 && offset < 784) { + offset -= 16; offset >>= 2; + *(((unsigned long *)(&t->reg_window[0]))+offset) = value; + goto success; + } + if(offset >= 784 && offset < 832) { + offset -= 784; offset >>= 2; + *(((unsigned long *)(&t->rwbuf_stkptrs[0]))+offset) = value; + goto success; + } + switch(offset) { + case 896: + cregs->u_regs[UREG_I0] = value; + break; + case 900: + cregs->u_regs[UREG_I1] = value; + break; + case 904: + cregs->u_regs[UREG_I2] = value; + break; + case 908: + cregs->u_regs[UREG_I3] = value; + break; + case 912: + cregs->u_regs[UREG_I4] = value; + break; + case 916: + cregs->u_regs[UREG_I5] = value; + break; + case 920: + cregs->u_regs[UREG_I6] = value; + break; + case 924: + cregs->u_regs[UREG_I7] = value; + break; + case 940: + cregs->u_regs[UREG_I0] = value; + break; + case 944: + cregs->u_regs[UREG_I1] = value; + break; + + /* Rest of them are completely unsupported or "no-touch". */ + default: + printk("%s [%d]: Wants to write user offset %d\n", + current->comm, current->pid, offset); + goto failure; + } +success: + pt_succ_return(regs, 0); + return; +failure: + pt_error_return(regs, EIO); + return; +} + +/* #define ALLOW_INIT_TRACING */ +/* #define DEBUG_PTRACE */ + +asmlinkage void do_ptrace(struct pt_regs *regs) +{ + unsigned long request = regs->u_regs[UREG_I0]; + unsigned long pid = regs->u_regs[UREG_I1]; + unsigned long addr = regs->u_regs[UREG_I2]; + unsigned long data = regs->u_regs[UREG_I3]; + unsigned long addr2 = regs->u_regs[UREG_I4]; + struct task_struct *child; + +#ifdef DEBUG_PTRACE + printk("do_ptrace: rq=%d pid=%d addr=%08lx data=%08lx addr2=%08lx\n", + (int) request, (int) pid, addr, data, addr2); +#endif + if(request == PTRACE_TRACEME) { + /* are we already being traced? */ + if (current->flags & PF_PTRACED) { + pt_error_return(regs, EPERM); + return; + } + /* set the ptrace bit in the process flags. */ + current->flags |= PF_PTRACED; + pt_succ_return(regs, 0); + return; + } +#ifndef ALLOW_INIT_TRACING + if(pid == 1) { + /* Can't dork with init. */ + pt_error_return(regs, EPERM); + return; + } +#endif + if(!(child = get_task(pid))) { + pt_error_return(regs, ESRCH); + return; + } + + if(request == PTRACE_SUNATTACH) { + if(child == current) { + /* Try this under SunOS/Solaris, bwa haha + * You'll never be able to kill the process. ;-) + */ + pt_error_return(regs, EPERM); + return; + } + if((!child->dumpable || + (current->uid != child->euid) || + (current->uid != child->uid) || + (current->gid != child->egid) || + (current->gid != child->gid)) && !suser()) { + pt_error_return(regs, EPERM); + return; + } + /* the same process cannot be attached many times */ + if (child->flags & PF_PTRACED) { + pt_error_return(regs, EPERM); + return; + } + child->flags |= PF_PTRACED; + if(child->p_pptr != current) { + REMOVE_LINKS(child); + child->p_pptr = current; + SET_LINKS(child); + } + send_sig(SIGSTOP, child, 1); + pt_succ_return(regs, 0); + return; + } + if(!(child->flags & PF_PTRACED)) { + pt_error_return(regs, ESRCH); + return; + } + if(child->state != TASK_STOPPED) { + if(request != PTRACE_KILL) { + pt_error_return(regs, ESRCH); + return; + } + } + if(child->p_pptr != current) { + pt_error_return(regs, ESRCH); + return; + } + switch(request) { + case PTRACE_PEEKTEXT: /* read word at location addr. */ + case PTRACE_PEEKDATA: { + unsigned long tmp; + int res; + + /* Non-word alignment _not_ allowed on Sparc. */ + if(addr & (sizeof(unsigned long) - 1)) { + pt_error_return(regs, EINVAL); + return; + } + res = read_long(child, addr, &tmp); + if (res < 0) { + pt_error_return(regs, -res); + return; + } + pt_succ_return(regs, tmp); + return; + } + + case PTRACE_PEEKUSR: + read_sunos_user(regs, addr, child); + return; + + case PTRACE_POKEUSR: + write_sunos_user(regs, addr, child); + return; + + case PTRACE_POKETEXT: /* write the word at location addr. */ + case PTRACE_POKEDATA: { + struct vm_area_struct *vma; + int res; + + /* Non-word alignment _not_ allowed on Sparc. */ + if(addr & (sizeof(unsigned long) - 1)) { + pt_error_return(regs, EINVAL); + return; + } + vma = find_extend_vma(child, addr); + if(vma && request == PTRACE_POKEDATA && (vma->vm_flags & VM_EXEC)) { + pt_error_return(regs, EIO); + return; + } + res = write_long(child, addr, data); + if(res < 0) + pt_error_return(regs, -res); + else + pt_succ_return(regs, res); + return; + } + + case PTRACE_GETREGS: { + struct pt_regs *pregs = (struct pt_regs *) addr; + struct pt_regs *cregs = child->tss.kregs; + int rval; + + rval = verify_area(VERIFY_WRITE, pregs, sizeof(struct pt_regs) - 4); + if(rval) { + pt_error_return(regs, rval); + return; + } + pregs->psr = cregs->psr; + pregs->pc = cregs->pc; + pregs->npc = cregs->npc; + pregs->y = cregs->y; + for(rval = 1; rval < 16; rval++) + pregs->u_regs[rval - 1] = cregs->u_regs[rval]; + pt_succ_return(regs, 0); + return; + } + + case PTRACE_SETREGS: { + struct pt_regs *pregs = (struct pt_regs *) addr; + struct pt_regs *cregs = child->tss.kregs; + unsigned long psr; + int rval, i; + + rval = verify_area(VERIFY_READ, pregs, sizeof(struct pt_regs) - 4); + if(rval) { + pt_error_return(regs, rval); + return; + } + /* Must be careful, tracing process can only set certain + * bits in the psr. + */ + psr = (pregs->psr) & PSR_ICC; + cregs->psr &= ~PSR_ICC; + cregs->psr |= psr; + if(!((pregs->pc | pregs->npc) & 3)) { + cregs->pc = pregs->pc; + cregs->npc = pregs->npc; + } + cregs->y = pregs->y; + for(i = 1; i < 16; i++) + cregs->u_regs[i] = pregs->u_regs[i-1]; + pt_succ_return(regs, 0); + return; + } + + case PTRACE_GETFPREGS: { + struct fps { + unsigned long regs[32]; + unsigned long fsr; + unsigned long flags; + unsigned long extra; + unsigned long fpqd; + struct fq { + unsigned long *insnaddr; + unsigned long insn; + } fpq[16]; + } *fps = (struct fps *) addr; + int rval, i; + + rval = verify_area(VERIFY_WRITE, fps, sizeof(struct fps)); + if(rval) { pt_error_return(regs, rval); return; } + for(i = 0; i < 32; i++) + fps->regs[i] = child->tss.float_regs[i]; + fps->fsr = child->tss.fsr; + fps->fpqd = child->tss.fpqdepth; + fps->flags = fps->extra = 0; + for(i = 0; i < 16; i++) { + fps->fpq[i].insnaddr = child->tss.fpqueue[i].insn_addr; + fps->fpq[i].insn = child->tss.fpqueue[i].insn; + } + pt_succ_return(regs, 0); + return; + } + + case PTRACE_SETFPREGS: { + struct fps { + unsigned long regs[32]; + unsigned long fsr; + unsigned long flags; + unsigned long extra; + unsigned long fpqd; + struct fq { + unsigned long *insnaddr; + unsigned long insn; + } fpq[16]; + } *fps = (struct fps *) addr; + int rval, i; + + rval = verify_area(VERIFY_READ, fps, sizeof(struct fps)); + if(rval) { pt_error_return(regs, rval); return; } + for(i = 0; i < 32; i++) + child->tss.float_regs[i] = fps->regs[i]; + child->tss.fsr = fps->fsr; + child->tss.fpqdepth = fps->fpqd; + for(i = 0; i < 16; i++) { + child->tss.fpqueue[i].insn_addr = fps->fpq[i].insnaddr; + child->tss.fpqueue[i].insn = fps->fpq[i].insn; + } + pt_succ_return(regs, 0); + return; + } + + case PTRACE_READTEXT: + case PTRACE_READDATA: { + unsigned char *dest = (unsigned char *) addr2; + unsigned long src = addr; + unsigned char tmp; + int res, len = data; + + res = verify_area(VERIFY_WRITE, (void *) dest, len); + if(res) { + pt_error_return(regs, -res); + return; + } + while(len) { + res = read_byte(child, src, &tmp); + if(res < 0) { + pt_error_return(regs, -res); + return; + } + *dest = tmp; + src++; dest++; len--; + } + pt_succ_return(regs, 0); + return; + } + + case PTRACE_WRITETEXT: + case PTRACE_WRITEDATA: { + unsigned char *src = (unsigned char *) addr2; + unsigned long dest = addr; + int res, len = data; + + res = verify_area(VERIFY_READ, (void *) src, len); + if(res) { + pt_error_return(regs, -res); + return; + } + while(len) { + res = write_byte(child, dest, *src); + if(res < 0) { + pt_error_return(regs, -res); + return; + } + src++; dest++; len--; + } + pt_succ_return(regs, 0); + return; + } + + case PTRACE_SYSCALL: /* continue and stop at (return from) syscall */ + data = 0; + addr = 1; + + case PTRACE_CONT: { /* restart after signal. */ + if ((unsigned long) data > NSIG) { + pt_error_return(regs, EIO); + return; + } + if (request == PTRACE_SYSCALL) + child->flags |= PF_TRACESYS; + else + child->flags &= ~PF_TRACESYS; + child->exit_code = data; + if((addr != 1) & !(addr & 3)) { + child->tss.kregs->pc = addr; + child->tss.kregs->npc = addr + 4; + } + wake_up_process(child); + pt_succ_return(regs, 0); + return; + } + +/* + * make the child exit. Best I can do is send it a sigkill. + * perhaps it should be put in the status that it wants to + * exit. + */ + case PTRACE_KILL: { + if (child->state == TASK_ZOMBIE) { /* already dead */ + pt_succ_return(regs, 0); + return; + } + wake_up_process(child); + child->exit_code = SIGKILL; + pt_succ_return(regs, 0); + return; + } + + case PTRACE_SUNDETACH: { /* detach a process that was attached. */ + if ((unsigned long) data > NSIG) { + pt_error_return(regs, EIO); + return; + } + child->flags &= ~(PF_PTRACED|PF_TRACESYS); + wake_up_process(child); + child->exit_code = data; + REMOVE_LINKS(child); + child->p_pptr = child->p_opptr; + SET_LINKS(child); + pt_succ_return(regs, 0); + return; + } + + /* PTRACE_DUMPCORE unsupported... */ + + default: + pt_error_return(regs, EIO); + return; + } +} + +asmlinkage void syscall_trace(void) +{ +#ifdef DEBUG_PTRACE + printk("%s [%d]: syscall_trace\n", current->comm, current->pid); +#endif + if ((current->flags & (PF_PTRACED|PF_TRACESYS)) + != (PF_PTRACED|PF_TRACESYS)) + return; + current->exit_code = SIGTRAP; + current->state = TASK_STOPPED; + current->tss.flags ^= 0x80000000; + 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/arch/sparc/kernel/setup.c b/arch/sparc/kernel/setup.c index bf6fbc844f61..58200bb4d9de 100644 --- a/arch/sparc/kernel/setup.c +++ b/arch/sparc/kernel/setup.c @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.60 1996/04/04 16:30:28 tridge Exp $ +/* $Id: setup.c,v 1.62 1996/04/25 09:11:33 davem Exp $ * linux/arch/sparc/kernel/setup.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -212,22 +212,13 @@ static struct pt_regs fake_swapper_regs = { 0, 0, 0, 0, { 0, } }; void setup_arch(char **cmdline_p, unsigned long * memory_start_p, unsigned long * memory_end_p) { - int total, i, panic_stuff[2], packed; + int total, i, packed; #if CONFIG_AP1000 register_console(prom_printf); ((char *)(&cputypval))[4] = 'm'; /* ugly :-( */ #endif -#if 0 - /* Always reboot on panic, but give 5 seconds to hit L1-A - * and look at debugging info if desired. - */ - panic_stuff[0] = 1; - panic_stuff[1] = 5; - panic_setup(0, panic_stuff); -#endif - sparc_ttable = (struct tt_entry *) &start; /* Initialize PROM console and command line. */ diff --git a/arch/sparc/kernel/signal.c b/arch/sparc/kernel/signal.c index 9f12ac964171..8987d6cf7e25 100644 --- a/arch/sparc/kernel/signal.c +++ b/arch/sparc/kernel/signal.c @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.31 1996/04/18 01:00:41 davem Exp $ +/* $Id: signal.c,v 1.32 1996/04/22 19:37:48 davem Exp $ * linux/arch/sparc/kernel/signal.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -232,6 +232,22 @@ asmlinkage int do_signal(unsigned long oldmask, struct pt_regs * regs) clear_bit(signr, ¤t->signal); sa = current->sig->action + 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->sig->action + signr - 1; + } if(sa->sa_handler == SIG_IGN) { if(signr != SIGCHLD) continue; diff --git a/arch/sparc/kernel/smp.c b/arch/sparc/kernel/smp.c index 60c538bb1ea8..8a4d1604cdf4 100644 --- a/arch/sparc/kernel/smp.c +++ b/arch/sparc/kernel/smp.c @@ -93,7 +93,7 @@ char *smp_info(void) sprintf(smp_buf, "\n CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n" "State: %s\t\t%s\t\t%s\t\t%s\n" -"Lock: %08lx\t\t%08lx\t%08lx\t\t%08lx\n" +"Lock: %08lx\t\t%08lx\t%08lx\t%08lx\n" "\n" "klock: %x\n", (cpu_present_map & 1) ? ((active_kernel_processor == 0) ? "akp" : "online") : "offline", @@ -236,7 +236,6 @@ void smp_boot_cpus(void) /* whirrr, whirrr, whirrrrrrrrr... */ printk("Starting CPU %d at %p\n", i, entry); mid_xlate[i] = (linux_cpus[i].mid & ~8); - current_set[i] = &init_task; local_flush_cache_all(); prom_startcpu(linux_cpus[i].prom_node, &penguin_ctable, 0, (char *)entry); @@ -255,7 +254,6 @@ void smp_boot_cpus(void) } else { printk("Penguin %d is stuck in the bottle.\n", i); } - current_set[i] = 0; } if(!(cpu_callin_map[i])) { cpu_present_map &= ~(1 << i); diff --git a/arch/sparc/kernel/sparc-stub.c b/arch/sparc/kernel/sparc-stub.c index 9e18e53e60c6..5e10f57c5ad1 100644 --- a/arch/sparc/kernel/sparc-stub.c +++ b/arch/sparc/kernel/sparc-stub.c @@ -1,4 +1,4 @@ -/* $Id: sparc-stub.c,v 1.15 1996/04/04 12:41:35 davem Exp $ +/* $Id: sparc-stub.c,v 1.16 1996/04/25 06:09:01 davem Exp $ * sparc-stub.c: KGDB support for the Linux kernel. * * Modifications to run under Linux diff --git a/arch/sparc/kernel/sunos_ioctl.c b/arch/sparc/kernel/sunos_ioctl.c index 5e523bf8f2b5..7b2fb486e3c9 100644 --- a/arch/sparc/kernel/sunos_ioctl.c +++ b/arch/sparc/kernel/sunos_ioctl.c @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl.c,v 1.18 1996/04/04 12:41:38 davem Exp $ +/* $Id: sunos_ioctl.c,v 1.20 1996/04/25 06:09:08 davem Exp $ * sunos_ioctl.c: The Linux Operating system: SunOS ioctl compatibility. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -139,8 +139,43 @@ asmlinkage int sunos_ioctl (int fd, unsigned long cmd, unsigned long arg) */ return 0; /* Non posix grp */ - case _IOR('t', 119, int): - return -EIO; + case _IOW('t', 118, int): { + int oldval, *ptr; + + cmd = TIOCSPGRP; + ptr = (int *) arg; + oldval = verify_area(VERIFY_WRITE, ptr, sizeof(int)); + if(oldval) + return oldval; + oldval = *ptr; + foo = sys_ioctl(fd, cmd, arg); + if(*ptr == -1) { + *ptr = oldval; + foo = -EIO; + } + if(foo == -ENOTTY) + foo = -EIO; + return foo; + } + + case _IOR('t', 119, int): { + int oldval, *ptr; + + cmd = TIOCGPGRP; + ptr = (int *) arg; + oldval = verify_area(VERIFY_WRITE, ptr, sizeof(int)); + if(oldval) + return oldval; + oldval = *ptr; + foo = sys_ioctl(fd, cmd, arg); + if(*ptr == -1) { + *ptr = oldval; + foo = -EIO; + } + if(foo == -ENOTTY) + foo = -EIO; + return foo; + } } #if 0 diff --git a/arch/sparc/kernel/sys_sparc.c b/arch/sparc/kernel/sys_sparc.c index da7d187d03dd..d9fa43e0f32d 100644 --- a/arch/sparc/kernel/sys_sparc.c +++ b/arch/sparc/kernel/sys_sparc.c @@ -1,4 +1,4 @@ -/* $Id: sys_sparc.c,v 1.10 1996/04/20 08:33:55 davem Exp $ +/* $Id: sys_sparc.c,v 1.11 1996/04/25 06:09:10 davem Exp $ * linux/arch/sparc/kernel/sys_sparc.c * * This file contains various random system calls that diff --git a/arch/sparc/kernel/sys_sunos.c b/arch/sparc/kernel/sys_sunos.c index 8f3e2c05f8fc..af9a480d0ca2 100644 --- a/arch/sparc/kernel/sys_sunos.c +++ b/arch/sparc/kernel/sys_sunos.c @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.37 1996/04/19 16:52:38 miguel Exp $ +/* $Id: sys_sunos.c,v 1.40 1996/04/25 09:11:36 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -35,6 +35,8 @@ #include #include #include +#include +#include #include #include #include @@ -565,7 +567,7 @@ asmlinkage int sunos_fpathconf(int fd, int name) case _PCONF_NOTRUNC: return 0; /* XXX Investigate XXX */ case _PCONF_VDISABLE: - return 30; /* XXX Investigate XXX */ + return 0; default: return -EINVAL; } @@ -1011,3 +1013,34 @@ repeat: return fdcount; } +extern asmlinkage int sys_shmat (int shmid, char *shmaddr, int shmflg, ulong *raddr); +extern asmlinkage int sys_shmctl (int shmid, int cmd, struct shmid_ds *buf); +extern asmlinkage int sys_shmdt (char *shmaddr); +extern asmlinkage int sys_shmget (key_t key, int size, int shmflg); + +asmlinkage int sunos_shmsys(int op, unsigned long arg1, unsigned long arg2, + unsigned long arg3) +{ + unsigned long raddr; + int rval; + + switch(op) { + case 0: + /* sys_shmat(): attach a shared memory area */ + rval = sys_shmat((int)arg1,(char *)arg2,(int)arg3,&raddr); + if(rval != 0) + return rval; + return (int) raddr; + case 1: + /* sys_shmctl(): modify shared memory area attr. */ + return sys_shmctl((int)arg1,(int)arg2,(struct shmid_ds *)arg3); + case 2: + /* sys_shmdt(): detach a shared memory area */ + return sys_shmdt((char *)arg1); + case 3: + /* sys_shmget(): get a shared memory area */ + return sys_shmget((key_t)arg1,(int)arg2,(int)arg3); + default: + return -EINVAL; + } +} diff --git a/arch/sparc/kernel/systbls.S b/arch/sparc/kernel/systbls.S index 7816f53f232d..92b6eda7ccdc 100644 --- a/arch/sparc/kernel/systbls.S +++ b/arch/sparc/kernel/systbls.S @@ -1,4 +1,4 @@ -/* $Id: systbls.S,v 1.38 1996/04/20 08:43:26 davem Exp $ +/* $Id: systbls.S,v 1.41 1996/04/25 09:11:39 davem Exp $ * systbls.S: System call entry point tables for OS compatibility. * The native Linux system call table lives here also. * @@ -147,7 +147,7 @@ C_LABEL(sunos_sys_table): .long C_LABEL(sys_chmod), C_LABEL(sys_chown), C_LABEL(sunos_brk) .long C_LABEL(sunos_nosys), C_LABEL(sys_lseek), C_LABEL(sunos_getpid) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) + .long C_LABEL(sunos_getuid), C_LABEL(sunos_nosys), C_LABEL(sys_ptrace) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sys_access), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) @@ -197,7 +197,7 @@ C_LABEL(sunos_sys_table): .long C_LABEL(sunos_getdomainname), C_LABEL(sys_setdomainname) .long C_LABEL(sunos_nosys), C_LABEL(sys_quotactl), C_LABEL(sunos_nosys) .long C_LABEL(sunos_mount), C_LABEL(sys_ustat), C_LABEL(sunos_nosys) - .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_audit) + .long C_LABEL(sunos_nosys), C_LABEL(sunos_shmsys), C_LABEL(sunos_audit) .long C_LABEL(sunos_nosys), C_LABEL(sunos_getdents), C_LABEL(sys_setsid) .long C_LABEL(sys_fchdir), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) .long C_LABEL(sunos_nosys), C_LABEL(sunos_nosys), C_LABEL(sunos_nosys) diff --git a/arch/sparc/kernel/traps.c b/arch/sparc/kernel/traps.c index 614cd9c5b7ac..1b9c46ba3a9e 100644 --- a/arch/sparc/kernel/traps.c +++ b/arch/sparc/kernel/traps.c @@ -1,4 +1,4 @@ -/* $Id: traps.c,v 1.42 1996/04/16 08:24:44 davem Exp $ +/* $Id: traps.c,v 1.43 1996/04/24 09:09:42 davem Exp $ * arch/sparc/kernel/traps.c * * Copyright 1995 David S. Miller (davem@caip.rutgers.edu) @@ -21,6 +21,7 @@ #include #include #include +#include #include /* #define TRAP_DEBUG */ @@ -95,6 +96,10 @@ void do_hw_interrupt(unsigned long type, unsigned long psr, unsigned long pc) printk("Unimplemented Sparc TRAP, type = %02lx\n", type); die_if_kernel("Whee... Hello Mr. Penguin", current->tss.kregs); } + if(type == SP_TRAP_SBPT) { + send_sig(SIGTRAP, current, 1); + return; + } current->tss.sig_desc = SUBSIG_BADTRAP(type - 0x80); current->tss.sig_address = pc; send_sig(SIGILL, current, 1); diff --git a/arch/sparc/kernel/wuf.S b/arch/sparc/kernel/wuf.S index cb92857d378f..a667fed7980f 100644 --- a/arch/sparc/kernel/wuf.S +++ b/arch/sparc/kernel/wuf.S @@ -1,4 +1,4 @@ -/* $Id: wuf.S,v 1.22 1996/04/03 02:15:13 davem Exp $ +/* $Id: wuf.S,v 1.23 1996/04/25 06:09:18 davem Exp $ * wuf.S: Window underflow trap handler for the Sparc. * * Copyright (C) 1995 David S. Miller diff --git a/arch/sparc/mm/fault.c b/arch/sparc/mm/fault.c index 16b085d34815..e0367faeefa6 100644 --- a/arch/sparc/mm/fault.c +++ b/arch/sparc/mm/fault.c @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.61 1996/04/12 06:52:35 davem Exp $ +/* $Id: fault.c,v 1.62 1996/04/25 06:09:26 davem Exp $ * fault.c: Page fault handlers for the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/generic.c b/arch/sparc/mm/generic.c index 7a9093246d4a..d8d7e5196220 100644 --- a/arch/sparc/mm/generic.c +++ b/arch/sparc/mm/generic.c @@ -1,4 +1,5 @@ -/* generic.c: Generic Sparc mm routines that are not dependent upon +/* $Id: generic.c,v 1.2 1996/04/25 06:09:30 davem Exp $ + * generic.c: Generic Sparc mm routines that are not dependent upon * MMU type but are Sparc specific. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/init.c b/arch/sparc/mm/init.c index 9e0203457cbc..cc9cffa79a01 100644 --- a/arch/sparc/mm/init.c +++ b/arch/sparc/mm/init.c @@ -1,4 +1,4 @@ -/* $Id: init.c,v 1.36 1996/04/16 08:02:54 davem Exp $ +/* $Id: init.c,v 1.37 1996/04/25 06:09:33 davem Exp $ * linux/arch/sparc/mm/init.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/arch/sparc/mm/srmmu.c b/arch/sparc/mm/srmmu.c index c7b7f4c446b3..6725145e7461 100644 --- a/arch/sparc/mm/srmmu.c +++ b/arch/sparc/mm/srmmu.c @@ -1,4 +1,4 @@ -/* $Id: srmmu.c,v 1.59 1996/04/21 10:32:21 davem Exp $ +/* $Id: srmmu.c,v 1.62 1996/04/25 09:11:47 davem Exp $ * srmmu.c: SRMMU specific routines for memory management. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -604,11 +604,14 @@ static void tsunami_flush_cache_page_to_uncache(unsigned long page) /* Tsunami does not have a Copy-back style virtual cache. */ static void tsunami_flush_page_to_ram(unsigned long page) { + tsunami_flush_icache(); + tsunami_flush_dcache(); } /* However, Tsunami is not IO coherent. */ static void tsunami_flush_page_for_dma(unsigned long page) { + tsunami_flush_icache(); tsunami_flush_dcache(); } @@ -805,7 +808,6 @@ static void swift_flush_tlb_page_for_cbit(unsigned long page) static void viking_flush_cache_all(void) { - viking_flush_icache(); } static void viking_flush_cache_mm(struct mm_struct *mm) @@ -814,7 +816,6 @@ static void viking_flush_cache_mm(struct mm_struct *mm) if(mm->context != NO_CONTEXT) { #endif flush_user_windows(); - viking_flush_icache(); #ifndef __SMP__ } #endif @@ -826,7 +827,6 @@ static void viking_flush_cache_range(struct mm_struct *mm, unsigned long start, if(mm->context != NO_CONTEXT) { #endif flush_user_windows(); - viking_flush_icache(); #ifndef __SMP__ } #endif @@ -839,8 +839,6 @@ static void viking_flush_cache_page(struct vm_area_struct *vma, unsigned long pa if(mm->context != NO_CONTEXT) { #endif flush_user_windows(); - if(vma->vm_flags & VM_EXEC) - viking_flush_icache(); #ifndef __SMP__ } #endif diff --git a/arch/sparc/prom/memory.c b/arch/sparc/prom/memory.c index 82dfa6d70bdd..805c1bded197 100644 --- a/arch/sparc/prom/memory.c +++ b/arch/sparc/prom/memory.c @@ -1,4 +1,4 @@ -/* $Id: memory.c,v 1.6 1996/04/08 09:02:27 davem Exp $ +/* $Id: memory.c,v 1.7 1996/04/25 06:09:46 davem Exp $ * memory.c: Prom routine for acquiring various bits of information * about RAM on the machine, both virtual and physical. * diff --git a/arch/sparc/prom/palloc.c b/arch/sparc/prom/palloc.c index 388f71a3c59f..84ce8bc54473 100644 --- a/arch/sparc/prom/palloc.c +++ b/arch/sparc/prom/palloc.c @@ -1,4 +1,4 @@ -/* $Id: palloc.c,v 1.3 1995/11/25 01:00:08 davem Exp $ +/* $Id: palloc.c,v 1.4 1996/04/25 06:09:48 davem Exp $ * palloc.c: Memory allocation from the Sun PROM. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/drivers/block/amiflop.c b/drivers/block/amiflop.c index 58ffd45a2f40..0d580061b8cc 100644 --- a/drivers/block/amiflop.c +++ b/drivers/block/amiflop.c @@ -677,7 +677,7 @@ unsigned short crc; /* on 68000 we got an alignment problem, but this compiler solves it by adding silently adding a pad byte so data wont fit and this cost about 3h to discover.... */ -unsigned char gap1[22]; /* for longword-aligndness (0x4e) */ +unsigned char gap1[22]; /* for longword-alignedness (0x4e) */ }; /* crc routines are borrowed from the messydos-handler */ @@ -702,7 +702,7 @@ return dos_crc(data, 0xe2, 0x95 ,511); /* precomputed magic */ ; How CRCs "really" work: ; ; First, you should regard a bitstring as a series of coefficients of -; polymomials. We calculate with these polynomials in modulo-2 +; polynomials. We calculate with these polynomials in modulo-2 ; arithmetic, in which both add and subtract are done the same as ; exclusive-or. Now, we modify our data (a very long polynomial) in ; such a way that it becomes divisible by the CCITT-standard 16-bit @@ -1637,7 +1637,7 @@ static int floppy_open(struct inode *inode, struct file *filp) unit[drive].blocks=unit[drive].type->heads*unit[drive].type->tracks* unit[drive].sects; -printk("fd%d: accesing %s-disk with %s-layout\n",drive,unit[drive].type->name, +printk("fd%d: accessing %s-disk with %s-layout\n",drive,unit[drive].type->name, data_types[system].name); return 0; diff --git a/drivers/block/ataflop.c b/drivers/block/ataflop.c index b52816f44023..20de5095167d 100644 --- a/drivers/block/ataflop.c +++ b/drivers/block/ataflop.c @@ -38,7 +38,7 @@ * - for medusa, the step rate is always 3ms * - on medusa, use only cache_push() * Roman: - * - Make disk format numbering independant from minors + * - Make disk format numbering independent from minors * - Let user set max. supported drive type (speeds up format * detection, saves buffer space) * @@ -244,7 +244,7 @@ static struct atari_floppy_struct { /* Buffering variables: * First, there is a DMA buffer in ST-RAM that is used for floppy DMA * operations. Second, a track buffer is used to cache a whole track - * of the disk to save read operations. These are two seperate buffers + * of the disk to save read operations. These are two separate buffers * because that allows write operations without clearing the track buffer. */ @@ -299,7 +299,7 @@ static unsigned int changed_floppies = 0xff, fake_change = 0; #define FD_MOTOR_OFF_MAXTRY (10*20) #define FLOPPY_TIMEOUT (6*HZ) -#define RECALIBRATE_ERRORS 4 /* Atfer this many errors the drive +#define RECALIBRATE_ERRORS 4 /* After this many errors the drive * will be recalibrated. */ #define MAX_ERRORS 8 /* After this many errors the driver * will give up. */ @@ -338,7 +338,7 @@ static unsigned int changed_floppies = 0xff, fake_change = 0; */ static int Probing = 0; -/* This flag is set when a dummy seek is necesary to make the WP +/* This flag is set when a dummy seek is necessary to make the WP * status bit accessible. */ static int NeedSeek = 0; @@ -550,7 +550,7 @@ static void check_change( void ) /* Handling of the Head Settling Flag: This flag should be set after each - * seek operation, because we dont't use seeks with verify. + * seek operation, because we don't use seeks with verify. */ static __inline__ void set_head_settle_flag( void ) @@ -880,7 +880,7 @@ static void fd_rwsec( void ) copy_buffer( ReqData, DMABuffer ); paddr = PhysDMABuffer; } - dma_cache_maintainance( paddr, 512, 1 ); + dma_cache_maintenance( paddr, 512, 1 ); rwflag = 0x100; } else { @@ -949,7 +949,7 @@ static void fd_rwsec( void ) if (read_track) { /* If reading a whole track, wait about one disk rotation and * then check if all sectors are read. The FDC will even - * search for the first non-existant sector and need 1 sec to + * search for the first non-existent sector and need 1 sec to * recognise that it isn't present :-( */ readtrack_timer.expires = @@ -1061,7 +1061,7 @@ static void fd_rwsec_done( int status ) } if ((status & FDCSTAT_RECNF) && /* RECNF is no error after a multiple read when the FDC - searched for a non-existant sector! */ + searched for a non-existent sector! */ !(read_track && FDC_READ(FDCREG_SECTOR) > SUDT->spt)) { if (Probing) { if (SUDT > disk_type) { @@ -1115,11 +1115,11 @@ static void fd_rwsec_done( int status ) if (!read_track) { void *addr; addr = ATARIHW_PRESENT( EXTD_DMA ) ? ReqData : DMABuffer; - dma_cache_maintainance( VTOP(addr), 512, 0 ); + dma_cache_maintenance( VTOP(addr), 512, 0 ); if (!ATARIHW_PRESENT( EXTD_DMA )) copy_buffer (addr, ReqData); } else { - dma_cache_maintainance( PhysTrackBuffer, MAX_SECTORS * 512, 0 ); + dma_cache_maintenance( PhysTrackBuffer, MAX_SECTORS * 512, 0 ); BufferDrive = SelectedDrive; BufferSide = ReqSide; BufferTrack = ReqTrack; @@ -1155,7 +1155,7 @@ static void fd_writetrack( void ) DPRINT(("fd_writetrack() Tr=%d Si=%d\n", ReqTrack, ReqSide )); paddr = PhysTrackBuffer; - dma_cache_maintainance( paddr, BUFFER_SIZE, 1 ); + dma_cache_maintenance( paddr, BUFFER_SIZE, 1 ); fd_select_side( ReqSide ); @@ -1233,11 +1233,11 @@ static void fd_writetrack_done( int status ) static void fd_times_out( unsigned long dummy ) { atari_disable_irq( IRQ_MFP_FDC ); - if (!FloppyIRQHandler) goto end; /* int occured after timer was fired, but + if (!FloppyIRQHandler) goto end; /* int occurred after timer was fired, but * before we came here... */ SET_IRQ_HANDLER( NULL ); - /* If the timeout occured while the readtrack_check timer was + /* If the timeout occurred while the readtrack_check timer was * active, we need to cancel it, else bad things will happen */ if (UseTrackbuffer) del_timer( &readtrack_timer ); @@ -1271,7 +1271,7 @@ static void finish_fdc( void ) MotorOn = 1; START_TIMEOUT(); /* we must wait for the IRQ here, because the ST-DMA - is released immediatly afterwards and the interrupt + is released immediately afterwards and the interrupt may be delivered to the wrong driver. */ } } @@ -1333,7 +1333,7 @@ static void floppy_off( unsigned int nr) {} * looking at the serial number in block 0. This isn't possible for * Linux, since the floppy driver can't make assumptions about the * filesystem used on the disk and thus the contents of block 0. I've - * choosen the method to always say "The disk was changed" if it is + * chosen the method to always say "The disk was changed" if it is * unsure whether it was. This implies that every open or mount * invalidates the disk buffers if you work with write protected * disks. But at least this is better than working with incorrect data diff --git a/drivers/block/floppy.c b/drivers/block/floppy.c index 1982953e9ec3..d46db8ff0050 100644 --- a/drivers/block/floppy.c +++ b/drivers/block/floppy.c @@ -294,7 +294,7 @@ static inline int DRIVE(kdev_t x) { /* * globals used by 'result()' */ -#define MAX_REPLIES 17 +#define MAX_REPLIES 16 static unsigned char reply_buffer[MAX_REPLIES]; static int inr; /* size of reply buffer, when called from interrupt */ #define ST0 (reply_buffer[0]) diff --git a/drivers/block/genhd.c b/drivers/block/genhd.c index 8d09a68dfa1e..f31f9a70ed70 100644 --- a/drivers/block/genhd.c +++ b/drivers/block/genhd.c @@ -208,6 +208,43 @@ done: brelse(bh); } +#ifdef CONFIG_BSD_DISKLABEL +/* + * Create devices for BSD partitions listed in a disklabel, under a + * dos-like partition. See extended_partition() for more information. + */ +static void bsd_disklabel_partition(struct gendisk *hd, int dev) +{ + struct buffer_head *bh; + struct bsd_disklabel *l; + struct bsd_partition *p; + int mask = (1 << hd->minor_shift) - 1; + + if (!(bh = bread(dev,0,1024))) + return; + bh->b_state = 0; + l = (struct bsd_disklabel *) (bh->b_data+512); + if (l->d_magic != BSD_DISKMAGIC) { + brelse(bh); + return; + } + + p = &l->d_partitions[0]; + while (p - &l->d_partitions[0] <= BSD_MAXPARTITIONS) { + if ((current_minor & mask) >= (4 + hd->max_p)) + break; + + if (p->p_fstype != BSD_FS_UNUSED) { + add_partition(hd, current_minor, p->p_offset, p->p_size); + current_minor++; + } + p++; + } + brelse(bh); + +} +#endif + static int msdos_partition(struct gendisk *hd, kdev_t dev, unsigned long first_sector) { int i, minor = current_minor; @@ -329,6 +366,13 @@ check_table: if (hd->part[minor].nr_sects > 2) hd->part[minor].nr_sects = 2; } +#ifdef CONFIG_BSD_DISKLABEL + if (p->sys_ind == BSD_PARTITION) { + printk(" <"); + bsd_disklabel_partition(hd, MKDEV(hd->major, minor)); + printk(" >"); + } +#endif } /* * Check for old-style Disk Manager partition table @@ -445,15 +489,27 @@ static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long fir unsigned short nsect; /* Sectors per track */ unsigned char spare3[4]; /* Even more magic... */ struct sun_partition { - unsigned long start_cylinder; - unsigned long num_sectors; + __u32 start_cylinder; + __u32 num_sectors; } partitions[8]; unsigned short magic; /* Magic number */ unsigned short csum; /* Label xor'd checksum */ } * label; struct sun_partition *p; + int other_endian; unsigned long spc; -#define SUN_LABEL_MAGIC 0xDABE +#define SUN_LABEL_MAGIC 0xDABE +#define SUN_LABEL_MAGIC_SWAPPED 0xBEDA +/* No need to optimize these macros since they are called only when reading + * the partition table. This occurs only at each disk change. */ +#define SWAP16(x) (other_endian ? (((__u16)(x) & 0xFF) << 8) \ + | (((__u16)(x) & 0xFF00) >> 8) \ + : (__u16)(x)) +#define SWAP32(x) (other_endian ? (((__u32)(x) & 0xFF) << 24) \ + | (((__u32)(x) & 0xFF00) << 8) \ + | (((__u32)(x) & 0xFF0000) >> 8) \ + | (((__u32)(x) & 0xFF000000) >> 24) \ + : (__u32)(x)) if(!(bh = bread(dev, 0, 1024))) { printk("Dev %d: unable to read partition table\n", dev); @@ -461,11 +517,12 @@ static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long fir } label = (struct sun_disklabel *) bh->b_data; p = label->partitions; - if(label->magic != SUN_LABEL_MAGIC) { - printk("Dev %d Sun disklabel: bad magic %08x\n", dev, label->magic); + if (label->magic != SUN_LABEL_MAGIC && label->magic != SUN_LABEL_MAGIC_SWAPPED) { + printk("Dev %d Sun disklabel: bad magic %04x\n", dev, label->magic); brelse(bh); return 0; } + other_endian = (label->magic == SUN_LABEL_MAGIC_SWAPPED); /* Look at the checksum */ ush = ((unsigned short *) (label+1)) - 1; for(csum = 0; ush >= ((unsigned short *) label);) @@ -476,20 +533,22 @@ static int sun_partition(struct gendisk *hd, unsigned int dev, unsigned long fir return 0; } /* All Sun disks have 8 partition entries */ - spc = (label->ntrks * label->nsect); + spc = SWAP16(label->ntrks) * SWAP16(label->nsect); for(i=0; i < 8; i++, p++) { unsigned long st_sector; /* We register all partitions, even if zero size, so that * the minor numbers end up ok as per SunOS interpretation. */ - st_sector = first_sector + (p->start_cylinder * spc); - add_partition(hd, current_minor, st_sector, p->num_sectors); + st_sector = first_sector + SWAP32(p->start_cylinder) * spc; + add_partition(hd, current_minor, st_sector, SWAP32(p->num_sectors)); current_minor++; } printk("\n"); brelse(bh); return 1; +#undef SWAP16 +#undef SWAP32 } #endif /* CONFIG_SUN_PARTITION */ diff --git a/drivers/block/rd.c b/drivers/block/rd.c index b63b1562339c..0ec6e0d960b8 100644 --- a/drivers/block/rd.c +++ b/drivers/block/rd.c @@ -32,6 +32,9 @@ * Default ramdisk size changed to 2.88MB * * Added initrd: Werner Almesberger & Hans Lermen, Feb '96 + * + * 4/25/96 : Made ramdisk size a parameter (default is now 4MB) + * - Chad Page */ #include @@ -60,9 +63,8 @@ extern void wait_for_keypress(void); #define MAJOR_NR RAMDISK_MAJOR #include -/* These *should* be defined as parameters */ -#define NUM_RAMDISKS 8 -#define RD_DEFAULTSIZE 2880 /* 2.88 MB */ +/* The ramdisk size is now a parameter */ +#define NUM_RAMDISKS 16 /* This cannot be overridden (yet) */ #ifndef MODULE /* We don't have to load ramdisks or gunzip them in a module... */ @@ -92,6 +94,7 @@ static int rd_blocksizes[NUM_RAMDISKS]; int rd_doload = 0; /* 1 = load ramdisk, 0 = don't load */ int rd_prompt = 1; /* 1 = prompt for ramdisk, 0 = don't prompt */ int rd_image_start = 0; /* starting block # of image */ +int rd_size = 4096; /* Size of the ramdisks */ #ifdef CONFIG_BLK_DEV_INITRD unsigned long initrd_start,initrd_end; int mount_initrd = 1; /* zero if initrd should not be mounted */ @@ -272,12 +275,15 @@ int rd_init(void) blk_dev[MAJOR_NR].request_fn = &rd_request; for (i = 0; i < NUM_RAMDISKS; i++) { - rd_length[i] = (RD_DEFAULTSIZE * 1024); + rd_length[i] = (rd_size * 1024); rd_blocksizes[i] = 1024; } blksize_size[MAJOR_NR] = rd_blocksizes; + printk("Ramdisk driver initialized : %d ramdisks of %dK size\n", + NUM_RAMDISKS, rd_size); + return 0; } diff --git a/drivers/char/Makefile b/drivers/char/Makefile index 86359ae63369..91c2a7049e06 100644 --- a/drivers/char/Makefile +++ b/drivers/char/Makefile @@ -20,18 +20,24 @@ FONTMAPFILE = cp437.uni L_TARGET := char.a M_OBJS := -L_OBJS := tty_io.o n_tty.o console.o keyboard.o \ +L_OBJS := tty_io.o n_tty.o console.o \ tty_ioctl.o pty.o vt.o mem.o vc_screen.o random.o \ - defkeymap.o consolemap.o selection.o - + consolemap.o selection.o + ifeq ($(CONFIG_SERIAL),y) -LX_OBJS += serial.o + ifndef CONFIG_SUN_SERIAL + LX_OBJS += serial.o + endif else ifeq ($(CONFIG_SERIAL),m) MX_OBJS += serial.o endif endif +ifndef CONFIG_SUN_KEYBOARD +L_OBJS += keyboard.o defkeymap.o +endif + ifeq ($(CONFIG_DIGI),y) L_OBJS += pcxx.o endif @@ -127,6 +133,10 @@ M = y # This is not modularized, so if configured then "misc.c" will be resident endif +ifdef CONFIG_SUN_MOUSE +M = y +endif + ifeq ($(CONFIG_WDT),y) M = y L_OBJS += wdt.o @@ -167,7 +177,7 @@ else MX_OBJS += misc.o endif endif - + ifeq ($(CONFIG_SCC),y) L_OBJS += scc.o else @@ -179,7 +189,9 @@ endif ifdef CONFIG_TGA_CONSOLE L_OBJS += tga.o else -L_OBJS += vga.o vesa_blank.o + ifndef CONFIG_SUN_CONSOLE + L_OBJS += vga.o vesa_blank.o + endif endif include $(TOPDIR)/Rules.make diff --git a/drivers/char/amigamouse.c b/drivers/char/amigamouse.c index f8261ee3ec84..60b968ff606d 100644 --- a/drivers/char/amigamouse.c +++ b/drivers/char/amigamouse.c @@ -25,7 +25,7 @@ * renamed mouse_fops => bus_mouse_fops, made bus_mouse_fops public. * renamed this file mouse.c => busmouse.c * - * Modfied for use in the 1.3 kernels by Jes Sorensen. + * Modified for use in the 1.3 kernels by Jes Sorensen. */ #include diff --git a/drivers/char/lp_intern.c b/drivers/char/lp_intern.c index f6d00f3522ea..efd4393bd9fb 100644 --- a/drivers/char/lp_intern.c +++ b/drivers/char/lp_intern.c @@ -1,6 +1,6 @@ /* - * split into mid and low-level for better support of diffent hardware + * split into mid and low-level for better support of different hardware * by Joerg Dorchain (dorchain@mpi-sb.mpg.de) * * Amiga printer device by Michael Rausch (linux@uni-koblenz.de); diff --git a/drivers/char/lp_m68k.c b/drivers/char/lp_m68k.c index e58448585bd0..42eeed3a571b 100644 --- a/drivers/char/lp_m68k.c +++ b/drivers/char/lp_m68k.c @@ -29,7 +29,7 @@ * with a certain priority is executed, all requests with lower or same * priority get locked out. executing the sti()-macro allows ANY interrupt * to be served. this really causes BIG trouble! - * to protect an interrupt driven routine against beeing interrupted + * to protect an interrupt driven routine against being interrupted * (if absolutely needed!) one should use save_flags();cli()/restore_flags()! * */ @@ -231,7 +231,7 @@ static int lp_write_interrupt(struct inode *inode, struct file *file, } if (lp_error) { - /* an error has occured, maybe in lp_interrupt(). + /* an error has occurred, maybe in lp_interrupt(). figure out the type of error, exit on request or if nothing has been printed at all. */ diff --git a/drivers/char/mem.c b/drivers/char/mem.c index 30df1b2396c0..ffec3f924571 100644 --- a/drivers/char/mem.c +++ b/drivers/char/mem.c @@ -53,7 +53,7 @@ static int read_mem(struct inode * inode, struct file * file, char * buf, int co if (count > high_memory - p) count = high_memory - p; read = 0; -#if defined(__i386__) /* we don't have page 0 mapped on x86.. */ +#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */ while (p < PAGE_OFFSET + PAGE_SIZE && count > 0) { put_user(0,buf); buf++; @@ -81,7 +81,7 @@ static int write_mem(struct inode * inode, struct file * file, const char * buf, if (count > high_memory - p) count = high_memory - p; written = 0; -#if defined(__i386__) /* we don't have page 0 mapped on x86.. */ +#if defined(__i386__) || defined(__sparc__) /* we don't have page 0 mapped on x86/sparc.. */ while (PAGE_OFFSET + p < PAGE_SIZE && count > 0) { /* Hmm. Do something? */ buf++; @@ -390,7 +390,7 @@ int chr_dev_init(void) #if defined (CONFIG_BUSMOUSE) || defined(CONFIG_UMISC) || \ defined (CONFIG_PSMOUSE) || defined (CONFIG_MS_BUSMOUSE) || \ defined (CONFIG_ATIXL_BUSMOUSE) || defined(CONFIG_SOFT_WATCHDOG) || \ - defined (CONFIG_APM) || defined (CONFIG_RTC) + defined (CONFIG_APM) || defined (CONFIG_RTC) || defined (CONFIG_SUN_MOUSE) misc_init(); #endif #ifdef CONFIG_SOUND diff --git a/drivers/char/misc.c b/drivers/char/misc.c index 738845ec874e..46577b62b998 100644 --- a/drivers/char/misc.c +++ b/drivers/char/misc.c @@ -65,6 +65,7 @@ extern int bus_mouse_init(void); extern int psaux_init(void); extern int ms_bus_mouse_init(void); extern int atixl_busmouse_init(void); +extern int sun_mouse_init(void); extern void watchdog_init(void); extern int rtc_init(void); @@ -205,6 +206,15 @@ int misc_init(void) #ifdef CONFIG_ATIXL_BUSMOUSE atixl_busmouse_init(); #endif +#ifdef CONFIG_AMIGAMOUSE + amiga_mouse_init(); +#endif +#ifdef CONFIG_ATARIMOUSE + atari_mouse_init(); +#endif +#ifdef CONFIG_SUN_MOUSE + sun_mouse_init(); +#endif #ifdef CONFIG_SOFT_WATCHDOG watchdog_init(); #endif diff --git a/drivers/char/pty.c b/drivers/char/pty.c index c262b85ab4fe..2066fa83ae3c 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -216,8 +216,9 @@ int pty_open(struct tty_struct *tty, struct file * filp) */ if (tty->driver.subtype == PTY_TYPE_MASTER) return 0; - add_wait_queue(&pty->open_wait, &wait); retval = 0; +#if PTY_SLAVE_WAITS_ON_OPEN + add_wait_queue(&pty->open_wait, &wait); while (1) { if (current->signal & ~current->blocked) { retval = -ERESTARTSYS; @@ -226,6 +227,7 @@ int pty_open(struct tty_struct *tty, struct file * filp) /* * Block until the master is open... */ + current->state = TASK_INTERRUPTIBLE; if (tty->link->count && !test_bit(TTY_OTHER_CLOSED, &tty->flags)) break; @@ -233,6 +235,10 @@ int pty_open(struct tty_struct *tty, struct file * filp) } current->state = TASK_RUNNING; remove_wait_queue(&pty->open_wait, &wait); +#else + if (!tty->link->count || test_bit(TTY_OTHER_CLOSED, &tty->flags)) + retval = -EPERM; +#endif return retval; } diff --git a/drivers/char/riscom8.c b/drivers/char/riscom8.c index 51b5a72a33f4..7475b339ac90 100644 --- a/drivers/char/riscom8.c +++ b/drivers/char/riscom8.c @@ -7,7 +7,7 @@ * Linus Torvalds, Theodore T'so and others. The RISCom/8 card * programming info was obtained from various drivers for other OSes * (FreeBSD, ISC, etc), but no source code from those drivers were - * directly included in this drvier. + * directly included in this driver. * * * This program is free software; you can redistribute it and/or modify @@ -173,7 +173,7 @@ extern inline void rc_out(struct riscom_board const * bp, unsigned short reg, outb(val, bp->base + RC_TO_ISA(reg)); } -/* Wait for Chanel Command Register ready */ +/* Wait for Channel Command Register ready */ extern inline void rc_wait_CCR(struct riscom_board const * bp) { unsigned long delay; @@ -196,7 +196,7 @@ extern inline int rc_check_io_range(struct riscom_board * const bp) for (i = 0; i < RC_NIOPORT; i++) if (check_region(RC_TO_ISA(rc_ioport[i]) + bp->base, 1)) { - printk("rc%d: Skipping probe at 0x%03x. I/O adress in use.\n", + printk("rc%d: Skipping probe at 0x%03x. I/O address in use.\n", board_No(bp), bp->base); return 1; } @@ -319,7 +319,7 @@ static int rc_probe(struct riscom_board *bp) /* * - * Inerrupt processing routines. + * Interrupt processing routines. * */ @@ -328,7 +328,7 @@ extern inline void rc_mark_event(struct riscom_port * port, int event) /* * I'm not quite happy with current scheme all serial * drivers use their own BH routine. - * It seem's this easily can be done with one BH routine + * It seems this easily can be done with one BH routine * serving for all serial drivers. * For now I must introduce another one - RISCOM8_BH. * Still hope this will be changed in near future. @@ -673,7 +673,7 @@ extern inline void rc_shutdown_board(struct riscom_board *bp) /* * Setting up port characteristics. - * Must be called with disabled interupts + * Must be called with disabled interrupts */ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) { @@ -785,7 +785,7 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) /* Real raw mode. Ignore all */ port->mark_mask &= ~RCSR_OE; } - /* Enable Hardware FLow Control */ + /* Enable Hardware Flow Control */ if (C_CRTSCTS(tty)) { #ifdef RISCOM_BRAIN_DAMAGED_CTS port->IER |= IER_DSR | IER_CTS; @@ -831,12 +831,12 @@ static void rc_change_speed(struct riscom_board *bp, struct riscom_port *port) /* Setting up modem option registers */ rc_out(bp, CD180_MCOR1, mcor1); rc_out(bp, CD180_MCOR2, mcor2); - /* Enable CD180 trasmitter & receiver */ + /* Enable CD180 transmitter & receiver */ rc_wait_CCR(bp); rc_out(bp, CD180_CCR, CCR_TXEN | CCR_RXEN); /* Enable interrupts */ rc_out(bp, CD180_IER, port->IER); - /* And finaly set RTS on */ + /* And finally set RTS on */ rc_out(bp, CD180_MSVR, port->MSVR); } @@ -927,7 +927,7 @@ static void rc_shutdown_port(struct riscom_board *bp, struct riscom_port *port) port->flags &= ~ASYNC_INITIALIZED; if (--bp->count < 0) { - printk("rc%d: rc_shutdow_port: bad board count: %d\n", + printk("rc%d: rc_shutdown_port: bad board count: %d\n", board_No(bp), bp->count); bp->count = 0; } @@ -1812,7 +1812,7 @@ static void rc_release_drivers(void) * * You can specify IO base for up to RC_NBOARD cards, * using line "riscom8=0xiobase1,0xiobase2,.." at LILO prompt. - * Note that there wiil be no probing at default + * Note that there will be no probing at default * addresses in this case. * */ @@ -1862,7 +1862,7 @@ int iobase3 = 0; /* * You can setup up to 4 boards (current value of RC_NBOARD) - * by specifying "iobase=0xXXX iobase1=0xXXX ..." as isnmod parametr. + * by specifying "iobase=0xXXX iobase1=0xXXX ..." as insmod parameter. * */ int init_module(void) diff --git a/drivers/char/riscom8.h b/drivers/char/riscom8.h index 8bdce318f2c7..1d014a921728 100644 --- a/drivers/char/riscom8.h +++ b/drivers/char/riscom8.h @@ -7,7 +7,7 @@ * Linus Torvalds, Theodore T'so and others. The RISCom/8 card * programming info was obtained from various drivers for other OSes * (FreeBSD, ISC, etc), but no source code from those drivers were - * directly included in this drvier. + * directly included in this driver. * * * This program is free software; you can redistribute it and/or modify diff --git a/drivers/char/riscom8_reg.h b/drivers/char/riscom8_reg.h index 4c69250c3852..a32475ed0d18 100644 --- a/drivers/char/riscom8_reg.h +++ b/drivers/char/riscom8_reg.h @@ -109,7 +109,7 @@ /* Channel Address Register (R/W) */ #define CAR_CHAN 0x07 /* Channel Number Mask */ -#define CAR_A7 0x08 /* A7 Address Extention (unused) */ +#define CAR_A7 0x08 /* A7 Address Extension (unused) */ /* Receive Character Status Register (R/O) */ diff --git a/drivers/net/3c509.c b/drivers/net/3c509.c index a96ee074ad03..e8517c89da16 100644 --- a/drivers/net/3c509.c +++ b/drivers/net/3c509.c @@ -221,7 +221,6 @@ int el3_probe(struct device *dev) lrs_state = lrs_state & 0x100 ? lrs_state ^ 0xcf : lrs_state; } - current_tag = dev->name[3]-'0'; /* For the first probe, clear all board's tag registers. */ if (current_tag == 0) outb(0xd0, id_port); @@ -266,10 +265,6 @@ int el3_probe(struct device *dev) /* Free the interrupt so that some other card can use it. */ outw(0x0f00, ioaddr + WN0_IRQ); - - if( check_region(ioaddr, EL3_IO_EXTENT) ) - return -ENODEV; - found: dev->base_addr = ioaddr; dev->irq = irq; diff --git a/drivers/net/Config.in b/drivers/net/Config.in index 7947aaa82708..5c9012559558 100644 --- a/drivers/net/Config.in +++ b/drivers/net/Config.in @@ -51,12 +51,12 @@ if [ "$CONFIG_NET_ISA" = "y" ]; then tristate 'Cabletron E21xx support' CONFIG_E2100 tristate 'DEPCA support' CONFIG_DEPCA tristate 'EtherWorks 3 support' CONFIG_EWRK3 + tristate 'EtherExpress 16 support' CONFIG_EEXPRESS if [ "$CONFIG_NET_ALPHA" = "y" ]; then bool 'SEEQ8005 support' CONFIG_SEEQ8005 tristate 'AT1700 support' CONFIG_AT1700 tristate 'FMV-181/182 support' CONFIG_FMV18X tristate 'EtherExpressPro support' CONFIG_EEXPRESS_PRO - tristate 'EtherExpress support' CONFIG_EEXPRESS tristate 'NI5210 support' CONFIG_NI52 bool 'NI6510 support' CONFIG_NI65 tristate 'WaveLAN support' CONFIG_WAVELAN diff --git a/drivers/net/Makefile b/drivers/net/Makefile index e59afeb94a63..bd81722a8330 100644 --- a/drivers/net/Makefile +++ b/drivers/net/Makefile @@ -450,6 +450,22 @@ else endif endif +ifeq ($(CONFIG_ATARILANCE),y) +L_OBJS += atarilance.o +else + ifeq ($(CONFIG_ATARILANCE),m) + M_OBJS += atarilance.o + endif +endif + +ifeq ($(CONFIG_A2065),y) +L_OBJS += a2065.o +else + ifeq ($(CONFIG_A2065),m) + M_OBJS += a2065.o + endif +endif + ifeq ($(CONFIG_SDLA),y) L_OBJS += sdla.o else @@ -466,6 +482,14 @@ else endif endif +ifeq ($(CONFIG_ARIADNE),y) +L_OBJS += ariadne.o +else + ifeq ($(CONFIG_ARIADNE),m) + M_OBJS += ariadne.o + endif +endif + ifeq ($(CONFIG_DGRS),y) L_OBJS += dgrs.o else diff --git a/drivers/net/Space.c b/drivers/net/Space.c index 8ccd863fdf52..c6c146ed7aae 100644 --- a/drivers/net/Space.c +++ b/drivers/net/Space.c @@ -74,6 +74,9 @@ extern int tc59x_probe(struct device *); extern int dgrs_probe(struct device *); extern int smc_init( struct device * ); extern int sparc_lance_probe(struct device *); +extern int atarilance_probe(struct device *); +extern int a2065_probe(struct device *); +extern int ariadne_probe(struct device *); /* Detachable devices ("pocket adaptors") */ extern int atp_init(struct device *); @@ -191,6 +194,15 @@ ethif_probe(struct device *dev) #ifdef CONFIG_NI52 && ni52_probe(dev) #endif +#ifdef CONFIG_ATARILANCE /* Lance-based Atari ethernet boards */ + && atarilance_probe(dev) +#endif +#ifdef CONFIG_A2065 /* Commodore/Ameristar A2065 Ethernet Board */ + && a2065_probe(dev) +#endif +#ifdef CONFIG_ARIADNE /* Village Tronic Ariadne Ethernet Board */ + && ariadne_probe(dev) +#endif #ifdef CONFIG_SUNLANCE && sparc_lance_probe(dev) #endif diff --git a/drivers/net/a2065.c b/drivers/net/a2065.c index df974b73e1ad..85d0eb813d74 100644 --- a/drivers/net/a2065.c +++ b/drivers/net/a2065.c @@ -346,7 +346,7 @@ static void a2065_interrupt(int irq, struct pt_regs *fp, void *data) board->Lance.RAP = CSR0; /* LANCE Controller Status */ - if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has + if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been generated by the board. */ return; diff --git a/drivers/net/ariadne.c b/drivers/net/ariadne.c index 7282150bf300..e44ab8026c80 100644 --- a/drivers/net/ariadne.c +++ b/drivers/net/ariadne.c @@ -394,7 +394,7 @@ static void ariadne_interrupt(int irq, struct pt_regs *fp, void *data) board->Lance.RAP = CSR0; /* PCnet-ISA Controller Status */ - if (!(board->Lance.RDP & INTR)) /* Check if any interrrupt has been + if (!(board->Lance.RDP & INTR)) /* Check if any interrupt has been return; generated by the board. */ if (dev->interrupt) diff --git a/drivers/net/ariadne.h b/drivers/net/ariadne.h index ebd47ae2b16e..6b04e450b203 100644 --- a/drivers/net/ariadne.h +++ b/drivers/net/ariadne.h @@ -122,8 +122,8 @@ struct Am79C960 { #define CSR61 0x3d00 /* Previous Transmit Descriptor Address */ #define CSR62 0x3e00 /* Previous Transmit Status and Byte Count */ #define CSR63 0x3f00 /* Previous Transmit Status and Byte Count */ -#define CSR64 0x4000 /* Next Transmit Buffer Addres */ -#define CSR65 0x4100 /* Next Transmit Buffer Addres */ +#define CSR64 0x4000 /* Next Transmit Buffer Address */ +#define CSR65 0x4100 /* Next Transmit Buffer Address */ #define CSR66 0x4200 /* Next Transmit Status and Byte Count */ #define CSR67 0x4300 /* Next Transmit Status and Byte Count */ #define CSR68 0x4400 /* Transmit Status Temporary Storage */ diff --git a/drivers/net/atarilance.c b/drivers/net/atarilance.c index 8daeee2a7dd3..2e843537f03c 100644 --- a/drivers/net/atarilance.c +++ b/drivers/net/atarilance.c @@ -219,7 +219,7 @@ struct lance_private { struct lance_ioreg *iobase; struct lance_memory *mem; int cur_rx, cur_tx; /* The next free ring entry */ - int dirty_tx; /* Ring entries to be freeed. */ + int dirty_tx; /* Ring entries to be freed. */ /* copy function */ void *(*memcpy_f)( void *, const void *, size_t ); struct enet_statistics stats; @@ -303,7 +303,7 @@ struct lance_addr { #define CSR2 2 /* init block addr (high) */ #define CSR3 3 /* misc */ #define CSR8 8 /* address filter */ -#define CSR15 15 /* promiscous mode */ +#define CSR15 15 /* promiscuous mode */ /* CSR0 */ /* (R=readable, W=writeable, S=set on write, C=clear on write) */ diff --git a/drivers/net/de4x5.c b/drivers/net/de4x5.c index 6fe2dec65362..402b3302394b 100644 --- a/drivers/net/de4x5.c +++ b/drivers/net/de4x5.c @@ -121,6 +121,11 @@ patched this driver to detect it because the SROM format used complies to a previous DEC-STD format. + I have removed the buffer copies needed for receive on Intels. I cannot + remove them for Alphas since the Tulip hardware only does longword + aligned DMA transfers and the Alphas get alignment traps with non + longword aligned data copies (which makes them really slow). No comment. + TO DO: ------ @@ -182,11 +187,19 @@ Duh, put the SA_SHIRQ flag into request_interrupt(). Fix SMC ethernet address in enet_det[]. Print chip name instead of "UNKNOWN" during boot. + 0.42 26-Apr-96 Fix MII write TA bit error. + Fix bug in dc21040 and dc21041 autosense code. + Remove buffer copies on receive for Intels. + Change sk_buff handling during media disconnects to + eliminate DUP packets. + Add dynamic TX thresholding. + Change all chips to use perfect multicast filtering. + Fix alloc_device() bug ========================================================================= */ -static const char *version = "de4x5.c:v0.41 96/3/21 davies@wanton.lkg.dec.com\n"; +static const char *version = "de4x5.c:v0.42 96/4/26 davies@wanton.lkg.dec.com\n"; #include @@ -298,6 +311,7 @@ static s32 de4x5_full_duplex = 0; ** Ethernet Info */ #define PKT_BUF_SZ 1536 /* Buffer size for each Tx/Rx buffer */ +#define IEEE802_3_SZ 1518 /* Packet + CRC */ #define MAX_PKT_SZ 1514 /* Maximum ethernet packet length */ #define MAX_DAT_SZ 1500 /* Maximum ethernet data length */ #define MIN_DAT_SZ 1 /* Minimum ethernet data length */ @@ -418,6 +432,7 @@ struct de4x5_srom { char info[100]; short chksum; }; +#define SUB_VENDOR_ID 0x500a /* ** DE4X5 Descriptors. Make sure that all the RX buffers are contiguous @@ -451,7 +466,8 @@ struct de4x5_private { char adapter_name[80]; /* Adapter name */ struct de4x5_desc rx_ring[NUM_RX_DESC]; /* RX descriptor ring */ struct de4x5_desc tx_ring[NUM_TX_DESC]; /* TX descriptor ring */ - struct sk_buff *skb[NUM_TX_DESC]; /* TX skb for freeing when sent */ + struct sk_buff *tx_skb[NUM_TX_DESC]; /* TX skb for freeing when sent */ + struct sk_buff *rx_skb[NUM_RX_DESC]; /* RX skb's */ int rx_new, rx_old; /* RX descriptor ring pointers */ int tx_new, tx_old; /* TX descriptor ring pointers */ char setup_frame[SETUP_FRAME_LEN]; /* Holds MCA and PA info. */ @@ -531,6 +547,8 @@ static struct bus_type { lp->tx_old+lp->txRingSize-lp->tx_new-1:\ lp->tx_old -lp->tx_new-1) +#define TX_PKT_PENDING (lp->tx_old != lp->tx_new) + /* ** Public Functions */ @@ -551,6 +569,7 @@ static int de4x5_sw_reset(struct device *dev); static int de4x5_rx(struct device *dev); static int de4x5_tx(struct device *dev); static int de4x5_ast(struct device *dev); +static int de4x5_txur(struct device *dev); static int autoconf_media(struct device *dev); static void create_packet(struct device *dev, char *frame, int len); @@ -563,13 +582,16 @@ static int dc21140m_autoconf(struct device *dev); static int de4x5_suspect_state(struct device *dev, int timeout, int prev_state, int (*fn)(struct device *, int), int (*asfn)(struct device *)); static int dc21040_state(struct device *dev, int csr13, int csr14, int csr15, int timeout, int next_state, int suspect_state, int (*fn)(struct device *, int)); static int test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 csr15, s32 msec); -/*static int test_sym_link(struct device *dev, u32 msec);*/ +static int test_sym_link(struct device *dev, int msec); static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec); static int is_spd_100(struct device *dev); static int is_100_up(struct device *dev); static int is_10_up(struct device *dev); static int is_anc_capable(struct device *dev); static int ping_media(struct device *dev, int msec); +static struct sk_buff *de4x5_alloc_rx_buff(struct device *dev, int index, int len); +static void de4x5_free_rx_buffs(struct device *dev); +static void de4x5_free_tx_buffs(struct device *dev); static void de4x5_save_skbs(struct device *dev); static void de4x5_restore_skbs(struct device *dev); static void de4x5_cache_state(struct device *dev, int flag); @@ -621,6 +643,7 @@ static void de4x5_dbg_open(struct device *dev); static void de4x5_dbg_mii(struct device *dev, int k); static void de4x5_dbg_media(struct device *dev); static void de4x5_dbg_srom(struct de4x5_srom *p); +static void de4x5_dbg_rx(struct sk_buff *skb, int len); static int de4x5_strncmp(char *a, char *b, int n); #ifdef MODULE @@ -655,7 +678,8 @@ static int num_de4x5s = 0, num_eth = 0; ** more info. Until I fix (un)register_netdevice() we won't be able to use it ** though. */ -int de4x5_probe(struct device *dev) +int +de4x5_probe(struct device *dev) { int tmp = num_de4x5s, status = -ENODEV; u_long iobase = dev->base_addr; @@ -793,62 +817,66 @@ de4x5_hw_init(struct device *dev, u_long iobase) sprintf(lp->adapter_name,"%s (%s)", name, dev->name); /* - ** Allocate contiguous receive buffers, long word aligned. + ** Set up the RX descriptor ring (Intels) + ** Allocate contiguous receive buffers, long word aligned (Alphas) */ +#ifndef __alpha__ + for (i=0; irx_ring[i].status = 0; + lp->rx_ring[i].des1 = RX_BUFF_SZ; + lp->rx_ring[i].buf = 0; + lp->rx_ring[i].next = 0; + lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + } + +#else if ((tmp = (void *)kmalloc(RX_BUFF_SZ * NUM_RX_DESC + ALIGN, - GFP_KERNEL)) != NULL) { - lp->cache.buf = tmp; - tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN); - for (i=0; irx_ring[i].status = 0; - lp->rx_ring[i].des1 = RX_BUFF_SZ; - lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ); - lp->rx_ring[i].next = (u32)NULL; - } - barrier(); + GFP_KERNEL)) == NULL) { + kfree(lp->cache.priv); + return -ENOMEM; + } + + lp->cache.buf = tmp; + tmp = (char *)(((u_long) tmp + ALIGN) & ~ALIGN); + for (i=0; irx_ring[i].status = 0; + lp->rx_ring[i].des1 = RX_BUFF_SZ; + lp->rx_ring[i].buf = virt_to_bus(tmp + i * RX_BUFF_SZ); + lp->rx_ring[i].next = 0; + lp->rx_skb[i] = (struct sk_buff *) 1; /* Dummy entry */ + } +#endif + + barrier(); - request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE), - lp->adapter_name); + request_region(iobase, (lp->bus == PCI ? DE4X5_PCI_TOTAL_SIZE : + DE4X5_EISA_TOTAL_SIZE), + lp->adapter_name); - lp->rxRingSize = NUM_RX_DESC; - lp->txRingSize = NUM_TX_DESC; + lp->rxRingSize = NUM_RX_DESC; + lp->txRingSize = NUM_TX_DESC; - /* Write the end of list marker to the descriptor lists */ - lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER; - lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER; + /* Write the end of list marker to the descriptor lists */ + lp->rx_ring[lp->rxRingSize - 1].des1 |= RD_RER; + lp->tx_ring[lp->txRingSize - 1].des1 |= TD_TER; - /* Tell the adapter where the TX/RX rings are located. */ - outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); - outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); + /* Tell the adapter where the TX/RX rings are located. */ + outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); + outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); - /* Initialise the IRQ mask and Enable/Disable */ - lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM ; - lp->irq_en = IMR_NIM | IMR_AIM; + /* Initialise the IRQ mask and Enable/Disable */ + lp->irq_mask = IMR_RIM | IMR_TIM | IMR_TUM | IMR_UNM; + lp->irq_en = IMR_NIM | IMR_AIM; - /* Create a loopback packet frame for later media probing */ - create_packet(dev, lp->frame, sizeof(lp->frame)); + /* Create a loopback packet frame for later media probing */ + create_packet(dev, lp->frame, sizeof(lp->frame)); - /* Initialise the adapter state */ - lp->state = CLOSED; + /* Initialise the adapter state */ + lp->state = CLOSED; + + printk(" and requires IRQ%d (provided by %s).\n", dev->irq, + ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); - printk(" and requires IRQ%d (provided by %s).\n", dev->irq, - ((lp->bus == PCI) ? "PCI BIOS" : "EISA CNFG")); - } else { - printk("%s: Kernel could not allocate RX buffer memory.\n", dev->name); - } - if (status) { - release_region(iobase, (lp->bus == PCI ? - DE4X5_PCI_TOTAL_SIZE : - DE4X5_EISA_TOTAL_SIZE)); - if (lp->rx_ring[0].buf) { - kfree(bus_to_virt(lp->rx_ring[0].buf)); - } - kfree(dev->priv); - dev->priv = NULL; - - return -ENXIO; - } } if (de4x5_debug > 0) { @@ -883,9 +911,17 @@ de4x5_open(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - int status = 0; + int i, status = 0; s32 omr; + /* Allocate the RX buffers */ + for (i=0; irxRingSize; i++) { + if (de4x5_alloc_rx_buff(dev, i, 0) == NULL) { + de4x5_free_rx_buffs(dev); + return -EAGAIN; + } + } + /* ** Wake up the adapter */ @@ -893,14 +929,13 @@ de4x5_open(struct device *dev) outl(0, PCI_CFDA); de4x5_ms_delay(10); } - - lp->state = OPEN; - + /* ** Re-initialize the DE4X5... */ status = de4x5_init(dev); + lp->state = OPEN; de4x5_dbg_open(dev); if (request_irq(dev->irq, (void *)de4x5_interrupt, SA_SHIRQ, @@ -937,7 +972,7 @@ de4x5_open(struct device *dev) /* ** Initialize the DE4X5 operating conditions. NB: a chip problem with the ** DC21140 requires using perfect filtering mode for that chip. Since I can't -** see why I'd want > 14 multicast addresses, I may change all chips to use +** see why I'd want > 14 multicast addresses, I have changed all chips to use ** the perfect filtering mode. Keep the DMA burst length at 8: there seems ** to be data corruption problems if it is larger (UDP errors seen from a ** ttcp source). @@ -956,7 +991,8 @@ de4x5_init(struct device *dev) return 0; } -static int de4x5_sw_reset(struct device *dev) +static int +de4x5_sw_reset(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -978,14 +1014,11 @@ static int de4x5_sw_reset(struct device *dev) bmr = (lp->chipset==DC21140 ? PBL_8 : PBL_4) | DESC_SKIP_LEN | CACHE_ALIGN; outl(bmr, DE4X5_BMR); - omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn of promiscuous mode */ - if (lp->chipset != DC21140) { - omr |= TR_96; - lp->setup_f = HASH_PERF; - } else { - omr |= OMR_SDP | OMR_SB | (!lp->phy[lp->active].id ? OMR_SF : 0); - lp->setup_f = PERFECT; + omr = inl(DE4X5_OMR) & ~OMR_PR; /* Turn off promiscuous mode */ + if (lp->chipset == DC21140) { + omr |= (OMR_SDP | OMR_SB); } + lp->setup_f = PERFECT; outl(virt_to_bus(lp->rx_ring), DE4X5_RRBA); outl(virt_to_bus(lp->tx_ring), DE4X5_TRBA); @@ -1005,11 +1038,7 @@ static int de4x5_sw_reset(struct device *dev) /* Build the setup frame depending on filtering mode */ SetMulticastFilter(dev); - if (lp->chipset != DC21140) { - load_packet(dev, lp->setup_frame, HASH_F|TD_SET|SETUP_FRAME_LEN, NULL); - } else { - load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL); - } + load_packet(dev, lp->setup_frame, PERFECT_F|TD_SET|SETUP_FRAME_LEN, NULL); outl(omr|OMR_ST, DE4X5_OMR); /* Poll for setup frame completion (adapter interrupts are disabled now) */ @@ -1041,15 +1070,14 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; int status = 0; - + if (skb == NULL) { dev_tint(dev); return 0; } if (lp->tx_enable == NO) { /* Cannot send for now */ - de4x5_put_cache(dev, skb); /* Queue the buffer locally */ - return 0; + return -1; } /* @@ -1063,14 +1091,14 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) sti(); /* Transmit descriptor ring full or stale skb */ - if (dev->tbusy || lp->skb[lp->tx_new]) { + if (dev->tbusy || lp->tx_skb[lp->tx_new]) { if (dev->interrupt) { de4x5_putb_cache(dev, skb); /* Requeue the buffer */ } else { de4x5_put_cache(dev, skb); } if (de4x5_debug > 1) { - printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n lostMedia:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->skb[lp->tx_new] ? "YES" : "NO")); + printk("%s: transmit busy, lost media or stale skb found:\n STS:%08x\n tbusy:%ld\n lostMedia:%d\n IMR:%08x\n OMR:%08x\n Stale skb: %s\n",dev->name, inl(DE4X5_STS), dev->tbusy, lp->lostMedia, inl(DE4X5_IMR), inl(DE4X5_OMR), (lp->tx_skb[lp->tx_new] ? "YES" : "NO")); } } else if (skb->len > 0) { /* If we already have stuff queued locally, use that first */ @@ -1079,7 +1107,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) skb = de4x5_get_cache(dev); } - while (skb && !dev->tbusy && !lp->skb[lp->tx_new]) { + while (skb && !dev->tbusy && !lp->tx_skb[lp->tx_new]) { set_bit(0, (void*)&dev->tbusy); cli(); if (TX_BUFFS_AVAIL) { /* Fill in a Tx ring entry */ @@ -1097,7 +1125,7 @@ de4x5_queue_pkt(struct sk_buff *skb, struct device *dev) } sti(); } - if (skb && (dev->tbusy || lp->skb[lp->tx_new])) { + if (skb && (dev->tbusy || lp->tx_skb[lp->tx_new])) { de4x5_putb_cache(dev, skb); } } @@ -1121,7 +1149,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) { struct device *dev = (struct device *)dev_id; struct de4x5_private *lp; - s32 imr, omr, sts; + s32 imr, omr, sts, limit; u_long iobase; if (dev == NULL) { @@ -1137,7 +1165,7 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) DISABLE_IRQs; /* Ensure non re-entrancy */ dev->interrupt = MASK_INTERRUPTS; - for (;;) { + for (limit=0; limit<8; limit++) { sts = inl(DE4X5_STS); /* Read IRQ status */ outl(sts, DE4X5_STS); /* Reset the board interrupts */ @@ -1154,6 +1182,10 @@ de4x5_interrupt(int irq, void *dev_id, struct pt_regs *regs) lp->irq_mask &= ~IMR_LFM; } + if (sts & STS_UNF) { /* Transmit underrun */ + de4x5_txur(dev); + } + if (sts & STS_SE) { /* Bus Error */ STOP_DE4X5; printk("%s: Fatal bus error occurred, sts=%#8x, device stopped.\n", @@ -1204,24 +1236,15 @@ de4x5_rx(struct device *dev) struct sk_buff *skb; short pkt_len = (short)(lp->rx_ring[entry].status >> 16) - 4; - if ((skb = dev_alloc_skb(pkt_len+2)) == NULL) { + if ((skb = de4x5_alloc_rx_buff(dev, entry, pkt_len)) == NULL) { printk("%s: Insufficient memory; nuking packet.\n", dev->name); lp->stats.rx_dropped++; /* Really, deferred. */ break; } + de4x5_dbg_rx(skb, pkt_len); - skb->dev = dev; - skb_reserve(skb,2); /* Align */ - if (entry < lp->rx_old) { /* Wrapped buffer */ - short len = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; - memcpy(skb_put(skb,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), len); - memcpy(skb_put(skb,pkt_len-len), bus_to_virt(lp->rx_ring[0].buf), pkt_len - len); - } else { /* Linear buffer */ - memcpy(skb_put(skb,pkt_len), bus_to_virt(lp->rx_ring[lp->rx_old].buf), pkt_len); - } - - /* Push up the protocol stack */ + /* Push up the protocol stack */ skb->protocol=eth_type_trans(skb,dev); netif_rx(skb); @@ -1284,29 +1307,32 @@ de4x5_tx(struct device *dev) status = lp->tx_ring[entry].status; if (status < 0) { /* Buffer not sent yet */ break; - } else if (status & TD_ES) { /* An error happened */ - lp->stats.tx_errors++; - if (status & TD_NC) lp->stats.tx_carrier_errors++; - if (status & TD_LC) lp->stats.tx_window_errors++; - if (status & TD_UF) lp->stats.tx_fifo_errors++; - if (status & TD_LC) lp->stats.collisions++; - if (status & TD_EC) lp->pktStats.excessive_collisions++; - if (status & TD_DE) lp->stats.tx_aborted_errors++; + } else if (status != 0x7fffffff) { /* Not setup frame */ + if (status & TD_ES) { /* An error happened */ + lp->stats.tx_errors++; + if (status & TD_NC) lp->stats.tx_carrier_errors++; + if (status & TD_LC) lp->stats.tx_window_errors++; + if (status & TD_UF) lp->stats.tx_fifo_errors++; + if (status & TD_LC) lp->stats.collisions++; + if (status & TD_EC) lp->pktStats.excessive_collisions++; + if (status & TD_DE) lp->stats.tx_aborted_errors++; - if ((status != 0x7fffffff) && /* Not setup frame */ - (status & (TD_LO | TD_NC | TD_EC | TD_LF))) { - lp->lostMedia++; - } else { - outl(POLL_DEMAND, DE4X5_TPD); /* Restart a stalled TX */ + if (status & (TD_LO | TD_NC | TD_EC | TD_LF)) { + lp->lostMedia++; + } + if (TX_PKT_PENDING) { + outl(POLL_DEMAND, DE4X5_TPD);/* Restart a stalled TX */ + } + } else { /* Packet sent */ + lp->stats.tx_packets++; + lp->lostMedia = 0; /* Remove transient problem */ + lp->linkOK++; + } + /* Free the buffer. */ + if (lp->tx_skb[entry] != NULL) { + dev_kfree_skb(lp->tx_skb[entry], FREE_WRITE); + lp->tx_skb[entry] = NULL; } - } else { /* Packet sent */ - lp->stats.tx_packets++; - lp->lostMedia = 0; /* Remove transient problem */ - } - /* Free the buffer if it's not a setup frame. */ - if (lp->skb[entry] != NULL) { - dev_kfree_skb(lp->skb[entry], FREE_WRITE); - lp->skb[entry] = NULL; } /* Update all the pointers */ @@ -1342,6 +1368,29 @@ de4x5_ast(struct device *dev) return 0; } +static int +de4x5_txur(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int iobase = dev->base_addr; + int omr; + + omr = inl(DE4X5_OMR); + if (!(omr & OMR_SF)) { + omr &= ~(OMR_ST|OMR_SR); + outl(omr, DE4X5_OMR); + while (inl(DE4X5_STS) & STS_TS); + if ((omr & OMR_TR) < OMR_TR) { + omr += 0x4000; + } else { + omr |= OMR_SF; + } + outl(omr | OMR_ST | OMR_SR, DE4X5_OMR); + } + + return 0; +} + static int de4x5_close(struct device *dev) { @@ -1362,14 +1411,15 @@ de4x5_close(struct device *dev) ** We stop the DE4X5 here... mask interrupts and stop TX & RX */ DISABLE_IRQs; - STOP_DE4X5; - /* - ** Free the associated irq - */ + /* Free the associated irq */ free_irq(dev->irq, dev); lp->state = CLOSED; + + /* Free any socket buffers */ + de4x5_free_rx_buffs(dev); + de4x5_free_tx_buffs(dev); MOD_DEC_USE_COUNT; @@ -1393,14 +1443,15 @@ de4x5_get_stats(struct device *dev) return &lp->stats; } -static void load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) +static void +load_packet(struct device *dev, char *buf, u32 flags, struct sk_buff *skb) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; lp->tx_ring[lp->tx_new].buf = virt_to_bus(buf); lp->tx_ring[lp->tx_new].des1 &= TD_TER; lp->tx_ring[lp->tx_new].des1 |= flags; - lp->skb[lp->tx_new] = skb; + lp->tx_skb[lp->tx_new] = skb; barrier(); lp->tx_ring[lp->tx_new].status = T_OWN; barrier(); @@ -1426,13 +1477,8 @@ set_multicast_list(struct device *dev) outl(omr, DE4X5_OMR); } else { SetMulticastFilter(dev); - if (lp->setup_f == HASH_PERF) { - load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | - SETUP_FRAME_LEN, NULL); - } else { - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); - } + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + SETUP_FRAME_LEN, NULL); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ @@ -1448,7 +1494,8 @@ set_multicast_list(struct device *dev) ** from a list of ethernet multicast addresses. ** Little endian crc one liner from Matt Thomas, DEC. */ -static void SetMulticastFilter(struct device *dev) +static void +SetMulticastFilter(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; struct dev_mc_list *dmi=dev->mc_list; @@ -1508,7 +1555,8 @@ static void SetMulticastFilter(struct device *dev) ** EISA bus I/O device probe. Probe from slot 1 since slot 0 is usually ** the motherboard. Upto 15 EISA devices are supported. */ -static void eisa_probe(struct device *dev, u_long ioaddr) +static void +eisa_probe(struct device *dev, u_long ioaddr) { int i, maxSlots, status; u_short vendor, device; @@ -1575,7 +1623,8 @@ static void eisa_probe(struct device *dev, u_long ioaddr) #define PCI_DEVICE (dev_num << 3) #define PCI_LAST_DEV 32 -static void pci_probe(struct device *dev, u_long ioaddr) +static void +pci_probe(struct device *dev, u_long ioaddr) { u_char irq; u_char pb, pbus, dev_num, dnum, dev_fn; @@ -1583,7 +1632,7 @@ static void pci_probe(struct device *dev, u_long ioaddr) u_int class = DE4X5_CLASS_CODE; u_int iobase; struct bus_type *lp = &bus; - + if ((!ioaddr || !loading_module) && autoprobed) return; if (!pcibios_present()) return; /* No PCI bus in this machine! */ @@ -1607,7 +1656,7 @@ static void pci_probe(struct device *dev, u_long ioaddr) pcibios_read_config_word(pb, PCI_DEVICE, PCI_VENDOR_ID, &vendor); pcibios_read_config_word(pb, PCI_DEVICE, PCI_DEVICE_ID, &device); if (!(is_DC21040 || is_DC21041 || is_DC21140)) continue; - + /* Set the device number information */ lp->device = dev_num; lp->bus_num = pb; @@ -1626,14 +1675,13 @@ static void pci_probe(struct device *dev, u_long ioaddr) /* Check if I/O accesses and Bus Mastering are enabled */ pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); if (!(status & PCI_COMMAND_IO)) continue; - if (!(status & PCI_COMMAND_MASTER)) { status |= PCI_COMMAND_MASTER; pcibios_write_config_word(pb, PCI_DEVICE, PCI_COMMAND, status); pcibios_read_config_word(pb, PCI_DEVICE, PCI_COMMAND, &status); } if (!(status & PCI_COMMAND_MASTER)) continue; - + DevicePresent(DE4X5_APROM); if (check_region(iobase, DE4X5_PCI_TOTAL_SIZE) == 0) { if ((dev = alloc_device(dev, iobase)) != NULL) { @@ -1657,7 +1705,8 @@ static void pci_probe(struct device *dev, u_long ioaddr) ** Allocate the device by pointing to the next available space in the ** device structure. Should one not be available, it is created. */ -static struct device *alloc_device(struct device *dev, u_long iobase) +static struct device * +alloc_device(struct device *dev, u_long iobase) { int addAutoProbe = 0; struct device *tmp = NULL, *ret; @@ -1700,7 +1749,7 @@ static struct device *alloc_device(struct device *dev, u_long iobase) ** and initialize it (name, I/O address, next device (NULL) and ** initialisation probe routine). */ - dev->name = (char *)(dev + sizeof(struct device)); + dev->name = (char *)(dev + 1); if (num_eth > 9999) { sprintf(dev->name,"eth????");/* New device name */ } else { @@ -1739,7 +1788,7 @@ static struct device *alloc_device(struct device *dev, u_long iobase) ** area and initialize it (name, I/O address, next device ** (NULL) and initialisation probe routine). */ - tmp->name = (char *)(tmp + sizeof(struct device)); + tmp->name = (char *)(tmp + 1); if (num_eth > 9999) { sprintf(tmp->name,"eth????"); } else { /* New device name */ @@ -1765,7 +1814,8 @@ static struct device *alloc_device(struct device *dev, u_long iobase) ** [TP] or no recent receive activity) to check whether the user has been ** sneaky and changed the port on us. */ -static int autoconf_media(struct device *dev) +static int +autoconf_media(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -1783,7 +1833,7 @@ static int autoconf_media(struct device *dev) } else if (lp->chipset == DC21140) { next_tick = dc21140m_autoconf(dev); } - if (lp->autosense == AUTO) enable_ast(dev, next_tick); + enable_ast(dev, next_tick); return (lp->media); } @@ -1800,7 +1850,8 @@ static int autoconf_media(struct device *dev) ** I may have to "age out" locally queued packets so that the higher layer ** timeouts don't effectively duplicate packets on the network. */ -static int dc21040_autoconf(struct device *dev) +static int +dc21040_autoconf(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -1827,32 +1878,32 @@ static int dc21040_autoconf(struct device *dev) break; case TP: - dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, + next_tick = dc21040_state(dev, 0x8f01, 0xffff, 0x0000, 3000, BNC_AUI, TP_SUSPECT, test_tp); break; case TP_SUSPECT: - de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21040_autoconf); break; case BNC: case AUI: case BNC_AUI: - dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, + next_tick = dc21040_state(dev, 0x8f09, 0x0705, 0x0006, 3000, EXT_SIA, BNC_AUI_SUSPECT, ping_media); break; case BNC_AUI_SUSPECT: - de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, BNC_AUI, ping_media, dc21040_autoconf); break; case EXT_SIA: - dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, + next_tick = dc21040_state(dev, 0x3041, 0x0000, 0x0006, 3000, NC, EXT_SIA_SUSPECT, ping_media); break; case EXT_SIA_SUSPECT: - de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, EXT_SIA, ping_media, dc21040_autoconf); break; case NC: @@ -1862,7 +1913,10 @@ static int dc21040_autoconf(struct device *dev) /* JAE: for Alpha, default to BNC/AUI, *not* TP */ reset_init_sia(dev, 0x8f09, 0x0705, 0x0006); #endif /* i386 */ - de4x5_dbg_media(dev); + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } lp->media = INIT; lp->tx_enable = NO; break; @@ -1953,7 +2007,8 @@ de4x5_suspect_state(struct device *dev, int timeout, int prev_state, ** any more packets to be queued to the hardware. Re-enable everything only ** when the media is found. */ -static int dc21041_autoconf(struct device *dev) +static int +dc21041_autoconf(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2013,6 +2068,7 @@ static int dc21041_autoconf(struct device *dev) lp->media = TP; next_tick = dc21041_autoconf(dev); } else { + lp->local_state = 1; de4x5_init_connection(dev); } } @@ -2023,7 +2079,7 @@ static int dc21041_autoconf(struct device *dev) break; case ANS_SUSPECT: - de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, ANS, test_tp, dc21041_autoconf); break; case TP: @@ -2046,6 +2102,7 @@ static int dc21041_autoconf(struct device *dev) } next_tick = dc21041_autoconf(dev); } else { + lp->local_state = 1; de4x5_init_connection(dev); } } @@ -2056,7 +2113,7 @@ static int dc21041_autoconf(struct device *dev) break; case TP_SUSPECT: - de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, TP, test_tp, dc21041_autoconf); break; case AUI: @@ -2067,7 +2124,7 @@ static int dc21041_autoconf(struct device *dev) } irqs = 0; irq_mask = 0; - sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x000e, 1000); + sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x000e, 1000); if (sts < 0) { next_tick = sts & ~TIMER_CB; } else { @@ -2075,6 +2132,7 @@ static int dc21041_autoconf(struct device *dev) lp->media = BNC; next_tick = dc21041_autoconf(dev); } else { + lp->local_state = 1; de4x5_init_connection(dev); } } @@ -2085,7 +2143,7 @@ static int dc21041_autoconf(struct device *dev) break; case AUI_SUSPECT: - de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, AUI, ping_media, dc21041_autoconf); break; case BNC: @@ -2097,7 +2155,7 @@ static int dc21041_autoconf(struct device *dev) } irqs = 0; irq_mask = 0; - sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf7fd, 0x0006, 1000); + sts = test_media(dev,irqs, irq_mask, 0xef09, 0xf73d, 0x0006, 1000); if (sts < 0) { next_tick = sts & ~TIMER_CB; } else { @@ -2131,14 +2189,17 @@ static int dc21041_autoconf(struct device *dev) break; case BNC_SUSPECT: - de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf); + next_tick = de4x5_suspect_state(dev, 1000, BNC, ping_media, dc21041_autoconf); break; case NC: omr = inl(DE4X5_OMR); /* Set up full duplex for the autonegotiate */ outl(omr | OMR_FD, DE4X5_OMR); reset_init_sia(dev, 0xef01, 0xffff, 0x0008);/* Initialise the SIA */ - de4x5_dbg_media(dev); + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } lp->media = INIT; lp->tx_enable = NO; break; @@ -2147,10 +2208,16 @@ static int dc21041_autoconf(struct device *dev) return next_tick; } -static int dc21140m_autoconf(struct device *dev) +/* +** Some autonegotiation chips are broken in that they do not return the +** acknowledge bit (anlpa & MII_ANLPA_ACK) in the link partner advertisement +** register, except at the first power up negotiation. +*/ +static int +dc21140m_autoconf(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; - int ana, anlpa, cap, cr, sr, iobase = dev->base_addr; + int ana, anlpa, cap, cr, slnk, sr, iobase = dev->base_addr; int next_tick = DE4X5_AUTOSENSE_MS; u_long imr, omr; @@ -2163,12 +2230,14 @@ static int dc21140m_autoconf(struct device *dev) next_tick &= ~TIMER_CB; } else { de4x5_save_skbs(dev); /* Save non transmitted skb's */ + lp->tmp = MII_SR_ASSC; /* Fake out the MII speed set */ SET_10Mb; if (lp->autosense == _100Mb) { lp->media = _100Mb; } else if (lp->autosense == _10Mb) { lp->media = _10Mb; - } else if ((lp->autosense == AUTO) && (sr=is_anc_capable(dev))) { + } else if ((lp->autosense == AUTO) && + ((sr=is_anc_capable(dev)) & MII_SR_ANC)) { ana = (((sr >> 6) & MII_ANA_TAF) | MII_ANA_CSMA); ana &= (de4x5_full_duplex ? ~0 : ~MII_ANA_FDAM); mii_wr(ana, MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); @@ -2206,21 +2275,23 @@ static int dc21140m_autoconf(struct device *dev) break; case 1: - if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 3000)) < 0) { + if ((sr=test_mii_reg(dev, MII_SR, MII_SR_ASSC, TRUE, 2000)) < 0) { next_tick = sr & ~TIMER_CB; } else { lp->media = SPD_DET; lp->local_state = 0; if (sr) { /* Success! */ + lp->tmp = MII_SR_ASSC; anlpa = mii_rd(MII_ANLPA, lp->phy[lp->active].addr, DE4X5_MII); ana = mii_rd(MII_ANA, lp->phy[lp->active].addr, DE4X5_MII); - if ((anlpa & MII_ANLPA_ACK) && !(anlpa & MII_ANLPA_RF) && - (cap = anlpa & MII_ANLPA_TAF & ana)) { + if (!(anlpa & MII_ANLPA_RF) && + (cap = anlpa & MII_ANLPA_TAF & ana)) { if (cap & MII_ANA_100M) { de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_100M) ? TRUE : FALSE); lp->media = _100Mb; } else if (cap & MII_ANA_10M) { de4x5_full_duplex = ((ana & anlpa & MII_ANA_FDAM & MII_ANA_10M) ? TRUE : FALSE); + lp->media = _10Mb; } } @@ -2232,17 +2303,23 @@ static int dc21140m_autoconf(struct device *dev) break; case SPD_DET: /* Choose 10Mb/s or 100Mb/s */ - if (!lp->phy[lp->active].id) { - outl(GEP_FDXD | GEP_MODE, DE4X5_GEP); + if (lp->timeout < 0) { + lp->tmp = (lp->phy[lp->active].id ? MII_SR_LKS : + (~inl(DE4X5_GEP) & GEP_LNP)); + SET_100Mb_PDET; } - if (is_spd_100(dev) && is_100_up(dev)) { - lp->media = _100Mb; - } else if (!is_spd_100(dev) && is_10_up(dev)) { - lp->media = _10Mb; + if ((slnk = test_sym_link(dev, 6200)) < 0) { + next_tick = slnk & ~TIMER_CB; } else { - lp->media = NC; + if (is_spd_100(dev) && is_100_up(dev)) { + lp->media = _100Mb; + } else if ((!is_spd_100(dev) && (is_10_up(dev) & lp->tmp))) { + lp->media = _10Mb; + } else { + lp->media = NC; + } + next_tick = dc21140m_autoconf(dev); } - next_tick = dc21140m_autoconf(dev); break; case _100Mb: /* Set 100Mb/s */ @@ -2276,8 +2353,10 @@ static int dc21140m_autoconf(struct device *dev) break; case NC: - SET_10Mb; - de4x5_dbg_media(dev); + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; + } lp->media = INIT; lp->tx_enable = FALSE; break; @@ -2286,12 +2365,16 @@ static int dc21140m_autoconf(struct device *dev) return next_tick; } -static void de4x5_init_connection(struct device *dev) +static void +de4x5_init_connection(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - de4x5_dbg_media(dev); + if (lp->media != lp->c_media) { + de4x5_dbg_media(dev); + lp->c_media = lp->media; /* Stop scrolling media messages */ + } de4x5_restore_skbs(dev); cli(); de4x5_rx(dev); @@ -2304,7 +2387,8 @@ static void de4x5_init_connection(struct device *dev) return; } -static int de4x5_reset_phy(struct device *dev) +static int +de4x5_reset_phy(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2360,7 +2444,8 @@ test_media(struct device *dev, s32 irqs, s32 irq_mask, s32 csr13, s32 csr14, s32 return sts; } -static int test_tp(struct device *dev, s32 msec) +static int +test_tp(struct device *dev, s32 msec) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2381,11 +2466,37 @@ static int test_tp(struct device *dev, s32 msec) return sisr; } +static int +test_sym_link(struct device *dev, int msec) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int iobase = dev->base_addr; + int gep = 0; + + if (lp->timeout < 0) { + lp->timeout = msec/100; + } + + if (lp->phy[lp->active].id) { + gep = ((is_100_up(dev) && is_spd_100(dev)) ? GEP_SLNK : 0); + } else { + gep = (~inl(DE4X5_GEP) & (GEP_SLNK | GEP_LNP)); + } + if (!(gep & GEP_SLNK) && --lp->timeout) { + gep = 100 | TIMER_CB; + } else { + lp->timeout = -1; + } + + return gep; +} + /* ** ** */ -static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec) +static int +test_mii_reg(struct device *dev, int reg, int mask, int pol, long msec) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int test, iobase = dev->base_addr; @@ -2395,7 +2506,7 @@ static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long mse } if (pol) pol = ~0; - reg = mii_rd(reg, lp->phy[lp->active].addr, DE4X5_MII) & mask; + reg = mii_rd((u_char)reg, lp->phy[lp->active].addr, DE4X5_MII) & mask; test = (reg ^ pol) & mask; if (test && --lp->timeout) { @@ -2407,7 +2518,8 @@ static int test_mii_reg(struct device *dev, int reg, int mask, int pol, long mse return reg; } -static int is_spd_100(struct device *dev) +static int +is_spd_100(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2424,7 +2536,8 @@ static int is_spd_100(struct device *dev) return spd; } -static int is_100_up(struct device *dev) +static int +is_100_up(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2438,7 +2551,8 @@ static int is_100_up(struct device *dev) } } -static int is_10_up(struct device *dev) +static int +is_10_up(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2452,13 +2566,14 @@ static int is_10_up(struct device *dev) } } -static int is_anc_capable(struct device *dev) +static int +is_anc_capable(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; if (lp->phy[lp->active].id) { - return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII) & MII_SR_ANC); + return (mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII)); } else { return 0; } @@ -2468,7 +2583,8 @@ static int is_anc_capable(struct device *dev) ** Send a packet onto the media and watch for send errors that indicate the ** media is bad or unconnected. */ -static int ping_media(struct device *dev, int msec) +static int +ping_media(struct device *dev, int msec) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2500,6 +2616,95 @@ static int ping_media(struct device *dev, int msec) return sisr; } +/* +** This function does 2 things: on Intels it kmalloc's another buffer to +** replace the one about to be passed up. On Alpha's it kmallocs a buffer +** into which the packet is copied. +*/ +static struct sk_buff * +de4x5_alloc_rx_buff(struct device *dev, int index, int len) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + struct sk_buff *p; + +#ifndef __alpha__ + struct sk_buff *ret; + u_long i=0, tmp; + + p = dev_alloc_skb(IEEE802_3_SZ + ALIGN + 2); + if (!p) return NULL; + + p->dev = dev; + tmp = virt_to_bus(p->data); + i = ((tmp + ALIGN) & ~ALIGN) - tmp; + skb_reserve(p, i); + lp->rx_ring[index].buf = tmp + i; + + ret = lp->rx_skb[index]; + lp->rx_skb[index] = p; + skb_put(ret, len); + + return ret; + +#else + if (lp->state != OPEN) return (struct sk_buff *)1; /* Fake out the open */ + + p = dev_alloc_skb(len + 2); + if (!p) return NULL; + + p->dev = dev; + skb_reserve(p, 2); /* Align */ + if (index < lp->rx_old) { /* Wrapped buffer */ + short tlen = (lp->rxRingSize - lp->rx_old) * RX_BUFF_SZ; + memcpy(skb_put(p,tlen), bus_to_virt(lp->rx_ring[lp->rx_old].buf),tlen); + memcpy(skb_put(p,len-tlen), bus_to_virt(lp->rx_ring[0].buf), len-tlen); + } else { /* Linear buffer */ + memcpy(skb_put(p,len), bus_to_virt(lp->rx_ring[lp->rx_old].buf),len); + } + + return p; +#endif +} + +static void +de4x5_free_rx_buffs(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int i; + + for (i=0; irxRingSize; i++) { + if (lp->rx_skb[i]) { + dev_kfree_skb(lp->rx_skb[i], FREE_WRITE); + } + lp->rx_ring[i].status = 0; + lp->rx_skb[i] = (struct sk_buff *)1; /* Dummy entry */ + } + + return; +} + +static void +de4x5_free_tx_buffs(struct device *dev) +{ + struct de4x5_private *lp = (struct de4x5_private *)dev->priv; + int i; + + for (i=0; itxRingSize; i++) { + if (lp->tx_skb[i]) { + dev_kfree_skb(lp->tx_skb[i], FREE_WRITE); + lp->tx_skb[i] = NULL; + } + lp->tx_ring[i].status = 0; + } + + /* Unload the locally queued packets */ + while (lp->cache.skb) { + dev_kfree_skb(de4x5_get_cache(dev), FREE_WRITE); + } + + return; +} + /* ** When a user pulls a connection, the DECchip can end up in a ** 'running - waiting for end of transmission' state. This means that we @@ -2507,28 +2712,17 @@ static int ping_media(struct device *dev, int msec) ** the hardware and software and make any media probes using a loopback ** packet meaningful. */ -static void de4x5_save_skbs(struct device *dev) +static void +de4x5_save_skbs(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - int i; s32 omr; if (!lp->cache.save_cnt) { STOP_DE4X5; de4x5_tx(dev); /* Flush any sent skb's */ - for (i=lp->tx_new; i!=lp->tx_old; i--) { - if (lp->skb[i]) { - de4x5_putb_cache(dev, lp->skb[i]); - lp->skb[i] = NULL; - } - if (i==0) i=lp->txRingSize; - } - if (lp->skb[i]) { - de4x5_putb_cache(dev, lp->skb[i]); - lp->skb[i] = NULL; - } - + de4x5_free_tx_buffs(dev); de4x5_cache_state(dev, DE4X5_SAVE_STATE); de4x5_sw_reset(dev); de4x5_cache_state(dev, DE4X5_RESTORE_STATE); @@ -2540,12 +2734,11 @@ static void de4x5_save_skbs(struct device *dev) return; } -static void de4x5_restore_skbs(struct device *dev) +static void +de4x5_restore_skbs(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; - struct sk_buff *skb; - int i; s32 omr; if (lp->cache.save_cnt) { @@ -2553,16 +2746,7 @@ static void de4x5_restore_skbs(struct device *dev) de4x5_cache_state(dev, DE4X5_SAVE_STATE); de4x5_sw_reset(dev); de4x5_cache_state(dev, DE4X5_RESTORE_STATE); - dev->tbusy = 1; - - for (i=0; TX_BUFFS_AVAIL && lp->cache.skb; i++) { - skb = de4x5_get_cache(dev); - load_packet(dev, skb->data, TD_IC | TD_LS | TD_FS | skb->len, skb); - lp->tx_new = (++lp->tx_new) % lp->txRingSize; - } - if (TX_BUFFS_AVAIL) { - dev->tbusy = 0; - } + dev->tbusy = 0; lp->cache.save_cnt--; START_DE4X5; } @@ -2570,7 +2754,8 @@ static void de4x5_restore_skbs(struct device *dev) return; } -static void de4x5_cache_state(struct device *dev, int flag) +static void +de4x5_cache_state(struct device *dev, int flag) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2609,7 +2794,8 @@ static void de4x5_cache_state(struct device *dev, int flag) return; } -static void de4x5_put_cache(struct device *dev, struct sk_buff *skb) +static void +de4x5_put_cache(struct device *dev, struct sk_buff *skb) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; struct sk_buff *p; @@ -2625,7 +2811,8 @@ static void de4x5_put_cache(struct device *dev, struct sk_buff *skb) return; } -static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb) +static void +de4x5_putb_cache(struct device *dev, struct sk_buff *skb) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; struct sk_buff *p = lp->cache.skb; @@ -2636,7 +2823,8 @@ static void de4x5_putb_cache(struct device *dev, struct sk_buff *skb) return; } -static struct sk_buff *de4x5_get_cache(struct device *dev) +static struct sk_buff * +de4x5_get_cache(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; struct sk_buff *p = lp->cache.skb; @@ -2653,7 +2841,8 @@ static struct sk_buff *de4x5_get_cache(struct device *dev) ** Check the Auto Negotiation State. Return OK when a link pass interrupt ** is received and the auto-negotiation status is NWAY OK. */ -static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec) +static int +test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2680,7 +2869,8 @@ static int test_ans(struct device *dev, s32 irqs, s32 irq_mask, s32 msec) return sts; } -static void de4x5_setup_intr(struct device *dev) +static void +de4x5_setup_intr(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2700,7 +2890,8 @@ static void de4x5_setup_intr(struct device *dev) /* ** */ -static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr) +static void +reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; u_long iobase = dev->base_addr; @@ -2716,7 +2907,8 @@ static void reset_init_sia(struct device *dev, s32 sicr, s32 strr, s32 sigr) /* ** Create a loopback ethernet packet with an invalid CRC */ -static void create_packet(struct device *dev, char *frame, int len) +static void +create_packet(struct device *dev, char *frame, int len) { int i; char *buf = frame; @@ -2737,7 +2929,8 @@ static void create_packet(struct device *dev, char *frame, int len) /* ** Known delay in microseconds */ -static void de4x5_us_delay(u32 usec) +static void +de4x5_us_delay(u32 usec) { udelay(usec); @@ -2747,7 +2940,8 @@ static void de4x5_us_delay(u32 usec) /* ** Known delay in milliseconds, in millisecond steps. */ -static void de4x5_ms_delay(u32 msec) +static void +de4x5_ms_delay(u32 msec) { u_int i; @@ -2762,7 +2956,8 @@ static void de4x5_ms_delay(u32 msec) /* ** Look for a particular board name in the EISA configuration space */ -static int EISA_signature(char *name, s32 eisa_id) +static int +EISA_signature(char *name, s32 eisa_id) { c_char *signatures[] = DE4X5_SIGNATURE; char ManCode[DE4X5_STRLEN]; @@ -2796,7 +2991,8 @@ static int EISA_signature(char *name, s32 eisa_id) /* ** Look for a particular board name in the PCI configuration space */ -static int PCI_signature(char *name, struct bus_type *lp) +static int +PCI_signature(char *name, struct bus_type *lp) { c_char *de4x5_signatures[] = DE4X5_SIGNATURE; int i, status = 0, siglen = sizeof(de4x5_signatures)/sizeof(c_char *); @@ -2833,7 +3029,8 @@ static int PCI_signature(char *name, struct bus_type *lp) ** Set up the Ethernet PROM counter to the start of the Ethernet address on ** the DC21040, else read the SROM for the other chips. */ -static void DevicePresent(u_long aprom_addr) +static void +DevicePresent(u_long aprom_addr) { int i; struct bus_type *lp = &bus; @@ -2851,7 +3048,8 @@ static void DevicePresent(u_long aprom_addr) return; } -static int get_hw_addr(struct device *dev) +static int +get_hw_addr(struct device *dev) { u_long iobase = dev->base_addr; int broken, i, k, tmp, status = 0; @@ -2902,7 +3100,7 @@ static int get_hw_addr(struct device *dev) chksum |= (u_short) (inb(EISA_APROM) << 8); if ((k != chksum) && (dec_only)) status = -1; } - + return status; } @@ -2910,7 +3108,8 @@ static int get_hw_addr(struct device *dev) ** Test for enet addresses in the first 32 bytes. The built-in strncmp ** didn't seem to work here...? */ -static int de4x5_bad_srom(struct bus_type *lp) +static int +de4x5_bad_srom(struct bus_type *lp) { int i, status = 0; @@ -2925,7 +3124,8 @@ static int de4x5_bad_srom(struct bus_type *lp) return status; } -static int de4x5_strncmp(char *a, char *b, int n) +static int +de4x5_strncmp(char *a, char *b, int n) { int ret=0; @@ -2939,7 +3139,8 @@ static int de4x5_strncmp(char *a, char *b, int n) /* ** SROM Read */ -static short srom_rd(u_long addr, u_char offset) +static short +srom_rd(u_long addr, u_char offset) { sendto_srom(SROM_RD | SROM_SR, addr); @@ -2950,7 +3151,8 @@ static short srom_rd(u_long addr, u_char offset) return srom_data(SROM_RD | SROM_SR | DT_CS, addr); } -static void srom_latch(u_int command, u_long addr) +static void +srom_latch(u_int command, u_long addr) { sendto_srom(command, addr); sendto_srom(command | DT_CLK, addr); @@ -2959,7 +3161,8 @@ static void srom_latch(u_int command, u_long addr) return; } -static void srom_command(u_int command, u_long addr) +static void +srom_command(u_int command, u_long addr) { srom_latch(command, addr); srom_latch(command, addr); @@ -2968,7 +3171,8 @@ static void srom_command(u_int command, u_long addr) return; } -static void srom_address(u_int command, u_long addr, u_char offset) +static void +srom_address(u_int command, u_long addr, u_char offset) { int i; char a; @@ -2987,7 +3191,8 @@ static void srom_address(u_int command, u_long addr, u_char offset) return; } -static short srom_data(u_int command, u_long addr) +static short +srom_data(u_int command, u_long addr) { int i; short word = 0; @@ -3007,7 +3212,8 @@ static short srom_data(u_int command, u_long addr) } /* -static void srom_busy(u_int command, u_long addr) +static void +srom_busy(u_int command, u_long addr) { sendto_srom((command & 0x0000ff00) | DT_CS, addr); @@ -3021,7 +3227,8 @@ static void srom_busy(u_int command, u_long addr) } */ -static void sendto_srom(u_int command, u_long addr) +static void +sendto_srom(u_int command, u_long addr) { outl(command, addr); udelay(1); @@ -3029,7 +3236,8 @@ static void sendto_srom(u_int command, u_long addr) return; } -static int getfrom_srom(u_long addr) +static int +getfrom_srom(u_long addr) { s32 tmp; @@ -3043,7 +3251,8 @@ static int getfrom_srom(u_long addr) ** MII Read/Write */ -static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr) +static int +mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr) { mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */ mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */ @@ -3055,7 +3264,8 @@ static int mii_rd(u_char phyreg, u_char phyaddr, u_long ioaddr) return mii_rdata(ioaddr); /* Read data */ } -static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr) +static void +mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr) { mii_wdata(MII_PREAMBLE, 2, ioaddr); /* Start of 34 bit preamble... */ mii_wdata(MII_PREAMBLE, 32, ioaddr); /* ...continued */ @@ -3069,7 +3279,8 @@ static void mii_wr(int data, u_char phyreg, u_char phyaddr, u_long ioaddr) return; } -static int mii_rdata(u_long ioaddr) +static int +mii_rdata(u_long ioaddr) { int i; s32 tmp = 0; @@ -3082,7 +3293,8 @@ static int mii_rdata(u_long ioaddr) return tmp; } -static void mii_wdata(int data, int len, u_long ioaddr) +static void +mii_wdata(int data, int len, u_long ioaddr) { int i; @@ -3094,7 +3306,8 @@ static void mii_wdata(int data, int len, u_long ioaddr) return; } -static void mii_address(u_char addr, u_long ioaddr) +static void +mii_address(u_char addr, u_long ioaddr) { int i; @@ -3107,11 +3320,12 @@ static void mii_address(u_char addr, u_long ioaddr) return; } -static void mii_ta(u_long rw, u_long ioaddr) +static void +mii_ta(u_long rw, u_long ioaddr) { if (rw == MII_STWR) { sendto_mii(MII_MWR | MII_WR, 1, ioaddr); - getfrom_mii(MII_MRD | MII_RD, ioaddr); + sendto_mii(MII_MWR | MII_WR, 0, ioaddr); } else { getfrom_mii(MII_MRD | MII_RD, ioaddr); /* Tri-state MDIO */ } @@ -3119,7 +3333,8 @@ static void mii_ta(u_long rw, u_long ioaddr) return; } -static int mii_swap(int data, int len) +static int +mii_swap(int data, int len) { int i, tmp = 0; @@ -3132,7 +3347,8 @@ static int mii_swap(int data, int len) return tmp; } -static void sendto_mii(u32 command, int data, u_long ioaddr) +static void +sendto_mii(u32 command, int data, u_long ioaddr) { u32 j; @@ -3145,7 +3361,8 @@ static void sendto_mii(u32 command, int data, u_long ioaddr) return; } -static int getfrom_mii(u32 command, u_long ioaddr) +static int +getfrom_mii(u32 command, u_long ioaddr) { outl(command, ioaddr); udelay(1); @@ -3159,7 +3376,8 @@ static int getfrom_mii(u32 command, u_long ioaddr) ** Here's 3 ways to calculate the OUI from the ID registers. One's a brain ** dead approach, 2 aren't (clue: mine isn't!). */ -static int mii_get_oui(u_char phyaddr, u_long ioaddr) +static int +mii_get_oui(u_char phyaddr, u_long ioaddr) { /* union { @@ -3202,7 +3420,8 @@ static int mii_get_oui(u_char phyaddr, u_long ioaddr) return r2; /* (I did it) My way */ } -static int mii_get_phy(struct device *dev) +static int +mii_get_phy(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int iobase = dev->base_addr; @@ -3246,7 +3465,8 @@ static int mii_get_phy(struct device *dev) return lp->mii_cnt; } -static char *build_setup_frame(struct device *dev, int mode) +static char * +build_setup_frame(struct device *dev, int mode) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int i; @@ -3277,14 +3497,16 @@ static char *build_setup_frame(struct device *dev, int mode) return pa; /* Points to the next entry */ } -static void enable_ast(struct device *dev, u32 time_out) +static void +enable_ast(struct device *dev, u32 time_out) { timeout(dev, (void *)&de4x5_ast, (u_long)dev, time_out); return; } -static void disable_ast(struct device *dev) +static void +disable_ast(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; @@ -3293,7 +3515,8 @@ static void disable_ast(struct device *dev) return; } -static long de4x5_switch_to_mii(struct device *dev) +static long +de4x5_switch_to_mii(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int iobase = dev->base_addr; @@ -3319,7 +3542,8 @@ static long de4x5_switch_to_mii(struct device *dev) return omr; } -static long de4x5_switch_to_srl(struct device *dev) +static long +de4x5_switch_to_srl(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int iobase = dev->base_addr; @@ -3327,7 +3551,6 @@ static long de4x5_switch_to_srl(struct device *dev) /* Deassert the OMR_PS bit in CSR6 */ omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR)); - outl(omr | OMR_TTM, DE4X5_OMR); outl(omr, DE4X5_OMR); /* Soft Reset */ @@ -3345,7 +3568,8 @@ static long de4x5_switch_to_srl(struct device *dev) return omr; } -static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec) +static void +timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_long msec) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int dt; @@ -3366,7 +3590,8 @@ static void timeout(struct device *dev, void (*fn)(u_long data), u_long data, u_ return; } -static void de4x5_dbg_open(struct device *dev) +static void +de4x5_dbg_open(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int i; @@ -3416,7 +3641,8 @@ static void de4x5_dbg_open(struct device *dev) return; } -static void de4x5_dbg_mii(struct device *dev, int k) +static void +de4x5_dbg_mii(struct device *dev, int k) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; int iobase = dev->base_addr; @@ -3442,7 +3668,8 @@ static void de4x5_dbg_mii(struct device *dev, int k) return; } -static void de4x5_dbg_media(struct device *dev) +static void +de4x5_dbg_media(struct device *dev) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; @@ -3473,7 +3700,8 @@ static void de4x5_dbg_media(struct device *dev) return; } -static void de4x5_dbg_srom(struct de4x5_srom *p) +static void +de4x5_dbg_srom(struct de4x5_srom *p) { int i; @@ -3496,11 +3724,48 @@ static void de4x5_dbg_srom(struct de4x5_srom *p) return; } +static void +de4x5_dbg_rx(struct sk_buff *skb, int len) +{ + int i, j; + + if (de4x5_debug > 2) { + printk("R: %02x:%02x:%02x:%02x:%02x:%02x <- %02x:%02x:%02x:%02x:%02x:%02x len/SAP:%02x%02x [%d]\n", + (u_char)skb->data[0], + (u_char)skb->data[1], + (u_char)skb->data[2], + (u_char)skb->data[3], + (u_char)skb->data[4], + (u_char)skb->data[5], + (u_char)skb->data[6], + (u_char)skb->data[7], + (u_char)skb->data[8], + (u_char)skb->data[9], + (u_char)skb->data[10], + (u_char)skb->data[11], + (u_char)skb->data[12], + (u_char)skb->data[13], + len); + if (de4x5_debug > 3) { + for (j=0; len>0;j+=16, len-=16) { + printk(" %03x: ",j); + for (i=0; i<16 && idata[i+j]); + } + printk("\n"); + } + } + } + + return; +} + /* ** Perform IOCTL call functions here. Some are privileged operations and the ** effective uid is checked in those cases. */ -static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) +static int +de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) { struct de4x5_private *lp = (struct de4x5_private *)dev->priv; struct de4x5_ioctl *ioc = (struct de4x5_ioctl *) &rq->ifr_data; @@ -3540,13 +3805,8 @@ static int de4x5_ioctl(struct device *dev, struct ifreq *rq, int cmd) build_setup_frame(dev, PHYS_ADDR_ONLY); /* Set up the descriptor and give ownership to the card */ while (set_bit(0, (void *)&dev->tbusy) != 0);/* Wait for lock to free*/ - if (lp->setup_f == HASH_PERF) { - load_packet(dev, lp->setup_frame, TD_IC | HASH_F | TD_SET | - SETUP_FRAME_LEN, NULL); - } else { - load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | - SETUP_FRAME_LEN, NULL); - } + load_packet(dev, lp->setup_frame, TD_IC | PERFECT_F | TD_SET | + SETUP_FRAME_LEN, NULL); lp->tx_new = (++lp->tx_new) % lp->txRingSize; outl(POLL_DEMAND, DE4X5_TPD); /* Start the TX */ dev->tbusy = 0; /* Unlock the TX ring */ diff --git a/drivers/net/de4x5.h b/drivers/net/de4x5.h index ada3ce1b806c..0342a4840178 100644 --- a/drivers/net/de4x5.h +++ b/drivers/net/de4x5.h @@ -671,9 +671,6 @@ #define EXT_SIA_SUSPECT 0x0805 /* Suspect the EXT SIA port is down */ #define BNC_SUSPECT 0x0806 /* Suspect the BNC port is down */ #define AUI_SUSPECT 0x0807 /* Suspect the AUI port is down */ -#define _10Mb_SUSPECT 0x0808 /* Suspect 10Mb/s is down */ -#define _100Mb_SUSPECT 0x0809 /* Suspect 100Mb/s is down */ -#define LINK_RESET 0x080a /* Reset the PHY and re-init auto sense */ #define AUTO 0x4000 /* Auto sense the media or speed */ #define TIMER_CB 0x80000000 /* Timer callback detection */ @@ -743,13 +740,15 @@ */ #define SET_10Mb {\ if (lp->phy[lp->active].id) {\ - mii_wr(MII_CR_10|MII_CR_ASSE,MII_CR,lp->phy[lp->active].addr,DE4X5_MII);\ - omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR);\ - omr |= (de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM;\ + omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\ + if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\ + mii_wr(MII_CR_10|(de4x5_full_duplex?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\ + }\ + omr |= ((de4x5_full_duplex ? OMR_FD : 0) | OMR_TTM);\ outl(omr, DE4X5_OMR);\ outl(0, DE4X5_GEP);\ } else {\ - omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));\ + omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\ omr |= (de4x5_full_duplex ? OMR_FD : 0);\ outl(omr | OMR_TTM, DE4X5_OMR);\ outl((de4x5_full_duplex ? 0 : GEP_FDXD), DE4X5_GEP);\ @@ -758,21 +757,40 @@ #define SET_100Mb {\ if (lp->phy[lp->active].id) {\ - mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\ - omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR);\ + int fdx=0;\ + if (lp->phy[lp->active].id == NATIONAL_TX) {\ + mii_wr(mii_rd(0x18, lp->phy[lp->active].addr, DE4X5_MII) & ~0x2000,\ + 0x18, lp->phy[lp->active].addr, DE4X5_MII);\ + }\ + omr = inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD);\ sr = mii_rd(MII_SR, lp->phy[lp->active].addr, DE4X5_MII);\ - if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) omr |= OMR_FD;\ + if (!(sr & MII_ANA_T4AM) && de4x5_full_duplex) fdx=1;\ + if ((lp->tmp != MII_SR_ASSC) || (lp->autosense != AUTO)) {\ + mii_wr(MII_CR_100|(fdx?MII_CR_FDM:0), MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\ + }\ + if (fdx) omr |= OMR_FD;\ outl(omr, DE4X5_OMR);\ - outl(((!(sr & MII_ANA_T4AM) && de4x5_full_duplex) ? 0:GEP_FDXD)|GEP_MODE,\ - DE4X5_GEP);\ } else {\ - omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR));\ + omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\ omr |= (de4x5_full_duplex ? OMR_FD : 0);\ outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\ outl((de4x5_full_duplex ? 0 : GEP_FDXD) | GEP_MODE, DE4X5_GEP);\ }\ } +/* FIX ME so I don't jam 10Mb networks */ +#define SET_100Mb_PDET {\ + if (lp->phy[lp->active].id) {\ + mii_wr(MII_CR_100|MII_CR_ASSE, MII_CR, lp->phy[lp->active].addr, DE4X5_MII);\ + omr = (inl(DE4X5_OMR) & ~(OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\ + outl(omr, DE4X5_OMR);\ + } else {\ + omr = (inl(DE4X5_OMR) & ~(OMR_PS | OMR_HBD | OMR_TTM | OMR_PCS | OMR_SCR | OMR_FD));\ + outl(omr | OMR_PS | OMR_HBD | OMR_PCS | OMR_SCR, DE4X5_OMR);\ + outl(GEP_FDXD | GEP_MODE, DE4X5_GEP);\ + }\ +} + /* ** Include the IOCTL stuff */ diff --git a/drivers/sbus/Makefile b/drivers/sbus/Makefile index b452fa9277f0..08bd0462e6cd 100644 --- a/drivers/sbus/Makefile +++ b/drivers/sbus/Makefile @@ -7,7 +7,18 @@ # # Note 2! The CFLAGS definitions are now in the main makefile... +SUB_DIRS := +MOD_SUB_DIRS := $(SUB_DIRS) +ALL_SUB_DIRS := $(SUB_DIRS) char + L_OBJS := sbus.o dvma.o L_TARGET := sbus.a +# Character devices for SBUS-based machines. +# +ifeq ($(CONFIG_SBUSCHAR),y) +SUB_DIRS += char +L_OBJS += char/sunchar.o +endif + include $(TOPDIR)/Rules.make diff --git a/drivers/sbus/char/Makefile b/drivers/sbus/char/Makefile new file mode 100644 index 000000000000..5f3bd978b0e7 --- /dev/null +++ b/drivers/sbus/char/Makefile @@ -0,0 +1,13 @@ +# +# 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... + +O_TARGET := sunchar.o +O_OBJS := suncons.o sunkbd.o sunkeymap.o sunmouse.o sunserial.o + +include $(TOPDIR)/Rules.make diff --git a/drivers/char/suncons.c b/drivers/sbus/char/suncons.c similarity index 95% rename from drivers/char/suncons.c rename to drivers/sbus/char/suncons.c index da70ff440a1f..48adfd152aa9 100644 --- a/drivers/char/suncons.c +++ b/drivers/sbus/char/suncons.c @@ -71,11 +71,11 @@ #include #include /* for the sun4c_nocache */ -#include "kbd_kern.h" -#include "vt_kern.h" -#include "consolemap.h" -#include "selection.h" -#include "console_struct.h" +#include "../../char/kbd_kern.h" +#include "../../char/vt_kern.h" +#include "../../char/consolemap.h" +#include "../../char/selection.h" +#include "../../char/console_struct.h" #define cmapsz 8192 @@ -1214,8 +1214,20 @@ bwtwo_setup (int slot, unsigned int bwtwo, int bw2_io) 0, sizeof (struct bwtwo_regs), "bwtwo_regs", bw2_io, 0); } +static void +cg14_setup (int slot, unsigned int cg14, int cg14_io) +{ + printk ("cgfourteen%d at 0x%8.8x\n", slot, cg14); + fbinfo [slot].type.fb_cmsize = 256; + fbinfo [slot].mmap = 0; + fbinfo [slot].loadcmap = 0; + fbinfo [slot].ioctl = 0; + fbinfo [slot].blank = 0; + fbinfo [slot].unblank = 0; +} + static char *known_cards [] = { - "cgsix", "cgthree", "bwtwo", "SUNW,tcx", 0 + "cgsix", "cgthree", "bwtwo", "SUNW,tcx", "cgfourteen", 0 }; static int @@ -1241,6 +1253,23 @@ static struct { { 0 }, }; +static int +cg14_present(void) +{ + int root, n; + + prom_printf ("Looking for cg14\n"); + root = prom_getchild (prom_root_node); + if ((n = prom_searchsiblings (root, "obio")) == 0) + return 0; + + n = prom_getchild (n); + if ((n = prom_searchsiblings (n, "cgfourteen")) == 0) + return 0; + prom_printf ("Cg14 found!\n"); + return n; +} + static int sparc_console_probe(void) { @@ -1248,6 +1277,7 @@ sparc_console_probe(void) struct linux_sbus_device *sbdp; unsigned int fbbase = 0xb001b001; int fbiospace = 0; + int cg14 = 0; /* XXX The detection code needs to support multiple video cards in one system */ con_node = 0; @@ -1290,47 +1320,62 @@ sparc_console_probe(void) case PROM_V3: case PROM_P1275: for_each_sbusdev(sbdp, SBus_chain) { + prom_printf ("Trying: %s\n", sbdp->prom_name); if (known_card (sbdp->prom_name)) break; } if (!sbdp){ - prom_printf ("Could not find a know video card on this machine\n"); - prom_halt (); + if (!(cg14 = cg14_present ())){ + prom_printf ("Could not find a known video card on this machine\n"); + prom_halt (); + } } - prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers); - fbbase = (long) sbdp->reg_addrs [0].phys_addr; - fbiospace = sbdp->reg_addrs[0].which_io; - con_node = (*romvec->pv_v2devops.v2_inst2pkg) - (*romvec->pv_v2bootargs.fd_stdout); - /* - * Determine the type of hardware accelerator. - */ - propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name)); - if (propl < 0 || propl >= sizeof (con_name)) { - /* Early cg3s had no "emulation". */ - propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name)); - if (propl < 0) { - prom_printf("console: no device name!!\n"); + if (!cg14){ + prom_apply_sbus_ranges (&sbdp->reg_addrs [0], sbdp->num_registers); + fbbase = (long) sbdp->reg_addrs [0].phys_addr; + fbiospace = sbdp->reg_addrs[0].which_io; + con_node = (*romvec->pv_v2devops.v2_inst2pkg) + (*romvec->pv_v2bootargs.fd_stdout); + /* + * Determine the type of hardware accelerator. + */ + propl = prom_getproperty(con_node, "emulation", con_name, sizeof (con_name)); + if (propl < 0 || propl >= sizeof (con_name)) { + /* Early cg3s had no "emulation". */ + propl = prom_getproperty(con_node, "name", con_name, sizeof (con_name)); + if (propl < 0) { + prom_printf("console: no device name!!\n"); + return -1; + } + } + if(!strncmp(con_name, "cgsix", sizeof (con_name))) { + con_type = FBTYPE_SUNFAST_COLOR; + } else if(!strncmp(con_name, "cgthree", sizeof (con_name))) { + con_type = FBTYPE_SUN3COLOR; + } else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) { + con_type = FBTYPE_MDICOLOR; + } else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) { + con_type = FBTYPE_SUN2BW; + } else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){ + con_type = FBTYPE_SUN3COLOR; + } else { + prom_printf("console: \"%s\" is unsupported\n", con_name); return -1; } - } - if(!strncmp(con_name, "cgsix", sizeof (con_name))) { - con_type = FBTYPE_SUNFAST_COLOR; - } else if(!strncmp(con_name, "cgthree", sizeof (con_name))) { - con_type = FBTYPE_SUN3COLOR; - } else if(!strncmp(con_name, "cgfourteen", sizeof (con_name))) { - con_type = FBTYPE_MDICOLOR; - } else if(!strncmp(con_name, "bwtwo", sizeof (con_name))) { - con_type = FBTYPE_SUN2BW; - } else if(!strncmp(con_name,"SUNW,tcx", sizeof (con_name))){ - con_type = FBTYPE_SUN3COLOR; + propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4); + if (propl != 4) { + con_fb_base = 0; + } } else { - prom_printf("console: \"%s\" is unsupported\n", con_name); - return -1; - } - propl = prom_getproperty(con_node, "address", (char *) &con_fb_base, 4); - if (propl != 4) { - con_fb_base = 0; + int bases [2]; + + con_node = cg14; + prom_printf ("Found a cg14\n"); + propl = prom_getproperty (cg14, "address", + (char *) &bases[0], 8); + prom_printf ("Size=%d, %x\n", propl, bases [1]); + con_fb_base = (unsigned char *) bases [1]; + con_type = FBTYPE_MDICOLOR; } break; default: @@ -1409,6 +1454,9 @@ sparc_console_probe(void) case FBTYPE_SUN2BW: bwtwo_setup (0, fbbase, fbiospace); break; + case FBTYPE_MDICOLOR: + cg14_setup (0, fbbase, fbiospace); + break; default: break; } diff --git a/drivers/sbus/char/sunkbd.c b/drivers/sbus/char/sunkbd.c new file mode 100644 index 000000000000..890b45a8e66b --- /dev/null +++ b/drivers/sbus/char/sunkbd.c @@ -0,0 +1,1317 @@ +/* keyboard.c: Sun keyboard driver. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + * Added vuid event generation and /dev/kbd device for SunOS + * compatibility - Miguel (miguel@nuclecu.unam.mx) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../../char/kbd_kern.h" +#include "../../char/diacr.h" +#include "../../char/vt_kern.h" + +#define SIZE(x) (sizeof(x)/sizeof((x)[0])) + +/* Define this one if you are making a new frame buffer driver */ +/* it will not block the keyboard */ +/* #define CODING_NEW_DRIVER */ + +/* KBD device number, temporal */ +#define KBD_MAJOR 11 + +#define KBD_REPORT_ERR +#define KBD_REPORT_UNKN + +#ifndef KBD_DEFMODE +#define KBD_DEFMODE ((1 << VC_REPEAT) | (1 << VC_META)) +#endif + +#ifndef KBD_DEFLEDS +/* + * Some laptops take the 789uiojklm,. keys as number pad when NumLock + * is on. This seems a good reason to start with NumLock off. + */ +#define KBD_DEFLEDS 0 +#endif + +#ifndef KBD_DEFLOCK +#define KBD_DEFLOCK 0 +#endif + +extern void poke_blanked_console(void); +extern void ctrl_alt_del(void); +extern void reset_vc(unsigned int new_console); +extern void scrollback(int); +extern void scrollfront(int); + +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 is now a global variable) + */ + +/* shift state counters.. */ +static unsigned char k_down[NR_SHIFT] = {0, }; +/* keyboard key bitmap */ +#define BITS_PER_LONG (8*sizeof(unsigned long)) +static unsigned long key_down[256/BITS_PER_LONG] = { 0, }; + +void push_kbd (int scan); +int kbd_redirected = 0; + +static int dead_key_next = 0; +/* + * In order to retrieve the shift_state (for the mouse server), either + * the variable must be global, or a new procedure must be created to + * return the value. I chose the former way. + */ +/*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[MAX_NR_CONSOLES]; +static struct tty_struct **ttytab; +static struct kbd_struct * kbd = kbd_table; +static struct tty_struct * tty = NULL; + +extern void compute_shiftstate(void); + +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, do_ignore; + +static k_hand key_handler[16] = { + do_self, do_fn, do_spec, do_pad, do_dead, do_cons, do_cur, do_shift, + do_meta, do_ascii, do_lock, do_lowercase, + do_ignore, do_ignore, do_ignore, do_ignore +}; + +typedef void (*void_fnp)(void); +typedef void (void_fn)(void); + +static void_fn do_null, enter, show_ptregs, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, boot_it, caps_on, compose, + SAK, decr_console, incr_console, spawn_console, bare_num; + +static void_fnp spec_fn_table[] = { + do_null, enter, show_ptregs, show_mem, + show_state, send_intr, lastcons, caps_toggle, + num, hold, scroll_forw, scroll_back, + boot_it, caps_on, compose, SAK, + decr_console, incr_console, spawn_console, bare_num +}; + +/* maximum values each key_handler can handle */ +const int max_vals[] = { + 255, SIZE(func_table) - 1, SIZE(spec_fn_table) - 1, NR_PAD - 1, + NR_DEAD - 1, 255, 3, NR_SHIFT - 1, + 255, NR_ASCII - 1, NR_LOCK - 1, 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; + +volatile unsigned char sunkbd_layout; +volatile unsigned char sunkbd_type; +#define SUNKBD_TYPE2 0x02 +#define SUNKBD_TYPE3 0x03 +#define SUNKBD_TYPE4 0x04 + +#define SUNKBD_LOUT_TYP4 0x00 +#define SUNKBD_LOUT_TYP5 0x22 + +volatile int kbd_reset_pending; +volatile int kbd_layout_pending; + +/* commands */ +#define SKBDCMD_RESET 0x1 +#define SKBDCMD_GLAYOUT 0xf +#define SKBDCMD_BELLON 0x2 +#define SKBDCMD_BELLOFF 0x3 +#define SKBDCMD_SETLED 0xe +#define SKBDCMD_NOCLICK 0xb +#define SKBDCMD_CLICK 0xa + +static unsigned char sunkbd_clickp; + +/* The led set commands require sending the SETLED byte then + * a byte encoding which led's to have set. Here are the bit + * values, a bit set = led-on. + */ +#define LED_NLOCK 0x1 /* Num-lock */ +#define LED_CMPOSE 0x2 /* Compose */ +#define LED_SCRLCK 0x4 /* Scroll-lock */ +#define LED_CLOCK 0x8 /* Caps-lock */ + +/* Special state characters */ +#define SKBD_RESET 0xff +#define SKBD_ALLUP 0x7f +#define SKBD_LYOUT 0xfe + +/* On the Sparc the keyboard could be one of two things. + * It could be a real keyboard speaking over one of the + * channels of the second zs8530 chip (other channel is + * used by the Sun mouse). Else we have serial console + * going, and thus the other zs8530 chip is who we speak + * to. Either way, we communicate through the zs8530 + * driver for all our I/O. + */ + +#define SUNKBD_UBIT 0x80 /* If set, key went up */ +#define SUNKBD_KMASK 0x7f /* Other bits are the keycode */ + +#define KEY_LSHIFT 0x81 +#define KEY_RSHIFT 0x82 +#define KEY_CONTROL 0x83 +#define KEY_NILL 0x84 +#define KEY_CAPSLOCK 0x85 +#define KEY_ALT 0x86 +#define KEY_L1 0x87 + +extern void kbd_put_char(unsigned char ch); +static inline void send_cmd(unsigned char c) +{ + kbd_put_char(c); +} + +/* kbd_bh() calls this to send the SKBDCMD_SETLED to the sun keyboard + * with the proper bit pattern for the leds to be set. It basically + * converts the kbd->ledflagstate values to corresponding sun kbd led + * bit value. + */ +static inline unsigned char vcleds_to_sunkbd(unsigned char vcleds) +{ + unsigned char retval = 0; + + if(vcleds & (1< 255 || keycode > 127) + return -EINVAL; + if (scancode < 128) + high_keys[scancode - SC_LIM] = keycode; + else + e0_keys[scancode - 128] = keycode; + return 0; +} + +int getkeycode(unsigned int scancode) +{ + return + (scancode < SC_LIM || scancode > 255) ? -EINVAL : + (scancode < 128) ? high_keys[scancode - SC_LIM] : + e0_keys[scancode - 128]; +} + +void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs); +static void keyboard_timer (unsigned long ignored); + +static struct timer_list +auto_repeat_timer = { NULL, NULL, 0, 0, keyboard_timer }; + +/* Keeps track of the last pressed key */ +static unsigned char last_keycode; + +static void +keyboard_timer (unsigned long ignored) +{ + unsigned long flags; + + save_flags(flags); cli(); + + /* Auto repeat: send regs = 0 to indicate autorepeat */ + sunkbd_inchar (last_keycode, 0, 0); + del_timer (&auto_repeat_timer); + auto_repeat_timer.expires = jiffies + HZ/20; + add_timer (&auto_repeat_timer); + restore_flags(flags); +} + +/* #define SKBD_DEBUG */ +/* This is our keyboard 'interrupt' routine. */ +void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs) +{ + unsigned char keycode; + char up_flag; /* 0 or SUNKBD_UBIT */ + char raw_mode; + + if(ch == SKBD_RESET) { + kbd_reset_pending = 1; + return; + } + if(ch == SKBD_LYOUT) { + kbd_layout_pending = 1; + return; + } + if(kbd_reset_pending) { + sunkbd_type = ch; + kbd_reset_pending = 0; + if(ch == SUNKBD_TYPE4) + send_cmd(SKBDCMD_GLAYOUT); + return; + } else if(kbd_layout_pending) { + sunkbd_layout = ch; + kbd_layout_pending = 0; + return; + } else if(ch == SKBD_ALLUP) { + /* eat it */ + return; + } +#ifdef SKBD_DEBUG + if(ch == 0x7f) + printk("KBD"); + else + printk("KBD<%x %s>", ch, + ((ch&0x80) ? "UP" : "DOWN")); +#endif + + /* Whee, a real character. */ + if (regs){ + pt_regs = regs; + last_keycode = keycode = ch; + } else + keycode = ch; + + mark_bh(KEYBOARD_BH); + do_poke_blanked_console = 1; + mark_bh(CONSOLE_BH); + kbd = kbd_table + fg_console; + tty = ttytab[fg_console]; + if((raw_mode = (kbd->kbdmode == VC_RAW))) { + if (kbd_redirected == fg_console+1) + push_kbd (keycode); + else + put_queue(keycode); + /* 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. + */ + } + up_flag = (keycode & SUNKBD_UBIT); /* The 'up' bit */ + keycode &= SUNKBD_KMASK; /* all the rest */ + del_timer (&auto_repeat_timer); + if(up_flag) { + rep = 0; + clear_bit(keycode, key_down); + } else { + auto_repeat_timer.expires = jiffies+HZ/5; + add_timer (&auto_repeat_timer); + rep = set_bit(keycode, key_down); + } + + if(raw_mode) + return; + + if(kbd->kbdmode == VC_MEDIUMRAW) { + put_queue(keycode + up_flag); + return; + } + + /* + * Small change in philosophy: earlier we defined repetition by + * rep = keycode == prev_keycode; + * prev_keycode = keycode; + * but now by the fact that the depressed key was down already. + * Does this ever make a difference? Yes. + */ + + /* + * 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) || (tty->driver.chars_in_buffer(tty) == 0)))) { + u_short keysym; + u_char type; + + /* the XOR below used to be an OR */ + int shift_final = shift_state ^ kbd->lockstate; + ushort *key_map = key_maps[shift_final]; + + if (key_map != NULL) { + keysym = key_map[keycode]; + type = KTYP(keysym); + + if (type >= 0xf0) { + type -= 0xf0; + if (type == KT_LETTER) { + type = KT_LATIN; + if (vc_kbd_led(kbd, VC_CAPSLOCK)) { + key_map = key_maps[shift_final ^ (1<slockstate = 0; + } + } else { + /* maybe beep? */ + /* we have at least to update shift_state */ + compute_shiftstate(); + } + } +} + +static void put_queue(int ch) +{ + wake_up(&keypress_wait); + if (tty) { + tty_insert_flip_char(tty, ch, 0); + tty_schedule_flip(tty); + } +} + +static void puts_queue(char *cp) +{ + wake_up(&keypress_wait); + if (!tty) + return; + + while (*cp) { + tty_insert_flip_char(tty, *cp, 0); + cp++; + } + tty_schedule_flip(tty); +} + +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) + show_regs(pt_regs); +} + +static void hold(void) +{ + if (rep || !tty) + return; + + /* + * Note: SCROLLOCK will 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 KDSKBLED.) + */ + if (tty->stopped) + start_tty(tty); + else + stop_tty(tty); +} + +static void num(void) +{ + if (vc_kbd_mode(kbd,VC_APPLIC)) + applkey('P', 1); + else + bare_num(); +} + +/* + * Bind this to Shift-NumLock if you work in application keypad mode + * but want to be able to change the NumLock flag. + * Bind this to NumLock if you prefer that the NumLock key always + * changes the NumLock flag. + */ +static void bare_num(void) +{ + if (!rep) + chg_vc_kbd_led(kbd,VC_NUMLOCK); +} + +static void lastcons(void) +{ + /* switch to the last used console, ChN */ + set_console(last_console); +} + +static void decr_console(void) +{ + int i; + + for (i = fg_console-1; i != fg_console; i--) { + if (i == -1) + i = MAX_NR_CONSOLES-1; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void incr_console(void) +{ + int i; + + for (i = fg_console+1; i != fg_console; i++) { + if (i == MAX_NR_CONSOLES) + i = 0; + if (vc_cons_allocated(i)) + break; + } + set_console(i); +} + +static void send_intr(void) +{ + if (!tty) + return; + tty_insert_flip_char(tty, 0, TTY_BREAK); + tty_schedule_flip(tty); +} + +static void scroll_forw(void) +{ + scrollfront(0); +} + +static void scroll_back(void) +{ + scrollback(0); +} + +static void boot_it(void) +{ + extern int obp_system_intr(void); + + if (!obp_system_intr()) + ctrl_alt_del(); + /* sigh.. atempt to prevent multiple entry */ + last_keycode=1; + rep = 0; +} + +static void compose(void) +{ + dead_key_next = 1; +} + +int spawnpid, spawnsig; + +static void spawn_console(void) +{ + if (spawnpid) + if(kill_proc(spawnpid, spawnsig, 1)) + spawnpid = 0; +} + +static void SAK(void) +{ + do_SAK(tty); +#if 0 + /* + * Need to fix SAK handling to fix up RAW/MEDIUM_RAW and + * vt_cons modes before we can enable RAW/MEDIUM_RAW SAK + * handling. + * + * We should do this some day --- the whole point of a secure + * attention key is that it should be guaranteed to always + * work. + */ + reset_vc(fg_console); + do_unblank_screen(); /* not in interrupt routine? */ +#endif +} + +static void do_ignore(unsigned char value, char up_flag) +{ +} + +static void do_null() +{ + compute_shiftstate(); +} + +static void do_spec(unsigned char value, char up_flag) +{ + if (up_flag) + return; + if (value >= SIZE(spec_fn_table)) + return; + spec_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)) { + if (func_table[value]) + 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 const char *pad_chars = "0123456789+-*/\015,.?"; + static const 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 const 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; + + /* Mimic typewriter: + a CapsShift key acts like Shift but undoes CapsLock */ + if (value == KVAL(K_CAPSSHIFT)) { + value = KVAL(K_SHIFT); + if (!up_flag) + 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, no joke... */ + if (up_flag && shift_state != old_state && npadch != -1) { + put_queue(npadch & 0xff); + npadch = -1; + } +} + +/* called after returning from RAW mode or when changing consoles - + recompute k_down[] and shift_state from key_down[] */ +/* maybe called when keymap is undefined, so that shiftkey release is seen */ +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*BITS_PER_LONG; + for(j=0; jledmode = LED_SHOW_IOCTL; + } else + kbd->ledmode = LED_SHOW_FLAGS; + set_leds(); +} + +static struct ledptr { + unsigned int *addr; + unsigned int mask; + unsigned char valid:1; +} ledptrs[3]; + +void register_leds(int console, unsigned int led, + unsigned int *addr, unsigned int mask) { + struct kbd_struct *kbd = kbd_table + console; + if (led < 3) { + ledptrs[led].addr = addr; + ledptrs[led].mask = mask; + ledptrs[led].valid = 1; + kbd->ledmode = LED_SHOW_MEM; + } else + kbd->ledmode = LED_SHOW_FLAGS; +} + +static inline unsigned char getleds(void){ + struct kbd_struct *kbd = kbd_table + fg_console; + unsigned char leds; + + if (kbd->ledmode == LED_SHOW_IOCTL) + return ledioctl; + leds = kbd->ledflagstate; + if (kbd->ledmode == LED_SHOW_MEM) { + if (ledptrs[0].valid) { + if (*ledptrs[0].addr & ledptrs[0].mask) + leds |= 1; + else + leds &= ~1; + } + if (ledptrs[1].valid) { + if (*ledptrs[1].addr & ledptrs[1].mask) + leds |= 2; + else + leds &= ~2; + } + if (ledptrs[2].valid) { + if (*ledptrs[2].addr & ledptrs[2].mask) + leds |= 4; + else + leds &= ~4; + } + } + return leds; +} + +/* + * 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) +{ + unsigned char leds = getleds(); + + if (leds != ledstate) { + ledstate = leds; + send_cmd(SKBDCMD_SETLED); + send_cmd(vcleds_to_sunkbd(leds)); + } +} + +int kbd_init(void) +{ + int i, opt_node; + struct kbd_struct kbd0; + extern struct tty_driver console_driver; + + kbd0.ledflagstate = kbd0.default_ledflagstate = KBD_DEFLEDS; + kbd0.ledmode = LED_SHOW_FLAGS; + kbd0.lockstate = KBD_DEFLOCK; + kbd0.modeflags = KBD_DEFMODE; + kbd0.kbdmode = VC_XLATE; + + for (i = 0 ; i < MAX_NR_CONSOLES ; i++) + kbd_table[i] = kbd0; + + ttytab = console_driver.table; + + /* XXX Check keyboard-click? property in 'options' PROM node XXX */ + if(sparc_cpu_model != sun4) { + opt_node = prom_getchild(prom_root_node); + opt_node = prom_searchsiblings(opt_node, "options"); + i = prom_getintdefault(opt_node, "keyboard-click?", -1); + if(i != -1) + sunkbd_clickp = 1; + else + sunkbd_clickp = 0; + } else { + sunkbd_clickp = 0; + } + init_bh(KEYBOARD_BH, kbd_bh); + mark_bh(KEYBOARD_BH); + return 0; +} + +/* /dev/kbd support */ + +#define KBD_QSIZE 32 +static Firm_event kbd_queue [KBD_QSIZE]; +static int kbd_head, kbd_tail; +char kbd_opened; +static struct wait_queue *kbd_wait; +static struct fasync_struct *kb_fasync; + +void +push_kbd (int scan) +{ + int next = (kbd_head + 1) % KBD_QSIZE; + + if (scan == KBD_IDLE) + return; + if (next != kbd_tail){ + kbd_queue [kbd_head].id = scan & KBD_KEYMASK; + kbd_queue [kbd_head].value=scan & KBD_UP ? VKEY_UP : VKEY_DOWN; + kbd_queue [kbd_head].time = xtime; + kbd_head = next; + } + if (kb_fasync) + kill_fasync (kb_fasync, SIGIO); + wake_up_interruptible (&kbd_wait); +} + +static int +kbd_read (struct inode *inode, struct file *f, char *buffer, int count) +{ + struct wait_queue wait = { current, NULL }; + char *end, *p; + + /* Return EWOULDBLOCK, because this is what the X server expects */ + if (kbd_head == kbd_tail){ + if (f->f_flags & O_NONBLOCK) + return -EWOULDBLOCK; + add_wait_queue (&kbd_wait, &wait); + while (kbd_head == kbd_tail && !(current->signal & ~current->blocked)){ + current->state = TASK_INTERRUPTIBLE; + schedule (); + } + current->state = TASK_RUNNING; + remove_wait_queue (&kbd_wait, &wait); + } + /* There is data in the keyboard, fill the user buffer */ + end = buffer+count; + p = buffer; + for (; p < end && kbd_head != kbd_tail; p += sizeof (Firm_event)){ + *(Firm_event *)p = kbd_queue [kbd_tail]; +#ifdef KBD_DEBUG + printk ("[%s]", kbd_queue [kbd_tail].value == VKEY_UP ? "UP" : "DOWN"); +#endif + kbd_tail++; + kbd_tail %= KBD_QSIZE; + } + return p-buffer; +} + +/* Needed by X */ +static int +kbd_fasync (struct inode *inode, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper (inode, filp, on, &kb_fasync); + if (retval < 0) + return retval; + return 0; +} + +static int +kbd_select (struct inode *i, struct file *f, int sel_type, select_table *wait) +{ + if (sel_type != SEL_IN) + return 0; + if (kbd_head != kbd_tail) + return 1; + select_wait (&kbd_wait, wait); + return 0; +} + +static int +kbd_ioctl (struct inode *i, struct file *f, unsigned int cmd, unsigned long arg) +{ + switch (cmd){ + case KIOCTYPE: /* return keyboard type */ + if (verify_area (VERIFY_WRITE, (void *)arg, sizeof (int))) + return -EFAULT; + *(int *) arg = sunkbd_type; + break; + case KIOCGTRANS: + if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) + return -EFAULT; + *(int *) arg = TR_UNTRANS_EVENT; + break; + case KIOCTRANS: + if (verify_area (VERIFY_READ, (void *) arg, sizeof (int))) + return -EFAULT; + if (*(int *) arg != TR_UNTRANS_EVENT) + return -EINVAL; + break; + case KIOCLAYOUT: + if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) + return -EFAULT; + *(int *) arg = sunkbd_layout; + break; + case KIOCSDIRECT: + if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) + return -EFAULT; +#ifndef CODING_NEW_DRIVER + if (*(int *) arg) + kbd_redirected = fg_console + 1; + else + kbd_redirected = 0; + kbd_table [fg_console].kbdmode = kbd_redirected ? VC_RAW : VC_XLATE; +#endif + break; + case KIOCCMD: + /* Need to support beep on/off, keyclick on/off */ + return 0; + case FIONREAD: /* return number of bytes in kbd queue */ + { + int count; + + if (verify_area (VERIFY_WRITE, (void *) arg, sizeof (int))) + return -EFAULT; + count = kbd_head - kbd_tail; + * (int *)arg = (count < 0) ? KBD_QSIZE - count : count; + return 0; + } + default: + printk ("Unknown Keyboard ioctl: %8.8x\n", cmd); + return -EINVAL; + } + return 0; +} + +static int +kbd_open (struct inode *i, struct file *f) +{ + if (kbd_opened) + return 0; + kbd_opened = fg_console + 1; + kbd_head = kbd_tail = 0; + return 0; +} + +static void +kbd_close (struct inode *i, struct file *f) +{ + if (kbd_redirected) + kbd_table [kbd_opened-1].kbdmode = VC_XLATE; + kbd_redirected = 0; + kbd_opened = 0; + + kbd_fasync (i, f, 0); +} + +static struct +file_operations kbd_fops = +{ + NULL, /* seek */ + kbd_read, /* read */ + NULL, /* write */ + NULL, /* readdir */ + kbd_select, /* select */ + kbd_ioctl, /* ioctl */ + NULL, /* mmap */ + kbd_open, /* open */ + kbd_close, /* close */ + NULL, /* fsync */ + kbd_fasync, /* fasync */ + NULL, /* check_media_change */ + NULL, /* revalidate */ +}; + +void +keyboard_zsinit(void) +{ + int timeout = 0; + + /* Test out the leds */ + sunkbd_type = 255; + send_cmd(SKBDCMD_RESET); + while((sunkbd_type==255) && timeout < 500000) { + udelay(100); + timeout += 20; + } + + if(timeout>=500000) { + printk("keyboard: not present\n"); + return; + } + + if(sunkbd_type != SUNKBD_TYPE4) { + printk("Sun TYPE %d keyboard detected ", sunkbd_type); + } else { + udelay(200); + timeout=0; + while(timeout++ < 500000) + barrier(); + printk("Sun TYPE %d keyboard detected ", + ((sunkbd_layout==SUNKBD_LOUT_TYP5) ? 5 : 4)); + } + if(sunkbd_type == SUNKBD_TYPE2) + sunkbd_clickp = 0; + + if(sunkbd_clickp) + printk("with keyclick\n"); + else + printk("without keyclick\n"); + + /* Dork with led lights, then turn them all off */ + send_cmd(SKBDCMD_SETLED); send_cmd(0xf); /* All on */ + send_cmd(SKBDCMD_SETLED); send_cmd(0x0); /* All off */ + + /* Register the /dev/kbd interface */ + if (register_chrdev (KBD_MAJOR, "kbd", &kbd_fops)){ + printk ("Could not register /dev/kbd device\n"); + return; + } + return; +} diff --git a/drivers/sbus/char/sunkeymap.c b/drivers/sbus/char/sunkeymap.c new file mode 100644 index 000000000000..17b2f5789914 --- /dev/null +++ b/drivers/sbus/char/sunkeymap.c @@ -0,0 +1,262 @@ +/* Do not edit this file! It was automatically generated by */ +/* loadkeys --mktable defkeymap.map > defkeymap.c */ + +#include +#include +#include + +u_short plain_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109, + 0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf105, 0xf200, + 0xf106, 0xf107, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209, + 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf031, 0xf032, + 0xf033, 0xf034, 0xf035, 0xf036, 0xf037, 0xf038, 0xf039, 0xf030, + 0xf02d, 0xf03d, 0xf060, 0xf07f, 0xf115, 0xf03d, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf009, 0xfb71, 0xfb77, + 0xfb65, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, + 0xf05b, 0xf05d, 0xf07f, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xfb61, 0xfb73, 0xfb64, + 0xfb66, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf03b, 0xf027, + 0xf05c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200, + 0xf118, 0xf200, 0xf208, 0xf700, 0xfb7a, 0xfb78, 0xfb63, 0xfb76, + 0xfb62, 0xfb6e, 0xfb6d, 0xf02c, 0xf02e, 0xf02f, 0xf700, 0xf00a, + 0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf020, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +u_short shift_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf10a, 0xf10b, 0xf113, + 0xf10c, 0xf10a, 0xf10d, 0xf10b, 0xf10e, 0xf701, 0xf105, 0xf200, + 0xf110, 0xf107, 0xf112, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf203, + 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf01b, 0xf021, 0xf040, + 0xf023, 0xf024, 0xf025, 0xf05e, 0xf026, 0xf02a, 0xf028, 0xf029, + 0xf05f, 0xf02b, 0xf07e, 0xf07f, 0xf115, 0xf200, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf009, 0xfb51, 0xfb57, + 0xfb45, 0xfb52, 0xfb54, 0xfb59, 0xfb55, 0xfb49, 0xfb4f, 0xfb50, + 0xf07b, 0xf07d, 0xf07f, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xfb41, 0xfb53, 0xfb44, + 0xfb46, 0xfb47, 0xfb48, 0xfb4a, 0xfb4b, 0xfb4c, 0xf03a, 0xf022, + 0xf07c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200, + 0xf20b, 0xf200, 0xf208, 0xf700, 0xfb5a, 0xfb58, 0xfb43, 0xfb56, + 0xfb42, 0xfb4e, 0xfb4d, 0xf03c, 0xf03e, 0xf03f, 0xf700, 0xf200, + 0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf020, 0xf200, 0xf20a, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +u_short altgr_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf50c, 0xf50d, 0xf515, + 0xf50e, 0xf516, 0xf50f, 0xf517, 0xf510, 0xf701, 0xf200, 0xf200, + 0xf512, 0xf513, 0xf514, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf202, + 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf040, + 0xf200, 0xf024, 0xf200, 0xf200, 0xf07b, 0xf05b, 0xf05d, 0xf07d, + 0xf05c, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xfb71, 0xfb77, + 0xf918, 0xfb72, 0xfb74, 0xfb79, 0xfb75, 0xfb69, 0xfb6f, 0xfb70, + 0xf200, 0xf07e, 0xf200, 0xf20e, 0xf911, 0xf912, 0xf913, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf914, 0xfb73, 0xf917, + 0xf919, 0xfb67, 0xfb68, 0xfb6a, 0xfb6b, 0xfb6c, 0xf200, 0xf200, + 0xf200, 0xf201, 0xf30e, 0xf90e, 0xf90f, 0xf910, 0xf90a, 0xf200, + 0xf118, 0xf200, 0xf208, 0xf700, 0xfb7a, 0xfb78, 0xf916, 0xfb76, + 0xf915, 0xfb6e, 0xfb6d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, + 0xf90b, 0xf90c, 0xf90d, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +u_short ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf100, 0xf101, 0xf109, + 0xf102, 0xf10a, 0xf103, 0xf10b, 0xf104, 0xf701, 0xf200, 0xf200, + 0xf107, 0xf200, 0xf108, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf204, + 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000, + 0xf01b, 0xf01c, 0xf01d, 0xf01e, 0xf01f, 0xf07f, 0xf200, 0xf200, + 0xf01f, 0xf200, 0xf000, 0xf008, 0xf115, 0xf200, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xf011, 0xf017, + 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, + 0xf01b, 0xf01d, 0xf008, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf001, 0xf013, 0xf004, + 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf007, + 0xf01c, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200, + 0xf118, 0xf200, 0xf208, 0xf700, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf20e, 0xf07f, 0xf700, 0xf200, + 0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf000, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +u_short shift_ctrl_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf701, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200, + 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf000, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf01f, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf200, 0xf011, 0xf017, + 0xf005, 0xf012, 0xf014, 0xf019, 0xf015, 0xf009, 0xf00f, 0xf010, + 0xf200, 0xf200, 0xf200, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf001, 0xf013, 0xf004, + 0xf006, 0xf007, 0xf008, 0xf00a, 0xf00b, 0xf00c, 0xf200, 0xf200, + 0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200, + 0xf118, 0xf200, 0xf208, 0xf700, 0xf01a, 0xf018, 0xf003, 0xf016, + 0xf002, 0xf00e, 0xf00d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, + 0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +u_short alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf509, + 0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf505, 0xf200, + 0xf507, 0xf200, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf209, + 0xf210, 0xf200, 0xf200, 0xf600, 0xf211, 0xf81b, 0xf831, 0xf832, + 0xf833, 0xf834, 0xf835, 0xf836, 0xf837, 0xf838, 0xf839, 0xf830, + 0xf82d, 0xf83d, 0xf860, 0xf87f, 0xf115, 0xf200, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf310, 0xf200, 0xf114, 0xf809, 0xf871, 0xf877, + 0xf865, 0xf872, 0xf874, 0xf879, 0xf875, 0xf869, 0xf86f, 0xf870, + 0xf85b, 0xf85d, 0xf200, 0xf87f, 0xf907, 0xf908, 0xf909, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf861, 0xf873, 0xf864, + 0xf866, 0xf867, 0xf868, 0xf86a, 0xf86b, 0xf86c, 0xf83b, 0xf827, + 0xf85c, 0xf80d, 0xf30e, 0xf904, 0xf905, 0xf906, 0xf900, 0xf200, + 0xf118, 0xf200, 0xf208, 0xf700, 0xf87a, 0xf878, 0xf863, 0xf876, + 0xf862, 0xf86e, 0xf86d, 0xf82c, 0xf82e, 0xf82f, 0xf700, 0xf200, + 0xf901, 0xf902, 0xf903, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf820, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +u_short ctrl_alt_map[NR_KEYS] = { + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf500, 0xf501, 0xf509, + 0xf502, 0xf50a, 0xf503, 0xf50b, 0xf504, 0xf701, 0xf200, 0xf200, + 0xf507, 0xf200, 0xf508, 0xf703, 0xf603, 0xf11d, 0xf200, 0xf200, + 0xf601, 0xf200, 0xf200, 0xf600, 0xf602, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, 0xf200, + 0xf200, 0xf200, 0xf200, 0xf200, 0xf115, 0xf200, 0xf30d, 0xf30c, + 0xf200, 0xf200, 0xf20c, 0xf200, 0xf114, 0xf200, 0xf811, 0xf817, + 0xf805, 0xf812, 0xf814, 0xf819, 0xf815, 0xf809, 0xf80f, 0xf810, + 0xf200, 0xf200, 0xf200, 0xf20e, 0xf307, 0xf308, 0xf309, 0xf30b, + 0xf200, 0xf200, 0xf117, 0xf200, 0xf702, 0xf801, 0xf813, 0xf804, + 0xf806, 0xf807, 0xf808, 0xf80a, 0xf80b, 0xf80c, 0xf200, 0xf200, + 0xf200, 0xf201, 0xf30e, 0xf304, 0xf305, 0xf306, 0xf300, 0xf200, + 0xf118, 0xf200, 0xf208, 0xf700, 0xf81a, 0xf818, 0xf803, 0xf816, + 0xf802, 0xf80e, 0xf80d, 0xf200, 0xf200, 0xf200, 0xf700, 0xf200, + 0xf301, 0xf302, 0xf303, 0xf200, 0xf200, 0xf200, 0xf11b, 0xf207, + 0xf200, 0xf200, 0xf200, 0xf119, 0xf200, 0xf30a, 0xf200, 0xf200, +}; + +ushort *key_maps[MAX_NR_KEYMAPS] = { + plain_map, shift_map, altgr_map, 0, + ctrl_map, shift_ctrl_map, 0, 0, + alt_map, 0, 0, 0, + ctrl_alt_map, 0 +}; + +unsigned int keymap_count = 7; + +/* + * Philosophy: most people do not define more strings, but they who do + * often want quite a lot of string space. So, we statically allocate + * the default and allocate dynamically in chunks of 512 bytes. + */ + +char func_buf[] = { + '\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, + '\033', '[', 'P', 0, +}; + +char *funcbufptr = func_buf; +int funcbufsize = sizeof(func_buf); +int funcbufleft = 0; /* space left */ + +char *func_table[MAX_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, + 0, + 0, + func_buf + 149, + 0, +}; + +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/drivers/sbus/char/sunkeymap.map b/drivers/sbus/char/sunkeymap.map new file mode 100644 index 000000000000..3b03ef50c966 --- /dev/null +++ b/drivers/sbus/char/sunkeymap.map @@ -0,0 +1,372 @@ +# Keyboard map for the Sun Type4/Type5 keyboards +# found on SparcStations +keymaps 0-2,4-5,8,12 +# +# +# Stop/L1 +keycode 0x01 = +# SND_LOWER +keycode 0x02 = +# Again/L2 +keycode 0x03 = +# SND_LOUDER +keycode 0x04 = +keycode 0x05 = F1 F11 Console_13 + control keycode 0x05 = F1 + alt keycode 0x05 = Console_1 + control alt keycode 0x05 = Console_1 +keycode 0x06 = F2 F12 Console_14 + control keycode 0x06 = F2 + alt keycode 0x06 = Console_2 + control alt keycode 0x06 = Console_2 +keycode 0x07 = F10 F20 Console_22 + control keycode 0x07 = F10 + alt keycode 0x07 = Console_10 + control alt keycode 0x07 = Console_10 +keycode 0x08 = F3 F13 Console_15 + control keycode 0x08 = F3 + alt keycode 0x08 = Console_3 + control alt keycode 0x08 = Console_3 +keycode 0x09 = F11 F11 Console_23 + control keycode 0x09 = F11 + alt keycode 0x09 = Console_11 + control alt keycode 0x09 = Console_11 +keycode 0x0a = F4 F14 Console_16 + control keycode 0x0a = F4 + alt keycode 0x0a = Console_4 + control alt keycode 0x0a = Console_4 +keycode 0x0b = F12 F12 Console_24 + control keycode 0x0b = F12 + alt keycode 0x0b = Console_12 + control alt keycode 0x0b = Console_12 +keycode 0x0c = F5 F15 Console_17 + control Keycode 0x0c = F5 + alt keycode 0x0c = Console_5 + control alt keycode 0x0c = Console_5 +keycode 0x0d = AltGr +keycode 0x0e = F6 F6 + alt keycode 0x0e = Console_6 +# BLANK KEY on type 5 keyboards +keycode 0x0f = +keycode 0x10 = F7 F17 Console_19 + control Keycode 0x10 = F7 + alt keycode 0x10 = Console_7 + control alt keycode 0x10 = Console_7 +keycode 0x11 = F8 F8 Console_20 + control keycode 0x10 = F8 + alt keycode 0x10 = Console_8 + control alt keycode 0x10 = Console_8 +keycode 0x12 = F9 F19 Console_21 + control keycode 0x12 = F9 + alt keycode 0x12 = Console_9 + control alt keycode 0x12 = Console_9 +keycode 0x13 = Alt +keycode 0x14 = Up +keycode 0x15 = Pause +# Print Screen +keycode 0x16 = +keycode 0x17 = Scroll_Lock Show_Memory Show_Registers + control keycode 0x17 = Show_State + alt keycode 0x17 = Scroll_Lock +keycode 0x18 = Left + alt keycode 0x18 = Decr_Console +# Props/L3 +keycode 0x19 = +# UNDO/L4 +keycode 0x1a = +keycode 0x1b = Down +keycode 0x1c = Right + alt keycode 0x1c = Incr_Console +keycode 0x1d = Escape Escape + alt keycode 0x1d = Meta_Escape +keycode 0x1e = one exclam + alt keycode 0x1e = Meta_one +keycode 0x1f = two at at + control keycode 0x1f = nul + shift control keycode 0x1f = nul + alt keycode 0x1f = Meta_two +keycode 0x20 = three numbersign + control keycode 0x20 = Escape + alt keycode 0x20 = Meta_three +keycode 0x21 = four dollar dollar + control keycode 0x21 = Control_backslash + alt keycode 0x21 = Meta_four +keycode 0x22 = five percent + control keycode 0x22 = Control_bracketright + alt keycode 0x22 = Meta_five +keycode 0x23 = six asciicircum + control keycode 0x23 = Control_asciicircum + alt keycode 0x23 = Meta_six +keycode 0x24 = seven ampersand braceleft + control keycode 0x24 = Control_underscore + alt keycode 0x24 = Meta_seven +keycode 0x25 = eight asterisk bracketleft + control keycode 0x25 = Delete + alt keycode 0x25 = Meta_eight +keycode 0x26 = nine parenleft bracketright + alt keycode 0x26 = Meta_nine +keycode 0x27 = zero parenright braceright + alt keycode 0x27 = Meta_zero +keycode 0x28 = minus underscore backslash + control keycode 0x28 = Control_underscore + shift control keycode 0x28 = Control_underscore + alt keycode 0x28 = Meta_minus +keycode 0x29 = equal plus + alt keycode 0x29 = Meta_equal +keycode 0x2a = grave asciitilde + control keycode 0x2a = nul + alt keycode 0x2a = Meta_grave +# Is marked as BackSpace but we define it as delete just like the i386 +# keyboard maps does +keycode 0x2b = Delete Delete + control keycode 0x2b = BackSpace + alt keycode 0x2b = Meta_Delete +keycode 0x2c = Insert +# This is really keypad = on type 4 keyboards +keycode 0x2d = equal +keycode 0x2e = KP_Divide +keycode 0x2f = KP_Multiply +# Power ON/OFF key on type 5 keyboard +keycode 0x30 = +# FRONT/L5 +keycode 0x31 = +keycode 0x32 = KP_Period +# altgr control keycode 0x32 = Boot + control alt keycode 0x32 = Boot +# COPY/L6 +keycode 0x33 = +# Home key, same difference +keycode 0x34 = Find +keycode 0x35 = Tab Tab + alt keycode 0x35 = Meta_Tab +keycode 0x36 = q +keycode 0x37 = w +keycode 0x38 = e + altgr keycode 0x38 = Hex_E +keycode 0x39 = r +keycode 0x3a = t +keycode 0x3b = y +keycode 0x3c = u +keycode 0x3d = i +keycode 0x3e = o +keycode 0x3f = p +keycode 0x40 = bracketleft braceleft + control keycode 0x40 = Escape + alt keycode 0x40 = Meta_bracketleft +keycode 0x41 = bracketright braceright asciitilde + control keycode 0x41 = Control_bracketright + alt keycode 0x41 = Meta_bracketright +keycode 0x42 = Delete Delete + control keycode 0x42 = BackSpace + alt keycode 0x43 = Meta_Delete +keycode 0x43 = Compose +keycode 0x44 = KP_7 + alt keycode 0x44 = Ascii_7 + altgr keycode 0x44 = Hex_7 +keycode 0x45 = KP_8 + alt keycode 0x45 = Ascii_8 + altgr keycode 0x45 = Hex_8 +keycode 0x46 = KP_9 + alt keycode 0x46 = Ascii_9 + altgr keycode 0x46 = Hex_9 +keycode 0x47 = KP_Subtract +# OPEN/L6 +keycode 0x48 = +# PASTE/L8 +keycode 0x49 = +keycode 0x4a = Select +# No key produces 0x4b to my knowledge +keycode 0x4b = +keycode 0x4c = Control +keycode 0x4d = a + altgr keycode 0x4d = Hex_A +keycode 0x4e = s +keycode 0x4f = d + altgr keycode 0x4f = Hex_D +keycode 0x50 = f + altgr keycode 0x50 = Hex_F +keycode 0x51 = g +keycode 0x52 = h +keycode 0x53 = j +keycode 0x54 = k +keycode 0x55 = l +keycode 0x56 = semicolon colon + alt keycode 0x56 = Meta_semicolon +keycode 0x57 = apostrophe quotedbl + control keycode 0x57 = Control_g + alt keycode 0x57 = Meta_apostrophe +keycode 0x58 = backslash bar + control keycode 0x58 = Control_backslash + alt keycode 0x58 = Meta_backslash +keycode 0x59 = Return + alt keycode 0x59 = Meta_Control_m +keycode 0x5a = KP_Enter +keycode 0x5b = KP_4 + alt keycode 0x5b = Ascii_4 + altgr keycode 0x5b = Hex_4 +keycode 0x5c = KP_5 + alt keycode 0x5c = Ascii_5 + altgr keycode 0x5c = Hex_5 +keycode 0x5d = KP_6 + alt keycode 0x5d = Ascii_6 + altgr keycode 0x5d = Hex_6 +keycode 0x5e = KP_0 + alt keycode 0x5e = Ascii_0 + altgr keycode 0x5e = Hex_0 +# FIND/L9 +keycode 0x5f = +keycode 0x60 = Prior + shift keycode 0x60 = Scroll_Backward +# CUT/L10 +keycode 0x61 = +keycode 0x62 = Num_Lock +# Linux/i386 console makes no distinction between right/left shift +# so neither do we. +keycode 0x63 = Shift +keycode 0x64 = z +keycode 0x65 = x +keycode 0x66 = c + altgr keycode 0x66 = Hex_C +keycode 0x67 = v +keycode 0x68 = b + altgr keycode 0x68 = Hex_B +keycode 0x69 = n +keycode 0x6a = m +keycode 0x6b = comma less + alt keycode 0x6b = Meta_comma +keycode 0x6c = period greater + control keycode 0x6c = Compose + alt keycode 0x6c = Meta_period +keycode 0x6d = slash question + control keycode 0x6d = Delete + alt keycode 0x6d = Meta_slash +keycode 0x6e = Shift +keycode 0x6f = Linefeed +keycode 0x70 = KP_1 + alt keycode 0x70 = Ascii_1 + altgr keycode 0x70 = Hex_1 +keycode 0x71 = KP_2 + alt keycode 0x71 = Ascii_2 + altgr keycode 0x71 = Hex_2 +keycode 0x72 = KP_3 + alt keycode 0x72 = Ascii_3 + altgr keycode 0x72 = Hex_3 +# To my knowledge no key produces 0x73, 0x74, or 0x75 +keycode 0x73 = +keycode 0x74 = +keycode 0x75 = +keycode 0x76 = Help +keycode 0x77 = Caps_Lock +# A True Meta-key, unused at this time +keycode 0x78 = +keycode 0x79 = space space + control keycode 0x79 = nul + alt keycode 0x79 = Meta_space +# Another real Meta-key, again unused +keycode 0x7a = +keycode 0x7b = Next + shift keycode 0x7b = Scroll_Forward +# No keys produce the following +keycode 0x7c = +keycode 0x7d = KP_Add +keycode 0x7e = +# keycode 0x7f is special and it means 'all keys released' and is +# taken care of within the sun keyboard driver itself +keycode 0x7f = +# Thats all folks... +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 Macro = "\033[M" +string Pause = "\033[P" +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/drivers/char/sunmouse.c b/drivers/sbus/char/sunmouse.c similarity index 100% rename from drivers/char/sunmouse.c rename to drivers/sbus/char/sunmouse.c diff --git a/drivers/sbus/char/sunserial.c b/drivers/sbus/char/sunserial.c new file mode 100644 index 000000000000..6f5d9fc3948d --- /dev/null +++ b/drivers/sbus/char/sunserial.c @@ -0,0 +1,2196 @@ +/* serial.c: Serial port driver for the Sparc. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "sunserial.h" + +#define NUM_SERIAL 2 /* Two chips on board. */ +#define NUM_CHANNELS (NUM_SERIAL * 2) + +#define KEYBOARD_LINE 0x2 +#define MOUSE_LINE 0x3 + +struct sun_zslayout *zs_chips[NUM_SERIAL] = { 0, 0, }; +struct sun_zschannel *zs_channels[NUM_CHANNELS] = { 0, 0, 0, 0, }; +struct sun_zschannel *zs_conschan; +struct sun_zschannel *zs_mousechan; +struct sun_zschannel *zs_kbdchan; +struct sun_zschannel *zs_kgdbchan; +int zs_nodes[NUM_SERIAL] = { 0, 0, }; + +struct sun_serial zs_soft[NUM_CHANNELS]; +struct sun_serial *zs_chain; /* IRQ servicing chain */ +int zilog_irq; + +struct tty_struct zs_ttys[NUM_CHANNELS]; +/** struct tty_struct *zs_constty; **/ + +/* Console hooks... */ +static int zs_cons_chanout = 0; +static int zs_cons_chanin = 0; +static struct l1a_kbd_state l1a_state = { 0, 0 }; +struct sun_serial *zs_consinfo = 0; + +/* Keyboard defines for L1-A processing... */ +#define SUNKBD_RESET 0xff +#define SUNKBD_L1 0x01 +#define SUNKBD_UP 0x80 +#define SUNKBD_A 0x4d + +extern void sunkbd_inchar(unsigned char ch, unsigned char status, struct pt_regs *regs); +extern void sun_mouse_inbyte(unsigned char byte, unsigned char status); + +static unsigned char kgdb_regs[16] = { + 0, 0, 0, /* write 0, 1, 2 */ + (Rx8 | RxENABLE), /* write 3 */ + (X16CLK | SB1 | PAR_EVEN), /* write 4 */ + (Tx8 | TxENAB), /* write 5 */ + 0, 0, 0, /* write 6, 7, 8 */ + (NV), /* write 9 */ + (NRZ), /* write 10 */ + (TCBR | RCBR), /* write 11 */ + 0, 0, /* BRG time constant, write 12 + 13 */ + (BRSRC | BRENABL), /* write 14 */ + (DCDIE) /* write 15 */ +}; + +#define ZS_CLOCK 4915200 /* Zilog input clock rate */ + +DECLARE_TASK_QUEUE(tq_serial); + +struct tty_driver serial_driver, callout_driver; +static int serial_refcount; + +/* serial subtype definitions */ +#define SERIAL_TYPE_NORMAL 1 +#define SERIAL_TYPE_CALLOUT 2 + +/* number of characters left in xmit buffer before we ask for more */ +#define WAKEUP_CHARS 256 + +/* Debugging... DEBUG_INTR is bad to use when one of the zs + * lines is your console ;( + */ +#undef SERIAL_DEBUG_INTR +#undef SERIAL_DEBUG_OPEN +#undef SERIAL_DEBUG_FLOW + +#define RS_STROBE_TIME 10 +#define RS_ISR_PASS_LIMIT 256 + +#define _INLINE_ inline + +static void change_speed(struct sun_serial *info); + +static struct tty_struct *serial_table[NUM_CHANNELS]; +static struct termios *serial_termios[NUM_CHANNELS]; +static struct termios *serial_termios_locked[NUM_CHANNELS]; + +#ifndef MIN +#define MIN(a,b) ((a) < (b) ? (a) : (b)) +#endif + +/* + * tmp_buf is used as a temporary buffer by serial_write. We need to + * lock it in case the memcpy_fromfs blocks while swapping in a page, + * and some other program tries to do a serial write at the same time. + * Since the lock will only come under contention when the system is + * swapping and available memory is low, it makes sense to share one + * buffer across all the serial ports, since it significantly saves + * memory if large numbers of serial ports are open. + */ +static unsigned char tmp_buf[4096]; /* This is cheating */ +static struct semaphore tmp_buf_sem = MUTEX; + +static inline int serial_paranoia_check(struct sun_serial *info, + dev_t device, const char *routine) +{ +#ifdef SERIAL_PARANOIA_CHECK + static const char *badmagic = + "Warning: bad magic number for serial struct (%d, %d) in %s\n"; + static const char *badinfo = + "Warning: null sun_serial for (%d, %d) in %s\n"; + + if (!info) { + printk(badinfo, MAJOR(device), MINOR(device), routine); + return 1; + } + if (info->magic != SERIAL_MAGIC) { + printk(badmagic, MAJOR(device), MINOR(device), routine); + return 1; + } +#endif + return 0; +} + +/* + * This is used to figure out the divisor 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 }; + +/* Reading and writing Zilog8530 registers. The delays are to make this + * driver work on the Sun4 which needs a settling delay after each chip + * register access, other machines handle this in hardware via auxiliary + * flip-flops which implement the settle time we do in software. + */ +static inline unsigned char read_zsreg(struct sun_zschannel *channel, unsigned char reg) +{ + unsigned char retval; + + channel->control = reg; + udelay(5); + retval = channel->control; + udelay(5); + return retval; +} + +static inline void write_zsreg(struct sun_zschannel *channel, unsigned char reg, unsigned char value) +{ + channel->control = reg; + udelay(5); + channel->control = value; + udelay(5); + return; +} + +static inline void load_zsregs(struct sun_zschannel *channel, unsigned char *regs) +{ + ZS_CLEARERR(channel); + ZS_CLEARFIFO(channel); + /* Load 'em up */ + write_zsreg(channel, R4, regs[R4]); + write_zsreg(channel, R10, regs[R10]); + write_zsreg(channel, R3, regs[R3] & ~RxENABLE); + write_zsreg(channel, R5, regs[R5] & ~TxENAB); + write_zsreg(channel, R1, regs[R1]); + write_zsreg(channel, R9, regs[R9]); + write_zsreg(channel, R11, regs[R11]); + write_zsreg(channel, R12, regs[R12]); + write_zsreg(channel, R13, regs[R13]); + write_zsreg(channel, R14, regs[R14]); + write_zsreg(channel, R15, regs[R15]); + write_zsreg(channel, R3, regs[R3]); + write_zsreg(channel, R5, regs[R5]); + return; +} + +/* Sets or clears DTR/RTS on the requested line */ +static inline void zs_rtsdtr(struct sun_serial *ss, int set) +{ + if(set) { + ss->curregs[5] |= (RTS | DTR); + ss->pendregs[5] = ss->curregs[5]; + write_zsreg(ss->zs_channel, 5, ss->curregs[5]); + } else { + ss->curregs[5] &= ~(RTS | DTR); + ss->pendregs[5] = ss->curregs[5]; + write_zsreg(ss->zs_channel, 5, ss->curregs[5]); + } + return; +} + +static inline void kgdb_chaninit(struct sun_serial *ss, int intson, int bps) +{ + int brg; + + if(intson) { + kgdb_regs[R1] = INT_ALL_Rx; + kgdb_regs[R9] |= MIE; + } else { + kgdb_regs[R1] = 0; + kgdb_regs[R9] &= ~MIE; + } + brg = BPS_TO_BRG(bps, ZS_CLOCK/16); + kgdb_regs[R12] = (brg & 255); + kgdb_regs[R13] = ((brg >> 8) & 255); + load_zsregs(ss->zs_channel, kgdb_regs); +} + +/* Utility routines for the Zilog */ +static inline int get_zsbaud(struct sun_serial *ss) +{ + struct sun_zschannel *channel = ss->zs_channel; + int brg; + + /* The baud rate is split up between two 8-bit registers in + * what is termed 'BRG time constant' format in my docs for + * the chip, it is a function of the clk rate the chip is + * receiving which happens to be constant. + */ + brg = ((read_zsreg(channel, 13)&0xff) << 8); + brg |= (read_zsreg(channel, 12)&0xff); + return BRG_TO_BPS(brg, (ZS_CLOCK/(ss->clk_divisor))); +} + +/* + * ------------------------------------------------------------ + * 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 sun_serial *info = (struct sun_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_stop")) + return; + + save_flags(flags); cli(); + if (info->curregs[5] & TxENAB) { + info->curregs[5] &= ~TxENAB; + info->pendregs[5] &= ~TxENAB; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + } + restore_flags(flags); +} + +static void rs_start(struct tty_struct *tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_start")) + return; + + save_flags(flags); cli(); + if (info->xmit_cnt && info->xmit_buf && !(info->curregs[5] & TxENAB)) { + info->curregs[5] |= TxENAB; + info->pendregs[5] = info->curregs[5]; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + } + restore_flags(flags); +} + +/* Drop into either the boot monitor or kadb upon receiving a break + * from keyboard/console input. + */ +static void batten_down_hatches(void) +{ + /* If we are doing kadb, we call the debugger + * else we just drop into the boot monitor. + * Note that we must flush the user windows + * first before giving up control. + */ + printk("\n"); + flush_user_windows(); + if((((unsigned long)linux_dbvec)>=DEBUG_FIRSTVADDR) && + (((unsigned long)linux_dbvec)<=DEBUG_LASTVADDR)) + sp_enter_debugger(); + else + prom_halt(); + + /* XXX We want to notify the keyboard driver that all + * XXX keys are in the up state or else weird things + * XXX happen... + */ + + return; +} + +/* On receive, this clears errors and the receiver interrupts */ +static inline void rs_recv_clear(struct sun_zschannel *zsc) +{ + zsc->control = ERR_RES; + udelay(5); + zsc->control = RES_H_IUS; + udelay(5); +} + +/* + * ---------------------------------------------------------------------- + * + * 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 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 sun_serial *info, + int event) +{ + info->event |= 1 << event; + queue_task_irq_off(&info->tqueue, &tq_serial); + mark_bh(SERIAL_BH); +} + +extern void breakpoint(void); /* For the KGDB frame character */ + +static _INLINE_ void receive_chars(struct sun_serial *info, struct pt_regs *regs) +{ + struct tty_struct *tty = info->tty; + unsigned char ch, stat; + + ch = info->zs_channel->data; + udelay(5); + stat = read_zsreg(info->zs_channel, R1); + udelay(5); + + /* If this is the console keyboard, we need to handle + * L1-A's here. + */ + if(info->cons_keyb) { + if(ch == SUNKBD_RESET) { + l1a_state.kbd_id = 1; + l1a_state.l1_down = 0; + } else if(l1a_state.kbd_id) { + l1a_state.kbd_id = 0; + } else if(ch == SUNKBD_L1) { + l1a_state.l1_down = 1; + } else if(ch == (SUNKBD_L1|SUNKBD_UP)) { + l1a_state.l1_down = 0; + } else if(ch == SUNKBD_A && l1a_state.l1_down) { + /* whee... */ + batten_down_hatches(); + /* Clear the line and continue execution... */ + rs_recv_clear(info->zs_channel); + l1a_state.l1_down = 0; + l1a_state.kbd_id = 0; + return; + } + rs_recv_clear(info->zs_channel); + sunkbd_inchar(ch, stat, regs); + + return; + } + if(info->cons_mouse) { + rs_recv_clear(info->zs_channel); + sun_mouse_inbyte(ch, stat); + return; + } + if(info->is_cons) { + if(ch==0) { /* whee, break received */ + batten_down_hatches(); + rs_recv_clear(info->zs_channel); + return; + } else if (ch == 1) { + show_state(); + return; + } else if (ch == 2) { + show_buffers(); + return; + } + /* It is a 'keyboard interrupt' ;-) */ + wake_up(&keypress_wait); + } + /* Look for kgdb 'stop' character, consult the gdb documentation + * for remote target debugging and arch/sparc/kernel/sparc-stub.c + * to see how all this works. + */ + if((info->kgdb_channel) && (ch =='\003')) { + breakpoint(); + goto clear_and_exit; + } + + if(!tty) + goto clear_and_exit; + + if (tty->flip.count >= TTY_FLIPBUF_SIZE) + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + tty->flip.count++; + if(stat & PAR_ERR) + *tty->flip.flag_buf_ptr++ = TTY_PARITY; + else if(stat & Rx_OVR) + *tty->flip.flag_buf_ptr++ = TTY_OVERRUN; + else if(stat & CRC_ERR) + *tty->flip.flag_buf_ptr++ = TTY_FRAME; + else + *tty->flip.flag_buf_ptr++ = 0; /* XXX */ + *tty->flip.char_buf_ptr++ = ch; + + queue_task_irq_off(&tty->flip.tqueue, &tq_timer); + +clear_and_exit: + rs_recv_clear(info->zs_channel); + return; +} + +static _INLINE_ void transmit_chars(struct sun_serial *info) +{ + /* P3: In theory we have to test readiness here because a + * serial console can clog the chip through rs_put_char(). + * David did not do this. I think he relies on 3-chars FIFO in 8530. + * Let's watch for lost _output_ characters. XXX + */ + + if (info->x_char) { + /* Send next char */ + info->zs_channel->data = info->x_char; + udelay(5); + info->x_char = 0; + goto clear_and_return; + } + + if((info->xmit_cnt <= 0) || info->tty->stopped) { + /* Thats peculiar... */ + info->zs_channel->control = RES_Tx_P; + udelay(5); + goto clear_and_return; + } + + /* Send char */ + info->zs_channel->data = info->xmit_buf[info->xmit_tail++]; + udelay(5); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + + if (info->xmit_cnt < WAKEUP_CHARS) + rs_sched_event(info, RS_EVENT_WRITE_WAKEUP); + + if(info->xmit_cnt <= 0) { + info->zs_channel->control = RES_Tx_P; + udelay(5); + goto clear_and_return; + } + +clear_and_return: + /* Clear interrupt */ + info->zs_channel->control = RES_H_IUS; + udelay(5); + return; +} + +static _INLINE_ void status_handle(struct sun_serial *info) +{ + unsigned char status; + + /* Get status from Read Register 0 */ + status = info->zs_channel->control; + udelay(5); + /* Clear status condition... */ + info->zs_channel->control = RES_EXT_INT; + udelay(5); + /* Clear the interrupt */ + info->zs_channel->control = RES_H_IUS; + udelay(5); + +#if 0 + if(status & DCD) { + if((info->tty->termios->c_cflag & CRTSCTS) && + ((info->curregs[3] & AUTO_ENAB)==0)) { + info->curregs[3] |= AUTO_ENAB; + info->pendregs[3] |= AUTO_ENAB; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + } + } else { + if((info->curregs[3] & AUTO_ENAB)) { + info->curregs[3] &= ~AUTO_ENAB; + info->pendregs[3] &= ~AUTO_ENAB; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + } + } +#endif + /* Whee, if this is console input and this is a + * 'break asserted' status change interrupt, call + * the boot prom. + */ + if((status & BRK_ABRT) && info->break_abort) + batten_down_hatches(); + + /* XXX Whee, put in a buffer somewhere, the status information + * XXX whee whee whee... Where does the information go... + */ + return; +} + +/* + * This is the serial driver's generic interrupt routine + */ +void rs_interrupt(int irq, void *dev_id, struct pt_regs * regs) +{ + struct sun_serial * info; + unsigned char zs_intreg; + + info = zs_chain; + if (!info) + return; + + zs_intreg = read_zsreg(info->zs_channel, 3); + + /* NOTE: The read register 3, which holds the irq status, + * does so for both channels on each chip. Although + * the status value itself must be read from the A + * channel and is only valid when read from channel A. + * Yes... broken hardware... + */ +#define CHAN_A_IRQMASK (CHARxIP | CHATxIP | CHAEXT) +#define CHAN_B_IRQMASK (CHBRxIP | CHBTxIP | CHBEXT) + + /* *** Chip 1 *** */ + /* Channel A -- /dev/ttya, could be the console */ + if(zs_intreg & CHAN_A_IRQMASK) { + if (zs_intreg & CHARxIP) + receive_chars(info, regs); + if (zs_intreg & CHATxIP) + transmit_chars(info); + if (zs_intreg & CHAEXT) + status_handle(info); + } + + info=info->zs_next; + + /* Channel B -- /dev/ttyb, could be the console */ + if(zs_intreg & CHAN_B_IRQMASK) { + if (zs_intreg & CHBRxIP) + receive_chars(info, regs); + if (zs_intreg & CHBTxIP) + transmit_chars(info); + if (zs_intreg & CHBEXT) + status_handle(info); + } + + info = info->zs_next; + + zs_intreg = read_zsreg(info->zs_channel, 3); + /* *** Chip 2 *** */ + /* Channel A -- /dev/kbd, pass communication to keyboard driver */ + if(zs_intreg & CHAN_A_IRQMASK) { + if (zs_intreg & CHARxIP) + receive_chars(info, regs); + if (zs_intreg & CHATxIP) + transmit_chars(info); + if (zs_intreg & CHAEXT) + status_handle(info); + } + + info=info->zs_next; + + /* Channel B -- /dev/mouse, pass communication to mouse driver */ + if(zs_intreg & CHAN_B_IRQMASK) { + if (zs_intreg & CHBRxIP) + receive_chars(info, regs); + if (zs_intreg & CHBTxIP) + transmit_chars(info); + if (zs_intreg & CHBEXT) + status_handle(info); + } + + return; +} + +/* + * ------------------------------------------------------------------- + * Here ends the serial interrupt routines. + * ------------------------------------------------------------------- + */ + +/* + * 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_serial_bh(void) +{ + run_task_queue(&tq_serial); +} + +static void do_softint(void *private_) +{ + struct sun_serial *info = (struct sun_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + if (clear_bit(RS_EVENT_WRITE_WAKEUP, &info->event)) { + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); + } +} + +/* + * This routine is called from the scheduler tqueue when the interrupt + * routine has signalled that a hangup has occurred. The path of + * hangup processing is: + * + * serial interrupt routine -> (scheduler tqueue) -> + * do_serial_hangup() -> tty->hangup() -> rs_hangup() + * + */ +static void do_serial_hangup(void *private_) +{ + struct sun_serial *info = (struct sun_serial *) private_; + struct tty_struct *tty; + + tty = info->tty; + if (!tty) + return; + + tty_hangup(tty); +} + + +/* + * This subroutine is called when the RS_TIMER goes off. It is used + * by the serial driver to handle ports that do not have an interrupt + * (irq=0). This doesn't work very well for 16450's, but gives barely + * passable results for a 16550A. (Although at the expense of much + * CPU overhead). + */ +static void rs_timer(void) +{ + printk("rs_timer called\n"); + prom_halt(); + return; +} + +static int startup(struct sun_serial * info) +{ + unsigned long flags; + + if (info->flags & ZILOG_INITIALIZED) + return 0; + + if (!info->xmit_buf) { + info->xmit_buf = (unsigned char *) get_free_page(GFP_KERNEL); + if (!info->xmit_buf) + return -ENOMEM; + } + + save_flags(flags); cli(); + +#ifdef SERIAL_DEBUG_OPEN + printk("starting up ttys%d (irq %d)...", info->line, info->irq); +#endif + + /* + * Clear the FIFO buffers and disable them + * (they will be reenabled in change_speed()) + */ + ZS_CLEARFIFO(info->zs_channel); + info->xmit_fifo_size = 1; + + /* + * Clear the interrupt registers. + */ + info->zs_channel->control = ERR_RES; + udelay(5); + info->zs_channel->control = RES_H_IUS; + udelay(5); + + /* + * Now, initialize the Zilog + */ + zs_rtsdtr(info, 1); + + /* + * Finally, enable sequencing and interrupts + */ + info->curregs[1] |= (info->curregs[1] & ~0x18) | (EXT_INT_ENAB|INT_ALL_Rx); + info->pendregs[1] = info->curregs[1]; + info->curregs[3] |= (RxENABLE | Rx8); + info->pendregs[3] = info->curregs[3]; + /* We enable Tx interrupts as needed. */ + info->curregs[5] |= (TxENAB | Tx8); + info->pendregs[5] = info->curregs[5]; + info->curregs[9] |= (NV | MIE); + info->pendregs[9] = info->curregs[9]; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + write_zsreg(info->zs_channel, 5, info->curregs[5]); + write_zsreg(info->zs_channel, 9, info->curregs[9]); + + /* + * And clear the interrupt registers again for luck. + */ + info->zs_channel->control = ERR_RES; + udelay(5); + info->zs_channel->control = RES_H_IUS; + udelay(5); + + if (info->tty) + clear_bit(TTY_IO_ERROR, &info->tty->flags); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + + /* + * Set up serial timers... + */ +#if 0 /* Works well and stops the machine. */ + timer_table[RS_TIMER].expires = jiffies + 2; + timer_active |= 1 << RS_TIMER; +#endif + + /* + * and set the speed of the serial port + */ + change_speed(info); + + info->flags |= ZILOG_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 sun_serial * info) +{ + unsigned long flags; + + if (!(info->flags & ZILOG_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 */ + + if (info->xmit_buf) { + free_page((unsigned long) info->xmit_buf); + info->xmit_buf = 0; + } + + if (info->tty) + set_bit(TTY_IO_ERROR, &info->tty->flags); + + info->flags &= ~ZILOG_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(struct sun_serial *info) +{ + unsigned short port; + unsigned cflag; + int i; + int brg; + + if (!info->tty || !info->tty->termios) + return; + cflag = info->tty->termios->c_cflag; + if (!(port = info->port)) + return; + i = cflag & CBAUD; + if (i & CBAUDEX) { + /* XXX CBAUDEX is not obeyed. + * It is impossible at a 32bits SPARC. + * But we have to report this to user ... someday. + */ + i = B9600; + } + info->zs_baud = baud_table[i]; + info->clk_divisor = 16; + + info->curregs[4] = X16CLK; + info->curregs[11] = TCBR | RCBR; + brg = BPS_TO_BRG(info->zs_baud, ZS_CLOCK/info->clk_divisor); + info->curregs[12] = (brg & 255); + info->curregs[13] = ((brg >> 8) & 255); + info->curregs[14] = BRSRC | BRENABL; + + /* byte size and parity */ + switch (cflag & CSIZE) { + case CS5: + info->curregs[3] &= ~(0xc0); + info->curregs[3] |= Rx5; + info->pendregs[3] = info->curregs[3]; + info->curregs[5] &= ~(0xe0); + info->curregs[5] |= Tx5; + info->pendregs[5] = info->curregs[5]; + break; + case CS6: + info->curregs[3] &= ~(0xc0); + info->curregs[3] |= Rx6; + info->pendregs[3] = info->curregs[3]; + info->curregs[5] &= ~(0xe0); + info->curregs[5] |= Tx6; + info->pendregs[5] = info->curregs[5]; + break; + case CS7: + info->curregs[3] &= ~(0xc0); + info->curregs[3] |= Rx7; + info->pendregs[3] = info->curregs[3]; + info->curregs[5] &= ~(0xe0); + info->curregs[5] |= Tx7; + info->pendregs[5] = info->curregs[5]; + break; + case CS8: + default: /* defaults to 8 bits */ + info->curregs[3] &= ~(0xc0); + info->curregs[3] |= Rx8; + info->pendregs[3] = info->curregs[3]; + info->curregs[5] &= ~(0xe0); + info->curregs[5] |= Tx8; + info->pendregs[5] = info->curregs[5]; + break; + } + info->curregs[4] &= ~(0x0c); + if (cflag & CSTOPB) { + info->curregs[4] |= SB2; + } else { + info->curregs[4] |= SB1; + } + info->pendregs[4] = info->curregs[4]; + if (cflag & PARENB) { + info->curregs[4] |= PAR_ENA; + info->pendregs[4] |= PAR_ENA; + } else { + info->curregs[4] &= ~PAR_ENA; + info->pendregs[4] &= ~PAR_ENA; + } + if (!(cflag & PARODD)) { + info->curregs[4] |= PAR_EVEN; + info->pendregs[4] |= PAR_EVEN; + } else { + info->curregs[4] &= ~PAR_EVEN; + info->pendregs[4] &= ~PAR_EVEN; + } + + /* Load up the new values */ + load_zsregs(info->zs_channel, info->curregs); + + return; +} + +/* This is for mouse/keyboard output. + * XXX mouse output??? can we send it commands??? XXX + */ +void kbd_put_char(unsigned char ch) +{ + struct sun_zschannel *chan = zs_kbdchan; + int flags, loops = 0; + + if(!chan) + return; + + save_flags(flags); cli(); + while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) { + loops++; + udelay(5); + } + + chan->data = ch; + udelay(5); + restore_flags(flags); +} + +void mouse_put_char(char ch) +{ + struct sun_zschannel *chan = zs_mousechan; + int flags, loops = 0; + + if(!chan) + return; + + save_flags(flags); cli(); + while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) { + loops++; + udelay(5); + } + + chan->data = ch; + udelay(5); + restore_flags(flags); +} + + +/* This is for console output over ttya/ttyb */ +static void rs_put_char(char ch) +{ + struct sun_zschannel *chan = zs_conschan; + int flags, loops = 0; + + if(!chan) + return; + + save_flags(flags); cli(); + while((chan->control & Tx_BUF_EMP)==0 && loops < 10000) { + loops++; + udelay(5); + } + + chan->data = ch; + udelay(5); + restore_flags(flags); +} + +/* These are for receiving and sending characters under the kgdb + * source level kernel debugger. + */ +void putDebugChar(char kgdb_char) +{ + struct sun_zschannel *chan = zs_kgdbchan; + + while((chan->control & Tx_BUF_EMP)==0) + udelay(5); + + chan->data = kgdb_char; +} + +char getDebugChar(void) +{ + struct sun_zschannel *chan = zs_kgdbchan; + + while((chan->control & Rx_CH_AV)==0) + barrier(); + return chan->data; +} + +/* + * Fair output driver allows a process to speak. + */ +static void rs_fair_output(void) +{ + int left; /* Output no more than that */ + unsigned long flags; + struct sun_serial *info = zs_consinfo; + char c; + + if (info == 0) return; + if (info->xmit_buf == 0) return; + + save_flags(flags); cli(); + left = info->xmit_cnt; + while (left != 0) { + c = info->xmit_buf[info->xmit_tail]; + info->xmit_tail = (info->xmit_tail+1) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + restore_flags(flags); + + rs_put_char(c); + + save_flags(flags); cli(); + left = MIN(info->xmit_cnt, left-1); + } + + /* Last character is being transmitted now (hopefuly). */ + zs_conschan->control = RES_Tx_P; + udelay(5); + + restore_flags(flags); + return; +} + +/* + * zs_console_print is registered for printk. + */ +static void zs_console_print(const char *p) +{ + char c; + + while((c=*(p++)) != 0) { + if(c == '\n') + rs_put_char('\r'); + rs_put_char(c); + } + + /* Comment this if you want to have a strict interrupt-driven output */ + rs_fair_output(); + + return; +} + +static void rs_flush_chars(struct tty_struct *tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_flush_chars")) + return; + + if (info->xmit_cnt <= 0 || tty->stopped || tty->hw_stopped || + !info->xmit_buf) + return; + + /* Enable transmitter */ + save_flags(flags); cli(); + info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB; + info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB; + write_zsreg(info->zs_channel, 1, info->curregs[1]); + info->curregs[5] |= TxENAB; + info->pendregs[5] |= TxENAB; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + + /* + * Send a first (bootstrapping) character. A best solution is + * to call transmit_chars() here which handles output in a + * generic way. Current transmit_chars() not only transmits, + * but resets interrupts also what we do not desire here. + * XXX Discuss with David. + */ + if (info->zs_channel->control & Tx_BUF_EMP) { + /* Send char */ + info->zs_channel->data = info->xmit_buf[info->xmit_tail++]; + udelay(5); + info->xmit_tail = info->xmit_tail & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt--; + } + restore_flags(flags); +} + +static int rs_write(struct tty_struct * tty, int from_user, + const unsigned char *buf, int count) +{ + int c, total = 0; + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + unsigned long flags; + + if (serial_paranoia_check(info, tty->device, "rs_write")) + return 0; + + if (!tty || !info->xmit_buf) + return 0; + + save_flags(flags); + while (1) { + cli(); + c = MIN(count, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + if (c <= 0) + break; + + if (from_user) { + down(&tmp_buf_sem); + memcpy_fromfs(tmp_buf, buf, c); + c = MIN(c, MIN(SERIAL_XMIT_SIZE - info->xmit_cnt - 1, + SERIAL_XMIT_SIZE - info->xmit_head)); + memcpy(info->xmit_buf + info->xmit_head, tmp_buf, c); + up(&tmp_buf_sem); + } else + memcpy(info->xmit_buf + info->xmit_head, buf, c); + info->xmit_head = (info->xmit_head + c) & (SERIAL_XMIT_SIZE-1); + info->xmit_cnt += c; + restore_flags(flags); + buf += c; + count -= c; + total += c; + } + if (info->xmit_cnt && !tty->stopped && !tty->hw_stopped && + !(info->curregs[5] & TxENAB)) { + /* Enable transmitter */ + info->curregs[1] |= TxINT_ENAB|EXT_INT_ENAB; + info->pendregs[1] |= TxINT_ENAB|EXT_INT_ENAB; + write_zsreg(info->zs_channel, 1, info->curregs[1]); + info->curregs[5] |= TxENAB; + info->pendregs[5] |= TxENAB; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + } + restore_flags(flags); + return total; +} + +static int rs_write_room(struct tty_struct *tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + int ret; + + if (serial_paranoia_check(info, tty->device, "rs_write_room")) + return 0; + ret = SERIAL_XMIT_SIZE - info->xmit_cnt - 1; + if (ret < 0) + ret = 0; + return ret; +} + +static int rs_chars_in_buffer(struct tty_struct *tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_chars_in_buffer")) + return 0; + return info->xmit_cnt; +} + +static void rs_flush_buffer(struct tty_struct *tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_flush_buffer")) + return; + cli(); + info->xmit_cnt = info->xmit_head = info->xmit_tail = 0; + sti(); + wake_up_interruptible(&tty->write_wait); + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); +} + +/* + * ------------------------------------------------------------ + * rs_throttle() + * + * This routine is called by the upper-layer tty layer to signal that + * incoming characters should be throttled. + * ------------------------------------------------------------ + */ +static void rs_throttle(struct tty_struct * tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("throttle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_throttle")) + return; + + if (I_IXOFF(tty)) + info->x_char = STOP_CHAR(tty); + + /* Turn off RTS line */ + cli(); + info->curregs[5] &= ~RTS; + info->pendregs[5] &= ~RTS; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + sti(); +} + +static void rs_unthrottle(struct tty_struct * tty) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; +#ifdef SERIAL_DEBUG_THROTTLE + char buf[64]; + + printk("unthrottle %s: %d....\n", _tty_name(tty, buf), + tty->ldisc.chars_in_buffer(tty)); +#endif + + if (serial_paranoia_check(info, tty->device, "rs_unthrottle")) + return; + + if (I_IXOFF(tty)) { + if (info->x_char) + info->x_char = 0; + else + info->x_char = START_CHAR(tty); + } + + /* Assert RTS line */ + cli(); + info->curregs[5] |= RTS; + info->pendregs[5] |= RTS; + write_zsreg(info->zs_channel, 5, info->curregs[5]); + sti(); +} + +/* + * ------------------------------------------------------------ + * rs_ioctl() and friends + * ------------------------------------------------------------ + */ + +static int get_serial_info(struct sun_serial * 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.closing_wait = info->closing_wait; + tmp.custom_divisor = info->custom_divisor; + memcpy_tofs(retinfo,&tmp,sizeof(*retinfo)); + return 0; +} + +static int set_serial_info(struct sun_serial * info, + struct serial_struct * new_info) +{ + struct serial_struct new_serial; + struct sun_serial old_info; + int retval = 0; + + if (!new_info) + return -EFAULT; + memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); + old_info = *info; + + if (!suser()) { + if ((new_serial.baud_base != info->baud_base) || + (new_serial.type != info->type) || + (new_serial.close_delay != info->close_delay) || + ((new_serial.flags & ~ZILOG_USR_MASK) != + (info->flags & ~ZILOG_USR_MASK))) + return -EPERM; + info->flags = ((info->flags & ~ZILOG_USR_MASK) | + (new_serial.flags & ZILOG_USR_MASK)); + info->custom_divisor = new_serial.custom_divisor; + goto check_and_exit; + } + + if (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 & ~ZILOG_FLAGS) | + (new_serial.flags & ZILOG_FLAGS)); + info->type = new_serial.type; + info->close_delay = new_serial.close_delay; + info->closing_wait = new_serial.closing_wait; + +check_and_exit: + retval = startup(info); + return retval; +} + +/* + * get_lsr_info - get line status register info + * + * Purpose: Let user call ioctl() to get info when the UART physically + * is emptied. On bus types like RS485, the transmitter must + * release the bus after transmitting. This must be done when + * the transmit shift register is empty, not be done when the + * transmit holding register is empty. This functionality + * allows RS485 driver to be written in user space. + */ +static int get_lsr_info(struct sun_serial * info, unsigned int *value) +{ + unsigned char status; + + cli(); + status = info->zs_channel->control; + sti(); + put_user(status,value); + return 0; +} + +/* + * This routine sends a break character out the serial port. + */ +static void send_break( struct sun_serial * info, int duration) +{ + if (!info->port) + return; + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + duration; + cli(); + write_zsreg(info->zs_channel, 5, (info->curregs[5] | SND_BRK)); + schedule(); + write_zsreg(info->zs_channel, 5, info->curregs[5]); + sti(); +} + +static int rs_ioctl(struct tty_struct *tty, struct file * file, + unsigned int cmd, unsigned long arg) +{ + int error; + struct sun_serial * info = (struct sun_serial *)tty->driver_data; + int retval; + + if (serial_paranoia_check(info, tty->device, "rs_ioctl")) + return -ENODEV; + + if ((cmd != TIOCGSERIAL) && (cmd != TIOCSSERIAL) && + (cmd != TIOCSERCONFIG) && (cmd != TIOCSERGWILD) && + (cmd != TIOCSERSWILD) && (cmd != TIOCSERGSTRUCT)) { + if (tty->flags & (1 << TTY_IO_ERROR)) + return -EIO; + } + + switch (cmd) { + case TCSBRK: /* SVID version: non-zero arg --> no break */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + if (!arg) + send_break(info, HZ/4); /* 1/4 second */ + return 0; + case TCSBRKP: /* support for POSIX tcsendbreak() */ + retval = tty_check_change(tty); + if (retval) + return retval; + tty_wait_until_sent(tty, 0); + 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 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 TIOCSERGETLSR: /* Get line status register */ + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(unsigned int)); + if (error) + return error; + else + return get_lsr_info(info, (unsigned int *) arg); + + case TIOCSERGSTRUCT: + error = verify_area(VERIFY_WRITE, (void *) arg, + sizeof(struct sun_serial)); + if (error) + return error; + memcpy_tofs((struct sun_serial *) arg, + info, sizeof(struct sun_serial)); + return 0; + + default: + return -ENOIOCTLCMD; + } + return 0; +} + +static void rs_set_termios(struct tty_struct *tty, struct termios *old_termios) +{ + struct sun_serial *info = (struct sun_serial *)tty->driver_data; + + if (tty->termios->c_cflag == old_termios->c_cflag) + return; + + change_speed(info); + + if ((old_termios->c_cflag & CRTSCTS) && + !(tty->termios->c_cflag & CRTSCTS)) { + tty->hw_stopped = 0; + rs_start(tty); + } +} + +/* + * ------------------------------------------------------------ + * 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 + * ZILOG 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 sun_serial * info = (struct sun_serial *)tty->driver_data; + unsigned long flags; + + if (!info || serial_paranoia_check(info, tty->device, "rs_close")) + return; + + save_flags(flags); cli(); + + if (tty_hung_up_p(filp)) { + restore_flags(flags); + return; + } + +#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) { + restore_flags(flags); + return; + } + info->flags |= ZILOG_CLOSING; + /* + * Save the termios structure, since this port may have + * separate termios for callout and dialin. + */ + if (info->flags & ZILOG_NORMAL_ACTIVE) + info->normal_termios = *tty->termios; + if (info->flags & ZILOG_CALLOUT_ACTIVE) + info->callout_termios = *tty->termios; + /* + * Now we wait for the transmit buffer to clear; and we notify + * the line discipline to only process XON/XOFF characters. + */ + tty->closing = 1; + if (info->closing_wait != ZILOG_CLOSING_WAIT_NONE) + tty_wait_until_sent(tty, info->closing_wait); + /* + * At this point we stop accepting input. To do this, we + * disable the receive line status interrupts, and tell the + * interrupt driver to stop checking the data ready bit in the + * line status register. + */ + /** if (!info->iscons) ... **/ + info->curregs[3] &= ~RxENABLE; + info->pendregs[3] = info->curregs[3]; + write_zsreg(info->zs_channel, 3, info->curregs[3]); + info->curregs[1] &= ~(0x18); + info->pendregs[1] = info->curregs[1]; + write_zsreg(info->zs_channel, 1, info->curregs[1]); + ZS_CLEARFIFO(info->zs_channel); + + shutdown(info); + if (tty->driver.flush_buffer) + tty->driver.flush_buffer(tty); + if (tty->ldisc.flush_buffer) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + info->event = 0; + info->tty = 0; + if (tty->ldisc.num != ldiscs[N_TTY].num) { + if (tty->ldisc.close) + (tty->ldisc.close)(tty); + tty->ldisc = ldiscs[N_TTY]; + tty->termios->c_line = N_TTY; + if (tty->ldisc.open) + (tty->ldisc.open)(tty); + } + if (info->blocked_open) { + if (info->close_delay) { + current->state = TASK_INTERRUPTIBLE; + current->timeout = jiffies + info->close_delay; + schedule(); + } + wake_up_interruptible(&info->open_wait); + } + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_CALLOUT_ACTIVE| + ZILOG_CLOSING); + wake_up_interruptible(&info->close_wait); + restore_flags(flags); +} + +/* + * rs_hangup() --- called by tty_hangup() when a hangup is signaled. + */ +void rs_hangup(struct tty_struct *tty) +{ + struct sun_serial * info = (struct sun_serial *)tty->driver_data; + + if (serial_paranoia_check(info, tty->device, "rs_hangup")) + return; + + rs_flush_buffer(tty); + shutdown(info); + info->event = 0; + info->count = 0; + info->flags &= ~(ZILOG_NORMAL_ACTIVE|ZILOG_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 sun_serial *info) +{ + struct wait_queue wait = { current, NULL }; + int retval; + int do_clocal = 0; + + /* + * If the device is in the middle of being closed, then block + * until it's done, and then try again. + */ + if (info->flags & ZILOG_CLOSING) { + interruptible_sleep_on(&info->close_wait); +#ifdef SERIAL_DO_RESTART + if (info->flags & ZILOG_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 (tty->driver.subtype == SERIAL_TYPE_CALLOUT) { + if (info->flags & ZILOG_NORMAL_ACTIVE) + return -EBUSY; + if ((info->flags & ZILOG_CALLOUT_ACTIVE) && + (info->flags & ZILOG_SESSION_LOCKOUT) && + (info->session != current->session)) + return -EBUSY; + if ((info->flags & ZILOG_CALLOUT_ACTIVE) && + (info->flags & ZILOG_PGRP_LOCKOUT) && + (info->pgrp != current->pgrp)) + return -EBUSY; + info->flags |= ZILOG_CALLOUT_ACTIVE; + return 0; + } + + /* + * If non-blocking mode is set, or the port is not enabled, + * then make the check up front and then exit. + */ + if ((filp->f_flags & O_NONBLOCK) || + (tty->flags & (1 << TTY_IO_ERROR))) { + if (info->flags & ZILOG_CALLOUT_ACTIVE) + return -EBUSY; + info->flags |= ZILOG_NORMAL_ACTIVE; + return 0; + } + + if (info->flags & ZILOG_CALLOUT_ACTIVE) { + if (info->normal_termios.c_cflag & CLOCAL) + do_clocal = 1; + } else { + if (tty->termios->c_cflag & CLOCAL) + do_clocal = 1; + } + + /* + * 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 & ZILOG_CALLOUT_ACTIVE)) + zs_rtsdtr(info, 1); + sti(); + current->state = TASK_INTERRUPTIBLE; + if (tty_hung_up_p(filp) || + !(info->flags & ZILOG_INITIALIZED)) { +#ifdef SERIAL_DO_RESTART + if (info->flags & ZILOG_HUP_NOTIFY) + retval = -EAGAIN; + else + retval = -ERESTARTSYS; +#else + retval = -EAGAIN; +#endif + break; + } + if (!(info->flags & ZILOG_CALLOUT_ACTIVE) && + !(info->flags & ZILOG_CLOSING) && do_clocal) + 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 |= ZILOG_NORMAL_ACTIVE; + return 0; +} + +/* + * This routine is called whenever a serial port is opened. It + * enables interrupts for a serial port, linking in its ZILOG structure into + * the IRQ chain. It also performs the serial-specific + * initialization for the tty structure. + */ +int rs_open(struct tty_struct *tty, struct file * filp) +{ + struct sun_serial *info; + int retval, line; + + line = MINOR(tty->device) - tty->driver.minor_start; + /* The zilog lines for the mouse/keyboard must be + * opened using their respective drivers. + */ + if ((line < 0) || (line >= NUM_CHANNELS)) + return -ENODEV; + if((line == KEYBOARD_LINE) || (line == MOUSE_LINE)) + return -ENODEV; + info = zs_soft + line; + /* Is the kgdb running over this line? */ + if (info->kgdb_channel) + return -ENODEV; + if (serial_paranoia_check(info, tty->device, "rs_open")) + return -ENODEV; +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open %s%d, count = %d\n", tty->driver.name, info->line, + info->count); +#endif + info->count++; + tty->driver_data = info; + info->tty = tty; + + /* + * Start up serial port + */ + retval = startup(info); + 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; + } + + if ((info->count == 1) && (info->flags & ZILOG_SPLIT_TERMIOS)) { + if (tty->driver.subtype == SERIAL_TYPE_NORMAL) + *tty->termios = info->normal_termios; + else + *tty->termios = info->callout_termios; + change_speed(info); + } + + info->session = current->session; + info->pgrp = current->pgrp; + +#ifdef SERIAL_DEBUG_OPEN + printk("rs_open ttys%d successful...", info->line); +#endif + return 0; +} + +/* Finally, routines used to initialize the serial driver. */ + +static void show_serial_version(void) +{ + printk("Sparc Zilog8530 serial driver version 1.00\n"); +} + +/* Probe the PROM for the request zs chip number. */ +static inline struct sun_zslayout *get_zs(int chip) +{ + struct linux_prom_irqs tmp_irq; + unsigned long paddr = 0; + unsigned long vaddr = 0; + int zsnode, tmpnode, iospace, slave; + static int irq = 0; + +#if CONFIG_AP1000 + printk("No zs chip\n"); + return NULL; +#endif + + iospace = 0; + if(chip < 0 || chip >= NUM_SERIAL) + panic("get_zs bogon zs chip number"); + + if(sparc_cpu_model == sun4) { + /* Grrr, these have to be hardcoded aieee */ + switch(chip) { + case 0: + paddr = 0xf1000000; + break; + case 1: + paddr = 0xf0000000; + break; + }; + iospace = 0; + zs_nodes[chip] = 0; + if(!irq) + zilog_irq = irq = 12; + vaddr = (unsigned long) + sparc_alloc_io((char *) paddr, 0, 8, + "Zilog Serial", iospace, 0); + } else { + /* Can use the prom for other machine types */ + zsnode = prom_getchild(prom_root_node); + tmpnode = prom_searchsiblings(zsnode, "obio"); + if(tmpnode) + zsnode = prom_getchild(tmpnode); + if(!zsnode) + panic("get_zs no zs serial prom node"); + while(zsnode) { + zsnode = prom_searchsiblings(zsnode, "zs"); + slave = prom_getintdefault(zsnode, "slave", -1); + if(slave==chip) { + /* The one we want */ + vaddr = (unsigned long) + prom_getintdefault(zsnode, "address", + 0xdeadbeef); + if(vaddr == 0xdeadbeef) + prom_halt(); + zs_nodes[chip] = zsnode; + prom_getproperty(zsnode, "intr", + (char *) &tmp_irq, + sizeof(tmp_irq)); +#ifdef OLD_STYLE_IRQ + tmp_irq.pri &= 0xf; +#endif + if(!irq) { + irq = zilog_irq = tmp_irq.pri; + } else { + if(tmp_irq.pri != irq) + panic("zilog: bogon irqs"); + } + break; + } + zsnode = prom_getsibling(zsnode); + } + if(!zsnode) + panic("get_zs whee chip not found"); + } + if(!vaddr) + panic("get_zs whee no serial chip mappable"); + + return (struct sun_zslayout *) vaddr; + +} + + +extern void register_console(void (*proc)(const char *)); + +static inline void +rs_cons_check(struct sun_serial *ss, int channel) +{ + int i, o, io; + static consout_registered = 0; + static msg_printed = 0; + + i = o = io = 0; + + /* Is this one of the serial console lines? */ + if((zs_cons_chanout != channel) && + (zs_cons_chanin != channel)) + return; + zs_conschan = ss->zs_channel; + zs_consinfo = ss; + + /* Register the console output putchar, if necessary */ + if((zs_cons_chanout == channel)) { + o = 1; + /* double whee.. */ + if(!consout_registered) { + register_console(zs_console_print); + consout_registered = 1; + } + } + + /* If this is console input, we handle the break received + * status interrupt on this line to mean prom_halt(). + */ + if(zs_cons_chanin == channel) { + ss->break_abort = 1; + i = 1; + } + if(o && i) + io = 1; + if(ss->zs_baud != 9600) + panic("Console baud rate weirdness"); + + /* Set flag variable for this port so that it cannot be + * opened for other uses by accident. + */ + ss->is_cons = 1; + + if(io) { + if(!msg_printed) { + printk("zs%d: console I/O\n", ((channel>>1)&1)); + msg_printed = 1; + } + } else { + printk("zs%d: console %s\n", ((channel>>1)&1), + (i==1 ? "input" : (o==1 ? "output" : "WEIRD"))); + } +} + +volatile int test_done; +extern void keyboard_zsinit(void); +extern void sun_mouse_zsinit(void); + +/* rs_init inits the driver */ +int rs_init(void) +{ + int chip, channel, i, flags; + struct sun_serial *info; + +#if CONFIG_AP1000 + printk("not doing rs_init()\n"); + return 0; +#endif + + /* Setup base handler, and timer table. */ + init_bh(SERIAL_BH, do_serial_bh); + timer_table[RS_TIMER].fn = rs_timer; + timer_table[RS_TIMER].expires = 0; + + show_serial_version(); + + /* Initialize the tty_driver structure */ + /* SPARC: Not all of this is exactly right for us. */ + + memset(&serial_driver, 0, sizeof(struct tty_driver)); + serial_driver.magic = TTY_DRIVER_MAGIC; + serial_driver.name = "ttyS"; + serial_driver.major = TTY_MAJOR; + serial_driver.minor_start = 64; + serial_driver.num = NUM_CHANNELS; + serial_driver.type = TTY_DRIVER_TYPE_SERIAL; + serial_driver.subtype = SERIAL_TYPE_NORMAL; + serial_driver.init_termios = tty_std_termios; + + serial_driver.init_termios.c_cflag = + B9600 | CS8 | CREAD | HUPCL | CLOCAL; + serial_driver.flags = TTY_DRIVER_REAL_RAW; + serial_driver.refcount = &serial_refcount; + serial_driver.table = serial_table; + serial_driver.termios = serial_termios; + serial_driver.termios_locked = serial_termios_locked; + + serial_driver.open = rs_open; + serial_driver.close = rs_close; + serial_driver.write = rs_write; + serial_driver.flush_chars = rs_flush_chars; + serial_driver.write_room = rs_write_room; + serial_driver.chars_in_buffer = rs_chars_in_buffer; + serial_driver.flush_buffer = rs_flush_buffer; + serial_driver.ioctl = rs_ioctl; + serial_driver.throttle = rs_throttle; + serial_driver.unthrottle = rs_unthrottle; + serial_driver.set_termios = rs_set_termios; + serial_driver.stop = rs_stop; + serial_driver.start = rs_start; + serial_driver.hangup = rs_hangup; + + /* + * The callout device is just like normal device except for + * major number and the subtype code. + */ + callout_driver = serial_driver; + callout_driver.name = "cua"; + callout_driver.major = TTYAUX_MAJOR; + callout_driver.subtype = SERIAL_TYPE_CALLOUT; + + if (tty_register_driver(&serial_driver)) + panic("Couldn't register serial driver\n"); + if (tty_register_driver(&callout_driver)) + panic("Couldn't register callout driver\n"); + + save_flags(flags); cli(); + + /* Set up our interrupt linked list */ + zs_chain = &zs_soft[0]; + zs_soft[0].zs_next = &zs_soft[1]; + zs_soft[1].zs_next = &zs_soft[2]; + zs_soft[2].zs_next = &zs_soft[3]; + zs_soft[3].zs_next = 0; + + for(chip = 0; chip < NUM_SERIAL; chip++) { + /* If we are doing kgdb over one of the channels on + * chip zero, kgdb_channel will be set to 1 by the + * rs_kgdb_hook() routine below. + */ + if(!zs_chips[chip]) { + zs_chips[chip] = get_zs(chip); + /* Two channels per chip */ + zs_channels[(chip*2)] = &zs_chips[chip]->channelA; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + zs_soft[(chip*2)].kgdb_channel = 0; + zs_soft[(chip*2)+1].kgdb_channel = 0; + } + /* First, set up channel A on this chip. */ + channel = chip * 2; + zs_soft[channel].zs_channel = zs_channels[channel]; + zs_soft[channel].change_needed = 0; + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); + zs_soft[channel].cons_mouse = 0; + /* If not keyboard/mouse and is console serial + * line, then enable receiver interrupts. + */ + if((channelzs_next, i++) + { + info->magic = SERIAL_MAGIC; + info->port = (int) info->zs_channel; + info->line = i; + info->tty = 0; + info->irq = zilog_irq; + info->custom_divisor = 16; + info->close_delay = 50; + info->closing_wait = 3000; + info->x_char = 0; + info->event = 0; + info->count = 0; + info->blocked_open = 0; + info->tqueue.routine = do_softint; + info->tqueue.data = info; + info->tqueue_hangup.routine = do_serial_hangup; + info->tqueue_hangup.data = info; + info->callout_termios =callout_driver.init_termios; + info->normal_termios = serial_driver.init_termios; + info->open_wait = 0; + info->close_wait = 0; + printk("tty%02d at 0x%04x (irq = %d)", info->line, + info->port, info->irq); + printk(" is a Zilog8530\n"); + } + + if (request_irq(zilog_irq, + rs_interrupt, + (SA_INTERRUPT | SA_STATIC_ALLOC), + "Zilog8530", NULL)) + panic("Unable to attach zs intr\n"); + restore_flags(flags); + + keyboard_zsinit(); + + return 0; +} + +/* + * register_serial and unregister_serial allows for serial ports to be + * configured at run-time, to support PCMCIA modems. + */ +/* SPARC: Unused at this time, just here to make things link. */ +int register_serial(struct serial_struct *req) +{ + return -1; +} + +void unregister_serial(int line) +{ + return; +} + +/* Hooks for running a serial console. con_init() calls this if the + * console is being run over one of the ttya/ttyb serial ports. + * 'chip' should be zero, as chip 1 drives the mouse/keyboard. + * 'channel' is decoded as 0=TTYA 1=TTYB, note that the channels + * are addressed backwards, channel B is first, then channel A. + */ +void +rs_cons_hook(int chip, int out, int channel) +{ + if(chip) + panic("rs_cons_hook called with chip not zero"); + if(!zs_chips[chip]) { + zs_chips[chip] = get_zs(chip); + /* Two channels per chip */ + zs_channels[(chip*2)] = &zs_chips[chip]->channelA; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + } + zs_soft[channel].zs_channel = zs_channels[channel]; + zs_soft[channel].change_needed = 0; + zs_soft[channel].clk_divisor = 16; + zs_soft[channel].zs_baud = get_zsbaud(&zs_soft[channel]); + rs_cons_check(&zs_soft[channel], channel); + if(out) + zs_cons_chanout = ((chip * 2) + channel); + else + zs_cons_chanin = ((chip * 2) + channel); + +} + +/* This is called at boot time to prime the kgdb serial debugging + * serial line. The 'tty_num' argument is 0 for /dev/ttya and 1 + * for /dev/ttyb which is determined in setup_arch() from the + * boot command line flags. + */ +void +rs_kgdb_hook(int tty_num) +{ + int chip = 0; + + if(!zs_chips[chip]) { + zs_chips[chip] = get_zs(chip); + /* Two channels per chip */ + zs_channels[(chip*2)] = &zs_chips[chip]->channelA; + zs_channels[(chip*2)+1] = &zs_chips[chip]->channelB; + } + zs_soft[tty_num].zs_channel = zs_channels[tty_num]; + zs_kgdbchan = zs_soft[tty_num].zs_channel; + zs_soft[tty_num].change_needed = 0; + zs_soft[tty_num].clk_divisor = 16; + zs_soft[tty_num].zs_baud = get_zsbaud(&zs_soft[tty_num]); + zs_soft[tty_num].kgdb_channel = 1; /* This runs kgdb */ + zs_soft[tty_num ^ 1].kgdb_channel = 0; /* This does not */ + /* Turn on transmitter/receiver at 8-bits/char */ + kgdb_chaninit(&zs_soft[tty_num], 0, 9600); + ZS_CLEARERR(zs_kgdbchan); + udelay(5); + ZS_CLEARFIFO(zs_kgdbchan); +} diff --git a/drivers/sbus/char/sunserial.h b/drivers/sbus/char/sunserial.h new file mode 100644 index 000000000000..8fb029669ac2 --- /dev/null +++ b/drivers/sbus/char/sunserial.h @@ -0,0 +1,420 @@ +/* serial.h: Definitions for the Sparc Zilog serial driver. + * + * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) + */ +#ifndef _SPARC_SERIAL_H +#define _SPARC_SERIAL_H + +/* Just one channel */ +struct sun_zschannel { + volatile unsigned char control; + volatile unsigned char pad1; + volatile unsigned char data; + volatile unsigned char pad2; +}; + +/* The address space layout for each zs chip. Yes they are + * backwards. + */ +struct sun_zslayout { + struct sun_zschannel channelB; + struct sun_zschannel channelA; +}; + +/* We need to keep track of the keyboard state, *ahead* of what + * the keyboard driver sees, which will be later on after the + * interrupt via tqueue wait queues and/or base-handler processing. + */ +struct l1a_kbd_state { + unsigned char kbd_id; + unsigned char l1_down; +}; + +#define NUM_ZSREGS 16 + +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; + unsigned short closing_wait; /* time to wait before closing */ + unsigned short closing_wait2; /* no longer used... */ + int reserved[4]; +}; + +/* + * For the close wait times, 0 means wait forever for serial port to + * flush its output. 65535 means don't wait at all. + */ +#define ZILOG_CLOSING_WAIT_INF 0 +#define ZILOG_CLOSING_WAIT_NONE 65535 + +/* + * Definitions for ZILOG_struct (and serial_struct) flags field + */ +#define ZILOG_HUP_NOTIFY 0x0001 /* Notify getty on hangups and closes + on the callout port */ +#define ZILOG_FOURPORT 0x0002 /* Set OU1, OUT2 per AST Fourport settings */ +#define ZILOG_SAK 0x0004 /* Secure Attention Key (Orange book) */ +#define ZILOG_SPLIT_TERMIOS 0x0008 /* Separate termios for dialin/callout */ + +#define ZILOG_SPD_MASK 0x0030 +#define ZILOG_SPD_HI 0x0010 /* Use 56000 instead of 38400 bps */ + +#define ZILOG_SPD_VHI 0x0020 /* Use 115200 instead of 38400 bps */ +#define ZILOG_SPD_CUST 0x0030 /* Use user-specified divisor */ + +#define ZILOG_SKIP_TEST 0x0040 /* Skip UART test during autoconfiguration */ +#define ZILOG_AUTO_IRQ 0x0080 /* Do automatic IRQ during autoconfiguration */ +#define ZILOG_SESSION_LOCKOUT 0x0100 /* Lock out cua opens based on session */ +#define ZILOG_PGRP_LOCKOUT 0x0200 /* Lock out cua opens based on pgrp */ +#define ZILOG_CALLOUT_NOHUP 0x0400 /* Don't do hangups for cua device */ + +#define ZILOG_FLAGS 0x0FFF /* Possible legal ZILOG flags */ +#define ZILOG_USR_MASK 0x0430 /* Legal flags that non-privileged + * users can set or reset */ + +/* Internal flags used only by kernel/chr_drv/serial.c */ +#define ZILOG_INITIALIZED 0x80000000 /* Serial port was initialized */ +#define ZILOG_CALLOUT_ACTIVE 0x40000000 /* Call out device is active */ +#define ZILOG_NORMAL_ACTIVE 0x20000000 /* Normal device is active */ +#define ZILOG_BOOT_AUTOCONF 0x10000000 /* Autoconfigure port on bootup */ +#define ZILOG_CLOSING 0x08000000 /* Serial port is closing */ +#define ZILOG_CTS_FLOW 0x04000000 /* Do CTS flow control */ +#define ZILOG_CHECK_CD 0x02000000 /* i.e., CLOCAL */ + +/* Software state per channel */ + +#ifdef __KERNEL__ +/* + * 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 + */ + +struct sun_serial { + struct sun_serial *zs_next; /* For IRQ servicing chain */ + struct sun_zschannel *zs_channel; /* Channel registers */ + unsigned char read_reg_zero; + + char soft_carrier; /* Use soft carrier on this channel */ + char cons_keyb; /* Channel runs the keyboard */ + char cons_mouse; /* Channel runs the mouse */ + char break_abort; /* Is serial console in, so process brk/abrt */ + char kgdb_channel; /* Kgdb is running on this channel */ + char is_cons; /* Is this our console. */ + + /* We need to know the current clock divisor + * to read the bps rate the chip has currently + * loaded. + */ + unsigned char clk_divisor; /* May be 1, 16, 32, or 64 */ + int zs_baud; + + /* Current write register values */ + unsigned char curregs[NUM_ZSREGS]; + + /* Values we need to set next opportunity */ + unsigned char pendregs[NUM_ZSREGS]; + + char change_needed; + + int magic; + int baud_base; + int port; + int irq; + int flags; /* defined in tty.h */ + int type; /* UART type */ + struct tty_struct *tty; + int read_status_mask; + int ignore_status_mask; + int timeout; + int xmit_fifo_size; + int custom_divisor; + int x_char; /* xon/xoff character */ + int close_delay; + unsigned short closing_wait; + unsigned short closing_wait2; + unsigned long event; + unsigned long last_active; + 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 */ + unsigned char *xmit_buf; + int xmit_head; + int xmit_tail; + int xmit_cnt; + struct tq_struct tqueue; + struct tq_struct tqueue_hangup; + struct termios normal_termios; + struct termios callout_termios; + struct wait_queue *open_wait; + struct wait_queue *close_wait; +}; + + +#define SERIAL_MAGIC 0x5301 + +/* + * The size of the serial xmit buffer is 1 page, or 4096 bytes + */ +#define SERIAL_XMIT_SIZE 4096 + +/* + * Events are used to schedule things to happen at timer-interrupt + * time, instead of at rs interrupt time. + */ +#define RS_EVENT_WRITE_WAKEUP 0 + +#endif /* __KERNEL__ */ + +/* Conversion routines to/from brg time constants from/to bits + * per second. + */ +#define BRG_TO_BPS(brg, freq) ((freq) / 2 / ((brg) + 2)) +#define BPS_TO_BRG(bps, freq) ((((freq) + (bps)) / (2 * (bps))) - 2) + +/* The Zilog register set */ + +#define FLAG 0x7e + +/* Write Register 0 */ +#define R0 0 /* Register selects */ +#define R1 1 +#define R2 2 +#define R3 3 +#define R4 4 +#define R5 5 +#define R6 6 +#define R7 7 +#define R8 8 +#define R9 9 +#define R10 10 +#define R11 11 +#define R12 12 +#define R13 13 +#define R14 14 +#define R15 15 + +#define NULLCODE 0 /* Null Code */ +#define POINT_HIGH 0x8 /* Select upper half of registers */ +#define RES_EXT_INT 0x10 /* Reset Ext. Status Interrupts */ +#define SEND_ABORT 0x18 /* HDLC Abort */ +#define RES_RxINT_FC 0x20 /* Reset RxINT on First Character */ +#define RES_Tx_P 0x28 /* Reset TxINT Pending */ +#define ERR_RES 0x30 /* Error Reset */ +#define RES_H_IUS 0x38 /* Reset highest IUS */ + +#define RES_Rx_CRC 0x40 /* Reset Rx CRC Checker */ +#define RES_Tx_CRC 0x80 /* Reset Tx CRC Checker */ +#define RES_EOM_L 0xC0 /* Reset EOM latch */ + +/* Write Register 1 */ + +#define EXT_INT_ENAB 0x1 /* Ext Int Enable */ +#define TxINT_ENAB 0x2 /* Tx Int Enable */ +#define PAR_SPEC 0x4 /* Parity is special condition */ + +#define RxINT_DISAB 0 /* Rx Int Disable */ +#define RxINT_FCERR 0x8 /* Rx Int on First Character Only or Error */ +#define INT_ALL_Rx 0x10 /* Int on all Rx Characters or error */ +#define INT_ERR_Rx 0x18 /* Int on error only */ + +#define WT_RDY_RT 0x20 /* Wait/Ready on R/T */ +#define WT_FN_RDYFN 0x40 /* Wait/FN/Ready FN */ +#define WT_RDY_ENAB 0x80 /* Wait/Ready Enable */ + +/* Write Register #2 (Interrupt Vector) */ + +/* Write Register 3 */ + +#define RxENABLE 0x1 /* Rx Enable */ +#define SYNC_L_INH 0x2 /* Sync Character Load Inhibit */ +#define ADD_SM 0x4 /* Address Search Mode (SDLC) */ +#define RxCRC_ENAB 0x8 /* Rx CRC Enable */ +#define ENT_HM 0x10 /* Enter Hunt Mode */ +#define AUTO_ENAB 0x20 /* Auto Enables */ +#define Rx5 0x0 /* Rx 5 Bits/Character */ +#define Rx7 0x40 /* Rx 7 Bits/Character */ +#define Rx6 0x80 /* Rx 6 Bits/Character */ +#define Rx8 0xc0 /* Rx 8 Bits/Character */ + +/* Write Register 4 */ + +#define PAR_ENA 0x1 /* Parity Enable */ +#define PAR_EVEN 0x2 /* Parity Even/Odd* */ + +#define SYNC_ENAB 0 /* Sync Modes Enable */ +#define SB1 0x4 /* 1 stop bit/char */ +#define SB15 0x8 /* 1.5 stop bits/char */ +#define SB2 0xc /* 2 stop bits/char */ + +#define MONSYNC 0 /* 8 Bit Sync character */ +#define BISYNC 0x10 /* 16 bit sync character */ +#define SDLC 0x20 /* SDLC Mode (01111110 Sync Flag) */ +#define EXTSYNC 0x30 /* External Sync Mode */ + +#define X1CLK 0x0 /* x1 clock mode */ +#define X16CLK 0x40 /* x16 clock mode */ +#define X32CLK 0x80 /* x32 clock mode */ +#define X64CLK 0xC0 /* x64 clock mode */ + +/* Write Register 5 */ + +#define TxCRC_ENAB 0x1 /* Tx CRC Enable */ +#define RTS 0x2 /* RTS */ +#define SDLC_CRC 0x4 /* SDLC/CRC-16 */ +#define TxENAB 0x8 /* Tx Enable */ +#define SND_BRK 0x10 /* Send Break */ +#define Tx5 0x0 /* Tx 5 bits (or less)/character */ +#define Tx7 0x20 /* Tx 7 bits/character */ +#define Tx6 0x40 /* Tx 6 bits/character */ +#define Tx8 0x60 /* Tx 8 bits/character */ +#define DTR 0x80 /* DTR */ + +/* Write Register 6 (Sync bits 0-7/SDLC Address Field) */ + +/* Write Register 7 (Sync bits 8-15/SDLC 01111110) */ + +/* Write Register 8 (transmit buffer) */ + +/* Write Register 9 (Master interrupt control) */ +#define VIS 1 /* Vector Includes Status */ +#define NV 2 /* No Vector */ +#define DLC 4 /* Disable Lower Chain */ +#define MIE 8 /* Master Interrupt Enable */ +#define STATHI 0x10 /* Status high */ +#define NORESET 0 /* No reset on write to R9 */ +#define CHRB 0x40 /* Reset channel B */ +#define CHRA 0x80 /* Reset channel A */ +#define FHWRES 0xc0 /* Force hardware reset */ + +/* Write Register 10 (misc control bits) */ +#define BIT6 1 /* 6 bit/8bit sync */ +#define LOOPMODE 2 /* SDLC Loop mode */ +#define ABUNDER 4 /* Abort/flag on SDLC xmit underrun */ +#define MARKIDLE 8 /* Mark/flag on idle */ +#define GAOP 0x10 /* Go active on poll */ +#define NRZ 0 /* NRZ mode */ +#define NRZI 0x20 /* NRZI mode */ +#define FM1 0x40 /* FM1 (transition = 1) */ +#define FM0 0x60 /* FM0 (transition = 0) */ +#define CRCPS 0x80 /* CRC Preset I/O */ + +/* Write Register 11 (Clock Mode control) */ +#define TRxCXT 0 /* TRxC = Xtal output */ +#define TRxCTC 1 /* TRxC = Transmit clock */ +#define TRxCBR 2 /* TRxC = BR Generator Output */ +#define TRxCDP 3 /* TRxC = DPLL output */ +#define TRxCOI 4 /* TRxC O/I */ +#define TCRTxCP 0 /* Transmit clock = RTxC pin */ +#define TCTRxCP 8 /* Transmit clock = TRxC pin */ +#define TCBR 0x10 /* Transmit clock = BR Generator output */ +#define TCDPLL 0x18 /* Transmit clock = DPLL output */ +#define RCRTxCP 0 /* Receive clock = RTxC pin */ +#define RCTRxCP 0x20 /* Receive clock = TRxC pin */ +#define RCBR 0x40 /* Receive clock = BR Generator output */ +#define RCDPLL 0x60 /* Receive clock = DPLL output */ +#define RTxCX 0x80 /* RTxC Xtal/No Xtal */ + +/* Write Register 12 (lower byte of baud rate generator time constant) */ + +/* Write Register 13 (upper byte of baud rate generator time constant) */ + +/* Write Register 14 (Misc control bits) */ +#define BRENABL 1 /* Baud rate generator enable */ +#define BRSRC 2 /* Baud rate generator source */ +#define DTRREQ 4 /* DTR/Request function */ +#define AUTOECHO 8 /* Auto Echo */ +#define LOOPBAK 0x10 /* Local loopback */ +#define SEARCH 0x20 /* Enter search mode */ +#define RMC 0x40 /* Reset missing clock */ +#define DISDPLL 0x60 /* Disable DPLL */ +#define SSBR 0x80 /* Set DPLL source = BR generator */ +#define SSRTxC 0xa0 /* Set DPLL source = RTxC */ +#define SFMM 0xc0 /* Set FM mode */ +#define SNRZI 0xe0 /* Set NRZI mode */ + +/* Write Register 15 (external/status interrupt control) */ +#define ZCIE 2 /* Zero count IE */ +#define DCDIE 8 /* DCD IE */ +#define SYNCIE 0x10 /* Sync/hunt IE */ +#define CTSIE 0x20 /* CTS IE */ +#define TxUIE 0x40 /* Tx Underrun/EOM IE */ +#define BRKIE 0x80 /* Break/Abort IE */ + + +/* Read Register 0 */ +#define Rx_CH_AV 0x1 /* Rx Character Available */ +#define ZCOUNT 0x2 /* Zero count */ +#define Tx_BUF_EMP 0x4 /* Tx Buffer empty */ +#define DCD 0x8 /* DCD */ +#define SYNC_HUNT 0x10 /* Sync/hunt */ +#define CTS 0x20 /* CTS */ +#define TxEOM 0x40 /* Tx underrun */ +#define BRK_ABRT 0x80 /* Break/Abort */ + +/* Read Register 1 */ +#define ALL_SNT 0x1 /* All sent */ +/* Residue Data for 8 Rx bits/char programmed */ +#define RES3 0x8 /* 0/3 */ +#define RES4 0x4 /* 0/4 */ +#define RES5 0xc /* 0/5 */ +#define RES6 0x2 /* 0/6 */ +#define RES7 0xa /* 0/7 */ +#define RES8 0x6 /* 0/8 */ +#define RES18 0xe /* 1/8 */ +#define RES28 0x0 /* 2/8 */ +/* Special Rx Condition Interrupts */ +#define PAR_ERR 0x10 /* Parity error */ +#define Rx_OVR 0x20 /* Rx Overrun Error */ +#define CRC_ERR 0x40 /* CRC/Framing Error */ +#define END_FR 0x80 /* End of Frame (SDLC) */ + +/* Read Register 2 (channel b only) - Interrupt vector */ + +/* Read Register 3 (interrupt pending register) ch a only */ +#define CHBEXT 0x1 /* Channel B Ext/Stat IP */ +#define CHBTxIP 0x2 /* Channel B Tx IP */ +#define CHBRxIP 0x4 /* Channel B Rx IP */ +#define CHAEXT 0x8 /* Channel A Ext/Stat IP */ +#define CHATxIP 0x10 /* Channel A Tx IP */ +#define CHARxIP 0x20 /* Channel A Rx IP */ + +/* Read Register 8 (receive data register) */ + +/* Read Register 10 (misc status bits) */ +#define ONLOOP 2 /* On loop */ +#define LOOPSEND 0x10 /* Loop sending */ +#define CLK2MIS 0x40 /* Two clocks missing */ +#define CLK1MIS 0x80 /* One clock missing */ + +/* Read Register 12 (lower byte of baud rate generator constant) */ + +/* Read Register 13 (upper byte of baud rate generator constant) */ + +/* Read Register 15 (value of WR 15) */ + +/* Misc macros */ +#define ZS_CLEARERR(channel) (channel->control = ERR_RES) +#define ZS_CLEARFIFO(channel) do { volatile unsigned char garbage; \ + garbage = channel->data; \ + udelay(2); \ + garbage = channel->data; \ + udelay(2); \ + garbage = channel->data; \ + udelay(2); } while(0) + +#endif /* !(_SPARC_SERIAL_H) */ diff --git a/drivers/scsi/Makefile b/drivers/scsi/Makefile index d91ceb2b430f..bfdbb86e9b8c 100644 --- a/drivers/scsi/Makefile +++ b/drivers/scsi/Makefile @@ -84,6 +84,38 @@ else endif endif +ifeq ($(CONFIG_A3000_SCSI),y) +L_OBJS += a3000.o wd33c93.o +else + ifeq ($(CONFIG_A3000_SCSI),m) + M_OBJS += a3000.o wd33c93.o + endif +endif + +ifeq ($(CONFIG_A2091_SCSI),y) +L_OBJS += a2091.o wd33c93.o +else + ifeq ($(CONFIG_A2091_SCSI),m) + M_OBJS += a2091.o wd33c93.o + endif +endif + +ifeq ($(CONFIG_GVP11_SCSI),y) +L_OBJS += gvp11.o wd33c93.o +else + ifeq ($(CONFIG_GVP11_SCSI),m) + M_OBJS += gvp11.o wd33c93.o + endif +endif + +ifeq ($(CONFIG_ATARI_SCSI),y) +L_OBJS += atari_scsi.o +else + ifeq ($(CONFIG_ATARI_SCSI),m) + M_OBJS += atari_scsi.o + endif +endif + ifeq ($(CONFIG_SCSI_PPA),y) L_OBJS += ppa.o else @@ -168,6 +200,14 @@ else endif endif +ifeq ($(CONFIG_SCSI_SUNESP),y) +L_OBJS += esp.o +else + ifeq ($(CONFIG_SCSI_SUNESP),m) + M_OBJS += esp.o + endif +endif + ifeq ($(CONFIG_SCSI_DEBUG),y) L_OBJS += scsi_debug.o else diff --git a/drivers/scsi/NCR5380.h b/drivers/scsi/NCR5380.h index fd0ccf81cefd..ad86a96065a5 100644 --- a/drivers/scsi/NCR5380.h +++ b/drivers/scsi/NCR5380.h @@ -298,7 +298,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd); #ifndef NCR5380_reset static #endif -int NCR5380_reset (Scsi_Cmnd *cmd); +int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int); #ifndef NCR5380_queue_command static #endif diff --git a/drivers/scsi/a2091.c b/drivers/scsi/a2091.c index dd1d6fefd2b7..5a470fac38c7 100644 --- a/drivers/scsi/a2091.c +++ b/drivers/scsi/a2091.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include diff --git a/drivers/scsi/a2091.h b/drivers/scsi/a2091.h index 08f398e2c79a..9067f6d97eee 100644 --- a/drivers/scsi/a2091.h +++ b/drivers/scsi/a2091.h @@ -1,6 +1,6 @@ #ifndef A2091_H -/* $Id: a2091.h,v 1.3 1996/03/12 20:41:46 root Exp root $ +/* $Id: a2091.h,v 1.4 1996/04/25 20:57:48 root Exp root $ * * Header file for the Commodore A2091 Zorro II SCSI controller for Linux * @@ -14,7 +14,7 @@ int a2091_detect(Scsi_Host_Template *); const char *wd33c93_info(void); int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int wd33c93_abort(Scsi_Cmnd *); -int wd33c93_reset(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *, unsigned int); #ifndef NULL #define NULL 0 diff --git a/drivers/scsi/a3000.c b/drivers/scsi/a3000.c index 5293d3cf199b..2139d5abad66 100644 --- a/drivers/scsi/a3000.c +++ b/drivers/scsi/a3000.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include diff --git a/drivers/scsi/a3000.h b/drivers/scsi/a3000.h index b36d52b22eb8..a29fa97d8a0b 100644 --- a/drivers/scsi/a3000.h +++ b/drivers/scsi/a3000.h @@ -1,6 +1,6 @@ #ifndef A3000_H -/* $Id: a3000.h,v 1.2 1996/02/29 22:10:29 root Exp root $ +/* $Id: a3000.h,v 1.3 1996/04/25 20:58:09 root Exp root $ * * Header file for the Amiga 3000 built-in SCSI controller for Linux * @@ -14,7 +14,7 @@ int a3000_detect(Scsi_Host_Template *); const char *wd33c93_info(void); int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int wd33c93_abort(Scsi_Cmnd *); -int wd33c93_reset(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *, unsigned int); #ifndef NULL #define NULL 0 diff --git a/drivers/scsi/atari_NCR5380.c b/drivers/scsi/atari_NCR5380.c index 0cffe26b37e1..fee15cf12e9a 100644 --- a/drivers/scsi/atari_NCR5380.c +++ b/drivers/scsi/atari_NCR5380.c @@ -47,7 +47,7 @@ * inside the execution of NCR5380_intr(), leading to recursive * calls. * - * - I've added a function merge_consecutive_buffers() that trys to + * - I've added a function merge_consecutive_buffers() that tries to * merge scatter-gather buffers that are located at consecutive * physical addresses and can be processed with the same DMA setup. * Since most scatter-gather operations work on a page (4K) of @@ -1995,7 +1995,7 @@ static int do_abort (struct Scsi_Host *host) * other phase and will have to source/sink data. * * We really don't care what value was on the bus or what value - * the target see's, so we just handshake. + * the target sees, so we just handshake. */ while (!(tmp = NCR5380_read(STATUS_REG)) & SR_REQ); @@ -2280,7 +2280,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) printk("scsi%d: target %d lun %d linked command complete.\n", HOSTNO, cmd->target, cmd->lun); #endif - /* Enable reselect interupts */ + /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); /* * Sanity check : A linked command should only terminate @@ -2348,7 +2348,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) #else hostdata->busy[cmd->target] &= ~(1 << cmd->lun); #endif - /* Enable reselect interupts */ + /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); /* @@ -2429,7 +2429,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) case MESSAGE_REJECT: /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interupts */ + /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); switch (hostdata->last_message) { case HEAD_OF_QUEUE_TAG: @@ -2439,7 +2439,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) * queuing, even though it announced this ability in * its INQUIRY data ?!? (maybe only this LUN?) Ok, * clear 'tagged_supported' and lock the LUN, since - * the command is treated as untagged furtheron. + * the command is treated as untagged further on. */ cmd->device->tagged_supported = 0; hostdata->busy[cmd->target] |= (1 << cmd->lun); @@ -2494,7 +2494,7 @@ static void NCR5380_information_transfer (struct Scsi_Host *instance) case RESTORE_POINTERS: /* Accept message by clearing ACK */ NCR5380_write(INITIATOR_COMMAND_REG, ICR_BASE); - /* Enable reselect interupts */ + /* Enable reselect interrupts */ NCR5380_write(SELECT_ENABLE_REG, hostdata->id_mask); break; case EXTENDED_MESSAGE: @@ -2713,7 +2713,7 @@ static void NCR5380_reselect (struct Scsi_Host *instance) #ifdef SUPPORT_TAGS /* If the phase is still MSGIN, the target wants to send some more * messages. In case it supports tagged queuing, this is probably a - * SIMPLE_QEUE_TAG for the I_T_L_Q nexus. + * SIMPLE_QUEUE_TAG for the I_T_L_Q nexus. */ tag = TAG_NONE; if (phase == PHASE_MSGIN && setup_use_tagged_queuing) { @@ -3002,7 +3002,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) /* - * Function : int NCR5380_reset (Scsi_Cmnd *cmd) + * Function : int NCR5380_reset (Scsi_Cmnd *cmd, unsigned int reset_flags) * * Purpose : reset the SCSI bus. * @@ -3010,7 +3010,7 @@ int NCR5380_abort (Scsi_Cmnd *cmd) * */ -static int NCR5380_reset( Scsi_Cmnd *cmd ) +static int NCR5380_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) { #if 0 SETUP_HOSTDATA(cmd->host); @@ -3045,7 +3045,7 @@ static int NCR5380_reset( Scsi_Cmnd *cmd ) /* After the reset, there are no more connected or disconnected commands * and no busy units; to avoid problems with re-inserting the commands * into the issue_queue (via scsi_done()), the aborted commands are - * remebered in local variables first. + * remembered in local variables first. */ save_flags(flags); cli(); diff --git a/drivers/scsi/atari_scsi.c b/drivers/scsi/atari_scsi.c index 101aa871f612..01aa7372cef9 100644 --- a/drivers/scsi/atari_scsi.c +++ b/drivers/scsi/atari_scsi.c @@ -1,5 +1,5 @@ /* - * atari_scsi.c -- Device dependant functions for the Atari generic SCSI port + * atari_scsi.c -- Device dependent functions for the Atari generic SCSI port * * Copyright 1994 Roman Hodek * @@ -40,19 +40,19 @@ /* totally empty if there is a lot of disk traffic. */ /* */ /* For this reasons I decided to employ a more elaborate scheme: */ -/* - First, we give up the lock everytime we can (for fairness), this */ +/* - First, we give up the lock every time we can (for fairness), this */ /* means every time a command finishes and there are no other commands */ /* on the disconnected queue. */ /* - If there are others waiting to lock the DMA chip, we stop */ -/* issueing commands, i.e. moving them onto the issue queue. */ +/* issuing commands, i.e. moving them onto the issue queue. */ /* Because of that, the disconnected queue will run empty in a */ /* while. Instead we go to sleep on a 'fairness_queue'. */ /* - If the lock is released, all processes waiting on the fairness */ -/* queue will be woken. The first of them trys to re-lock the DMA, */ +/* queue will be woken. The first of them tries to re-lock the DMA, */ /* the others wait for the first to finish this task. After that, */ /* they can all run on and do their commands... */ /* This sounds complicated (and it is it :-(), but it seems to be a */ -/* good compromise between fairness and performance: As long as noone */ +/* good compromise between fairness and performance: As long as no one */ /* else wants to work with the ST-DMA chip, SCSI can go along as */ /* usual. If now someone else comes, this behaviour is changed to a */ /* "fairness mode": just already initiated commands are finished and */ @@ -324,7 +324,7 @@ static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy) #endif /* Look if it was the DMA that has interrupted: First possibility - * is that a bus error occured... + * is that a bus error occurred... */ if (dma_stat & 0x80) { if (!scsi_dma_is_ignored_buserr( dma_stat )) { @@ -335,7 +335,7 @@ static void scsi_tt_intr (int irq, struct pt_regs *fp, void *dummy) } /* If the DMA is active but not finished, we have the the case - * that some other 5380 interrupt occured within the DMA transfer. + * that some other 5380 interrupt occurred within the DMA transfer. * This means we have residual bytes, if the desired end address * is not yet reached. Maybe we have to fetch some bytes from the * rest data register, too. The residual must be calculated from @@ -537,7 +537,7 @@ falcon_release_lock_if_possible( struct NCR5380_hostdata * hostdata ) } /* This function manages the locking of the ST-DMA. - * If the DMA isn't locked already for SCSI, it trys to lock it by + * If the DMA isn't locked already for SCSI, it tries to lock it by * calling stdma_lock(). But if the DMA is locked by the SCSI code and * there are other drivers waiting for the chip, we do not issue the * command immediately but wait on 'falcon_fairness_queue'. We will be @@ -585,7 +585,7 @@ static void falcon_get_lock( void ) /* This is the wrapper function for NCR5380_queue_command(). It just - * trys to get the lock on the ST-DMA (see above) and then calls the + * tries to get the lock on the ST-DMA (see above) and then calls the * original function. */ @@ -772,7 +772,7 @@ int atari_scsi_release (struct Scsi_Host *sh) remove_isr (IRQ_TT_MFP_SCSIDMA, scsi_dma_buserr); #endif } - if (atari_dma_bufffer) + if (atari_dma_buffer) scsi_init_free (atari_dma_buffer, STRAM_BUFFER_SIZE); return 1; } @@ -840,7 +840,7 @@ void atari_scsi_setup( char *str, int *ints ) #endif } -int atari_scsi_reset( Scsi_Cmnd *cmd ) +int atari_scsi_reset( Scsi_Cmnd *cmd, unsigned int reset_flags) { int rv; struct NCR5380_hostdata *hostdata = @@ -866,7 +866,7 @@ int atari_scsi_reset( Scsi_Cmnd *cmd ) #endif /* REAL_DMA */ } - rv = NCR5380_reset( cmd ); + rv = NCR5380_reset(cmd, reset_flags); /* Re-enable ints */ if (IS_A_TT()) { @@ -955,7 +955,7 @@ unsigned long atari_scsi_dma_setup( struct Scsi_Host *instance, void *data, * ++roman: For the Medusa, there's no need at all for that cache stuff, * because the hardware does bus snooping (fine!). */ - dma_cache_maintainance( addr, count, dir ); + dma_cache_maintenance( addr, count, dir ); if (count == 0) printk("SCSI warning: DMA programmed for 0 bytes !\n"); diff --git a/drivers/scsi/atari_scsi.h b/drivers/scsi/atari_scsi.h index 85546de9f228..4ead7ed9de46 100644 --- a/drivers/scsi/atari_scsi.h +++ b/drivers/scsi/atari_scsi.h @@ -22,7 +22,7 @@ int atari_scsi_abort (Scsi_Cmnd *); int atari_scsi_detect (Scsi_Host_Template *); const char *atari_scsi_info (struct Scsi_Host *); int atari_scsi_queue_command (Scsi_Cmnd *, void (*done) (Scsi_Cmnd *)); -int atari_scsi_reset (Scsi_Cmnd *); +int atari_scsi_reset (Scsi_Cmnd *, unsigned int); int atari_scsi_proc_info (char *, char **, off_t, int, int, int); #ifdef MODULE int atari_scsi_release (struct Scsi_Host *); @@ -34,7 +34,7 @@ int atari_scsi_release (struct Scsi_Host *); * values should work, too; try it! (but cmd_per_lun costs memory!) */ /* But there seems to be a bug somewhere that requires CAN_QUEUE to be - * 2*CMD_OER_LUN. At least on a TT, no suprious timeouts seen since + * 2*CMD_OER_LUN. At least on a TT, no spurious timeouts seen since * changed CMD_PER_LUN... */ /* Note: The Falcon currently uses 8/1 setting due to unsolved problems with diff --git a/drivers/scsi/gvp11.c b/drivers/scsi/gvp11.c index b3c67d9e1081..a81977919e08 100644 --- a/drivers/scsi/gvp11.c +++ b/drivers/scsi/gvp11.c @@ -1,6 +1,7 @@ #include #include #include +#include #include #include diff --git a/drivers/scsi/gvp11.h b/drivers/scsi/gvp11.h index 35ad1d2c76d9..00bbfb5d4b33 100644 --- a/drivers/scsi/gvp11.h +++ b/drivers/scsi/gvp11.h @@ -1,6 +1,6 @@ #ifndef GVP11_H -/* $Id: gvp11.h,v 1.4 1996/03/12 20:42:40 root Exp root $ +/* $Id: gvp11.h,v 1.5 1996/04/25 20:58:31 root Exp root $ * * Header file for the GVP Series II SCSI controller for Linux * @@ -15,7 +15,7 @@ int gvp11_detect(Scsi_Host_Template *); const char *wd33c93_info(void); int wd33c93_queuecommand(Scsi_Cmnd *, void (*done)(Scsi_Cmnd *)); int wd33c93_abort(Scsi_Cmnd *); -int wd33c93_reset(Scsi_Cmnd *); +int wd33c93_reset(Scsi_Cmnd *, unsigned int); #ifndef NULL #define NULL 0 diff --git a/drivers/scsi/hosts.c b/drivers/scsi/hosts.c index b728ea9dbcc1..9c2076c5c9dc 100644 --- a/drivers/scsi/hosts.c +++ b/drivers/scsi/hosts.c @@ -41,6 +41,22 @@ #include "hosts.h" +#ifdef CONFIG_A3000_SCSI +#include "a3000.h" +#endif + +#ifdef CONFIG_A2091_SCSI +#include "a2091.h" +#endif + +#ifdef CONFIG_GVP11_SCSI +#include "gvp11.h" +#endif + +#ifdef CONFIG_ATARI_SCSI +#include "atari_scsi.h" +#endif + #ifdef CONFIG_SCSI_ADVANSYS #include "advansys.h" #endif @@ -147,7 +163,7 @@ /* -static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.10 1996/04/16 08:09:36 davem Exp $"; +static const char RCSid[] = "$Header: /usr/src/linux-1.3.95/drivers/scsi/RCS/hosts.c,v 1.7 1996/04/25 22:21:56 root Exp root $"; */ /* @@ -179,6 +195,24 @@ Scsi_Host_Template * scsi_hosts = NULL; static Scsi_Host_Template builtin_scsi_hosts[] = { +#ifdef CONFIG_AMIGA +#ifdef CONFIG_A3000_SCSI + A3000_SCSI, +#endif +#ifdef CONFIG_A2091_SCSI + A2091_SCSI, +#endif +#ifdef CONFIG_GVP11_SCSI + GVP11_SCSI, +#endif +#endif + +#ifdef CONFIG_ATARI +#ifdef CONFIG_ATARI_SCSI + ATARI_SCSI, +#endif +#endif + #ifdef CONFIG_SCSI_ADVANSYS ADVANSYS, #endif diff --git a/drivers/scsi/scsi.c b/drivers/scsi/scsi.c index 72957c487c7e..57bc3fc500a4 100644 --- a/drivers/scsi/scsi.c +++ b/drivers/scsi/scsi.c @@ -288,7 +288,7 @@ static struct dev_info device_list[] = {"NRC","MBR-7","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-602X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, {"PIONEER","CD-ROM DRM-604X","*", BLIST_FORCELUN | BLIST_SINGLELUN}, -{"EMULEX","MD21/S2 ESDI","*",BLIST_FORCELUN | BLIST_SINGLELUN}, +{"EMULEX","MD21/S2 ESDI","*",BLIST_SINGLELUN}, /* * Must be at end of list... */ diff --git a/drivers/scsi/wd33c93.c b/drivers/scsi/wd33c93.c index 678bebfad3b7..c0cafa5a88e0 100644 --- a/drivers/scsi/wd33c93.c +++ b/drivers/scsi/wd33c93.c @@ -28,18 +28,23 @@ * * - Target Disconnection/Reconnection is now supported. Any * system with more than one device active on the SCSI bus - * will benefit from this. + * will benefit from this. The driver defaults to what I'm + * 'adaptive disconnect' - meaning that each command is + * evaluated individually as to whether or not it should + * be run with the option to disconnect/reslect (if the + * device chooses), or as a "SCSI-bus-hog". * - * - Synchronous data transfers are now supported. The driver - * automatically uses this faster protocol with any device - * able to handle it. + * - Synchronous data transfers are now supported. Because of + * a few devices that choke after telling the driver that + * they can do sync transfers, we don't automatically use + * this faster protocol - it can be enabled via the command- + * line on a device-by-device basis. * * - Runtime operating parameters can now be specified through - * either the 'amiboot' or the LILO command line. Something - * like: - * "wd33c93=0x0000" - * The value 0x0000 results in the defaults being used; bits - * are defined in wd33c93.h. + * the 'amiboot' or the 'insmod' command line. For amiboot do: + * "amiboot [usual stuff] wd33c93=blah,blah,blah" + * The defaults should be good for most people. See the comment + * for 'setup_strings' below for more details. * * - The old driver relied exclusively on what the Western Digital * docs call "Combination Level 2 Commands", which are a great @@ -52,7 +57,7 @@ * * * TODO: - * more speed. tagged queuing. + * more speed. linked commands. * * * People with bug reports, wish-lists, complaints, comments, @@ -67,18 +72,33 @@ #include #include #include +#include + +#if LINUX_VERSION_CODE >= 0x010300 #include +#else +#include "../block/blk.h" +#endif + #include "scsi.h" #include "hosts.h" #include "wd33c93.h" +#ifdef MODULE +#include +#endif -#define SYNC_DEBUG +/* Leave this undefined for now - need to make some changes in the + * a3000/a2019/gvp11 files to get it working right + */ +/*#define PROC_INTERFACE*/ /* add code for /proc/scsi/wd33c93/xxx interface */ -#define DEBUGGING_ON +#define SYNC_DEBUG /* extra info on sync negotiation printed */ +#define DEBUGGING_ON /* enable command-line debugging bitmask */ +#define DEBUG_DEFAULTS 0 /* default debugging bitmask */ -#define WD33C93_VERSION "1.17" -#define WD33C93_DATE "06/Feb/1996" +#define WD33C93_VERSION "1.21" +#define WD33C93_DATE "20/Apr/1996" #ifdef DEBUGGING_ON #define DB(f,a) if (hostdata->args & (f)) a; @@ -92,15 +112,59 @@ /* - * setup_default is a bunch of bits that define some of the operating - * parameters and settings for this driver. It is used unless a LILO - * or insmod command line has been specified, in which case setup_default - * is _completely_ ignored. Take a look at the "defines for hostdata->args" - * section in wd33c93.h - that stuff is what you'd use here if you want - * to change the defaults. + * setup_strings is an array of strings that define some of the operating + * parameters and settings for this driver. It is used unless an amiboot + * or insmod command line has been specified, in which case those settings + * are combined with the ones here. The driver recognizes the following + * keywords (lower case required) and arguments: + * + * - nosync:bitmask -bitmask is a byte where the 1st 7 bits correspond with + * the 7 possible SCSI devices. Set a bit to prevent sync + * negotiation on that device. To maintain backwards + * compatability, a command-line such as "wd33c93=255" will + * be automatically translated to "wd33c93=nosync:0xff". + * - period:ns -ns is the minimum # of nanoseconds in a SCSI data transfer + * period. Default is 500; acceptable values are 250 - 1000. + * - disconnect:x -x = 0 to never allow disconnects, 2 to always allow them. + * x = 1 does 'adaptive' disconnects, which is the default + * and generally the best choice. + * - debug:x -If 'DEBUGGING_ON' is defined, x is a bit mask that causes + * various types of debug output to printed - see the DB_xxx + * defines in wd33c93.h + * - clock:x -x = clock input in MHz for WD33c93 chip. Normal values + * would be from 8 through 20. Default is 8. + * - next -No argument. Used to separate blocks of keywords when + * there's more than one host adapter in the system. + * + * Syntax Notes: + * - Numeric arguments can be decimal or the '0x' form of hex notation. There + * _must_ be a colon between a keyword and its numeric argument, with no + * spaces. + * - Keywords are separated by commas, no spaces, in the standard kernel + * command-line manner, except in the case of 'setup_strings[]' (see + * below), which is simply a C array of pointers to char. Each element + * in the array is a string comprising one keyword & argument. + * - A keyword in the 'nth' comma-separated command-line member will overwrite + * the 'nth' element of setup_strings[]. A blank command-line member (in + * other words, a comma with no preceding keyword) will _not_ overwrite + * the corresponding setup_strings[] element. + * - If a keyword is used more than once, the first one applies to the first + * SCSI host found, the second to the second card, etc, unless the 'next' + * keyword is used to change the order. + * + * Some amiboot examples (for insmod, use 'setup_strings' instead of 'wd33c93'): + * - wd33c93=nosync:255 + * - wd33c93=disconnect:2,nosync:0x08,period:250 + * - wd33c93=debug:0x1c */ -static unsigned int setup_default = 0; +static char *setup_strings[] = + {"","","","","","","","","","","",""}; + +#ifdef PROC_INTERFACE +unsigned long disc_allowed_total; +unsigned long disc_taken_total; +#endif inline uchar read_wd33c93(wd33c93_regs *regp,uchar reg_num) @@ -176,27 +240,32 @@ static struct sx_period sx_table[] = { {1000,0x00}, {0, 0} }; -uchar calc_sync_xfer(unsigned int period, unsigned int offset) +int round_period(unsigned int period) { -uchar result; int x; - period *= 4; /* convert SDTR code to ns */ - result = 0x00; for (x=1; sx_table[x].period_ns; x++) { if ((period <= sx_table[x-0].period_ns) && (period > sx_table[x-1].period_ns)) { - result = sx_table[x].reg_value; - break; + return x; } } + return 7; +} + +uchar calc_sync_xfer(unsigned int period, unsigned int offset) +{ +uchar result; + + period *= 4; /* convert SDTR code to ns */ + result = sx_table[round_period(period)].reg_value; result |= (offset < OPTIMUM_SX_OFF)?offset:OPTIMUM_SX_OFF; return result; } -static void wd33c93_execute(struct Scsi_Host *instance); +void wd33c93_execute(struct Scsi_Host *instance); int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)) { @@ -204,13 +273,14 @@ struct WD33C93_hostdata *hostdata; Scsi_Cmnd *tmp; unsigned long flags; + + save_flags(flags); + cli(); hostdata = (struct WD33C93_hostdata *)cmd->host->hostdata; DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) - -/* - * Set up a few fields in the Scsi_Cmnd structure for our own use: +/* Set up a few fields in the Scsi_Cmnd structure for our own use: * - host_scribble is the pointer to the next cmd in the input queue * - scsi_done points to the routine we call when a cmd is finished * - result is what you'd expect @@ -230,6 +300,9 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) * - SCp.this_residual is the size of that buffer * - SCp.buffer points to the current scatter-gather buffer * - SCp.buffers_residual tells us how many S.G. buffers there are + * - SCp.have_data_in is not used + * - SCp.sent_command is not used + * - SCp.phase records this command's SRCID_ER bit setting */ if (cmd->use_sg) { @@ -255,19 +328,16 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) * sense data is not lost before REQUEST_SENSE executes. */ - save_flags(flags); - cli(); if (!(hostdata->input_Q) || (cmd->cmnd[0] == REQUEST_SENSE)) { cmd->host_scribble = (uchar *)hostdata->input_Q; hostdata->input_Q = cmd; } - else { + else { /* find the end of the queue */ for (tmp=(Scsi_Cmnd *)hostdata->input_Q; tmp->host_scribble; tmp=(Scsi_Cmnd *)tmp->host_scribble) ; tmp->host_scribble = (uchar *)cmd; } - restore_flags(flags); /* We know that there's at least one command in 'input_Q' now. * Go see if any of them are runnable! @@ -275,7 +345,9 @@ DB(DB_QUEUE_COMMAND,printk("Q-%d-%02x-%ld( ",cmd->target,cmd->cmnd[0],cmd->pid)) wd33c93_execute(cmd->host); -DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid)) +DB(DB_QUEUE_COMMAND,printk(")Q-%ld ",cmd->pid)) + + restore_flags(flags); return 0; } @@ -287,7 +359,7 @@ DB(DB_QUEUE_COMMAND,printk(")Q-%d-%02x-%ld ",cmd->target,cmd->cmnd[0],cmd->pid)) * the input_Q, using the first command we find that's intended * for a currently non-busy target/lun. */ -static void wd33c93_execute (struct Scsi_Host *instance) +void wd33c93_execute (struct Scsi_Host *instance) { struct WD33C93_hostdata *hostdata; wd33c93_regs *regp; @@ -301,10 +373,12 @@ int i; hostdata = (struct WD33C93_hostdata *)instance->hostdata; regp = hostdata->regp; -DB(DB_EXECUTE,printk("EX( ")) +DB(DB_EXECUTE,printk("EX(")) if (hostdata->selecting || hostdata->connected) { + DB(DB_EXECUTE,printk(")EX-0 ")) + restore_flags(flags); return; } @@ -326,18 +400,19 @@ DB(DB_EXECUTE,printk(")EX-0 ")) /* quit if queue empty or all possible targets are busy */ if (!cmd) { + DB(DB_EXECUTE,printk(")EX-1 ")) + restore_flags(flags); return; } - /* remove command from queue, put it in selecting */ + /* remove command from queue */ if (prev) prev->host_scribble = cmd->host_scribble; else hostdata->input_Q = (Scsi_Cmnd *)cmd->host_scribble; - hostdata->selecting = cmd; /* * Start the selection process @@ -348,22 +423,78 @@ DB(DB_EXECUTE,printk(")EX-1 ")) else write_wd33c93(regp, WD_DESTINATION_ID, cmd->target | DSTID_DPD); +/* Now we need to figure out whether or not this command is a good + * candidate for disconnect/reselect. We guess to the best of our + * ability, based on a set of hierarchical rules. When several + * devices are operating simultaneously, disconnects are usually + * an advantage. In a single device system, or if only 1 device + * is being accessed, transfers usually go faster if disconnects + * are not allowed: + * + * + Commands should NEVER disconnect if hostdata->disconnect = + * DIS_NEVER (this holds for tape drives also), and ALWAYS + * disconnect if hostdata->disconnect = DIS_ALWAYS. + * + Tape drive commands should always be allowed to disconnect. + * + Disconnect should be allowed if disconnected_Q isn't empty. + * + Commands should NOT disconnect if input_Q is empty. + * + Disconnect should be allowed if there are commands in input_Q + * for a different target/lun. In this case, the other commands + * should be made disconnect-able, if not already. + * + * I know, I know - this code would flunk me out of any + * "C Programming 101" class ever offered. But it's easy + * to change around and experiment with for now. + */ + + cmd->SCp.phase = 0; /* assume no disconnect */ + if (hostdata->disconnect == DIS_NEVER) + goto no; + if (hostdata->disconnect == DIS_ALWAYS) + goto yes; + if (cmd->device->type == 1) /* tape drive? */ + goto yes; + if (hostdata->disconnected_Q) /* other commands disconnected? */ + goto yes; + if (!(hostdata->input_Q)) /* input_Q empty? */ + goto no; + for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev; + prev=(Scsi_Cmnd *)prev->host_scribble) { + if ((prev->target != cmd->target) || (prev->lun != cmd->lun)) { + for (prev=(Scsi_Cmnd *)hostdata->input_Q; prev; + prev=(Scsi_Cmnd *)prev->host_scribble) + prev->SCp.phase = 1; + goto yes; + } + } + goto no; + +yes: + cmd->SCp.phase = 1; + +#ifdef PROC_INTERFACE + disc_allowed_total++; +#endif + +no: + write_wd33c93(regp, WD_SOURCE_ID, ((cmd->SCp.phase)?SRCID_ER:0)); + write_wd33c93(regp, WD_TARGET_LUN, cmd->lun); - write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - write_wd33c93_count(regp, 0); /* this guarantees a DATA_PHASE interrupt */ + write_wd33c93(regp,WD_SYNCHRONOUS_TRANSFER,hostdata->sync_xfer[cmd->target]); hostdata->busy[cmd->target] |= (1 << cmd->lun); if ((hostdata->level2 == L2_NONE) || (hostdata->sync_stat[cmd->target] == SS_UNSET)) { /* - * Now do a 'Select-With-ATN' command. This will end with + * Do a 'Select-With-ATN' command. This will end with * one of the following interrupts: * CSR_RESEL_AM: failure - can try again later. * CSR_TIMEOUT: failure - give up. * CSR_SELECT: success - proceed. */ + hostdata->selecting = cmd; + /* Every target has its own synchronous transfer setting, kept in the * sync_xfer array, and a corresponding status byte in sync_stat[]. * Each target's sync_stat[] entry is initialized to SX_UNSET, and its @@ -376,19 +507,20 @@ DB(DB_EXECUTE,printk(")EX-1 ")) * make the defaults final. */ if (hostdata->sync_stat[cmd->target] == SS_UNSET) { - if (hostdata->args & (1 << cmd->target)) + if (hostdata->no_sync & (1 << cmd->target)) hostdata->sync_stat[cmd->target] = SS_SET; else hostdata->sync_stat[cmd->target] = SS_FIRST; } hostdata->state = S_SELECTING; + write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */ write_wd33c93_cmd(regp, WD_CMD_SEL_ATN); } else { /* - * Now do a 'Select-With-ATN-Xfer' command. This will end with + * Do a 'Select-With-ATN-Xfer' command. This will end with * one of the following interrupts: * CSR_RESEL_AM: failure - can try again later. * CSR_TIMEOUT: failure - give up. @@ -396,13 +528,15 @@ DB(DB_EXECUTE,printk(")EX-1 ")) */ hostdata->connected = cmd; - hostdata->selecting = NULL; write_wd33c93(regp, WD_COMMAND_PHASE, 0); - /* copy command_descriptor_block into WD chip */ + /* copy command_descriptor_block into WD chip + * (take advantage of auto-incrementing) + */ + regp->SASR = WD_CDB_1; for (i=0; icmd_len; i++) - write_wd33c93(regp, WD_CDB_1+i, cmd->cmnd[i]); + regp->SCMD = cmd->cmnd[i]; /* The wd33c93 only knows about Group 0, 1, and 5 commands when * it's doing a 'select-and-transfer'. To be safe, we write the @@ -412,6 +546,23 @@ DB(DB_EXECUTE,printk(")EX-1 ")) write_wd33c93(regp, WD_OWN_ID, cmd->cmd_len); + /* When doing a non-disconnect command, we can save ourselves a DATA + * phase interrupt later by setting everything up now. + */ + + if (cmd->SCp.phase == 0) { + if (hostdata->dma_setup(cmd, + (IS_DIR_OUT(cmd))?DATA_OUT_DIR:DATA_IN_DIR)) + write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */ + else { + write_wd33c93_count(regp, cmd->SCp.this_residual); + write_wd33c93(regp,WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); + hostdata->dma = D_DMA_RUNNING; + } + } + else + write_wd33c93_count(regp,0); /* guarantee a DATA_PHASE interrupt */ + hostdata->state = S_RUNNING_LEVEL2; write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); } @@ -423,47 +574,38 @@ DB(DB_EXECUTE,printk(")EX-1 ")) * to search the input_Q again... */ -DB(DB_EXECUTE,printk(")EX-2 ")) +DB(DB_EXECUTE,printk("%s%ld)EX-2 ",(cmd->SCp.phase)?"d:":"",cmd->pid)) + restore_flags(flags); } -void transfer_pio(wd33c93_regs *regp, uchar **buf, int *cnt, +void transfer_pio(wd33c93_regs *regp, uchar *buf, int cnt, int data_in_dir, struct WD33C93_hostdata *hostdata) { -uchar *b, asr; -int c; +uchar asr; + +DB(DB_TRANSFER,printk("(%p,%d,%s)",buf,cnt,data_in_dir?"in":"out")) write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); - b = *buf; - c = *cnt; -DB(DB_TRANSFER_DATA,printk("[[%p/%d]]",b,c)) - write_wd33c93_count(regp,c); + write_wd33c93_count(regp,cnt); write_wd33c93_cmd(regp, WD_CMD_TRANS_INFO); if (data_in_dir) { do { asr = READ_AUX_STAT(); if (asr & ASR_DBR) - *b++ = read_wd33c93(regp, WD_DATA); + *buf++ = read_wd33c93(regp, WD_DATA); } while (!(asr & ASR_INT)); } else { do { asr = READ_AUX_STAT(); if (asr & ASR_DBR) - write_wd33c93(regp, WD_DATA, *b++); + write_wd33c93(regp, WD_DATA, *buf++); } while (!(asr & ASR_INT)); } -/* update original buffer pointer and original count */ - - *cnt = read_wd33c93_count(regp); - if (data_in_dir) - *buf = b; - else - *buf += (c - *cnt); - /* Note: we are returning with the interrupt UN-cleared. * Since (presumably) an entire I/O operation has * completed, the bus phase is probably different, and @@ -501,7 +643,7 @@ struct WD33C93_hostdata *hostdata; /* 'dma_setup()' will return TRUE if we can't do DMA. */ if (hostdata->dma_setup(cmd, data_in_dir)) { - transfer_pio(regp, (uchar **)&cmd->SCp.ptr, &cmd->SCp.this_residual, + transfer_pio(regp, (uchar *)&cmd->SCp.ptr, cmd->SCp.this_residual, data_in_dir, hostdata); } @@ -516,11 +658,10 @@ struct WD33C93_hostdata *hostdata; else { write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); -DB(DB_TRANSFER_DATA,printk("[%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) write_wd33c93_count(regp,cmd->SCp.this_residual); - if (hostdata->level2 >= L2_DATA) { - write_wd33c93(regp, WD_COMMAND_PHASE, 0x41); + if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) { + write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); hostdata->state = S_RUNNING_LEVEL2; } @@ -538,9 +679,9 @@ void wd33c93_intr (struct Scsi_Host *instance) struct WD33C93_hostdata *hostdata; Scsi_Cmnd *patch, *cmd; wd33c93_regs *regp; +unsigned long flags; uchar asr, sr, phs, id, lun, *ucp, msg; unsigned long length; -int i; hostdata = (struct WD33C93_hostdata *)instance->hostdata; @@ -550,6 +691,11 @@ int i; if (!(asr & ASR_INT) || (asr & ASR_BSY)) return; +/* OK - it should be safe to re-enable system interrupts */ + + save_flags(flags); + sti(); + cmd = (Scsi_Cmnd *)hostdata->connected; /* assume we're connected */ sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear the interrupt */ phs = read_wd33c93(regp, WD_COMMAND_PHASE); @@ -572,13 +718,13 @@ DB(DB_INTR,printk("{%02x:%02x-",asr,sr)) */ if (hostdata->dma == D_DMA_RUNNING) { -DB(DB_TRANSFER_DATA,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual)) +DB(DB_TRANSFER,printk("[%p/%d:",cmd->SCp.ptr,cmd->SCp.this_residual)) hostdata->dma_stop(cmd->host, cmd, 1); hostdata->dma = D_DMA_OFF; length = cmd->SCp.this_residual; cmd->SCp.this_residual = read_wd33c93_count(regp); cmd->SCp.ptr += (length - cmd->SCp.this_residual); -DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) +DB(DB_TRANSFER,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) } /* Respond to the specific WD3393 interrupt - there are quite a few! */ @@ -586,26 +732,26 @@ DB(DB_TRANSFER_DATA,printk("%p/%d]",cmd->SCp.ptr,cmd->SCp.this_residual)) switch (sr) { case CSR_TIMEOUT: - cli(); DB(DB_INTR,printk("TIMEOUT")) - if (hostdata->state == S_RUNNING_LEVEL2) { + + cli(); + if (hostdata->state == S_RUNNING_LEVEL2) hostdata->connected = NULL; - hostdata->busy[cmd->target] &= ~(1 << cmd->lun); - } else { cmd = (Scsi_Cmnd *)hostdata->selecting; /* get a valid cmd */ hostdata->selecting = NULL; } cmd->result = DID_NO_CONNECT << 16; - hostdata->selecting = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; - cmd->scsi_done(cmd); /* I think scsi_done() enables ints */ + cmd->scsi_done(cmd); /* We are not connected to a target - check to see if there * are commands waiting to be executed. */ + sti(); wd33c93_execute(instance); break; @@ -620,10 +766,9 @@ DB(DB_INTR,printk("SELECT")) /* construct an IDENTIFY message with correct disconnect bit */ - if (hostdata->args & A_NO_DISCONNECT) - hostdata->outgoing_msg[0] = (0x80 | cmd->lun); - else - hostdata->outgoing_msg[0] = (0x80 | 0x40 | cmd->lun); + hostdata->outgoing_msg[0] = (0x80 | 0x00 | cmd->lun); + if (cmd->SCp.phase) + hostdata->outgoing_msg[0] |= 0x40; if (hostdata->sync_stat[cmd->target] == SS_FIRST) { #ifdef SYNC_DEBUG @@ -671,11 +816,10 @@ DB(DB_INTR,printk("OUT-%d.%d",cmd->SCp.this_residual,cmd->SCp.buffers_residual)) /* Note: this interrupt should not occur in a LEVEL2 command */ case CSR_XFER_DONE|PHS_COMMAND: + case CSR_UNEXP |PHS_COMMAND: case CSR_SRV_REQ |PHS_COMMAND: DB(DB_INTR,printk("CMND-%02x,%ld",cmd->cmnd[0],cmd->pid)) - ucp = cmd->cmnd; - i = cmd->cmd_len; - transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata); + transfer_pio(regp, cmd->cmnd, cmd->cmd_len, DATA_OUT_DIR, hostdata); hostdata->state = S_CONNECTED; break; @@ -704,6 +848,7 @@ DB(DB_INTR,printk("=%02x",cmd->SCp.Status)) case CSR_SRV_REQ |PHS_MESS_IN: DB(DB_INTR,printk("MSG_IN=")) + cli(); msg = read_1_byte(regp); sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ @@ -730,7 +875,6 @@ DB(DB_INTR,printk("SDP")) case RESTORE_POINTERS: DB(DB_INTR,printk("RDP")) - if (hostdata->level2 >= L2_BASIC) { write_wd33c93(regp, WD_COMMAND_PHASE, 0x45); write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); @@ -777,24 +921,50 @@ printk("%02x",ucp[hostdata->incoming_ptr]); case EXTENDED_SDTR: id = calc_sync_xfer(ucp[3],ucp[4]); if (hostdata->sync_stat[cmd->target] != SS_WAITING) { - printk("Rejecting target's SDTR message "); + +/* A device has sent an unsolicited SDTR message; rather than go + * through the effort of decoding it and then figuring out what + * our reply should be, we're just gonna say that we have a + * synchronous fifo depth of 0. This will result in asynchronous + * transfers - not ideal but so much easier. + * Actually, this is OK because it assures us that if we don't + * specifically ask for sync transfers, we won't do any. + */ + write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ - hostdata->outgoing_msg[0] = MESSAGE_REJECT; - hostdata->outgoing_len = 1; + hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; + hostdata->outgoing_msg[1] = 3; + hostdata->outgoing_msg[2] = EXTENDED_SDTR; + hostdata->outgoing_msg[3] = hostdata->default_sx_per/4; + hostdata->outgoing_msg[4] = 0; + hostdata->outgoing_len = 5; + hostdata->sync_xfer[cmd->target] = + calc_sync_xfer(hostdata->default_sx_per/4,0); } else { hostdata->sync_xfer[cmd->target] = id; - hostdata->sync_stat[cmd->target] = SS_SET; } #ifdef SYNC_DEBUG -printk("sync_xfer=%02x",id); +printk("sync_xfer=%02x",hostdata->sync_xfer[cmd->target]); #endif + hostdata->sync_stat[cmd->target] = SS_SET; + write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); + hostdata->state = S_CONNECTED; + break; + case EXTENDED_WDTR: + write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ + printk("sending WDTR "); + hostdata->outgoing_msg[0] = EXTENDED_MESSAGE; + hostdata->outgoing_msg[1] = 2; + hostdata->outgoing_msg[2] = EXTENDED_WDTR; + hostdata->outgoing_msg[3] = 0; /* 8 bit transfer width */ + hostdata->outgoing_len = 4; write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); hostdata->state = S_CONNECTED; break; default: - printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]); write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ + printk("Rejecting Unknown Extended Message(%02x). ",ucp[2]); hostdata->outgoing_msg[0] = MESSAGE_REJECT; hostdata->outgoing_len = 1; write_wd33c93_cmd(regp,WD_CMD_NEGATE_ACK); @@ -814,7 +984,7 @@ printk("sync_xfer=%02x",id); break; default: - printk("Rejecting Unknown Message(%02x) ",ucp[0]); + printk("Rejecting Unknown Message(%02x) ",msg); write_wd33c93_cmd(regp,WD_CMD_ASSERT_ATN); /* want MESS_OUT */ hostdata->outgoing_msg[0] = MESSAGE_REJECT; hostdata->outgoing_len = 1; @@ -828,6 +998,12 @@ printk("sync_xfer=%02x",id); case CSR_SEL_XFER_DONE: cli(); + +/* Make sure that reselection is enabled at this point - it may + * have been turned off for the command that just completed. + */ + + write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER); if (phs == 0x60) { DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) cmd->SCp.Message = COMMAND_COMPLETE; @@ -841,7 +1017,7 @@ DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; - cmd->scsi_done(cmd); /* I think scsi_done() enables ints */ + cmd->scsi_done(cmd); /* We are no longer connected to a target - check to see if * there are commands waiting to be executed. @@ -877,8 +1053,8 @@ DB(DB_INTR,printk("MSG_OUT=")) * it - like when our SDTR message is rejected by a target. Some * targets send the REJECT before receiving all of the extended * message, and then seem to go back to MESSAGE_OUT for a byte - * or two. Not sure why, ot if I'm doing something wrong to - * casue this to happen. Regardless, it seems that sending + * or two. Not sure why, or if I'm doing something wrong to + * cause this to happen. Regardless, it seems that sending * NOP messages in these situations results in no harm and * makes everyone happy. */ @@ -887,22 +1063,67 @@ DB(DB_INTR,printk("MSG_OUT=")) hostdata->outgoing_len = 1; hostdata->outgoing_msg[0] = NOP; } - ucp = hostdata->outgoing_msg; - i = hostdata->outgoing_len; - transfer_pio(regp, &ucp, &i, DATA_OUT_DIR, hostdata); + transfer_pio(regp, hostdata->outgoing_msg, hostdata->outgoing_len, + DATA_OUT_DIR, hostdata); DB(DB_INTR,printk("%02x",hostdata->outgoing_msg[0])) hostdata->outgoing_len = 0; hostdata->state = S_CONNECTED; break; - case CSR_DISC: -DB(DB_INTR,printk("DISC")) + case CSR_UNEXP_DISC: + +/* I think I've seen this after a request-sense that was in response + * to an error condition, but not sure. We certainly need to do + * something when we get this interrupt - the question is 'what?'. + * Let's think positively, and assume some command has finished + * in a legal manner (like a command that provokes a request-sense), + * so we treat it as a normal command-complete-disconnect. + */ + + cli(); + +/* Make sure that reselection is enabled at this point - it may + * have been turned off for the command that just completed. + */ + + write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER); if (cmd == NULL) { printk(" - Already disconnected! "); hostdata->state = S_UNCONNECTED; return; } +DB(DB_INTR,printk("UNEXP_DISC-%ld",cmd->pid)) + hostdata->connected = NULL; + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); + hostdata->state = S_UNCONNECTED; + 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); + cmd->scsi_done(cmd); + +/* We are no longer connected to a target - check to see if + * there are commands waiting to be executed. + */ + + wd33c93_execute(instance); + break; + + + case CSR_DISC: + cli(); + +/* Make sure that reselection is enabled at this point - it may + * have been turned off for the command that just completed. + */ + + write_wd33c93(regp,WD_SOURCE_ID, SRCID_ER); +DB(DB_INTR,printk("DISC-%ld",cmd->pid)) + if (cmd == NULL) { + printk(" - Already disconnected! "); + hostdata->state = S_UNCONNECTED; + } switch (hostdata->state) { case S_PRE_CMP_DISC: hostdata->connected = NULL; @@ -912,7 +1133,7 @@ DB(DB_INTR,printk("DISC")) cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); else if (cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); - cmd->scsi_done(cmd); /* I think scsi_done() enables ints */ + cmd->scsi_done(cmd); break; case S_PRE_TMP_DISC: case S_RUNNING_LEVEL2: @@ -920,6 +1141,11 @@ DB(DB_INTR,printk("DISC")) hostdata->disconnected_Q = cmd; hostdata->connected = NULL; hostdata->state = S_UNCONNECTED; + +#ifdef PROC_INTERFACE + disc_taken_total++; +#endif + break; default: printk("*** Unexpected DISCONNECT interrupt! ***"); @@ -943,7 +1169,7 @@ DB(DB_INTR,printk("RESEL")) /* happen during Arbitration/Selection of some other device. */ /* If yes, put losing command back on top of input_Q. */ - if (hostdata->level2 == L2_NONE) { + if (hostdata->level2 <= L2_NONE) { if (hostdata->selecting) { cmd = (Scsi_Cmnd *)hostdata->selecting; @@ -971,7 +1197,7 @@ DB(DB_INTR,printk("RESEL")) } - /* OK - find out which device reslected us. */ + /* OK - find out which device reselected us. */ id = read_wd33c93(regp, WD_SOURCE_ID); id &= SRCID_MASK; @@ -1034,9 +1260,11 @@ DB(DB_INTR,printk("-%ld",cmd->pid)) break; default: - printk("\n---UNKNOWN INTERRUPT:%02x:%02x:%02x!!---",asr,sr,phs); + printk("--UNKNOWN INTERRUPT:%02x:%02x:%02x--",asr,sr,phs); } + restore_flags(flags); + DB(DB_INTR,printk("} ")) } @@ -1056,7 +1284,7 @@ uchar sr; instance->this_id | hostdata->clock_freq); write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_wd33c93(regp, WD_SYNCHRONOUS_TRANSFER, - calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF)); + calc_sync_xfer(hostdata->default_sx_per/4,DEFAULT_SX_OFF)); write_wd33c93(regp, WD_COMMAND, WD_CMD_RESET); while (!(READ_AUX_STAT() & ASR_INT)) @@ -1080,26 +1308,44 @@ uchar sr; hostdata->chip = C_UNKNOWN_CHIP; write_wd33c93(regp, WD_TIMEOUT_PERIOD, TIMEOUT_PERIOD_VALUE); - if (hostdata->args & A_NO_DISCONNECT) - write_wd33c93(regp, WD_SOURCE_ID, 0); - else - write_wd33c93(regp, WD_SOURCE_ID, SRCID_ER); write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); } +#if LINUX_VERSION_CODE >= 0x010300 +int wd33c93_reset(Scsi_Cmnd *SCpnt, unsigned int reset_flags) +#else int wd33c93_reset(Scsi_Cmnd *SCpnt) +#endif { unsigned long flags; struct Scsi_Host *instance; +struct WD33C93_hostdata *hostdata; +int i; instance = SCpnt->host; + hostdata = (struct WD33C93_hostdata *)instance->hostdata; printk("scsi%d: reset. ", instance->host_no); save_flags(flags); cli(); + ((struct WD33C93_hostdata *)instance->hostdata)->dma_stop(instance,NULL,0); + for (i = 0; i < 8; i++) { + hostdata->busy[i] = 0; + hostdata->sync_xfer[i] = calc_sync_xfer(DEFAULT_SX_PER/4,DEFAULT_SX_OFF); + hostdata->sync_stat[i] = SS_UNSET; /* using default sync values */ + } + hostdata->input_Q = NULL; + hostdata->selecting = NULL; + hostdata->connected = NULL; + hostdata->disconnected_Q = NULL; + hostdata->state = S_UNCONNECTED; + hostdata->dma = D_DMA_OFF; + hostdata->incoming_ptr = 0; + hostdata->outgoing_len = 0; + reset_wd33c93(instance); SCpnt->result = DID_RESET << 16; restore_flags(flags); @@ -1113,38 +1359,41 @@ int wd33c93_abort (Scsi_Cmnd *cmd) struct Scsi_Host *instance; struct WD33C93_hostdata *hostdata; wd33c93_regs *regp; -Scsi_Cmnd *tmp, **prev; +Scsi_Cmnd *tmp, *prev; unsigned long flags; + save_flags (flags); + cli(); + instance = cmd->host; hostdata = (struct WD33C93_hostdata *)instance->hostdata; regp = hostdata->regp; - printk ("scsi%d: abort. ", instance->host_no); - - save_flags (flags); - cli(); - /* * Case 1 : If the command hasn't been issued yet, we simply remove it - * from the issue queue. + * from the input_Q. */ - for (prev=(Scsi_Cmnd **)&(hostdata->input_Q),tmp=(Scsi_Cmnd *)hostdata->input_Q; - 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 = DID_ABORT << 16; + + tmp = (Scsi_Cmnd *)hostdata->input_Q; + prev = 0; + while (tmp) { + if (tmp == cmd) { + if (prev) + prev->host_scribble = cmd->host_scribble; + cmd->host_scribble = NULL; + cmd->result = DID_ABORT << 16; + printk("scsi%d: Abort - removing command %ld from input_Q. ", + instance->host_no, cmd->pid); + cmd->scsi_done(cmd); restore_flags(flags); - printk("scsi%d : abort removed command from issue queue. ", - instance->host_no); - tmp->scsi_done(tmp); return SCSI_ABORT_SUCCESS; } + prev = tmp; + tmp = (Scsi_Cmnd *)tmp->host_scribble; + } /* - * Case 2 : If any commands are connected, we're going to fail the abort + * Case 2 : If the command is connected, we're going to fail the abort * and let the high level SCSI driver retry at a later time or * issue a reset. * @@ -1158,20 +1407,22 @@ unsigned long flags; uchar sr, asr; unsigned long timeout; - printk("scsi%d : aborting connected command. ", instance->host_no); + printk("scsi%d: Aborting connected command %ld - ", + instance->host_no, cmd->pid); + printk("stopping DMA - "); if (hostdata->dma == D_DMA_RUNNING) { hostdata->dma_stop(instance, cmd, 0); hostdata->dma = D_DMA_OFF; } - printk("scsi%d : wd33c93 asr is %x. ", instance->host_no, READ_AUX_STAT()); - + printk("sending wd33c93 ABORT command - "); write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_POLLED); write_wd33c93_cmd(regp, WD_CMD_ABORT); /* Now we have to attempt to flush out the FIFO... */ + printk("flushing fifo - "); timeout = 1000000; do { asr = READ_AUX_STAT(); @@ -1179,46 +1430,34 @@ unsigned long flags; read_wd33c93(regp, WD_DATA); } while (!(asr & ASR_INT) && timeout-- > 0); sr = read_wd33c93(regp, WD_SCSI_STATUS); - printk("scsi%d : wd33c93 sr is %x. ", instance->host_no, - read_wd33c93(regp, WD_SCSI_STATUS)); + printk("asr=%02x, sr=%02x, %ld bytes un-transferred (timeout=%ld) - ", + asr, sr, read_wd33c93_count(regp), timeout); - if (sr >= (CSR_ABORT|PHS_DATA_OUT) && sr <= (CSR_ABORT|PHS_MESS_IN)) { /* * Abort command processed. * Still connected. * We must disconnect. */ - printk("scsi%d : count was %ld. ", instance->host_no, - read_wd33c93_count(regp)); - timeout = 1000000; - while ((asr & ASR_CIP) && timeout-- > 0) - asr = READ_AUX_STAT(); - write_wd33c93_cmd(regp, WD_CMD_DISCONNECT); - asr = READ_AUX_STAT(); - if (asr & ASR_LCI) - printk ("scsi%d: disconnect command ignored. ", - instance->host_no); - timeout = 1000000; - while ((asr & ASR_CIP) && timeout-- > 0) - asr = READ_AUX_STAT(); - } - asr = READ_AUX_STAT(); - sr = read_wd33c93(regp, WD_SCSI_STATUS); - printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr); + printk("sending wd33c93 DISCONNECT command - "); write_wd33c93_cmd(regp, WD_CMD_DISCONNECT); + timeout = 1000000; + asr = READ_AUX_STAT(); while ((asr & ASR_CIP) && timeout-- > 0) asr = READ_AUX_STAT(); sr = read_wd33c93(regp, WD_SCSI_STATUS); - printk("scsi%d : asr is %x, sr is %x. ",instance->host_no,asr,sr); - reset_wd33c93(instance); - cmd->result = DID_ABORT << 16; - cmd->scsi_done(cmd); + printk("asr=%02x, sr=%02x.",asr,sr); + hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->connected = NULL; hostdata->state = S_UNCONNECTED; + cmd->result = DID_ABORT << 16; + cmd->scsi_done(cmd); + +/* sti();*/ wd33c93_execute (instance); + restore_flags(flags); return SCSI_ABORT_SUCCESS; } @@ -1229,12 +1468,17 @@ unsigned long flags; * an ABORT_SNOOZE and hope for the best... */ - for (tmp=(Scsi_Cmnd *)hostdata->disconnected_Q; tmp; - tmp=(Scsi_Cmnd *)tmp->host_scribble) - if (cmd == tmp) { + tmp = (Scsi_Cmnd *)hostdata->disconnected_Q; + while (tmp) { + if (tmp == cmd) { + printk("scsi%d: Abort - command %ld found on disconnected_Q - ", + instance->host_no, cmd->pid); + printk("returning ABORT_SNOOZE. "); restore_flags(flags); return SCSI_ABORT_SNOOZE; } + tmp = (Scsi_Cmnd *)tmp->host_scribble; + } /* * Case 4 : If we reached this point, the command was not found in any of @@ -1242,29 +1486,101 @@ unsigned long flags; * * 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 + * so we won't panic, but we will notify the user in case something really * broke. */ +/* sti();*/ + wd33c93_execute (instance); + restore_flags(flags); - printk("scsi%d : warning : SCSI command probably completed successfully\n" + printk("scsi%d: warning : SCSI command probably completed successfully" " before abortion. ", instance->host_no); return SCSI_ABORT_NOT_RUNNING; } -#define MAX_WD33C93_HOSTS 8 -static unsigned int setup_args_array[MAX_WD33C93_HOSTS]; -static int setup_args_array_x = 0; +#define MAX_WD33C93_HOSTS 4 +#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *)) +#define SETUP_BUFFER_SIZE 200 +static char setup_buffer[SETUP_BUFFER_SIZE]; +static char setup_used[MAX_SETUP_STRINGS]; void wd33c93_setup (char *str, int *ints) { -int i; +int i,x; +char *p1,*p2; + + /* The kernel does some processing of the command-line before calling + * this function: If it begins with any decimal or hex number arguments, + * ints[0] = how many numbers found and ints[1] through [n] are the values + * themselves. str points to where the non-numeric arguments (if any) + * start: We do our own parsing of those. We construct synthetic 'nosync' + * keywords out of numeric args (to maintain compatibility with older + * versions) and then add the rest of the arguments. + */ + + p1 = setup_buffer; + *p1 = '\0'; + if (ints[0]) { + for (i=0; i= '0') && (*cp <= '9')) { + *val = simple_strtoul(cp,NULL,0); } + return ++x; } @@ -1274,6 +1590,9 @@ void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs, { struct WD33C93_hostdata *hostdata; int i; +int flags; +int val; +char buf[32]; hostdata = (struct WD33C93_hostdata *)instance->hostdata; @@ -1294,46 +1613,226 @@ int i; hostdata->disconnected_Q = NULL; hostdata->state = S_UNCONNECTED; hostdata->dma = D_DMA_OFF; + hostdata->level2 = L2_BASIC; + hostdata->disconnect = DIS_ADAPTIVE; + hostdata->args = DEBUG_DEFAULTS; hostdata->incoming_ptr = 0; hostdata->outgoing_len = 0; + hostdata->default_sx_per = DEFAULT_SX_PER; + hostdata->no_sync = 0xff; /* sync defaults to off */ + +#ifdef PROC_INTERFACE + hostdata->proc = PR_VERSION|PR_INFO|PR_TOTALS| + PR_CONNECTED|PR_INPUTQ|PR_DISCQ| + PR_STOP; + + disc_allowed_total = 0; + disc_taken_total = 0; +#endif + - hostdata->args = setup_default; - if ((setup_args_array_x < MAX_WD33C93_HOSTS) && - (setup_args_array[setup_args_array_x])) - hostdata->args = setup_args_array[setup_args_array_x]; - setup_args_array_x++; + if (check_setup_strings("nosync",&flags,&val,buf)) + hostdata->no_sync = val; + + if (check_setup_strings("period",&flags,&val,buf)) + hostdata->default_sx_per = sx_table[round_period((unsigned int)val)].period_ns; + + if (check_setup_strings("disconnect",&flags,&val,buf)) { + if ((val >= DIS_NEVER) && (val <= DIS_ALWAYS)) + hostdata->disconnect = val; + else + hostdata->disconnect = DIS_ADAPTIVE; + } + + if (check_setup_strings("debug",&flags,&val,buf)) + hostdata->args = val & DB_MASK; + + if (check_setup_strings("clock",&flags,&val,buf)) { + if (val>7 && val<11) + val = WD33C93_FS_8_10; + else if (val>11 && val<16) + val = WD33C93_FS_12_15; + else if (val>15 && val<21) + val = WD33C93_FS_16_20; + else + val = WD33C93_FS_8_10; + hostdata->clock_freq = val; + } + + if ((i = check_setup_strings("next",&flags,&val,buf))) { + while (i) + setup_used[--i] = 1; + } + +#ifdef PROC_INTERFACE + if (check_setup_strings("proc",&flags,&val,buf)) + hostdata->proc = val; +#endif - i = hostdata->args & (A_LEVEL2_0 | A_LEVEL2_1 | A_LEVEL2_2); - i >>= 8; - if (i == 0) - i = L2_DEFAULT; - hostdata->level2 = i; cli(); reset_wd33c93(instance); sti(); - printk("wd33c93-%d: ",instance->host_no); - switch (hostdata->chip) { - case C_WD33C93: - printk("Found WD33c93 chip! This driver probably needs at least the 'A' version!\n"); - break; - case C_WD33C93A: - printk("Found WD33c93A chip: microcode=%02x\n",hostdata->microcode); - break; - case C_WD33C93B: - printk("Found WD33c93B chip: microcode=%02x\n",hostdata->microcode); - break; - default: - printk("Unknown 3393 chip!\n"); - } - printk("wd33c93-%d: LEVEL2 commands %s (%d)\n",instance->host_no, - (hostdata->level2 == L2_NONE)?"disabled":"enabled", - hostdata->level2); + printk("wd33c93-%d: chip=%s microcode=%02x\n",instance->host_no, + (hostdata->chip==C_WD33C93)?"WD33c93": + (hostdata->chip==C_WD33C93A)?"WD33c93A": + (hostdata->chip==C_WD33C93B)?"WD33c93B":"unknown", + hostdata->microcode); + #ifdef DEBUGGING_ON + printk("wd33c93-%d: setup_strings=",instance->host_no); + for (i=0; ihost_no,hostdata->args); #endif printk("wd33c93-%d: driver version %s - %s\n",instance->host_no, WD33C93_VERSION,WD33C93_DATE); + printk("wd33c93-%d: compiled on %s at %s\n",instance->host_no, + __DATE__,__TIME__); +} + + +int wd33c93_proc_info(char *buf, char **start, off_t off, int len, int hn, int in) +{ + +#ifdef PROC_INTERFACE + +char *bp; +char tbuf[128]; +unsigned long flags; +struct Scsi_Host *instance; +struct WD33C93_hostdata *hd; +Scsi_Cmnd *cmd; +int x,i; +static int stop = 0; + + for (instance=instance_list; instance; instance=instance->next) { + if (instance->host_no == hn) + break; + } + if (!instance) { + printk("*** Hmm... Can't find host #%d!\n",hn); + return (-ESRCH); + } + hd = (struct WD33C93_hostdata *)instance->hostdata; + +/* If 'in' is TRUE we need to _read_ the proc file. We accept the following + * keywords (same format as command-line, but only ONE per read): + * debug + * disconnect + * period + * resync + * proc + */ + + if (in) { + buf[len] = '\0'; + bp = buf; + if (!strncmp(bp,"debug:",6)) { + bp += 6; + hd->args = simple_strtoul(bp,NULL,0) & DB_MASK; + } + else if (!strncmp(bp,"disconnect:",11)) { + bp += 11; + x = simple_strtoul(bp,NULL,0); + if (x < DIS_NEVER || x > DIS_ALWAYS) + x = DIS_ADAPTIVE; + hd->disconnect = x; + } + else if (!strncmp(bp,"period:",7)) { + bp += 7; + x = simple_strtoul(bp,NULL,0); + hd->default_sx_per = sx_table[round_period((unsigned int)x)].period_ns; + } + else if (!strncmp(bp,"resync:",7)) { + bp += 7; + x = simple_strtoul(bp,NULL,0); + for (i=0; i<7; i++) + if (x & (1<sync_stat[i] = SS_UNSET; + } + else if (!strncmp(bp,"proc:",5)) { + bp += 5; + hd->proc = simple_strtoul(bp,NULL,0); + } + return len; + } + + save_flags(flags); + cli(); + bp = buf; + *bp = '\0'; + if (hd->proc & PR_VERSION) { + sprintf(tbuf,"\nVersion %s - %s. Compiled %s %s", + WD33C93_VERSION,WD33C93_DATE,__DATE__,__TIME__); + strcat(bp,tbuf); + } + if (hd->proc & PR_INFO) { + ; + } + if (hd->proc & PR_TOTALS) { + sprintf(tbuf,"\n%ld disc_allowed, %ld disc_taken", + disc_allowed_total,disc_taken_total); + strcat(bp,tbuf); + } + if (hd->proc & PR_CONNECTED) { + strcat(bp,"\nconnected: "); + if (hd->connected) { + cmd = (Scsi_Cmnd *)hd->connected; + sprintf(tbuf," %ld-%d:%d(%02x)", + cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); + strcat(bp,tbuf); + } + } + if (hd->proc & PR_INPUTQ) { + strcat(bp,"\ninput_Q: "); + cmd = (Scsi_Cmnd *)hd->input_Q; + while (cmd) { + sprintf(tbuf," %ld-%d:%d(%02x)", + cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); + strcat(bp,tbuf); + cmd = (Scsi_Cmnd *)cmd->host_scribble; + } + } + if (hd->proc & PR_DISCQ) { + strcat(bp,"\ndisconnected_Q:"); + cmd = (Scsi_Cmnd *)hd->disconnected_Q; + while (cmd) { + sprintf(tbuf," %ld-%d:%d(%02x)", + cmd->pid, cmd->target, cmd->lun, cmd->cmnd[0]); + strcat(bp,tbuf); + cmd = (Scsi_Cmnd *)cmd->host_scribble; + } + } + strcat(bp,"\n"); + restore_flags(flags); + *start = buf; + if (stop) { + stop = 0; + return 0; + } + if (off > 0x40000) /* ALWAYS stop after 256k bytes have been read */ + stop = 1;; + if (hd->proc & PR_STOP) /* stop every other time */ + stop = 1; + return strlen(bp); + +#else /* PROC_INTERFACE */ + + return 0; + +#endif /* PROC_INTERFACE */ + } + +#ifdef MODULE + +Scsi_Host_Template driver_template = WD33C93; + +#include "scsi_module.c" + +#endif + diff --git a/drivers/scsi/wd33c93.h b/drivers/scsi/wd33c93.h index 4436badc85e4..5dcdc13af2b9 100644 --- a/drivers/scsi/wd33c93.h +++ b/drivers/scsi/wd33c93.h @@ -1,10 +1,9 @@ -#ifndef WD33C93_H -#define WD33C93_H - /* * wd33c93.h - Linux device driver definitions for the * Commodore Amiga A2091/590 SCSI controller card * + * IMPORTANT: This file is for version 1.21 - 20/Mar/1996 + * * Copyright (c) 1996 John Shifflett, GeoLog Consulting * john@geolog.com * jshiffle@netcom.com @@ -21,6 +20,8 @@ * */ +#ifndef WD33C93_H +#define WD33C93_H #define uchar unsigned char @@ -151,7 +152,7 @@ #define CTRL_DMA 0x80 /* Timeout Period register */ -#define TIMEOUT_PERIOD_VALUE 20 /* results in 200 ms. */ +#define TIMEOUT_PERIOD_VALUE 20 /* 20 = 200 ms */ /* Synchronous Transfer Register */ #define STR_FSS 0x80 @@ -193,18 +194,23 @@ struct sx_period { uchar reg_value; }; +/* FEF: defines for hostdata->dma_buffer_pool */ + +#define BUF_CHIP_ALLOCED 0 +#define BUF_SCSI_ALLOCED 1 struct WD33C93_hostdata { struct Scsi_Host *next; wd33c93_regs *regp; uchar clock_freq; uchar chip; /* what kind of wd33c93? */ - uchar microcode; /* microcode rev if 'B' */ + uchar microcode; /* microcode rev */ int dma_dir; /* data transfer dir. */ dma_setup_t dma_setup; dma_stop_t dma_stop; uchar *dma_bounce_buffer; unsigned int dma_bounce_len; + uchar dma_buffer_pool; /* FEF: buffer from chip_ram? */ volatile uchar busy[8]; /* index = target, bit = lun */ volatile Scsi_Cmnd *input_Q; /* commands waiting to be started */ volatile Scsi_Cmnd *selecting; /* trying to select this command */ @@ -213,13 +219,19 @@ struct WD33C93_hostdata { uchar state; /* what we are currently doing */ uchar dma; /* current state of DMA (on/off) */ uchar level2; /* extent to which Level-2 commands are used */ + uchar disconnect; /* disconnect/reselect policy */ unsigned int args; /* set from command-line argument */ uchar incoming_msg[8]; /* filled during message_in phase */ int incoming_ptr; /* mainly used with EXTENDED messages */ uchar outgoing_msg[8]; /* send this during next message_out */ int outgoing_len; /* length of outgoing message */ + unsigned int default_sx_per; /* default transfer period for SCSI bus */ uchar sync_xfer[8]; /* sync_xfer reg settings per target */ uchar sync_stat[8]; /* status of sync negotiation per target */ + uchar no_sync; /* bitmask: don't do sync on these targets */ +#if 0 + uchar proc; /* bitmask: what's in proc output */ +#endif }; @@ -245,34 +257,31 @@ struct WD33C93_hostdata { #define D_DMA_RUNNING 1 /* defines for hostdata->level2 */ -/* NOTE: only the first 3 are implemented so far - having trouble - * when more than 1 device is reading/writing at the same time... - */ +/* NOTE: only the first 3 are implemented so far */ -#define L2_NONE 1 /* no combination commands - we get lots of ints */ +/* (The first 8 bits are reserved for compatibility. They function #define L2_SELECT 2 /* start with SEL_ATN_XFER, but never resume it */ #define L2_BASIC 3 /* resume after STATUS ints & RDP messages */ #define L2_DATA 4 /* resume after DATA_IN/OUT ints */ #define L2_MOST 5 /* resume after anything except a RESELECT int */ #define L2_RESELECT 6 /* resume after everything, including RESELECT ints */ #define L2_ALL 7 /* always resume */ -#define L2_DEFAULT L2_BASIC -/* defines for hostdata->args */ -/* (The first 8 bits are reserved for compatability. They function - * as they did in the old driver - note that turning off sync_xfer - * on a target affects all LUNs at that SCSI id.) - */ +/* defines for hostdata->disconnect */ + +#define DIS_NEVER 0 +#define DIS_ADAPTIVE 1 +#define DIS_ALWAYS 2 -#define A_LEVEL2_0 1<<8 -#define A_LEVEL2_1 1<<9 -#define A_LEVEL2_2 1<<10 -#define A_NO_DISCONNECT 1<<11 +/* defines for hostdata->args */ -#define DB_QUEUE_COMMAND 1<<12 -#define DB_EXECUTE 1<<13 -#define DB_INTR 1<<14 -#define DB_TRANSFER_DATA 1<<15 +#define DB_TEST1 1<<0 +#define DB_TEST2 1<<1 +#define DB_QUEUE_COMMAND 1<<2 +#define DB_EXECUTE 1<<3 +#define DB_INTR 1<<4 +#define DB_TRANSFER 1<<5 +#define DB_MASK 0x3f /* defines for hostdata->sync_stat[] */ @@ -281,12 +290,33 @@ struct WD33C93_hostdata { #define SS_WAITING 2 #define SS_SET 3 +/* defines for hostdata->proc */ + +#define PR_VERSION 1<<0 +#define PR_INFO 1<<1 +#define PR_TOTALS 1<<2 +#define PR_CONNECTED 1<<3 +#define PR_INPUTQ 1<<4 +#define PR_DISCQ 1<<5 +#define PR_TEST 1<<6 +#define PR_STOP 1<<7 + void wd33c93_init (struct Scsi_Host *instance, wd33c93_regs *regs, dma_setup_t setup, dma_stop_t stop, int clock_freq); int wd33c93_abort (Scsi_Cmnd *cmd); -int wd33c93_reset (Scsi_Cmnd *); int wd33c93_queuecommand (Scsi_Cmnd *cmd, void (*done)(Scsi_Cmnd *)); void wd33c93_intr (struct Scsi_Host *instance); +int wd33c93_proc_info(char *, char **, off_t, int, int, int); + +#if LINUX_VERSION_CODE >= 0x010300 +int wd33c93_reset (Scsi_Cmnd *, unsigned int); +#else +int wd33c93_reset (Scsi_Cmnd *); +#endif + +#if 0 +struct proc_dir_entry proc_scsi_wd33c93; +#endif #endif /* WD33C93_H */ diff --git a/drivers/sound/dmasound.c b/drivers/sound/dmasound.c index 7ad74e135cd7..13f76b6b1993 100644 --- a/drivers/sound/dmasound.c +++ b/drivers/sound/dmasound.c @@ -475,7 +475,7 @@ typedef struct { } TRANS; struct sound_settings { - MACHINE mach; /* machine dependend things */ + MACHINE mach; /* machine dependent things */ SETTINGS hard; /* hardware settings */ SETTINGS soft; /* software settings */ SETTINGS dsp; /* /dev/dsp default settings */ @@ -676,11 +676,11 @@ void sound_setup(char *str, int *ints); /* ++Martin: stub for now */ * I think I've optimized anything as far as one can do in plain C, all * variables should fit in registers and the loops are really short. There's * one loop for every possible situation. Writing a more generalized and thus - * parametrized loop would only produce slower code. Feel free to optimize + * parameterized loop would only produce slower code. Feel free to optimize * this in assembler if you like. :) * * I think these routines belong here because they're not yet really hardware - * independend, especially the fact that the Falcon can play 16bit samples + * independent, especially the fact that the Falcon can play 16bit samples * only in stereo is hardcoded in both of them! * * ++geert: split in even more functions (one per format) @@ -1872,7 +1872,7 @@ static void AtaPlay(void) * than considering all possible situations. But the point is that * disabling the irq doesn't have any bad influence on this version of * the driver as we benefit from having pre-programmed the DMA - * whereever possible: There's no need to reload the DMA at the exact + * wherever possible: There's no need to reload the DMA at the exact * time of an interrupt but only at some time while the pre-programmed * frame is playing! */ @@ -2755,7 +2755,7 @@ static int sq_sync(void) while (sq.playing) { SLEEP(sq.sync_queue, ONE_SECOND); if (SIGNAL_RECEIVED) { - /* While waiting for audio output to drain, an interrupt occured. + /* While waiting for audio output to drain, an interrupt occurred. Stop audio output immediately and clear the queue. */ sq_reset(); rc = -EINTR; @@ -2775,7 +2775,7 @@ static int sq_release(void) rc = sq_sync(); sq.busy = 0; WAKE_UP(sq.open_queue); - /* Wake up a process waiting for the queue beeing released. + /* Wake up a process waiting for the queue being released. Note: There may be several processes waiting for a call to open() returning. */ } diff --git a/fs/Config.in b/fs/Config.in index 3816fb1935f5..0447a9c5da44 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -34,6 +34,10 @@ fi tristate 'ISO9660 cdrom filesystem support' CONFIG_ISO9660_FS tristate 'OS/2 HPFS filesystem support (read only)' CONFIG_HPFS_FS tristate 'System V and Coherent filesystem support' CONFIG_SYSV_FS -bool 'AFFS filesystem support' CONFIG_AFFS_FS -bool 'UFS filesystem support (read only)' CONFIG_UFS_FS +tristate 'AFFS filesystem support (read only)' CONFIG_AFFS_FS +tristate 'UFS filesystem support (read only)' CONFIG_UFS_FS +if [ "$CONFIG_UFS_FS" != "n" ]; then + bool "BSD disklabel (FreeBSD partition tables) support" CONFIG_BSD_DISKLABEL + bool "SMD disklabel (Sun partition tables) support" CONFIG_SMD_DISKLABEL +fi endmenu diff --git a/fs/Makefile b/fs/Makefile index c58ab034d961..5ec162671d61 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -143,10 +143,18 @@ endif ifeq ($(CONFIG_UFS_FS),y) SUB_DIRS += ufs +else + ifeq ($(CONFIG_UFS_FS),m) + MOD_SUB_DIRS += ufs + endif endif ifeq ($(CONFIG_AFFS_FS),y) SUB_DIRS += affs +else + ifeq ($(CONFIG_AFFS_FS),m) + MOD_SUB_DIRS += affs + endif endif ifeq ($(CONFIG_BINFMT_ELF),y) diff --git a/fs/affs/amigaffs.c b/fs/affs/amigaffs.c index 6443a63035f6..0a0ce359ec85 100644 --- a/fs/affs/amigaffs.c +++ b/fs/affs/amigaffs.c @@ -1,10 +1,15 @@ /* * linux/fs/affs/amigaffs.c * + * (C) 1996 Stefan Reinauer - Modified to compile as Module + * * (C) 1993 Ray Burr - Amiga FFS filesystem. * */ + +#include + #include #include #include @@ -91,7 +96,7 @@ int affs_get_file_name (int bsize, void *fh_data, char **name) return file_end->file_name[0]; } -/* Get the key number of the first extention block for the file +/* Get the key number of the first extension block for the file header pointed to by FH_DATA. */ int affs_get_extension (int bsize, void *fh_data) @@ -128,3 +133,20 @@ int init_affs_fs(void) return register_filesystem(&affs_fs_type); } +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_affs_fs()) == 0) + register_symtab(0); + return status; +} + +void cleanup_module(void) +{ + unregister_filesystem(&affs_fs_type); +} + +#endif + diff --git a/fs/affs/amigaffs.h b/fs/affs/amigaffs.h index c8c2b6269957..457a32c90a4b 100644 --- a/fs/affs/amigaffs.h +++ b/fs/affs/amigaffs.h @@ -180,7 +180,7 @@ struct hardlink_front LONG primary_type; ULONG own_key; LONG unused[3]; - ULONG checkksum; + ULONG checksum; }; struct hardlink_end diff --git a/fs/affs/file.c b/fs/affs/file.c index 5afc42c84346..50f126e7ee49 100644 --- a/fs/affs/file.c +++ b/fs/affs/file.c @@ -115,7 +115,7 @@ static int affs_smap(struct inode *inode, int block) /* * affs_file_read() is also needed by the directory read-routine, * so it's not static. NOTE! reading directories directly is a bad idea, - * but has to be supported for now for compatability reasons with older + * but has to be supported for now for compatibility reasons with older * versions. */ int affs_file_read(struct inode * inode, struct file * filp, diff --git a/fs/affs/inode.c b/fs/affs/inode.c index 23acfe0b2a4f..82ed07cce273 100644 --- a/fs/affs/inode.c +++ b/fs/affs/inode.c @@ -294,7 +294,7 @@ void affs_read_inode(struct inode * inode) } file_front = (struct file_front *) fh_data; - file_end = GET_END_PTR (struct file_end, fh_data, /* coincidendly the same as dir_end */ + file_end = GET_END_PTR (struct file_end, fh_data, /* coincidently the same as dir_end */ AFFS_I2BSIZE (inode)); /* don't use bitmap data for mode, uid & gid of the rootblock */ @@ -305,7 +305,7 @@ void affs_read_inode(struct inode * inode) inode->i_mode = S_IRWXUGO | S_IFDIR | S_ISVTX ; /* drwxrwxrwt */ inode->i_nlink = 2; /* at least ..... */ - inode->i_size = 0; /* some differrent idea ? */ + inode->i_size = 0; /* some different idea ? */ inode->i_uid = 0; inode->i_gid = 0; @@ -340,7 +340,7 @@ void affs_read_inode(struct inode * inode) probably spend some time on this */ link_end = (struct hardlink_end *)file_end; inode->i_ino = link_end->original; - inode->i_nlink += 2; /* It's hard to say whats correct */ + inode->i_nlink += 2; /* It's hard to say what's correct */ brelse(bh); link = 1; break; diff --git a/fs/binfmt_aout.c b/fs/binfmt_aout.c index e66d3e17cc97..c8dc68deb07f 100644 --- a/fs/binfmt_aout.c +++ b/fs/binfmt_aout.c @@ -227,7 +227,7 @@ static unsigned long * create_aout_tables(char * p, struct linux_binprm * bprm) envp = sp; sp -= argc+1; argv = sp; -#ifdef __i386__ +#if defined(__i386__) || defined(__mc68000__) put_user(envp,--sp); put_user(argv,--sp); #endif diff --git a/fs/buffer.c b/fs/buffer.c index 241698709aab..bd2c299a6c6d 100644 --- a/fs/buffer.c +++ b/fs/buffer.c @@ -211,7 +211,7 @@ static int sync_buffers(kdev_t dev, int wait) printk("[%d %s %ld] ", nlist, kdevname(bh->b_dev), bh->b_blocknr); ncount++; - }; + } bh->b_count--; retry = 1; } @@ -373,7 +373,7 @@ static inline void remove_from_queues(struct buffer_head * bh) remove_from_free_list(bh); /* Free list entries should not be in the hash queue */ return; - }; + } nr_buffers_type[bh->b_list]--; nr_buffers_st[BUFSIZE_INDEX(bh->b_size)][bh->b_list]--; remove_from_hash_queue(bh); @@ -420,7 +420,7 @@ static inline void put_last_free(struct buffer_head * bh) if(!free_list[isize]) { free_list[isize] = bh; bh->b_prev_free = bh; - }; + } nr_free[isize]++; bh->b_next_free = free_list[isize]; @@ -919,15 +919,19 @@ struct buffer_head * breada(kdev_t dev, int block, int bufsize, index = BUFSIZE_INDEX(bh->b_size); if (buffer_uptodate(bh)) - return bh; + return(bh); + else ll_rw_block(READ, 1, &bh); - blocks = ((filesize & (bufsize - 1)) - (pos & (bufsize - 1))) >> (9+index); + blocks = (filesize - pos) >> (9+index); - if (blocks > (read_ahead[MAJOR(dev)] >> index)) + if (blocks < (read_ahead[MAJOR(dev)] >> index)) blocks = read_ahead[MAJOR(dev)] >> index; - if (blocks > NBUF) + if (blocks > NBUF) blocks = NBUF; - + +/* if (blocks) printk("breada (new) %d blocks\n",blocks); */ + + bhlist[0] = bh; j = 1; for(i=1; i1) + ll_rw_block(READA, (j-1), bhlist+1); for(i=1; is_blocksize == 512){ - ret = bread (sb->s_dev,block,512); +/* ret = bread (sb->s_dev,block,512); */ + ret = breada (sb->s_dev,block,512,0,18*1024); }else{ - struct buffer_head *real = bread (sb->s_dev,block>>1,1024); +/* struct buffer_head *real = bread (sb->s_dev,block>>1,1024); */ + struct buffer_head *real = breada (sb->s_dev,block>>1,1024,0,18*1024); if (real != NULL){ ret = (struct buffer_head *)kmalloc (sizeof(struct buffer_head) ,GFP_KERNEL); diff --git a/fs/fat/cache.c b/fs/fat/cache.c index cb05f26c581c..54badbeadb77 100644 --- a/fs/fat/cache.c +++ b/fs/fat/cache.c @@ -12,6 +12,7 @@ #include "msbuffer.h" + static struct fat_cache *fat_cache,cache[FAT_CACHE]; /* Returns the this'th FAT entry, -1 if it is an end-of-file entry. If @@ -29,18 +30,18 @@ int fat_access(struct super_block *sb,int nr,int new_value) first = nr*3/2; last = first+1; } - if (!(bh = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >> - SECTOR_BITS),SECTOR_SIZE))) { - printk("bread in fat_access failed\n"); + if (!(bh = breada(sb->s_dev,MSDOS_SB(sb)->fat_start+(first >> + SECTOR_BITS),SECTOR_SIZE,0,FAT_READAHEAD))) { + printk("breada in fat_access failed\n"); return 0; } if ((first >> SECTOR_BITS) == (last >> SECTOR_BITS)) bh2 = bh; else { - if (!(bh2 = bread(sb->s_dev,MSDOS_SB(sb)->fat_start+(last - >> SECTOR_BITS),SECTOR_SIZE))) { + if (!(bh2 = breada(sb->s_dev,MSDOS_SB(sb)->fat_start+(last + >> SECTOR_BITS),SECTOR_SIZE,0,FAT_READAHEAD))) { brelse(bh); - printk("bread in fat_access failed\n"); + printk("breada in fat_access failed\n"); return 0; } } @@ -75,16 +76,16 @@ int fat_access(struct super_block *sb,int nr,int new_value) } mark_buffer_dirty(bh, 1); for (copy = 1; copy < MSDOS_SB(sb)->fats; copy++) { - if (!(c_bh = bread(sb->s_dev,MSDOS_SB(sb)-> + if (!(c_bh = breada(sb->s_dev,MSDOS_SB(sb)-> fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)-> - fat_length*copy,SECTOR_SIZE))) break; + fat_length*copy,SECTOR_SIZE,0,FAT_READAHEAD))) break; memcpy(c_bh->b_data,bh->b_data,SECTOR_SIZE); mark_buffer_dirty(c_bh, 1); if (bh != bh2) { - if (!(c_bh2 = bread(sb->s_dev, + if (!(c_bh2 = breada(sb->s_dev, MSDOS_SB(sb)->fat_start+(first >> SECTOR_BITS)+MSDOS_SB(sb)->fat_length*copy - +1,SECTOR_SIZE))) { + +1,SECTOR_SIZE,0,FAT_READAHEAD))) { brelse(c_bh); break; } diff --git a/fs/fat/misc.c b/fs/fat/misc.c index b01f07a9aaa9..5d865f4d20ea 100644 --- a/fs/fat/misc.c +++ b/fs/fat/misc.c @@ -298,7 +298,7 @@ int fat_get_entry(struct inode *dir, loff_t *pos,struct buffer_head **bh, if (*bh) brelse(*bh); PRINTK (("get_entry sector apres brelse\n")); - if (!(*bh = bread(dir->i_dev,sector,SECTOR_SIZE))) { + if (!(*bh = breada(dir->i_dev,sector,SECTOR_SIZE,0,FAT_READAHEAD))) { printk("Directory sread (sector %d) failed\n",sector); continue; } @@ -372,7 +372,7 @@ static int raw_scan_sector(struct super_block *sb,int sector,const char *name, struct inode *inode; int entry,start,done; - if (!(bh = bread(sb->s_dev,sector,SECTOR_SIZE))) return -EIO; + if (!(bh = breada(sb->s_dev,sector,SECTOR_SIZE,0,FAT_READAHEAD))) return -EIO; data = (struct msdos_dir_entry *) bh->b_data; for (entry = 0; entry < MSDOS_DPS; entry++) { /* RSS_COUNT: if (data[entry].name == name) done=true else done=false. */ diff --git a/fs/fat/msbuffer.h b/fs/fat/msbuffer.h index d5d29970a370..5b386afe3689 100644 --- a/fs/fat/msbuffer.h +++ b/fs/fat/msbuffer.h @@ -1,3 +1,5 @@ +/* Number of bytes to readahead on disc access */ +#define FAT_READAHEAD (18*1024) struct buffer_head *fat_bread (struct super_block *sb, int block); struct buffer_head *fat_getblk (struct super_block *sb, int block); diff --git a/fs/fcntl.c b/fs/fcntl.c index 9de3284b8c88..6f19c71fd5b5 100644 --- a/fs/fcntl.c +++ b/fs/fcntl.c @@ -85,6 +85,10 @@ asmlinkage long sys_fcntl(unsigned int fd, unsigned int cmd, unsigned long arg) if (!(arg & FASYNC) && (filp->f_flags & FASYNC) && filp->f_op->fasync) filp->f_op->fasync(filp->f_inode, filp, 0); + /* requiered for SunOS emulation */ + if (O_NONBLOCK != O_NDELAY) + if (arg & O_NDELAY) + arg |= O_NONBLOCK; filp->f_flags &= ~(O_APPEND | O_NONBLOCK | FASYNC); filp->f_flags |= arg & (O_APPEND | O_NONBLOCK | FASYNC); diff --git a/fs/filesystems.c b/fs/filesystems.c index 278cb396b855..dacda9315ab4 100644 --- a/fs/filesystems.c +++ b/fs/filesystems.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -101,6 +102,10 @@ asmlinkage int sys_setup(void) init_hpfs_fs(); #endif +#ifdef CONFIG_AFFS_FS + init_affs_fs(); +#endif + #ifdef CONFIG_UFS_FS init_ufs_fs(); #endif diff --git a/fs/isofs/inode.c b/fs/isofs/inode.c index f19e2357836b..2d1d20ea26cb 100644 --- a/fs/isofs/inode.c +++ b/fs/isofs/inode.c @@ -25,6 +25,7 @@ #include #include +#define MULTI_VOLUME #ifdef LEAK_CHECK static int check_malloc = 0; static int check_bread = 0; @@ -306,8 +307,10 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, if(high_sierra){ rootp = (struct iso_directory_record *) h_pri->root_directory_record; if (isonum_723 (h_pri->volume_set_size) != 1) { +#ifndef MULTI_VOLUME printk("Multi-volume disks not (yet) supported.\n"); goto out; +#endif }; 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); @@ -315,8 +318,10 @@ struct super_block *isofs_read_super(struct super_block *s,void *data, } else { rootp = (struct iso_directory_record *) pri->root_directory_record; if (isonum_723 (pri->volume_set_size) != 1) { +#ifndef MULTI_VOLUME printk("Multi-volume disks not (yet) supported.\n"); goto out; +#endif }; 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); @@ -614,10 +619,13 @@ void isofs_read_inode(struct inode * inode) inode->i_sb->u.isofs_sb.s_cruft = 'y'; } +#ifndef MULTI_VOLUME if (inode->i_sb->u.isofs_sb.s_cruft != 'y' && (volume_seq_no != 0) && (volume_seq_no != 1)) { printk("Multi volume CD somehow got mounted.\n"); - } else { + } else +#endif + { if (S_ISREG(inode->i_mode)) inode->i_op = &isofs_file_inode_operations; else if (S_ISDIR(inode->i_mode)) diff --git a/fs/locks.c b/fs/locks.c index fd5aa6a2bf49..d73d26bd1b74 100644 --- a/fs/locks.c +++ b/fs/locks.c @@ -273,9 +273,18 @@ int fcntl_setlk(unsigned int fd, unsigned int cmd, struct flock *l) break; case F_SHLCK : case F_EXLCK : +#if 1 +/* warn a bit for now, but don't overdo it */ +{ + static int count = 0; + if (count < 5) { + count++; printk(KERN_WARNING "fcntl_setlk() called by process %d with broken flock() emulation\n", current->pid); + } +} +#endif if (!(filp->f_mode & 3)) return (-EBADF); break; diff --git a/fs/nfs/README b/fs/nfs/README index 553af1f5b57b..f87cb3629cea 100644 --- a/fs/nfs/README +++ b/fs/nfs/README @@ -13,7 +13,7 @@ HOW TO USE This stuff compiles as a loadable module (I developed it on 1.3.77). - Simply type mkmodule, and insmod nfs.o. This will start for nfsiod's + Simply type mkmodule, and insmod nfs.o. This will start four nfsiod's at the same time (which will show up under the pseudonym of insmod in ps-style listings). diff --git a/fs/nfs/dir.c b/fs/nfs/dir.c index e6cc98b82882..bd36ea1e5f3f 100644 --- a/fs/nfs/dir.c +++ b/fs/nfs/dir.c @@ -20,25 +20,19 @@ #include /* for fs functions */ -static int nfs_dir_read(struct inode *, struct file *filp, char *buf, - int count); +static int nfs_dir_open(struct inode * inode, struct file * file); +static int nfs_dir_read(struct inode *, struct file *, char *, int); static int nfs_readdir(struct inode *, struct file *, void *, filldir_t); -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 int nfs_lookup(struct inode *, const char *, int, struct inode **); +static int nfs_create(struct inode *, const char *, int, int, struct inode **); +static int nfs_mkdir(struct inode *, const char *, int, int); +static int nfs_rmdir(struct inode *, const char *, int); +static int nfs_unlink(struct inode *, const char *, int); +static int nfs_symlink(struct inode *, const char *, int, const char *); +static int nfs_link(struct inode *, struct inode *, const char *, int); +static int nfs_mknod(struct inode *, const char *, int, int, int); +static int nfs_rename(struct inode *, const char *, int, + struct inode *, const char *, int); static struct file_operations nfs_dir_operations = { NULL, /* lseek - default */ @@ -48,7 +42,7 @@ static struct file_operations nfs_dir_operations = { NULL, /* select - default */ NULL, /* ioctl - default */ NULL, /* mmap */ - NULL, /* no special open code */ + nfs_dir_open, /* open - revalidate */ NULL, /* no special release code */ NULL /* fsync */ }; @@ -73,6 +67,29 @@ struct inode_operations nfs_dir_inode_operations = { NULL /* permission */ }; +static inline void revalidate_dir(struct nfs_server * server, struct inode * dir) +{ + struct nfs_fattr fattr; + + if (jiffies - NFS_READTIME(dir) < server->acdirmax) + return; + + NFS_READTIME(dir) = jiffies; + if (nfs_proc_getattr(server, NFS_FH(dir), &fattr) == 0) { + nfs_refresh_inode(dir, &fattr); + if (fattr.mtime.seconds == NFS_OLDMTIME(dir)) + return; + NFS_OLDMTIME(dir) = fattr.mtime.seconds; + } + /* invalidate directory cache here when we _really_ start caching */ +} + +static int nfs_dir_open(struct inode * dir, struct file * file) +{ + revalidate_dir(NFS_SERVER(dir), dir); + return 0; +} + static int nfs_dir_read(struct inode *inode, struct file *filp, char *buf, int count) { @@ -105,6 +122,8 @@ static int nfs_readdir(struct inode *inode, struct file *filp, return -EBADF; } + revalidate_dir(NFS_SERVER(inode), inode); + /* initialize cache memory if it hasn't been used before */ if (c_entry == NULL) { @@ -190,7 +209,7 @@ static int nfs_readdir(struct inode *inode, struct file *filp, void nfs_kfree_cache(void) { - int i; + int i; if (c_entry == NULL) return; diff --git a/fs/nfs/inode.c b/fs/nfs/inode.c index f84d12fa037d..d5a414eccb99 100644 --- a/fs/nfs/inode.c +++ b/fs/nfs/inode.c @@ -340,6 +340,7 @@ static int run_nfsiod(void *dummy) #endif MOD_INC_USE_COUNT; + exit_mm(current); current->session = 1; current->pgrp = 1; sprintf(current->comm, "nfsiod"); diff --git a/fs/proc/array.c b/fs/proc/array.c index 6b2cd9e73289..f63ab6af239c 100644 --- a/fs/proc/array.c +++ b/fs/proc/array.c @@ -470,6 +470,11 @@ static unsigned long get_wchan(struct task_struct *p) + (long)&((struct pt_regs *)0)->reg) # define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc))) # define KSTK_ESP(tsk) ((tsk) == current ? rdusp() : (tsk)->tss.usp) +#elif defined(__sparc__) +# define PT_REG(reg) (PAGE_SIZE - sizeof(struct pt_regs) \ + + (long)&((struct pt_regs *)0)->reg) +# define KSTK_EIP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(pc))) +# define KSTK_ESP(tsk) (*(unsigned long *)(tsk->kernel_stack_page + PT_REG(u_regs[UREG_FP]))) #endif /* Gcc optimizes away "strlen(x)" for constant x */ @@ -607,7 +612,7 @@ static inline char * task_sig(struct task_struct *p, char *buffer) bit <<= 1; action++; } - + buffer += sprintf(buffer, "SigIgn:\t%08lx\n" "SigCgt:\t%08lx\n", diff --git a/fs/proc/inode.c b/fs/proc/inode.c index 99b2712ec49b..27aee98f000b 100644 --- a/fs/proc/inode.c +++ b/fs/proc/inode.c @@ -74,7 +74,7 @@ static int parse_options(char *options,uid_t *uid,gid_t *gid) struct inode * proc_get_inode(struct super_block * s, int ino, struct proc_dir_entry * de) { struct inode * inode = iget(s, ino); - if (inode) { + if (inode && inode->i_sb == s) { inode->u.generic_ip = (void *) de; if (de) { if (de->mode) { diff --git a/fs/proc/mem.c b/fs/proc/mem.c index 8ae07ac009f5..8e3969ca798b 100644 --- a/fs/proc/mem.c +++ b/fs/proc/mem.c @@ -65,14 +65,9 @@ static int mem_read(struct inode * inode, struct file * file,char * buf, int cou return -EINVAL; pid = inode->i_ino; pid >>= 16; - tsk = NULL; - for (i = 1 ; i < NR_TASKS ; i++) - if (task[i] && task[i]->pid == pid) { - tsk = task[i]; - break; - } - if (!tsk) + if (pid != current->pid) return -EACCES; + tsk = current; addr = file->f_pos; count = check_range(tsk, addr, count); if (count < 0) @@ -131,14 +126,9 @@ static int mem_write(struct inode * inode, struct file * file,char * buf, int co addr = file->f_pos; pid = inode->i_ino; pid >>= 16; - tsk = NULL; - for (i = 1 ; i < NR_TASKS ; i++) - if (task[i] && task[i]->pid == pid) { - tsk = task[i]; - break; - } - if (!tsk) + if (pid != current->pid) return -EACCES; + tsk = current; tmp = buf; while (count > 0) { if (current->signal & ~current->blocked) diff --git a/fs/ufs/ufs_dir.c b/fs/ufs/ufs_dir.c index f4817be4a8ba..1cbc59a02226 100644 --- a/fs/ufs/ufs_dir.c +++ b/fs/ufs/ufs_dir.c @@ -6,22 +6,16 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_dir.c,v 1.1 1996/04/21 14:41:04 davem Exp $ + * $Id: ufs_dir.c,v 1.3 1996/04/25 09:12:00 davem Exp $ * */ #include /* XXX */ -extern int ufs_lookup(); -extern int ufs_bmap(); - -static int ufs_dir_read (struct inode * inode, struct file * filp, - char * buf, int count) -{ - /* XXX - probably allow this for root, EISDIR for normal users */ - return -EISDIR; -} +extern int ufs_lookup (struct inode *, const char *, int, struct inode **); +extern int ufs_bmap (struct inode *, int); +extern void ufs_print_inode (struct inode *); /* * This is blatantly stolen from ext2fs @@ -43,7 +37,7 @@ ufs_readdir (struct inode * inode, struct file * filp, void * dirent, if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { printk("ufs_readdir: ino %lu f_pos %lu\n", - inode->i_ino, filp->f_pos); + inode->i_ino, (unsigned long) filp->f_pos); ufs_print_inode(inode); } @@ -95,7 +89,7 @@ revalidate: de = (struct direct *) (bh->b_data + offset); /* XXX - put in a real ufs_check_dir_entry() */ if ((de->d_reclen == 0) || (de->d_namlen == 0)) { - filp->f_pos = filp->f_pos & (sb->s_blocksize - 1) + sb->s_blocksize; + filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1)) + sb->s_blocksize; brelse(bh); return stored; } @@ -123,7 +117,7 @@ revalidate: de->d_ino); version = inode->i_version; if (inode->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("ufs_readdir: filldir(%s,%lu)\n", + printk("ufs_readdir: filldir(%s,%u)\n", de->d_name, de->d_ino); } error = filldir(dirent, de->d_name, de->d_namlen, filp->f_pos, de->d_ino); @@ -147,18 +141,17 @@ revalidate: return 0; } - static struct file_operations ufs_dir_operations = { NULL, /* lseek */ - &ufs_dir_read, /* read */ + NULL, /* read */ NULL, /* write */ - &ufs_readdir, /* readdir */ + ufs_readdir, /* readdir */ NULL, /* select */ NULL, /* ioctl */ NULL, /* mmap */ NULL, /* open */ NULL, /* release */ - &file_fsync, /* fsync */ + file_fsync, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL, /* revalidate */ @@ -167,7 +160,7 @@ static struct file_operations ufs_dir_operations = { struct inode_operations ufs_dir_inode_operations = { &ufs_dir_operations, /* default directory file operations */ NULL, /* create */ - &ufs_lookup, /* lookup */ + ufs_lookup, /* lookup */ NULL, /* link */ NULL, /* unlink */ NULL, /* symlink */ diff --git a/fs/ufs/ufs_file.c b/fs/ufs/ufs_file.c index 0b6b759a2935..0b0b5e0b4643 100644 --- a/fs/ufs/ufs_file.c +++ b/fs/ufs/ufs_file.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_file.c,v 1.1 1996/04/21 14:41:08 davem Exp $ + * $Id: ufs_file.c,v 1.3 1996/04/25 09:12:02 davem Exp $ * */ @@ -75,13 +75,13 @@ int ufs_bmap (struct inode * inode, int block) bh = bread(inode->i_dev, inode->u.ufs_i.ui_ib[0], BLOCK_SIZE); if (bh == NULL) { - printk("ufs_bmap: can't map block %lu, ino %lu\n", + printk("ufs_bmap: can't map block %u, ino %lu\n", block + UFS_NDADDR, inode->i_ino); return(0); } phys_block = ((__u32 *)bh->b_data)[block]; brelse(bh); - printk("ufs_bmap: imap ino %lu block %lu phys %lu\n", + printk("ufs_bmap: imap ino %lu block %u phys %lu\n", inode->i_ino, block + UFS_NDADDR, phys_block); return(phys_block); } else { @@ -94,18 +94,17 @@ int ufs_bmap (struct inode * inode, int block) return(0); } - static struct file_operations ufs_file_operations = { NULL, /* lseek */ - &generic_file_read, /* read */ + generic_file_read, /* read */ NULL, /* write */ NULL, /* readdir */ NULL, /* select */ NULL, /* ioctl */ - &generic_file_mmap, /* mmap */ + generic_file_mmap, /* mmap */ NULL, /* open */ NULL, /* release */ - &file_fsync, /* fsync */ /* XXX - is this ok? */ + file_fsync, /* fsync */ NULL, /* fasync */ NULL, /* check_media_change */ NULL, /* revalidate */ @@ -124,9 +123,9 @@ struct inode_operations ufs_file_inode_operations = { NULL, /* rename */ NULL, /* readlink */ NULL, /* follow_link */ - &generic_readpage, /* readpage */ + generic_readpage, /* readpage */ NULL, /* writepage */ - &ufs_bmap, /* bmap */ + ufs_bmap, /* bmap */ NULL, /* truncate */ NULL, /* permission */ NULL, /* smap */ diff --git a/fs/ufs/ufs_inode.c b/fs/ufs/ufs_inode.c index d80d172ffdf0..ec568f5026e8 100644 --- a/fs/ufs/ufs_inode.c +++ b/fs/ufs/ufs_inode.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_inode.c,v 1.1 1996/04/21 14:41:12 davem Exp $ + * $Id: ufs_inode.c,v 1.3 1996/04/25 09:12:05 davem Exp $ * */ diff --git a/fs/ufs/ufs_namei.c b/fs/ufs/ufs_namei.c index dbe0579862f7..0cfe1285ec3a 100644 --- a/fs/ufs/ufs_namei.c +++ b/fs/ufs/ufs_namei.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_namei.c,v 1.1 1996/04/21 14:41:15 davem Exp $ + * $Id: ufs_namei.c,v 1.3 1996/04/25 09:12:07 davem Exp $ * */ @@ -103,7 +103,7 @@ int ufs_lookup (struct inode * dir, const char * name, int len, } bh = bread(dir->i_dev, fragno, dir->i_sb->s_blocksize); if (bh == NULL) { - printk("ufs_lookup: bread failed: ino %lu, lfragno %u", + printk("ufs_lookup: bread failed: ino %lu, lfragno %lu", dir->i_ino, lfragno); return(-EIO); } @@ -119,7 +119,7 @@ int ufs_lookup (struct inode * dir, const char * name, int len, break; } if (dir->i_sb->u.ufs_sb.s_flags & UFS_DEBUG) { - printk("lfragno 0x%x direct d 0x%x d_ino %u d_reclen %u d_namlen %u d_name `%s'\n", + printk("lfragno 0x%lx direct d 0x%x d_ino %u d_reclen %u d_namlen %u d_name `%s'\n", lfragno, (unsigned int)d, d->d_ino, d->d_reclen, d->d_namlen, d->d_name); } if ((d->d_namlen == len) && diff --git a/fs/ufs/ufs_super.c b/fs/ufs/ufs_super.c index 340336c021bf..f44fd20c8f84 100644 --- a/fs/ufs/ufs_super.c +++ b/fs/ufs/ufs_super.c @@ -6,10 +6,17 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_super.c,v 1.1 1996/04/21 14:41:19 davem Exp $ + * $Id: ufs_super.c,v 1.3 1996/04/25 09:12:09 davem Exp $ * */ +/* + * Kernel module support added on 96/04/26 by + * Stefan Reinauer + */ + +#include + #include #include #include @@ -26,18 +33,18 @@ extern void ufs_read_inode(struct inode * inode); extern void ufs_put_inode(struct inode * inode); static struct super_operations ufs_super_ops = { - &ufs_read_inode, + ufs_read_inode, NULL, /* notify_change() */ NULL, /* XXX - ufs_write_inode() */ - &ufs_put_inode, - &ufs_put_super, + ufs_put_inode, + ufs_put_super, NULL, /* XXX - ufs_write_super() */ - &ufs_statfs, + ufs_statfs, NULL, /* XXX - ufs_remount() */ }; static struct file_system_type ufs_fs_type = { - &ufs_read_super, "ufs", 1, NULL + ufs_read_super, "ufs", 1, NULL }; int @@ -46,6 +53,23 @@ init_ufs_fs(void) return(register_filesystem(&ufs_fs_type)); } +#ifdef MODULE +int init_module(void) +{ + int status; + + if ((status = init_ufs_fs()) == 0) + register_symtab(0); + return status; +} + +void cleanup_module(void) +{ + unregister_filesystem(&ufs_fs_type); +} +#endif + +#if 0 /* unused */ static void ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb) { @@ -65,6 +89,7 @@ ufs_print_super_stuff(struct super_block * sb, struct ufs_superblock * usb) return; } +#endif struct super_block * ufs_read_super(struct super_block * sb, void * data, int silent) @@ -203,7 +228,7 @@ ufs_read_super(struct super_block * sb, void * data, int silent) sb->u.ufs_sb.s_fsfrag = usb->fs_frag; /* XXX - rename this later */ sb->s_mounted = iget(sb, UFS_ROOTINO); - printk("ufs_read_super: inopb %lu\n", sb->u.ufs_sb.s_inopb); + printk("ufs_read_super: inopb %u\n", sb->u.ufs_sb.s_inopb); /* * XXX - read cg structs? */ diff --git a/fs/ufs/ufs_symlink.c b/fs/ufs/ufs_symlink.c index b31a6f8cb96a..83cd9e1c3d51 100644 --- a/fs/ufs/ufs_symlink.c +++ b/fs/ufs/ufs_symlink.c @@ -6,7 +6,7 @@ * Laboratory for Computer Science Research Computing Facility * Rutgers, The State University of New Jersey * - * $Id: ufs_symlink.c,v 1.1 1996/04/21 14:41:23 davem Exp $ + * $Id: ufs_symlink.c,v 1.3 1996/04/25 09:12:11 davem Exp $ * */ @@ -15,13 +15,15 @@ #include +extern int ufs_bmap (struct inode *, int); + static int ufs_readlink(struct inode * inode, char * buffer, int buflen) { unsigned long int block; struct buffer_head * bh = NULL; char * link; - int i, err; + int i; char c; if (inode->i_sb->u.ufs_sb.s_flags & (UFS_DEBUG|UFS_DEBUG_LINKS)) { @@ -64,8 +66,6 @@ ufs_readlink(struct inode * inode, char * buffer, int buflen) if (bh) brelse (bh); return i; - - return(0); } /* diff --git a/include/asm-i386/smp.h b/include/asm-i386/smp.h index 566b09c235db..ff0caafe07da 100644 --- a/include/asm-i386/smp.h +++ b/include/asm-i386/smp.h @@ -19,7 +19,7 @@ * information is. */ -#define SMP_MAGIC_IDENT ('_'<<24)|('P'<<16)|('M'<<8)|'_' +#define SMP_MAGIC_IDENT (('_'<<24)|('P'<<16)|('M'<<8)|'_') struct intel_mp_floating { diff --git a/include/asm-m68k/atarihw.h b/include/asm-m68k/atarihw.h index 3ec565560452..24ae1e220cdf 100644 --- a/include/asm-m68k/atarihw.h +++ b/include/asm-m68k/atarihw.h @@ -18,7 +18,7 @@ #include -/* Reading the MFP port register gives a machine independant delay, since the +/* Reading the MFP port register gives a machine independent delay, since the * MFP always has a 8 MHz clock. This avoids problems with the varying length * of nops on various machines. Somebody claimed that the tstb takes 600 ns. */ @@ -42,7 +42,7 @@ extern int is_medusa; #include #include -static inline void dma_cache_maintainance( unsigned long paddr, +static inline void dma_cache_maintenance( unsigned long paddr, unsigned long len, int writeflag ) @@ -293,7 +293,7 @@ struct BLITTER u_short endmask3; u_short dst_x_inc; u_short dst_y_inc; - u_long dst_adress; + u_long dst_address; u_short wd_per_line; u_short ln_per_bb; u_short hlf_op_reg; @@ -448,7 +448,7 @@ struct TT_RTC { */ /* constants for the ACIA registers */ -/* baudrate selection and reset (Baudrte = clock/factor) */ +/* baudrate selection and reset (Baudrate = clock/factor) */ #define ACIA_DIV1 0 #define ACIA_DIV16 1 #define ACIA_DIV64 2 diff --git a/include/asm-m68k/atariints.h b/include/asm-m68k/atariints.h index 0318a0f9d56a..bc23d25f1f00 100644 --- a/include/asm-m68k/atariints.h +++ b/include/asm-m68k/atariints.h @@ -4,7 +4,7 @@ ** Copyright 1994 by Bj”rn Brauel ** ** 5/2/94 Roman Hodek: -** TT interupt definitions added. +** TT interrupt definitions added. ** ** 12/02/96: (Roman) ** Adapted to new int handling scheme (see ataints.c); revised numbering @@ -45,7 +45,7 @@ #define IRQ_TYPE_FAST 1 #define IRQ_TYPE_PRIO 2 -#define IRQ_SUPRIOUS (IRQ_MACHSPEC | 0) +#define IRQ_SPURIOUS (IRQ_MACHSPEC | 0) /* auto-vector interrupts */ #define IRQ_AUTO_1 (IRQ_MACHSPEC | 1) diff --git a/include/asm-m68k/atomic.h b/include/asm-m68k/atomic.h index 7c39167384c0..d65198fca729 100644 --- a/include/asm-m68k/atomic.h +++ b/include/asm-m68k/atomic.h @@ -24,7 +24,7 @@ static __inline__ void atomic_add(atomic_t i, atomic_t *v) __asm__ __volatile__( "addl %1,%0" :"=m" (__atomic_fool_gcc(v)) - :"ir" (i), "m" (__atomic_fool_gcc(v))); + :"ir" (i), "0" (__atomic_fool_gcc(v))); } static __inline__ void atomic_sub(atomic_t i, atomic_t *v) @@ -32,7 +32,7 @@ static __inline__ void atomic_sub(atomic_t i, atomic_t *v) __asm__ __volatile__( "subl %1,%0" :"=m" (__atomic_fool_gcc(v)) - :"ir" (i), "m" (__atomic_fool_gcc(v))); + :"ir" (i), "0" (__atomic_fool_gcc(v))); } static __inline__ void atomic_inc(atomic_t *v) @@ -40,7 +40,7 @@ static __inline__ void atomic_inc(atomic_t *v) __asm__ __volatile__( "addql #1,%0" :"=m" (__atomic_fool_gcc(v)) - :"m" (__atomic_fool_gcc(v))); + :"0" (__atomic_fool_gcc(v))); } static __inline__ void atomic_dec(atomic_t *v) @@ -48,16 +48,17 @@ static __inline__ void atomic_dec(atomic_t *v) __asm__ __volatile__( "subql #1,%0" :"=m" (__atomic_fool_gcc(v)) - :"m" (__atomic_fool_gcc(v))); + :"0" (__atomic_fool_gcc(v))); } static __inline__ int atomic_dec_and_test(atomic_t *v) { + char c; __asm__ __volatile__( - "subql #1,%0" - :"=m" (__atomic_fool_gcc(v)) - :"m" (__atomic_fool_gcc(v))); - return (*v <= 0); + "subql #1,%0; seq %1" + :"=m" (__atomic_fool_gcc(v)), "=d" (c) + :"0" (__atomic_fool_gcc(v))); + return c != 0; } #endif /* __ARCH_M68K_ATOMIC __ */ diff --git a/include/asm-m68k/bitops.h b/include/asm-m68k/bitops.h index 0a91c8110f17..5b618801c8c4 100644 --- a/include/asm-m68k/bitops.h +++ b/include/asm-m68k/bitops.h @@ -46,12 +46,7 @@ extern __inline__ int change_bit(int nr, void * vaddr) extern __inline__ int test_bit(int nr, const void * vaddr) { - char retval; - - __asm__ __volatile__ ("bftst %2@{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr^31), "a" (vaddr)); - - return retval; + return ((1UL << (nr & 31)) & (((const unsigned int *) vaddr)[nr >> 5])) != 0; } extern __inline__ int find_first_zero_bit(void * vaddr, unsigned size) @@ -166,12 +161,7 @@ minix_clear_bit (int nr, void *vaddr) extern __inline__ int minix_test_bit (int nr, const void *vaddr) { - char retval; - - __asm__ __volatile__ ("bftst %2{%1:#1}; sne %0" - : "=d" (retval) : "d" (nr^15), "m" (*(const char *) vaddr)); - - return retval; + return ((1U << (nr & 15)) & (((const unsigned short *) vaddr)[nr >> 4])) != 0; } /* Bitmap functions for the ext2 filesystem. */ @@ -201,12 +191,7 @@ ext2_clear_bit (int nr, void *vaddr) extern __inline__ int ext2_test_bit (int nr, const void *vaddr) { - char retval; - - __asm__ __volatile__ ("bftst %2{%1,#1}; sne %0" - : "=d" (retval) : "d" (nr^7), "m" (*(const char *) vaddr)); - - return retval; + return ((1U << (nr & 7)) & (((const unsigned char *) vaddr)[nr >> 3])) != 0; } extern __inline__ int diff --git a/include/asm-m68k/bootinfo.h b/include/asm-m68k/bootinfo.h index 638c7b3c828a..08e4b6dee1ac 100644 --- a/include/asm-m68k/bootinfo.h +++ b/include/asm-m68k/bootinfo.h @@ -10,7 +10,7 @@ ** Created 09/29/92 by Greg Harp ** ** 5/2/94 Roman Hodek: -** Added bi_atari part of the machine dependant union bi_un; for now it +** Added bi_atari part of the machine dependent union bi_un; for now it ** contains just a model field to distinguish between TT and Falcon. */ @@ -98,7 +98,7 @@ struct bi_Atari { struct { /* video hardware */ ATARIHW_DECLARE(STND_SHIFTER); /* ST-Shifter - no base low ! */ - ATARIHW_DECLARE(EXTD_SHIFTER); /* STe-Shifter - 24 bit adress */ + ATARIHW_DECLARE(EXTD_SHIFTER); /* STe-Shifter - 24 bit address */ ATARIHW_DECLARE(TT_SHIFTER); /* TT-Shifter */ ATARIHW_DECLARE(VIDEL_SHIFTER); /* Falcon-Shifter */ /* sound hardware */ diff --git a/include/asm-m68k/dma.h b/include/asm-m68k/dma.h index 08f792fc3682..af73a0f6fa34 100644 --- a/include/asm-m68k/dma.h +++ b/include/asm-m68k/dma.h @@ -2,7 +2,7 @@ #define _M68K_DMA_H 1 /* Don't define MAX_DMA_ADDRESS; it's useless on the m68k and any - occurence should be flagged as an error. */ + occurrence should be flagged as an error. */ #define MAX_DMA_CHANNELS 8 diff --git a/include/asm-m68k/font.h b/include/asm-m68k/font.h index 1151255b837e..0b189d6d879c 100644 --- a/include/asm-m68k/font.h +++ b/include/asm-m68k/font.h @@ -18,7 +18,7 @@ * Find a font with a specific name */ -extern int findsoftfont(char *name, int *width, int *heigth, u_char *data[]); +extern int findsoftfont(char *name, int *width, int *height, u_char *data[]); /* @@ -29,4 +29,7 @@ extern void getdefaultfont(int xres, int yres, char *name[], int *width, int *height, u_char *data[]); +/* Max. length for the name of a predefined font */ +#define MAX_FONT_NAME 32 + #endif /* _ASM_M68K_FONT_H_ */ diff --git a/include/asm-m68k/pgtable.h b/include/asm-m68k/pgtable.h index bad53470da2f..00c52e8745fd 100644 --- a/include/asm-m68k/pgtable.h +++ b/include/asm-m68k/pgtable.h @@ -141,7 +141,7 @@ static inline void flush_tlb_range(struct mm_struct *mm, #define __S110 PAGE_SHARED #define __S111 PAGE_SHARED -/* zero page used for unitialized stuff */ +/* zero page used for uninitialized stuff */ extern unsigned long empty_zero_page; /* @@ -525,22 +525,14 @@ extern void cache_push (unsigned long paddr, int len); */ extern void cache_push_v (unsigned long vaddr, int len); -#if 0 -#define flush_cache_all() do { \ - if (m68k_is040or060 >= 4) \ - __asm__ __volatile__ (".word 0xf478\n" ::); \ - } while (0) +/* + * Could someone take a look at these? + */ +extern void flush_cache_all(void); #define flush_cache_mm(mm) flush_cache_all() #define flush_cache_range(mm, start, end) flush_cache_all() -#define flush_cache_page(vma, vmaddr) flush_cache_all() -#define flush_page_to_ram(page) flush_cache_all() -#else -#define flush_cache_all() do { } while (0) -#define flush_cache_mm(mm) do { } while (0) -#define flush_cache_range(mm, start, end) do { } while (0) -#define flush_cache_page(vma, vmaddr) do { } while (0) -#define flush_page_to_ram(page) do { } while (0) -#endif +#define flush_cache_page(vma, addr) flush_cache_all() +extern void flush_page_to_ram(unsigned long addr); /* cache code */ #define FLUSH_I_AND_D (0x00000808) @@ -579,8 +571,19 @@ extern inline void update_mmu_cache(struct vm_area_struct * vma, { } +/* + * I don't know what is going on here, but since these were changed, + * swapping haven't been working on the 68040. + */ + +#if 0 #define SWP_TYPE(entry) (((entry) >> 2) & 0x7f) #define SWP_OFFSET(entry) ((entry) >> 9) #define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << 9)) +#else +#define SWP_TYPE(entry) (((entry) & 0x1fc) >> 2) +#define SWP_OFFSET(entry) ((entry) >> PAGE_SHIFT) +#define SWP_ENTRY(type,offset) (((type) << 2) | ((offset) << PAGE_SHIFT)) +#endif #endif /* _M68K_PGTABLE_H */ diff --git a/include/asm-m68k/system.h b/include/asm-m68k/system.h index 65f844534e55..a7563e5ab7a1 100644 --- a/include/asm-m68k/system.h +++ b/include/asm-m68k/system.h @@ -32,7 +32,7 @@ extern inline void wrusp(unsigned long usp) { * and so we might get see unexpected behaviors when a task returns * with unexpected register values. * - * syscall stores these regsiters itself and none of them are used + * syscall stores these registers itself and none of them are used * by syscall after the function in the syscall has been called. * * Beware that resume now expects *next to be in d1 and the offset of diff --git a/include/asm-m68k/traps.h b/include/asm-m68k/traps.h index cd6f7eacb10c..661c303e8f2b 100644 --- a/include/asm-m68k/traps.h +++ b/include/asm-m68k/traps.h @@ -148,7 +148,7 @@ extern e_vector vectors[]; #define MMU060_SIZ (0x00600000) /* transfer size */ #define MMU060_TT (0x00180000) /* transfer type (TT) bits */ #define MMU060_TM (0x00070000) /* transfer modifier (TM) bits */ -#define MMU060_IO (0x00008000) /* intruction or operand */ +#define MMU060_IO (0x00008000) /* instruction or operand */ #define MMU060_PBE (0x00004000) /* push buffer bus error */ #define MMU060_SBE (0x00002000) /* store buffer bus error */ #define MMU060_PTA (0x00001000) /* pointer A fault */ diff --git a/include/asm-sparc/asi.h b/include/asm-sparc/asi.h index 653776c37bfc..f81ab33b9cb0 100644 --- a/include/asm-sparc/asi.h +++ b/include/asm-sparc/asi.h @@ -1,4 +1,4 @@ -/* $Id: asi.h,v 1.15 1996/04/17 22:45:52 davem Exp $ */ +/* $Id: asi.h,v 1.16 1996/04/25 06:12:43 davem Exp $ */ #ifndef _SPARC_ASI_H #define _SPARC_ASI_H diff --git a/include/asm-sparc/auxio.h b/include/asm-sparc/auxio.h index 619f3b225745..1989642ce4e9 100644 --- a/include/asm-sparc/auxio.h +++ b/include/asm-sparc/auxio.h @@ -1,4 +1,4 @@ -/* $Id: auxio.h,v 1.10 1996/01/03 03:52:58 davem Exp $ +/* $Id: auxio.h,v 1.11 1996/04/25 06:12:45 davem Exp $ * auxio.h: Definitions and code for the Auxiliary I/O register. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/bsderrno.h b/include/asm-sparc/bsderrno.h index 663b61d1a2b9..54a75be43abb 100644 --- a/include/asm-sparc/bsderrno.h +++ b/include/asm-sparc/bsderrno.h @@ -1,4 +1,4 @@ -/* $Id: bsderrno.h,v 1.2 1995/11/25 02:31:17 davem Exp $ +/* $Id: bsderrno.h,v 1.3 1996/04/25 06:12:47 davem Exp $ * bsderrno.h: Error numbers for NetBSD binary compatibility * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/cache.h b/include/asm-sparc/cache.h index 9ad2ad54264e..eef46a217431 100644 --- a/include/asm-sparc/cache.h +++ b/include/asm-sparc/cache.h @@ -1,4 +1,4 @@ -/* $Id: cache.h,v 1.3 1995/11/25 02:31:22 davem Exp $ +/* $Id: cache.h,v 1.4 1996/04/25 06:12:49 davem Exp $ * cache.h: Cache specific code for the Sparc. These include flushing * and direct tag/data line access. * diff --git a/include/asm-sparc/cypress.h b/include/asm-sparc/cypress.h index 0b58c7486086..b9704b6c7a2b 100644 --- a/include/asm-sparc/cypress.h +++ b/include/asm-sparc/cypress.h @@ -1,4 +1,4 @@ -/* $Id: cypress.h,v 1.4 1996/03/12 17:48:12 davem Exp $ +/* $Id: cypress.h,v 1.5 1996/04/25 06:12:51 davem Exp $ * cypress.h: Cypress module specific definitions and defines. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/dma.h b/include/asm-sparc/dma.h index 29bb7c9d3924..b7281ca99efc 100644 --- a/include/asm-sparc/dma.h +++ b/include/asm-sparc/dma.h @@ -1,4 +1,4 @@ -/* $Id: dma.h,v 1.15 1996/03/23 02:40:00 davem Exp $ +/* $Id: dma.h,v 1.16 1996/04/25 06:12:54 davem Exp $ * include/asm-sparc/dma.h * * Copyright 1995 (C) David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/ecc.h b/include/asm-sparc/ecc.h index 1bd3e0bc5935..8e27ceccb76d 100644 --- a/include/asm-sparc/ecc.h +++ b/include/asm-sparc/ecc.h @@ -1,4 +1,4 @@ -/* $Id: ecc.h,v 1.2 1995/11/25 02:31:37 davem Exp $ +/* $Id: ecc.h,v 1.3 1996/04/25 06:12:57 davem Exp $ * ecc.h: Definitions and defines for the external cache/memory * controller on the sun4m. * diff --git a/include/asm-sparc/elf.h b/include/asm-sparc/elf.h index cfeeef6af521..ca8e00807843 100644 --- a/include/asm-sparc/elf.h +++ b/include/asm-sparc/elf.h @@ -1,4 +1,4 @@ -/* $Id: elf.h,v 1.2 1995/11/25 02:31:40 davem Exp $ */ +/* $Id: elf.h,v 1.3 1996/04/22 15:48:48 miguel Exp $ */ #ifndef __ASMSPARC_ELF_H #define __ASMSPARC_ELF_H @@ -15,4 +15,6 @@ typedef elf_greg_t elf_gregset_t[ELF_NGREG]; typedef unsigned long elf_fpregset_t; +#define elf_check_arch(x) ((x) == EM_SPARC) +#define ELF_ARCH EM_SPARC #endif diff --git a/include/asm-sparc/head.h b/include/asm-sparc/head.h index 19e6113b3504..8e6aec9e65ff 100644 --- a/include/asm-sparc/head.h +++ b/include/asm-sparc/head.h @@ -1,4 +1,4 @@ -/* $Id: head.h,v 1.26 1996/03/25 20:21:08 davem Exp $ */ +/* $Id: head.h,v 1.27 1996/04/25 06:13:06 davem Exp $ */ #ifndef __SPARC_HEAD_H #define __SPARC_HEAD_H diff --git a/include/asm-sparc/irq.h b/include/asm-sparc/irq.h index 0344433856bf..6ba760db61e7 100644 --- a/include/asm-sparc/irq.h +++ b/include/asm-sparc/irq.h @@ -1,4 +1,4 @@ -/* $Id: irq.h,v 1.12 1996/04/03 02:17:34 davem Exp $ +/* $Id: irq.h,v 1.13 1996/04/25 06:13:09 davem Exp $ * irq.h: IRQ registers on the Sparc. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/mbus.h b/include/asm-sparc/mbus.h index 52d34944e402..8301ecce164a 100644 --- a/include/asm-sparc/mbus.h +++ b/include/asm-sparc/mbus.h @@ -1,4 +1,4 @@ -/* $Id: mbus.h,v 1.6 1996/04/16 09:34:31 zaitcev Exp $ +/* $Id: mbus.h,v 1.7 1996/04/25 06:13:12 davem Exp $ * mbus.h: Various defines for MBUS modules. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/memreg.h b/include/asm-sparc/memreg.h index 6f9adf6ba2d0..215e39fe2fe6 100644 --- a/include/asm-sparc/memreg.h +++ b/include/asm-sparc/memreg.h @@ -1,4 +1,4 @@ -/* $Id: memreg.h,v 1.5 1995/12/02 20:05:25 davem Exp $ */ +/* $Id: memreg.h,v 1.6 1996/04/25 06:13:13 davem Exp $ */ #ifndef _SPARC_MEMREG_H #define _SPARC_MEMREG_H /* memreg.h: Definitions of the values found in the synchronous diff --git a/include/asm-sparc/mman.h b/include/asm-sparc/mman.h index 2198ef59af24..c69d6771ef89 100644 --- a/include/asm-sparc/mman.h +++ b/include/asm-sparc/mman.h @@ -1,4 +1,4 @@ -/* $Id: mman.h,v 1.6 1996/01/03 03:53:05 davem Exp $ */ +/* $Id: mman.h,v 1.7 1996/04/25 06:13:15 davem Exp $ */ #ifndef __SPARC_MMAN_H__ #define __SPARC_MMAN_H__ diff --git a/include/asm-sparc/mostek.h b/include/asm-sparc/mostek.h index e90aa01132a7..4cabb6a7d458 100644 --- a/include/asm-sparc/mostek.h +++ b/include/asm-sparc/mostek.h @@ -1,4 +1,4 @@ -/* $Id: mostek.h,v 1.4 1995/11/25 02:32:05 davem Exp $ +/* $Id: mostek.h,v 1.5 1996/04/25 06:13:17 davem Exp $ * mostek.h: Describes the various Mostek time of day clock registers. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/mp.h b/include/asm-sparc/mp.h deleted file mode 100644 index fc4c8a69f40c..000000000000 --- a/include/asm-sparc/mp.h +++ /dev/null @@ -1,32 +0,0 @@ -/* $Id: mp.h,v 1.3 1996/03/25 20:21:09 davem Exp $ - * mp.h: Multiprocessing definitions for the Sparc. - * - * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) - */ -#ifndef _SPARC_MP_H -#define _SPARC_MP_H - -#include -#include -#include - -struct sparc_percpu { - struct tt_entry *trap_table; - char *kernel_stack[PAGE_SIZE<<1]; - int cpuid; /* Who am I? */ - int cpu_is_alive; /* Linux has fired it up. */ - int cpu_is_idling; /* Is sitting in the idle loop. */ - /* More to come... */ - char filler[PERCPU_ENTSIZE-(PAGE_SIZE*2)-0xc]; -}; - -extern struct sparc_percpu *percpu_table; - -struct prom_cpuinfo { - int prom_node; - int mid; -}; - -extern struct prom_cpuinfo linux_cpus[NCPUS]; - -#endif /* !(_SPARC_MP_H) */ diff --git a/include/asm-sparc/mpmbox.h b/include/asm-sparc/mpmbox.h index a8fa3240f335..0e1bc5801d8a 100644 --- a/include/asm-sparc/mpmbox.h +++ b/include/asm-sparc/mpmbox.h @@ -1,4 +1,4 @@ -/* $Id: mpmbox.h,v 1.3 1995/11/25 02:32:09 davem Exp $ +/* $Id: mpmbox.h,v 1.4 1996/04/25 06:13:19 davem Exp $ * mpmbox.h: Interface and defines for the OpenProm mailbox * facilities for MP machines under Linux. * diff --git a/include/asm-sparc/mxcc.h b/include/asm-sparc/mxcc.h index 63c31b6f2b28..7b273b650e88 100644 --- a/include/asm-sparc/mxcc.h +++ b/include/asm-sparc/mxcc.h @@ -1,4 +1,4 @@ -/* $Id: mxcc.h,v 1.3 1996/04/20 10:15:44 davem Exp $ +/* $Id: mxcc.h,v 1.4 1996/04/25 06:13:21 davem Exp $ * mxcc.h: Definitions of the Viking MXCC registers * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/openprom.h b/include/asm-sparc/openprom.h index 8362e02d2332..e30f681e403d 100644 --- a/include/asm-sparc/openprom.h +++ b/include/asm-sparc/openprom.h @@ -1,4 +1,4 @@ -/* $Id: openprom.h,v 1.15 1995/11/25 02:32:13 davem Exp $ */ +/* $Id: openprom.h,v 1.16 1996/04/23 01:54:46 davem Exp $ */ #ifndef __SPARC_OPENPROM_H #define __SPARC_OPENPROM_H diff --git a/include/asm-sparc/oplib.h b/include/asm-sparc/oplib.h index 51b2dc83d191..3504ef1faf07 100644 --- a/include/asm-sparc/oplib.h +++ b/include/asm-sparc/oplib.h @@ -1,4 +1,4 @@ -/* $Id: oplib.h,v 1.7 1996/04/04 16:31:25 tridge Exp $ +/* $Id: oplib.h,v 1.8 1996/04/25 06:13:23 davem Exp $ * oplib.h: Describes the interface and available routines in the * Linux Prom library. * diff --git a/include/asm-sparc/pconf.h b/include/asm-sparc/pconf.h index 84cc8dd242da..d73c1f1c49dc 100644 --- a/include/asm-sparc/pconf.h +++ b/include/asm-sparc/pconf.h @@ -1,4 +1,4 @@ -/* $Id: pconf.h,v 1.2 1995/11/25 02:32:20 davem Exp $ +/* $Id: pconf.h,v 1.3 1996/04/25 06:13:25 davem Exp $ * pconf.h: pathconf() and fpathconf() defines for SunOS * system call compatibility. * diff --git a/include/asm-sparc/pgtsrmmu.h b/include/asm-sparc/pgtsrmmu.h index 4ec29493e3c5..cb31df128d6d 100644 --- a/include/asm-sparc/pgtsrmmu.h +++ b/include/asm-sparc/pgtsrmmu.h @@ -1,4 +1,4 @@ -/* $Id: pgtsrmmu.h,v 1.16 1996/04/04 16:31:32 tridge Exp $ +/* $Id: pgtsrmmu.h,v 1.17 1996/04/25 06:13:26 davem Exp $ * pgtsrmmu.h: SRMMU page table defines and code. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/ptrace.h b/include/asm-sparc/ptrace.h index 758fc39ca584..b16592363a3a 100644 --- a/include/asm-sparc/ptrace.h +++ b/include/asm-sparc/ptrace.h @@ -1,4 +1,4 @@ -/* $Id: ptrace.h,v 1.19 1996/01/24 02:33:50 davem Exp $ */ +/* $Id: ptrace.h,v 1.20 1996/04/24 09:10:02 davem Exp $ */ #ifndef _SPARC_PTRACE_H #define _SPARC_PTRACE_H @@ -171,12 +171,8 @@ extern void show_regs(struct pt_regs *); #define SF_XXARG 0x5c /* Stuff for the ptrace system call */ -#if 0 /* Need to fix the header files a bit... */ -#undef PTRACE_ATTACH -#undef PTRACE_DETACH -#define PTRACE_ATTACH 10 -#define PTRACE_DETACH 11 -#endif +#define PTRACE_SUNATTACH 10 +#define PTRACE_SUNDETACH 11 #define PTRACE_GETREGS 12 #define PTRACE_SETREGS 13 #define PTRACE_GETFPREGS 14 diff --git a/include/asm-sparc/signal.h b/include/asm-sparc/signal.h index ee8295d3b875..0b2351d8215b 100644 --- a/include/asm-sparc/signal.h +++ b/include/asm-sparc/signal.h @@ -1,4 +1,4 @@ -/* $Id: signal.h,v 1.20 1996/03/24 20:21:27 davem Exp $ */ +/* $Id: signal.h,v 1.21 1996/04/25 06:13:28 davem Exp $ */ #ifndef _ASMSPARC_SIGNAL_H #define _ASMSPARC_SIGNAL_H diff --git a/include/asm-sparc/solerrno.h b/include/asm-sparc/solerrno.h index 6a388efc11fa..8abce7e4639f 100644 --- a/include/asm-sparc/solerrno.h +++ b/include/asm-sparc/solerrno.h @@ -1,4 +1,4 @@ -/* $Id: solerrno.h,v 1.4 1996/03/23 02:40:09 davem Exp $ +/* $Id: solerrno.h,v 1.5 1996/04/25 06:13:32 davem Exp $ * solerrno.h: Solaris error return codes for compatibility. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/traps.h b/include/asm-sparc/traps.h index 8bdc39f3c17c..84673a3dba22 100644 --- a/include/asm-sparc/traps.h +++ b/include/asm-sparc/traps.h @@ -1,4 +1,4 @@ -/* $Id: traps.h,v 1.5 1995/11/25 02:33:05 davem Exp $ +/* $Id: traps.h,v 1.6 1996/04/25 06:13:33 davem Exp $ * traps.h: Format of entries for the Sparc trap table. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff --git a/include/asm-sparc/unistd.h b/include/asm-sparc/unistd.h index 2de3db6cbdcc..2c32f2276e47 100644 --- a/include/asm-sparc/unistd.h +++ b/include/asm-sparc/unistd.h @@ -1,4 +1,4 @@ -/* $Id: unistd.h,v 1.20 1996/04/20 07:54:39 davem Exp $ */ +/* $Id: unistd.h,v 1.21 1996/04/25 06:13:35 davem Exp $ */ #ifndef _SPARC_UNISTD_H #define _SPARC_UNISTD_H diff --git a/include/asm-sparc/vac-ops.h b/include/asm-sparc/vac-ops.h index 800ce142cf70..ac434d40bdd1 100644 --- a/include/asm-sparc/vac-ops.h +++ b/include/asm-sparc/vac-ops.h @@ -1,4 +1,4 @@ -/* $Id: vac-ops.h,v 1.10 1996/04/04 12:51:36 davem Exp $ */ +/* $Id: vac-ops.h,v 1.11 1996/04/25 06:13:38 davem Exp $ */ #ifndef _SPARC_VAC_OPS_H #define _SPARC_VAC_OPS_H diff --git a/include/asm-sparc/vaddrs.h b/include/asm-sparc/vaddrs.h index c7deddc72a79..6b0000c3c355 100644 --- a/include/asm-sparc/vaddrs.h +++ b/include/asm-sparc/vaddrs.h @@ -1,4 +1,4 @@ -/* $Id: vaddrs.h,v 1.19 1996/03/26 06:51:58 miguel Exp $ */ +/* $Id: vaddrs.h,v 1.20 1996/04/25 06:13:40 davem Exp $ */ #ifndef _SPARC_VADDRS_H #define _SPARC_VADDRS_H diff --git a/include/asm-sparc/viking.h b/include/asm-sparc/viking.h index be3bf654df1e..10253172734c 100644 --- a/include/asm-sparc/viking.h +++ b/include/asm-sparc/viking.h @@ -1,4 +1,4 @@ -/* $Id: viking.h,v 1.12 1996/04/20 10:15:46 davem Exp $ +/* $Id: viking.h,v 1.13 1996/04/25 06:13:43 davem Exp $ * viking.h: Defines specific to the GNU/Viking MBUS module. * This is SRMMU stuff. * diff --git a/include/linux/blk.h b/include/linux/blk.h index b1e66ce622ed..d2f5b562ef40 100644 --- a/include/linux/blk.h +++ b/include/linux/blk.h @@ -318,7 +318,7 @@ static void floppy_off(unsigned int nr); #define CURRENT_DEV DEVICE_NR(CURRENT->rq_dev) #ifdef DEVICE_INTR -void (*DEVICE_INTR)(void) = NULL; +static void (*DEVICE_INTR)(void) = NULL; #endif #ifdef DEVICE_TIMEOUT diff --git a/include/linux/config.h b/include/linux/config.h index add2f6bb53bf..da47f8c39974 100644 --- a/include/linux/config.h +++ b/include/linux/config.h @@ -27,6 +27,8 @@ * in linux/version.h, and should only be used by linux/version.c */ +/* Shouldn't these be defined somewhere in a i386 definition? */ + /* Don't touch these, unless you really know what you're doing. */ #define DEF_INITSEG 0x9000 #define DEF_SYSSEG 0x1000 diff --git a/include/linux/console.h b/include/linux/console.h index 102d60f32b6b..f879fde222f1 100644 --- a/include/linux/console.h +++ b/include/linux/console.h @@ -101,6 +101,8 @@ struct consw { int (*con_bmove)(struct vc_data *, int, int, int, int, int, int); int (*con_switch)(struct vc_data *); int (*con_blank)(int); + int (*con_get_font)(struct vc_data *, int *, int *, char *); + int (*con_set_font)(struct vc_data *, int, int, char *); }; extern struct consw *conswitchp; diff --git a/include/linux/fb.h b/include/linux/fb.h index 322c330512dc..f97a313c60fe 100644 --- a/include/linux/fb.h +++ b/include/linux/fb.h @@ -3,11 +3,6 @@ /* Definitions of frame buffers */ -#ifdef __KERNEL__ -#include -#include -#endif - /* ioctls 0x46 is 'F' */ #define FBIOGET_VSCREENINFO 0x4600 @@ -39,7 +34,8 @@ struct fb_fix_screeninfo { u_short xpanstep; /* zero if no hardware panning */ u_short ypanstep; /* zero if no hardware panning */ u_short ywrapstep; /* zero if no hardware ywrap */ - short reserved[11]; /* Reserved for future compatibility */ + u_long line_length; /* length of a line in bytes */ + short reserved[9]; /* Reserved for future compatibility */ }; struct fb_bitfield { @@ -78,6 +74,8 @@ struct fb_bitfield { #define FB_VMODE_MASK 255 #define FB_VMODE_YWRAP 256 /* ywrap instead of panning */ +#define FB_VMODE_SMOOTH_XPAN 512 /* smooth xpan possible (internally used) */ +#define FB_VMODE_CONUPDATE 512 /* don't update x/yoffset */ struct fb_var_screeninfo { int xres; /* visible resolution */ @@ -128,12 +126,14 @@ struct fb_cmap { #ifdef __KERNEL__ +#include + struct fb_ops { - /* get non setable parameters */ + /* get non settable parameters */ int (*fb_get_fix) (struct fb_fix_screeninfo *, int); - /* get setable parameters */ + /* get settable parameters */ int (*fb_get_var) (struct fb_var_screeninfo *, int); - /* set setable parameters */ + /* set settable parameters */ int (*fb_set_var) (struct fb_var_screeninfo *, int); /* get colormap */ int (*fb_get_cmap) (struct fb_cmap *, int, int); @@ -156,43 +156,6 @@ int unregister_framebuffer(int); */ struct display { -/* - * As long as the old Amiga screen driver is being used, we have to - * include these old parameters. - */ -#if defined(CONFIG_AMIGA) - ushort scr_max_height; /* screen dimensions */ - ushort scr_max_width; - ushort scr_height; - ushort scr_width; - ushort scr_depth; - int bytes_per_row; /* offset to one line below */ - - ulong crsrcol; - - ushort scroll_latch; /* Vblank support for hardware scroll */ - ushort y_wrap; - ushort cursor_latch; /* Hardware cursor */ - ushort *cursor, *dummy; - ushort cursor_flash; - ushort cursor_visible; - - /* Some chipreg values we need to rebuild copper lists */ - ushort diwstrt_v, diwstrt_h; /* display window control */ - ushort diwstop_v, diwstop_h; - ushort bplcon0; /* display mode */ - ushort htotal; - - u_char *bitplane[8]; /* pointers to display bitplanes */ - ulong plane_size; - - ushort *coplist1hdr; /* List 1 static component */ - ushort *coplist1dyn; /* List 1 dynamic component */ - ushort *coplist2hdr; /* List 2 static component */ - ushort *coplist2dyn; /* List 2 dynamic component */ - -#endif - /* Filled in by the frame buffer device */ struct fb_var_screeninfo var; /* variable infos. yoffset and vmode */ @@ -204,6 +167,7 @@ struct display { int type_aux; /* Interleave for interleaved Planes */ u_short ypanstep; /* zero if no hardware ypan */ u_short ywrapstep; /* zero if no hardware ywrap */ + u_long line_length; /* length of a line in bytes */ u_short can_soft_blank; /* zero if no hardware blanking */ u_short inverse; /* != 0 text black on white as default */ @@ -216,6 +180,7 @@ struct display { /* Filled in by the low-level console driver */ struct vc_data *conp; /* pointer to console data */ + int vrows; /* number of virtual rows */ int cursor_x; /* current cursor position */ int cursor_y; int fgcol; /* text colors */ @@ -225,6 +190,7 @@ struct display { u_char *fontdata; /* Font associated to this display */ int fontheight; int fontwidth; + int userfont; /* != 0 if fontdata kmalloc()ed */ struct display_switch *dispsw; /* low level operations */ u_short scrollmode; /* Scroll Method */ short yscroll; /* Hardware scrolling */ @@ -274,7 +240,11 @@ struct fb_fix_cursorinfo { }; struct fb_var_cursorinfo { - u_long data[256]; /* max. 64x64 (ilbm, 2 planes) */ + u_short width; + u_short height; + u_short xspot; + u_short yspot; + u_char data[1]; /* field with [height][width] */ }; struct fb_cursorstate { @@ -287,6 +257,31 @@ struct fb_cursorstate { #define FB_CURSOR_ON 1 #define FB_CURSOR_FLASH 2 +#define FBCMD_DRAWLINE 0x4621 +#define FBCMD_MOVE 0x4622 + +#define FB_LINE_XOR 1 +#define FB_LINE_BOX 2 +#define FB_LINE_FILLED 4 + +struct fb_line { + int start_x; + int start_y; + int end_x; + int end_y; + int color; + int option; +}; + +struct fb_move { + int src_x; + int src_y; + int dest_x; + int dest_y; + int height; + int width; +}; + #endif /* Preliminary */ diff --git a/include/linux/genhd.h b/include/linux/genhd.h index 75d1dd598c58..a028fb2514ad 100644 --- a/include/linux/genhd.h +++ b/include/linux/genhd.h @@ -9,13 +9,15 @@ * */ +#include + #define CONFIG_MSDOS_PARTITION 1 #ifdef __alpha__ #define CONFIG_OSF_PARTITION 1 #endif -#ifdef __sparc__ +#if defined(__sparc__) || defined(CONFIG_SMD_DISKLABEL) #define CONFIG_SUN_PARTITION 1 #endif @@ -64,6 +66,61 @@ struct gendisk { struct gendisk *next; }; +#ifdef CONFIG_BSD_DISKLABEL +/* + * BSD disklabel support by Yossi Gottlieb + */ + +#define BSD_PARTITION 0xa5 /* Partition ID */ + +#define BSD_DISKMAGIC (0x82564557UL) /* The disk magic number */ +#define BSD_MAXPARTITIONS 8 +#define BSD_FS_UNUSED 0 /* disklabel unused partition entry ID */ +struct bsd_disklabel { + __u32 d_magic; /* the magic number */ + __s16 d_type; /* drive type */ + __s16 d_subtype; /* controller/d_type specific */ + char d_typename[16]; /* type name, e.g. "eagle" */ + char d_packname[16]; /* pack identifier */ + __u32 d_secsize; /* # of bytes per sector */ + __u32 d_nsectors; /* # of data sectors per track */ + __u32 d_ntracks; /* # of tracks per cylinder */ + __u32 d_ncylinders; /* # of data cylinders per unit */ + __u32 d_secpercyl; /* # of data sectors per cylinder */ + __u32 d_secperunit; /* # of data sectors per unit */ + __u16 d_sparespertrack; /* # of spare sectors per track */ + __u16 d_sparespercyl; /* # of spare sectors per cylinder */ + __u32 d_acylinders; /* # of alt. cylinders per unit */ + __u16 d_rpm; /* rotational speed */ + __u16 d_interleave; /* hardware sector interleave */ + __u16 d_trackskew; /* sector 0 skew, per track */ + __u16 d_cylskew; /* sector 0 skew, per cylinder */ + __u32 d_headswitch; /* head switch time, usec */ + __u32 d_trkseek; /* track-to-track seek, usec */ + __u32 d_flags; /* generic flags */ +#define NDDATA 5 + __u32 d_drivedata[NDDATA]; /* drive-type specific information */ +#define NSPARE 5 + __u32 d_spare[NSPARE]; /* reserved for future use */ + __u32 d_magic2; /* the magic number (again) */ + __u16 d_checksum; /* xor of data incl. partitions */ + + /* filesystem and partition information: */ + __u16 d_npartitions; /* number of partitions in following */ + __u32 d_bbsize; /* size of boot area at sn0, bytes */ + __u32 d_sbsize; /* max size of fs superblock, bytes */ + struct bsd_partition { /* the partition table */ + __u32 p_size; /* number of sectors in partition */ + __u32 p_offset; /* starting sector */ + __u32 p_fsize; /* filesystem basic fragment size */ + __u8 p_fstype; /* filesystem type, see below */ + __u8 p_frag; /* filesystem fragments per block */ + __u16 p_cpg; /* filesystem cylinders per group */ + } d_partitions[BSD_MAXPARTITIONS]; /* actually may be more */ +}; + +#endif /* CONFIG_BSD_DISKLABEL */ + extern struct gendisk *gendisk_head; /* linked list of disks */ /* diff --git a/include/linux/if_arp.h b/include/linux/if_arp.h index f52aad01df00..7f972a51b0e2 100644 --- a/include/linux/if_arp.h +++ b/include/linux/if_arp.h @@ -22,6 +22,7 @@ #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 */ diff --git a/include/linux/major.h b/include/linux/major.h index a1af9b745ff3..906874b95bcc 100644 --- a/include/linux/major.h +++ b/include/linux/major.h @@ -33,6 +33,7 @@ #define XT_DISK_MAJOR 13 #define SOUND_MAJOR 14 #define CDU31A_CDROM_MAJOR 15 +#define JOYSTICK_MAJOR 15 #define GOLDSTAR_CDROM_MAJOR 16 #define OPTICS_CDROM_MAJOR 17 #define SANYO_CDROM_MAJOR 18 @@ -54,17 +55,20 @@ #define MATSUSHITA_CDROM3_MAJOR 27 #define MATSUSHITA_CDROM4_MAJOR 28 #define STL_SIOMEMMAJOR 28 +#define ACSI_MAJOR 28 #define AZTECH_CDROM_MAJOR 29 -#define GRAPHDEV_MAJOR 29 /* SparcLinux /dev/fb */ +#define GRAPHDEV_MAJOR 29 /* SparcLinux & Linux/68k /dev/fb */ #define CM206_CDROM_MAJOR 32 #define IDE2_MAJOR 33 #define IDE3_MAJOR 34 #define NETLINK_MAJOR 36 #define IDETAPE_MAJOR 37 +#define Z2RAM_MAJOR 37 #define RISCOM8_NORMAL_MAJOR 48 #define RISCOM8_CALLOUT_MAJOR 49 #define APBLOCK_MAJOR 60 /* AP1000 Block device */ #define DDV_MAJOR 61 /* AP1000 DDV block device */ + /* * Tests for SCSI devices. */ diff --git a/include/linux/miscdevice.h b/include/linux/miscdevice.h index 07c74e1165da..f8ea74922e30 100644 --- a/include/linux/miscdevice.h +++ b/include/linux/miscdevice.h @@ -5,6 +5,8 @@ #define PSMOUSE_MINOR 1 #define MS_BUSMOUSE_MINOR 2 #define ATIXL_BUSMOUSE_MINOR 3 +#define AMIGAMOUSE_MINOR 4 +#define ATARIMOUSE_MINOR 5 #define SUN_MOUSE_MINOR 6 #define MISC_DYNAMIC_MINOR 255 diff --git a/include/linux/mm.h b/include/linux/mm.h index 8733a8a886d8..0e936afe9175 100644 --- a/include/linux/mm.h +++ b/include/linux/mm.h @@ -4,6 +4,9 @@ #include #include #include + +#ifdef __KERNEL__ + #include extern unsigned long high_memory; @@ -11,8 +14,6 @@ extern unsigned long high_memory; #include #include -#ifdef __KERNEL__ - #define VERIFY_READ 0 #define VERIFY_WRITE 1 diff --git a/include/linux/proc_fs.h b/include/linux/proc_fs.h index 267c33f30024..9164d5553a94 100644 --- a/include/linux/proc_fs.h +++ b/include/linux/proc_fs.h @@ -131,6 +131,10 @@ enum scsi_directory_inos { PROC_SCSI_NCR53C406A, PROC_SCSI_PPA, PROC_SCSI_ESP, + PROC_SCSI_A3000, + PROC_SCSI_A2091, + PROC_SCSI_GVP11, + PROC_SCSI_ATARI, PROC_SCSI_SCSI_DEBUG, PROC_SCSI_NOT_PRESENT, PROC_SCSI_FILE, /* I'm assuming here that we */ diff --git a/include/linux/sched.h b/include/linux/sched.h index e6f60fb46bb0..fd2d8a1783fe 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h @@ -269,6 +269,7 @@ struct task_struct { #define PF_EXITING 0x00000200 /* getting shut down */ #define PF_USEDFPU 0x00100000 /* Process used the FPU this quantum (SMP only) */ +#define PF_DTRACE 0x00200000 /* delayed trace (used on m68k) */ /* * Limit the stack by to some sane default: root can always @@ -344,6 +345,7 @@ extern void wake_up_interruptible(struct wait_queue ** p); extern void wake_up_process(struct task_struct * tsk); extern void notify_parent(struct task_struct * tsk); +extern void force_sig(unsigned long sig,struct task_struct * p); extern int send_sig(unsigned long sig,struct task_struct * p,int priv); extern int in_group_p(gid_t grp); @@ -373,6 +375,7 @@ extern void copy_thread(int, unsigned long, unsigned long, struct task_struct *, extern void flush_thread(void); extern void exit_thread(void); +extern void exit_mm(struct task_struct *); extern void exit_fs(struct task_struct *); extern void exit_files(struct task_struct *); extern void exit_sighand(struct task_struct *); diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index cd3bdc4da6d9..d61c6fb2514c 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -13,10 +13,9 @@ #ifndef _LINUX_SKBUFF_H #define _LINUX_SKBUFF_H -#include -#include -#include + #include +#include #include @@ -131,6 +130,7 @@ struct sk_buff /* * Handling routines are only of interest to the kernel */ +#include #include diff --git a/include/linux/timex.h b/include/linux/timex.h index 0de6d4f55749..c532629e318d 100644 --- a/include/linux/timex.h +++ b/include/linux/timex.h @@ -17,12 +17,27 @@ /* * Modification history timex.h * + * 26 Sep 94 David L. Mills + * Added defines for hybrid phase/frequency-lock loop. + * + * 19 Mar 94 David L. Mills + * Moved defines from kernel routines to header file and added new + * defines for PPS phase-lock loop. + * + * 20 Feb 94 David L. Mills + * Revised status codes and structures for external clock and PPS + * signal discipline. + * + * 28 Nov 93 David L. Mills + * Adjusted parameters to improve stability and increase poll + * interval. + * * 17 Sep 93 David L. Mills * Created file $NTP/include/sys/timex.h * 07 Oct 93 Torsten Duwe * Derived linux/timex.h * 1995-08-13 Torsten Duwe - * kernel PLL updated to 1994-12-13 specs (rfc-1489) + * kernel PLL updated to 1994-12-13 specs (rfc-1589) */ #ifndef _LINUX_TIMEX_H #define _LINUX_TIMEX_H @@ -67,14 +82,16 @@ * SHIFT_USEC defines the scaling (shift) of the time_freq and * time_tolerance variables, which represent the current frequency * offset and maximum frequency tolerance. + * + * FINEUSEC is 1 us in SHIFT_UPDATE units of the time_phase variable. */ -#define SHIFT_SCALE 22 /* shift for phase scale factor */ -#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* shift for offset scale factor */ +#define SHIFT_SCALE 22 /* phase scale (shift) */ +#define SHIFT_UPDATE (SHIFT_KG + MAXTC) /* time offset scale (shift) */ #define SHIFT_USEC 16 /* frequency offset scale (shift) */ #define FINEUSEC (1L << SHIFT_SCALE) /* 1 us in phase units */ #define MAXPHASE 512000L /* max phase error (us) */ -#define MAXFREQ (100L << SHIFT_USEC) /* max frequency error (ppm) */ +#define MAXFREQ (512L << SHIFT_USEC) /* max frequency error (ppm) */ #define MAXTIME (200L << PPS_AVG) /* max PPS error (jitter) (200 us) */ #define MINSEC 16L /* min interval between updates (s) */ #define MAXSEC 1200L /* max interval between updates (s) */ @@ -171,6 +188,9 @@ struct timex { #define MOD_ESTERROR ADJ_ESTERROR #define MOD_STATUS ADJ_STATUS #define MOD_TIMECONST ADJ_TIMECONST +#define MOD_CLKB ADJ_TICK +#define MOD_CLKA ADJ_OFFSET_SINGLESHOT /* 0x8000 in original */ + /* * Status codes (timex.status) @@ -198,17 +218,19 @@ struct timex { /* * Clock states (time_state) */ -#define TIME_OK 0 /* clock synchronized */ +#define TIME_OK 0 /* clock synchronized, no leap second */ #define TIME_INS 1 /* insert leap second */ #define TIME_DEL 2 /* delete leap second */ #define TIME_OOP 3 /* leap second in progress */ -#define TIME_WAIT 4 /* leap second has occurred */ +#define TIME_WAIT 4 /* leap second has occured */ #define TIME_ERROR 5 /* clock not synchronized */ #define TIME_BAD TIME_ERROR /* bw compat */ #ifdef __KERNEL__ /* * kernel variables + * Note: maximum error = NTP synch distance = dispersion + delay / 2; + * estimated error = NTP dispersion. */ extern long tick; /* timer interrupt period */ extern int tickadj; /* amount of adjustment per tick */ diff --git a/include/linux/ufs_fs.h b/include/linux/ufs_fs.h index 5dc8fc6e3fde..3688fa5942d6 100644 --- a/include/linux/ufs_fs.h +++ b/include/linux/ufs_fs.h @@ -153,7 +153,7 @@ struct ufs_superblock { ufsquad fs_qbmask; /* ~usb_bmask - for use with __s64 size */ ufsquad fs_qfmask; /* ~usb_fmask - for use with __s64 size */ __s32 fs_postblformat; /* format of positional layout tables */ - __s32 fs_nrpos; /* number of rotaional positions */ + __s32 fs_nrpos; /* number of rotational positions */ __s32 fs_postbloff; /* (__s16) rotation block list head */ __s32 fs_rotbloff; /* (__u8) blocks for each rotation */ __s32 fs_magic; /* magic number */ diff --git a/include/net/tcp.h b/include/net/tcp.h index a4a0333dfad3..fd0a4248a9a6 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -127,7 +127,6 @@ static __inline__ int max(unsigned int a, unsigned int b) extern struct proto tcp_prot; extern struct tcp_mib tcp_statistics; -extern struct wait_queue *master_select_wakeup; extern void tcp_err(int type, int code, unsigned char *header, __u32 daddr, __u32, struct inet_protocol *protocol); @@ -311,10 +310,6 @@ static __inline__ void tcp_set_state(struct sock *sk, int state) case TCP_ESTABLISHED: if (oldstate != TCP_ESTABLISHED) { tcp_statistics.TcpCurrEstab++; - /* This is a hack but it doesn't occur often and it's going to - be a real to fix nicely */ - if (oldstate == TCP_SYN_RECV) - wake_up_interruptible(&master_select_wakeup); } break; diff --git a/init/main.c b/init/main.c index 01042217029e..3175251b6e9c 100644 --- a/init/main.c +++ b/init/main.c @@ -121,6 +121,7 @@ extern void isp16_setup(char *str, int *ints); static void ramdisk_start_setup(char *str, int *ints); static void load_ramdisk(char *str, int *ints); static void prompt_ramdisk(char *str, int *ints); +static void ramdisk_size(char *str, int *ints); #ifdef CONFIG_BLK_DEV_INITRD static void no_initrd(char *s,int *ints); #endif @@ -132,6 +133,18 @@ extern void icn_setup(char *str, int *ints); extern void teles_setup(char *str, int *ints); #endif +#ifdef CONFIG_ATARIMOUSE +extern void atari_mouse_setup (char *str, int *ints); +#endif +#ifdef CONFIG_DMASOUND +extern void dmasound_setup (char *str, int *ints); +#endif +#ifdef CONFIG_ATARI_SCSI +extern void atari_scsi_setup (char *str, int *ints); +#endif +extern void wd33c93_setup (char *str, int *ints); +extern void gvp11_setup (char *str, int *ints); + #ifdef CONFIG_DIGI extern void pcxx_setup(char *str, int *ints); #endif @@ -163,6 +176,7 @@ int rows, cols; #ifdef CONFIG_BLK_DEV_RAM extern int rd_doload; /* 1 = load ramdisk, 0 = don't load */ extern int rd_prompt; /* 1 = prompt for ramdisk, 0 = don't prompt */ +extern int rd_size; /* Size of the ramdisk(s) */ extern int rd_image_start; /* starting block # of image */ #ifdef CONFIG_BLK_DEV_INITRD kdev_t real_root_dev; @@ -224,6 +238,8 @@ struct { { "ramdisk_start=", ramdisk_start_setup }, { "load_ramdisk=", load_ramdisk }, { "prompt_ramdisk=", prompt_ramdisk }, + { "ramdisk=", ramdisk_size }, + { "ramdisk_size=", ramdisk_size }, #ifdef CONFIG_BLK_DEV_INITRD { "noinitrd", no_initrd }, #endif @@ -346,6 +362,22 @@ struct { #ifdef CONFIG_ISDN_DRV_PCBIT { "pcbit=", pcbit_setup }, #endif +#ifdef CONFIG_ATARIMOUSE + { "atamouse=", atari_mouse_setup }, +#endif +#ifdef CONFIG_DMASOUND + { "dmasound=", dmasound_setup }, +#endif +#ifdef CONFIG_ATARI_SCSI + { "atascsi=", atari_scsi_setup }, +#endif +#if defined(CONFIG_A3000_SCSI) || defined(CONFIG_A2091_SCSI) \ + || defined(CONFIG_GVP11_SCSI) + { "wd33c93=", wd33c93_setup }, +#endif +#if defined(CONFIG_GVP11_SCSI) + { "gvp11=", gvp11_setup }, +#endif #ifdef CONFIG_DIGI { "digi=", pcxx_setup }, #endif @@ -373,6 +405,13 @@ static void prompt_ramdisk(char *str, int *ints) if (ints[0] > 0 && ints[1] >= 0) rd_prompt = ints[1] & 1; } + +static void ramdisk_size(char *str, int *ints) +{ + if (ints[0] > 0 && ints[1] >= 0) + rd_size = ints[1]; +} + #endif static int checksetup(char *line) diff --git a/ipc/shm.c b/ipc/shm.c index 91eabfcb80e0..396d20ad513c 100644 --- a/ipc/shm.c +++ b/ipc/shm.c @@ -454,7 +454,7 @@ static int shm_map (struct vm_area_struct *shmd) set_pte(page_table, __pte(shm_sgn)); } flush_tlb_range(shmd->vm_mm, shmd->vm_start, shmd->vm_end); - return 0; + return error; } /* diff --git a/kernel/exit.c b/kernel/exit.c index f8e6c439dfc8..d483a0b388ce 100644 --- a/kernel/exit.c +++ b/kernel/exit.c @@ -49,6 +49,26 @@ static inline void generate(unsigned long sig, struct task_struct * p) wake_up_process(p); } +/* + * Force a signal that the process can't ignore: if necessary + * we unblock the signal and change any SIG_IGN to SIG_DFL. + */ +void force_sig(unsigned long sig, struct task_struct * p) +{ + sig--; + if (p->sig) { + unsigned long mask = 1UL << sig; + struct sigaction *sa = p->sig->action + sig; + p->signal |= mask; + p->blocked &= ~mask; + if (sa->sa_handler == SIG_IGN) + sa->sa_handler = SIG_DFL; + if (p->state == TASK_INTERRUPTIBLE) + wake_up_process(p); + } +} + + int send_sig(unsigned long sig,struct task_struct * p,int priv) { if (!p || sig > 32) @@ -428,17 +448,17 @@ void exit_sighand(struct task_struct *tsk) __exit_sighand(tsk); } -static inline void exit_mm(void) +static inline void __exit_mm(struct task_struct * tsk) { - struct mm_struct * mm = current->mm; + struct mm_struct * mm = tsk->mm; /* Set us up to use the kernel mm state */ if (mm != &init_mm) { flush_cache_mm(mm); flush_tlb_mm(mm); - current->mm = &init_mm; - current->swappable = 0; - SET_PAGE_DIR(current, swapper_pg_dir); + tsk->mm = &init_mm; + tsk->swappable = 0; + SET_PAGE_DIR(tsk, swapper_pg_dir); /* free the old state - not used any more */ if (!--mm->count) { @@ -449,6 +469,11 @@ static inline void exit_mm(void) } } +void exit_mm(struct task_struct *tsk) +{ + __exit_mm(tsk); +} + /* * Send signals to all our closest relatives so that they know * to properly mourn us.. @@ -528,7 +553,7 @@ fake_volatile: del_timer(¤t->real_timer); sem_exit(); kerneld_exit(); - exit_mm(); + __exit_mm(current); __exit_files(current); __exit_fs(current); __exit_sighand(current); diff --git a/kernel/sched.c b/kernel/sched.c index f1059dc15632..f58e7cea37ca 100644 --- a/kernel/sched.c +++ b/kernel/sched.c @@ -2,6 +2,8 @@ * linux/kernel/sched.c * * Copyright (C) 1991, 1992 Linus Torvalds + * + * 1996-04-21 Modified by Ulrich Windl to make NTP work */ /* @@ -52,14 +54,15 @@ DECLARE_TASK_QUEUE(tq_scheduler); /* * phase-lock loop variables */ -int time_state = TIME_BAD; /* clock synchronization status */ -int time_status = STA_UNSYNC | STA_PLL; /* clock status bits */ +/* TIME_ERROR prevents overwriting the CMOS clock */ +int time_state = TIME_ERROR; /* clock synchronization status */ +int time_status = STA_UNSYNC; /* clock status bits */ long time_offset = 0; /* time adjustment (us) */ long time_constant = 2; /* 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_maxerror = MAXPHASE; /* maximum error (us) */ +long time_esterror = MAXPHASE; /* estimated error (us) */ 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) */ @@ -396,7 +399,8 @@ asmlinkage void schedule(void) return; scheduling_in_interrupt: - printk("Aiee: scheduling in interrupt\n"); + printk("Aiee: scheduling in interrupt %p\n", + __builtin_return_address(0)); } #ifndef __alpha__ @@ -665,9 +669,9 @@ static void second_overflow(void) long ltemp; /* Bump the maxerror field */ - time_maxerror = (0x70000000-time_maxerror < - time_tolerance >> SHIFT_USEC) ? - 0x70000000 : (time_maxerror + (time_tolerance >> SHIFT_USEC)); + time_maxerror += time_tolerance >> SHIFT_USEC; + if ( time_maxerror > MAXPHASE ) + time_maxerror = MAXPHASE; /* * Leap second processing. If in leap-insert state at @@ -704,7 +708,6 @@ static void second_overflow(void) break; case TIME_OOP: - time_state = TIME_WAIT; break; @@ -727,21 +730,17 @@ static void second_overflow(void) if (!(time_status & STA_FLL)) ltemp >>= SHIFT_KG + time_constant; if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE) - ltemp = (MAXPHASE / MINSEC) << - SHIFT_UPDATE; + ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE; time_offset += ltemp; - time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - - SHIFT_UPDATE); + time_adj = -ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); } else { ltemp = time_offset; if (!(time_status & STA_FLL)) ltemp >>= SHIFT_KG + time_constant; if (ltemp > (MAXPHASE / MINSEC) << SHIFT_UPDATE) - ltemp = (MAXPHASE / MINSEC) << - SHIFT_UPDATE; + ltemp = (MAXPHASE / MINSEC) << SHIFT_UPDATE; time_offset -= ltemp; - time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - - SHIFT_UPDATE); + time_adj = ltemp << (SHIFT_SCALE - SHIFT_HZ - SHIFT_UPDATE); } /* @@ -775,6 +774,7 @@ static void second_overflow(void) #endif } +/* in the NTP reference this is called "hardclock()" */ static void update_wall_time_one_tick(void) { /* diff --git a/kernel/time.c b/kernel/time.c index 331747c15972..931b52b4c785 100644 --- a/kernel/time.c +++ b/kernel/time.c @@ -75,9 +75,9 @@ asmlinkage int sys_stime(int * tptr) cli(); xtime.tv_sec = value; xtime.tv_usec = 0; - time_state = TIME_BAD; - time_maxerror = 0x70000000; - time_esterror = 0x70000000; + time_state = TIME_ERROR; + time_maxerror = MAXPHASE; + time_esterror = MAXPHASE; sti(); return 0; } @@ -317,7 +317,7 @@ asmlinkage int sys_adjtimex(struct timex *txc_p) time_freq = time_tolerance; else if (time_freq < -time_tolerance) time_freq = -time_tolerance; - } + } /* STA_PLL || STA_PPSTIME */ if (txc.modes & ADJ_TICK) tick = txc.tick; diff --git a/mm/filemap.c b/mm/filemap.c index c8616b7ba98c..8bae43ef5f36 100644 --- a/mm/filemap.c +++ b/mm/filemap.c @@ -424,8 +424,8 @@ static void profile_readahead(int async, struct file *filp) * We try to have a limit of MAX_READWINDOW = 48K. */ -#define MAX_READWINDOW (PAGE_SIZE*32) -#define MAX_READAHEAD (PAGE_SIZE*16) +#define MAX_READWINDOW (PAGE_SIZE*12) +#define MAX_READAHEAD (PAGE_SIZE*7) #define MIN_READAHEAD (PAGE_SIZE) static inline unsigned long generic_file_readahead(struct file * filp, struct inode * inode, @@ -987,7 +987,7 @@ static int filemap_sync(struct vm_area_struct * vma, unsigned long address, unsigned long end = address + size; int error = 0; - dir = pgd_offset(current->mm, address); + dir = pgd_offset(vma->vm_mm, address); flush_cache_range(vma->vm_mm, end - size, end); while (address < end) { error |= filemap_sync_pmd_range(dir, address, end - address, vma, flags); diff --git a/mm/memory.c b/mm/memory.c index 8fe9d3e54f2c..7957bb286454 100644 --- a/mm/memory.c +++ b/mm/memory.c @@ -931,7 +931,7 @@ void do_no_page(struct task_struct * tsk, struct vm_area_struct * vma, */ page = vma->vm_ops->nopage(vma, address, write_access && !(vma->vm_flags & VM_SHARED)); if (!page) { - send_sig(SIGBUS, current, 1); + force_sig(SIGBUS, current); flush_cache_page(vma, address); put_page(page_table, BAD_PAGE); flush_tlb_page(vma, address); diff --git a/net/README b/net/README index 7c9432a948b3..69ba2561c6ec 100644 --- a/net/README +++ b/net/README @@ -6,12 +6,12 @@ Code Section Bug Report Contact 802 [other ] alan@cymru.net [token ring ] needs a maintainer/debugger appletalk alan@cymru.net and netatalk@umich.edu -ax25 g4klx@g4klx.demon.co.uk +ax25 jsn@cs.nott.ac.uk core alan@cymru.net ethernet alan@cymru.net ipv4 alan@cymru.net ipx alan@cymru.net,greg@caldera.com -netrom g4klx@g4klx.demon.co.uk +netrom jsn@cs.nott.ac.uk unix alan@cymru.net diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c index 187600fe2889..dd9f41ea1df5 100644 --- a/net/ax25/af_ax25.c +++ b/net/ax25/af_ax25.c @@ -614,7 +614,7 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) break; case AX25_T3: - if (ax25_ctl.arg < 1) + if (ax25_ctl.arg < 0) return -EINVAL; save_flags(flags); cli(); ax25->t3 = ax25_ctl.arg * PR_SLOWHZ; @@ -624,10 +624,8 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void *arg) break; case AX25_IDLE: - if (ax25_ctl.arg < 1) + if (ax25_ctl.arg < 0) return -EINVAL; - if (ax25->idle == 0) - return 0; save_flags(flags); cli(); ax25->idle = ax25_ctl.arg * PR_SLOWHZ * 60; if (ax25->idletimer != 0) @@ -682,7 +680,7 @@ static ax25_cb *ax25_create_cb(void) ax25->n2 = AX25_DEF_N2; ax25->paclen = AX25_DEF_PACLEN; ax25->maxqueue= AX25_DEF_IPMAXQUEUE; - ax25->idle = 0; + ax25->idle = AX25_DEF_IDLE; ax25->modulus = AX25_DEF_AXDEFMODE; ax25->fragno = 0; @@ -753,9 +751,9 @@ static void ax25_fillin_cb(ax25_cb *ax25, struct device *dev) ax25->n2 = ax25_dev_get_value(dev, AX25_VALUES_N2); ax25->paclen = ax25_dev_get_value(dev, AX25_VALUES_PACLEN); ax25->maxqueue = ax25_dev_get_value(dev, AX25_VALUES_IPMAXQUEUE); + ax25->idle = ax25_dev_get_value(dev, AX25_VALUES_IDLE); ax25->dama_slave = 0; - ax25->idle = 0; ax25->modulus = ax25_dev_get_value(dev, AX25_VALUES_AXDEFMODE); @@ -819,7 +817,7 @@ int ax25_send_frame(struct sk_buff *skb, ax25_address *src, ax25_address *dest, /* idle timeouts only for mode vc connections */ - ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE); + ax25->idletimer = ax25->idle; ax25_insert_socket(ax25); @@ -1196,7 +1194,8 @@ static struct sock *ax25_make_new(struct sock *osk, struct device *dev) ax25->idle = osk->ax25->idle; ax25->paclen = osk->ax25->paclen; - ax25->window = osk->ax25->window; + ax25->window = osk->ax25->window; + ax25->maxqueue = osk->ax25->maxqueue; ax25->source_addr = osk->ax25->source_addr; @@ -1823,7 +1822,7 @@ static int ax25_rcv(struct sk_buff *skb, struct device *dev, ax25_address *dev_a } ax25_fillin_cb(ax25, dev); - ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE); + ax25->idletimer = ax25->idle; #else if (mine) { ax25_rt_rx_frame(&src, dev, &dp); @@ -2272,7 +2271,6 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i int len = 0; off_t pos = 0; off_t begin = 0; - int idletimer; cli(); @@ -2283,9 +2281,6 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i devname = "???"; else devname = dev->name; - - idletimer = ax25->idletimer / (PR_SLOWHZ * 60); - idletimer += (ax25->idletimer && ax25->idletimer < ax25->idle)? 1:0; len += sprintf(buffer + len, "%-9s ", ax2asc(&ax25->dest_addr)); @@ -2299,8 +2294,8 @@ static int ax25_get_info(char *buffer, char **start, off_t offset, int length, i ax25->t2 / PR_SLOWHZ, ax25->t3timer / PR_SLOWHZ, ax25->t3 / PR_SLOWHZ, - idletimer, - ax25->idle / (PR_SLOWHZ*60), + ax25->idletimer / (PR_SLOWHZ * 60), + ax25->idle / (PR_SLOWHZ * 60), ax25->n2count, ax25->n2, ax25->rtt / PR_SLOWHZ, ax25->window, diff --git a/net/ax25/ax25_in.c b/net/ax25/ax25_in.c index 9757347af049..d3053e19a1ba 100644 --- a/net/ax25/ax25_in.c +++ b/net/ax25/ax25_in.c @@ -163,13 +163,14 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) unsigned char pid; if (skb == NULL) return 0; + + ax25->idletimer = ax25->idle; pid = *skb->data; switch (pid) { #ifdef CONFIG_NETROM case AX25_P_NETROM: - ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE); if (ax25_dev_get_value(ax25->device, AX25_VALUES_NETROM)) { skb_pull(skb, 1); /* Remove PID */ queued = nr_route_frame(skb, ax25); @@ -178,23 +179,19 @@ static int ax25_rx_iframe(ax25_cb *ax25, struct sk_buff *skb) #endif #ifdef CONFIG_INET case AX25_P_IP: - ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE); skb_pull(skb, 1); /* Remove PID */ skb->h.raw = skb->data; ax25_ip_mode_set(&ax25->dest_addr, ax25->device, 'V'); ip_rcv(skb, ax25->device, NULL); /* Wrong ptype */ queued = 1; - break; #endif case AX25_P_SEGMENT: - ax25->idletimer = ax25->idle = ax25_dev_get_value(ax25->device, AX25_VALUES_IDLE); skb_pull(skb, 1); /* Remove PID */ queued = ax25_rx_fragment(ax25, skb); break; default: - ax25->idletimer = ax25->idle = 0; if (ax25->sk != NULL && ax25_dev_get_value(ax25->device, AX25_VALUES_TEXT) && ax25->sk->protocol == pid) { if (sock_queue_rcv_skb(ax25->sk, skb) == 0) { queued = 1; diff --git a/net/ax25/ax25_out.c b/net/ax25/ax25_out.c index 823d682223b0..fd0f7cfa4bbf 100644 --- a/net/ax25/ax25_out.c +++ b/net/ax25/ax25_out.c @@ -77,21 +77,12 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb) mtu = ax25->paclen; if ((skb->len - 1) > mtu) { - switch (*skb->data) { - case AX25_P_SEGMENT: - /* this is an error, but... */ - printk("ax25_output(): woops, fragmentation of fragment?!\n"); - /* okay, let's fragment it further (tss, tss...) */ - case AX25_P_NETROM: /* err, is this a good idea? */ - case AX25_P_IP: - mtu -= 2; /* Allow for fragment control info */ - ka9qfrag = 1; - break; - default: - ka9qfrag = 0; - skb_pull(skb, 1); /* skip PID */ - break; - + if (*skb->data == AX25_P_TEXT) { + skb_pull(skb, 1); /* skip PID */ + ka9qfrag = 0; + } else { + mtu -= 2; /* Allow for fragment control info */ + ka9qfrag = 1; } fragno = skb->len / mtu; @@ -105,11 +96,10 @@ void ax25_output(ax25_cb *ax25, struct sk_buff *skb) /* * do _not_ use sock_alloc_send_skb, our socket may have * sk->shutdown set... - * */ if ((skbn = alloc_skb(mtu + 2 + frontlen, GFP_ATOMIC)) == NULL) { restore_flags(flags); - printk("ax25_output(): alloc_skb returned NULL\n"); + printk("ax25_output: alloc_skb returned NULL\n"); if (skb_device_locked(skb)) skb_device_unlock(skb); return; diff --git a/net/ax25/ax25_timer.c b/net/ax25/ax25_timer.c index 3b5237b8c2e1..aa34d77675a1 100644 --- a/net/ax25/ax25_timer.c +++ b/net/ax25/ax25_timer.c @@ -197,8 +197,7 @@ static void ax25_timer(unsigned long param) ax25->t1timer = ax25->t1 = ax25_calculate_t1(ax25); - if (ax25->sk != NULL) - { + if (ax25->sk != NULL) { ax25->sk->state = TCP_CLOSE; ax25->sk->err = 0; if (!ax25->sk->dead) @@ -208,7 +207,6 @@ static void ax25_timer(unsigned long param) } } - /* dl1bke 960114: DAMA T1 timeouts are handled in ax25_dama_slave_transmit */ /* nevertheless we have to re-enqueue the timer struct... */ diff --git a/net/bridge/br.c b/net/bridge/br.c index e6fd0bea5909..2d9a0863fa99 100644 --- a/net/bridge/br.c +++ b/net/bridge/br.c @@ -1065,6 +1065,8 @@ int br_receive_frame(struct sk_buff *skb) /* 3.5 */ return(0); port = find_port(skb->dev); + + skb->arp = 1; /* Received frame so it is resolved */ skb->h.raw = skb->mac.raw; if (br_stats.flags & BR_DEBUG) printk("port %i src %02x:%02x:%02x:%02x:%02x:%02x\ diff --git a/net/core/dev.c b/net/core/dev.c index 166a3cc2165f..7ada1a7b4447 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -605,9 +605,21 @@ void net_bh(void) if (br_stats.flags & BR_UP) { + /* + * We pass the bridge a complete frame. This means + * recovering the MAC header first. + */ + + int offset=skb->data-skb->mac.raw; cli(); + skb_push(skb,offset); /* Put header back on for bridge */ if(br_receive_frame(skb)) continue; + /* + * Pull the MAC header off for the copy going to + * the upper layers. + */ + skb_pull(skb,offset); sti(); } #endif @@ -621,9 +633,9 @@ void net_bh(void) skb->h.raw = skb->data; - /* - * Fetch the packet protocol ID. - */ + /* + * Fetch the packet protocol ID. + */ type = skb->protocol; diff --git a/net/core/iovec.c b/net/core/iovec.c index 2601f103392b..2e4f3265c608 100644 --- a/net/core/iovec.c +++ b/net/core/iovec.c @@ -35,11 +35,11 @@ int verify_iovec(struct msghdr *m, struct iovec *iov, char *address, int mode) { if(mode==VERIFY_READ) { err=move_addr_to_kernel(m->msg_name, m->msg_namelen, address); - m->msg_name = address; } else err=verify_area(mode, m->msg_name, m->msg_namelen); if(err<0) return err; + m->msg_name = address; } if(m->msg_accrights!=NULL) { diff --git a/net/core/skbuff.c b/net/core/skbuff.c index 96d054de2463..63ead6139bba 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -36,22 +36,24 @@ #include #include #include -#include -#include #include #include #include #include #include +#include +#include +#include + #include #include -#include #include #include #include -#include #include +#include +#include /* * Resource tracking variables diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index 66a64e0fcfe4..7b87d8934b46 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -22,7 +22,7 @@ if [ "$CONFIG_NET_ALIAS" = "y" ]; then tristate 'IP: aliasing support' CONFIG_IP_ALIAS fi if [ "$CONFIG_KERNELD" = "y" ]; then - bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD +# bool 'IP: ARP daemon support (experimental)' CONFIG_ARPD fi comment '(it is safe to leave these untouched)' bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP diff --git a/net/ipv4/icmp.c b/net/ipv4/icmp.c index 953bc40a6242..5c4f4da75d34 100644 --- a/net/ipv4/icmp.c +++ b/net/ipv4/icmp.c @@ -18,16 +18,23 @@ * Alan Cox : Multicast ping reply as self. * Alan Cox : Fix atomicity lockup in ip_build_xmit call * Alan Cox : Added 216,128 byte paths to the MTU code. + * Martin Mares : RFC1812 checks. + * Martin Mares : Can be configured to follow redirects if acting + * as a router _without_ a routing protocol (RFC 1812). + * Martin Mares : Echo requests may be configured to be ignored (RFC 1812). + * Martin Mares : Limitation of ICMP error message transmit rate (RFC 1812). + * Martin Mares : TOS and Precedence set correctly (RFC 1812). * * * - * RFC1122 Status: (boy, are there a lot of rules for ICMP) + * RFC1122 (Host Requirements -- Comm. Layer) Status: + * (boy, are there a lot of rules for ICMP) * 3.2.2 (Generic ICMP stuff) * MUST discard messages of unknown type. (OK) * MUST copy at least the first 8 bytes from the offending packet - * when sending ICMP errors. (OK) + * when sending ICMP errors. (OBSOLETE -- see RFC1812) * MUST pass received ICMP errors up to protocol level. (OK) - * SHOULD send ICMP errors with TOS == 0. (OK) + * SHOULD send ICMP errors with TOS == 0. (OBSOLETE -- see RFC1812) * MUST NOT send ICMP errors in reply to: * ICMP errors (OK) * Broadcast/multicast datagrams (OK) @@ -38,8 +45,8 @@ * All the rules govern the IP layer, and are dealt with in ip.c, not here. * 3.2.2.2 (Redirect) * Host SHOULD NOT send ICMP_REDIRECTs. (OK) - * MUST update routing table in response to host or network redirects. - * (host OK, network NOT YET) [Intentionally -- AC] + * MUST update routing table in response to host or network redirects. + * (host OK, network OBSOLETE) * SHOULD drop redirects if they're not from directly connected gateway * (OK -- we drop it if it's not from our old gateway, which is close * enough) @@ -50,7 +57,7 @@ * MUST pass TIME_EXCEEDED to transport layer (OK) * Other requirements dealt with at IP (generating TIME_EXCEEDED). * 3.2.2.5 (Parameter Problem) - * SHOULD generate these, but it doesn't say for what. So we're OK. =) + * SHOULD generate these (OK) * MUST pass received PARAMPROBLEM to transport layer (NOT YET) * [Solaris 2.X seems to assert EPROTO when this occurs] -- AC * 3.2.2.6 (Echo Request/Reply) @@ -60,7 +67,7 @@ * We're OK for unicast ECHOs, and it doesn't say anything about * how to handle broadcast ones, since it's optional. * MUST copy data from REQUEST to REPLY (OK) - * unless it would require illegal fragmentation (N/A) + * unless it would require illegal fragmentation (OK) * MUST pass REPLYs to transport/user layer (OK) * MUST use any provided source route (reversed) for REPLY. (NOT YET) * 3.2.2.7 (Information Request/Reply) @@ -81,6 +88,130 @@ * MUST discard received REPLYs if not using this system (OK) * MUST NOT send replies unless specifically made agent for this sort * of thing. (OK) + * + * + * RFC 1812 (IPv4 Router Requirements) Status (even longer): + * 4.3.2.1 (Unknown Message Types) + * MUST pass messages of unknown type to ICMP user iface or silently discard + * them (OK) + * 4.3.2.2 (ICMP Message TTL) + * MUST initialize TTL when originating an ICMP message (OK) + * 4.3.2.3 (Original Message Header) + * SHOULD copy as much data from the offending packet as possible without + * the length of the ICMP datagram exceeding 576 bytes (NOT YET) + * MUST leave original IP header of the offending packet, but we're not + * required to undo modifications made (OK) + * 4.3.2.4 (Original Message Source Address) + * MUST use one of addresses for the interface the orig. packet arrived as + * source address (OK) + * 4.3.2.5 (TOS and Precedence) + * SHOULD leave TOS set to the same value unless the packet would be discarded + * for that reason (OK) + * MUST use TOS=0 if not possible to leave original value (OK) + * MUST leave IP Precedence for Source Quench messages (OK -- not sent at all) + * SHOULD use IP Precedence = 6 (Internetwork Control) or 7 (Network Control) + * for all other error messages (OK, we use 6) + * MAY allow configuration of IP Precedence (OK -- not done) + * MUST leave IP Precedence and TOS for reply messages (OK) + * 4.3.2.6 (Source Route) + * SHOULD use reverse source route UNLESS sending Parameter Problem on source + * routing and UNLESS the packet would be immediately discarded (NOT YET) + * 4.3.2.7 (When Not to Send ICMP Errors) + * MUST NOT send ICMP errors in reply to: + * ICMP errors (OK) + * Packets failing IP header validation tests unless otherwise noted (OK) + * Broadcast/multicast datagrams (OK) + * MAC broadcasts (OK) + * Non-initial fragments (OK) + * Datagram with a source address that isn't a single host. (OK) + * 4.3.2.8 (Rate Limiting) + * SHOULD be able to limit error message rate (OK) + * SHOULD allow setting of rate limits (OK, in the source) + * 4.3.3.1 (Destination Unreachable) + * All the rules govern the IP layer, and are dealt with in ip.c, not here. + * 4.3.3.2 (Redirect) + * MAY ignore ICMP Redirects if running a routing protocol or if forwarding + * is enabled on the interface (OK -- ignores) + * 4.3.3.3 (Source Quench) + * SHOULD NOT originate SQ messages (OK) + * MUST be able to limit SQ rate if originates them (OK as we don't send them) + * MAY ignore SQ messages it receives (OK -- we don't) + * 4.3.3.4 (Time Exceeded) + * Requirements dealt with at IP (generating TIME_EXCEEDED). + * 4.3.3.5 (Parameter Problem) + * MUST generate these for all errors not covered by other messages (OK) + * MUST include original value of the value pointed by (OK) + * 4.3.3.6 (Echo Request) + * MUST implement echo server function (OK) + * MUST process at ER of at least max(576, MTU) (OK) + * MAY reject broadcast/multicast ER's (We don't, but that's OK) + * SHOULD have a config option for silently ignoring ER's (OK) + * MUST have a default value for the above switch = NO (OK) + * MUST have application layer interface for Echo Request/Reply (OK) + * MUST reply using same source address as the request was sent to. + * We're OK for unicast ECHOs, and it doesn't say anything about + * how to handle broadcast ones, since it's optional. + * MUST copy data from Request to Reply (OK) + * SHOULD update Record Route / Timestamp options (??) + * MUST use reversed Source Route for Reply if possible (NOT YET) + * 4.3.3.7 (Information Request/Reply) + * SHOULD NOT originate or respond to these (OK) + * 4.3.3.8 (Timestamp / Timestamp Reply) + * MAY implement (OK) + * MUST reply to every Timestamp message received (OK) + * MAY discard broadcast REQUESTs. (OK, but see source for inconsistency) + * MUST reply using same source address as the request was sent to. (OK) + * MUST use reversed Source Route if possible (NOT YET) + * SHOULD update Record Route / Timestamp options (??) + * MUST pass REPLYs to transport/user layer (requires RAW, just like ECHO) (OK) + * MUST update clock for timestamp at least 16 times/sec (OK) + * MUST be "correct within a few minutes" (OK) + * 4.3.3.9 (Address Mask Request/Reply) + * MUST have support for receiving AMRq and responding with AMRe (OK, but only as a + * compile-time option) + * SHOULD have option for each interface for AMRe's, MUST default to NO (NOT YET) + * MUST NOT reply to AMRq before knows the correct AM (OK) + * MUST NOT respond to AMRq with source address 0.0.0.0 and the AM's for + * logical i-faces for the physical i-face are not the same (NOT YET) + * SHOULD examine all AMRe's it receives and check them (NOT YET) + * SHOULD log invalid AMRe's (AM+sender) (NOT YET) + * MUST NOT use contents of AMRe to determine correct AM (OK) + * MAY broadcast AMRe's after having configured address masks (OK -- doesn't) + * MUST NOT do broadcast AMRe's if not set by extra option (OK, no option) + * MUST use the { , -1 } form of broadcast addresses (OK) + * 4.3.3.10 (Router Advertisement and Solicitations) + * MUST support router part of Router Discovery Protocol on all networks we + * support broadcast or multicast addressing. (OK -- done by gated) + * MUST have all config parameters with the respective defaults (OK) + * 5.2.7.1 (Destination Unreachable) + * MUST generate DU's (OK) + * SHOULD choose a best-match response code (OK) + * SHOULD NOT generate Host Isolated codes (OK) + * SHOULD use Communication Administratively Prohibited when administratively + * filtering packets (NOT YET) + * MAY include config option for not generating the above and silently discard + * the packets instead (OK) + * MAY include config option for not generating Precedence Violation and + * Precedence Cutoff messages (OK as we don't generate them at all) + * MUST use Host Unreachable or Dest. Host Unknown codes whenever other hosts + * on the same network might be reachable (OK -- no net unreach's at all) + * MUST use new form of Fragmentation Needed and DF Set messages (OK) + * 5.2.7.2 (Redirect) + * MUST NOT generate network redirects (OK) + * MUST be able to generate host redirects (OK) + * SHOULD be able to generate Host+TOS redirects (NO as we don't use TOS) + * MUST have an option to use Host redirects instead of Host+TOS ones (OK as + * no Host+TOS Redirects are used) + * MUST NOT generate redirects unless forwarding to the same i-face and the + * dest. address is on the same subnet as the src. address and no source + * routing is in use. (OK) + * MUST NOT follow redirects when using a routing protocol (OK) + * MAY use redirects if not using a routing protocol (OK, compile-time option) + * MUST comply to Host Requirements when not acting as a router (OK) + * 5.2.7.3 (Time Exceeded) + * MUST generate Time Exceeded Code 0 when discarding packet due to TTL=0 (OK) + * MAY have a per-interface option to disable origination of TE messages, but + * it MUST default to "originate" (OK -- we don't support it) */ #include @@ -141,6 +272,34 @@ struct icmp_err icmp_err_convert[] = { unsigned long dummy; +/* + * ICMP transmit rate limit control structures. We use a relatively simple + * approach to the problem: For each type of ICMP message with rate limit + * we count the number of messages sent during some time quantum. If this + * count exceeds given maximal value, we ignore all messages not separated + * from the last message sent at least by specified time. + */ + +#define XRLIM_CACHE_SIZE 16 /* How many destination hosts do we cache */ + +struct icmp_xrl_cache /* One entry of the ICMP rate cache */ +{ + __u32 daddr; /* Destination address */ + unsigned long counter; /* Message counter */ + unsigned long next_reset; /* Time of next reset of the counter */ + unsigned long last_access; /* Time of last access to this entry (LRU) */ + unsigned int restricted; /* Set if we're in restricted mode */ + unsigned long next_packet; /* When we'll allow a next packet if restricted */ +}; + +struct icmp_xrlim +{ + unsigned long timeout; /* Time quantum for rate measuring */ + unsigned long limit; /* Maximal number of messages per time quantum allowed */ + unsigned long delay; /* How long we wait between packets when restricting */ + struct icmp_xrl_cache cache[XRLIM_CACHE_SIZE]; /* Rate cache */ +}; + /* * ICMP control array. This specifies what to do with each ICMP. */ @@ -150,7 +309,8 @@ struct icmp_control unsigned long *output; /* Address to increment on output */ unsigned long *input; /* Address to increment on input */ void (*handler)(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len); - unsigned long error; /* This ICMP is classed as an error message */ + unsigned long error; /* This ICMP is classed as an error message */ + struct icmp_xrlim *xrlim; /* Transmit rate limit control structure or NULL for no limits */ }; static struct icmp_control icmp_pointers[19]; @@ -182,6 +342,97 @@ struct socket icmp_socket; */ +/* + * Initialize the transmit rate limitation mechanism. + */ + +#ifndef CONFIG_NO_ICMP_LIMIT + +static void xrlim_init(void) +{ + int type, entry; + struct icmp_xrlim *xr; + + for (type=0; type<=18; type++) { + xr = icmp_pointers[type].xrlim; + if (xr) { + for (entry=0; entrycache[entry].daddr = INADDR_NONE; + } + } +} + +/* + * Check transmit rate limitation for given message. + * + * RFC 1812: 4.3.2.8 SHOULD be able to limit error message rate + * SHOULD allow setting of rate limits (we allow in the source) + */ + +static int xrlim_allow(int type, __u32 addr) +{ + struct icmp_xrlim *r; + struct icmp_xrl_cache *c; + unsigned long now; + + if (type > 18) /* No time limit present */ + return 1; + r = icmp_pointers[type].xrlim; + if (!r) + return 1; + + for (c = r->cache; c < &r->cache[XRLIM_CACHE_SIZE]; c++) /* Cache lookup */ + if (c->daddr == addr) + break; + + now = jiffies; /* Cache current time (saves accesses to volatile variable) */ + + if (c == &r->cache[XRLIM_CACHE_SIZE]) { /* Cache miss */ + unsigned long oldest = now; /* Find the oldest entry to replace */ + struct icmp_xrl_cache *d; + c = r->cache; + for (d = r->cache; d < &r->cache[XRLIM_CACHE_SIZE]; d++) + if (!d->daddr) { /* Unused entry */ + c = d; + break; + } else if (d->last_access < oldest) { + oldest = d->last_access; + c = d; + } + c->last_access = now; /* Fill the entry with new data */ + c->daddr = addr; + c->counter = 1; + c->next_reset = now + r->timeout; + c->restricted = 0; + return 1; + } + + c->last_access = now; + if (c->next_reset > now) { /* Let's increment the counter */ + c->counter++; + if (c->counter == r->limit) { /* Limit exceeded, start restrictions */ + c->restricted = 1; + c->next_packet = now + r->delay; + return 0; + } + if (c->restricted) { /* Any restrictions pending? */ + if (c->next_packet > now) + return 0; + c->next_packet = now + r->delay; + return 1; + } + } else { /* Reset the counter */ + if (c->counter < r->limit) /* Switch off all restrictions */ + c->restricted = 0; + c->next_reset = now + r->timeout; + c->counter = 0; + } + + return 1; /* Send the packet */ +} + +#endif /* CONFIG_NO_ICMP_LIMIT */ + /* * Maintain the counters used in the SNMP statistics for outgoing ICMP */ @@ -229,12 +480,13 @@ static void icmp_glue_bits(const void *p, __u32 saddr, char *to, unsigned int of * Driving logic for building and sending ICMP messages. */ -static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr) +static void icmp_build_xmit(struct icmp_bxm *icmp_param, __u32 saddr, __u32 daddr, __u8 tos) { struct sock *sk=icmp_socket.data; icmp_param->icmph.checksum=0; icmp_param->csum=0; icmp_out_count(icmp_param->icmph.type); + sk->ip_tos = tos; ip_build_xmit(sk, icmp_glue_bits, icmp_param, icmp_param->data_len+sizeof(struct icmphdr), daddr, saddr, &icmp_param->replyopts, 0, IPPROTO_ICMP, 1); @@ -309,7 +561,16 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, s return; } } - + + /* + * Check the rate limit + */ + +#ifndef CONFIG_NO_ICMP_LIMIT + if (!xrlim_allow(type, iph->saddr)) + return; +#endif + /* * Tell our driver what to send */ @@ -329,7 +590,7 @@ void icmp_send(struct sk_buff *skb_in, int type, int code, unsigned long info, s */ if (ip_options_echo(&icmp_param.replyopts, NULL, saddr, iph->saddr, skb_in) == 0) - icmp_build_xmit(&icmp_param, saddr, iph->saddr); + icmp_build_xmit(&icmp_param, saddr, iph->saddr, ((iph->tos & 0x38) | 6)); } @@ -491,10 +752,12 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev iph = (struct iphdr *) (icmph + 1); ip = iph->daddr; -#ifdef CONFIG_IP_FORWARD /* - * We are a router. Routers should not respond to ICMP_REDIRECT messages. + * If we are a router and we run a routing protocol, we MUST NOT follow redirects. + * When using no routing protocol, we MAY follow redirects. (RFC 1812, 5.2.7.2) */ + +#if defined(CONFIG_IP_FORWARD) && !defined(CONFIG_IP_DUMB_ROUTER) printk(KERN_INFO "icmp: ICMP redirect ignored. dest = %s, " "orig gw = %s, \"new\" gw = %s, device = %s.\n", in_ntoa(ip), in_ntoa(source), in_ntoa(icmph->un.gateway), dev->name); @@ -505,7 +768,8 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev /* * This causes a problem with subnetted networks. What we should do * is use ICMP_ADDRESS to get the subnet mask of the problem route - * and set both. But we don't.. + * and set both. But we don't.. [RFC1812 says routers MUST NOT + * generate Network Redirects] */ #ifdef not_a_good_idea ip_rt_add((RTF_DYNAMIC | RTF_MODIFIED | RTF_GATEWAY), @@ -548,18 +812,21 @@ static void icmp_redirect(struct icmphdr *icmph, struct sk_buff *skb, struct dev * * RFC 1122: 3.2.2.6 MUST have an echo server that answers ICMP echo requests. * RFC 1122: 3.2.2.6 Data received in the ICMP_ECHO request MUST be included in the reply. + * RFC 1812: 4.3.3.6 SHOULD have a config option for silently ignoring echo requests, MUST have default=NOT. * See also WRT handling of options once they are done and working. */ static void icmp_echo(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { +#ifndef CONFIG_IP_IGNORE_ECHO_REQUESTS struct icmp_bxm icmp_param; icmp_param.icmph=*icmph; icmp_param.icmph.type=ICMP_ECHOREPLY; icmp_param.data_ptr=(icmph+1); icmp_param.data_len=len; if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0) - icmp_build_xmit(&icmp_param, daddr, saddr); + icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos); +#endif kfree_skb(skb, FREE_READ); } @@ -604,7 +871,7 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct de icmp_param.data_ptr=× icmp_param.data_len=12; if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0) - icmp_build_xmit(&icmp_param, daddr, saddr); + icmp_build_xmit(&icmp_param, daddr, saddr, skb->ip_hdr->tos); kfree_skb(skb,FREE_READ); } @@ -623,8 +890,7 @@ static void icmp_timestamp(struct icmphdr *icmph, struct sk_buff *skb, struct de static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct device *dev, __u32 saddr, __u32 daddr, int len) { -#ifdef CONFIG_IP_ADDR_AGENT - __u32 answer; +#ifdef CONFIG_IP_ADDR_AGENT /* Don't use, broken */ struct icmp_bxm icmp_param; icmp_param.icmph.type=ICMP_ADDRESSREPLY; icmp_param.icmph.code=0; @@ -633,7 +899,7 @@ static void icmp_address(struct icmphdr *icmph, struct sk_buff *skb, struct devi icmp_param.data_ptr=&dev->pa_mask; icmp_param.data_len=4; if (ip_options_echo(&icmp_param.replyopts, NULL, daddr, saddr, skb)==0) - icmp_build_xmit(&icmp_param, daddr, saddr); + icmp_build_xmit(&icmp_param, daddr, saddr, skb->iph->tos); #endif kfree_skb(skb, FREE_READ); } @@ -668,7 +934,7 @@ int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, } /* - * 18 is the highest 'known' icmp type. Anything else is a mystery + * 18 is the highest 'known' ICMP type. Anything else is a mystery * * RFC 1122: 3.2.2 Unknown ICMP messages types MUST be silently discarded. */ @@ -711,44 +977,53 @@ int icmp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, return 0; } +/* + * This table defined limits of ICMP sending rate for various ICMP messages. + */ + +static struct icmp_xrlim + xrl_unreach = { 4*HZ, 80, HZ/4 }, /* Host Unreachable */ + xrl_redirect = { 2*HZ, 10, HZ/2 }, /* Redirect */ + xrl_generic = { 3*HZ, 30, HZ/4 }; /* All other errors */ + /* * This table is the definition of how we handle ICMP. */ static struct icmp_control icmp_pointers[19] = { /* ECHO REPLY (0) */ - { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0 }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 }, + { &icmp_statistics.IcmpOutEchoReps, &icmp_statistics.IcmpInEchoReps, icmp_discard, 0, NULL }, + { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL }, + { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL }, /* DEST UNREACH (3) */ - { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1 }, + { &icmp_statistics.IcmpOutDestUnreachs, &icmp_statistics.IcmpInDestUnreachs, icmp_unreach, 1, &xrl_unreach }, /* SOURCE QUENCH (4) */ - { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1 }, + { &icmp_statistics.IcmpOutSrcQuenchs, &icmp_statistics.IcmpInSrcQuenchs, icmp_unreach, 1, NULL }, /* REDIRECT (5) */ - { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1 }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 }, + { &icmp_statistics.IcmpOutRedirects, &icmp_statistics.IcmpInRedirects, icmp_redirect, 1, &xrl_redirect }, + { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL }, + { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL }, /* ECHO (8) */ - { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0 }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 }, - { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1 }, + { &icmp_statistics.IcmpOutEchos, &icmp_statistics.IcmpInEchos, icmp_echo, 0, NULL }, + { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL }, + { &dummy, &icmp_statistics.IcmpInErrors, icmp_discard, 1, NULL }, /* TIME EXCEEDED (11) */ - { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1 }, + { &icmp_statistics.IcmpOutTimeExcds, &icmp_statistics.IcmpInTimeExcds, icmp_unreach, 1, &xrl_generic }, /* PARAMETER PROBLEM (12) */ /* FIXME: RFC1122 3.2.2.5 - MUST pass PARAM_PROB messages to transport layer */ - { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1 }, + { &icmp_statistics.IcmpOutParmProbs, &icmp_statistics.IcmpInParmProbs, icmp_discard, 1, &xrl_generic }, /* TIMESTAMP (13) */ - { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0 }, + { &icmp_statistics.IcmpOutTimestamps, &icmp_statistics.IcmpInTimestamps, icmp_timestamp, 0, NULL }, /* TIMESTAMP REPLY (14) */ - { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0 }, + { &icmp_statistics.IcmpOutTimestampReps, &icmp_statistics.IcmpInTimestampReps, icmp_discard, 0, NULL }, /* INFO (15) */ - { &dummy, &dummy, icmp_discard, 0 }, + { &dummy, &dummy, icmp_discard, 0, NULL }, /* INFO REPLY (16) */ - { &dummy, &dummy, icmp_discard, 0 }, + { &dummy, &dummy, icmp_discard, 0, NULL }, /* ADDR MASK (17) */ - { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0 }, + { &icmp_statistics.IcmpOutAddrMasks, &icmp_statistics.IcmpInAddrMasks, icmp_address, 0, NULL }, /* ADDR MASK REPLY (18) */ - { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0 } + { &icmp_statistics.IcmpOutAddrMaskReps, &icmp_statistics.IcmpInAddrMaskReps, icmp_discard, 0, NULL } }; void icmp_init(struct proto_ops *ops) @@ -762,5 +1037,8 @@ void icmp_init(struct proto_ops *ops) sk=icmp_socket.data; sk->allocation=GFP_ATOMIC; sk->num = 256; /* Don't receive any data */ +#ifndef CONFIG_NO_ICMP_LIMIT + xrlim_init(); +#endif } diff --git a/net/ipv4/ip_fragment.c b/net/ipv4/ip_fragment.c index 741c235084a3..919af64c8669 100644 --- a/net/ipv4/ip_fragment.c +++ b/net/ipv4/ip_fragment.c @@ -248,7 +248,6 @@ static struct ipq *ip_create(struct sk_buff *skb, struct iphdr *iph, struct devi { NETDEBUG(printk("IP: create: no memory left !\n")); return(NULL); - skb->dev = qp->dev; } memset(qp, 0, sizeof(struct ipq)); diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c index cec17ede6827..713d141fd36f 100644 --- a/net/ipv4/ip_sockglue.c +++ b/net/ipv4/ip_sockglue.c @@ -9,6 +9,9 @@ * * Fixes: * Many : Split from ip.c , see ip.c for history. + * Martin Mares : TOS setting fixed. + * Alan Cox : Fixed a couple of oopses in Martins + * TOS tweaks. */ #include @@ -89,8 +92,6 @@ int ip_mc_procinfo(char *buffer, char **start, off_t offset, int length, int dum * an IP socket. * * We implement IP_TOS (type of service), IP_TTL (time to live). - * - * Next release we will sort out IP_OPTIONS since for some people are kind of important. */ static struct device *ip_mc_find_devfor(unsigned long addr) @@ -177,14 +178,23 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char *optval, int opt kfree_s(old_opt, sizeof(struct optlen) + old_opt->optlen); return 0; } - case IP_TOS: - if(val<0||val>255) + case IP_TOS: /* This sets both TOS and Precedence */ + if (val<0 || val>63) /* Reject setting of unused bits */ return -EINVAL; + if ((val&3) > 4 && !suser()) /* Only root can set Prec>4 */ + return -EPERM; sk->ip_tos=val; - if(val==IPTOS_LOWDELAY) - sk->priority=SOPRI_INTERACTIVE; - if(val==IPTOS_THROUGHPUT) - sk->priority=SOPRI_BACKGROUND; + switch (val & 0x38) { + case IPTOS_LOWDELAY: + sk->priority=SOPRI_INTERACTIVE; + break; + case IPTOS_THROUGHPUT: + sk->priority=SOPRI_BACKGROUND; + break; + default: + sk->priority=SOPRI_NORMAL; + break; + } return 0; case IP_TTL: if(val<1||val>255) diff --git a/net/ipv4/tcp.c b/net/ipv4/tcp.c index 64b74eddc8d2..f572acad4555 100644 --- a/net/ipv4/tcp.c +++ b/net/ipv4/tcp.c @@ -436,12 +436,6 @@ struct tcp_mib tcp_statistics; static void tcp_close(struct sock *sk, unsigned long timeout); -/* - * The less said about this the better, but it works and will do for 1.2 (and 1.4 ;)) - */ - -struct wait_queue *master_select_wakeup; - /* * Find someone to 'accept'. Must be called with * the socket locked or with interrupts disabled @@ -462,24 +456,6 @@ static struct sk_buff *tcp_find_established(struct sock *s) return NULL; } -/* - * Remove a completed connection and return it. This is used by - * tcp_accept() to get connections from the queue. - */ - -static struct sk_buff *tcp_dequeue_established(struct sock *s) -{ - struct sk_buff *skb; - unsigned long flags; - save_flags(flags); - cli(); - skb=tcp_find_established(s); - if(skb!=NULL) - skb_unlink(skb); /* Take it off the queue */ - restore_flags(flags); - return skb; -} - /* * This routine closes sockets which have been at least partially * opened, but not yet accepted. Currently it is only called by @@ -685,14 +661,15 @@ static int tcp_readable(struct sock *sk) static int tcp_listen_select(struct sock *sk, int sel_type, select_table *wait) { if (sel_type == SEL_IN) { - int retval; + struct sk_buff * skb; lock_sock(sk); - retval = (tcp_find_established(sk) != NULL); + skb = tcp_find_established(sk); release_sock(sk); - if (!retval) - select_wait(&master_select_wakeup,wait); - return retval; + if (skb) + return 1; + select_wait(sk->sleep,wait); + return 0; } return 0; } @@ -895,31 +872,53 @@ static void wait_for_tcp_memory(struct sock * sk) * and starts the transmit system. */ -static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg, - int len, int nonblock, int flags) +static int do_tcp_sendmsg(struct sock *sk, + int iovlen, struct iovec *iov, + int len, int nonblock, int flags) { int copied = 0; - int copy; - int tmp; - int seglen; - int iovct=0; - struct sk_buff *skb; - struct sk_buff *send_tmp; - struct proto *prot; struct device *dev = NULL; - unsigned char *from; + + /* + * Wait for a connection to finish. + */ + while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) + { + if (sk->err) + return sock_error(sk); + + if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) + { + if (sk->keepopen) + send_sig(SIGPIPE, current, 0); + return -EPIPE; + } + + if (nonblock) + return -EAGAIN; + + if (current->signal & ~current->blocked) + return -ERESTARTSYS; + + wait_for_tcp_connect(sk); + } /* * Ok commence sending */ - while(iovctmsg_iovlen) + while (--iovlen >= 0) { - seglen=msg->msg_iov[iovct].iov_len; - from=msg->msg_iov[iovct++].iov_base; - prot = sk->prot; + int seglen=iov->iov_len; + unsigned char * from=iov->iov_base; + iov++; + while(seglen > 0) { + int copy, delay; + int tmp; + struct sk_buff *skb; + /* * Stop on errors */ @@ -940,33 +939,6 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg, return -EPIPE; } - /* - * Wait for a connection to finish. - */ - while (sk->state != TCP_ESTABLISHED && sk->state != TCP_CLOSE_WAIT) - { - if (copied) - return copied; - - if (sk->err) - return sock_error(sk); - - if (sk->state != TCP_SYN_SENT && sk->state != TCP_SYN_RECV) - { - if (sk->keepopen) - send_sig(SIGPIPE, current, 0); - return -EPIPE; - } - - if (nonblock) - return -EAGAIN; - - if (current->signal & ~current->blocked) - return -ERESTARTSYS; - - wait_for_tcp_connect(sk); - } - /* * 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). @@ -1055,20 +1027,18 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg, return -EFAULT; } - /* - * We should really check the window here also. - */ + /* + * We should really check the window here also. + */ - send_tmp = NULL; + delay = 0; + tmp = copy + sk->prot->max_header + 15; if (copy < sk->mss && !(flags & MSG_OOB) && sk->packets_out) { - skb = sock_wmalloc(sk, sk->mtu + 128 + prot->max_header + 15, 0, GFP_KERNEL); - send_tmp = skb; - } - else - { - skb = sock_wmalloc(sk, copy + prot->max_header + 15 , 0, GFP_KERNEL); + tmp = tmp - copy + sk->mtu + 128; + delay = 1; } + skb = sock_wmalloc(sk, tmp, 0, GFP_KERNEL); /* * If we didn't get any memory, we need to sleep. @@ -1104,7 +1074,7 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg, * Perhaps some hints here would be good. */ - tmp = prot->build_header(skb, sk->saddr, sk->daddr, &dev, + tmp = sk->prot->build_header(skb, sk->saddr, sk->daddr, &dev, IPPROTO_TCP, sk->opt, skb->truesize,sk->ip_tos,sk->ip_ttl,&sk->ip_route_cache); if (tmp < 0 ) { @@ -1143,9 +1113,9 @@ static int do_tcp_sendmsg(struct sock *sk, struct msghdr *msg, skb->free = 0; sk->write_seq += copy; - if (send_tmp != NULL) + if (delay) { - tcp_enqueue_partial(send_tmp, sk); + tcp_enqueue_partial(skb, sk); continue; } tcp_send_skb(sk, skb); @@ -1186,7 +1156,7 @@ static int tcp_sendmsg(struct sock *sk, struct msghdr *msg, } lock_sock(sk); - retval = do_tcp_sendmsg(sk, msg, len, nonblock, flags); + retval = do_tcp_sendmsg(sk, msg->msg_iovlen, msg->msg_iov, len, nonblock, flags); /* * Nagle's rule. Turn Nagle off with TCP_NODELAY for highly @@ -1797,64 +1767,81 @@ static void tcp_close(struct sock *sk, unsigned long timeout) } +/* + * Wait for a incoming connection, avoid race + * conditions. This must be called with the socket + * locked. + */ +static struct sk_buff * wait_for_connect(struct sock * sk) +{ + struct wait_queue wait = { current, NULL }; + struct sk_buff * skb = NULL; + + add_wait_queue(sk->sleep, &wait); + for (;;) { + current->state = TASK_INTERRUPTIBLE; + release_sock(sk); + schedule(); + lock_sock(sk); + skb = tcp_find_established(sk); + if (skb) + break; + if (current->signal & ~current->blocked) + break; + } + remove_wait_queue(sk->sleep, &wait); + return skb; +} + /* * This will accept the next outstanding connection. + * + * Be careful about race conditions here - this is subtle. */ static struct sock *tcp_accept(struct sock *sk, int flags) { - struct sock *newsk; + int error; struct sk_buff *skb; + struct sock *newsk = NULL; /* * We need to make sure that this socket is listening, * and that it has something pending. */ + error = EINVAL; if (sk->state != TCP_LISTEN) - { - sk->err = EINVAL; - return(NULL); - } + goto no_listen; - /* Avoid the race. */ - cli(); lock_sock(sk); - while((skb = tcp_dequeue_established(sk)) == NULL) - { - if (flags & O_NONBLOCK) - { - sti(); - release_sock(sk); - sk->err = EAGAIN; - return(NULL); - } - + skb = tcp_find_established(sk); + if (skb) { +got_new_connect: + __skb_unlink(skb, &sk->receive_queue); + newsk = skb->sk; + kfree_skb(skb, FREE_READ); + sk->ack_backlog--; + error = 0; +out: release_sock(sk); - interruptible_sleep_on(sk->sleep); - if (current->signal & ~current->blocked) - { - sti(); - sk->err = ERESTARTSYS; - return(NULL); - } - lock_sock(sk); - } - sti(); - - /* - * Now all we need to do is return skb->sk. - */ - - newsk = skb->sk; +no_listen: + sk->err = error; + return newsk; + } - kfree_skb(skb, FREE_READ); - sk->ack_backlog--; - release_sock(sk); - return(newsk); + error = EAGAIN; + if (flags & O_NONBLOCK) + goto out; + skb = wait_for_connect(sk); + if (skb) + goto got_new_connect; + error = ERESTARTSYS; + goto out; } + /* * This will initiate an outgoing connection. */ diff --git a/net/socket.c b/net/socket.c index 4e83574836f1..f5e9efb0a8da 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1137,8 +1137,9 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags) if(msg_sys.msg_iovlen>MAX_IOVEC) return -EINVAL; - err=verify_iovec(&msg_sys,iov,address, VERIFY_READ); - if(err<0) + /* This will also move the address data into kernel space */ + err = verify_iovec(&msg_sys, iov, address, VERIFY_READ); + if (err < 0) return err; total_len=err; @@ -1153,13 +1154,19 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) { struct socket *sock; struct file *file; - char address[MAX_SOCK_ADDR]; struct iovec iov[MAX_IOVEC]; struct msghdr msg_sys; int err; int total_len; - int addr_len; int len; + + /* kernel mode address */ + char addr[MAX_SOCK_ADDR]; + int addr_len; + + /* user mode address pointers */ + struct sockaddr *uaddr; + int *uaddr_len; if (fd < 0 || fd >= NR_OPEN || ((file = current->files->fd[fd]) == NULL)) return(-EBADF); @@ -1172,9 +1179,17 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr)); if(msg_sys.msg_iovlen>MAX_IOVEC) return -EINVAL; - err=verify_iovec(&msg_sys,iov,address, VERIFY_WRITE); + + /* + * save the user-mode address (verify_iovec will change the + * kernel msghdr to use the kernel address space) + */ + uaddr = msg_sys.msg_name; + uaddr_len = &msg->msg_namelen; + err=verify_iovec(&msg_sys,iov,addr, VERIFY_WRITE); if(err<0) return err; + total_len=err; if(sock->ops->recvmsg==NULL) @@ -1182,11 +1197,12 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) len=sock->ops->recvmsg(sock, &msg_sys, total_len, (file->f_flags&O_NONBLOCK), flags, &addr_len); if(len<0) return len; - /* - * Fixme: writing actual length into original msghdr. - */ - if(msg_sys.msg_name!=NULL && (err=move_addr_to_user(address,addr_len, msg_sys.msg_name, &msg_sys.msg_namelen))<0) - return err; + + if (uaddr != NULL) { + err = move_addr_to_user(addr, addr_len, uaddr, uaddr_len); + if (err) + return err; + } return len; } diff --git a/scripts/lxdialog/menubox.c b/scripts/lxdialog/menubox.c index a227ec58117d..ad4380870380 100644 --- a/scripts/lxdialog/menubox.c +++ b/scripts/lxdialog/menubox.c @@ -199,7 +199,7 @@ dialog_menu (const char *title, const char *prompt, int height, int width, while (key != ESC) { key = wgetch(dialog); - if (isalpha(key)) key = tolower(key); + if (key < 256 && isalpha(key)) key = tolower(key); if (strchr("ynm", key)) i = max_choice; diff --git a/scripts/lxdialog/util.c b/scripts/lxdialog/util.c index 41274d870ab1..b3a7af9d2dda 100644 --- a/scripts/lxdialog/util.c +++ b/scripts/lxdialog/util.c @@ -347,8 +347,8 @@ first_alpha(const char *string, const char *exempt) for (i = 0; i < strlen(string); i++) { c = tolower(string[i]); - if (c == '(') ++in_paren; - if (c == ')') --in_paren; + if (strchr("<[(", c)) ++in_paren; + if (strchr(">])", c)) --in_paren; if ((! in_paren) && isalpha(c) && strchr(exempt, c) == 0) -- 2.39.5