diff -u --recursive --new-file v2.1.44/linux/CREDITS linux/CREDITS --- v2.1.44/linux/CREDITS Mon Jul 7 08:19:59 1997 +++ linux/CREDITS Wed Jul 16 19:22:50 1997 @@ -81,6 +81,14 @@ S: Notre Dame, Indiana S: USA +N: James Banks +E: james.banks@caldera.com +D: TLAN network driver +S: Caldera, Inc. +S: 633 South 550 East +S: Provo, UT 84606 +S: USA + N: Peter Bauer E: 100136.3530@compuserve.com D: Driver for depca-ethernet-board @@ -107,7 +115,9 @@ N: Randolph Bentson E: bentson@grieg.seaslug.org -D: author of driver for Cyclades Cyclom-Y async mux +D: author of driver for Cyclom-Y and Cyclades-Z async mux +P: 1024/39ED5729 5C A8 7A F4 B2 7A D1 3E B5 3B 81 CF 47 30 11 71 +W: http://www.aa.net/~bentson/ S: 2322 37th Ave SW S: Seattle, Washington 98126-2010 S: USA @@ -793,6 +803,12 @@ S: D-91080 Uttenreuth S: Germany +N: Jaroslav Kysela +E: perex@jcu.cz +D: Original Author and Maintainer for HP 10/100 Mbit Network Adapters +W: http://www.pf.jcu.cz/~perex +S: Unix Centre of Pedagogical Faculty, University of South Bohemia + N: Bas Laarhoven E: bas@vimec.nl D: Loadable modules and ftape driver @@ -842,6 +858,13 @@ S: North Little Rock, Arkansas 72115 S: US +N: Siegfried "Frieder" Loeffler (dg1sek) +E: floeff@tunix.mathematik.uni-stuttgart.de, fl@LF.net +W: http://www.mathematik.uni-stuttgart.de/~floeff +D: Busmaster driver for HP 10/100 Mbit Network Adapters +S: University of Stuttgart, Germany and +S: Ecole Nationale Superieure des Telecommunications, Paris + N: Martin von Loewis E: loewis@informatik.hu-berlin.de D: script binary format @@ -956,12 +979,13 @@ S: Germany N: Michael Meskes -E: meskes@informatik.rwth-aachen.de +E: meskes@topsystem.de +P: 1024/04B6E8F5 6C 77 33 CA CC D6 22 03 AB AB 15 A3 AE AD 39 7D D: Kernel hacker. Software watchdog daemon. D: Maintainer of several Debian packages -S: Lehrstuhl fuer angewandte Mathematik insb. Informatik -S: RWTH-Aachen -S: D-52056 Aachen +S: topsystem Systemhaus GmbH +S: Europark A2, Adenauerstr. 20 +S: D-52146 Wuerselen S: Germany N: Nigel Metheringham diff -u --recursive --new-file v2.1.44/linux/Documentation/Configure.help linux/Documentation/Configure.help --- v2.1.44/linux/Documentation/Configure.help Thu Jun 26 12:33:36 1997 +++ linux/Documentation/Configure.help Wed Jul 16 19:22:50 1997 @@ -3308,6 +3308,14 @@ Multiple-Ethernet-mini-HOWTO, available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. +TI ThunderLAN support (EXPERIMENTAL) +CONFIG_TLAN + If you have a TLAN based network card which is supported by this + driver, say Y and read the Ethernet-HOWTO. Devices currently supported + are the Compaq Netelligent 10, Netelligent 10/100, and Internal + NetFlex 3. This driver is also available as a module. Please email + feedback to james.banks@caldera.com. + Zenith Z-Note support CONFIG_ZNET The Zenith Z-Note notebook computer has a built-in network @@ -4384,6 +4392,12 @@ you are unsure, try first to say N here and come back if the mouse doesn't work. Read the Busmouse-HOWTO, available via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO. + +PC110 digitizer pad support +CONFIG_PC110_PAD + This drives the digitizer pad on the IBM PC110 palmtop (see + http://toy.cabi.net). It can turn the digitizer pad into a + mouse emulation with tap gestures or into an absolute pad. Microsoft busmouse support CONFIG_MS_BUSMOUSE diff -u --recursive --new-file v2.1.44/linux/Documentation/binfmt_misc.txt linux/Documentation/binfmt_misc.txt --- v2.1.44/linux/Documentation/binfmt_misc.txt Tue Jul 1 08:55:56 1997 +++ linux/Documentation/binfmt_misc.txt Wed Jul 16 07:47:32 1997 @@ -1,26 +1,26 @@ - Kernel Support for miscellaneous (your favourite) Binary Formats v1.1 - ===================================================================== + Kernel Support for miscellaneous (your favourite) Binary Formats v1.1 + ===================================================================== This Kernel feature allows to invoke almost (for restrictions see below) every -program by simply typing it's name in the shell. +program by simply typing its name in the shell. This includes for example compiled Java(TM), Python or Emacs programs. -To achieve this you must tell binfmt_misc which interpreter has to be invoked with -which binary. Binfmt_misc recognises the binary-type by matching some bytes at the -beginning of the file with a magic byte sequence (masking out specified bits) you -have supplied. Binfmt_misc can also recognise a filename extension (aka .com) and -optionally strip it off. +To achieve this you must tell binfmt_misc which interpreter has to be invoked +with which binary. Binfmt_misc recognises the binary-type by matching some bytes +at the beginning of the file with a magic byte sequence (masking out specified +bits) you have supplied. Binfmt_misc can also recognise a filename extension +(aka .com) and optionally strip it off. To actually register a new binary type, you have to set up a string looking like -:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon your -needs) and echo it to /proc/sys/fs/binfmt_misc/register. +:name:type:offset:magic:mask:interpreter: (where you can choose the ':' upon +your needs) and echo it to /proc/sys/fs/binfmt_misc/register. Here is what the fields mean: - 'name' is an identifier string. A new /proc file will be created with this - this name below /proc/sys/fs/binfmt_misc + name below /proc/sys/fs/binfmt_misc - 'type' is the type of recognition. Give 'M' for magic and 'E' for extension. - Give the corresponding lowercase letter to let binfmt_misc strip of the + Give the corresponding lowercase letter to let binfmt_misc strip off the filename extension. - - 'offset' is the offset of the magic/mask in the file counted in bytes. This + - 'offset' is the offset of the magic/mask in the file, counted in bytes. This defaults to 0 if you omit it (i.e. you write ':name:type::magic...') - 'magic' is the byte sequence binfmt_misc is matching for. The magic string may contain hex-encoded characters like \x0a or \xA4. In a shell environment @@ -28,26 +28,23 @@ If you chose filename extension matching, this is the extension to be recognised (the \x0a specials are not allowed). Extension matching is case sensitive! - - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some bits - from matching by supplying a string like magic and as long as magic. The - mask is anded with the byte sequence of the file. + - 'mask' is an (optional, defaults to all 0xff) mask. You can mask out some + bits from matching by supplying a string like magic and as long as magic. + The mask is anded with the byte sequence of the file. - 'interpreter' is the program that should be invoked with the binary as first argument (specify the full path) There are some restrictions: - the whole register string may not exceed 255 characters - - the magic must resist in the first 128 bytes of the file, i.e. offset+size(magic) - has to be less than 128 + - the magic must resist in the first 128 bytes of the file, i.e. + offset+size(magic) has to be less than 128 - the interpreter string may not exceed 127 characters -You may want to add the binary formats in one of your /etc/rc scripts during boot-up. -Read the manual of your init program to figure out how to do this right. +You may want to add the binary formats in one of your /etc/rc scripts during +boot-up. Read the manual of your init program to figure out how to do this +right. A few examples (assumed you are in /proc/sys/fs/binfmt_misc): -- enable Java(TM)-support (like binfmt_java): - echo ":Java:M::\xca\xfe\xba\xbe::/usr/local/bin/java:" > register - echo :Applet:M::\<\!--applet::/usr/local/bin/appletviewer: > register - - enable support for em86 (like binfmt_em86, for Alpha AXP only): echo ":i386:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x03:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register echo ":i486:M::\x7fELF\x01\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x06:\xff\xff\xff\xff\xff\xfe\xfe\xff\xff\xff\xff\xff\xff\xff\xff\xff\xfb\xff\xff:/bin/em86:" > register @@ -57,8 +54,9 @@ - enable support for DOS/Windows executables (using mzloader and dosemu/wine): echo ":DOSWin:M::MZ::/usr/sbin/mzloader:" > register - echo ":DOS:E::com::/usr/sbin/mzloader:" > register - echo ":DOS2:E::exe::/usr/sbin/mzloader:" > register + echo ":DOScom:E::com::/usr/sbin/mzloader:" > register + echo ":DOSexe:E::exe::/usr/sbin/mzloader:" > register + You can enable/disable binfmt_misc or one binary type by echoing 0 (to disable) or 1 (to enable) to /proc/sys/fs/binfmt_misc/status or /proc/.../the_name. @@ -66,6 +64,25 @@ You can remove one entry or all entries by echoing -1 to /proc/.../the_name or /proc/sys/fs/binfmt_misc/status. + + +Emulating binfmt_java: +====================== + +To emulate binfmt_java the following register-strings are necessary +(the first two for byte-compiled Java binaries, the third for applets +contained in a html-file). Register exactly in this order! + ":Java:M::\xca\xfe\xba\xbe::/usr/local/java/bin/java:" + ":JavaC:e::class::/usr/local/java/bin/java:" + ":Applet:E::html::/usr/local/java/bin/appletviewer:" + +To add a Java-executable to your path you can either make a symbolic +link to the .class file elsewhere in your path (cut the .class-extension +in the destination name for convenience) or add the directory of your +.class files to your PATH environment. In both cases, ensure that the +.class files are in your CLASSPATH environment! + +This is sort of ugly - Javas filename handling is just broken. HINTS: diff -u --recursive --new-file v2.1.44/linux/Documentation/networking/wan-router.txt linux/Documentation/networking/wan-router.txt --- v2.1.44/linux/Documentation/networking/wan-router.txt Sun Feb 2 05:18:29 1997 +++ linux/Documentation/networking/wan-router.txt Wed Jul 16 19:22:50 1997 @@ -1,10 +1,11 @@ ------------------------------------------------------------------------------ WAN Router for Linux Operating System ------------------------------------------------------------------------------ -Version 1.0.0 -December 31, 1996 -Author: Gene Kozin -Copyright (c) 1995-1996 Sangoma Technologies Inc. +Version 1.0.3 - June 3, 1997 +Version 1.0.1 - January 30, 1997 +Author: Jaspreet Singh + Gene Kozin +Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ INTRODUCTION @@ -95,12 +96,6 @@ -KNOWN BUGS AND LIMITATIONS - -/proc user interface is not complete yet. - - - ACKNOLEGEMENTS This product is based on the WANPIPE(tm) Multiprotocol WAN Router developed @@ -122,9 +117,19 @@ REVISION HISTORY +1.0.3 June 3, 1997 + o UDP port for multiple boards (Frame relay, PPP) + o Continuous Transmission of Configure Request Packet for PPP (this + support is only added for 508 cards) + o Connection Timeout for PPP changed from 900 to 0 + o Flow Control for multiple boards and multiple channels (Frame Relay) + +1.0.1 January 30, 1997 + + o Implemented user-readable status and statistics via /proc filesystem + +1.0.0 December 31, 1996 -1.0.0 December 31, 1996 --------------------------- - o Initial version. + o Initial version >>>>>> END <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< diff -u --recursive --new-file v2.1.44/linux/MAINTAINERS linux/MAINTAINERS --- v2.1.44/linux/MAINTAINERS Thu Jun 26 12:33:36 1997 +++ linux/MAINTAINERS Wed Jul 16 19:22:50 1997 @@ -95,6 +95,12 @@ L: linux-net@vger.rutgers.edu S: Maintained +TLAN NETWORK DRIVER +P: James Banks +M: james.banks@caldera.com +L: linux-net@vger.rutgers.edu +S: Supported + DIGI RIGHTSWITCH NETWORK DRIVER P: Rick Richardson M: rick@dgii.com @@ -107,6 +113,11 @@ M: jt@hplb.hpl.hp.com S: Maintained +HP100: Driver for HP 10/100 Mbit/s Network Adapter Series +P: Jarsolav Kysela +M: perex@jcu.cz +S: Maintained + APM DRIVER P: Rik Faith & Stephen Rothwell M: faith@cs.unc.edu, Stephen.Rothwell@canb.auug.org.au @@ -217,10 +228,10 @@ S: Maintained IPX NETWORK LAYER -P: Alan Cox [for the moment] -M: net-patches@lxorguk.ukuu.org.uk -L: linux-ipx@vger.rutgers.edu [will change] -S: Maintained +P: +M: +L: +S: Orphan IDE DRIVER [GENERAL] P: Mark Lord @@ -280,10 +291,10 @@ S: Maintained NETWORKING [GENERAL]: -P: Alan Cox -M: net-patches@lxorguk.ukuu.org.uk +P: Networking Teak +M: netdev@nuclecu.unam.mx L: linux-net@vger.rutgers.edu -W: http://www.uk.linux.org/NetNews.html +W: http://www.uk.linux.org/NetNews.html (2.0 only) S: Maintained NETWORKING [IPv4/IPv6]: @@ -326,8 +337,8 @@ S: Maintained SMP: (except SPARC) -P: Alan Cox -M: smp-patches@lxorguk.ukuu.org.uk +P: Linus Torvalds +M: torvalds@transmeta.com L: linux-smp@vger.rutgers.edu S: Maintained diff -u --recursive --new-file v2.1.44/linux/Makefile linux/Makefile --- v2.1.44/linux/Makefile Thu Jun 26 12:33:36 1997 +++ linux/Makefile Fri Jul 11 11:20:54 1997 @@ -1,6 +1,6 @@ VERSION = 2 PATCHLEVEL = 1 -SUBLEVEL = 44 +SUBLEVEL = 45 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/) diff -u --recursive --new-file v2.1.44/linux/arch/alpha/defconfig linux/arch/alpha/defconfig --- v2.1.44/linux/arch/alpha/defconfig Tue Jul 1 23:23:47 1997 +++ linux/arch/alpha/defconfig Sun Jul 13 21:20:10 1997 @@ -66,7 +66,7 @@ # # CONFIG_BLK_DEV_LOOP is not set # CONFIG_BLK_DEV_MD is not set -CONFIG_BLK_DEV_RAM=y +# CONFIG_BLK_DEV_RAM is not set # CONFIG_BLK_DEV_INITRD is not set # CONFIG_BLK_DEV_XD is not set # CONFIG_BLK_DEV_EZ is not set @@ -195,9 +195,6 @@ # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_DCACHE_PRELOAD is not set -# CONFIG_OMIRR is not set -# CONFIG_TRANS_NAMES is not set # CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y # CONFIG_FAT_FS is not set @@ -205,12 +202,13 @@ # CONFIG_VFAT_FS is not set # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y -# CONFIG_NFS_FS is not set +CONFIG_NFS_FS=y +# CONFIG_ROOT_NFS is not set # CONFIG_NFSD is not set -# CONFIG_SUNRPC is not set -# CONFIG_LOCKD is not set +CONFIG_SUNRPC=y +CONFIG_LOCKD=y # CONFIG_SMB_FS is not set -# CONFIG_ISO9660_FS is not set +CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set diff -u --recursive --new-file v2.1.44/linux/arch/alpha/kernel/osf_sys.c linux/arch/alpha/kernel/osf_sys.c --- v2.1.44/linux/arch/alpha/kernel/osf_sys.c Tue Jul 1 23:23:47 1997 +++ linux/arch/alpha/kernel/osf_sys.c Sun Jul 13 21:20:10 1997 @@ -135,30 +135,46 @@ { int error; struct file *file; + struct dentry *dentry; + struct inode *inode; struct osf_dirent_callback buf; - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) - return -EBADF; - if (!file->f_op || !file->f_op->readdir) - return -ENOTDIR; - error = verify_area(VERIFY_WRITE, dirent, count); - if (error) - return error; - if (basep) { - error = verify_area(VERIFY_WRITE, basep, sizeof(long)); - if (error) - return error; - } + error = -EBADF; + if (fd >= NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if (!file) + goto out; + + dentry = file->f_dentry; + if (!dentry) + goto out; + + inode = dentry->d_inode; + if (!inode) + goto out; + buf.dirent = dirent; buf.basep = basep; buf.count = count; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, osf_filldir); + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = file->f_op->readdir(inode, file, &buf, osf_filldir); if (error < 0) - return error; + goto out; + + error = buf.error; if (count == buf.count) - return buf.error; - return count - buf.count; + goto out; + + error = count - buf.count; +out: + return error; } /* @@ -267,76 +283,73 @@ __kernel_fsid_t f_fsid; } *osf_stat; -static void linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat) +static int linux_to_osf_statfs(struct statfs *linux_stat, struct osf_statfs *osf_stat, unsigned long bufsiz) { - osf_stat->f_type = linux_stat->f_type; - osf_stat->f_flags = 0; /* mount flags */ + struct osf_statfs tmp_stat; + + tmp_stat.f_type = linux_stat->f_type; + tmp_stat.f_flags = 0; /* mount flags */ /* Linux doesn't provide a "fundamental filesystem block size": */ - osf_stat->f_fsize = linux_stat->f_bsize; - osf_stat->f_bsize = linux_stat->f_bsize; - osf_stat->f_blocks = linux_stat->f_blocks; - osf_stat->f_bfree = linux_stat->f_bfree; - osf_stat->f_bavail = linux_stat->f_bavail; - osf_stat->f_files = linux_stat->f_files; - osf_stat->f_ffree = linux_stat->f_ffree; - osf_stat->f_fsid = linux_stat->f_fsid; + tmp_stat.f_fsize = linux_stat->f_bsize; + tmp_stat.f_bsize = linux_stat->f_bsize; + tmp_stat.f_blocks = linux_stat->f_blocks; + tmp_stat.f_bfree = linux_stat->f_bfree; + tmp_stat.f_bavail = linux_stat->f_bavail; + tmp_stat.f_files = linux_stat->f_files; + tmp_stat.f_ffree = linux_stat->f_ffree; + tmp_stat.f_fsid = linux_stat->f_fsid; + if (bufsiz > sizeof(tmp_stat)) + bufsiz = sizeof(tmp_stat); + return copy_to_user(osf_stat, &tmp_stat, bufsiz) ? -EFAULT : 0; } +static int do_osf_statfs(struct dentry * dentry, struct osf_statfs *buffer, unsigned long bufsiz) +{ + struct statfs linux_stat; + struct inode * inode = dentry->d_inode; + struct super_block * sb = inode->i_sb; + int error; + + error = -ENOSYS; + if (sb->s_op->statfs) { + set_fs(KERNEL_DS); + error = sb->s_op->statfs(sb, &linux_stat, sizeof(linux_stat)); + set_fs(USER_DS); + if (!error) + error = linux_to_osf_statfs(&linux_stat, buffer, bufsiz); + } + return error; +} asmlinkage int osf_statfs(char *path, struct osf_statfs *buffer, unsigned long bufsiz) { - struct statfs linux_stat; - struct inode *inode; + struct dentry *dentry; int retval; lock_kernel(); - if (bufsiz > sizeof(struct osf_statfs)) - bufsiz = sizeof(struct osf_statfs); - retval = verify_area(VERIFY_WRITE, buffer, bufsiz); - if (retval) - goto out; - retval = namei(path, &inode); - if (retval) - goto out; - retval = -ENOSYS; - if (!inode->i_sb->s_op->statfs) { - iput(inode); - goto out; + dentry = namei(path); + retval = PTR_ERR(dentry); + if (!IS_ERR(dentry)) { + retval = do_osf_statfs(dentry, buffer, bufsiz); + dput(dentry); } - inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat)); - linux_to_osf_statfs(&linux_stat, buffer); - iput(inode); - retval = 0; -out: unlock_kernel(); return retval; } asmlinkage int osf_fstatfs(unsigned long fd, struct osf_statfs *buffer, unsigned long bufsiz) { - struct statfs linux_stat; struct file *file; - struct inode *inode; + struct dentry *dentry; int retval; lock_kernel(); - retval = verify_area(VERIFY_WRITE, buffer, bufsiz); - if (retval) - goto out; - if (bufsiz > sizeof(struct osf_statfs)) - bufsiz = sizeof(struct osf_statfs); retval = -EBADF; if (fd >= NR_OPEN || !(file = current->files->fd[fd])) goto out; - retval = -ENOENT; - if (!(inode = file->f_inode)) - goto out; - retval = -ENOSYS; - if (!inode->i_sb->s_op->statfs) - goto out; - inode->i_sb->s_op->statfs(inode->i_sb, &linux_stat, sizeof(linux_stat)); - linux_to_osf_statfs(&linux_stat, buffer); - retval = 0; + dentry = file->f_dentry; + if (dentry) + retval = do_osf_statfs(dentry, buffer, bufsiz); out: unlock_kernel(); return retval; @@ -369,56 +382,60 @@ uid_t exroot; }; -static int getdev(const char *name, int rdonly, struct inode **ino) +static int getdev(const char *name, int rdonly, struct dentry **dp) { kdev_t dev; + struct dentry *dentry; struct inode *inode; struct file_operations *fops; int retval; - retval = namei(name, &inode); - if (retval) + dentry = namei(name); + retval = PTR_ERR(dentry); + if (IS_ERR(dentry)) return retval; + + inode = dentry->d_inode; if (!S_ISBLK(inode->i_mode)) { - iput(inode); + dput(dentry); return -ENOTBLK; } if (IS_NODEV(inode)) { - iput(inode); + dput(dentry); return -EACCES; } dev = inode->i_rdev; if (MAJOR(dev) >= MAX_BLKDEV) { - iput(inode); + dput(dentry); return -ENXIO; } fops = get_blkfops(MAJOR(dev)); if (!fops) { - iput(inode); + dput(dentry); return -ENODEV; } if (fops->open) { struct file dummy; memset(&dummy, 0, sizeof(dummy)); - dummy.f_inode = inode; + dummy.f_dentry = dentry; dummy.f_mode = rdonly ? 1 : 3; retval = fops->open(inode, &dummy); if (retval) { - iput(inode); + dput(dentry); return retval; } } - *ino = inode; + *dp = dentry; return 0; } -static void putdev(struct inode *inode) +static void putdev(struct dentry *dentry) { struct file_operations *fops; - fops = get_blkfops(MAJOR(inode->i_rdev)); + fops = get_blkfops(MAJOR(dentry->d_inode->i_rdev)); if (fops->release) - fops->release(inode, NULL); + fops->release(dentry->d_inode, NULL); } /* @@ -429,40 +446,40 @@ static int osf_ufs_mount(char *dirname, struct ufs_args *args, int flags) { int retval; - struct inode *inode; + struct dentry *dentry; struct cdfs_args tmp; retval = verify_area(VERIFY_READ, args, sizeof(*args)); if (retval) return retval; copy_from_user(&tmp, args, sizeof(tmp)); - retval = getdev(tmp.devname, 0, &inode); + retval = getdev(tmp.devname, 0, &dentry); if (retval) return retval; - retval = do_mount(inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL); + retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, "ext2", flags, NULL); if (retval) - putdev(inode); - iput(inode); + putdev(dentry); + dput(dentry); return retval; } static int osf_cdfs_mount(char *dirname, struct cdfs_args *args, int flags) { int retval; - struct inode *inode; + struct dentry * dentry; struct cdfs_args tmp; retval = verify_area(VERIFY_READ, args, sizeof(*args)); if (retval) return retval; copy_from_user(&tmp, args, sizeof(tmp)); - retval = getdev(tmp.devname, 1, &inode); + retval = getdev(tmp.devname, 1, &dentry); if (retval) return retval; - retval = do_mount(inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL); + retval = do_mount(dentry->d_inode->i_rdev, tmp.devname, dirname, "iso9660", flags, NULL); if (retval) - putdev(inode); - iput(inode); + putdev(dentry); + dput(dentry); return retval; } diff -u --recursive --new-file v2.1.44/linux/arch/alpha/kernel/process.c linux/arch/alpha/kernel/process.c --- v2.1.44/linux/arch/alpha/kernel/process.c Tue May 13 22:41:00 1997 +++ linux/arch/alpha/kernel/process.c Sun Jul 13 21:20:10 1997 @@ -308,8 +308,9 @@ char * filename; lock_kernel(); - error = getname((char *) a0, &filename); - if (error) + filename = getname((char *) a0); + error = PTR_ERR(filename); + if (IS_ERR(filename)) goto out; error = do_execve(filename, (char **) a1, (char **) a2, ®s); putname(filename); diff -u --recursive --new-file v2.1.44/linux/arch/alpha/kernel/traps.c linux/arch/alpha/kernel/traps.c --- v2.1.44/linux/arch/alpha/kernel/traps.c Wed Apr 23 19:01:14 1997 +++ linux/arch/alpha/kernel/traps.c Sun Jul 13 21:20:10 1997 @@ -24,13 +24,14 @@ unsigned long *r9_15) { long i; - unsigned long sp, ra; + unsigned long ra; unsigned int * pc; + unsigned long * sp; if (regs->ps & 8) return; printk("%s(%d): %s %ld\n", current->comm, current->pid, str, err); - sp = (unsigned long) (regs+1); + sp = (unsigned long *) (regs+1); __get_user(ra, (unsigned long *)sp); printk("pc = [<%016lx>] ps = %04lx\n", regs->pc, regs->ps); printk("rp = [<%016lx>] ra = [<%016lx>]\n", regs->r26, ra); @@ -54,7 +55,7 @@ printk("r22= %016lx r23= %016lx\n", regs->r22, regs->r23); printk("r24= %016lx r25= %016lx\n", regs->r24, regs->r25); printk("r27= %016lx r28= %016lx\n", regs->r27, regs->r28); - printk("gp = %016lx sp = %016lx\n", regs->gp, sp); + printk("gp = %016lx sp = %p\n", regs->gp, sp); printk("Code:"); pc = (unsigned int *) regs->pc; @@ -65,6 +66,19 @@ printk("%c%08x%c",i?' ':'<',insn,i?' ':'>'); } printk("\n"); + printk("Trace:"); + while (0x1ff8 & (unsigned long) sp) { + extern unsigned long _stext, _etext; + unsigned long tmp = *sp; + sp++; + if (tmp < (unsigned long) &_stext) + continue; + if (tmp >= (unsigned long) &_etext) + continue; + printk(" [<%lx>]", tmp); + } + printk("\n"); + do_exit(SIGSEGV); } diff -u --recursive --new-file v2.1.44/linux/arch/alpha/mm/fault.c linux/arch/alpha/mm/fault.c --- v2.1.44/linux/arch/alpha/mm/fault.c Thu May 15 16:48:01 1997 +++ linux/arch/alpha/mm/fault.c Mon Jul 14 10:40:40 1997 @@ -67,8 +67,7 @@ long cause, struct pt_regs *regs) { struct vm_area_struct * vma; - struct task_struct *tsk = current; - struct mm_struct *mm = tsk->mm; + struct mm_struct *mm = current->mm; unsigned fixup; down(&mm->mmap_sem); @@ -97,7 +96,7 @@ if (!(vma->vm_flags & VM_WRITE)) goto bad_area; } - handle_mm_fault(tsk, vma, address, cause > 0); + handle_mm_fault(current, vma, address, cause > 0); up(&mm->mmap_sem); return; @@ -108,23 +107,20 @@ bad_area: up(&mm->mmap_sem); + if (user_mode(regs)) { + force_sig(SIGSEGV, current); + return; + } + /* Are we prepared to handle this fault as an exception? */ if ((fixup = search_exception_table(regs->pc)) != 0) { unsigned long newpc; newpc = fixup_exception(dpf_reg, fixup, regs->pc); - printk("Taking exception at [<%lx>] (%lx)\n", regs->pc, newpc); + printk("%s: Exception at [<%lx>] (%lx)\n", current->comm, regs->pc, newpc); regs->pc = newpc; return; } - if (user_mode(regs)) { - printk("%s: memory violation at pc=%08lx ra=%08lx " - "(bad address = %08lx)\n", - tsk->comm, regs->pc, regs->r26, address); - die_if_kernel("oops", regs, cause, (unsigned long*)regs - 16); - force_sig(SIGSEGV, tsk); - return; - } /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. diff -u --recursive --new-file v2.1.44/linux/arch/i386/defconfig linux/arch/i386/defconfig --- v2.1.44/linux/arch/i386/defconfig Mon Jul 7 10:50:01 1997 +++ linux/arch/i386/defconfig Wed Jul 16 20:04:35 1997 @@ -192,9 +192,6 @@ # Filesystems # # CONFIG_QUOTA is not set -# CONFIG_DCACHE_PRELOAD is not set -# CONFIG_OMIRR is not set -# CONFIG_TRANS_NAMES is not set # CONFIG_MINIX_FS is not set CONFIG_EXT2_FS=y # CONFIG_FAT_FS is not set @@ -208,7 +205,7 @@ CONFIG_SUNRPC=y CONFIG_LOCKD=y # CONFIG_SMB_FS is not set -# CONFIG_ISO9660_FS is not set +CONFIG_ISO9660_FS=y # CONFIG_HPFS_FS is not set # CONFIG_SYSV_FS is not set # CONFIG_AFFS_FS is not set @@ -230,12 +227,14 @@ # CONFIG_MS_BUSMOUSE is not set CONFIG_PSMOUSE=y CONFIG_82C710_MOUSE=y +# CONFIG_PC110_PAD is not set # CONFIG_UMISC is not set # CONFIG_QIC02_TAPE is not set # CONFIG_FTAPE is not set # CONFIG_APM is not set # CONFIG_WATCHDOG is not set # CONFIG_RTC is not set +# CONFIG_JOYSTICK is not set # # Sound diff -u --recursive --new-file v2.1.44/linux/arch/i386/kernel/bios32.c linux/arch/i386/kernel/bios32.c --- v2.1.44/linux/arch/i386/kernel/bios32.c Thu May 15 16:48:01 1997 +++ linux/arch/i386/kernel/bios32.c Wed Jul 16 19:22:50 1997 @@ -1,7 +1,7 @@ /* * bios32.c - BIOS32, PCI BIOS functions. * - * $Id: bios32.c,v 1.11 1997/05/07 13:35:21 mj Exp $ + * $Id: bios32.c,v 1.12 1997/06/26 13:33:46 mj Exp $ * * Sponsored by * iX Multiuser Multitasking Magazine @@ -59,6 +59,8 @@ * * May 7, 1997 : Added some missing cli()'s. [mj] * + * Jun 20, 1997 : Corrected problems in "conf1" type accesses. + * (paubert@iram.es) */ #include @@ -512,16 +514,7 @@ save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - switch (where & 3) { - case 0: *value = inb(0xCFC); - break; - case 1: *value = inb(0xCFD); - break; - case 2: *value = inb(0xCFE); - break; - case 3: *value = inb(0xCFF); - break; - } + *value = inb(0xCFC + (where&3)); restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -531,12 +524,10 @@ { unsigned long flags; + if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - if (where & 2) - *value = inw(0xCFE); - else - *value = inw(0xCFC); + *value = inw(0xCFC + (where&2)); restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -546,6 +537,7 @@ { unsigned long flags; + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); *value = inl(0xCFC); @@ -560,7 +552,7 @@ save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - outb(value, 0xCFC); + outb(value, 0xCFC + (where&3)); restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -570,9 +562,10 @@ { unsigned long flags; + if (where&1) return PCIBIOS_BAD_REGISTER_NUMBER; save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); - outw(value, 0xCFC); + outw(value, 0xCFC + (where&2)); restore_flags(flags); return PCIBIOS_SUCCESSFUL; } @@ -582,6 +575,7 @@ { unsigned long flags; + if (where&3) return PCIBIOS_BAD_REGISTER_NUMBER; save_flags(flags); cli(); outl(CONFIG_CMD(bus,device_fn,where), 0xCF8); outl(value, 0xCFC); diff -u --recursive --new-file v2.1.44/linux/arch/i386/kernel/process.c linux/arch/i386/kernel/process.c --- v2.1.44/linux/arch/i386/kernel/process.c Tue May 13 22:41:01 1997 +++ linux/arch/i386/kernel/process.c Mon Jul 14 10:17:29 1997 @@ -623,8 +623,9 @@ char * filename; lock_kernel(); - error = getname((char *) regs.ebx, &filename); - if (error) + filename = getname((char *) regs.ebx); + error = PTR_ERR(filename); + if (IS_ERR(filename)) goto out; error = do_execve(filename, (char **) regs.ecx, (char **) regs.edx, ®s); putname(filename); diff -u --recursive --new-file v2.1.44/linux/arch/i386/kernel/setup.c linux/arch/i386/kernel/setup.c --- v2.1.44/linux/arch/i386/kernel/setup.c Mon Jun 30 15:57:14 1997 +++ linux/arch/i386/kernel/setup.c Wed Jul 16 19:22:50 1997 @@ -244,6 +244,17 @@ return NULL; } +static const char * k5model(unsigned int nr) +{ + static const char *model[] = { + "SSA5 (PR-75, PR-90, PR-100)", "5k86 (PR-120, PR-133)", + "5k86 (PR-166)", "5k86 (PR-200)", "", "", "K6" + }; + if (nr < sizeof(model)/sizeof(char *)) + return model[nr]; + return NULL; +} + static const char * i686model(unsigned int nr) { static const char *model[] = { @@ -263,7 +274,11 @@ p = i486model(model); break; case 5: - p = i586model(model); + if(strcmp(x86_vendor_id, "AuthenticAMD") == 0){ + p = k5model(model); + } else { + p = i586model(model); + } break; case 6: p = i686model(model); diff -u --recursive --new-file v2.1.44/linux/arch/i386/mm/fault.c linux/arch/i386/mm/fault.c --- v2.1.44/linux/arch/i386/mm/fault.c Thu May 15 16:48:01 1997 +++ linux/arch/i386/mm/fault.c Mon Jul 14 10:40:13 1997 @@ -161,23 +161,25 @@ bad_area: up(&mm->mmap_sem); - /* Are we prepared to handle this fault? */ + /* User mode accesses just cause a SIGSEGV */ + if (error_code & 4) { + tsk->tss.cr2 = address; + tsk->tss.error_code = error_code; + tsk->tss.trap_no = 14; + force_sig(SIGSEGV, tsk); + goto out; + } + + /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { printk(KERN_DEBUG "%s: Exception at [<%lx>] (%lx)\n", - current->comm, + tsk->comm, regs->eip, fixup); regs->eip = fixup; goto out; } - if (error_code & 4) { - tsk->tss.cr2 = address; - tsk->tss.error_code = error_code; - tsk->tss.trap_no = 14; - force_sig(SIGSEGV, tsk); - goto out; - } /* * Oops. The kernel tried to access some bad page. We'll have to * terminate things with extreme prejudice. diff -u --recursive --new-file v2.1.44/linux/arch/sparc/Makefile linux/arch/sparc/Makefile --- v2.1.44/linux/arch/sparc/Makefile Tue May 13 22:41:03 1997 +++ linux/arch/sparc/Makefile Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.28 1997/05/01 01:41:21 davem Exp $ +# $Id: Makefile,v 1.29 1997/07/11 11:05:23 jj Exp $ # sparc/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -45,3 +45,6 @@ check_asm: $(MAKE) -C arch/sparc/kernel check_asm + +tftpboot.img: + $(MAKE) -C arch/sparc/boot tftpboot.img diff -u --recursive --new-file v2.1.44/linux/arch/sparc/boot/Makefile linux/arch/sparc/boot/Makefile --- v2.1.44/linux/arch/sparc/boot/Makefile Sat Nov 9 00:11:31 1996 +++ linux/arch/sparc/boot/Makefile Wed Jul 16 19:22:50 1997 @@ -1,12 +1,23 @@ -# $Id: Makefile,v 1.3 1996/08/04 08:40:58 ecd Exp $ -# Makefile for the Sparc low level /boot module. +# $Id: Makefile,v 1.4 1997/07/11 11:05:18 jj Exp $ +# Makefile for the Sparc boot stuff. # # Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) +# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + +ROOT_IMG =/usr/src/root.img +ELFTOAOUT =elftoaout all: boot boot: @echo "Nothing special to be done for 'boot' on Linux/SPARC." + +tftpboot.img: piggyback + $(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img + ./piggyback tftpboot.img $(TOPDIR)/System.map $(ROOT_IMG) + +piggyback: piggyback.c + $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c dep: diff -u --recursive --new-file v2.1.44/linux/arch/sparc/boot/piggyback.c linux/arch/sparc/boot/piggyback.c --- v2.1.44/linux/arch/sparc/boot/piggyback.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc/boot/piggyback.c Wed Jul 16 19:22:50 1997 @@ -0,0 +1,100 @@ +/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:17 jj Exp $ + Simple utility to make a single-image install kernel with initial ramdisk + for Sparc tftpbooting without need to set up nfs. + + Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Note: run this on an a.out kernel (use elftoaout for it), as PROM looks for a.out image onlly + usage: piggyback vmlinux System.map tail, where tail is gzipped fs of the initial ramdisk */ + +void die(char *str) +{ + perror (str); + exit(1); +} + +int main(int argc,char **argv) +{ + char buffer [1024], *q, *r; + unsigned int i, j, k, start, end, offset; + FILE *map; + struct stat s; + int image, tail; + + if (stat (argv[3], &s) < 0) die (argv[3]); + map = fopen (argv[2], "r"); + if (!map) die(argv[2]); + while (fgets (buffer, 1024, map)) { + if (!strcmp (buffer + 11, "start\n")) + start = strtoul (buffer, NULL, 16); + else if (!strcmp (buffer + 11, "end\n")) + end = strtoul (buffer, NULL, 16); + } + fclose (map); + if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]); + if (read(image,buffer,512) != 512) die(argv[1]); + if (!memcmp (buffer, "\177ELF", 4)) { + unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28)); + + i = p[1] + *(unsigned int *)(buffer + 24) - p[2]; + if (lseek(image,i,0) < 0) die("lseek"); + if (read(image,buffer,512) != 512) die(argv[1]); + j = 0; + } else if (*(unsigned int *)buffer == 0x01030107) { + i = j = 32; + } else { + fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n"); + exit(1); + } + k = i; + i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512; + if (lseek(image,i,0) < 0) die("lseek"); + if (read(image,buffer,1024) != 1024) die(argv[1]); + for (q = buffer, r = q + 512; q < r; q += 4) { + if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S') + break; + } + if (q == r) { + fprintf (stderr, "Couldn't find headers signature in the kernel.\n"); + exit(1); + } + offset = i + (q - buffer) + 10; + if (lseek(image, offset, 0) < 0) die ("lseek"); + *(unsigned *)buffer = 0; + *(unsigned *)(buffer + 4) = 0x01000000; + *(unsigned *)(buffer + 8) = ((end + 32 + 4095) & ~4095); + *(unsigned *)(buffer + 12) = s.st_size; + if (write(image,buffer+2,14) != 14) die (argv[1]); + if (lseek(image, k - start + ((end + 32 + 4095) & ~4095), 0) < 0) die ("lseek"); + if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]); + while ((i = read (tail,buffer,1024)) > 0) + if (write(image,buffer,i) != i) die (argv[1]); + if (close(image) < 0) die("close"); + if (close(tail) < 0) die("close"); + return 0; +} diff -u --recursive --new-file v2.1.44/linux/arch/sparc/defconfig linux/arch/sparc/defconfig --- v2.1.44/linux/arch/sparc/defconfig Thu Jun 26 12:33:38 1997 +++ linux/arch/sparc/defconfig Wed Jul 16 19:22:50 1997 @@ -42,7 +42,7 @@ SUN_FB_BWTWO=y SUN_FB_LEO=y TADPOLE_FB_WEITEK=y -SUN_FB_CREATOR=y +#SUN_FB_CREATOR is not set # # Misc Linux/SPARC drivers diff -u --recursive --new-file v2.1.44/linux/arch/sparc/kernel/process.c linux/arch/sparc/kernel/process.c --- v2.1.44/linux/arch/sparc/kernel/process.c Thu May 15 16:48:01 1997 +++ linux/arch/sparc/kernel/process.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.98 1997/05/14 20:44:54 davem Exp $ +/* $Id: process.c,v 1.99 1997/07/17 02:20:13 davem Exp $ * linux/arch/sparc/kernel/process.c * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -594,8 +594,9 @@ base = 1; lock_kernel(); - error = getname((char *) regs->u_regs[base + UREG_I0], &filename); - if(error) + filename = getname((char *)regs->u_regs[base + UREG_I0]); + error = PTR_ERR(filename); + if(IS_ERR(filename)) goto out; error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1], (char **) regs->u_regs[base + UREG_I2], regs); diff -u --recursive --new-file v2.1.44/linux/arch/sparc/kernel/sys_sunos.c linux/arch/sparc/kernel/sys_sunos.c --- v2.1.44/linux/arch/sparc/kernel/sys_sunos.c Tue May 13 22:41:03 1997 +++ linux/arch/sparc/kernel/sys_sunos.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos.c,v 1.79 1997/04/23 23:01:15 ecd Exp $ +/* $Id: sys_sunos.c,v 1.80 1997/07/17 02:20:22 davem Exp $ * sys_sunos.c: SunOS specific syscall compatibility support. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) @@ -90,10 +90,12 @@ * of /dev/zero, transform it into an anonymous mapping. * SunOS is so stupid some times... hmph! */ - if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR && - MINOR(file->f_inode->i_rdev) == 5) { - flags |= MAP_ANONYMOUS; - file = 0; + if(file->f_dentry && file->f_dentry->d_inode) { + if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR && + MINOR(file->f_dentry->d_inode->i_rdev) == 5) { + flags |= MAP_ANONYMOUS; + file = 0; + } } if(!(flags & MAP_FIXED)) addr = 0; @@ -428,16 +430,32 @@ asmlinkage int sunos_getdents(unsigned int fd, void * dirent, int cnt) { struct file * file; + struct dentry * dentry; + struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; lock_kernel(); - if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= SUNOS_NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + dentry = file->f_dentry; + if(!dentry) goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; + error = -EINVAL; if(cnt < (sizeof(struct sunos_dirent) + 255)) goto out; @@ -446,13 +464,12 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir); + error = file->f_op->readdir(inode, file, &buf, sunos_filldir); if (error < 0) goto out; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - } else { + error = buf.error; + if (lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = cnt - buf.count; } @@ -503,16 +520,32 @@ asmlinkage int sunos_getdirentries(unsigned int fd, void * dirent, int cnt, unsigned int *basep) { struct file * file; + struct dentry * dentry; + struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; lock_kernel(); - if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= SUNOS_NR_OPEN) goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; + error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) goto out; @@ -521,13 +554,12 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry); + error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry); if (error < 0) goto out; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - } else { + error = buf.error; + if (lastdirent) { put_user(file->f_pos, basep); error = cnt - buf.count; } @@ -725,12 +757,13 @@ int try_port; int ret; struct socket *socket; + struct dentry *dentry; struct inode *inode; struct file *file; file = current->files->fd [fd]; - inode = file->f_inode; - if (!inode || !inode->i_sock) + dentry = file->f_dentry; + if(!dentry || !(inode = dentry->d_inode)) return 0; socket = &inode->u.socket_i; diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/Makefile linux/arch/sparc64/Makefile --- v2.1.44/linux/arch/sparc64/Makefile Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/Makefile Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.19 1997/06/26 12:48:45 jj Exp $ +# $Id: Makefile,v 1.20 1997/07/11 11:05:29 jj Exp $ # sparc64/Makefile # # Makefile for the architecture dependent flags and dependencies on the @@ -49,3 +49,6 @@ check_asm: $(MAKE) -C arch/sparc64/kernel check_asm + +tftpboot.img: + $(MAKE) -C arch/sparc64/boot tftpboot.img diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/boot/Makefile linux/arch/sparc64/boot/Makefile --- v2.1.44/linux/arch/sparc64/boot/Makefile Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/boot/Makefile Wed Jul 16 19:22:50 1997 @@ -0,0 +1,23 @@ +# $Id: Makefile,v 1.1 1997/07/11 11:05:25 jj Exp $ +# Makefile for the Sparc64 boot stuff. +# +# Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) +# Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + +ROOT_IMG =/usr/src/root.img +ELFTOAOUT =elftoaout + +all: boot + +boot: + @echo "Nothing special to be done for 'boot' on Linux/UltraSPARC." + +tftpboot.img: piggyback + $(ELFTOAOUT) $(TOPDIR)/vmlinux -o tftpboot.img + ./piggyback tftpboot.img $(TOPDIR)/System.map $(ROOT_IMG) + +piggyback: piggyback.c + $(HOSTCC) $(HOSTCFLAGS) -o piggyback piggyback.c + +dep: + diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/boot/piggyback.c linux/arch/sparc64/boot/piggyback.c --- v2.1.44/linux/arch/sparc64/boot/piggyback.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/boot/piggyback.c Wed Jul 16 19:22:50 1997 @@ -0,0 +1,109 @@ +/* $Id: piggyback.c,v 1.1 1997/07/11 11:05:26 jj Exp $ + Simple utility to make a single-image install kernel with initial ramdisk + for Sparc64 tftpbooting without need to set up nfs. + + Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* Note: run this on an a.out kernel (use elftoaout for it), as PROM looks for a.out image onlly + usage: piggyback vmlinux System.map tail, where tail is gzipped fs of the initial ramdisk */ + +void die(char *str) +{ + perror (str); + exit(1); +} + +int main(int argc,char **argv) +{ + char buffer [1024], *q, *r; + unsigned int i, j, k, start, end, offset; + FILE *map; + struct stat s; + int image, tail; + + if (stat (argv[3], &s) < 0) die (argv[3]); + map = fopen (argv[2], "r"); + if (!map) die(argv[2]); + while (fgets (buffer, 1024, map)) { + if (!strcmp (buffer + 19, "start\n")) + start = strtoul (buffer + 8, NULL, 16); + else if (!strcmp (buffer + 19, "end\n")) + end = strtoul (buffer + 8, NULL, 16); + } + fclose (map); + if ((image = open(argv[1],O_RDWR)) < 0) die(argv[1]); + if (read(image,buffer,512) != 512) die(argv[1]); + if (!memcmp (buffer, "\177ELF", 4)) { + unsigned int *p = (unsigned int *)(buffer + *(unsigned int *)(buffer + 28)); + + i = p[1] + *(unsigned int *)(buffer + 24) - p[2]; + if (lseek(image,i,0) < 0) die("lseek"); + if (read(image,buffer,512) != 512) die(argv[1]); + j = 0; + } else if (*(unsigned int *)buffer == 0x01030107) { + i = j = 32; + } else { + fprintf (stderr, "Not ELF nor a.out. Don't blame me.\n"); + exit(1); + } + k = i; + if (j == 32 && buffer[40] == 'H' && buffer[41] == 'd' && buffer[42] == 'r' && buffer[43] == 'S') { + offset = 40 + 10; + } else { + i += ((*(unsigned short *)(buffer + j + 2))<<2) - 512; + if (lseek(image,i,0) < 0) die("lseek"); + if (read(image,buffer,1024) != 1024) die(argv[1]); + for (q = buffer, r = q + 512; q < r; q += 4) { + if (*q == 'H' && q[1] == 'd' && q[2] == 'r' && q[3] == 'S') + break; + } + if (q == r) { + fprintf (stderr, "Couldn't find headers signature in the kernel.\n"); + exit(1); + } + offset = i + (q - buffer) + 10; + } + if (lseek(image, offset, 0) < 0) die ("lseek"); + *(unsigned *)buffer = 0; + *(unsigned *)(buffer + 4) = 0x01000000; + *(unsigned *)(buffer + 8) = ((end + 32 + 8191) & ~8191); + *(unsigned *)(buffer + 12) = s.st_size; + if (write(image,buffer+2,14) != 14) die (argv[1]); + if (lseek(image, 4, 0) < 0) die ("lseek"); + *(unsigned *)buffer = ((end + 32 + 8191) & ~8191) - (start & ~0x3fffffUL) + s.st_size; + *(unsigned *)(buffer + 4) = 0; + *(unsigned *)(buffer + 8) = 0; + if (write(image,buffer,12) != 12) die (argv[1]); + if (lseek(image, k - start + ((end + 32 + 8191) & ~8191), 0) < 0) die ("lseek"); + if ((tail = open(argv[3],O_RDONLY)) < 0) die(argv[3]); + while ((i = read (tail,buffer,1024)) > 0) + if (write(image,buffer,i) != i) die (argv[1]); + if (close(image) < 0) die("close"); + if (close(tail) < 0) die("close"); + return 0; +} diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/defconfig linux/arch/sparc64/defconfig --- v2.1.44/linux/arch/sparc64/defconfig Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/defconfig Wed Jul 16 19:22:50 1997 @@ -94,7 +94,7 @@ CONFIG_PATH_MTU_DISCOVERY=y CONFIG_IP_NOSR=y CONFIG_SKB_LARGE=y -# CONFIG_IPV6 is not set +CONFIG_IPV6=m # # @@ -120,7 +120,7 @@ # SCSI support type (disk, tape, CDrom) # CONFIG_BLK_DEV_SD=y -# CONFIG_CHR_DEV_ST is not set +CONFIG_CHR_DEV_ST=y CONFIG_BLK_DEV_SR=y CONFIG_BLK_DEV_SR_VENDOR=y CONFIG_CHR_DEV_SG=m @@ -141,13 +141,20 @@ # Network device support # CONFIG_NETDEVICES=y -CONFIG_DUMMY=y -# CONFIG_PPP is not set -# CONFIG_SLIP is not set +CONFIG_DUMMY=m +CONFIG_PPP=m + +# +# CCP compressors for PPP are only built as modules. +# +CONFIG_SLIP=m +CONFIG_SLIP_COMPRESSED=y +CONFIG_SLIP_SMART=y +# CONFIG_SLIP_MODE_SLIP6 is not set CONFIG_SUNLANCE=y -CONFIG_HAPPYMEAL=m +CONFIG_HAPPYMEAL=y CONFIG_SUNQE=m -# CONFIG_MYRI_SBUS is not set +CONFIG_MYRI_SBUS=m # # Filesystems @@ -156,11 +163,11 @@ # CONFIG_DCACHE_PRELOAD is not set # CONFIG_OMIRR is not set # CONFIG_TRANS_NAMES is not set -# CONFIG_MINIX_FS is not set +CONFIG_MINIX_FS=m CONFIG_EXT2_FS=y -# CONFIG_FAT_FS is not set -# CONFIG_MSDOS_FS is not set -# CONFIG_VFAT_FS is not set +CONFIG_FAT_FS=m +CONFIG_MSDOS_FS=m +CONFIG_VFAT_FS=m # CONFIG_UMSDOS_FS is not set CONFIG_PROC_FS=y CONFIG_NFS_FS=y @@ -170,15 +177,17 @@ CONFIG_NFSD=m CONFIG_SUNRPC=y CONFIG_LOCKD=y -# CONFIG_SMB_FS is not set -# CONFIG_NCP_FS is not set +CONFIG_SMB_FS=m +CONFIG_SMB_WIN95=y +CONFIG_NCP_FS=m CONFIG_ISO9660_FS=y -# CONFIG_HPFS_FS is not set -# CONFIG_SYSV_FS is not set -# CONFIG_AFFS_FS is not set -# CONFIG_ROMFS_FS is not set +CONFIG_HPFS_FS=m +CONFIG_SYSV_FS=m +CONFIG_AFFS_FS=m +CONFIG_ROMFS_FS=m CONFIG_AUTOFS_FS=m -CONFIG_UFS_FS=y +CONFIG_AMIGA_PARTITION=y +CONFIG_UFS_FS=m CONFIG_BSD_DISKLABEL=y CONFIG_SMD_DISKLABEL=y diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/binfmt_aout32.c linux/arch/sparc64/kernel/binfmt_aout32.c --- v2.1.44/linux/arch/sparc64/kernel/binfmt_aout32.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/binfmt_aout32.c Wed Jul 16 19:22:50 1997 @@ -78,6 +78,7 @@ static inline int do_aout32_core_dump(long signr, struct pt_regs * regs) { + struct dentry * dentry = NULL; struct inode * inode = NULL; struct file file; unsigned short fs; @@ -103,10 +104,12 @@ #else corefile[4] = '\0'; #endif - if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { - inode = NULL; + dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600); + if (IS_ERR(dentry)) { + dentry = NULL; goto end_coredump; } + inode = dentry->d_inode; if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) @@ -116,7 +119,7 @@ file.f_mode = 3; file.f_flags = 0; file.f_count = 1; - file.f_inode = inode; + file.f_dentry = dentry; file.f_pos = 0; file.f_reada = 0; file.f_op = inode->i_op->default_file_ops; @@ -169,7 +172,6 @@ /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); - inode->i_status |= ST_MODIFIED; close_coredump: if (file.f_op->release) file.f_op->release(inode,&file); @@ -177,7 +179,7 @@ put_write_access(inode); end_coredump: set_fs(fs); - iput(inode); + dput(dentry); return has_dumped; } @@ -259,7 +261,7 @@ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || - bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { + bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } @@ -297,12 +299,12 @@ error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), ex.a_text, 0); error = do_mmap(NULL, N_DATADDR(ex), ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex), + read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex), ex.a_data, 0); goto beyond_if; } @@ -312,14 +314,14 @@ ex.a_text+ex.a_data + PAGE_SIZE - 1, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); } else { if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && (N_MAGIC(ex) != NMAGIC)) printk(KERN_NOTICE "executable not page aligned\n"); - fd = open_inode(bprm->inode, O_RDONLY); + fd = open_dentry(bprm->dentry, O_RDONLY); if (fd < 0) return fd; @@ -329,7 +331,7 @@ do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset, + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); goto beyond_if; } @@ -396,17 +398,20 @@ { struct file * file; struct exec ex; - struct inode * inode; + struct dentry * dentry; + struct inode * inode; unsigned int len; unsigned int bss; unsigned int start_addr; unsigned long error; file = current->files->fd[fd]; - inode = file->f_inode; if (!file || !file->f_op) return -EACCES; + + dentry = file->f_dentry; + inode = dentry->d_inode; /* Seek into the file */ if (file->f_op->llseek) { diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/cpu.c linux/arch/sparc64/kernel/cpu.c --- v2.1.44/linux/arch/sparc64/kernel/cpu.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/cpu.c Wed Jul 16 19:22:50 1997 @@ -28,6 +28,7 @@ */ struct cpu_fp_info linux_sparc_fpu[] = { { 0x17, 0x10, 0, "UltraSparc I integrated FPU"}, + { 0x22, 0x10, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x11, 0, "UltraSparc II integrated FPU"}, { 0x17, 0x12, 0, "UltraSparc III integrated FPU"}, }; @@ -36,6 +37,7 @@ struct cpu_iu_info linux_sparc_chips[] = { { 0x17, 0x10, "TI UltraSparc I (SpitFire)"}, + { 0x22, 0x10, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x11, "TI UltraSparc II (BlackBird)"}, { 0x17, 0x12, "TI UltraSparc III (Cheetah)"}, /* A guess... */ }; diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/entry.S linux/arch/sparc64/kernel/entry.S --- v2.1.44/linux/arch/sparc64/kernel/entry.S Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/entry.S Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: entry.S,v 1.45 1997/07/05 09:52:25 davem Exp $ +/* $Id: entry.S,v 1.50 1997/07/15 16:53:00 davem Exp $ * arch/sparc64/kernel/entry.S: Sparc64 trap low-level entry points. * * Copyright (C) 1995,1997 David S. Miller (davem@caip.rutgers.edu) @@ -7,6 +7,7 @@ * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ +#include #include #include @@ -191,16 +192,18 @@ wrpr %g3, %tstate retry +#ifdef __SMP__ /* Note check out head.h, this code isn't even used for UP, * for SMP things will be different. In particular the data * registers for cross calls will be: * - * DATA 0: Address of function to call - * DATA 1: Argument 1, place in %g6 - * DATA 2: Argument 2, place in %g7 + * DATA 0: [low 32-bits] Address of function to call, jmp to this + * [high 32-bits] MMU Context Argument 0, place in %g5 + * DATA 1: Address Argument 1, place in %g6 + * DATA 2: Address Argument 2, place in %g7 * * With this method we can do most of the cross-call tlb/cache - * flushing in very quickly. + * flushing very quickly. */ .align 32 .globl do_ivec @@ -211,12 +214,14 @@ mov 0x40, %g2 /* Load up Interrupt Vector Data 0 register. */ + sethi %hi(KERNBASE), %g4 ldxa [%g2] ASI_UDB_INTR_R, %g3 - sethi %hi(ivector_to_mask), %g5 + cmp %g3, %g4 + bgeu,pn %xcc, do_ivec_xcall + nop and %g3, 0x7ff, %g3 - orcc %g5, %lo(ivector_to_mask), %g5 sllx %g3, 3, %g3 - ldx [%g5 + %g3], %g2 + ldx [%g1 + %g3], %g2 brz,pn %g2, do_ivec_spurious nop @@ -231,7 +236,14 @@ stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync retry - +do_ivec_xcall: + srlx %g3, 32, %g5 + add %g2, 0x10, %g2 + sra %g3, 0, %g3 + ldxa [%g2] ASI_UDB_INTR_R, %g6 + add %g2, 0x10, %g2 + jmpl %g3, %g0 + ldxa [%g2] ASI_UDB_INTR_R, %g7 do_ivec_spurious: stxa %g0, [%g0] ASI_INTR_RECEIVE membar #Sync @@ -243,6 +255,7 @@ add %sp, STACK_BIAS + REGWIN_SZ, %o0 ba,pt %xcc, rtrap clr %l6 +#endif /* __SMP__ */ .globl getcc, setcc getcc: @@ -263,10 +276,104 @@ retl stx %o1, [%o0 + PT_V9_TSTATE] - /* XXX Here is stuff we still need to write... -DaveM XXX */ - .globl floppy_hardint, indirect_syscall, netbsd_syscall - .globl solaris_syscall +#ifdef CONFIG_BLK_DEV_FD + .globl floppy_hardint floppy_hardint: + sethi %hi(doing_pdma), %g1 + ld [%g1 + %lo(doing_pdma)], %g2 + brz,pn %g2, floppy_dosoftint + sethi %hi(fdc_status), %g3 + ldx [%g3 + %lo(fdc_status)], %g3 + sethi %hi(pdma_vaddr), %g5 + ldx [%g5 + %lo(pdma_vaddr)], %g4 + sethi %hi(pdma_size), %g5 + ldx [%g5 + %lo(pdma_size)], %g5 + +next_byte: + ldub [%g3], %g7 + andcc %g7, 0x80, %g0 + be,pn %icc, floppy_fifo_emptied + andcc %g7, 0x20, %g0 + be,pn %icc, floppy_overrun + andcc %g7, 0x40, %g0 + be,pn %icc, floppy_write + sub %g5, 1, %g5 + + ldub [%g3 + 1], %g7 + orcc %g0, %g5, %g0 + stb %g7, [%g4] + bne,pn %xcc, next_byte + add %g4, 1, %g4 + + b,pt %xcc, floppy_tdone + nop + +floppy_write: + ldub [%g4], %g7 + orcc %g0, %g5, %g0 + stb %g7, [%g3 + 1] + bne,pn %xcc, next_byte + add %g4, 1, %g4 + +floppy_tdone: + sethi %hi(pdma_vaddr), %g1 + stx %g4, [%g1 + %lo(pdma_vaddr)] + sethi %hi(pdma_size), %g1 + stx %g5, [%g1 + %lo(pdma_size)] + sethi %hi(auxio_register), %g1 + ldx [%g1 + %lo(auxio_register)], %g7 + ldub [%g7], %g5 + or %g5, 0xc2, %g5 + stb %g5, [%g7] + andn %g5, 0x02, %g5 + + nop; nop; nop; nop; nop; nop; + nop; nop; nop; nop; nop; nop; + + stb %g5, [%g7] + sethi %hi(doing_pdma), %g1 + b,pt %xcc, floppy_dosoftint + st %g0, [%g1 + %lo(doing_pdma)] + +floppy_fifo_emptied: + sethi %hi(pdma_vaddr), %g1 + stx %g4, [%g1 + %lo(pdma_vaddr)] + sethi %hi(pdma_size), %g1 + stx %g5, [%g1 + %lo(pdma_size)] + sethi %hi(irq_action), %g1 + or %g1, %lo(irq_action), %g1 + ldx [%g1 + (11 << 3)], %g3 ! irqaction[floppy_irq] + ldx [%g3 + 0x10], %g4 ! action->mask + st %g0, [%g4] ! SYSIO_ICLR_IDLE + membar #Sync ! probably not needed... + retry + +floppy_overrun: + sethi %hi(pdma_vaddr), %g1 + stx %g4, [%g1 + %lo(pdma_vaddr)] + sethi %hi(pdma_size), %g1 + stx %g5, [%g1 + %lo(pdma_size)] + sethi %hi(doing_pdma), %g1 + st %g0, [%g1 + %lo(doing_pdma)] + +floppy_dosoftint: + rdpr %pil, %g2 + wrpr %g0, 15, %pil + b,pt %xcc, etrap_irq + rd %pc, %g7 + + mov 11, %o0 + mov 0, %o1 + call sparc_floppy_irq + add %sp, STACK_BIAS + REGWIN_SZ, %o2 + + b,pt %xcc, rtrap + clr %l6 + +#endif /* CONFIG_BLK_DEV_FD */ + + /* XXX Here is stuff we still need to write... -DaveM XXX */ + .globl indirect_syscall, netbsd_syscall, solaris_syscall indirect_syscall: netbsd_syscall: solaris_syscall: @@ -436,16 +543,39 @@ ba,pt %xcc, rtrap clr %l6 - /* This is how fork() was meant to be done, 12 instruction entry. -DaveM */ - .globl sys_fork, sys_vfork, sys_clone, ret_from_syscall + /* This is how fork() was meant to be done, 12 instruction entry. + * + * I questioned the following code briefly, let me clear things + * up so you must not reason on it like I did. + * + * Know the fork_kpsr etc. we use in the sparc32 port? We don't + * need it here because the only piece of window state we copy to + * the child is the CWP register. Even if the parent sleeps, + * we are safe because we stuck it into pt_regs of the parent + * so it will not change. + * + * XXX This raises the question, whether we can do the same on + * XXX sparc32 to get rid of fork_kpsr _and_ fork_kwim. The + * XXX answer is yes. We stick fork_kpsr in UREG_G0 and + * XXX fork_kwim in UREG_G1 (global registers are considered + * XXX volatile across a system call in the sparc ABI I think + * XXX if it isn't we can use regs->y instead, anyone who depends + * XXX upon the Y register being preserved across a fork deserves + * XXX to lose). + * + * In fact we should take advantage of that fact for other things + * during system calls... + */ + .globl sys_fork, sys_vfork, sys_clone + .globl ret_from_syscall, ret_from_smpfork .align 32 sys_fork: sys_vfork: mov SIGCHLD, %o0 clr %o1 sys_clone: mov %o7, %l5 - save %sp, -REGWIN_SZ, %sp +/*???*/ save %sp, -REGWIN_SZ, %sp flushw - restore %g0, %g0, %g0 +/*???*/ restore %g0, %g0, %g0 rdpr %cwp, %o4 add %sp, STACK_BIAS + REGWIN_SZ, %o2 @@ -453,10 +583,15 @@ stx %o4, [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_G0] call do_fork mov %l5, %o7 -ret_from_syscall:b,pt %xcc, ret_sys_call - ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 - nop - nop +#ifdef __SMP__ +ret_from_smpfork: + sethi %hi(scheduler_lock), %o4 + membar #StoreStore | #LoadStore + stb %g0, [%o4 + %lo(scheduler_lock)] +#endif +ret_from_syscall: + b,pt %xcc, ret_sys_call + ldx [%sp + STACK_BIAS + REGWIN_SZ + PT_V9_I0], %o0 linux_syscall_trace: call syscall_trace diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/ioctl32.c linux/arch/sparc64/kernel/ioctl32.c --- v2.1.44/linux/arch/sparc64/kernel/ioctl32.c Thu Jun 26 12:33:38 1997 +++ linux/arch/sparc64/kernel/ioctl32.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: ioctl32.c,v 1.11 1997/06/16 11:05:00 jj Exp $ +/* $Id: ioctl32.c,v 1.13 1997/07/17 02:20:38 davem Exp $ * ioctl32.c: Conversion between 32bit and 64bit native ioctls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -485,8 +486,13 @@ int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(filp = current->files->fd[fd])) + if(fd >= NR_OPEN) goto out; + + filp = current->files->fd[fd]; + if(!filp) + goto out; + if (!filp->f_op || !filp->f_op->ioctl) { error = sys_ioctl (fd, cmd, (unsigned long)arg); goto out; @@ -612,6 +618,15 @@ case FIBMAP: case FIGETBSZ: + /* 0x02 -- Floppy ioctls */ + case FDSETEMSGTRESH: + case FDFLUSH: + case FDSETMAXERRS: + case FDGETMAXERRS: + case FDGETDRVTYP: + case FDEJECT: + /* XXX The rest need struct floppy_* translations. */ + /* 0x12 */ case BLKRRPART: case BLKFLSBUF: diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/irq.c linux/arch/sparc64/kernel/irq.c --- v2.1.44/linux/arch/sparc64/kernel/irq.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/irq.c Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: irq.c,v 1.14 1997/06/24 17:30:26 davem Exp $ +/* $Id: irq.c,v 1.16 1997/07/11 03:03:08 davem Exp $ * irq.c: UltraSparc IRQ handling/init/registry. * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -47,7 +47,8 @@ static struct irqaction static_irqaction[MAX_STATIC_ALLOC]; static int static_irq_count = 0; -static struct irqaction *irq_action[NR_IRQS+1] = { +/* XXX Must be exported so that fast IRQ handlers can get at it... -DaveM */ +struct irqaction *irq_action[NR_IRQS+1] = { NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL , NULL, NULL }; @@ -279,13 +280,13 @@ /* If this is flagged as statically allocated then we use our * private struct which is never freed. */ - if(irqflags & SA_STATIC_ALLOC) + if(irqflags & SA_STATIC_ALLOC) { if(static_irq_count < MAX_STATIC_ALLOC) action = &static_irqaction[static_irq_count++]; else printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " "using kmalloc\n", irq, name); - + } if(action == NULL) action = (struct irqaction *)kmalloc(sizeof(struct irqaction), GFP_KERNEL); @@ -464,14 +465,101 @@ } #endif -/* XXX This needs to be written for floppy driver, and soon will be necessary - * XXX for serial driver as well. +/* The following assumes that the branch lies before the place we + * are branching to. This is the case for a trap vector... + * You have been warned. */ +#define SPARC_BRANCH(dest_addr, inst_addr) \ + (0x10800000 | ((((dest_addr)-(inst_addr))>>2)&0x3fffff)) + +#define SPARC_NOP (0x01000000) + +static void install_fast_irq(unsigned int cpu_irq, + void (*handler)(int, void *, struct pt_regs *)) +{ + extern unsigned long sparc64_ttable_tl0; + unsigned long ttent = (unsigned long) &sparc64_ttable_tl0; + unsigned int *insns; + + ttent += 0x820; + ttent += (cpu_irq - 1) << 5; + insns = (unsigned int *) ttent; + insns[0] = SPARC_BRANCH(((unsigned long) handler), + ((unsigned long)&insns[0])); + insns[1] = SPARC_NOP; + __asm__ __volatile__("flush %0" : : "r" (ttent)); +} + int request_fast_irq(unsigned int irq, void (*handler)(int, void *, struct pt_regs *), unsigned long irqflags, const char *name) { - return -1; + struct irqaction *action; + unsigned long flags; + unsigned int cpu_irq, *imap, *iclr; + + /* XXX This really is not the way to do it, the "right way" + * XXX is to have drivers set SA_SBUS or something like that + * XXX in irqflags and we base our decision here on whether + * XXX that flag bit is set or not. + * + * In this case nobody can have a fast interrupt at the level + * where TICK interrupts live. + */ + if(irq == 14) + return -EINVAL; + cpu_irq = ino_to_pil[irq]; + + if(!handler) + return -EINVAL; + imap = irq_to_imap(irq); + action = *(cpu_irq + irq_action); + if(action) { + if(action->flags & SA_SHIRQ) + panic("Trying to register fast irq when already shared.\n"); + if(irqflags & SA_SHIRQ) + panic("Trying to register fast irq as shared.\n"); + printk("request_fast_irq: Trying to register yet already owned.\n"); + return -EBUSY; + } + save_and_cli(flags); + if(irqflags & SA_STATIC_ALLOC) { + if(static_irq_count < MAX_STATIC_ALLOC) + action = &static_irqaction[static_irq_count++]; + else + printk("Request for IRQ%d (%s) SA_STATIC_ALLOC failed " + "using kmalloc\n", irq, name); + } + if(action == NULL) + action = (struct irqaction *)kmalloc(sizeof(struct irqaction), + GFP_KERNEL); + if(!action) { + restore_flags(flags); + return -ENOMEM; + } + install_fast_irq(cpu_irq, handler); + + if(imap) { + int ivindex = (*imap & (SYSIO_IMAP_IGN | SYSIO_IMAP_INO)); + + ivector_to_mask[ivindex] = (1 << cpu_irq); + iclr = imap_to_iclr(imap); + action->mask = (unsigned long) iclr; + irqflags |= SA_SYSIO_MASKED; + } else + action->mask = 0; + + action->handler = handler; + action->flags = irqflags; + action->dev_id = NULL; + action->name = name; + action->next = NULL; + + *(cpu_irq + irq_action) = action; + + enable_irq(irq); + restore_flags(flags); + return 0; } /* We really don't need these at all on the Sparc. We only have @@ -496,27 +584,31 @@ /* XXX This doesn't belong here, just do this cruft in the timer.c handler code. */ static void timer_handler(int irq, void *dev_id, struct pt_regs *regs) { - extern void timer_interrupt(int, void *, struct pt_regs *); - unsigned long compare; - if (!(get_softint () & 1)) { /* Just to be sure... */ clear_softint(1 << 14); printk("Spurious level14 at %016lx\n", regs->tpc); return; - } + } else { + unsigned long compare, tick; - timer_interrupt(irq, dev_id, regs); + do { + extern void timer_interrupt(int, void *, struct pt_regs *); - /* Acknowledge INT_TIMER */ - clear_softint(1 << 0); + timer_interrupt(irq, dev_id, regs); - /* Set up for next timer tick. */ - __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" - "add %0, %1, %0\n\t" - "wr %0, 0x0, %%tick_cmpr" - : "=r" (compare) - : "r" (tick_offset)); + /* Acknowledge INT_TIMER */ + clear_softint(1 << 0); + + /* Set up for next timer tick. */ + __asm__ __volatile__("rd %%tick_cmpr, %0\n\t" + "add %0, %2, %0\n\t" + "wr %0, 0x0, %%tick_cmpr\n\t" + "rd %%tick, %1" + : "=&r" (compare), "=r" (tick) + : "r" (tick_offset)); + } while(tick >= compare); + } } /* This is called from time_init() to get the jiffies timer going. */ @@ -584,7 +676,7 @@ prom_timers = (struct sun5_timer *) 0; return; } - prom_timers = (struct sun5_timer *) addr[0]; + prom_timers = (struct sun5_timer *) ((unsigned long)addr[0]); } static void kill_prom_timer(void) diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/process.c linux/arch/sparc64/kernel/process.c --- v2.1.44/linux/arch/sparc64/kernel/process.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/process.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: process.c,v 1.26 1997/07/01 21:15:07 jj Exp $ +/* $Id: process.c,v 1.29 1997/07/17 02:20:40 davem Exp $ * arch/sparc64/kernel/process.c * * Copyright (C) 1995, 1996 David S. Miller (davem@caip.rutgers.edu) @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include #include @@ -263,9 +265,6 @@ void show_regs(struct pt_regs * regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif printk("TSTATE: %016lx TPC: %016lx TNPC: %016lx Y: %08x\n", regs->tstate, regs->tpc, regs->tnpc, regs->y); printk("g0: %016lx g1: %016lx g2: %016lx g3: %016lx\n", @@ -285,9 +284,6 @@ void show_regs32(struct pt_regs32 *regs) { -#if __MPP__ - printk("CID: %d\n",mpp_cid()); -#endif printk("PSR: %08x PC: %08x NPC: %08x Y: %08x\n", regs->psr, regs->pc, regs->npc, regs->y); printk("g0: %08x g1: %08x g2: %08x g3: %08x\n", @@ -365,26 +361,33 @@ __asm__ __volatile__("flush %g6"); } -static __inline__ struct sparc_stackf * -clone_stackframe(struct sparc_stackf *dst, struct sparc_stackf *src) +/* It's a bit more tricky when 64-bit tasks are involved... */ +static unsigned long clone_stackframe(unsigned long csp, unsigned long psp) { - struct sparc_stackf *sp; - -#if 0 - unsigned long size; - size = ((unsigned long)src->fp) - ((unsigned long)src); - sp = (struct sparc_stackf *)(((unsigned long)dst) - size); + unsigned long fp, distance, rval; - if (copy_to_user(sp, src, size)) + if(!(current->tss.flags & SPARC_FLAG_32BIT)) { + csp += STACK_BIAS; + psp += STACK_BIAS; + __get_user(fp, &(((struct reg_window *)psp)->ins[6])); + } else + __get_user(fp, &(((struct reg_window32 *)psp)->ins[6])); + distance = fp - psp; + rval = (csp - distance); + if(copy_in_user(rval, psp, distance)) return 0; - if (put_user(dst, &sp->fp)) - return 0; -#endif - return sp; + if(current->tss.flags & SPARC_FLAG_32BIT) { + if(put_user(((u32)csp), &(((struct reg_window32 *)rval)->ins[6]))) + return 0; + return rval; + } else { + if(put_user(((u64)csp - STACK_BIAS), + &(((struct reg_window *)rval)->ins[6]))) + return 0; + return rval - STACK_BIAS; + } } -/* #define DEBUG_WINFIXUPS */ - /* Standard stuff. */ static inline void shift_window_buffer(int first_win, int last_win, struct thread_struct *tp) @@ -408,9 +411,6 @@ int winsize = REGWIN_SZ; int bias = 0; -#ifdef DEBUG_WINFIXUPS - printk("sus(%d", (int)window); -#endif if(tp->flags & SPARC_FLAG_32BIT) winsize = REGWIN32_SZ; else @@ -426,9 +426,6 @@ tp->w_saved--; } } while(window--); -#ifdef DEBUG_WINFIXUPS - printk(")"); -#endif } } @@ -445,9 +442,6 @@ bias = STACK_BIAS; flush_user_windows(); window = tp->w_saved; -#ifdef DEBUG_WINFIXUPS - printk("fiuw(%d", (int)window); -#endif if(window != 0) { window -= 1; do { @@ -459,9 +453,6 @@ } while(window--); } current->tss.w_saved = 0; -#ifdef DEBUG_WINFIXUPS - printk(")"); -#endif } /* Copy a Sparc thread. The fork() return value conventions @@ -485,10 +476,6 @@ char *child_trap_frame; int tframe_size; -#if 0 /* Now all syscall entries flip off the fpu. */ - if(regs->tstate & TSTATE_PRIV) - regs->fprs = 0; -#endif /* Calculate offset to stack_frame & pt_regs */ stack_offset = (((PAGE_SIZE << 1) - ((sizeof(unsigned int)*64) + (2*sizeof(unsigned long)))) & @@ -512,23 +499,14 @@ p->tss.flags &= ~SPARC_FLAG_KTHREAD; p->tss.current_ds = USER_DS; p->tss.ctx = (p->mm->context & 0x1fff); -#if 0 if (sp != regs->u_regs[UREG_FP]) { - struct sparc_stackf *childstack; - struct sparc_stackf *parentstack; + unsigned long csp; - /* - * This is a clone() call with supplied user stack. - * Set some valid stack frames to give to the child. - */ - childstack = (struct sparc_stackf *)sp; - parentstack = (struct sparc_stackf *)regs->u_regs[UREG_FP]; - childstack = clone_stackframe(childstack, parentstack); - if (!childstack) + csp = clone_stackframe(sp, regs->u_regs[UREG_FP]); + if(!csp) return -EFAULT; - childregs->u_regs[UREG_FP] = (unsigned long)childstack; + p->tss.kregs->u_regs[UREG_FP] = csp; } -#endif } /* Set the return value for the child. */ @@ -592,9 +570,11 @@ if(regs->u_regs[UREG_G1] == 0) base = 1; - error = getname((char *) regs->u_regs[base + UREG_I0], &filename); - if(error) - return error; + lock_kernel(); + filename = getname((char *)regs->u_regs[base + UREG_I0]); + error = PTR_ERR(filename); + if(IS_ERR(filename)) + goto out; error = do_execve(filename, (char **) regs->u_regs[base + UREG_I1], (char **) regs->u_regs[base + UREG_I2], regs); putname(filename); @@ -602,5 +582,7 @@ fprs_write(0); regs->fprs = 0; } +out: + unlock_kernel(); return error; } diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/ptrace.c linux/arch/sparc64/kernel/ptrace.c --- v2.1.44/linux/arch/sparc64/kernel/ptrace.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/ptrace.c Wed Jul 16 19:22:50 1997 @@ -742,7 +742,7 @@ cregs->tstate |= psr_to_tstate_icc(psr); if(!((pc | npc) & 3)) { cregs->tpc = pc; - cregs->tpc = npc; + cregs->tnpc = npc; } cregs->y = y; for(i = 1; i < 16; i++) diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/setup.c linux/arch/sparc64/kernel/setup.c --- v2.1.44/linux/arch/sparc64/kernel/setup.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/setup.c Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: setup.c,v 1.9 1997/07/05 09:52:29 davem Exp $ +/* $Id: setup.c,v 1.10 1997/07/08 11:07:47 jj Exp $ * linux/arch/sparc64/kernel/setup.c * * Copyright (C) 1995,1996 David S. Miller (davem@caip.rutgers.edu) @@ -35,6 +35,7 @@ #include #include #include +#include struct screen_info screen_info = { 0, 0, /* orig-x, orig-y */ @@ -288,7 +289,7 @@ *memory_start_p = PAGE_ALIGN(((unsigned long) &end)); *memory_end_p = (end_of_phys_memory + PAGE_OFFSET); -#ifndef NO_DAVEM_DEBUGGING +#ifdef DAVEM_DEBUGGING prom_printf("phys_base[%016lx] memory_start[%016lx] memory_end[%016lx]\n", phys_base, *memory_start_p, *memory_end_p); #endif @@ -303,8 +304,11 @@ #endif #ifdef CONFIG_BLK_DEV_INITRD if (ramdisk_image) { - initrd_start = ramdisk_image; - if (initrd_start < PAGE_OFFSET) initrd_start += PAGE_OFFSET; + unsigned long start = 0; + + if (ramdisk_image >= (unsigned long)&end - 2 * PAGE_SIZE) + ramdisk_image -= KERNBASE; + initrd_start = ramdisk_image + phys_base + PAGE_OFFSET; initrd_end = initrd_start + ramdisk_size; if (initrd_end > *memory_end_p) { printk(KERN_CRIT "initrd extends beyond end of memory " @@ -312,9 +316,11 @@ initrd_end,*memory_end_p); initrd_start = 0; } - if (initrd_start >= *memory_start_p && initrd_start < *memory_start_p + 2 * PAGE_SIZE) { + if (initrd_start) + start = ramdisk_image + KERNBASE; + if (start >= *memory_start_p && start < *memory_start_p + 2 * PAGE_SIZE) { initrd_below_start_ok = 1; - *memory_start_p = PAGE_ALIGN (initrd_end); + *memory_start_p = PAGE_ALIGN (start + ramdisk_size); } } #endif diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/signal.c linux/arch/sparc64/kernel/signal.c --- v2.1.44/linux/arch/sparc64/kernel/signal.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/signal.c Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: signal.c,v 1.17 1997/07/05 09:52:31 davem Exp $ +/* $Id: signal.c,v 1.20 1997/07/14 03:10:28 davem Exp $ * arch/sparc64/kernel/signal.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -317,8 +317,6 @@ { struct new_signal_frame *sf; int sigframe_size; - unsigned long tmp; - int i; /* 1. Make sure everything is clean */ synchronize_user_stack(); @@ -329,16 +327,13 @@ sf = (struct new_signal_frame *) (regs->u_regs[UREG_FP] + STACK_BIAS - sigframe_size); - if (invalid_frame_pointer (sf, sigframe_size)) { - lock_kernel (); - do_exit(SIGILL); - } + if (invalid_frame_pointer (sf, sigframe_size)) + goto sigill; if (current->tss.w_saved != 0) { printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); - lock_kernel (); - do_exit (SIGILL); + goto sigill; } /* 2. Save the current process state */ @@ -352,10 +347,10 @@ } __put_user(oldmask, &sf->info.si_mask); - for (i = 0; i < sizeof(struct reg_window)/sizeof(u64); i++) { - __get_user(tmp, (((u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS))+i)); - __put_user(tmp, (((u64 *)sf)+i)); - } + + copy_in_user((u64 *)sf, + (u64 *)(regs->u_regs[UREG_FP]+STACK_BIAS), + sizeof(struct reg_window)); /* 3. return to kernel instructions */ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ @@ -388,6 +383,11 @@ : "memory"); } } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); } static inline void handle_signal(unsigned long signr, struct sigaction *sa, @@ -396,8 +396,11 @@ new_setup_frame(sa, regs, signr, oldmask); if(sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) + if(!(sa->sa_flags & SA_NOMASK)) { + spin_lock_irq(¤t->sigmask_lock); current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + } } static inline void syscall_restart(unsigned long orig_i0, struct pt_regs *regs, @@ -439,7 +442,11 @@ #endif while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); - clear_bit(signr + 32, ¤t->signal); + + spin_lock_irq(¤t->sigmask_lock); + current->signal &= ~(1 << signr); + spin_unlock_irq(¤t->sigmask_lock); + sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { @@ -453,7 +460,9 @@ if (signr == SIGSTOP) continue; if (_S(signr) & current->blocked) { + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr); + spin_unlock_irq(¤t->sigmask_lock); continue; } sa = current->sig->action + signr - 1; @@ -496,8 +505,10 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { + lock_kernel(); if(current->binfmt->core_dump(signr, regs)) signr |= 0x80; + unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ @@ -506,9 +517,15 @@ #endif /* fall through */ default: + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr & 0x7f); + spin_unlock_irq(¤t->sigmask_lock); + current->flags |= PF_SIGNALED; + + lock_kernel(); do_exit(signr); + unlock_kernel(); } } if(restart_syscall) diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/signal32.c linux/arch/sparc64/kernel/signal32.c --- v2.1.44/linux/arch/sparc64/kernel/signal32.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/signal32.c Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: signal32.c,v 1.23 1997/07/05 07:09:15 davem Exp $ +/* $Id: signal32.c,v 1.26 1997/07/14 03:10:31 davem Exp $ * arch/sparc64/kernel/signal32.c * * Copyright (C) 1991, 1992 Linus Torvalds @@ -245,7 +245,6 @@ #endif int old_status = current->tss.sstk_info.cur_status; unsigned psr; - int i; synchronize_user_stack(); regs->u_regs[UREG_FP] &= 0x00000000ffffffffUL; @@ -292,13 +291,9 @@ } else #endif - /* XXX Perhaps we need a copy_in_user()? -DaveM */ - for (i = 0; i < 16; i++) { - u32 temp; - - get_user (temp, (((u32 *)(regs->u_regs[UREG_FP]))+i)); - put_user (temp, (((u32 *)sframep)+i)); - } + copy_in_user((u32 *)sframep, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); current->tss.w_saved = 0; /* So process is allowed to execute. */ __put_user(signr, &sframep->sig_num); @@ -351,8 +346,7 @@ printk("new_setup_frame32(%s:%d): invalid_frame_pointer(%p, %d)\n", current->comm, current->pid, sf, sigframe_size); #endif - lock_kernel (); - do_exit(SIGILL); + goto sigill; } if (current->tss.w_saved != 0) { @@ -360,8 +354,7 @@ printk ("%s[%d]: Invalid user stack frame for " "signal delivery.\n", current->comm, current->pid); #endif - lock_kernel (); - do_exit (SIGILL); + goto sigill; } /* 2. Save the current process state */ @@ -384,13 +377,9 @@ __put_user(oldmask, &sf->info.si_mask); - /* XXX Perhaps we need a copy_in_user()? -DaveM */ - for (i = 0; i < sizeof(struct reg_window32)/4; i++) { - u32 tmp; - - __get_user(tmp, (((u32 *)regs->u_regs[UREG_FP])+i)); - __put_user(tmp, (((u32 *)sf)+i)); - } + copy_in_user((u32 *)sf, + (u32 *)(regs->u_regs[UREG_FP]), + sizeof(struct reg_window32)); /* 3. return to kernel instructions */ __put_user(0x821020d8, &sf->insns[0]); /* mov __NR_sigreturn, %g1 */ @@ -423,6 +412,11 @@ : "memory"); } } + return; + +sigill: + lock_kernel(); + do_exit(SIGILL); } /* Setup a Solaris stack frame */ @@ -614,16 +608,16 @@ if (tp->w_saved){ printk ("Uh oh, w_saved is: 0x%lx\n", tp->w_saved); - do_exit(SIGSEGV); + goto sigsegv; } if (((unsigned long) c) & 3){ printk ("Unaligned structure passed\n"); - do_exit (SIGSEGV); + goto sigsegv; } if(!__access_ok((unsigned long)c, sizeof(*c))) { /* Miguel, add nice debugging msg _here_. ;-) */ - do_exit(SIGSEGV); + goto sigsegv; } /* Check for valid PC and nPC */ @@ -632,7 +626,7 @@ __get_user(npc, &((*gr)[SVR4_NPC])); if((pc | npc) & 3) { printk ("setcontext, PC or nPC were bogus\n"); - do_exit (SIGSEGV); + goto sigsegv; } /* Retrieve information from passed ucontext */ /* note that nPC is ored a 1, this is used to inform entry.S */ @@ -655,6 +649,9 @@ __get_user(regs->u_regs[UREG_I0+i], (&(*gr)[SVR4_O0])+i); return -EINTR; +sigsegv: + lock_kernel(); + do_exit(SIGSEGV); } static inline void handle_signal32(unsigned long signr, struct sigaction *sa, @@ -671,8 +668,11 @@ } if(sa->sa_flags & SA_ONESHOT) sa->sa_handler = NULL; - if(!(sa->sa_flags & SA_NOMASK)) + if(!(sa->sa_flags & SA_NOMASK)) { + spin_lock_irq(¤t->sigmask_lock); current->blocked |= (sa->sa_mask | _S(signr)) & _BLOCKABLE; + spin_unlock_irq(¤t->sigmask_lock); + } } static inline void syscall_restart32(unsigned long orig_i0, struct pt_regs *regs, @@ -708,7 +708,11 @@ while ((signr = current->signal & mask) != 0) { signr = ffz(~signr); - clear_bit(signr + 32, ¤t->signal); + + spin_lock_irq(¤t->sigmask_lock); + current->signal &= ~(1 << signr); + spin_unlock_irq(¤t->sigmask_lock); + sa = current->sig->action + signr; signr++; if ((current->flags & PF_PTRACED) && signr != SIGKILL) { @@ -722,7 +726,9 @@ if (signr == SIGSTOP) continue; if (_S(signr) & current->blocked) { + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr); + spin_unlock_irq(¤t->sigmask_lock); continue; } sa = current->sig->action + signr - 1; @@ -765,8 +771,10 @@ case SIGQUIT: case SIGILL: case SIGTRAP: case SIGABRT: case SIGFPE: case SIGSEGV: case SIGBUS: if(current->binfmt && current->binfmt->core_dump) { + lock_kernel(); if(current->binfmt->core_dump(signr, regs)) signr |= 0x80; + unlock_kernel(); } #ifdef DEBUG_SIGNALS /* Very useful to debug dynamic linker problems */ @@ -775,9 +783,15 @@ #endif /* fall through */ default: + spin_lock_irq(¤t->sigmask_lock); current->signal |= _S(signr & 0x7f); + spin_unlock_irq(¤t->sigmask_lock); + current->flags |= PF_SIGNALED; + + lock_kernel(); do_exit(signr); + unlock_kernel(); } } if(restart_syscall) diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/smp.c linux/arch/sparc64/kernel/smp.c --- v2.1.44/linux/arch/sparc64/kernel/smp.c Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/kernel/smp.c Wed Jul 16 19:22:50 1997 @@ -0,0 +1,347 @@ +/* smp.c: Sparc64 SMP support. + * + * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) + */ + +#define __KERNEL_SYSCALLS__ +#include + +extern int linux_num_cpus; +extern void calibrate_delay(void); + +volatile int smp_processors_ready = 0; +unsigned long cpu_present_map = 0; +int smp_num_cpus = 1; +int smp_threads_ready = 0; + +struct cpuinfo_sparc64 cpu_data[NR_CPUS]; +static unsigned char boot_cpu_id = 0; +static int smp_activated = 0; + +volatile int cpu_number_map[NR_CPUS]; +volatile int cpu_logical_map[NR_CPUS]; + +struct klock_info klock_info = { KLOCK_CLEAR, 0 }; + +static volatile int smp_commenced = 0; + +void smp_setup(char *str, int *ints) +{ + /* XXX implement me XXX */ +} + +static char smp_buf[512]; + +char *smp_info(void) +{ + /* XXX not SMP safe and need to support up to 64 penguins */ + sprintf(smp_buf, +" CPU0\t\tCPU1\t\tCPU2\t\tCPU3\n" +"State: %s\t\t%s\t\t%s\t\t%s\n", +(cpu_present_map & 1) ? ((klock_info.akp == 0) ? "akp" : "online") : "offline", +(cpu_present_map & 2) ? ((klock_info.akp == 1) ? "akp" : "online") : "offline", +(cpu_present_map & 4) ? ((klock_info.akp == 2) ? "akp" : "online") : "offline", +(cpu_present_map & 8) ? ((klock_info.akp == 3) ? "akp" : "online") : "offline"); + return smp_buf; +} + +void smp_store_cpu_info(int id) +{ + cpu_data[id].udelay_val = loops_per_sec; +} + +void smp_commence(void) +{ + local_flush_cache_all(); + local_flush_tlb_all(); + smp_commenced = 1; + local_flush_cache_all(); + local_flush_tlb_all(); +} + +static void smp_setup_percpu_timer(void); + +static volatile unsigned long callin_flag = 0; + +void smp_callin(void) +{ + int cpuid = hard_smp_processor_id(); + + local_flush_cache_all(); + local_flush_tlb_all(); + + smp_setup_percpu_timer(); + + calibrate_delay(); + smp_store_cpu_info(cpuid); + callin_flag = 1; + __asm__ __volatile__("membar #Sync\n\t" + "flush %g6" : : : "memory"); + + while(!task[cpuid]) + barrier(); + current = task[cpuid]; + + while(!smp_commenced) + barrier(); + + __sti(); +} + +extern int cpu_idle(void *unused); +extern void init_IRQ(void); + +void initialize_secondary(void) +{ +} + +int start_secondary(void *unused) +{ + trap_init(); + init_IRQ(); + smp_callin(); + return cpu_idle(NULL); +} + +extern struct prom_cpuinfo linux_cpus[NR_CPUS]; + +void smp_boot_cpus(void) +{ + int cpucount = 0, i, first, prev; + + printk("Entering UltraSMPenguin Mode...\n"); + __sti(); + cpu_present_map = 0; + for(i = 0; i < linux_num_cpus; i++) + cpu_present_map |= (1 << i); + for(i = 0; i < NR_CPUS; i++) { + cpu_number_map[i] = -1; + cpu_logical_map[i] = -1; + } + cpu_number_map[boot_cpu_id] = 0; + cpu_logical_map[0] = boot_cpu_id; + klock_info.akp = boot_cpu_id; + current->processor = boot_cpu_id; + smp_store_cpu_info(boot_cpu_id); + smp_setup_percpu_timer(); + + if(linux_num_cpus == 1) + return; + + for(i = 0; i < NR_CPUS; i++) { + if(i == boot_cpu_id) + continue; + + if(cpu_present_map & (1 << i)) { + extern unsigned long sparc64_cpu_startup; + unsigned long entry = (unsigned long)&sparc_cpu_startup; + struct task_struct *p; + int timeout; + + kernel_thread(start_secondary, NULL, CLONE_PID); + p = task[++cpucount]; + p->processor = i; + prom_startcpu(linux_cpus[i].prom_node, entry, i); + for(timeout = 0; timeout < 5000000; timeout++) { + if(cpu_callin_map[i]) + break; + udelay(100); + } + if(cpu_callin_map[i]) { + /* XXX fix this */ + cpu_number_map[i] = i; + cpu_logical_map[i] = i; + } else { + cpucount--; + printk("Processor %d is stuck.\n", i); + } + } + if(!(cpu_callin_map[i])) { + cpu_present_map &= ~(1 << i); + cpu_number_map[i] = -1; + } + } + if(cpucount == 0) { + printk("Error: only one processor found.\n"); + cpu_present_map = (1 << smp_processor_id()); + } else { + unsigned long bogosum = 0; + + for(i = 0; i < NR_CPUS; i++) { + if(cpu_present_map & (1 << i)) + bogosum += cpu_data[i].udelay_val; + } + printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n", + cpucount + 1, + (bogosum + 2500)/500000, + ((bogosum + 2500)/5000)%100); + smp_activated = 1; + smp_num_cpus = cpucount + 1; + } + smp_processors_ready = 1; +} + +/* XXX deprecated interface... */ +void smp_message_pass(int target, int msg, unsigned long data, int wait) +{ + printk("smp_message_pass() called, this is bad, spinning.\n"); + __sti(); + while(1) + barrier(); +} + +/* XXX Make it fast later. */ +void smp_cross_call(unsigned long *func, u32 ctx, u64 data1, u64 data2) +{ + if(smp_processors_ready) { + unsigned long mask; + u64 data0 = (((unsigned long)ctx)<<32 | + (((unsigned long)func) & 0xffffffff)); + u64 pstate; + int i, ncpus = smp_num_cpus; + + __asm__ __volatile__("rdpr %%pstate, %0" : "=r" (pstate)); + mask = (cpu_present_map & ~(1 << smp_processor_id())); + for(i = 0; i < ncpus; i++) { + if(mask & (1 << i)) { + u64 target = mid<<14 | 0x70; + u64 result; + + __asm__ __volatile__(" + wrpr %0, %1, %%pstate + wrpr %%g0, %2, %%asi + stxa %3, [0x40] %%asi + stxa %4, [0x50] %%asi + stxa %5, [0x60] %%asi + stxa %%g0, [%6] %7 + membar #Sync" + : /* No outputs */ + : "r" (pstate), "i" (PSTATE_IE), "i" (ASI_UDB_INTR_W), + "r" (data0), "r" (data1), "r" (data2), + "r" (target), "i" (ASI_UDB_INTR_W)); + + /* NOTE: PSTATE_IE is still clear. */ + do { + __asm__ __volatile__("ldxa [%%g0] %1, %0", + : "=r" (result) + : "i" (ASI_INTR_DISPATCH_STAT)); + } while(result & 0x1); + __asm__ __volatile__("wrpr %0, 0x0, %%pstate" + : : "r" (pstate)); + if(result & 0x2) + panic("Penguin NACK's master!"); + } + } + + /* NOTE: Caller runs local copy on master. */ + } +} + +extern unsigned long xcall_flush_tlb_page; +extern unsigned long xcall_flush_tlb_mm; +extern unsigned long xcall_flush_tlb_range; +extern unsigned long xcall_flush_tlb_all; +extern unsigned long xcall_flush_cache_all; + +void smp_flush_cache_all(void) +{ + smp_cross_call(&xcall_flush_cache_all, 0, 0, 0); +} + +void smp_flush_tlb_all(void) +{ + smp_cross_call(&xcall_flush_tlb_all, 0, 0, 0); +} + +void smp_flush_tlb_mm(struct mm_struct *mm) +{ + u32 ctx = mm->context & 0x1fff; + if(mm->cpu_vm_mask != (1 << smp_processor_id())) + smp_cross_call(&xcall_flush_tlb_mm, ctx, 0, 0); + __flush_tlb_mm(ctx); +} + +void smp_flush_tlb_range(struct mm_struct *mm, unsigned long start, + unsigned long end) +{ + u32 ctx = mm->context & 0x1fff; + if(mm->cpu_vm_mask != (1 << smp_processor_id())) + smp_cross_call(&xcall_flush_tlb_range, ctx, start, end); + __flush_tlb_range(ctx, start, end); +} + +void smp_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) +{ + struct mm_struct *mm = vma->vm_mm; + u32 ctx = mm->context & 0x1fff; + + if(mm->cpu_vm_mask != (1 << smp_processor_id())) + smp_cross_call(&xcall_flush_tlb_page, ctx, page, 0); + __flush_tlb_page(ctx, page); +} + +static spinlock_t ticker_lock = SPIN_LOCK_UNLOCKED; + +static inline void sparc64_do_profile(unsigned long pc) +{ + if(prof_buffer && current->pid) { + extern int _stext; + + pc -= (unsigned long) &_stext; + pc >>= prof_shift; + + spin_lock(&ticker_lock); + if(pc < prof_len) + prof_buffer[pc]++; + else + prof_buffer[prof_len - 1]++; + spin_unlock(&ticker_lock); + } +} + +unsigned int prof_multiplier[NR_CPUS]; +unsigned int prof_counter[NR_CPUS]; + +extern void update_one_process(struct task_struct *p, unsigned long ticks, + unsigned long user, unsigned long system); + +void smp_percpu_timer_interrupt(struct pt_regs *regs) +{ + int cpu = smp_processor_id(); + + clear_profile_irq(cpu); + if(!user_mode(regs)) + sparc_do_profile(regs->pc); + if(!--prof_counter[cpu]) { + int user = user_mode(regs); + if(current->pid) { + update_one_process(current, 1, user, !user); + if(--current->counter < 0) { + current->counter = 0; + need_resched = 1; + } + + spin_lock(&ticker_lock); + if(user) { + if(current->priority < DEF_PRIORITY) + kstat.cpu_nice++; + else + kstat.cpu_user++; + } else { + kstat.cpu_system++; + } + spin_unlock(&ticker_lock); + } + prof_counter[cpu] = prof_multiplier[cpu]; + } +} + +static void smp_setup_percpu_timer(void) +{ + /* XXX implement me */ +} + +int setup_profiling_timer(unsigned int multiplier) +{ + /* XXX implement me */ +} diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sparc64_ksyms.c linux/arch/sparc64/kernel/sparc64_ksyms.c --- v2.1.44/linux/arch/sparc64/kernel/sparc64_ksyms.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/sparc64_ksyms.c Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: sparc64_ksyms.c,v 1.8 1997/07/07 04:58:14 davem Exp $ +/* $Id: sparc64_ksyms.c,v 1.11 1997/07/14 23:58:20 davem Exp $ * arch/sparc64/kernel/sparc64_ksyms.c: Sparc64 specific ksyms support. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include #include @@ -79,20 +81,12 @@ EXPORT_SYMBOL(request_fast_irq); EXPORT_SYMBOL(sparc_alloc_io); EXPORT_SYMBOL(sparc_free_io); -#if 0 -EXPORT_SYMBOL(io_remap_page_range); -EXPORT_SYMBOL(mmu_unlockarea); -EXPORT_SYMBOL(mmu_lockarea); +EXPORT_SYMBOL(local_irq_count); +EXPORT_SYMBOL(__sparc64_bh_counter); +EXPORT_SYMBOL(sparc_ultra_unmapioaddr); EXPORT_SYMBOL(mmu_get_scsi_sgl); EXPORT_SYMBOL(mmu_get_scsi_one); -EXPORT_SYMBOL(mmu_release_scsi_sgl); -EXPORT_SYMBOL(mmu_release_scsi_one); -#endif EXPORT_SYMBOL(sparc_dvma_malloc); -#if 0 -EXPORT_SYMBOL(sun4c_unmapioaddr); -EXPORT_SYMBOL(srmmu_unmapioaddr); -#endif #if CONFIG_SBUS EXPORT_SYMBOL(SBus_chain); EXPORT_SYMBOL(dma_chain); diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sunos_ioctl32.c linux/arch/sparc64/kernel/sunos_ioctl32.c --- v2.1.44/linux/arch/sparc64/kernel/sunos_ioctl32.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/sunos_ioctl32.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: sunos_ioctl32.c,v 1.2 1997/07/05 07:09:16 davem Exp $ +/* $Id: sunos_ioctl32.c,v 1.4 1997/07/17 02:20:43 davem Exp $ * sunos_ioctl32.c: SunOS ioctl compatability on sparc64. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -86,14 +86,19 @@ extern asmlinkage int sys32_ioctl(unsigned int, unsigned int, u32); extern asmlinkage int sys_setsid(void); -asmlinkage int sunos_ioctl (int fd, unsigned long cmd, u32 arg) +asmlinkage int sunos_ioctl (int fd, u32 cmd, u32 arg) { struct file *filp; int ret = -EBADF; lock_kernel(); - if(fd >= SUNOS_NR_OPEN || !(filp = current->files->fd[fd])) + if(fd >= SUNOS_NR_OPEN) goto out; + + filp = current->files->fd[fd]; + if(!filp) + goto out; + if(cmd == TIOCSETD) { unsigned long old_fs = get_fs(); int *p, ntty = N_TTY; diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sys_sparc32.c linux/arch/sparc64/kernel/sys_sparc32.c --- v2.1.44/linux/arch/sparc64/kernel/sys_sparc32.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/sys_sparc32.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: sys_sparc32.c,v 1.42 1997/07/05 09:52:36 davem Exp $ +/* $Id: sys_sparc32.c,v 1.43 1997/07/17 02:20:45 davem Exp $ * sys_sparc32.c: Conversion between 32bit and 64bit native syscalls. * * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -759,14 +759,29 @@ asmlinkage long sys32_readv(int fd, u32 vector, u32 count) { struct file *file; + struct dentry *dentry; struct inode *inode; long err = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + if(fd >= NR_OPEN) goto out; - if (!(file->f_mode & 1)) + + file = current->files->fd[fd]; + if(!file) + goto out; + + if(!(file->f_mode & 1)) + goto out; + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) goto out; + err = do_readv_writev32(VERIFY_WRITE, inode, file, (struct iovec32 *)A(vector), count); out: @@ -778,13 +793,28 @@ { int error = -EBADF; struct file *file; + struct dentry *dentry; struct inode *inode; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd]) || !(inode=file->f_inode)) + if(fd >= NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + if(!(file->f_mode & 2)) + goto out; + + dentry = file->f_dentry; + if(!dentry) goto out; - if (!(file->f_mode & 2)) + + inode = dentry->d_inode; + if(!inode) goto out; + down(&inode->i_sem); error = do_readv_writev32(VERIFY_READ, inode, file, (struct iovec32 *)A(vector), count); @@ -833,21 +863,34 @@ { int error = -EBADF; struct file * file; + struct dentry * dentry; + struct inode * inode; struct readdir_callback32 buf; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= NR_OPEN) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) + + file = current->files->fd[fd]; + if(!file) goto out; - error = verify_area(VERIFY_WRITE, (void *)A(dirent), - sizeof(struct old_linux_dirent32)); - if (error) + + dentry = file->f_dentry; + if(!dentry) goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + buf.count = 0; buf.dirent = (struct old_linux_dirent32 *)A(dirent); - error = file->f_op->readdir(file->f_inode, file, &buf, fillonedir); + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = file->f_op->readdir(inode, file, &buf, fillonedir); if (error < 0) goto out; error = buf.count; @@ -897,30 +940,43 @@ asmlinkage int sys32_getdents(unsigned int fd, u32 dirent, unsigned int count) { struct file * file; + struct dentry * dentry; + struct inode *inode; struct linux_dirent32 * lastdirent; struct getdents_callback32 buf; int error = -EBADF; lock_kernel(); - if (fd >= NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= NR_OPEN) goto out; - error = -ENOTDIR; - if (!file->f_op || !file->f_op->readdir) + + file = current->files->fd[fd]; + if(!file) goto out; - error = verify_area(VERIFY_WRITE, (void *)A(dirent), count); - if (error) + + dentry = file->f_dentry; + if(!dentry) goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + buf.current_dir = (struct linux_dirent32 *) A(dirent); buf.previous = NULL; buf.count = count; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, filldir); + + error = -ENOTDIR; + if (!file->f_op || !file->f_op->readdir) + goto out; + + error = file->f_op->readdir(inode, file, &buf, filldir); if (error < 0) goto out; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - } else { + error = buf.error; + if(lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = count - buf.count; } @@ -1725,11 +1781,11 @@ return NULL; } - inode = file->f_inode; + inode = file->f_dentry->d_inode; if (!inode || !inode->i_sock || !socki_lookup(inode)) { *err = -ENOTSOCK; - fput(file,inode); + fput(file); return NULL; } @@ -1738,7 +1794,7 @@ extern __inline__ void sockfd_put(struct socket *sock) { - fput(sock->file,sock->inode); + fput(sock->file); } struct msghdr32 { @@ -2168,25 +2224,33 @@ do_execve32(char * filename, u32 * argv, u32 * envp, struct pt_regs * regs) { struct linux_binprm bprm; + struct dentry * dentry; int retval; int i; bprm.p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); for (i=0 ; iu_regs[UREG_G1] == 0) base = 1; - error = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0], &filename); - if(error) - return error; + lock_kernel(); + filename = getname((char *)(unsigned long)(u32)regs->u_regs[base + UREG_I0]); + error = PTR_ERR(filename); + if(IS_ERR(filename)) + goto out; error = do_execve32(filename, (u32 *)A((u32)regs->u_regs[base + UREG_I1]), (u32 *)A((u32)regs->u_regs[base + UREG_I2]), regs); putname(filename); + if(!error) { fprs_write(0); regs->fprs = 0; } +out: + unlock_kernel(); return error; } diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/sys_sunos32.c linux/arch/sparc64/kernel/sys_sunos32.c --- v2.1.44/linux/arch/sparc64/kernel/sys_sunos32.c Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/sys_sunos32.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: sys_sunos32.c,v 1.2 1997/07/05 07:09:16 davem Exp $ +/* $Id: sys_sunos32.c,v 1.3 1997/07/17 02:20:48 davem Exp $ * sys_sunos32.c: SunOS binary compatability layer on sparc64. * * Copyright (C) 1995, 1996, 1997 David S. Miller (davem@caip.rutgers.edu) @@ -80,10 +80,12 @@ goto out; addr = (u32) attempt; } - if(MAJOR(file->f_inode->i_rdev) == MEM_MAJOR && - MINOR(file->f_inode->i_rdev) == 5) { - flags |= MAP_ANONYMOUS; - file = 0; + if(file->f_dentry && file->f_dentry->d_inode) { + if(MAJOR(file->f_dentry->d_inode->i_rdev) == MEM_MAJOR && + MINOR(file->f_dentry->d_inode->i_rdev) == 5) { + flags |= MAP_ANONYMOUS; + file = 0; + } } if(!(flags & MAP_FIXED)) addr = 0; @@ -377,17 +379,33 @@ asmlinkage int sunos_getdents(unsigned int fd, u32 u_dirent, int cnt) { struct file * file; + struct dentry * dentry; + struct inode * inode; struct sunos_dirent * lastdirent; struct sunos_dirent_callback buf; int error = -EBADF; void *dirent = (void *)A(u_dirent); lock_kernel(); - if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= SUNOS_NR_OPEN) goto out; + + file = current->files->fd[fd]; + if(!file) + goto out; + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; + error = -EINVAL; if(cnt < (sizeof(struct sunos_dirent) + 255)) goto out; @@ -396,13 +414,13 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldir); + + error = file->f_op->readdir(inode, file, &buf, sunos_filldir); if (error < 0) goto out; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - } else { + error = buf.error; + if (lastdirent) { put_user(file->f_pos, &lastdirent->d_off); error = cnt - buf.count; } @@ -454,6 +472,8 @@ int cnt, u32 u_basep) { struct file * file; + struct dentry * dentry; + struct inode * inode; struct sunos_direntry * lastdirent; struct sunos_direntry_callback buf; int error = -EBADF; @@ -461,11 +481,25 @@ unsigned int *basep = (unsigned int *)A(u_basep); lock_kernel(); - if (fd >= SUNOS_NR_OPEN || !(file = current->files->fd[fd])) + if(fd >= SUNOS_NR_OPEN) + goto out; + + file = current->files->fd[fd]; + if(!file) goto out; + + dentry = file->f_dentry; + if(!dentry) + goto out; + + inode = dentry->d_inode; + if(!inode) + goto out; + error = -ENOTDIR; if (!file->f_op || !file->f_op->readdir) goto out; + error = -EINVAL; if(cnt < (sizeof(struct sunos_direntry) + 255)) goto out; @@ -474,13 +508,13 @@ buf.previous = NULL; buf.count = cnt; buf.error = 0; - error = file->f_op->readdir(file->f_inode, file, &buf, sunos_filldirentry); + + error = file->f_op->readdir(inode, file, &buf, sunos_filldirentry); if (error < 0) goto out; lastdirent = buf.previous; - if (!lastdirent) { - error = buf.error; - } else { + error = buf.error; + if (lastdirent) { put_user(file->f_pos, basep); error = cnt - buf.count; } @@ -684,12 +718,20 @@ int try_port; int ret; struct socket *socket; + struct dentry *dentry; struct inode *inode; struct file *file; file = current->files->fd [fd]; - inode = file->f_inode; - if (!inode || !inode->i_sock) + if(!file) + return 0; + + dentry = file->f_dentry; + if(!dentry) + return 0; + + inode = dentry->d_inode; + if(!inode) return 0; socket = &inode->u.socket_i; @@ -770,7 +812,8 @@ linux_nfs_mount.acdirmin = sunos_mount->acdirmin; linux_nfs_mount.acdirmax = sunos_mount->acdirmax; - if (getname (sunos_mount->hostname, &the_name)) + the_name = getname(sunos_mount->hostname); + if(IS_ERR(the_name)) return -EFAULT; strncpy (linux_nfs_mount.hostname, the_name, 254); diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/kernel/winfixup.S linux/arch/sparc64/kernel/winfixup.S --- v2.1.44/linux/arch/sparc64/kernel/winfixup.S Mon Jul 7 08:18:54 1997 +++ linux/arch/sparc64/kernel/winfixup.S Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: winfixup.S,v 1.15 1997/07/04 01:41:07 davem Exp $ +/* $Id: winfixup.S,v 1.16 1997/07/13 20:02:42 davem Exp $ * * winfixup.S: Handle cases where user stack pointer is found to be bogus. * @@ -68,7 +68,7 @@ mov %g5, %l5 ! Fault address clr %l4 ! It was a load, not a store wrpr %g0, 0x0, %tl ! Out of trap levels. - wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate sethi %uhi(PAGE_OFFSET), %g4 ! Prepare page_offset global reg mov %o7, %g6 b,pt %xcc, window_scheisse_merge ! And merge. @@ -186,7 +186,7 @@ mov %g5, %o4 ! final call to do_sparc64_fault. mov %g6, %o7 ! Stash away current. wrpr %g0, 0x0, %tl ! Out of trap levels. - wrpr %l1, (PSTATE_IE | PSTATE_AG), %pstate + wrpr %l1, (PSTATE_IE | PSTATE_AG | PSTATE_RMO), %pstate sethi %uhi(PAGE_OFFSET), %g4 ! Set page_offset global reg. mov %o7, %g6 ! Get current back. b,pt %xcc, window_mna_merge ! And merge. diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/Makefile linux/arch/sparc64/lib/Makefile --- v2.1.44/linux/arch/sparc64/lib/Makefile Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/lib/Makefile Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -# $Id: Makefile,v 1.12 1997/06/25 10:12:18 jj Exp $ +# $Id: Makefile,v 1.13 1997/07/16 10:12:03 jj Exp $ # Makefile for Sparc library files.. # @@ -6,7 +6,7 @@ OBJS = blockops.o locks.o strlen.o strncmp.o \ memscan.o strncpy_from_user.o strlen_user.o memcmp.o checksum.o \ - VIScopy.o VISbzero.o VISmemset.o + VIScopy.o VISbzero.o VISmemset.o VIScsum.o lib.a: $(OBJS) $(AR) rcs lib.a $(OBJS) diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/VIScopy.S linux/arch/sparc64/lib/VIScopy.S --- v2.1.44/linux/arch/sparc64/lib/VIScopy.S Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/lib/VIScopy.S Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: VIScopy.S,v 1.8 1997/06/28 17:21:22 jj Exp $ +/* $Id: VIScopy.S,v 1.9 1997/07/13 18:23:39 davem Exp $ * VIScopy.S: High speed copy operations utilizing the UltraSparc * Visual Instruction Set. * @@ -315,6 +315,14 @@ .globl __copy_to_user .type __copy_to_user,@function __copy_to_user: mov ASI_BLK_P, asi_src ! IEU0 Group + brnz,pt %o2, __memcpy_entry ! CTI + mov ASI_BLK_S, asi_dest ! IEU1 + retl ! CTI Group + clr %o0 ! IEU0 Group + + .globl __copy_in_user + .type __copy_in_user,@function +__copy_in_user: mov ASI_BLK_S, asi_src ! IEU0 Group brnz,pt %o2, __memcpy_entry ! CTI mov ASI_BLK_S, asi_dest ! IEU1 retl ! CTI Group diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/VIScsum.S linux/arch/sparc64/lib/VIScsum.S --- v2.1.44/linux/arch/sparc64/lib/VIScsum.S Wed Dec 31 16:00:00 1969 +++ linux/arch/sparc64/lib/VIScsum.S Wed Jul 16 20:37:21 1997 @@ -0,0 +1,436 @@ +/* $Id: VIScsum.S,v 1.1 1997/07/16 10:12:02 jj Exp $ + * VIScsum.S: High bandwidth IP checksumming utilizing the UltraSparc + * Visual Instruction Set. + * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * + * Based on older sparc32/sparc64 checksum.S, which is: + * + * Copyright(C) 1995 Linus Torvalds + * Copyright(C) 1995 Miguel de Icaza + * Copyright(C) 1996,1997 David S. Miller + * derived from: + * Linux/Alpha checksum c-code + * Linux/ix86 inline checksum assembly + * RFC1071 Computing the Internet Checksum (esp. Jacobsons m68k code) + * David Mosberger-Tang for optimized reference c-code + * BSD4.4 portable checksum routine + */ + +#ifdef __sparc_v9__ +#define STACKOFF 2175 +#else +#define STACKOFF 64 +#endif + +#ifdef __KERNEL__ +#include +#include +#else +#define ASI_BLK_P 0xf0 +#define FRPS_FEF 0x04 +#endif + +/* Dobrou noc, SunSoft engineers. Spete sladce. + * This has a couple of tricks in and those + * tricks are UltraLinux trade secrets :)) + */ + +#define START_THE_TRICK(fz,f0,f2,f4,f6,f8,f10) \ + fcmpgt32 %fz, %f0, %g1 /* FPM Group */; \ + fcmpgt32 %fz, %f2, %g2 /* FPM Group */; \ + fcmpgt32 %fz, %f4, %g3 /* FPM Group */; \ + fcmpgt32 %fz, %f6, %g5 /* FPM Group */; \ + inc %g1 /* IEU0 */; \ + fcmpgt32 %fz, %f8, %g7 /* FPM Group */; \ + srl %g1, 1, %g1 /* IEU0 */; \ + inc %g2 /* IEU1 */; \ + fcmpgt32 %fz, %f10, %o3 /* FPM Group */; \ + srl %g2, 1, %g2 /* IEU0 */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + add %g3, 1, %g3 /* IEU0 Group */; \ + srl %g3, 1, %g3 /* IEU0 Group */; \ + add %o2, %g2, %o2 /* IEU1 */; \ + inc %g5 /* IEU0 Group */; \ + add %o2, %g3, %o2 /* IEU1 */; + +#define DO_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,F0,F2,F4,F6,F8,F10,F12,F14) \ + fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \ + srl %g5, 1, %g5 /* IEU0 */; \ + inc %g7 /* IEU1 */; \ + fpadd32 %F0, %f0, %F0 /* FPA */; \ + fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \ + srl %g7, 1, %g7 /* IEU0 */; \ + add %o2, %g5, %o2 /* IEU1 */; \ + fpadd32 %F2, %f2, %F2 /* FPA */; \ + inc %o3 /* IEU0 Group */; \ + add %o2, %g7, %o2 /* IEU1 */; \ + fcmpgt32 %f0, %F0, %g1 /* FPM Group */; \ + srl %o3, 1, %o3 /* IEU0 */; \ + inc %o4 /* IEU1 */; \ + fpadd32 %F4, %f4, %F4 /* FPA */; \ + fcmpgt32 %f2, %F2, %g2 /* FPM Group */; \ + srl %o4, 1, %o4 /* IEU0 */; \ + add %o2, %o3, %o2 /* IEU1 */; \ + fpadd32 %F6, %f6, %F6 /* FPA */; \ + inc %o5 /* IEU0 Group */; \ + add %o2, %o4, %o2 /* IEU1 */; \ + fcmpgt32 %f4, %F4, %g3 /* FPM Group */; \ + srl %o5, 1, %o5 /* IEU0 */; \ + inc %g1 /* IEU1 */; \ + fpadd32 %F8, %f8, %F8 /* FPA */; \ + fcmpgt32 %f6, %F6, %g5 /* FPM Group */; \ + srl %g1, 1, %g1 /* IEU0 */; \ + add %o2, %o5, %o2 /* IEU1 */; \ + fpadd32 %F10, %f10, %F10 /* FPA */; \ + inc %g2 /* IEU0 Group */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + fcmpgt32 %f8, %F8, %g7 /* FPM Group */; \ + srl %g2, 1, %g2 /* IEU0 */; \ + inc %g3 /* IEU1 */; \ + fpadd32 %F12, %f12, %F12 /* FPA */; \ + fcmpgt32 %f10, %F10, %o3 /* FPM Group */; \ + srl %g3, 1, %g3 /* IEU0 */; \ + add %o2, %g2, %o2 /* IEU1 */; \ + fpadd32 %F14, %f14, %F14 /* FPA */; \ + inc %g5 /* IEU0 Group */; \ + add %o2, %g3, %o2 /* IEU1 */; + +#define END_THE_TRICK(O12,O14,f0,f2,f4,f6,f8,f10,f12,f14,S0,S1,S2,S3,T0,T1,U0,fz) \ + fcmpgt32 %O12, %f12, %o4 /* FPM Group */; \ + srl %g5, 1, %g5 /* IEU0 */; \ + inc %g7 /* IEU1 */; \ + fpadd32 %f2, %f0, %S0 /* FPA */; \ + fcmpgt32 %O14, %f14, %o5 /* FPM Group */; \ + srl %g7, 1, %g7 /* IEU0 */; \ + add %o2, %g5, %o2 /* IEU1 */; \ + fpadd32 %f6, %f4, %S1 /* FPA */; \ + inc %o3 /* IEU0 Group */; \ + add %o2, %g7, %o2 /* IEU1 */; \ + fcmpgt32 %f0, %S0, %g1 /* FPM Group */; \ + srl %o3, 1, %o3 /* IEU0 */; \ + inc %o4 /* IEU1 */; \ + fpadd32 %f10, %f8, %S2 /* FPA */; \ + fcmpgt32 %f4, %S1, %g2 /* FPM Group */; \ + srl %o4, 1, %o4 /* IEU0 */; \ + add %o2, %o3, %o2 /* IEU1 */; \ + fpadd32 %f14, %f12, %S3 /* FPA */; \ + inc %o5 /* IEU0 Group */; \ + add %o2, %o4, %o2 /* IEU1 */; \ + fzero %fz /* FPA */; \ + fcmpgt32 %f8, %S2, %g3 /* FPM Group */; \ + srl %o5, 1, %o5 /* IEU0 */; \ + inc %g1 /* IEU1 */; \ + fpadd32 %S0, %S1, %T0 /* FPA */; \ + fcmpgt32 %f12, %S3, %g5 /* FPM Group */; \ + srl %g1, 1, %g1 /* IEU0 */; \ + add %o2, %o5, %o2 /* IEU1 */; \ + fpadd32 %S2, %S3, %T1 /* FPA */; \ + inc %g2 /* IEU0 Group */; \ + add %o2, %g1, %o2 /* IEU1 */; \ + fcmpgt32 %S0, %T0, %g7 /* FPM Group */; \ + srl %g2, 1, %g2 /* IEU0 */; \ + inc %g3 /* IEU1 */; \ + fcmpgt32 %S2, %T1, %o3 /* FPM Group */; \ + srl %g3, 1, %g3 /* IEU0 */; \ + add %o2, %g2, %o2 /* IEU1 */; \ + inc %g5 /* IEU0 Group */; \ + add %o2, %g3, %o2 /* IEU1 */; \ + fcmpgt32 %fz, %f2, %o4 /* FPM Group */; \ + srl %g5, 1, %g5 /* IEU0 */; \ + inc %g7 /* IEU1 */; \ + fpadd32 %T0, %T1, %U0 /* FPA */; \ + fcmpgt32 %fz, %f6, %o5 /* FPM Group */; \ + srl %g7, 1, %g7 /* IEU0 */; \ + add %o2, %g5, %o2 /* IEU1 */; \ + inc %o3 /* IEU0 Group */; \ + add %o2, %g7, %o2 /* IEU1 */; \ + fcmpgt32 %fz, %f10, %g1 /* FPM Group */; \ + srl %o3, 1, %o3 /* IEU0 */; \ + inc %o4 /* IEU1 */; \ + fcmpgt32 %fz, %f14, %g2 /* FPM Group */; \ + srl %o4, 1, %o4 /* IEU0 */; \ + add %o2, %o3, %o2 /* IEU1 */; \ + std %U0, [%sp + STACKOFF] /* Store Group */; \ + inc %o5 /* IEU0 */; \ + sub %o2, %o4, %o2 /* IEU1 */; \ + fcmpgt32 %fz, %S1, %g3 /* FPM Group */; \ + srl %o5, 1, %o5 /* IEU0 */; \ + inc %g1 /* IEU1 */; \ + fcmpgt32 %fz, %S3, %g5 /* FPM Group */; \ + srl %g1, 1, %g1 /* IEU0 */; \ + sub %o2, %o5, %o2 /* IEU1 */; \ + ldx [%sp + STACKOFF], %o5 /* Load Group */; \ + inc %g2 /* IEU0 */; \ + sub %o2, %g1, %o2 /* IEU1 */; \ + fcmpgt32 %fz, %T1, %g7 /* FPM Group */; \ + srl %g2, 1, %g2 /* IEU0 */; \ + inc %g3 /* IEU1 */; \ + fcmpgt32 %T0, %U0, %o3 /* FPM Group */; \ + srl %g3, 1, %g3 /* IEU0 */; \ + sub %o2, %g2, %o2 /* IEU1 */; \ + inc %g5 /* IEU0 Group */; \ + sub %o2, %g3, %o2 /* IEU1 */; \ + fcmpgt32 %fz, %U0, %o4 /* FPM Group */; \ + srl %g5, 1, %g5 /* IEU0 */; \ + inc %g7 /* IEU1 */; \ + srl %g7, 1, %g7 /* IEU0 Group */; \ + sub %o2, %g5, %o2 /* IEU1 */; \ + inc %o3 /* IEU0 Group */; \ + sub %o2, %g7, %o2 /* IEU1 */; \ + srl %o3, 1, %o3 /* IEU0 Group */; \ + inc %o4 /* IEU1 */; \ + srl %o4, 1, %o4 /* IEU0 Group */; \ + add %o2, %o3, %o2 /* IEU1 */; \ + sub %o2, %o4, %o2 /* IEU0 Group */; \ + addcc %o2, %o5, %o2 /* IEU1 Group */; \ + bcs,a,pn %xcc, 33f /* CTI */; \ + add %o2, 1, %o2 /* IEU0 */; \ +33: /* That's it */; + +#define CSUM_LASTCHUNK(offset) \ + ldx [%o0 - offset - 0x10], %g2; \ + ldx [%o0 - offset - 0x08], %g3; \ + addcc %g2, %o2, %o2; \ + bcs,a,pn %xcc, 31f; \ + add %o2, 1, %o2; \ +31: addcc %g3, %o2, %o2; \ + bcs,a,pn %xcc, 32f; \ + add %o2, 1, %o2; \ +32: + + .text + .globl csum_partial + .align 32 +csum_partial: + andcc %o0, 7, %g0 /* IEU1 Group */ + be,pt %icc, 4f /* CTI */ + andcc %o0, 0x38, %g3 /* IEU1 */ + mov 1, %g5 /* IEU0 Group */ + cmp %o1, 6 /* IEU1 */ + bl,pn %icc, 21f /* CTI */ + andcc %o0, 2, %g0 /* IEU1 Group */ + be,pt %icc, 1f /* CTI */ + and %o0, 4, %g7 /* IEU0 */ + lduh [%o0], %g2 /* Load */ + sub %o1, 2, %o1 /* IEU0 Group */ + add %o0, 2, %o0 /* IEU1 */ + andcc %o0, 4, %g7 /* IEU1 Group */ + sll %g5, 16, %g5 /* IEU0 */ + sll %g2, 16, %g2 /* IEU0 Group */ + addcc %g2, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %icc, 1f /* CTI */ + add %o2, %g5, %o2 /* IEU0 */ +1: ld [%o0], %g2 /* Load */ + brz,a,pn %g7, 4f /* CTI+IEU1 Group */ + and %o0, 0x38, %g3 /* IEU0 */ + add %o0, 4, %o0 /* IEU0 Group */ + sub %o1, 4, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %icc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: and %o0, 0x38, %g3 /* IEU1 Group */ +4: srl %o2, 0, %o2 /* IEU0 Group */ + mov 0x40, %g1 /* IEU1 */ + brz,pn %g3, 3f /* CTI+IEU1 Group */ + sub %g1, %g3, %g1 /* IEU0 */ + cmp %o1, 56 /* IEU1 Group */ + blu,pn %icc, 20f /* CTI */ + andcc %o0, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + ldx [%o0], %g2 /* Load */ + add %o0, 8, %o0 /* IEU0 Group */ + sub %o1, 8, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: andcc %g1, 0x10, %g0 /* IEU1 Group */ + be,pn %icc, 2f /* CTI */ + and %g1, 0x20, %g1 /* IEU0 */ + ldx [%o0], %g2 /* Load */ + ldx [%o0+8], %g3 /* Load Group */ + add %o0, 16, %o0 /* IEU0 */ + sub %o1, 16, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 2f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +2: brz,pn %g1, 3f /* CTI+IEU1 Group */ + ldx [%o0], %g2 /* Load */ + ldx [%o0+8], %g3 /* Load Group */ + ldx [%o0+16], %g5 /* Load Group */ + ldx [%o0+24], %g7 /* Load Group */ + add %o0, 32, %o0 /* IEU0 */ + sub %o1, 32, %o1 /* IEU1 */ + addcc %g2, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g5, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: addcc %g7, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 3f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +3: cmp %o1, 0xc0 /* IEU1 Group */ + blu,pn %icc, 20f /* CTI */ + sllx %o2, 32, %g1 /* IEU0 */ + addcc %o2, %g1, %o2 /* IEU1 Group */ + sub %o1, 0xc0, %o1 /* IEU0 */ + wr %g0, ASI_BLK_P, %asi /* LSU Group */ +#ifdef __KERNEL__ + wr %g0, FPRS_FEF, %fprs /* LSU Group */ +#endif + membar #StoreLoad /* LSU Group */ + srlx %o2, 32, %o2 /* IEU0 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU1 */ +1: andcc %o1, 0x80, %g0 /* IEU1 Group */ + bne,pn %icc, 7f /* CTI */ + andcc %o1, 0x40, %g0 /* IEU1 Group */ + be,pn %icc, 6f /* CTI */ + fzero %f12 /* FPA */ + fzero %f14 /* FPA Group */ + ldda [%o0 + 0x000] %asi, %f16 + ldda [%o0 + 0x040] %asi, %f32 + ldda [%o0 + 0x080] %asi, %f48 + START_THE_TRICK(f12,f16,f18,f20,f22,f24,f26) + ba,a,pt %xcc, 3f +6: sub %o0, 0x40, %o0 /* IEU0 Group */ + fzero %f28 /* FPA */ + fzero %f30 /* FPA Group */ + ldda [%o0 + 0x040] %asi, %f32 + ldda [%o0 + 0x080] %asi, %f48 + ldda [%o0 + 0x0c0] %asi, %f0 + START_THE_TRICK(f28,f32,f34,f36,f38,f40,f42) + ba,a,pt %xcc, 4f +7: bne,pt %icc, 8f /* CTI */ + fzero %f44 /* FPA */ + add %o0, 0x40, %o0 /* IEU0 Group */ + fzero %f60 /* FPA */ + fzero %f62 /* FPA Group */ + ldda [%o0 - 0x040] %asi, %f0 + ldda [%o0 + 0x000] %asi, %f16 + ldda [%o0 + 0x040] %asi, %f32 + START_THE_TRICK(f60,f0,f2,f4,f6,f8,f10) + ba,a,pt %xcc, 2f +8: add %o0, 0x80, %o0 /* IEU0 Group */ + fzero %f46 /* FPA */ + ldda [%o0 - 0x080] %asi, %f48 + ldda [%o0 - 0x040] %asi, %f0 + ldda [%o0 + 0x000] %asi, %f16 + START_THE_TRICK(f44,f48,f50,f52,f54,f56,f58) +1: DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14) + ldda [%o0 + 0x040] %asi, %f32 +2: DO_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30) + ldda [%o0 + 0x080] %asi, %f48 +3: DO_THE_TRICK(f12,f14,f16,f18,f20,f22,f24,f26,f28,f30,f32,f34,f36,f38,f40,f42,f44,f46) + ldda [%o0 + 0x0c0] %asi, %f0 +4: DO_THE_TRICK(f28,f30,f32,f34,f36,f38,f40,f42,f44,f46,f48,f50,f52,f54,f56,f58,f60,f62) + add %o0, 0x100, %o0 /* IEU0 Group */ + subcc %o1, 0x100, %o1 /* IEU1 */ + bgeu,a,pt %icc, 1b /* CTI */ + ldda [%o0 + 0x000] %asi, %f16 + membar #Sync /* LSU Group */ + DO_THE_TRICK(f44,f46,f48,f50,f52,f54,f56,f58,f60,f62,f0,f2,f4,f6,f8,f10,f12,f14) + END_THE_TRICK(f60,f62,f0,f2,f4,f6,f8,f10,f12,f14,f16,f18,f20,f22,f24,f26,f28,f30) + and %o1, 0x3f, %o1 /* IEU0 Group */ +#ifdef __KERNEL__ + wr %g0, 0, %fprs /* LSU Group */ +#endif +20: andcc %o1, 0xf0, %g1 /* IEU1 Group */ + be,pn %icc, 23f /* CTI */ + and %o1, 0xf, %o3 /* IEU0 */ +22: rd %pc, %g7 /* LSU Group */ + sll %g1, 1, %o4 /* IEU0 Group */ + sub %g7, %o4, %g7 /* IEU0 Group (regdep) */ + jmpl %g7 + (23f - 22b), %g0 /* CTI Group brk forced */ + add %o0, %g1, %o0 /* IEU0 */ + CSUM_LASTCHUNK(0xe0) + CSUM_LASTCHUNK(0xd0) + CSUM_LASTCHUNK(0xc0) + CSUM_LASTCHUNK(0xb0) + CSUM_LASTCHUNK(0xa0) + CSUM_LASTCHUNK(0x90) + CSUM_LASTCHUNK(0x80) + CSUM_LASTCHUNK(0x70) + CSUM_LASTCHUNK(0x60) + CSUM_LASTCHUNK(0x50) + CSUM_LASTCHUNK(0x40) + CSUM_LASTCHUNK(0x30) + CSUM_LASTCHUNK(0x20) + CSUM_LASTCHUNK(0x10) + CSUM_LASTCHUNK(0x00) +23: brnz,pn %o3, 26f /* CTI+IEU1 Group */ +24: sllx %o2, 32, %g1 /* IEU0 */ +25: addcc %o2, %g1, %o0 /* IEU1 Group */ + srlx %o0, 32, %o0 /* IEU0 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o0, 1, %o0 /* IEU1 */ +1: retl /* CTI Group brk forced */ + srl %o0, 0, %o0 /* IEU0 */ +26: andcc %o1, 8, %g0 /* IEU1 Group */ + be,pn %icc, 1f /* CTI */ + ldx [%o0], %g3 /* Load */ + add %o0, 8, %o0 /* IEU0 Group */ + addcc %g3, %o2, %o2 /* IEU1 Group */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: andcc %o1, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + ld [%o0], %g2 /* Load */ + add %o0, 4, %o0 /* IEU0 Group */ + sllx %g2, 32, %g2 /* IEU0 Group */ +1: andcc %o1, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduh [%o0], %o4 /* Load */ + add %o0, 2, %o0 /* IEU1 */ + sll %o4, 16, %o4 /* IEU0 Group */ +1: andcc %o1, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%o0], %o5 /* Load */ + sll %o5, 8, %o5 /* IEU0 Group */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %o2, 32, %g1 /* IEU0 */ +21: srl %o2, 0, %o2 /* IEU0 Group */ + cmp %o1, 0 /* IEU1 */ + be,pn %icc, 24b /* CTI */ + andcc %o1, 4, %g0 /* IEU1 Group */ + be,a,pn %icc, 1f /* CTI */ + clr %g2 /* IEU0 */ + lduh [%o0], %g3 /* Load */ + lduh [%o0+2], %g2 /* Load Group */ + add %o0, 4, %o0 /* IEU0 Group */ + sllx %g3, 48, %g3 /* IEU0 Group */ + sllx %g2, 32, %g2 /* IEU0 Group */ + or %g3, %g2, %g2 /* IEU0 Group */ +1: andcc %o1, 2, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o4 /* IEU0 Group */ + lduh [%o0], %o4 /* Load */ + add %o0, 2, %o0 /* IEU1 */ + sll %o4, 16, %o4 /* IEU0 Group */ +1: andcc %o1, 1, %g0 /* IEU1 */ + be,a,pn %icc, 1f /* CTI */ + clr %o5 /* IEU0 Group */ + ldub [%o0], %o5 /* Load */ + sll %o5, 8, %o5 /* IEU0 Group */ +1: or %g2, %o4, %o4 /* IEU1 */ + or %o5, %o4, %o4 /* IEU0 Group (regdep) */ + addcc %o4, %o2, %o2 /* IEU1 Group (regdep) */ + bcs,a,pn %xcc, 1f /* CTI */ + add %o2, 1, %o2 /* IEU0 */ +1: ba,pt %xcc, 25b /* CTI Group */ + sllx %o2, 32, %g1 /* IEU0 */ diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/checksum.S linux/arch/sparc64/lib/checksum.S --- v2.1.44/linux/arch/sparc64/lib/checksum.S Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/lib/checksum.S Wed Jul 16 20:37:21 1997 @@ -25,223 +25,12 @@ * into the accumulated sum. The following is much better. * * This should run at max bandwidth for ecache hits, a better - * technique is to use VIS and fpu operations somehow, but - * this requires more reasoning on my part... - * - * Assuming ecache hits and branches predicted well, this - * can be expected to run at a rate of 16 cycles per 64-bytes - * of data summed. (the old code summed 32 bytes in 20 - * cycles, with numerous bubbles and unnecessary stalls) + * technique is to use VIS and fpu operations. This is already + * done for csum_partial, needs to be written for the copy stuff + * still. */ -#define CSUM_ECACHE_LOAD(buf, offset, t0, t1, t2, t3, t4, t5, t6, t7) \ - ldx [buf + offset + 0x00], t0; \ - ldx [buf + offset + 0x08], t1; \ - ldx [buf + offset + 0x10], t2; \ - ldx [buf + offset + 0x18], t3; \ - ldx [buf + offset + 0x20], t4; \ - ldx [buf + offset + 0x28], t5; \ - ldx [buf + offset + 0x30], t6; \ - ldx [buf + offset + 0x38], t7; \ - nop; nop; /* THIS IS CRITICAL!!!!!!!!! */ - -#define CSUM_ECACHE_BLOCK_LDNEXT(buf, offset, sum, t0, t1, t2, t3, t4, t5, t6, t7) \ - addcc sum, t0, sum; \ - bcc,pt %xcc, 11f; \ - ldx [buf + offset + 0x00], t0; \ - add sum, 1, sum; \ -11: addcc sum, t1, sum; \ - bcc,pt %xcc, 12f; \ - ldx [buf + offset + 0x08], t1; \ - add sum, 1, sum; \ -12: addcc sum, t2, sum; \ - bcc,pt %xcc, 13f; \ - ldx [buf + offset + 0x10], t2; \ - add sum, 1, sum; \ -13: addcc sum, t3, sum; \ - bcc,pt %xcc, 14f; \ - ldx [buf + offset + 0x18], t3; \ - add sum, 1, sum; \ -14: addcc sum, t4, sum; \ - bcc,pt %xcc, 15f; \ - ldx [buf + offset + 0x20], t4; \ - add sum, 1, sum; \ -15: addcc sum, t5, sum; \ - bcc,pt %xcc, 16f; \ - ldx [buf + offset + 0x28], t5; \ - add sum, 1, sum; \ -16: addcc sum, t6, sum; \ - bcc,pt %xcc, 17f; \ - ldx [buf + offset + 0x30], t6; \ - add sum, 1, sum; \ -17: addcc sum, t7, sum; \ - bcc,pt %xcc, 18f; \ - ldx [buf + offset + 0x38], t7; \ - add sum, 1, sum; \ -18: nop; nop; /* DO NOT TOUCH! */ - -#define CSUM_ECACHE_BLOCK(sum, t0, t1, t2, t3, t4, t5, t6, t7) \ - addcc sum, t0, sum; \ - bcs,a,pn %xcc, 21f; \ - add sum, 1, sum; \ -21: addcc sum, t1, sum; \ - bcs,a,pn %xcc, 22f; \ - add sum, 1, sum; \ -22: addcc sum, t2, sum; \ - bcs,a,pn %xcc, 23f; \ - add sum, 1, sum; \ -23: addcc sum, t3, sum; \ - bcs,a,pn %xcc, 24f; \ - add sum, 1, sum; \ -24: addcc sum, t4, sum; \ - bcs,a,pn %xcc, 25f; \ - add sum, 1, sum; \ -25: addcc sum, t5, sum; \ - bcs,a,pn %xcc, 26f; \ - add sum, 1, sum; \ -26: addcc sum, t6, sum; \ - bcs,a,pn %xcc, 27f; \ - add sum, 1, sum; \ -27: addcc sum, t7, sum; \ - bcs,a,pn %xcc, 28f; \ - add sum, 1, sum; \ -28: - -#define CSUM_LASTCHUNK(buf, offset, sum, t0, t1) \ - ldx [buf - offset - 0x08], t0; \ - ldx [buf - offset - 0x00], t1; \ - addcc t0, sum, sum; \ - bcs,a,pn %xcc, 31f; \ - add sum, 1, sum; \ -31: addcc t1, sum, sum; \ - bcs,a,pn %xcc, 32f; \ - add sum, 1, sum; \ -32: .text - /* Keep this garbage from swiping the icache. */ -csum_partial_end_cruft: - andcc %o1, 8, %g0 ! IEU1 Group - be,pn %icc, 1f ! CTI - and %o1, 4, %g5 ! IEU0 - ldx [%o0 + 0x00], %g2 ! Load Group - add %o0, 0x8, %o0 ! IEU0 - addcc %g2, %o2, %o2 ! IEU1 Group + 2 bubbles - bcs,a,pn %xcc, 1f ! CTI - add %o2, 1, %o2 ! IEU0 4 clocks (mispredict) -1: andcc %o1, 2, %g0 ! IEU1 Group - brz,pn %g5, 1f ! CTI Group (needs IEU1) - clr %g2 ! IEU0 - ld [%o0], %g2 ! Load - add %o0, 4, %o0 ! IEU0 Group - sllx %g2, 32, %g2 ! IEU0 Group + 2 bubbles -1: and %o1, 1, %o1 ! IEU1 - be,pn %icc, 1f ! CTI - clr %o4 ! IEU0 Group - lduh [%o0], %o4 ! Load - add %o0, 2, %o0 ! IEU1 - sll %o4, 16, %o4 ! IEU0 Group + 2 bubbles -1: brz,pn %o1, 1f ! CTI - clr %o5 ! IEU1 - ldub [%o0], %o5 ! Load Group - sll %o5, 8, %o5 ! IEU0 Group + 2 bubbles -1: or %g2, %o4, %o4 ! IEU1 - or %o5, %o4, %o4 ! IEU0 Group - addcc %o4, %o2, %o2 ! IEU1 Group (regdep) - bcc,pt %xcc, cfold ! CTI - sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 -1: b,pt %xcc, cfold ! CTI Group - add %o2, 1, %o2 ! IEU0 - -csum_partial_fixit: - bl,pn %icc, cpte ! CTI Group - and %o1, 0xf, %o3 ! IEU0 - andcc %o0, 0x2, %g0 ! IEU1 - be,pn %icc, 1f ! CTI Group - and %o0, 0x4, %g7 ! IEU0 - lduh [%o0 + 0x00], %g2 ! Load - sub %o1, 2, %o1 ! IEU0 Group - addcc %o0, 2, %o0 ! IEU1 - and %o0, 0x4, %g7 ! IEU0 Group - sll %g2, 16, %g2 ! IEU0 Group (no load stall) - addcc %g2, %o2, %o2 ! IEU1 Group (regdep) - bcc,pt %icc, 0f ! CTI - andn %o1, 0xff, %o3 ! IEU0 - srl %o2, 16, %g2 ! IEU0 Group - b,pt %xcc, 9f ! CTI - add %g2, 1, %g2 ! IEU1 -0: srl %o2, 16, %g2 ! IEU0 Group 8-( -9: sll %o2, 16, %o2 ! IEU0 Group 8-( - sll %g2, 16, %g3 ! IEU0 Group 8-( - srl %o2, 16, %o2 ! IEU0 Group 8-( - or %g3, %o2, %o2 ! IEU1 -1: brnz,pt %g7, 2f ! CTI Group - sub %o1, 4, %o1 ! IEU0 - b,pt %xcc, csum_partial_aligned ! CTI Group - add %o1, 4, %o1 ! IEU0 -2: ld [%o0 + 0x00], %g2 ! Load Group - add %o0, 4, %o0 ! IEU0 - andn %o1, 0xff, %o3 ! IEU1 - addcc %g2, %o2, %o2 ! IEU1 Group + 2 bubbles - bcc,pt %xcc, csum_partial_aligned ! CTI - nop ! IEU0 - b,pt %xcc, csum_partial_aligned ! CTI Group - add %o2, 1, %o2 ! IEU0 - - .align 32 - .globl csum_partial -csum_partial: /* %o0=buf, %o1=len, %o2=sum */ - andcc %o0, 0x7, %g0 ! IEU1 Group - srl %o1, 0, %o1 ! IEU0 - srl %o2, 0, %o2 ! IEU0 Group - be,pt %icc, csum_partial_aligned ! CTI - andn %o1, 0xff, %o3 ! IEU1 - b,pt %xcc, csum_partial_fixit ! CTI Group - cmp %o1, 6 ! IEU0 - nop -csum_partial_aligned: - brz,pt %o3, 3f ! CTI Group - and %o1, 0xf0, %g1 ! IEU0 -5: CSUM_ECACHE_LOAD( %o0, 0x000, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7) - CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x040, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7) - CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x080, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7) - CSUM_ECACHE_BLOCK_LDNEXT(%o0, 0x0c0, %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7) - CSUM_ECACHE_BLOCK( %o2, %o4, %o5, %g2, %g3, %g4, %g5, %g1, %g7) - subcc %o3, 256, %o3 ! IEU1 Group - bne,pt %icc, 5b ! CTI - add %o0, 256, %o0 ! IEU0 - and %o1, 0xf0, %g1 ! IEU0 Group -3: brz,pn %g1, cpte ! CTI - and %o1, 0xf, %o3 ! IEU1 Group -10: rd %pc, %g7 ! LSU Group + 4 clocks - sll %g1, 1, %o4 ! IEU0 Group - sub %g7, %o4, %g7 ! IEU1 - jmp %g7 + %lo(cpte - 10b) ! CTI Group brk forced - add %o0, %g1, %o0 ! IEU0 -cptbl: CSUM_LASTCHUNK(%o0, 0xe8, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0xd8, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0xc8, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0xb8, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0xa8, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x98, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x88, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x78, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x68, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x58, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x48, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x38, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x28, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x18, %o2, %g2, %g3) - CSUM_LASTCHUNK(%o0, 0x08, %o2, %g2, %g3) -cpte: brnz,pn %o3, csum_partial_end_cruft ! CTI Group - sethi %uhi(PAGE_OFFSET), %g4 ! IEU0 -cfold: sllx %o2, 32, %o0 ! IEU0 Group - addcc %o2, %o0, %o0 ! IEU1 Group (regdep) - srlx %o0, 32, %o0 ! IEU0 Group (regdep) - bcs,a,pn %xcc, 1f ! CTI - add %o0, 1, %o0 ! IEU1 4 clocks (mispredict) -1: retl ! CTI Group brk forced - sllx %g4, 32, %g4 ! IEU0 Group - .globl __csum_partial_copy_start, __csum_partial_copy_end __csum_partial_copy_start: diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/lib/strlen_user.S linux/arch/sparc64/lib/strlen_user.S --- v2.1.44/linux/arch/sparc64/lib/strlen_user.S Mon Jun 16 16:35:54 1997 +++ linux/arch/sparc64/lib/strlen_user.S Wed Jul 16 19:22:50 1997 @@ -20,36 +20,27 @@ andcc %o0, 3, %g0 be,pt %icc, 9f sethi %hi(HI_MAGIC), %o4 -10: - lduba [%o0] ASI_S, %o5 +10: lduba [%o0] ASI_S, %o5 brz,pn %o5, 21f add %o0, 1, %o0 andcc %o0, 3, %g0 be,pn %icc, 4f or %o4, %lo(HI_MAGIC), %o3 -11: - lduba [%o0] ASI_S, %o5 +11: lduba [%o0] ASI_S, %o5 brz,pn %o5, 22f add %o0, 1, %o0 andcc %o0, 3, %g0 - be,pt %icc, 5f - sethi %hi(LO_MAGIC), %o4 -12: - lduba [%o0] ASI_S, %o5 + be,pt %icc, 13f + srl %o3, 7, %o2 +12: lduba [%o0] ASI_S, %o5 brz,pn %o5, 23f add %o0, 1, %o0 - ba,pt %icc, 13f - or %o4, %lo(LO_MAGIC), %o2 -9: - or %o4, %lo(HI_MAGIC), %o3 -4: - sethi %hi(LO_MAGIC), %o4 -5: - or %o4, %lo(LO_MAGIC), %o2 -13: - lda [%o0] ASI_S, %o5 -2: - sub %o5, %o2, %o4 + ba,pt %icc, 2f +15: lda [%o0] ASI_S, %o5 +9: or %o4, %lo(HI_MAGIC), %o3 +4: srl %o3, 7, %o2 +13: lda [%o0] ASI_S, %o5 +2: sub %o5, %o2, %o4 andcc %o4, %o3, %g0 be,pt %icc, 13b add %o0, 4, %o0 @@ -69,20 +60,15 @@ add %o4, 1, %o4 andcc %o5, 0xff, %g0 bne,a,pt %icc, 2b -14: - lda [%o0] ASI_S, %o5 +14: lda [%o0] ASI_S, %o5 add %o4, 1, %o4 -1: - retl +1: retl sub %o4, %o1, %o0 -21: - retl +21: retl mov 1, %o0 -22: - retl +22: retl mov 2, %o0 -23: - retl +23: retl mov 3, %o0 .section .fixup,#alloc,#execinstr @@ -97,5 +83,6 @@ .xword 10b, 30b .xword 11b, 30b .xword 12b, 30b + .xword 15b, 30b .xword 13b, 30b .xword 14b, 30b diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/mm/fault.c linux/arch/sparc64/mm/fault.c --- v2.1.44/linux/arch/sparc64/mm/fault.c Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/mm/fault.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: fault.c,v 1.17 1997/07/04 01:41:10 davem Exp $ +/* $Id: fault.c,v 1.18 1997/07/17 02:20:56 davem Exp $ * arch/sparc64/mm/fault.c: Page fault handlers for the 64-bit Sparc. * * Copyright (C) 1996 David S. Miller (davem@caip.rutgers.edu) @@ -228,7 +228,7 @@ pte_t *ptep; int alias_found = 0; - inode = vma->vm_inode; + inode = vma->vm_dentry->d_inode; if(!inode) return; diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/mm/ultra.S linux/arch/sparc64/mm/ultra.S --- v2.1.44/linux/arch/sparc64/mm/ultra.S Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/mm/ultra.S Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: ultra.S,v 1.6 1997/06/30 10:31:43 jj Exp $ +/* $Id: ultra.S,v 1.8 1997/07/15 05:35:50 davem Exp $ * ultra.S: Don't expand these all over the place... * * Copyright (C) 1997 David S. Miller (davem@caip.rutgers.edu) @@ -97,5 +97,130 @@ retl flush %g6 +#ifdef __SMP__ + /* These are all called by the slaves of a cross call, at + * trap level 1, with interrupts fully disabled. + * + * Register usage: + * %g5 mm->context (all tlb flushes) + * %g6 address arg 1 (tlb page and range flushes) + * %g7 address arg 2 (tlb range flush only) + * + * %g1 ivector table, don't touch + * %g2 scratch 1 + * %g3 scratch 2 + * %g4 scratch 3 + * + * NOTE: We do not acknowledge the UPA until we are done + * with the service. This is what tells the master + * that he can consider the effects of the flush + * "complete" on this cpu. + */ + .align 32 + .globl xcall_flush_tlb_page +xcall_flush_tlb_page: + mov SECONDARY_CONTEXT, %g2 + nop + ldxa [%g2] ASI_DMMU, %g3 + cmp %g3, %g5 + be,pt %icc, 1f + or %g6, 0x10, %g4 + stxa %g5, [%g2] ASI_DMMU +1: stxa %g0, [%g4] ASI_DMMU_DEMAP + + be,pt %icc, 1f + stxa %g0, [%g4] ASI_IMMU_DEMAP + stxa %g3, [%g2] ASI_DMMU +1: b,pt %xcc, do_ivec_return + flush %g1 + + .align 32 + .globl xcall_flush_tlb_mm +xcall_flush_tlb_mm: + mov SECONDARY_CONTEXT, %g2 + nop + ldxa [%g2] ASI_DMMU, %g3 + cmp %g3, %g5 + be,pt %icc, 1f + mov 0x50, %g4 + stxa %g5, [%g2] ASI_DMMU +1: stxa %g0, [%g4] ASI_DMMU_DEMAP - + be,pt %icc, 1f + stxa %g0, [%g4] ASI_IMMU_DEMAP + stxa %g3, [%g2] ASI_DMMU +1: b,pt %xcc, do_ivec_return + flush %g1 + + .align 32 + .globl xcall_flush_tlb_range +xcall_flush_tlb_range: + sethi %hi(8192 - 1), %g2 + or %g2, %lo(8192 - 1), %g2 + andn %g6, %g2, %g6 + andn %g7, %g2, %g7 + sub %g7, %g6, %g3 + add %g2, 1, %g2 + orcc %g6, 0x50, %g6 + srlx %g3, 13, %g4 + + cmp %g4, 96 + bgu,pn %icc, xcall_flush_tlb_mm + mov SECONDARY_CONTEXT, %g4 + ldxa [%g4] ASI_DMMU, %g7 + cmp %g7, %g5 + be,pt %icc, 1f + sub %g3, %g2, %g3 + stxa %g5, [%g4] ASI_DMMU + +1: stxa %g0, [%g6 + %g3] ASI_DMMU_DEMAP + stxa %g0, [%g6 + %g3] ASI_IMMU_DEMAP + brnz,pt %g3, 1b + sub %g3, %g2, %g3 + bne,a,pn %icc, 1f + stxa %g7, [%g4] ASI_DMMU +1: b,pt %xcc, do_ivec_return + flush %g1 + + /* These two are not performance critical... */ + .globl xcall_flush_tlb_all +xcall_flush_tlb_all: + clr %g2 + clr %g3 +1: ldxa [%g3] ASI_DTLB_DATA_ACCESS, %g4 + and %g4, _PAGE_L, %g5 + brnz,pn %g5, 2f + mov TLB_TAG_ACCESS, %g7 + stxa %g0, [%g7] ASI_DMMU + membar #Sync + + stxa %g0, [%g3] ASI_DTLB_DATA_ACCESS + membar #Sync +2: ldxa [%g3] ASI_ITLB_DATA_ACCESS, %g4 + and %g4, _PAGE_L, %g5 + brnz,pn %g5, 2f + mov TLB_TAG_ACCESS, %g7 + stxa %g0, [%g7] ASI_IMMU + membar #Sync + + stxa %g0, [%g3] ASI_ITLB_DATA_ACCESS +2: add %g2, 1, %g2 + cmp %g2, 63 + ble,pt %icc, 1b + sll %g2, 3, %g3 + b,pt %xcc, do_ivec_return + flush %g1 + + .globl xcall_flush_cache_all +xcall_flush_cache_all: + sethi %hi(16383), %g2 + or %g2, %lo(16383), %g2 + clr %g3 +1: stxa %g0, [%g3] ASI_IC_TAG + add %g3, 32, %g3 + cmp %g3, %g2 + bleu,pt %xcc, 1b + nop + b,pt %xcc, do_ivec_return + flush %g1 +#endif /* __SMP__ */ diff -u --recursive --new-file v2.1.44/linux/arch/sparc64/prom/misc.c linux/arch/sparc64/prom/misc.c --- v2.1.44/linux/arch/sparc64/prom/misc.c Mon Jul 7 08:18:55 1997 +++ linux/arch/sparc64/prom/misc.c Wed Jul 16 19:22:50 1997 @@ -1,4 +1,4 @@ -/* $Id: misc.c,v 1.7 1997/07/05 09:52:51 davem Exp $ +/* $Id: misc.c,v 1.8 1997/07/14 23:45:28 davem Exp $ * misc.c: Miscellaneous prom functions that don't belong * anywhere else. * @@ -133,3 +133,10 @@ { p1275_cmd("SUNW,set-trap-table", P1275_INOUT(1, 0), tba); } + +#ifdef __SMP__ +void prom_start_cpu(int cpunode, unsigned long pc, unsigned long o0) +{ + p1275_cmd("SUNW,start-cpu", P1275_INOUT(3, 0), cpunode, pc, o0); +} +#endif diff -u --recursive --new-file v2.1.44/linux/drivers/block/loop.c linux/drivers/block/loop.c --- v2.1.44/linux/drivers/block/loop.c Mon Jun 16 16:35:54 1997 +++ linux/drivers/block/loop.c Wed Jul 16 20:37:21 1997 @@ -292,7 +292,7 @@ return -EBADF; if (lo->lo_inode) return -EBUSY; - inode = file->f_inode; + inode = file->f_dentry->d_inode; if (!inode) { printk("loop_set_fd: NULL inode?!?\n"); return -EINVAL; @@ -318,7 +318,7 @@ } lo->lo_inode = inode; - atomic_inc(&lo->lo_inode->i_count); + lo->lo_inode->i_count++; lo->transfer = NULL; figure_loop_size(lo); MOD_INC_USE_COUNT; diff -u --recursive --new-file v2.1.44/linux/drivers/block/md.c linux/drivers/block/md.c --- v2.1.44/linux/drivers/block/md.c Mon Jun 16 16:35:54 1997 +++ linux/drivers/block/md.c Wed Jul 16 19:22:50 1997 @@ -202,10 +202,10 @@ { int i; - if (atomic_read(&inode->i_count)>1 || md_dev[minor].busy>1) /* ioctl : one open channel */ + if (inode->i_count > 1 || md_dev[minor].busy>1) /* ioctl : one open channel */ { printk ("STOP_MD md%x failed : i_count=%d, busy=%d\n", minor, - atomic_read(&inode->i_count), md_dev[minor].busy); + inode->i_count, md_dev[minor].busy); return -EBUSY; } diff -u --recursive --new-file v2.1.44/linux/drivers/block/rd.c linux/drivers/block/rd.c --- v2.1.44/linux/drivers/block/rd.c Tue May 13 22:41:05 1997 +++ linux/drivers/block/rd.c Mon Jul 14 11:33:24 1997 @@ -360,10 +360,10 @@ * Read block 0 to test for gzipped kernel */ if (fp->f_op->llseek) - fp->f_op->llseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0); + fp->f_op->llseek(fp->f_dentry->d_inode, fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; - fp->f_op->read(fp->f_inode, fp, buf, size); + fp->f_op->read(fp->f_dentry->d_inode, fp, buf, size); /* * If it matches the gzip magic numbers, return -1 @@ -390,11 +390,11 @@ * Read block 1 to test for minix and ext2 superblock */ if (fp->f_op->llseek) - fp->f_op->llseek(fp->f_inode, fp, + fp->f_op->llseek(fp->f_dentry->d_inode, fp, (start_block+1) * BLOCK_SIZE, 0); fp->f_pos = (start_block+1) * BLOCK_SIZE; - fp->f_op->read(fp->f_inode, fp, buf, size); + fp->f_op->read(fp->f_dentry->d_inode, fp, buf, size); /* Try minix */ if (minixsb->s_magic == MINIX_SUPER_MAGIC || @@ -421,7 +421,7 @@ done: if (fp->f_op->llseek) - fp->f_op->llseek(fp->f_inode, fp, start_block * BLOCK_SIZE, 0); + fp->f_op->llseek(fp->f_dentry->d_inode, fp, start_block * BLOCK_SIZE, 0); fp->f_pos = start_block * BLOCK_SIZE; if ((nblocks > 0) && blk_size[MAJOR(device)]) { @@ -444,8 +444,9 @@ */ __initfunc(static void rd_load_image(kdev_t device,int offset)) { - struct inode inode, out_inode; + struct inode inode, out_inode; struct file infile, outfile; + struct dentry in_dentry, out_dentry; unsigned short fs; kdev_t ram_device; int nblocks, i; @@ -457,15 +458,19 @@ memset(&infile, 0, sizeof(infile)); memset(&inode, 0, sizeof(inode)); + memset(&in_dentry, 0, sizeof(in_dentry)); inode.i_rdev = device; infile.f_mode = 1; /* read only */ - infile.f_inode = &inode; + infile.f_dentry = &in_dentry; + in_dentry.d_inode = &inode; memset(&outfile, 0, sizeof(outfile)); memset(&out_inode, 0, sizeof(out_inode)); + memset(&out_dentry, 0, sizeof(out_dentry)); out_inode.i_rdev = ram_device; outfile.f_mode = 3; /* read/write */ - outfile.f_inode = &out_inode; + outfile.f_dentry = &out_dentry; + out_dentry.d_inode = &out_inode; if (blkdev_open(&inode, &infile) != 0) return; if (blkdev_open(&out_inode, &outfile) != 0) return; @@ -506,9 +511,9 @@ printk(KERN_NOTICE "RAMDISK: Loading %d blocks into ram disk... ", nblocks); for (i=0; i < nblocks; i++) { - infile.f_op->read(infile.f_inode, &infile, buf, + infile.f_op->read(infile.f_dentry->d_inode, &infile, buf, BLOCK_SIZE); - outfile.f_op->write(outfile.f_inode, &outfile, buf, + outfile.f_op->write(outfile.f_dentry->d_inode, &outfile, buf, BLOCK_SIZE); if (!(i % 16)) { printk("%c\b", rotator[rotate & 0x3]); @@ -637,7 +642,7 @@ { if (exit_code) return -1; - insize = crd_infp->f_op->read(crd_infp->f_inode, crd_infp, + insize = crd_infp->f_op->read(crd_infp->f_dentry->d_inode, crd_infp, inbuf, INBUFSIZ); if (insize == 0) return -1; @@ -656,7 +661,7 @@ unsigned n; uch *in, ch; - crd_outfp->f_op->write(crd_outfp->f_inode, crd_outfp, window, + crd_outfp->f_op->write(crd_outfp->f_dentry->d_inode, crd_outfp, window, outcnt); in = window; for (n = 0; n < outcnt; n++) { diff -u --recursive --new-file v2.1.44/linux/drivers/char/Config.in linux/drivers/char/Config.in --- v2.1.44/linux/drivers/char/Config.in Tue May 13 22:41:06 1997 +++ linux/drivers/char/Config.in Wed Jul 16 19:22:50 1997 @@ -52,6 +52,7 @@ if [ "$CONFIG_PSMOUSE" != "n" ]; then bool 'C&T 82C710 mouse port support (as on TI Travelmate)' CONFIG_82C710_MOUSE fi + tristate 'PC110 digitizer pad support' CONFIG_PC110_PAD fi if [ "$CONFIG_MODULES" = "y" ]; then @@ -97,4 +98,5 @@ tristate ' Berkshire Products PC Watchdog' CONFIG_PCWATCHDOG fi bool 'Enhanced Real Time Clock Support' CONFIG_RTC +tristate 'PC joystick support' CONFIG_JOYSTICK endmenu diff -u --recursive --new-file v2.1.44/linux/drivers/char/Makefile linux/drivers/char/Makefile --- v2.1.44/linux/drivers/char/Makefile Mon Jun 16 16:35:54 1997 +++ linux/drivers/char/Makefile Wed Jul 16 19:22:50 1997 @@ -143,6 +143,14 @@ endif endif +ifeq ($(CONFIG_JOYSTICK),y) +L_OBJS += joystick.o +else + ifeq ($(CONFIG_JOYSTICK),m) + M_OBJS += joystick.o + endif +endif + ifeq ($(CONFIG_MS_BUSMOUSE),y) M = y L_OBJS += msbusmouse.o @@ -210,6 +218,16 @@ ifdef CONFIG_SUN_MOUSE M = y +endif + +ifeq ($(CONFIG_PC110_PAD),y) +M = y +L_OBJS += pc110pad.o +else + ifeq ($(CONFIG_PC110_PAD),m) + M_OBJS += pc110pad.o + MM = m + endif endif ifeq ($(CONFIG_SUN_OPENPROMIO),y) diff -u --recursive --new-file v2.1.44/linux/drivers/char/cyclades.c linux/drivers/char/cyclades.c --- v2.1.44/linux/drivers/char/cyclades.c Tue May 13 22:41:06 1997 +++ linux/drivers/char/cyclades.c Thu Jul 10 11:22:04 1997 @@ -1,6 +1,6 @@ #define BLOCKMOVE static char rcsid[] = -"$Revision: 1.36.4.27 $$Date: 1997/03/26 10:30:00 $"; +"$Revision: 1.36.4.33 $$Date: 1997/06/27 19:00:00 $"; /* * linux/drivers/char/cyclades.c @@ -29,6 +29,50 @@ * void cleanup_module(void); * * $Log: cyclades.c,v $ + * Revision 1.36.4.33 1997/06/27 19:00:00 ivan + * Fixes related to kernel version conditional + * compilation. + * + * Revision 1.36.4.32 1997/06/14 19:30:00 ivan + * Compatibility issues between kernels 2.0.x and + * 2.1.x (mainly related to clear_bit function). + * + * Revision 1.36.4.31 1997/06/03 15:30:00 ivan + * Changes to define the memory window according to the + * board type. + * + * Revision 1.36.4.30 1997/05/16 15:30:00 daniel + * Changes to suport new cycladesZ boards. + * + * Revision 1.36.4.29 1997/05/12 11:30:00 daniel + * Merge of Bentson's and Daniel's version 1.36.4.28. + * Corrects bug in cy_detect_pci: check if there are more + * ports than the number of static structs allocated. + * Warning message during initialization if this driver is + * used with the new generation of cycladesZ boards. Those + * will be supported only in next release of the driver. + * Corrects bug in cy_detect_pci and cy_detect_isa that + * returned wrong number of VALID boards, when a cyclomY + * was found with no serial modules connected. + * Changes to use current (2.1.x) kernel subroutine names + * and created macros for compilation with 2.0.x kernel, + * instead of the other way around. + * + * Revision 1.36.4.28 1997/05/?? ??:00:00 bentson + * Change queue_task_irq_off to queue_task_irq. + * The inline function queue_task_irq_off (tqueue.h) + * was removed from latest releases of 2.1.x kernel. + * Use of macro __initfunc to mark the initialization + * routines, so memory can be reused. + * Also incorporate implementation of critical region + * in function cleanup_module() created by anonymous + * linuxer. + * + * Revision 1.36.4.28 1997/04/25 16:00:00 daniel + * Change to support new firmware that solves DCD problem: + * application could fail to receive SIGHUP signal when DCD + * varying too fast. + * * Revision 1.36.4.27 1997/03/26 10:30:00 daniel * Changed for suport linux versions 2.1.X. * Backward compatible with linux versions 2.0.X. @@ -98,7 +142,7 @@ * after -Y stuff (to make changes clearer) * * Revision 1.36.4.12 1996/07/11 15:40:55 bentson - * Add code to poll Cyclom-Z. Add code to get & set RS-232 control. + * Add code to poll Cyclades-Z. Add code to get & set RS-232 control. * Add code to send break. Clear firmware ID word at startup (so * that other code won't talk to inactive board). * @@ -391,7 +435,13 @@ constant in the definition below. No other change is necessary to support more boards/ports. */ -#define NR_PORTS 64 +//#define NR_PORTS 64 +#define NR_PORTS 128 + +#define ZE_V1_NPORTS 64 +#define ZO_V1 0 +#define ZO_V2 1 +#define ZE_V1 2 #define SERIAL_PARANOIA_CHECK #undef SERIAL_DEBUG_OPEN @@ -453,35 +503,51 @@ #include #include #include -#include #include -#if LINUX_VERSION_CODE >= 131328 +#if (LINUX_VERSION_CODE >= 0x020100) #include +#include -#define memcpy_fromfs copy_from_user -#define memcpy_tofs copy_to_user -#define put_fs_long put_user -#define vremap ioremap +#define cy_put_user put_user -static unsigned long get_fs_long(unsigned long *addr) +static unsigned long cy_get_user(unsigned long *addr) { unsigned long result = 0; int error = get_user (result, addr); if (error) - printk ("cyclades: get_fs_long: error == %d\n", error); + printk ("cyclades: cy_get_user: error == %d\n", error); return result; } +#else + +#define __initfunc(__arginit) __arginit +#define copy_from_user memcpy_fromfs +#define copy_to_user memcpy_tofs +#define cy_get_user get_fs_long +#define cy_put_user put_fs_long +#define ioremap vremap + #endif #ifndef MIN #define MIN(a,b) ((a) < (b) ? (a) : (b)) #endif + #define IS_CYC_Z(card) ((card).num_chips == 1) +#define Z_FPGA_CHECK(card) \ + ((((struct RUNTIME_9060 *)((card).ctl_addr))->init_ctrl&(1<<17))!=0) + +#define ISZLOADED(card) (((ZO_V1==((struct RUNTIME_9060 *) \ + ((card).ctl_addr))->mail_box_0) || \ + Z_FPGA_CHECK(card)) && \ + (ZFIRM_ID==((struct FIRM_ID *) \ + ((card).base_addr+ID_ADDRESS))->signature)) + #define WAKEUP_CHARS (SERIAL_XMIT_SIZE-256) #define STD_COM_FLAGS (0) @@ -548,7 +614,7 @@ /* * 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, + * lock it in case the copy_from_user 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 @@ -698,10 +764,12 @@ { (data<10)? CP(data+'0'): CP(data+'A'-10); }/* CP4 */ static void CP8(int data) { CP4((data>>4) & 0x0f); CP4( data & 0x0f); }/* CP8 */ +#if 0 static void CP16(int data) { CP8((data>>8) & 0xff); CP8(data & 0xff); }/* CP16 */ static void CP32(long data) { CP16((data>>16) & 0xffff); CP16(data & 0xffff); }/* CP32 */ +#endif /* @@ -758,6 +826,7 @@ if (!tty) return; +#if (LINUX_VERSION_CODE >= 0x020125) if (test_and_clear_bit(Cy_EVENT_HANGUP, &info->event)) { tty_hangup(info->tty); wake_up_interruptible(&info->open_wait); @@ -774,6 +843,24 @@ } wake_up_interruptible(&tty->write_wait); } +#else + if (clear_bit(Cy_EVENT_HANGUP, &info->event)) { + tty_hangup(info->tty); + wake_up_interruptible(&info->open_wait); + info->flags &= ~(ASYNC_NORMAL_ACTIVE| + ASYNC_CALLOUT_ACTIVE); + } + if (clear_bit(Cy_EVENT_OPEN_WAKEUP, &info->event)) { + wake_up_interruptible(&info->open_wait); + } + if (clear_bit(Cy_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); + } +#endif } /* do_softint */ @@ -1351,7 +1438,7 @@ /***********************************************************/ /********* End of block of Cyclom-Y specific code **********/ -/******** Start of block of Cyclom-Z specific code *********/ +/******** Start of block of Cyclades-Z specific code *********/ /***********************************************************/ @@ -1365,7 +1452,7 @@ unsigned long loc_doorbell; firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(*cinfo)){ return (-1); } zfw_ctrl = (struct ZFW_CTRL *) @@ -1397,7 +1484,7 @@ int index; firm_id = (struct FIRM_ID *)(cinfo->base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(*cinfo)){ return (-1); } zfw_ctrl = (struct ZFW_CTRL *) @@ -1408,7 +1495,7 @@ pci_doorbell = &((struct RUNTIME_9060 *) (cinfo->ctl_addr))->pci_doorbell; while( (*pci_doorbell & 0xff) != 0){ - if (index++ == 100){ + if (index++ == 1000){ return(-1); } udelay(50L); @@ -1421,6 +1508,7 @@ } /* cyz_issue_cmd */ +#if 0 static int cyz_update_channel( struct cyclades_card *cinfo, u_long channel, u_char mode, u_char cmd) @@ -1430,7 +1518,7 @@ struct ZFW_CTRL *zfw_ctrl; struct CH_CTRL *ch_ctrl; - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(*cinfo)){ return (-1); } zfw_ctrl = @@ -1442,6 +1530,7 @@ return cyz_issue_cmd(cinfo, channel, cmd, 0L); } /* cyz_update_channel */ +#endif static void @@ -1467,6 +1556,7 @@ u_long channel; u_char cmd; u_long *param; + u_long hw_ver, fw_ver; cyz_timerlist.expires = jiffies + 100; @@ -1476,7 +1566,7 @@ firm_id = (struct FIRM_ID *) (cinfo->base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(*cinfo)){ continue; } @@ -1484,6 +1574,8 @@ (struct ZFW_CTRL *) (cinfo->base_addr + firm_id->zfwctrl_addr); board_ctrl = &zfw_ctrl->board_ctrl; + fw_ver = board_ctrl->fw_version; + hw_ver = ((struct RUNTIME_9060 *)(cinfo->ctl_addr))->mail_box_0; while( cyz_fetch_msg( cinfo, &channel, &cmd, ¶m) == 1){ char_count = 0; @@ -1514,7 +1606,9 @@ break; case C_CM_MDCD: if (info->flags & ASYNC_CHECK_CD){ - if( ch_ctrl[channel].rs_status & C_RS_DCD){ + if (((hw_ver != 0 || fw_ver > 241) + ? ((u_long)param) + : ch_ctrl[channel].rs_status) & C_RS_DCD) { /* SP("Open Wakeup\n"); */ cy_sched_event(info, Cy_EVENT_OPEN_WAKEUP); @@ -1709,7 +1803,7 @@ } /* cyz_poll */ -/********** End of block of Cyclom-Z specific code *********/ +/********** End of block of Cyclades-Z specific code *********/ /***********************************************************/ @@ -1794,7 +1888,7 @@ base_addr = (unsigned char*) (cy_card[card].base_addr); firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(cy_card[card])){ return -ENODEV; } @@ -1951,7 +2045,7 @@ #endif firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(cy_card[card])) { return; } @@ -2143,7 +2237,7 @@ base_addr = (char *)(cinfo->base_addr); firm_id = (struct FIRM_ID *) (base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(*cinfo)){ return -EINVAL; } @@ -2237,11 +2331,17 @@ will make the user pay attention. */ if (IS_CYC_Z(cy_card[info->card])) { - struct FIRM_ID *firm_id = - (struct FIRM_ID *) - (cy_card[info->card].base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ - printk("Cyclom-Z firmware not yet loaded\n"); + if (!ISZLOADED(cy_card[info->card])) { + if (((ZE_V1 ==((struct RUNTIME_9060 *) + ((cy_card[info->card]).ctl_addr))->mail_box_0) && + Z_FPGA_CHECK(cy_card[info->card])) && + (ZFIRM_HLT==((struct FIRM_ID *) + ((cy_card[info->card]).base_addr+ID_ADDRESS))->signature)) + { + printk ("Cyclades-Z Error: you need an external power supply for this number of ports.\n\rFirmware halted.\r\n"); + } else { + printk("Cyclades-Z firmware not yet loaded\n"); + } return -ENODEV; } } @@ -2448,7 +2548,7 @@ } if (from_user) { - memcpy_fromfs(tmp_buf, buf, c); + copy_from_user(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); @@ -2816,7 +2916,7 @@ firm_id = (struct FIRM_ID *) (cy_card[card].base_addr + ID_ADDRESS); - if (firm_id->signature != ZFIRM_ID){ + if (!ISZLOADED(cy_card[card])) { return; } @@ -2956,7 +3056,7 @@ tmp.baud_base = info->baud; tmp.custom_divisor = 0; /*!!!*/ tmp.hub6 = 0; /*!!!*/ - memcpy_tofs(retinfo,&tmp,sizeof(*retinfo)); + copy_to_user(retinfo,&tmp,sizeof(*retinfo)); return 0; } /* get_serial_info */ @@ -2970,7 +3070,7 @@ if (!new_info) return -EFAULT; - memcpy_fromfs(&new_serial,new_info,sizeof(new_serial)); + copy_from_user(&new_serial,new_info,sizeof(new_serial)); old_info = *info; if (!suser()) { @@ -3051,7 +3151,7 @@ firm_id = (struct FIRM_ID *) (cy_card[card].base_addr + ID_ADDRESS); - if (firm_id->signature == ZFIRM_ID){ + if (ISZLOADED(cy_card[card])) { zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr + firm_id->zfwctrl_addr); @@ -3070,7 +3170,7 @@ } } - put_fs_long(result,(unsigned long *) value); + cy_put_user(result,(unsigned long *) value); return 0; } /* get_modem_info */ @@ -3082,7 +3182,7 @@ int card,chip,channel,index; unsigned char *base_addr; unsigned long flags; - unsigned int arg = get_fs_long((unsigned long *) value); + unsigned int arg = cy_get_user((unsigned long *) value); struct FIRM_ID *firm_id; struct ZFW_CTRL *zfw_ctrl; struct BOARD_CTRL *board_ctrl; @@ -3180,7 +3280,7 @@ firm_id = (struct FIRM_ID *) (cy_card[card].base_addr + ID_ADDRESS); - if (firm_id->signature == ZFIRM_ID){ + if (ISZLOADED(cy_card[card])) { zfw_ctrl = (struct ZFW_CTRL *) (cy_card[card].base_addr + firm_id->zfwctrl_addr); @@ -3281,7 +3381,7 @@ get_mon_info(struct cyclades_port * info, struct cyclades_monitor * mon) { - memcpy_tofs(mon, &info->mon, sizeof(struct cyclades_monitor)); + copy_to_user(mon, &info->mon, sizeof(struct cyclades_monitor)); info->mon.int_count = 0; info->mon.char_count = 0; info->mon.char_max = 0; @@ -3335,7 +3435,7 @@ + (cy_chip_offset[chip]<default_threshold,value); + cy_put_user(info->default_threshold,value); return 0; }/* get_default_threshold */ @@ -3401,7 +3501,7 @@ + (cy_chip_offset[chip]<default_timeout,value); + cy_put_user(info->default_timeout,value); return 0; }/* get_default_timeout */ @@ -3530,7 +3630,7 @@ ret_val = error; break; } - put_fs_long(C_CLOCAL(tty) ? 1 : 0, + cy_put_user(C_CLOCAL(tty) ? 1 : 0, (unsigned long *) arg); break; case TIOCSSOFTCAR: @@ -3541,7 +3641,7 @@ break; } - arg = get_fs_long((unsigned long *) arg); + arg = cy_get_user((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | (arg ? CLOCAL : 0)); @@ -3967,8 +4067,8 @@ } /* probe for CD1400... */ -#if LINUX_VERSION_CODE >= 131328 - cy_isa_address = vremap((unsigned int)cy_isa_address,0x2000); +#if (LINUX_VERSION_CODE >= 0x020100) + cy_isa_address = ioremap((unsigned int)cy_isa_address,0x2000); #endif cy_isa_nchan = 4 * cyy_init_card(cy_isa_address,0); if (cy_isa_nchan == 0) { @@ -3988,6 +4088,7 @@ printk("Cyclom-Y/ISA found at 0x%x ", (unsigned int) cy_isa_address); printk("but no more channels are available.\n"); + printk("Change NR_PORTS in cyclades.c and recompile kernel.\n"); return(nboard); } /* fill the next cy_card structure available */ @@ -3998,6 +4099,7 @@ printk("Cyclom-Y/ISA found at 0x%x ", (unsigned int) cy_isa_address); printk("but no more cards can be used .\n"); + printk("Change NR_CARDS in cyclades.c and recompile kernel.\n"); return(nboard); } @@ -4051,6 +4153,8 @@ unsigned int cy_pci_addr0, cy_pci_addr1, cy_pci_addr2; unsigned short i,j,cy_pci_nchan; unsigned short device_id,dev_index = 0,board_index = 0; + unsigned long mailbox; + unsigned int Ze_addr0[NR_CARDS], Ze_addr2[NR_CARDS], ZeIndex = 0; if(pcibios_present() == 0) { /* PCI bus not present */ return(0); @@ -4070,6 +4174,9 @@ } } + if (device_id == 0) + break; + /* read PCI configuration area */ pcibios_read_config_byte(cyy_bus, cyy_dev_fn, PCI_INTERRUPT_LINE, &cy_pci_irq); @@ -4081,9 +4188,7 @@ PCI_BASE_ADDRESS_2, &cy_pci_addr2); pcibios_read_config_byte(cyy_bus, cyy_dev_fn, PCI_REVISION_ID, &cyy_rev_id); - if (device_id == 0){ - break; - }else if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) + if ((device_id == PCI_DEVICE_ID_CYCLOM_Y_Lo) || (device_id == PCI_DEVICE_ID_CYCLOM_Y_Hi)){ #ifdef CY_PCI_DEBUG printk("Cyclom-Y/PCI (bus=0x0%x, pci_id=0x%x, ", @@ -4096,11 +4201,11 @@ cy_pci_addr1 &= 0xfffffffc; cy_pci_addr2 &= 0xfffffff0; -#if LINUX_VERSION_CODE < 131328 +#if (LINUX_VERSION_CODE < 0x020100) if ((ulong)cy_pci_addr2 >= 0x100000) /* above 1M? */ #endif cy_pci_addr2 = - (unsigned int) vremap(cy_pci_addr2,CyPCI_Ywin); + (unsigned int) ioremap(cy_pci_addr2,CyPCI_Ywin); #ifdef CY_PCI_DEBUG printk("Cyclom-Y/PCI: relocate winaddr=0x%x ioaddr=0x%x\n", @@ -4112,12 +4217,14 @@ printk("Cyclom-Y PCI host card with "); printk("no Serial-Modules at 0x%x.\n", (unsigned int) cy_pci_addr2); + i--; continue; } if((cy_next_channel+cy_pci_nchan) > NR_PORTS) { printk("Cyclom-Y/PCI found at 0x%x ", (unsigned int) cy_pci_addr2); printk("but no channels are available.\n"); + printk("Change NR_PORTS in cyclades.c and recompile kernel.\n"); return(i); } /* fill the next cy_card structure available */ @@ -4128,6 +4235,7 @@ printk("Cyclom-Y/PCI found at 0x%x ", (unsigned int) cy_pci_addr2); printk("but no more cards can be used.\n"); + printk("Change NR_CARDS in cyclades.c and recompile kernel.\n"); return(i); } @@ -4167,65 +4275,101 @@ cy_next_channel += cy_pci_nchan; }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Lo){ /* print message */ - printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ", + printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", cyy_bus, cyy_dev_fn); printk("rev_id=%d) IRQ%d\n", cyy_rev_id, (int)cy_pci_irq); - printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n", + printk("Cyclades-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n", cy_pci_addr2, cy_pci_addr0); - printk("Cyclom-Z/PCI not supported for low addresses\n"); + printk("Cyclades-Z/PCI not supported for low addresses\n"); break; }else if (device_id == PCI_DEVICE_ID_CYCLOM_Z_Hi){ #ifdef CY_PCI_DEBUG - printk("Cyclom-Z/PCI (bus=0x0%x, pci_id=0x%x, ", + printk("Cyclades-Z/PCI (bus=0x0%x, pci_id=0x%x, ", cyy_bus, cyy_dev_fn); printk("rev_id=%d) IRQ%d\n", cyy_rev_id, (int)cy_pci_irq); - printk("Cyclom-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n", + printk("Cyclades-Z/PCI: found winaddr=0x%x ctladdr=0x%x\n", cy_pci_addr2, cy_pci_addr0); #endif - cy_pci_addr2 &= 0xfffffff0; - cy_pci_addr2 = (unsigned int) vremap( - cy_pci_addr2 & PAGE_MASK, - PAGE_ALIGN(CyPCI_Zwin)) - + (cy_pci_addr2 & (PAGE_SIZE-1)); cy_pci_addr0 &= 0xfffffff0; - cy_pci_addr0 = (unsigned int) vremap( + cy_pci_addr0 = (unsigned int) ioremap( cy_pci_addr0 & PAGE_MASK, PAGE_ALIGN(CyPCI_Zctl)) + (cy_pci_addr0 & (PAGE_SIZE-1)); + + mailbox = ((struct RUNTIME_9060 *) cy_pci_addr0)->mail_box_0; + cy_pci_addr2 &= 0xfffffff0; + if (mailbox == ZE_V1) { + cy_pci_addr2 = (unsigned int) ioremap( + cy_pci_addr2 & PAGE_MASK, + PAGE_ALIGN(CyPCI_Ze_win)) + + (cy_pci_addr2 & (PAGE_SIZE-1)); + if (ZeIndex == NR_CARDS) { + printk("Cyclades-Z/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no more cards can be used.\n"); + printk("Change NR_CARDS in cyclades.c and recompile kernel.\n"); + } else { + Ze_addr0[ZeIndex] = cy_pci_addr0; + Ze_addr2[ZeIndex] = cy_pci_addr2; + ZeIndex++; + } + i--; + continue; + } else { + cy_pci_addr2 = (unsigned int) ioremap( + cy_pci_addr2 & PAGE_MASK, + PAGE_ALIGN(CyPCI_Zwin)) + + (cy_pci_addr2 & (PAGE_SIZE-1)); + } + #ifdef CY_PCI_DEBUG - printk("Cyclom-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n", + printk("Cyclades-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n", cy_pci_addr2, cy_pci_addr0); - ((struct RUNTIME_9060 *)(cy_pci_addr0)) + if (mailbox == ZO_V1) { + ((struct RUNTIME_9060 *)(cy_pci_addr0)) ->loc_addr_base = WIN_CREG; - PAUSE - printk("Cyclom-Z/PCI: FPGA id %lx, ver %lx\n", - 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id, - 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version); - ((struct RUNTIME_9060 *)(cy_pci_addr0)) - ->loc_addr_base = WIN_RAM; + PAUSE + printk("Cyclades-Z/PCI: FPGA id %lx, ver %lx\n", + 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_id, + 0xff & ((struct CUSTOM_REG *)(cy_pci_addr2))->fpga_version); + ((struct RUNTIME_9060 *)(cy_pci_addr0)) + ->loc_addr_base = WIN_RAM; + } else { + printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n"); + } #endif /* The following clears the firmware id word. This ensures that the driver will not attempt to talk to the board until it has been properly initialized. */ PAUSE - *(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L; + if (mailbox == ZO_V1) + *(unsigned long *)(cy_pci_addr2+ID_ADDRESS) = 0L; - /* This must be a Cyclom-8Zo/PCI. The extendable + /* This must be a Cyclades-8Zo/PCI. The extendable version will have a different device_id and will be allocated its maximum number of ports. */ cy_pci_nchan = 8; + if((cy_next_channel+cy_pci_nchan) > NR_PORTS) { + printk("Cyclades-Z/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no channels are available.\n"); + printk("Change NR_PORTS in cyclades.c and recompile kernel.\n"); + return(i); + } + /* fill the next cy_card structure available */ for (j = 0 ; j < NR_CARDS ; j++) { if (cy_card[j].base_addr == 0) break; } if (j == NR_CARDS) { /* no more cy_cards available */ - printk("Cyclom-Z/PCI found at 0x%x ", + printk("Cyclades-Z/PCI found at 0x%x ", (unsigned int) cy_pci_addr2); printk("but no more cards can be used.\n"); + printk("Change NR_CARDS in cyclades.c and recompile kernel.\n"); return(i); } @@ -4235,9 +4379,9 @@ SA_INTERRUPT,"cyclomZ",NULL)) { printk("Could not allocate IRQ%d ", - (unsigned int) cy_pci_addr2); - printk("for Cyclom-Z/PCI at 0x%x.\n", cy_pci_irq); + printk("for Cyclades-Z/PCI at 0x%x.\n", + (unsigned int) cy_pci_addr2); return(i); } } @@ -4254,12 +4398,12 @@ /* print message */ /* don't report IRQ if board is no IRQ */ if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { - printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ", + printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ", j+1,cy_pci_addr2, (cy_pci_addr2 + CyPCI_Zwin - 1), (int)cy_pci_irq); }else{ - printk("Cyclom-Z/PCI #%d: 0x%x-0x%x, ", + printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, ", j+1,cy_pci_addr2, (cy_pci_addr2 + CyPCI_Zwin - 1)); } @@ -4268,6 +4412,93 @@ cy_next_channel += cy_pci_nchan; } } + + for (; ZeIndex != 0 && i < NR_CARDS; i++) { + cy_pci_addr0 = Ze_addr0[0]; + cy_pci_addr2 = Ze_addr2[0]; + for (j = 0 ; j < ZeIndex-1 ; j++) { + Ze_addr0[j] = Ze_addr0[j+1]; + Ze_addr2[j] = Ze_addr2[j+1]; + } + ZeIndex--; + mailbox = ((struct RUNTIME_9060 *) cy_pci_addr0)->mail_box_0; +#ifdef CY_PCI_DEBUG + printk("Cyclades-Z/PCI: relocate winaddr=0x%x ctladdr=0x%x\n", + cy_pci_addr2, cy_pci_addr0); + printk("Cyclades-Z/PCI: New Cyclades-Z board. FPGA not loaded\n"); +#endif + /* The following clears the firmware id word. This ensures + that the driver will not attempt to talk to the board + until it has been properly initialized. + */ + PAUSE + /* This must be the new Cyclades-Ze/PCI. */ + cy_pci_nchan = ZE_V1_NPORTS; + + if((cy_next_channel+cy_pci_nchan) > NR_PORTS) { + printk("Cyclades-Z/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no channels are available.\n"); + printk("Change NR_PORTS in cyclades.c and recompile kernel.\n"); + return(i); + } + + /* fill the next cy_card structure available */ + for (j = 0 ; j < NR_CARDS ; j++) { + if (cy_card[j].base_addr == 0) break; + } + if (j == NR_CARDS) { /* no more cy_cards available */ + printk("Cyclades-Z/PCI found at 0x%x ", + (unsigned int) cy_pci_addr2); + printk("but no more cards can be used.\n"); + printk("Change NR_CARDS in cyclades.c and recompile kernel.\n"); + return(i); + } + + /* allocate IRQ only if board has an IRQ */ + if( (1 < cy_pci_irq) && (cy_pci_irq < 15) ) { + if(request_irq(cy_pci_irq,cyz_interrupt, + SA_INTERRUPT,"cyclomZ",NULL)) + { + printk("Could not allocate IRQ%d ", + cy_pci_irq); + printk("for Cyclades-Z/PCI at 0x%x.\n", + (unsigned int) cy_pci_addr2); + return(i); + } + } + + /* set cy_card */ + cy_card[j].base_addr = cy_pci_addr2; + cy_card[j].ctl_addr = cy_pci_addr0; + cy_card[j].irq = (int) cy_pci_irq; + cy_card[j].bus_index = 1; + cy_card[j].first_line = cy_next_channel; + cy_card[j].num_chips = 1; + IRQ_cards[cy_pci_irq] = &cy_card[j]; + + /* print message */ + /* don't report IRQ if board is no IRQ */ + if( (cy_pci_irq < 15) && (cy_pci_irq > 1) ) { + printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, IRQ%d, ", + j+1,cy_pci_addr2, + (cy_pci_addr2 + CyPCI_Ze_win - 1), + (int)cy_pci_irq); + }else{ + printk("Cyclades-Z/PCI #%d: 0x%x-0x%x, ", + j+1,cy_pci_addr2, + (cy_pci_addr2 + CyPCI_Ze_win - 1)); + } + printk("%d channels starting from port %d.\n", + cy_pci_nchan,cy_next_channel); + cy_next_channel += cy_pci_nchan; + } + if (ZeIndex != 0) { + printk("Cyclades-Z/PCI found at 0x%x ", + (unsigned int) Ze_addr2[0]); + printk("but no more cards can be used.\n"); + printk("Change NR_CARDS in cyclades.c and recompile kernel.\n"); + } return(i); #else return(0); @@ -4319,6 +4550,8 @@ struct cyclades_card *cinfo; int number_z_boards = 0; int board,port,i; + unsigned long mailbox; + int nports; show_version(); @@ -4416,10 +4649,13 @@ /* initialize per-port data structures for each valid board found */ for (board = 0 ; board < cy_nboard ; board++) { cinfo = &cy_card[board]; - if (cinfo->num_chips == 1){ /* Cyclom-8Zo/PCI */ + if (cinfo->num_chips == 1){ /* Cyclades-8Zo/PCI */ number_z_boards++; + mailbox = ((struct RUNTIME_9060 *) + cy_card[board].ctl_addr)->mail_box_0; + nports = (mailbox == ZE_V1) ? ZE_V1_NPORTS : 8; for (port = cinfo->first_line ; - port < cinfo->first_line + 8; + port < cinfo->first_line + nports; port++) { info = &cy_port[port]; @@ -4523,7 +4759,7 @@ cyz_timerlist.expires = jiffies + 1; add_timer(&cyz_timerlist); #ifdef CY_PCI_DEBUG - printk("Cyclom-Z polling initialized\n"); + printk("Cyclades-Z polling initialized\n"); #endif } diff -u --recursive --new-file v2.1.44/linux/drivers/char/joystick.c linux/drivers/char/joystick.c --- v2.1.44/linux/drivers/char/joystick.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/joystick.c Wed Jul 16 19:22:50 1997 @@ -0,0 +1,376 @@ +/* + + linux/drivers/char/joystick.c + Copyright (C) 1992, 1993 Arthur C. Smith + Joystick driver for Linux running on an IBM compatible computer. + +VERSION INFO: +01/08/93 ACS 0.1: Works but needs multi-joystick support +01/13/93 ACS 0.2: Added multi-joystick support (minor 0 and 1) + Added delay between measuring joystick axis + Added scaling ioctl +02/16/93 ACS 0.3: Modified scaling to use ints to prevent kernel + panics 8-) +02/28/93 ACS 0.4: Linux99.6 and fixed race condition in js_read. + After looking at a schematic of a joystick card + it became apparent that any write to the joystick + port started ALL the joystick one shots. If the + one that we are reading is short enough and the + first one to be read, the second one will return + bad data if it's one shot has not expired when + the joystick port is written for the second time. + Thus solves the mystery delay problem in 0.2! +05/05/93 ACS/Eyal 0.5: Upgraded the driver to the 99.9 kernel, added + joystick support to the make config options, + updated the driver to return the buttons as + positive logic, and read both axis at once + (thanks Eyal!), and added some new ioctls. +02/12/94 Jeff Tranter 0.6: Made necessary changes to work with 0.99pl15 + kernel (and hopefully 1.0). Also did some + cleanup: indented code, fixed some typos, wrote + man page, etc... +05/17/95 Dan Fandrich 0.7.3: Added I/O port registration, cleaned up code +04/03/96 Matt Rhoten 0.8: many minor changes: + new read loop from Hal Maney + cleaned up #includes to allow #include of + joystick.h with gcc -Wall and from g++ + made js_init fail if it finds zero joysticks + general source/comment cleanup + use of MOD_(INC|DEC)_USE_COUNT + changes from Bernd Schmidt + to compile correctly under 1.3 in kernel or as module +06/30/97 Alan Cox 0.9: Ported to 2.1.x + Reformatted to resemble Linux coding standard + Removed semaphore bug (we can dump the lot I think) + Fixed xntp timer adjust during joystick timer0 bug + Changed variable names to lower case. Kept binary + compatibility. + Better ioctl names. Kept binary compatibility. + Removed 'save_busy'. Just set busy to 1. +*/ + +#include +#include +#include +#include +#include +#include +#include + +static struct js_config js_data[JS_MAX]; /* misc data */ +static int js_exist; /* which joysticks' axis exist? */ +static int js_read_semaphore; /* to prevent two processes from trying + to read different joysticks at the + same time */ + +/* + * get_timer0(): + * returns the current value of timer 0. This is a 16 bit counter that starts + * at LATCH and counts down to 0 + */ + +extern inline int get_timer0(void) +{ + unsigned long flags; + int t0, t1; + save_flags(flags); + cli(); + outb (0, PIT_MODE); + t0 = (int) inb (PIT_COUNTER_0); + t1 = ((int) inb (PIT_COUNTER_0) << 8) + t0; + restore_flags(flags); + return (t1); +} + +/* + * find_axes(): + * + * returns which axes are hooked up, in a bitfield. 2^n is set if + * axis n is hooked up, for 0 <= n < 4. + * + * REVIEW: should update this to handle eight-axis (four-stick) game port + * cards. anyone have one of these to test on? mattrh 3/23/96 + */ + +extern inline int find_axes(void) +{ + int j; + outb (0xff, JS_PORT); /* trigger oneshots */ + /* and see what happens */ + for (j = JS_DEF_TIMEOUT; (0x0f & inb (JS_PORT)) && j; j--); + /* do nothing; wait for the timeout */ + js_exist = inb (JS_PORT) & 0x0f; /* get joystick status byte */ + js_exist = (~js_exist) & 0x0f; +/* printk("find_axes: js_exist is %d (0x%04X)\n", js_exist, js_exist);*/ + return js_exist; +} + +static int js_ioctl (struct inode *inode, + struct file *file, + unsigned int cmd, + unsigned long arg) +{ + unsigned int minor = MINOR (inode->i_rdev); + if (minor >= JS_MAX) + return -ENODEV; + + if ((((inb (JS_PORT) & 0x0f) >> (minor << 1)) & 0x03) == 0x03) /*js minor exists?*/ + return -ENODEV; + switch (cmd) + { + + case JSIOCSCAL: /*from struct *arg to js_data[minor]*/ + if(copy_from_user(&js_data[minor].js_corr, + (void *)arg, sizeof(struct js_status))) + return -EFAULT; + break; + case JSIOCGCAL: /*to struct *arg from js_data[minor]*/ + if(copy_to_user((void *) arg, &js_data[minor].js_corr, + sizeof(struct js_status))) + return -EFAULT; + break; + case JSIOCSTIMEOUT: + if(copy_from_user(&js_data[minor].js_timeout, + (void *)arg, sizeof(js_data[0].js_timeout))) + return -EFAULT; + break; + case JSIOCGTIMEOUT: + if(copy_to_user((void *)arg, &js_data[minor].js_timeout, + sizeof(js_data[0].js_timeout))) + return -EFAULT; + break; + case JSIOCSTIMELIMIT: + if(copy_from_user(&js_data[minor].js_timelimit, + (void *)arg, sizeof(js_data[0].js_timelimit))) + return -EFAULT; + break; + case JSIOCGTIMELIMIT: + if(copy_to_user((void *)arg, &js_data[minor].js_timelimit, + sizeof(js_data[0].js_timelimit))) + return -EFAULT; + break; + case JSIOCGCONFIG: + if(copy_to_user((void *)arg, &js_data[minor], + sizeof(struct js_config))) + return -EFAULT; + break; + case JSIOCSCONFIG: + if(copy_from_user(&js_data[minor], (void *)arg, + sizeof(struct js_config))) + return -EFAULT; + /* Must be busy to do this ioctl! */ + js_data[minor].busy = 1; + break; + default: + return -EINVAL; + } + return 0; +} + +/* + * js_open(): + * device open routine. increments module usage count, initializes + * data for that joystick. + * + * returns: 0 or + * -ENODEV: asked for joystick other than #0 or #1 + * -ENODEV: asked for joystick on axis where there is none + * -EBUSY: attempt to open joystick already open + */ + +static int js_open (struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR (inode->i_rdev); + int j; + + if (minor >= JS_MAX) + return -ENODEV; /*check for joysticks*/ + + for (j = JS_DEF_TIMEOUT; (js_exist & inb (JS_PORT)) && j; j--); + cli(); /*block js_read while js_exist is being modified*/ + /*js minor exists?*/ + if ((((js_exist = inb (JS_PORT)) >> (minor << 1)) & 0x03) == 0x03) { + js_exist = (~js_exist) & 0x0f; + sti(); + return -ENODEV; + } + js_exist = (~js_exist) & 0x0f; + sti(); + + if (js_data[minor].busy) + return -EBUSY; + js_data[minor].busy = JS_TRUE; + js_data[minor].js_corr.x = JS_DEF_CORR; /*default scale*/ + js_data[minor].js_corr.y = JS_DEF_CORR; + js_data[minor].js_timeout = JS_DEF_TIMEOUT; + js_data[minor].js_timelimit = JS_DEF_TIMELIMIT; + js_data[minor].js_expiretime = jiffies; + + MOD_INC_USE_COUNT; + return 0; +} + +static int js_release (struct inode *inode, struct file *file) +{ + unsigned int minor = MINOR (inode->i_rdev); + inode->i_atime = CURRENT_TIME; + js_data[minor].busy = JS_FALSE; + MOD_DEC_USE_COUNT; + return 0; +} + +/* + * js_read() reads the buttons x, and y axis from both joysticks if a + * given interval has expired since the last read or is equal to + * -1l. The buttons are in port 0x201 in the high nibble. The axis are + * read by writing to 0x201 and then measuring the time it takes the + * one shots to clear. + */ + +static long js_read (struct inode *inode, struct file *file, char *buf, unsigned long count) +{ + int j, chk, jsmask; + int t0, t_x0, t_y0, t_x1, t_y1; + unsigned int minor, minor2; + int buttons; + + if (count != JS_RETURN) + return -EINVAL; + minor = MINOR (inode->i_rdev); + inode->i_atime = CURRENT_TIME; + if (jiffies >= js_data[minor].js_expiretime) + { + minor2 = minor << 1; + j = js_data[minor].js_timeout; + for (; (js_exist & inb (JS_PORT)) && j; j--); + if (j == 0) + return -ENODEV; /*no joystick here*/ + /*Make sure no other proc is using port*/ + + cli(); + js_read_semaphore++; + sti(); + + buttons = ~(inb (JS_PORT) >> 4); + js_data[0].js_save.buttons = buttons & 0x03; + js_data[1].js_save.buttons = (buttons >> 2) & 0x03; + j = js_data[minor].js_timeout; + jsmask = 0; + + cli(); /*no interrupts!*/ + outb (0xff, JS_PORT); /*trigger one-shots*/ + /*get init timestamp*/ + t_x0 = t_y0 = t_x1 = t_y1 = t0 = get_timer0 (); + /*wait for an axis' bit to clear or timeout*/ + while (j-- && (chk = (inb (JS_PORT) & js_exist ) | jsmask)) + { + if (!(chk & JS_X_0)) { + t_x0 = get_timer0(); + jsmask |= JS_X_0; + } + if (!(chk & JS_Y_0)) { + t_y0 = get_timer0(); + jsmask |= JS_Y_0; + } + if (!(chk & JS_X_1)) { + t_x1 = get_timer0(); + jsmask |= JS_X_1; + } + if (!(chk & JS_Y_1)) { + t_y1 = get_timer0(); + jsmask |= JS_Y_1; + } + } + sti(); /* allow interrupts */ + + js_read_semaphore = 0; /* allow other reads to progress */ + if (j == 0) + return -ENODEV; /*read timed out*/ + js_data[0].js_expiretime = jiffies + + js_data[0].js_timelimit; /*update data*/ + js_data[1].js_expiretime = jiffies + + js_data[1].js_timelimit; + js_data[0].js_save.x = DELTA_TIME (t0, t_x0) >> + js_data[0].js_corr.x; + js_data[0].js_save.y = DELTA_TIME (t0, t_y0) >> + js_data[0].js_corr.y; + js_data[1].js_save.x = DELTA_TIME (t0, t_x1) >> + js_data[1].js_corr.x; + js_data[1].js_save.y = DELTA_TIME (t0, t_y1) >> + js_data[1].js_corr.y; + } + + if(copy_to_user(buf, &js_data[minor].js_save, JS_RETURN)) + return -EFAULT; + return JS_RETURN; +} + + +static struct file_operations js_fops = +{ + NULL, /* js_lseek*/ + js_read, /* js_read */ + NULL, /* js_write*/ + NULL, /* js_readaddr*/ + NULL, /* js_select */ + js_ioctl, /* js_ioctl*/ + NULL, /* js_mmap */ + js_open, /* js_open*/ + js_release, /* js_release*/ + NULL /* js_fsync */ +}; + +#ifdef MODULE + +#define joystick_init init_module + +void cleanup_module (void) +{ + if (unregister_chrdev (JOYSTICK_MAJOR, "joystick")) + printk ("joystick: cleanup_module failed\n"); + release_region(JS_PORT, 1); +} + +#endif /* MODULE */ + +int joystick_init(void) +{ + int js_num; + int js_count; + + if (check_region(JS_PORT, 1)) { + printk("js_init: port already in use\n"); + return -EBUSY; + } + + js_num = find_axes(); + js_count = !!(js_num & 0x3) + !!(js_num & 0xC); + + + if (js_count == 0) + { + printk("No joysticks found.\n"); + return -ENODEV; + /* if the user boots the machine, which runs insmod, and THEN + decides to hook up the joystick, well, then we do the wrong + thing. But it's a good idea to avoid giving out a false sense + of security by letting the module load otherwise. */ + } + + if (register_chrdev (JOYSTICK_MAJOR, "joystick", &js_fops)) { + printk ("Unable to get major=%d for joystick\n", + JOYSTICK_MAJOR); + return -EBUSY; + } + request_region(JS_PORT, 1, "joystick"); + + for (js_num = 0; js_num < JS_MAX; js_num++) + js_data[js_num].busy = JS_FALSE; + js_read_semaphore = 0; + + printk (KERN_INFO "Found %d joystick%c.\n", + js_count, + (js_num == 1) ? ' ' : 's'); + return 0; +} + diff -u --recursive --new-file v2.1.44/linux/drivers/char/lp.c linux/drivers/char/lp.c --- v2.1.44/linux/drivers/char/lp.c Thu May 29 21:53:05 1997 +++ linux/drivers/char/lp.c Wed Jul 16 19:22:50 1997 @@ -724,7 +724,11 @@ return 0; printk(KERN_INFO "lp: driver loaded but no devices found\n"); +#ifdef MODULE + return 0; +#else return 1; +#endif } #ifdef MODULE diff -u --recursive --new-file v2.1.44/linux/drivers/char/mem.c linux/drivers/char/mem.c --- v2.1.44/linux/drivers/char/mem.c Mon Jun 16 16:35:55 1997 +++ linux/drivers/char/mem.c Wed Jul 16 19:22:50 1997 @@ -20,6 +20,7 @@ #include #include #include +#include #include #include @@ -134,8 +135,7 @@ #endif if (remap_page_range(vma->vm_start, offset, vma->vm_end - vma->vm_start, vma->vm_page_prot)) return -EAGAIN; - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + vma->vm_dentry = dget(file->f_dentry); return 0; } @@ -532,6 +532,13 @@ #ifdef CONFIG_SOUND soundcard_init(); #endif +#ifdef CONFIG_JOYSTICK + /* + * Some joysticks only appear when the soundcard they are + * connected too is confgured. Keep the sound/joystick ordering. + */ + joystick_init(); +#endif #if CONFIG_QIC02_TAPE qic02_tape_init(); #endif diff -u --recursive --new-file v2.1.44/linux/drivers/char/misc.c linux/drivers/char/misc.c --- v2.1.44/linux/drivers/char/misc.c Mon Jun 16 16:35:55 1997 +++ linux/drivers/char/misc.c Wed Jul 16 19:22:50 1997 @@ -215,6 +215,9 @@ #ifdef CONFIG_SUN_MOUSE sun_mouse_init(); #endif +#ifdef CONFIG_PC110_PAD + pc110pad_init(); +#endif /* * Only one watchdog can succeed. We probe the pcwatchdog first, * then the wdt cards and finally the software watchdog which always diff -u --recursive --new-file v2.1.44/linux/drivers/char/n_tty.c linux/drivers/char/n_tty.c --- v2.1.44/linux/drivers/char/n_tty.c Thu Jun 26 12:33:38 1997 +++ linux/drivers/char/n_tty.c Wed Jul 16 19:22:50 1997 @@ -706,7 +706,7 @@ return; tty->icanon = (L_ICANON(tty) != 0); - if (tty->flags & (1<flags)) { tty->raw = 1; tty->real_raw = 1; return; @@ -854,7 +854,7 @@ /* NOTE: not yet done after every sleep pending a thorough check of the logic of this change. -- jlc */ /* don't stop on /dev/console */ - if (file->f_inode->i_rdev != CONSOLE_DEV && + if (file->f_dentry->d_inode->i_rdev != CONSOLE_DEV && current->tty == tty) { if (tty->pgrp <= 0) printk("read_chan: tty->pgrp <= 0!\n"); @@ -912,7 +912,7 @@ tty->minimum_to_wake = (minimum - (b - buf)); if (!input_available_p(tty, 0)) { - if (tty->flags & (1 << TTY_OTHER_CLOSED)) { + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) { retval = -EIO; break; } @@ -1013,7 +1013,7 @@ int retval = 0; /* Job control check -- must be done at start (POSIX.1 7.1.1.4). */ - if (L_TOSTOP(tty) && file->f_inode->i_rdev != CONSOLE_DEV) { + if (L_TOSTOP(tty) && file->f_dentry->d_inode->i_rdev != CONSOLE_DEV) { retval = tty_check_change(tty); if (retval) return retval; @@ -1030,7 +1030,7 @@ retval = -EIO; break; } - if (O_OPOST(tty) && !(tty->flags & (1<flags))) { while (nr > 0) { num = opost_block(tty, b, nr); b += num; @@ -1072,7 +1072,7 @@ mask |= POLLIN | POLLRDNORM; if (tty->packet && tty->link->ctrl_status) mask |= POLLPRI | POLLIN | POLLRDNORM; - if (tty->flags & (1 << TTY_OTHER_CLOSED)) + if (test_bit(TTY_OTHER_CLOSED, &tty->flags)) mask |= POLLHUP; if (tty_hung_up_p(file)) mask |= POLLHUP; diff -u --recursive --new-file v2.1.44/linux/drivers/char/pc110pad.c linux/drivers/char/pc110pad.c --- v2.1.44/linux/drivers/char/pc110pad.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/pc110pad.c Wed Jul 16 19:22:50 1997 @@ -0,0 +1,690 @@ +/* + * Linux driver for the PC110 pad + * + * The pad provides triples of data. The first byte has + * 0x80=bit 8 X, 0x01=bit 7 X, 0x08=bit 8 Y, 0x01=still down + * The second byte is bits 0-6 X + * The third is bits 0-6 Y + * + * This is read internally and used to synthesize a stream of + * triples in the form expected from a PS/2 device. + * + * 0.0 1997-05-16 Alan Cox - Pad reader + * 0.1 1997-05-19 Robin O'Leary - PS/2 emulation + * 0.2 1997-06-03 Robin O'Leary - tap gesture + * 0.3 1997-06-27 Alan Cox - 2.1 commit + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "pc110pad.h" + + +static struct pc110pad_params default_params = { + PC110PAD_PS2, /* read mode */ + 50 MS, /* bounce interval */ + 200 MS, /* tap interval */ + 10, /* IRQ */ + 0x15E0, /* I/O port */ +}; + + +static struct pc110pad_params current_params; + + +/* driver/filesystem interface management */ +static struct wait_queue *queue; +static struct fasync_struct *asyncptr; +static int active=0; /* number of concurrent open()s */ + + +/* + * Utility to reset a timer to go off some time in the future. + */ + +static void set_timer_callback(struct timer_list *timer, int ticks) +{ + del_timer(timer); + timer->expires = jiffies+ticks; + add_timer(timer); +} + + +/* + * Take care of letting any waiting processes know that + * now would be a good time to do a read(). Called + * whenever a state transition occurs, real or synthetic. + */ + +static void wake_readers(void) +{ + wake_up_interruptible(&queue); + if(asyncptr) + kill_fasync(asyncptr, SIGIO); +} + + +/*****************************************************************************/ +/* + * Deal with the messy business of synthesizing button tap and drag + * events. + * + * Exports: + * notify_pad_up_down() + * Must be called whenever debounced pad up/down state changes. + * button_pending + * Flag is set whenever read_button() has new values + * to return. + * read_button() + * Obtains the current synthetic mouse button state. + */ + +/* + * These keep track of up/down transitions needed to generate the + * synthetic mouse button events. While recent_transition is set, + * up/down events cause transition_count to increment. tap_timer + * turns off the recent_transition flag and may cause some synthetic + * up/down mouse events to be created by incrementing synthesize_tap. + */ + +static int button_pending=0; +static int recent_transition=0; +static int transition_count=0; +static int synthesize_tap=0; +static void tap_timeout(unsigned long data); +static struct timer_list tap_timer = { NULL, NULL, 0, 0, tap_timeout }; + + +/* + * This callback goes off a short time after an up/down transition; + * before it goes off, transitions will be considered part of a + * single PS/2 event and counted in transition_count. Once the + * timeout occurs the recent_transition flag is cleared and + * any synthetic mouse up/down events are generated. + */ + +static void tap_timeout(unsigned long data) +{ + if(!recent_transition) + { + printk("pc110pad: tap_timeout but no recent transition!\n"); + } + if( transition_count==2 || transition_count==4 || transition_count==6 ) + { + synthesize_tap+=transition_count; + button_pending = 1; + wake_readers(); + } + recent_transition=0; +} + + +/* + * Called by the raw pad read routines when a (debounced) up/down + * transition is detected. + */ + +void notify_pad_up_down(void) +{ + if(recent_transition) + { + transition_count++; + } + else + { + transition_count=1; + recent_transition=1; + } + set_timer_callback(&tap_timer, current_params.tap_interval); + + /* changes to transition_count can cause reported button to change */ + button_pending = 1; + wake_readers(); +} + + +static void read_button(int *b) +{ + if(synthesize_tap) + { + *b=--synthesize_tap & 1; + } + else + { + *b=(!recent_transition && transition_count==3); /* drag */ + } + button_pending=(synthesize_tap>0); +} + + +/*****************************************************************************/ +/* + * Read pad absolute co-ordinates and debounced up/down state. + * + * Exports: + * pad_irq() + * Function to be called whenever the pad signals + * that it has new data available. + * read_raw_pad() + * Returns the most current pad state. + * xy_pending + * Flag is set whenever read_raw_pad() has new values + * to return. + * Imports: + * wake_readers() + * Called when movement occurs. + * notify_pad_up_down() + * Called when debounced up/down status changes. + */ + +/* + * These are up/down state and absolute co-ords read directly from pad + */ + +static int raw_data[3]; +static int raw_data_count=0; +static int raw_x=0, raw_y=0; /* most recent absolute co-ords read */ +static int raw_down=0; /* raw up/down state */ +static int debounced_down=0; /* up/down state after debounce processing */ +static enum { NO_BOUNCE, JUST_GONE_UP, JUST_GONE_DOWN } bounce=NO_BOUNCE; + /* set just after an up/down transition */ +static int xy_pending=0; /* set if new data have not yet been read */ + +/* + * Timer goes off a short while after an up/down transition and copies + * the value of raw_down to debounced_down. + */ + +static void bounce_timeout(unsigned long data); +static struct timer_list bounce_timer = { NULL, NULL, 0, 0, bounce_timeout }; + + +static void bounce_timeout(unsigned long data) +{ + /* + * No further up/down transitions happened within the + * bounce period, so treat this as a genuine transition. + */ + switch(bounce) + { + case NO_BOUNCE: + { + /* + * Strange; the timer callback should only go off if + * we were expecting to do bounce processing! + */ + printk("pc110pad, bounce_timeout: bounce flag not set!\n"); + break; + } + case JUST_GONE_UP: + { + /* + * The last up we spotted really was an up, so set + * debounced state the same as raw state. + */ + bounce=NO_BOUNCE; + if(debounced_down==raw_down) + { + printk("pc110pad, bounce_timeout: raw already debounced!\n"); + } + debounced_down=raw_down; + + notify_pad_up_down(); + break; + } + case JUST_GONE_DOWN: + { + /* + * We don't debounce down events, but we still time + * out soon after one occurs so we can avoid the (x,y) + * skittering that sometimes happens. + */ + bounce=NO_BOUNCE; + break; + } + } +} + + +/* + * Callback when pad's irq goes off; copies values in to raw_* globals; + * initiates debounce processing. + */ +static void pad_irq(int irq, void *ptr, struct pt_regs *regs) +{ + + /* Obtain byte from pad and prime for next byte */ + { + int value=inb_p(current_params.io); + int handshake=inb_p(current_params.io+2); + outb_p(handshake | 1, current_params.io+2); + outb_p(handshake &~1, current_params.io+2); + inb_p(0x64); + + raw_data[raw_data_count++]=value; + } + + if(raw_data_count==3) + { + int new_down=raw_data[0]&0x01; + int new_x=raw_data[1]; + int new_y=raw_data[2]; + if(raw_data[0]&0x10) new_x+=128; + if(raw_data[0]&0x80) new_x+=256; + if(raw_data[0]&0x08) new_y+=128; + + if( (raw_x!=new_x) || (raw_y!=new_y) ) + { + raw_x=new_x; + raw_y=new_y; + xy_pending=1; + } + + if(new_down != raw_down) + { + /* Down state has changed. raw_down always holds + * the most recently observed state. + */ + raw_down=new_down; + + /* Forget any earlier bounce processing */ + if(bounce) + { + del_timer(&bounce_timer); + bounce=NO_BOUNCE; + } + + if(new_down) + { + if(debounced_down) + { + /* pad gone down, but we were reporting + * it down anyway because we suspected + * (correctly) that the last up was just + * a bounce + */ + } + else + { + bounce=JUST_GONE_DOWN; + set_timer_callback(&bounce_timer, + current_params.bounce_interval); + /* start new stroke/tap */ + debounced_down=new_down; + notify_pad_up_down(); + } + } + else /* just gone up */ + { + if(recent_transition) + { + /* early bounces are probably part of + * a multi-tap gesture, so process + * immediately + */ + debounced_down=new_down; + notify_pad_up_down(); + } + else + { + /* don't trust it yet */ + bounce=JUST_GONE_UP; + set_timer_callback(&bounce_timer, + current_params.bounce_interval); + } + } + } + wake_readers(); + raw_data_count=0; + } +} + + +static void read_raw_pad(int *down, int *debounced, int *x, int *y) +{ + disable_irq(current_params.irq); + { + *down=raw_down; + *debounced=debounced_down; + *x=raw_x; + *y=raw_y; + xy_pending = 0; + } + enable_irq(current_params.irq); +} + +/*****************************************************************************/ +/* + * Filesystem interface + */ + +/* + * Read returns byte triples, so we need to keep track of + * how much of a triple has been read. This is shared across + * all processes which have this device open---not that anything + * will make much sense in that case. + */ +static int read_bytes[3]; +static int read_byte_count=0; + + + +static void sample_raw(int d[3]) +{ + d[0]=raw_data[0]; + d[1]=raw_data[1]; + d[2]=raw_data[2]; +} + + +static void sample_rare(int d[3]) +{ + int thisd, thisdd, thisx, thisy; + + read_raw_pad(&thisd, &thisdd, &thisx, &thisy); + + d[0]=(thisd?0x80:0) + | (thisx/256)<<4 + | (thisdd?0x08:0) + | (thisy/256) + ; + d[1]=thisx%256; + d[2]=thisy%256; +} + + +static void sample_debug(int d[3]) +{ + int thisd, thisdd, thisx, thisy; + int b; + cli(); + read_raw_pad(&thisd, &thisdd, &thisx, &thisy); + d[0]=(thisd?0x80:0) | (thisdd?0x40:0) | bounce; + d[1]=(recent_transition?0x80:0)+transition_count; + read_button(&b); + d[2]=(synthesize_tap<<4) | (b?0x01:0); + sti(); +} + + +static void sample_ps2(int d[3]) +{ + static int lastx, lasty, lastd; + + int thisd, thisdd, thisx, thisy; + int dx, dy, b; + + /* + * Obtain the current mouse parameters and limit as appropriate for + * the return data format. Interrupts are only disabled while + * obtaining the parameters, NOT during the puts_fs_byte() calls, + * so paging in put_user() does not affect mouse tracking. + */ + read_raw_pad(&thisd, &thisdd, &thisx, &thisy); + read_button(&b); + + /* Now compare with previous readings. Note that we use the + * raw down flag rather than the debounced one. + */ + if( (thisd && !lastd) /* new stroke */ + || (bounce!=NO_BOUNCE) ) + { + dx=0; + dy=0; + } + else + { + dx = (thisx-lastx); + dy = -(thisy-lasty); + } + lastx=thisx; + lasty=thisy; + lastd=thisd; + +/* + d[0]= ((dy<0)?0x20:0) + | ((dx<0)?0x10:0) + | 0x08 + | (b? 0x01:0x00) + ; +*/ + d[0]= ((dy<0)?0x20:0) + | ((dx<0)?0x10:0) + | (b? 0x00:0x08) + ; + d[1]=dx; + d[2]=dy; +} + + + +static int fasync_pad(struct inode *inode, struct file *filp, int on) +{ + int retval; + + retval = fasync_helper(inode, filp, on, &asyncptr); + if (retval < 0) + return retval; + return 0; +} + + +/* + * close access to the pad + */ +static int close_pad(struct inode * inode, struct file * file) +{ + fasync_pad(inode, file, 0); + if (--active) + return; + outb(0x30, current_params.io+2); /* switch off digitiser */ + MOD_DEC_USE_COUNT; + return 0; +} + + +/* + * open access to the pad + */ +static int open_pad(struct inode * inode, struct file * file) +{ + if (active++) + return 0; + MOD_INC_USE_COUNT; + + cli(); + outb(0x30, current_params.io+2); /* switch off digitiser */ + pad_irq(0,0,0); /* read to flush any pending bytes */ + pad_irq(0,0,0); /* read to flush any pending bytes */ + pad_irq(0,0,0); /* read to flush any pending bytes */ + outb(0x38, current_params.io+2); /* switch on digitiser */ + current_params = default_params; + raw_data_count=0; /* re-sync input byte counter */ + read_byte_count=0; /* re-sync output byte counter */ + button_pending=0; + recent_transition=0; + transition_count=0; + synthesize_tap=0; + del_timer(&bounce_timer); + del_timer(&tap_timer); + sti(); + + return 0; +} + + +/* + * writes are disallowed + */ +static long write_pad(struct inode * inode, struct file * file, const char * buffer, unsigned long count) +{ + return -EINVAL; +} + + +void new_sample(int d[3]) +{ + switch(current_params.mode) + { + case PC110PAD_RAW: sample_raw(d); break; + case PC110PAD_RARE: sample_rare(d); break; + case PC110PAD_DEBUG: sample_debug(d); break; + case PC110PAD_PS2: sample_ps2(d); break; + } +} + + +/* + * Read pad data. Currently never blocks. + */ +static long read_pad(struct inode * inode, struct file * file, char * buffer, unsigned long count) +{ + int r; + + for(r=0; rPC110PAD_PS2) + || (new.bounce_interval<0) + || (new.tap_interval<0) + ) + return -EINVAL; + + current_params.mode = new.mode; + current_params.bounce_interval = new.bounce_interval; + current_params.tap_interval = new.tap_interval; + return 0; + } + return -ENOIOCTLCMD; +} + + +static struct file_operations pad_fops = { + NULL, /* pad_seek */ + read_pad, + write_pad, + NULL, /* pad_readdir */ + pad_poll, + pad_ioctl, + NULL, /* pad_mmap */ + open_pad, + close_pad, + NULL, /* fsync */ + fasync_pad, + NULL, /* check_media_change */ + NULL, /* revalidate */ + NULL /* lock */ +}; + + +static struct miscdevice pc110_pad = { + PC110PAD_MINOR, "pc110 pad", &pad_fops +}; + + +static int pc110pad_init(void) +{ + current_params = default_params; + + if(request_irq(current_params.irq, pad_irq, 0, "pc110pad", 0)) + { + printk("pc110pad: Unable to get IRQ.\n"); + return -EBUSY; + } + if(check_region(current_params.io, 4)) + { + printk("pc110pad: I/O area in use.\n"); + free_irq(current_params.irq,0); + return -EBUSY; + } + request_region(current_params.io, 4, "pc110pad"); + printk("PC110 digitizer pad at 0x%X, irq %d.\n", + current_params.io,current_params.irq); + misc_register(&pc110_pad); + outb(0x30, current_params.io+2); /* switch off digitiser */ + + return 0; +} + +#ifdef MODULE + +static void pc110pad_unload(void) +{ + outb(0x30, current_params.io+2); /* switch off digitiser */ + if(current_params.irq) + free_irq(current_params.irq, 0); + current_params.irq=0; + release_region(current_params.io, 4); + misc_deregister(&pc110_pad); +} + + + +int init_module(void) +{ + return pc110pad_init(); +} + +void cleanup_module(void) +{ + pc110pad_unload(); +} +#endif diff -u --recursive --new-file v2.1.44/linux/drivers/char/pc110pad.h linux/drivers/char/pc110pad.h --- v2.1.44/linux/drivers/char/pc110pad.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/char/pc110pad.h Wed Jul 16 19:22:50 1997 @@ -0,0 +1,31 @@ +#ifndef _PC110PAD_H +#define _PC110PAD_H + +#include + +enum pc110pad_mode { + PC110PAD_RAW, /* bytes as they come out of the hardware */ + PC110PAD_RARE, /* debounced up/down and absolute x,y */ + PC110PAD_DEBUG, /* up/down, debounced, transitions, button */ + PC110PAD_PS2, /* ps2 relative (default) */ +}; + + +struct pc110pad_params { + enum pc110pad_mode mode; + int bounce_interval; + int tap_interval; + int irq; + int io; +}; + +#define MS *HZ/1000 + +/* Appears as device major=10 (MISC), minor=PC110_PAD */ + +#define PC110PAD_IOCTL_TYPE 0x9a + +#define PC110PADIOCGETP _IOR(PC110PAD_IOCTL_TYPE, 0, struct pc110pad_params) +#define PC110PADIOCSETP _IOR(PC110PAD_IOCTL_TYPE, 1, struct pc110pad_params) + +#endif /* _PC110PAD_H */ diff -u --recursive --new-file v2.1.44/linux/drivers/char/psaux.c linux/drivers/char/psaux.c --- v2.1.44/linux/drivers/char/psaux.c Fri Jul 4 23:33:56 1997 +++ linux/drivers/char/psaux.c Thu Jul 10 17:06:47 1997 @@ -168,6 +168,11 @@ outb_p(val, KBD_DATA_REG); /* Write data */ } +/* + * Write to device & handle returned ack + */ + +#ifdef INITIALIZE_DEVICE __initfunc(static void aux_write_dev_nosleep(int val)) { poll_aux_status_nosleep(); @@ -176,11 +181,6 @@ outb_p(val, KBD_DATA_REG); } -/* - * Write to device & handle returned ack - */ - -#ifdef INITIALIZE_DEVICE __initfunc(static int aux_write_ack(int val)) { aux_write_dev_nosleep(val); diff -u --recursive --new-file v2.1.44/linux/drivers/char/random.c linux/drivers/char/random.c --- v2.1.44/linux/drivers/char/random.c Mon Jul 7 08:24:28 1997 +++ linux/drivers/char/random.c Tue Jul 8 16:28:45 1997 @@ -1125,8 +1125,7 @@ * update the access time. */ if (inode && count != 0) { - inode->i_atime = CURRENT_TIME; - inode->i_dirt = 1; + UPDATE_ATIME(inode); } return (count ? count : retval); @@ -1182,7 +1181,7 @@ } if ((ret > 0) && inode) { inode->i_mtime = CURRENT_TIME; - inode->i_dirt = 1; + mark_inode_dirty(inode); } return ret; } diff -u --recursive --new-file v2.1.44/linux/drivers/char/rtc.c linux/drivers/char/rtc.c --- v2.1.44/linux/drivers/char/rtc.c Mon Jul 7 08:24:28 1997 +++ linux/drivers/char/rtc.c Wed Jul 16 19:22:50 1997 @@ -180,7 +180,9 @@ data = rtc_irq_data; rtc_irq_data = 0; restore_flags(flags); - retval = put_user(data, (unsigned long *)buf) ?: sizeof(unsigned long); + retval = put_user(data, (unsigned long *)buf); + if (!retval) + retval = sizeof(unsigned long); } current->state = TASK_RUNNING; @@ -262,7 +264,6 @@ * "don't care" or "match all". Only the tm_hour, * tm_min and tm_sec are used. */ - int retval; unsigned char hrs, min, sec; struct rtc_time alm_tm; @@ -305,7 +306,6 @@ } case RTC_SET_TIME: /* Set the RTC */ { - int retval; struct rtc_time rtc_tm; unsigned char mon, day, hrs, min, sec, leap_yr; unsigned char save_control, save_freq_select; @@ -418,7 +418,7 @@ default: return -EINVAL; } - return copy_to_user(arg, &wtime, sizeof wtime) ? -EFAULT : 0; + return copy_to_user((void *)arg, &wtime, sizeof wtime) ? -EFAULT : 0; } /* diff -u --recursive --new-file v2.1.44/linux/drivers/char/tty_io.c linux/drivers/char/tty_io.c --- v2.1.44/linux/drivers/char/tty_io.c Sat Jun 28 10:31:36 1997 +++ linux/drivers/char/tty_io.c Wed Jul 16 19:22:50 1997 @@ -373,13 +373,15 @@ for (filp = inuse_filps; filp; filp = filp->f_next) { if (filp->private_data != tty) continue; - if (!filp->f_inode) + if (!filp->f_dentry) continue; - if (filp->f_inode->i_rdev == CONSOLE_DEV) + if (!filp->f_dentry->d_inode) + continue; + if (filp->f_dentry->d_inode->i_rdev == CONSOLE_DEV) continue; if (filp->f_op != &tty_fops) continue; - tty_fasync(filp->f_inode, filp, 0); + tty_fasync(filp->f_dentry->d_inode, filp, 0); filp->f_op = fops; } @@ -387,7 +389,7 @@ tty->ldisc.flush_buffer(tty); if (tty->driver.flush_buffer) tty->driver.flush_buffer(tty); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); @@ -536,7 +538,7 @@ } if (tty->driver.start) (tty->driver.start)(tty); - if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) && tty->ldisc.write_wakeup) (tty->ldisc.write_wakeup)(tty); wake_up_interruptible(&tty->write_wait); @@ -551,7 +553,7 @@ tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode->i_rdev, "tty_read")) return -EIO; - if (!tty || (tty->flags & (1 << TTY_IO_ERROR))) + if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; /* This check not only needs to be done before reading, but also @@ -633,7 +635,7 @@ tty = (struct tty_struct *)file->private_data; if (tty_paranoia_check(tty, inode->i_rdev, "tty_write")) return -EIO; - if (!tty || !tty->driver.write || (tty->flags & (1 << TTY_IO_ERROR))) + if (!tty || !tty->driver.write || (test_bit(TTY_IO_ERROR, &tty->flags))) return -EIO; #if 0 if (!is_console && L_TOSTOP(tty) && (tty->pgrp > 0) && @@ -822,7 +824,7 @@ * opens on a pty master. */ fast_track: - if (tty->flags & (1 << TTY_CLOSING)) { + if (test_bit(TTY_CLOSING, &tty->flags)) { retval = -EIO; goto end_init; } @@ -919,12 +921,12 @@ int idx; tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "release_dev")) + if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "release_dev")) return; check_tty_count(tty, "release_dev"); - tty_fasync(filp->f_inode, filp, 0); + tty_fasync(filp->f_dentry->d_inode, filp, 0); idx = MINOR(tty->device) - tty->driver.minor_start; pty_master = (tty->driver.type == TTY_DRIVER_TYPE_PTY && @@ -1069,9 +1071,9 @@ * to close, and TTY_CLOSING makes sure we can't be reopened. */ if(tty_closing) - tty->flags |= (1 << TTY_CLOSING); + set_bit(TTY_CLOSING, &tty->flags); if(o_tty_closing) - o_tty->flags |= (1 << TTY_CLOSING); + set_bit(TTY_CLOSING, &o_tty->flags); /* * If _either_ side is closing, make sure there aren't any @@ -1248,7 +1250,7 @@ struct tty_struct * tty; tty = (struct tty_struct *)filp->private_data; - if (tty_paranoia_check(tty, filp->f_inode->i_rdev, "tty_poll")) + if (tty_paranoia_check(tty, filp->f_dentry->d_inode->i_rdev, "tty_poll")) return 0; if (tty->ldisc.poll) diff -u --recursive --new-file v2.1.44/linux/drivers/net/8390.c linux/drivers/net/8390.c --- v2.1.44/linux/drivers/net/8390.c Wed Apr 23 19:01:18 1997 +++ linux/drivers/net/8390.c Sun Jul 13 09:28:11 1997 @@ -186,6 +186,7 @@ /* Mask interrupts from the ethercard. */ outb_p(0x00, e8390_base + EN0_IMR); + synchronize_irq(); if (dev->interrupt) { printk("%s: Tx request while isr active.\n",dev->name); outb_p(ENISR_ALL, e8390_base + EN0_IMR); diff -u --recursive --new-file v2.1.44/linux/drivers/net/Config.in linux/drivers/net/Config.in --- v2.1.44/linux/drivers/net/Config.in Mon Jul 7 08:19:59 1997 +++ linux/drivers/net/Config.in Wed Jul 16 19:22:50 1997 @@ -84,6 +84,7 @@ tristate 'Digi Intl. RightSwitch SE-X support' CONFIG_DGRS tristate 'EtherExpressPro/100 support' CONFIG_EEXPRESS_PRO100 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + tristate 'TI ThunderLAN support (EXPERIMENTAL)' CONFIG_TLAN tristate 'Racal-Interlan EISA ES3210 support (EXPERIMENTAL)' CONFIG_ES3210 bool 'Zenith Z-Note support (EXPERIMENTAL)' CONFIG_ZNET fi @@ -151,12 +152,14 @@ bool 'Soundmodem support for 2400 baud AFSK modulation (8MHz crystal)' CONFIG_SOUNDMODEM_AFSK2400_8 bool 'Soundmodem support for 4800 baud HAPN-1 modulation' CONFIG_SOUNDMODEM_HAPN4800 bool 'Soundmodem support for 9600 baud FSK G3RUH modulation' CONFIG_SOUNDMODEM_FSK9600 - if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then - bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666 - fi - if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then - bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800 - fi +# if [ -f doesn't work with xconfig. Enable it again when the drivers are really +# included. +# if [ -f drivers/net/soundmodem/sm_afsk2666.c ]; then +# bool 'Soundmodem support for 2666 baud AFSK modulation' CONFIG_SOUNDMODEM_AFSK2666 +# fi +# if [ -f drivers/net/soundmodem/sm_psk4800.c ]; then +# bool 'Soundmodem support for 4800 baud PSK modulation' CONFIG_SOUNDMODEM_PSK4800 +# fi fi fi tristate 'STRIP (Metricom starmode radio IP)' CONFIG_STRIP diff -u --recursive --new-file v2.1.44/linux/drivers/net/Makefile linux/drivers/net/Makefile --- v2.1.44/linux/drivers/net/Makefile Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/Makefile Wed Jul 16 19:22:50 1997 @@ -391,6 +391,14 @@ endif endif +ifeq ($(CONFIG_TLAN),y) +L_OBJS += tlan.o +else + ifeq ($(CONFIG_TLAN),m) + M_OBJS += tlan.o + endif +endif + ifeq ($(CONFIG_ZNET),y) L_OBJS += znet.o endif @@ -793,7 +801,7 @@ sdladrv.o: sdladrv.c CONFIG wanpipe.o: $(WANPIPE_OBJS) - ld -r -o $@ $^ + ld -r -o $@ $(WANPIPE_OBJS) sdlamain.o: sdlamain.c CONFIG diff -u --recursive --new-file v2.1.44/linux/drivers/net/README.wanpipe linux/drivers/net/README.wanpipe --- v2.1.44/linux/drivers/net/README.wanpipe Sun Feb 2 05:18:36 1997 +++ linux/drivers/net/README.wanpipe Wed Jul 16 19:22:50 1997 @@ -1,10 +1,10 @@ ------------------------------------------------------------------------------ WANPIPE(tm) Multiprotocol WAN Driver for Linux WAN Router ------------------------------------------------------------------------------ -Release 3.0.0 -December 31, 1996 +Release 3.1.0 +January 30, 1997 Author: Gene Kozin -Copyright (c) 1995-1996 Sangoma Technologies Inc. +Copyright (c) 1995-1997 Sangoma Technologies Inc. ------------------------------------------------------------------------------ INTRODUCTION @@ -80,6 +80,12 @@ REVISION HISTORY + +3.1.0 January 30, 1997 + + o Implemented IOCTL for executing adapter commands. + o Fixed a bug in frame relay code causing driver configured as a FR + switch to be stuck in WAN_DISCONNECTED mode. 3.0.0 December 31, 1996 diff -u --recursive --new-file v2.1.44/linux/drivers/net/Space.c linux/drivers/net/Space.c --- v2.1.44/linux/drivers/net/Space.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/net/Space.c Wed Jul 16 19:22:50 1997 @@ -89,6 +89,7 @@ extern int a2065_probe(struct device *); extern int ariadne_probe(struct device *); extern int hydra_probe(struct device *); +extern int tlan_probe(struct device *); extern int cs89x0_probe(struct device *dev); /* Detachable devices ("pocket adaptors") */ @@ -241,6 +242,9 @@ #endif #ifdef CONFIG_SUNLANCE && sparc_lance_probe(dev) +#endif +#ifdef CONFIG_TLAN + && tlan_probe(dev) #endif #ifdef CONFIG_HAPPYMEAL && happy_meal_probe(dev) diff -u --recursive --new-file v2.1.44/linux/drivers/net/cops.c linux/drivers/net/cops.c --- v2.1.44/linux/drivers/net/cops.c Mon Jul 7 08:19:59 1997 +++ linux/drivers/net/cops.c Wed Jul 16 19:22:50 1997 @@ -40,6 +40,7 @@ * the driver figure it out. */ +#include #ifdef MODULE #include #include diff -u --recursive --new-file v2.1.44/linux/drivers/net/ibmtr.c linux/drivers/net/ibmtr.c --- v2.1.44/linux/drivers/net/ibmtr.c Sat May 24 09:10:23 1997 +++ linux/drivers/net/ibmtr.c Wed Jul 16 19:22:50 1997 @@ -55,7 +55,10 @@ * + completed multiple adapter support. (November 20 1996) * + implemented csum_partial_copy in tr_rx and increased receive * buffer size and count. Minor fixes. (March 15, 1997) -*/ + * + * Changes by Christopher Turcksin + * + Now compiles ok as a module again. + */ #ifdef PCMCIA #define MODULE @@ -163,9 +166,9 @@ int ibmtr_probe(struct device *dev); static int ibmtr_probe1(struct device *dev, int ioaddr); -unsigned char get_sram_size(struct tok_info *adapt_info); +static unsigned char get_sram_size(struct tok_info *adapt_info); static int tok_init_card(struct device *dev); -int trdev_init(struct device *dev); +static int trdev_init(struct device *dev); void tok_interrupt(int irq, void *dev_id, struct pt_regs *regs); static void initial_tok_int(struct device *dev); static void open_sap(unsigned char type,struct device *dev); @@ -1583,7 +1586,7 @@ dev_ibmtr[i]->init = &ibmtr_probe; if (register_trdev(dev_ibmtr[i]) != 0) { - kfree_s(dev_ibmtr[i], sizeof(struct dev)); + kfree_s(dev_ibmtr[i], sizeof(struct device)); dev_ibmtr[i] = NULL; if (i == 0) { printk("ibmtr: register_trdev() returned non-zero.\n"); diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdla_fr.c linux/drivers/net/sdla_fr.c --- v2.1.44/linux/drivers/net/sdla_fr.c Tue May 13 22:41:09 1997 +++ linux/drivers/net/sdla_fr.c Wed Jul 16 19:22:50 1997 @@ -10,6 +10,49 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* +* Jun 29, 1997 Alan Cox o Hacked up vendor source 1.0.3 to remove +* C++ style comments, and a massive security +* hole (the UDP management junk). +* +* May 29, 1997 Jaspreet Singh o Fixed major Flow Control Problem +* With multiple boards a problem was seen where +* the second board always stopped transmitting +* packet after running for a while. The code +* got into a stage where the interrupts were +* disabled and dev->tbusy was set to 1. +* This caused the If_send() routine to get into +* the if clause for set_bit(0,dev->tbusy) +* forever. +* The code got into this stage due to an +* interrupt occuring within the if clause for +* set_bit(0,dev->tbusy). Since an interrupt +* disables furhter transmit interrupt and +* makes dev->tbusy = 0, this effect was undone +* by making dev->tbusy = 1 in the if clause. +* The Fix checks to see if Transmit interrupts +* are disabled then do not make dev->tbusy = 1 +* Introduced a global variable: int_occur and +* added tx_int_enabled in the wan_device +* structure. +* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple +* boards. +* +* Apr 25, 1997 Farhan Thawar o added UDP Management stuff +* o fixed bug in if_send() and tx_intr() to +* sleep and wakeup all devices +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o fixed (+1) bug in fr508_rx_intr() +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* o added tx_intr() routine +* Jan 30, 1997 Gene Kozin Version 3.1.0 +* o implemented exec() entry point +* o fixed a bug causing driver configured as +* a FR switch to be stuck in WAN_DISCONNECTED +* mode * Jan 02, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -22,12 +65,13 @@ #include /* return codes */ #include /* inline memset(), etc. */ #include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ +#include /* WAN router definitions */ #include /* WANPIPE common user API definitions */ #include /* ARPHRD_* defines */ #include /* __initfunc et al. */ #include /* htons(), etc. */ #include /* for inb(), outb(), etc. */ +#include #define _GNUC_ #include /* frame relay firmware API definitions */ @@ -67,6 +111,9 @@ unsigned char state PACKED; } dlci_status_t; +static char TracingEnabled; +/* variable for checking interrupts within the ISR routine */ +static int int_occur = 0; /****** Function Prototypes *************************************************/ /* WAN link driver entry points. These are called by the WAN router module. */ @@ -75,14 +122,16 @@ wanif_conf_t* conf); static int del_if (wan_device_t* wandev, struct device* dev); +/* WANPIPE-specific entry points */ +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data); + /* Network device interface */ static int if_init (struct device* dev); static int if_open (struct device* dev); static int if_close (struct device* dev); static int if_header (struct sk_buff* skb, struct device* dev, unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb); +static int if_rebuild_hdr (struct sk_buff* skb); static int if_send (struct sk_buff* skb, struct device* dev); static struct enet_statistics* if_stats (struct device* dev); @@ -103,6 +152,8 @@ static int fr_set_intr_mode (sdla_t* card, unsigned mode, unsigned mtu); static int fr_comm_enable (sdla_t* card); static int fr_comm_disable (sdla_t* card); +static int fr_get_err_stats (sdla_t* card); +static int fr_get_stats (sdla_t* card); static int fr_add_dlci (sdla_t* card, int dlci, int num); static int fr_activate_dlci (sdla_t* card, int dlci, int num); static int fr_issue_isf (sdla_t* card, int isf); @@ -120,7 +171,6 @@ static struct device* find_channel (sdla_t* card, unsigned dlci); static int is_tx_ready (sdla_t* card); static unsigned int dec_to_uint (unsigned char* str, int len); -static unsigned int hex_to_uint (unsigned char* str, int len); /****** Public Functions ****************************************************/ @@ -198,7 +248,7 @@ u.cfg.n392 = 3; u.cfg.n393 = 4; u.cfg.kbps = conf->bps / 1000; - u.cfg.cir_fwd = max(min(u.cfg.kbps, 512), 1); + u.cfg.cir_fwd = 16; u.cfg.cir_bwd = u.cfg.bc_fwd = u.cfg.bc_bwd = u.cfg.cir_fwd; u.cfg.options = 0x0081; /* direct Rx, no CIR check */ switch (conf->u.fr.signalling) @@ -214,7 +264,7 @@ { u.cfg.station = 1; /* switch emulation mode */ card->u.f.node_dlci = conf->u.fr.dlci ? conf->u.fr.dlci : 16; - card->u.f.dlci_num = max(min(conf->u.fr.dlci_num, 1), 100); + card->u.f.dlci_num = min(max(conf->u.fr.dlci_num, 1), 100); } if (conf->clocking == WANOPT_INTERNAL) u.cfg.port |= 0x0001 @@ -270,11 +320,14 @@ card->wandev.clocking = conf->clocking; card->wandev.station = conf->station; card->poll = &wpf_poll; + card->exec = &wpf_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; card->wandev.state = WAN_DISCONNECTED; - return 0; + card->wandev.udp_port = conf->udp_port; + TracingEnabled = '0'; + return 0; } /******* WAN Device Driver Entry Points *************************************/ @@ -284,9 +337,22 @@ */ static int update (wan_device_t* wandev) { -/* - sdla_t* card = wandev->private; -*/ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT + ; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV + ; + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN + ; + card = wandev->private; + fr_get_err_stats(card); + fr_get_stats(card); + wandev->critical = 0; return 0; } @@ -377,6 +443,43 @@ return 0; } +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ +static int wpf_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, len; + fr_cmd_t cmd; + + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + /* execute command */ + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + if (cmd.length) + if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) + return -EFAULT; + if (sdla_exec(mbox)) + err = mbox->cmd.result; + else + return -EIO; + } + while (err && retry-- && fr_event(card, err, mbox)); + + /* return result */ + if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(fr_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) + return -EFAULT; + return 0; +} + /****** Network Device Interface ********************************************/ /*============================================================================ @@ -416,6 +519,9 @@ dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; + /* Set transmit buffer queue length */ + dev->tx_queue_len = 30; + /* Initialize socket buffers */ for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]) @@ -451,12 +557,14 @@ err = -EIO; goto done; } + wanpipe_set_state(card, WAN_CONNECTED); + if (card->wandev.station == WANOPT_CPE) { /* CPE: issue full status enquiry */ fr_issue_isf(card, FR_ISF_FSE); } - else /* Switch: activate DLCI(s) */ + else /* FR switch: activate DLCI(s) */ { fr_add_dlci(card, card->u.f.node_dlci, card->u.f.dlci_num) @@ -465,7 +573,6 @@ card->u.f.node_dlci, card->u.f.dlci_num) ; } - wanpipe_set_state(card, WAN_CONNECTED); } dev->mtu = min(dev->mtu, card->wandev.mtu - FR_HEADER_LEN); dev->interrupt = 0; @@ -538,14 +645,13 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - fr_channel_t* chan = dev->priv; + fr_channel_t* chan = skb->dev->priv; sdla_t* card = chan->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name) + card->devname, skb->dev->name) ; return 1; } @@ -570,10 +676,11 @@ */ static int if_send (struct sk_buff* skb, struct device* dev) { - fr_channel_t* chan = dev->priv; - sdla_t* card = chan->card; - int retry = 0; - + fr_channel_t *chan = dev->priv; + sdla_t *card = chan->card; + int retry=0, err; + struct device *dev2; + if (test_and_set_bit(0, (void*)&card->wandev.critical)) { #ifdef _DEBUG_ @@ -581,7 +688,8 @@ card->devname) ; #endif - return 1; + dev_kfree_skb(skb, FREE_WRITE); + return 0; } if (test_and_set_bit(0, (void*)&dev->tbusy)) @@ -592,23 +700,55 @@ ; #endif ++chan->ifstats.collisions; + ++card->wandev.stats.collisions; + retry = 1; + if(card->wandev.tx_int_enabled) + { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + dev2->tbusy = 1; + } + } + } + else if (card->wandev.state != WAN_CONNECTED) + { + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + else if (chan->state != WAN_CONNECTED) + { + update_chan_state(dev); + ++chan->ifstats.tx_dropped; + ++card->wandev.stats.tx_dropped; + } + else if (!is_tx_ready(card)) + { + retry = 1; + if(card->wandev.tx_int_enabled) + { + for (dev2 = card->wandev.dev; dev2; dev2 = dev2->slave) + { + dev2->tbusy = 1; + } + } } - else if ((card->wandev.state != WAN_CONNECTED) || - (chan->state != WAN_CONNECTED)) - ++chan->ifstats.tx_dropped - ; - else if (!is_tx_ready(card)) - retry = 1 - ; else { - int err = (card->hw.fwid == SFID_FR508) ? + err = (card->hw.fwid == SFID_FR508) ? fr508_send(card, chan->dlci, 0, skb->len, skb->data) : fr502_send(card, chan->dlci, 0, skb->len, skb->data) ; - if (err) ++chan->ifstats.tx_errors; - else ++chan->ifstats.tx_packets; + if (err) + { + ++chan->ifstats.tx_errors; + ++card->wandev.stats.tx_errors; + } + else + { + ++chan->ifstats.tx_packets; + ++card->wandev.stats.tx_packets; + } } if (!retry) { @@ -619,6 +759,7 @@ return retry; } + /*============================================================================ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. @@ -663,7 +804,14 @@ { fr508_flags_t* flags = card->flags; fr_buf_ctl_t* bctl; - + + if(int_occur){ +#ifdef _DEBUG_ + printk(KERN_INFO "%s:Interrupt Occurred within an ISR\n",card->devname); +#endif + return; + } + int_occur=1; switch (flags->iflag) { case 0x01: /* receive interrupt */ @@ -681,6 +829,7 @@ default: spur_intr(card); } + int_occur = 0; flags->iflag = 0; } @@ -690,13 +839,14 @@ static void fr502_rx_intr (sdla_t* card) { fr_mbox_t* mbox = card->rxmb; - struct sk_buff* skb; - struct device* dev; - fr_channel_t* chan; + struct sk_buff *skb; + struct device *dev; + fr_channel_t *chan; unsigned dlci, len; void* buf; - + sdla_mapmem(&card->hw, FR502_RX_VECTOR); + dlci = mbox->cmd.dlci; len = mbox->cmd.length; @@ -741,13 +891,14 @@ /* can't decapsulate packet */ dev_kfree_skb(skb, FREE_READ); ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; } else { netif_rx(skb); ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; } - rx_done: sdla_mapmem(&card->hw, FR_MB_VECTOR); } @@ -763,7 +914,7 @@ fr_channel_t* chan; unsigned dlci, len, offs; void* buf; - + if (frbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", @@ -804,9 +955,9 @@ } /* Copy data to the socket buffer */ - if ((offs + len) > card->u.f.rx_top) + if ((offs + len) > card->u.f.rx_top + 1) { - unsigned tmp = card->u.f.rx_top - offs; + unsigned tmp = card->u.f.rx_top - offs + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, offs, buf, tmp); @@ -814,8 +965,7 @@ len -= tmp; } buf = skb_put(skb, len); - sdla_peek(&card->hw, offs, buf, len); - + sdla_peek(&card->hw, offs, buf, len); /* Decapsulate packet and pass it up the protocol stack */ skb->dev = dev; buf = skb_pull(skb, 1); /* remove hardware header */ @@ -824,13 +974,14 @@ /* can't decapsulate packet */ dev_kfree_skb(skb, FREE_READ); ++chan->ifstats.rx_errors; + ++card->wandev.stats.rx_errors; } else { netif_rx(skb); ++chan->ifstats.rx_packets; + ++card->wandev.stats.rx_packets; } - rx_done: /* Release buffer element and calculate a pointer to the next one */ frbuf->flag = 0; @@ -848,7 +999,17 @@ */ static void tx_intr (sdla_t* card) { + struct device* dev = card->wandev.dev; + + for (; dev; dev = dev->slave) { + if( !dev || !dev->start ) continue; + dev->tbusy = 0; + dev_tint(dev); + } + card->wandev.tx_int_enabled = 0; +/* printk(KERN_INFO "%s: transmit interrupt!\n", card->devname); +*/ } /*============================================================================ @@ -877,8 +1038,14 @@ */ static void wpf_poll (sdla_t* card) { - fr502_flags_t* flags = card->flags; + static unsigned long last_poll; + fr502_flags_t* flags; + + if ((jiffies - last_poll) < HZ) + return + ; + flags = card->flags; if (flags->event) { fr_mbox_t* mbox = card->mbox; @@ -889,6 +1056,7 @@ err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; if (err) fr_event(card, err, mbox); } + last_poll = jiffies; } /****** Frame Relay Firmware-Specific Functions *****************************/ @@ -1025,6 +1193,65 @@ } /*============================================================================ + * Get communications error statistics. + */ +static int fr_get_err_stats (sdla_t* card) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_ERROR_STATS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_comm_stat_t* stats = (void*)mbox->data; + + card->wandev.stats.rx_over_errors = stats->rx_overruns; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_aborts; + card->wandev.stats.rx_length_errors = stats->rx_too_long; + card->wandev.stats.tx_aborted_errors = stats->tx_aborts; + } + return err; +} + +/*============================================================================ + * Get statistics. + */ +static int fr_get_stats (sdla_t* card) +{ + fr_mbox_t* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(fr_cmd_t)); + mbox->cmd.command = FR_READ_STATISTICS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } + while (err && retry-- && fr_event(card, err, mbox)); + + if (!err) + { + fr_link_stat_t* stats = (void*)mbox->data; + + card->wandev.stats.rx_frame_errors = stats->rx_bad_format; + card->wandev.stats.rx_dropped = + stats->rx_dropped + stats->rx_dropped2 + ; + } + return err; +} + +/*============================================================================ * Add DLCI(s) (Access Node only!). */ static int fr_add_dlci (sdla_t* card, int dlci, int num) @@ -1363,6 +1590,7 @@ if (sb & 0x02) return 1; flags->imask |= 0x02; + card->wandev.tx_int_enabled = 1; } else { @@ -1386,29 +1614,6 @@ for (val = 0; len && is_digit(*str); ++str, --len) val = (val * 10) + (*str - (unsigned)'0') ; - return val; -} - -/*============================================================================ - * Convert hex string to unsigned integer. - * If len != 0 then only 'len' characters of the string are conferted. - */ -static unsigned int hex_to_uint (unsigned char* str, int len) -{ - unsigned val, ch; - - if (!len) len = strlen(str); - for (val = 0; len; ++str, --len) - { - ch = *str; - if (is_digit(ch)) - val = (val << 4) + (ch - (unsigned)'0') - ; - else if (is_hex_digit(ch)) - val = (val << 4) + ((ch & 0xDF) - (unsigned)'A' + 10) - ; - else break; - } return val; } diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdla_ppp.c linux/drivers/net/sdla_ppp.c --- v2.1.44/linux/drivers/net/sdla_ppp.c Tue May 13 22:41:11 1997 +++ linux/drivers/net/sdla_ppp.c Wed Jul 16 19:22:51 1997 @@ -10,6 +10,25 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Jun 29, 1997 Alan Cox o Dumped the idiot UDP management system. +* +* May 22, 1997 Jaspreet Singh o Added change in the PPP_SET_CONFIG command for +* 508 card to reflect changes in the new +* ppp508.sfm for supporting:continous transmission +* of Configure-Request packets without receiving a +* reply +* OR-ed 0x300 to conf_flags +* o Changed connect_tmout from 900 to 0 +* May 21, 1997 Jaspreet Singh o Fixed UDP Management for multiple boards +* Apr 25, 1997 Farhan Thawar o added UDP Management stuff +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o fixed (+1) bug in rx_intr() +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o implemented exec() entry point * Jan 06, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -22,11 +41,12 @@ #include /* return codes */ #include /* inline memset(), etc. */ #include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ +#include /* WAN router definitions */ #include /* WANPIPE common user API definitions */ #include /* ARPHRD_* defines */ #include /* __initfunc et al. */ #include /* htons(), etc. */ +#include #define _GNUC_ #include /* PPP firmware API definitions */ @@ -57,14 +77,16 @@ wanif_conf_t* conf); static int del_if (wan_device_t* wandev, struct device* dev); +/* WANPIPE-specific entry points */ +static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data); + /* Network device interface */ static int if_init (struct device* dev); static int if_open (struct device* dev); static int if_close (struct device* dev); static int if_header (struct sk_buff* skb, struct device* dev, unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb); +static int if_rebuild_hdr (struct sk_buff* skb); static int if_send (struct sk_buff* skb, struct device* dev); static struct enet_statistics* if_stats (struct device* dev); @@ -74,6 +96,7 @@ static int ppp_set_intr_mode (sdla_t* card, unsigned mode); static int ppp_comm_enable (sdla_t* card); static int ppp_comm_disable (sdla_t* card); +static int ppp_get_err_stats (sdla_t* card); static int ppp_send (sdla_t* card, void* data, unsigned len, unsigned proto); static int ppp_error (sdla_t *card, int err, ppp_mbox_t* mb); @@ -94,6 +117,7 @@ static void show_disc_cause (sdla_t* card, unsigned cause); static unsigned char bps_to_speed_code (unsigned long bps); +static char TracingEnabled; /****** Public Functions ****************************************************/ /*============================================================================ @@ -163,10 +187,13 @@ card->wandev.station = conf->station; card->isr = &wpp_isr; card->poll = &wpp_poll; + card->exec = &wpp_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; card->wandev.state = WAN_DISCONNECTED; + card->wandev.udp_port = conf->udp_port; + TracingEnabled = '0'; return 0; } @@ -177,9 +204,22 @@ */ static int update (wan_device_t* wandev) { -/* - sdla_t* card = wandev->private; -*/ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT + ; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV + ; + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN + ; + card = wandev->private; + + ppp_get_err_stats(card); + wandev->critical = 0; return 0; } @@ -228,6 +268,38 @@ return 0; } +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ +static int wpp_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + ppp_mbox_t* mbox = card->mbox; + int len; + + if(copy_from_user((void*)&mbox->cmd, u_cmd, sizeof(ppp_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len) + { + if(copy_from_user((void*)&mbox->data, u_data, len)) + return -EFAULT; + } + + /* execute command */ + if (!sdla_exec(mbox)) + return -EIO; + + /* return result */ + if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(ppp_cmd_t))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data && copy_to_user(u_data, (void*)&mbox->data, len)) + return -EFAULT; + return 0; +} + /****** Network Device Interface ********************************************/ /*============================================================================ @@ -264,6 +336,9 @@ dev->mem_start = wandev->maddr; dev->mem_end = wandev->maddr + wandev->msize - 1; + /* Set transmit buffer queue length */ + dev->tx_queue_len = 30; + /* Initialize socket buffers */ for (i = 0; i < DEV_NUMBUFFS; ++i) skb_queue_head_init(&dev->buffs[i]) @@ -408,13 +483,12 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - sdla_t* card = dev->priv; + sdla_t* card = skb->dev->priv; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name) + card->devname, skb->dev->name) ; return 1; } @@ -460,8 +534,7 @@ #endif ++card->wandev.stats.collisions; retry = 1; - } - else if (card->wandev.state != WAN_CONNECTED) + } else if (card->wandev.state != WAN_CONNECTED) ++card->wandev.stats.tx_dropped ; else if (!skb->protocol) @@ -489,6 +562,7 @@ * Get ethernet-style interface statistics. * Return a pointer to struct enet_statistics. */ + static struct enet_statistics* if_stats (struct device* dev) { sdla_t* card = dev->priv; @@ -599,6 +673,31 @@ } /*============================================================================ + * Get communications error statistics. + */ +static int ppp_get_err_stats (sdla_t* card) +{ + ppp_mbox_t* mb = card->mbox; + int err; + + memset(&mb->cmd, 0, sizeof(ppp_cmd_t)); + mb->cmd.command = PPP_READ_ERROR_STATS; + err = sdla_exec(mb) ? mb->cmd.result : CMD_TIMEOUT; + if (err == CMD_OK) + { + ppp_err_stats_t* stats = (void*)mb->data; + + card->wandev.stats.rx_over_errors = stats->rx_overrun; + card->wandev.stats.rx_crc_errors = stats->rx_bad_crc; + card->wandev.stats.rx_missed_errors = stats->rx_abort; + card->wandev.stats.rx_length_errors = stats->rx_lost; + card->wandev.stats.tx_aborted_errors = stats->tx_abort; + } + else ppp_error(card, err, mb); + return err; +} + +/*============================================================================ * Send packet. * Return: 0 - o.k. * 1 - no transmit buffers available @@ -701,7 +800,7 @@ struct sk_buff* skb; unsigned len; void* buf; - + if (rxbuf->flag != 0x01) { printk(KERN_INFO "%s: corrupted Rx buffer @ 0x%X!\n", @@ -738,9 +837,9 @@ { unsigned addr = rxbuf->buf.ptr; - if ((addr + len) > card->u.p.rx_top) + if ((addr + len) > card->u.p.rx_top + 1) { - unsigned tmp = card->u.p.rx_top - addr; + unsigned tmp = card->u.p.rx_top - addr + 1; buf = skb_put(skb, tmp); sdla_peek(&card->hw, addr, buf, tmp); @@ -751,8 +850,8 @@ sdla_peek(&card->hw, addr, buf, len); } - /* Decapsulate packet and pass it up the protocol stack */ - switch (rxbuf->proto) + /* Decapsulate packet */ + switch (rxbuf->proto) { case 0x00: skb->protocol = htons(ETH_P_IP); @@ -762,10 +861,11 @@ skb->protocol = htons(ETH_P_IPX); break; } + + /* Pass it up the protocol stack */ skb->dev = dev; netif_rx(skb); ++card->wandev.stats.rx_packets; - rx_done: /* Release buffer element and calculate a pointer to the next one */ rxbuf->flag = (card->hw.fwid == SFID_PPP502) ? 0xFF : 0x00; @@ -891,13 +991,14 @@ cfg.auth_wait_tmr = 300; cfg.mdm_fail_tmr = 5; cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 900; + cfg.connect_tmout = 0; /* changed it from 900 */ cfg.conf_retry = 10; cfg.term_retry = 2; cfg.fail_retry = 5; cfg.auth_retry = 10; cfg.ip_options = 0x80; cfg.ipx_options = 0xA0; + cfg.conf_flags |= 0x0E; /* cfg.ip_local = dev->pa_addr; cfg.ip_remote = dev->pa_dstaddr; @@ -921,6 +1022,7 @@ if (card->wandev.interface == WANOPT_RS232) cfg.conf_flags |= 0x0020; ; + cfg.conf_flags |= 0x300; /*send Configure-Request packets forever*/ cfg.txbuf_percent = 60; /* % of Tx bufs */ cfg.mtu_local = card->wandev.mtu; cfg.mtu_remote = card->wandev.mtu; @@ -929,7 +1031,7 @@ cfg.auth_wait_tmr = 300; cfg.mdm_fail_tmr = 5; cfg.dtr_drop_tmr = 1; - cfg.connect_tmout = 900; + cfg.connect_tmout = 0; /* changed it from 900 */ cfg.conf_retry = 10; cfg.term_retry = 2; cfg.fail_retry = 5; diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdla_x25.c linux/drivers/net/sdla_x25.c --- v2.1.44/linux/drivers/net/sdla_x25.c Tue May 13 22:41:11 1997 +++ linux/drivers/net/sdla_x25.c Wed Jul 16 19:22:51 1997 @@ -10,6 +10,17 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. * ============================================================================ +* Mar 11, 1997 Farhan Thawar Version 3.1.1 +* o added support for V35 +* o changed if_send() to return 0 if +* wandev.critical() is true +* o free socket buffer in if_send() if +* returning 0 +* o added support for single '@' address to +* accept all incoming calls +* o fixed bug in set_chan_state() to disconnect +* Jan 15, 1997 Gene Kozin Version 3.1.0 +* o implemented exec() entry point * Jan 07, 1997 Gene Kozin Initial version. *****************************************************************************/ @@ -22,10 +33,11 @@ #include /* return codes */ #include /* inline memset(), etc. */ #include /* kmalloc(), kfree() */ -#include /* WAN router definitions */ +#include /* WAN router definitions */ #include /* WANPIPE common user API definitions */ #include /* __initfunc et al. */ #include /* htons(), etc. */ +#include /* copy_from_user, etc */ #define _GNUC_ #include /* X.25 firmware API definitions */ @@ -90,14 +102,16 @@ wanif_conf_t* conf); static int del_if (wan_device_t* wandev, struct device* dev); +/* WANPIPE-specific entry points */ +static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data); + /* Network device interface */ static int if_init (struct device* dev); static int if_open (struct device* dev); static int if_close (struct device* dev); static int if_header (struct sk_buff* skb, struct device* dev, unsigned short type, void* daddr, void* saddr, unsigned len); -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb); +static int if_rebuild_hdr (struct sk_buff* skb); static int if_send (struct sk_buff* skb, struct device* dev); static struct enet_statistics* if_stats (struct device* dev); @@ -118,6 +132,8 @@ /* X.25 firmware interface functions */ static int x25_get_version (sdla_t* card, char* str); static int x25_configure (sdla_t* card, TX25Config* conf); +static int x25_get_err_stats (sdla_t* card); +static int x25_get_stats (sdla_t* card); static int x25_set_intr_mode (sdla_t* card, int mode); static int x25_close_hdlc (sdla_t* card); static int x25_open_hdlc (sdla_t* card); @@ -235,7 +251,9 @@ { u.cfg.station = 0; /* DCE mode */ } - + if (conf->interface != WANOPT_RS232 ) { + u.cfg.hdlcOptions |= 0x80; /* V35 mode */ + } /* adjust MTU */ if (!conf->mtu || (conf->mtu >= 1024)) card->wandev.mtu = 1024 @@ -299,6 +317,7 @@ card->wandev.station = conf->station; card->isr = &wpx_isr; card->poll = &wpx_poll; + card->exec = &wpx_exec; card->wandev.update = &update; card->wandev.new_if = &new_if; card->wandev.del_if = &del_if; @@ -313,9 +332,23 @@ */ static int update (wan_device_t* wandev) { -/* - sdla_t* card = wandev->private; -*/ + sdla_t* card; + + /* sanity checks */ + if ((wandev == NULL) || (wandev->private == NULL)) + return -EFAULT + ; + if (wandev->state == WAN_UNCONFIGURED) + return -ENODEV + ; + if (test_and_set_bit(0, (void*)&wandev->critical)) + return -EAGAIN + ; + card = wandev->private; + + x25_get_err_stats(card); + x25_get_stats(card); + wandev->critical = 0; return 0; } @@ -412,6 +445,45 @@ return 0; } +/****** WANPIPE-specific entry points ***************************************/ + +/*============================================================================ + * Execute adapter interface command. + */ +static int wpx_exec (struct sdla* card, void* u_cmd, void* u_data) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err, len; + TX25Cmd cmd; + + if(copy_from_user((void*)&cmd, u_cmd, sizeof(cmd))) + return -EFAULT; + + /* execute command */ + do + { + memcpy(&mbox->cmd, &cmd, sizeof(cmd)); + if (cmd.length) + if(copy_from_user((void*)&mbox->data, u_data, cmd.length)) + return -EFAULT; + if (sdla_exec(mbox)) + err = mbox->cmd.result; + else + return -EIO; + } + while (err && retry-- && x25_error(card, err, cmd.command, cmd.lcn)); + + /* return result */ + if(copy_to_user(u_cmd, (void*)&mbox->cmd, sizeof(TX25Cmd))) + return -EFAULT; + len = mbox->cmd.length; + if (len && u_data) + if(copy_to_user(u_data, (void*)&mbox->data, len)) + return -EFAULT; + return 0; +} + /****** Network Device Interface ********************************************/ /*============================================================================ @@ -555,14 +627,13 @@ * Return: 1 physical address resolved. * 0 physical address not resolved */ -static int if_rebuild_hdr (void* hdr, struct device* dev, unsigned long raddr, - struct sk_buff* skb) +static int if_rebuild_hdr (struct sk_buff* skb) { - x25_channel_t* chan = dev->priv; + x25_channel_t* chan = skb->dev->priv; sdla_t* card = chan->card; printk(KERN_INFO "%s: rebuild_header() called for interface %s!\n", - card->devname, dev->name) + card->devname, skb->dev->name) ; return 1; } @@ -588,7 +659,7 @@ { x25_channel_t* chan = dev->priv; sdla_t* card = chan->card; - int retry = 0, queued = 0; + int queued = 0; if (test_and_set_bit(0, (void*)&card->wandev.critical)) { @@ -597,7 +668,8 @@ card->devname) ; #endif - return 1; + dev_kfree_skb(skb, FREE_WRITE); + return 0; } if (test_and_set_bit(0, (void*)&dev->tbusy)) @@ -608,7 +680,10 @@ ; #endif ++chan->ifstats.collisions; - retry = 1; + ++card->wandev.stats.collisions; + dev_kfree_skb(skb, FREE_WRITE); + card->wandev.critical = 0; + return 0; } else if (chan->protocol && (chan->protocol != skb->protocol)) { @@ -646,13 +721,13 @@ ++chan->ifstats.tx_dropped; } - if (!retry && !queued) + if (!queued) { dev_kfree_skb(skb, FREE_WRITE); dev->tbusy = 0; } card->wandev.critical = 0; - return retry; + return 0; } /*============================================================================ @@ -996,6 +1071,62 @@ } /*============================================================================ + * Get communications error statistics. + */ +static int x25_get_err_stats (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_HDLC_READ_COMM_ERR; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_HDLC_READ_COMM_ERR, 0)) + ; + if (!err) + { + THdlcCommErr* stats = (void*)mbox->data; + + card->wandev.stats.rx_over_errors = stats->rxOverrun; + card->wandev.stats.rx_crc_errors = stats->rxBadCrc; + card->wandev.stats.rx_missed_errors = stats->rxAborted; + card->wandev.stats.tx_aborted_errors = stats->txAborted; + } + return err; +} + +/*============================================================================ + * Get protocol statistics. + */ +static int x25_get_stats (sdla_t* card) +{ + TX25Mbox* mbox = card->mbox; + int retry = MAX_CMD_RETRY; + int err; + + do + { + memset(&mbox->cmd, 0, sizeof(TX25Cmd)); + mbox->cmd.command = X25_READ_STATISTICS; + err = sdla_exec(mbox) ? mbox->cmd.result : CMD_TIMEOUT; + } while (err && retry-- && + x25_error(card, err, X25_READ_STATISTICS, 0)) + ; + if (!err) + { + TX25Stats* stats = (void*)mbox->data; + + card->wandev.stats.rx_packets = stats->rxData; + card->wandev.stats.tx_packets = stats->rxData; + } + return err; +} + +/*============================================================================ * Close HDLC link. */ static int x25_close_hdlc (sdla_t* card) @@ -1478,6 +1609,10 @@ if (strcmp(info->src, chan->addr) == 0) break ; + // If just an '@' is specified, accept all incomming calls + if (strcmp(chan->addr, "") == 0) + break + ; } if (dev == NULL) @@ -1755,9 +1890,10 @@ printk (KERN_INFO "%s: interface %s disconnected!\n", card->devname, dev->name) ; - if (chan->svc) - *(unsigned short*)dev->dev_addr = 0 - ; + if (chan->svc) { + *(unsigned short*)dev->dev_addr = 0; + chan->lcn = 0; + } break; } chan->state = state; diff -u --recursive --new-file v2.1.44/linux/drivers/net/sdlamain.c linux/drivers/net/sdlamain.c --- v2.1.44/linux/drivers/net/sdlamain.c Tue May 13 22:41:11 1997 +++ linux/drivers/net/sdlamain.c Wed Jul 16 19:22:51 1997 @@ -26,9 +26,10 @@ #include /* support for loadable modules */ #include /* request_region(), release_region() */ #include /* for kernel task queues */ -#include /* WAN router definitions */ +#include /* WAN router definitions */ #include /* WANPIPE common user API definitions */ -#include /* kernel <-> user copy */ +#include /* kernel <-> user copy */ + /****** Defines & Macros ****************************************************/ @@ -404,20 +405,13 @@ unsigned long oldvec; /* DPM window vector */ int err = 0; - if ((u_dump == NULL) || - verify_area(VERIFY_READ, u_dump, sizeof(sdla_dump_t))) - return -EFAULT - ; - memcpy_fromfs((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t)); + if(copy_from_user((void*)&dump, (void*)u_dump, sizeof(sdla_dump_t))) + return -EFAULT; + if ((dump.magic != WANPIPE_MAGIC) || (dump.offset + dump.length > card->hw.memory)) - return -EINVAL - ; - if ((dump.ptr == NULL) || - verify_area(VERIFY_WRITE, dump.ptr, dump.length)) - return -EFAULT - ; - + return -EINVAL; + winsize = card->hw.dpmsize; cli(); /* >>> critical section start <<< */ oldvec = card->hw.vector; @@ -433,9 +427,12 @@ err = -EIO; break; } - memcpy_tofs((void*)(dump.ptr), - (void*)(card->hw.dpmbase + pos), len) - ; + /* FIXME::: COPY TO KERNEL BUFFER FIRST ?? */ + sti(); /* Not ideal but tough we have to do this */ + if(copy_to_user((void*)(dump.ptr), + (void*)(card->hw.dpmbase + pos), len)) + return -EFAULT; + cli(); dump.length -= len; dump.offset += len; (char*)dump.ptr += len; @@ -456,16 +453,12 @@ sdla_exec_t exec; if (card->exec == NULL) - return -ENODEV - ; - if ((u_exec == NULL) || - verify_area(VERIFY_READ, u_exec, sizeof(sdla_exec_t))) - return -EFAULT - ; - memcpy_fromfs((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t)); + return -ENODEV; + + if(copy_from_user((void*)&exec, (void*)u_exec, sizeof(sdla_exec_t))) + return -EFAULT; if ((exec.magic != WANPIPE_MAGIC) || (exec.cmd == NULL)) - return -EINVAL - ; + return -EINVAL; return card->exec(card, exec.cmd, exec.data); } diff -u --recursive --new-file v2.1.44/linux/drivers/net/shaper.c linux/drivers/net/shaper.c --- v2.1.44/linux/drivers/net/shaper.c Wed Apr 23 19:01:20 1997 +++ linux/drivers/net/shaper.c Wed Jul 16 19:22:51 1997 @@ -70,11 +70,11 @@ #include #include #include -#include "shaper.h" +#include int sh_debug; /* Debug flag */ -#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.03 for Linux 2.1\n" +#define SHAPER_BANNER "CymruNet Traffic Shaper BETA 0.04 for Linux 2.1\n" /* * Locking @@ -426,17 +426,26 @@ unsigned short type, void *daddr, void *saddr, unsigned len) { struct shaper *sh=dev->priv; + int v; if(sh_debug) printk("Shaper header\n"); - return sh->hard_header(skb,sh->dev,type,daddr,saddr,len); + skb->dev=sh->dev; + v=sh->hard_header(skb,sh->dev,type,daddr,saddr,len); + skb->dev=dev; + return v; } static int shaper_rebuild_header(struct sk_buff *skb) { struct shaper *sh=skb->dev->priv; + struct device *dev=skb->dev; + int v; if(sh_debug) printk("Shaper rebuild header\n"); - return sh->rebuild_header(skb); + skb->dev=sh->dev; + v=sh->rebuild_header(skb); + skb->dev=dev; + return v; } static int shaper_cache(struct dst_entry *dst, struct neighbour *neigh, struct hh_cache *hh) @@ -483,6 +492,7 @@ else shdev->rebuild_header = NULL; +#if 0 if(dev->hard_header_cache) { sh->hard_header_cache = dev->hard_header_cache; @@ -500,6 +510,10 @@ } else shdev->header_cache_update= NULL; +#else + shdev->header_cache_update = NULL; + shdev->hard_header_cache = NULL; +#endif shdev->hard_header_len=dev->hard_header_len; shdev->type=dev->type; diff -u --recursive --new-file v2.1.44/linux/drivers/net/shaper.h linux/drivers/net/shaper.h --- v2.1.44/linux/drivers/net/shaper.h Mon Apr 14 16:28:12 1997 +++ linux/drivers/net/shaper.h Wed Dec 31 16:00:00 1969 @@ -1,61 +0,0 @@ -#ifndef __LINUX_SHAPER_H -#define __LINUX_SHAPER_H - -#ifdef __KERNEL__ - -#define SHAPER_QLEN 10 -/* - * This is a bit speed dependant (read it shouldnt be a constant!) - * - * 5 is about right for 28.8 upwards. Below that double for every - * halving of speed or so. - ie about 20 for 9600 baud. - */ -#define SHAPER_LATENCY (5*HZ) -#define SHAPER_MAXSLIP 2 -#define SHAPER_BURST (HZ/50) /* Good for >128K then */ - -struct shaper -{ - struct sk_buff_head sendq; - __u32 bytespertick; - __u32 shapelatency; - __u32 shapeclock; - __u32 recovery; /* Time we can next clock a packet out on - an empty queue */ - char locked; - struct device *dev; - int (*hard_start_xmit) (struct sk_buff *skb, - struct device *dev); - int (*hard_header) (struct sk_buff *skb, - struct device *dev, - unsigned short type, - void *daddr, - void *saddr, - unsigned len); - int (*rebuild_header)(struct sk_buff *skb); - int (*hard_header_cache)(struct dst_entry *dst, struct neighbour *neigh, - struct hh_cache *hh); - void (*header_cache_update)(struct hh_cache *hh, struct device *dev, unsigned char * haddr); - struct net_device_stats* (*get_stats)(struct device *dev); - struct wait_queue *wait_queue; - struct timer_list timer; -}; - -#endif - -#define SHAPER_SET_DEV 0x0001 -#define SHAPER_SET_SPEED 0x0002 - -struct shaperconf -{ - __u16 ss_cmd; - union - { - char ssu_name[14]; - __u32 ssu_speed; - } ss_u; -#define ss_speed ss_u.ssu_speed -#define ss_name ss_u.ssu_name -}; - -#endif diff -u --recursive --new-file v2.1.44/linux/drivers/net/strip.c linux/drivers/net/strip.c --- v2.1.44/linux/drivers/net/strip.c Tue May 13 22:41:11 1997 +++ linux/drivers/net/strip.c Wed Jul 16 19:22:51 1997 @@ -14,53 +14,62 @@ * for kernel-based devices like TTY. It interfaces between a * raw TTY, and the kernel's INET protocol layers (via DDI). * - * Version: @(#)strip.c 0.9.8 June 1996 + * Version: @(#)strip.c 1.2 February 1997 * * Author: Stuart Cheshire * - * Fixes: v0.9 12th Feb 1996. + * Fixes: v0.9 12th Feb 1996 (SC) * New byte stuffing (2+6 run-length encoding) * New watchdog timer task * New Protocol key (SIP0) * - * v0.9.1 3rd March 1996 + * v0.9.1 3rd March 1996 (SC) * Changed to dynamic device allocation -- no more compile * time (or boot time) limit on the number of STRIP devices. * - * v0.9.2 13th March 1996 + * v0.9.2 13th March 1996 (SC) * Uses arp cache lookups (but doesn't send arp packets yet) * - * v0.9.3 17th April 1996 + * v0.9.3 17th April 1996 (SC) * Fixed bug where STR_ERROR flag was getting set unneccessarily + * (causing otherwise good packets to be unneccessarily dropped) * - * v0.9.4 27th April 1996 + * v0.9.4 27th April 1996 (SC) * First attempt at using "&COMMAND" Starmode AT commands * - * v0.9.5 29th May 1996 + * v0.9.5 29th May 1996 (SC) * First attempt at sending (unicast) ARP packets * - * v0.9.6 5th June 1996 - * Elliot put "message level" tags in every "printk" statement + * v0.9.6 5th June 1996 (Elliot) + * Put "message level" tags in every "printk" statement * - * v0.9.7 13th June 1996 - * Added support for the /proc fs (laik) + * v0.9.7 13th June 1996 (laik) + * Added support for the /proc fs * - * v0.9.8 July 1996 - * Added packet logging (Mema) - */ - -/* - * Undefine this symbol if you don't have PROC_NET_STRIP_STATUS - * defined in include/linux/proc_fs.h + * v0.9.8 July 1996 (Mema) + * Added packet logging + * + * v1.0 November 1996 (SC) + * Fixed (severe) memory leaks in the /proc fs code + * Fixed race conditions in the logging code + * + * v1.1 January 1997 (SC) + * Deleted packet logging (use tcpdump instead) + * Added support for Metricom Firmware v204 features + * (like message checksums) + * + * v1.2 January 1997 (SC) + * Put portables list back in */ -#define DO_PROC_NET_STRIP_STATUS 1 - -/* - * Define this symbol if you want to enable STRIP packet tracing. - */ +#ifdef MODULE +static const char StripVersion[] = "1.2-STUART.CHESHIRE-MODULAR"; +#else +static const char StripVersion[] = "1.2-STUART.CHESHIRE"; +#endif -#define DO_PROC_NET_STRIP_TRACE 0 +#define TICKLE_TIMERS 0 +#define EXT_COUNTERS 1 /************************************************************************/ @@ -146,13 +155,19 @@ __u8 c[24]; } MetricomAddressString; +/* Encapsulation can expand packet of size x to 65/64x + 1 + * Sent packet looks like "*
*" + * 1 1 1-18 1 4 ? 1 + * eg. *0000-1234*SIP0 + * We allow 31 bytes for the stars, the key, the address and the s + */ +#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) + /* - * Note: A Metricom packet looks like this: *
* - * eg. *0000-1234*SIP0 - * A STRIP_Header is never really sent over the radio, but making a dummy header - * for internal use within the kernel that looks like an Ethernet header makes - * certain other software happier. For example, tcpdump already understands - * Ethernet headers. + * A STRIP_Header is never really sent over the radio, but making a dummy + * header for internal use within the kernel that looks like an Ethernet + * header makes certain other software happier. For example, tcpdump + * already understands Ethernet headers. */ typedef struct @@ -162,83 +177,20 @@ unsigned short protocol; /* The protocol type, using Ethernet codes */ } STRIP_Header; -typedef struct GeographicLocation -{ - char s[18]; -} GeographicLocation; - -typedef enum { - NodeValid = 0x1, - NodeHasWAN = 0x2, - NodeIsRouter = 0x4 -} NodeType; - -typedef struct MetricomNode -{ - NodeType type; /* Some flags about the type of node */ - GeographicLocation gl; /* The location of the node. */ - MetricomAddress addr; /* The metricom address of this node */ - int poll_latency; /* The latency to poll that node ? */ - int rssi; /* The Receiver Signal Strength Indicator */ - struct MetricomNode *next; /* The next node */ -} MetricomNode; - -enum { FALSE = 0, TRUE = 1 }; - -/* - * Holds the packet signature for an IP packet. - */ typedef struct { - IPaddr src; - /* Data is stored in the following field in network byte order. */ - __u16 id; -} IPSignature; + char c[60]; +} MetricomNode; -/* - * Holds the packet signature for an ARP packet. - */ +#define NODE_TABLE_SIZE 32 typedef struct { - IPaddr src; - /* Data is stored in the following field in network byte order. */ - __u16 op; -} ARPSignature; - -/* - * Holds the signature of a packet. - */ -typedef union -{ - IPSignature ip_sig; - ARPSignature arp_sig; - __u8 print_sig[6]; -} PacketSignature; - -typedef enum { - EntrySend = 0, - EntryReceive = 1 -} LogEntry; - -/* Structure for Packet Logging */ -typedef struct stripLog -{ - LogEntry entry_type; - u_long seqNum; - int packet_type; - PacketSignature sig; - MetricomAddress src; - MetricomAddress dest; - struct timeval timeStamp; - u_long rawSize; - u_long stripSize; - u_long slipSize; - u_long valid; -} StripLog; + struct timeval timestamp; + int num_nodes; + MetricomNode node[NODE_TABLE_SIZE]; +} MetricomNodeTable; -#define ENTRY_TYPE_TO_STRING(X) ((X) ? "r" : "s") - -#define BOOLEAN_TO_STRING(X) ((X) ? "true" : "false") +enum { FALSE = 0, TRUE = 1 }; /* * Holds the radio's firmware version. @@ -246,7 +198,7 @@ typedef struct { char c[50]; -} MetricomFirmwareVersion; +} FirmwareVersion; /* * Holds the radio's serial number. @@ -254,7 +206,7 @@ typedef struct { char c[18]; -} MetricomSerialNumber; +} SerialNumber; /* * Holds the radio's battery voltage. @@ -262,7 +214,19 @@ typedef struct { char c[11]; -} MetricomBatteryVoltage; +} BatteryVoltage; + +typedef struct +{ + char c[8]; +} char8; + +enum +{ + NoStructure = 0, /* Really old firmware */ + StructuredMessages = 1, /* Parsable AT response msgs */ + ChecksummedMessages = 2 /* Parsable AT response msgs with checksums */ +} FirmwareLevel; struct strip { @@ -292,6 +256,25 @@ unsigned long tx_dropped; /* When MTU change */ unsigned long rx_over_errors; /* Frame bigger then STRIP buf. */ + unsigned long pps_timer; /* Timer to determine pps */ + unsigned long rx_pps_count; /* Counter to determine pps */ + unsigned long tx_pps_count; /* Counter to determine pps */ + unsigned long sx_pps_count; /* Counter to determine pps */ + unsigned long rx_average_pps; /* rx packets per second * 8 */ + unsigned long tx_average_pps; /* tx packets per second * 8 */ + unsigned long sx_average_pps; /* sent packets per second * 8 */ + +#ifdef EXT_COUNTERS + unsigned long rx_bytes; /* total received bytes */ + unsigned long tx_bytes; /* total received bytes */ + unsigned long rx_rbytes; /* bytes thru radio i/f */ + unsigned long tx_rbytes; /* bytes thru radio i/f */ + unsigned long rx_sbytes; /* tot bytes thru serial i/f */ + unsigned long tx_sbytes; /* tot bytes thru serial i/f */ + unsigned long rx_ebytes; /* tot stat/err bytes */ + unsigned long tx_ebytes; /* tot stat/err bytes */ +#endif + /* * Internal variables. */ @@ -300,52 +283,142 @@ struct strip **referrer; /* The pointer that points to us*/ int discard; /* Set if serial error */ int working; /* Is radio working correctly? */ - int structured_messages; /* Parsable AT response msgs? */ + int firmware_level; /* Message structuring level */ + int next_command; /* Next periodic command */ int mtu; /* Our mtu (to spot changes!) */ long watchdog_doprobe; /* Next time to test the radio */ long watchdog_doreset; /* Time to do next reset */ long gratuitous_arp; /* Time to send next ARP refresh*/ long arp_interval; /* Next ARP interval */ struct timer_list idle_timer; /* For periodic wakeup calls */ - MetricomNode *neighbor_list; /* The list of neighbor nodes */ - int neighbor_list_locked; /* Indicates the list is locked */ - MetricomFirmwareVersion firmware_version; /* The radio's firmware version */ - MetricomSerialNumber serial_number; /* The radio's serial number */ - MetricomBatteryVoltage battery_voltage; /* The radio's battery voltage */ + MetricomAddress true_dev_addr; /* True address of radio */ + int manual_dev_addr; /* Hack: See note below */ + + FirmwareVersion firmware_version; /* The radio's firmware version */ + SerialNumber serial_number; /* The radio's serial number */ + BatteryVoltage battery_voltage; /* The radio's battery voltage */ /* * Other useful structures. */ struct tty_struct *tty; /* ptr to TTY structure */ - char if_name[8]; /* Dynamically generated name */ + char8 if_name; /* Dynamically generated name */ struct device dev; /* Our device structure */ /* - * Packet Logging Structures. + * Neighbour radio records */ - u_long num_sent; - u_long num_received; - - int next_entry; /* The index of the oldest packet; */ - /* Also the next to be logged. */ - StripLog packetLog[610]; + MetricomNodeTable portables; + MetricomNodeTable poletops; }; +/* + * Note: manual_dev_addr hack + * + * It is not possible to change the hardware address of a Metricom radio, + * or to send packets with a user-specified hardware source address, thus + * trying to manually set a hardware source address is a questionable + * thing to do. However, if the user *does* manually set the hardware + * source address of a STRIP interface, then the kernel will believe it, + * and use it in certain places. For example, the hardware address listed + * by ifconfig will be the manual address, not the true one. + * (Both addresses are listed in /proc/net/strip.) + * Also, ARP packets will be sent out giving the user-specified address as + * the source address, not the real address. This is dangerous, because + * it means you won't receive any replies -- the ARP replies will go to + * the specified address, which will be some other radio. The case where + * this is useful is when that other radio is also connected to the same + * machine. This allows you to connect a pair of radios to one machine, + * and to use one exclusively for inbound traffic, and the other + * exclusively for outbound traffic. Pretty neat, huh? + * + * Here's the full procedure to set this up: + * + * 1. "slattach" two interfaces, e.g. st0 for outgoing packets, + * and st1 for incoming packets + * + * 2. "ifconfig" st0 (outbound radio) to have the hardware address + * which is the real hardware address of st1 (inbound radio). + * Now when it sends out packets, it will masquerade as st1, and + * replies will be sent to that radio, which is exactly what we want. + * + * 3. Set the route table entry ("route add default ..." or + * "route add -net ...", as appropriate) to send packets via the st0 + * interface (outbound radio). Do not add any route which sends packets + * out via the st1 interface -- that radio is for inbound traffic only. + * + * 4. "ifconfig" st1 (inbound radio) to have hardware address zero. + * This tells the STRIP driver to "shut down" that interface and not + * send any packets through it. In particular, it stops sending the + * periodic gratuitous ARP packets that a STRIP interface normally sends. + * Also, when packets arrive on that interface, it will search the + * interface list to see if there is another interface who's manual + * hardware address matches its own real address (i.e. st0 in this + * example) and if so it will transfer ownership of the skbuff to + * that interface, so that it looks to the kernel as if the packet + * arrived on that interface. This is necessary because when the + * kernel sends an ARP packet on st0, it expects to get a reply on + * st0, and if it sees the reply come from st1 then it will ignore + * it (to be accurate, it puts the entry in the ARP table, but + * labelled in such a way that st0 can't use it). + * + * Thanks to Petros Maniatis for coming up with the idea of splitting + * inbound and outbound traffic between two interfaces, which turned + * out to be really easy to implement, even if it is a bit of a hack. + * + * Having set a manual address on an interface, you can restore it + * to automatic operation (where the address is automatically kept + * consistent with the real address of the radio) by setting a manual + * address of all ones, e.g. "ifconfig st0 hw strip FFFFFFFFFFFF" + * This 'turns off' manual override mode for the device address. + * + * Note: The IEEE 802 headers reported in tcpdump will show the *real* + * radio addresses the packets were sent and received from, so that you + * can see what is really going on with packets, and which interfaces + * they are really going through. + */ + /************************************************************************/ /* Constants */ -#ifdef MODULE -static const char StripVersion[] = "0.9.8-STUART.CHESHIRE-MODULAR"; -#else -static const char StripVersion[] = "0.9.8-STUART.CHESHIRE"; -#endif - -static const char TickleString1[] = "***&COMMAND*ATS305?\r"; -static const char TickleString2[] = "***&COMMAND*ATS305?\r\r" - "*&COMMAND*ATS300?\r\r*&COMMAND*ATS325?\r\r*&COMMAND*AT~I2 nn\r\r"; +/* + * CommandString1 works on all radios + * Other CommandStrings are only used with firmware that provides structured responses. + * + * ats319=1 Enables Info message for node additions and deletions + * ats319=2 Enables Info message for a new best node + * ats319=4 Enables checksums + * ats319=8 Enables ACK messages + */ + +static const int MaxCommandStringLength = 32; +static const int CompatibilityCommand = 1; + +static const char CommandString0[] = "*&COMMAND*ATS319=7"; /* Turn on checksums & info messages */ +static const char CommandString1[] = "*&COMMAND*ATS305?"; /* Query radio name */ +static const char CommandString2[] = "*&COMMAND*ATS325?"; /* Query battery voltage */ +static const char CommandString3[] = "*&COMMAND*ATS300?"; /* Query version information */ +static const char CommandString4[] = "*&COMMAND*ATS311?"; /* Query poletop list */ +static const char CommandString5[] = "*&COMMAND*AT~LA"; /* Query portables list */ +typedef struct { const char *string; long length; } StringDescriptor; + +static const StringDescriptor CommandString[] = + { + { CommandString0, sizeof(CommandString0)-1 }, + { CommandString1, sizeof(CommandString1)-1 }, + { CommandString2, sizeof(CommandString2)-1 }, + { CommandString3, sizeof(CommandString3)-1 }, + { CommandString4, sizeof(CommandString4)-1 }, + { CommandString5, sizeof(CommandString5)-1 } + }; + +#define GOT_ALL_RADIO_INFO(S) \ + ((S)->firmware_version.c[0] && \ + (S)->battery_voltage.c[0] && \ + memcmp(&(S)->true_dev_addr, zero_address.c, sizeof(zero_address))) static const char hextable[16] = "0123456789ABCDEF"; @@ -354,26 +427,27 @@ static const MetricomKey SIP0Key = { { "SIP0" } }; static const MetricomKey ARP0Key = { { "ARP0" } }; -static const MetricomKey ERR_Key = { { "ERR_" } }; static const MetricomKey ATR_Key = { { "ATR " } }; +static const MetricomKey ACK_Key = { { "ACK_" } }; +static const MetricomKey INF_Key = { { "INF_" } }; +static const MetricomKey ERR_Key = { { "ERR_" } }; static const long MaxARPInterval = 60 * HZ; /* One minute */ /* - * Maximum Starmode packet length (including starmode address) is 1183 bytes. - * Allowing 32 bytes for header, and 65/64 expansion for STRIP encoding, - * that translates to a maximum payload MTU of 1132. - */ -static const unsigned short MAX_STRIP_MTU = 1132; -static const unsigned short DEFAULT_STRIP_MTU = 1024; + * Maximum Starmode packet length is 1183 bytes. Allowing 4 bytes for + * protocol key, 4 bytes for checksum, one byte for CR, and 65/64 expansion + * for STRIP encoding, that translates to a maximum payload MTU of 1155. + * Note: A standard NFS 1K data packet is a total of 0x480 (1152) bytes + * long, including IP header, UDP header, and NFS header. Setting the STRIP + * MTU to 1152 allows us to send default sized NFS packets without fragmentation. + */ +static const unsigned short MAX_SEND_MTU = 1152; +static const unsigned short MAX_RECV_MTU = 1500; /* Hoping for Ethernet sized packets in the future! */ +static const unsigned short DEFAULT_STRIP_MTU = 1152; static const int STRIP_MAGIC = 0x5303; static const long LongTime = 0x7FFFFFFF; -static const int STRIP_NODE_LEN = 64; -static const char STRIP_PORTABLE_CHAR = 'P'; -static const char STRIP_ROUTER_CHAR = 'r'; -static const int STRIP_PROC_BUFFER_SIZE = 4096; -static const int STRIP_LOG_INT_SIZE = 10; /************************************************************************/ /* Global variables */ @@ -384,10 +458,18 @@ /************************************************************************/ /* Macros */ +/* Returns TRUE if text T begins with prefix P */ +#define has_prefix(T,P) (!strncmp((T), (P), sizeof(P)-1)) + +/* Returns TRUE if text T of length L is equal to string S */ +#define text_equal(T,L,S) (((L) == sizeof(S)-1) && !strncmp((T), (S), sizeof(S)-1)) + #define READHEX(X) ((X)>='0' && (X)<='9' ? (X)-'0' : \ (X)>='a' && (X)<='f' ? (X)-'a'+10 : \ (X)>='A' && (X)<='F' ? (X)-'A'+10 : 0 ) +#define READHEX16(X) ((__u16)(READHEX(X))) + #define READDEC(X) ((X)>='0' && (X)<='9' ? (X)-'0' : 0) #define MIN(X, Y) ((X) < (Y) ? (X) : (Y)) @@ -395,17 +477,6 @@ #define ELEMENTS_OF(X) (sizeof(X) / sizeof((X)[0])) #define ARRAY_END(X) (&((X)[ELEMENTS_OF(X)])) -/* Encapsulation can expand packet of size x to 65/64x + 1 */ -/* Sent packet looks like "*
*" */ -/* 1 1-18 1 4 ? 1 */ -/* We allow 31 bytes for the stars, the key, the address and the */ -#define STRIP_ENCAP_SIZE(X) (32 + (X)*65L/64L) - -#define IS_RADIO_ADDRESS(p) ( \ - isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ - (p)[4] == '-' && \ - isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) - #define JIFFIE_TO_SEC(X) ((X) / HZ) @@ -605,7 +676,15 @@ } /* else, we only have one so far, so switch to Stuff_Diff code */ code = Stuff_Diff; - /* and fall through to Stuff_Diff case below */ + /* and fall through to Stuff_Diff case below + * Note cunning cleverness here: case Stuff_Diff compares + * the current character with the previous two to see if it + * has a run of three the same. Won't this be an error if + * there aren't two previous characters stored to compare with? + * No. Because we know the current character is *not* the same + * as the previous one, the first test below will necessarily + * fail and the send half of the "if" won't be executed. + */ /* Stuff_Diff: We have at least two *different* bytes encoded */ case Stuff_Diff: @@ -639,10 +718,10 @@ src++; /* Consume the byte */ break; } - if (count == Stuff_MaxCount) - { - StuffData_FinishBlock(code + count); - } + if (count == Stuff_MaxCount) + { + StuffData_FinishBlock(code + count); + } } if (code == Stuff_NoCode) { @@ -758,14 +837,21 @@ * Convert a string to a Metricom Address. */ -static void string_to_radio_address(MetricomAddress *addr, __u8 *p) +#define IS_RADIO_ADDRESS(p) ( \ + isdigit((p)[0]) && isdigit((p)[1]) && isdigit((p)[2]) && isdigit((p)[3]) && \ + (p)[4] == '-' && \ + isdigit((p)[5]) && isdigit((p)[6]) && isdigit((p)[7]) && isdigit((p)[8]) ) + +static int string_to_radio_address(MetricomAddress *addr, __u8 *p) { + if (!IS_RADIO_ADDRESS(p)) return(1); addr->c[0] = 0; addr->c[1] = 0; addr->c[2] = READHEX(p[0]) << 4 | READHEX(p[1]); addr->c[3] = READHEX(p[2]) << 4 | READHEX(p[3]); addr->c[4] = READHEX(p[5]) << 4 | READHEX(p[6]); addr->c[5] = READHEX(p[7]) << 4 | READHEX(p[8]); + return(0); } /* @@ -780,19 +866,18 @@ /* * Note: Must make sure sx_size is big enough to receive a stuffed - * MAX_STRIP_MTU packet. Additionally, we also want to ensure that it's + * MAX_RECV_MTU packet. Additionally, we also want to ensure that it's * big enough to receive a large radio neighbour list (currently 4K). */ static int allocate_buffers(struct strip *strip_info) { struct device *dev = &strip_info->dev; - int stuffedlen = STRIP_ENCAP_SIZE(dev->mtu); - int sx_size = MAX(stuffedlen, 4096); - int tx_size = stuffedlen + sizeof(TickleString2); - __u8 *r = kmalloc(MAX_STRIP_MTU, GFP_ATOMIC); - __u8 *s = kmalloc(sx_size, GFP_ATOMIC); - __u8 *t = kmalloc(tx_size, GFP_ATOMIC); + int sx_size = MAX(STRIP_ENCAP_SIZE(MAX_RECV_MTU), 4096); + int tx_size = STRIP_ENCAP_SIZE(dev->mtu) + MaxCommandStringLength; + __u8 *r = kmalloc(MAX_RECV_MTU, GFP_ATOMIC); + __u8 *s = kmalloc(sx_size, GFP_ATOMIC); + __u8 *t = kmalloc(tx_size, GFP_ATOMIC); if (r && s && t) { strip_info->rx_buff = r; @@ -824,10 +909,10 @@ unsigned char *otbuff = strip_info->tx_buff; InterruptStatus intstat; - if (dev->mtu > MAX_STRIP_MTU) + if (dev->mtu > MAX_SEND_MTU) { printk(KERN_ERR "%s: MTU exceeds maximum allowable (%d), MTU change cancelled.\n", - strip_info->dev.name, MAX_STRIP_MTU); + strip_info->dev.name, MAX_SEND_MTU); dev->mtu = old_mtu; return; } @@ -856,9 +941,8 @@ memcpy(strip_info->sx_buff, osbuff, strip_info->sx_count); else { - strip_info->sx_count = 0; + strip_info->discard = strip_info->sx_count; strip_info->rx_over_errors++; - strip_info->discard = 1; } } @@ -889,7 +973,7 @@ /* * Set the time to go off in one second. */ - strip_info->idle_timer.expires = jiffies + HZ; + strip_info->idle_timer.expires = jiffies + 1*HZ; add_timer(&strip_info->idle_timer); if (!test_and_clear_bit(0, (void *)&strip_info->dev.tbusy)) printk(KERN_ERR "%s: trying to unlock already unlocked device!\n", @@ -900,8 +984,6 @@ /************************************************************************/ /* Callback routines for exporting information through /proc */ -#if DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE - /* * This function updates the total amount of data printed so far. It then * determines if the amount of data printed into a buffer has reached the @@ -912,29 +994,29 @@ */ static int shift_buffer(char *buffer, int requested_offset, int requested_len, - int *total, int *slop, char **buf) + int *total, int *slop, char **buf) { int printed; /* printk(KERN_DEBUG "shift: buffer: %d o: %d l: %d t: %d buf: %d\n", - (int) buffer, requested_offset, requested_len, *total, - (int) *buf); */ + (int) buffer, requested_offset, requested_len, *total, + (int) *buf); */ printed = *buf - buffer; if (*total + printed <= requested_offset) { - *total += printed; - *buf = buffer; + *total += printed; + *buf = buffer; } else { - if (*total < requested_offset) { - *slop = requested_offset - *total; - } - *total = requested_offset + printed - *slop; + if (*total < requested_offset) { + *slop = requested_offset - *total; + } + *total = requested_offset + printed - *slop; } if (*total > requested_offset + requested_len) { - return 1; + return 1; } else { - return 0; + return 0; } } @@ -945,12 +1027,12 @@ */ static int calc_start_len(char *buffer, char **start, int requested_offset, - int requested_len, int total, char *buf) + int requested_len, int total, char *buf) { int return_len, buffer_len; buffer_len = buf - buffer; - if (buffer_len >= STRIP_PROC_BUFFER_SIZE - 1) { + if (buffer_len >= 4095) { printk(KERN_ERR "STRIP: exceeded /proc buffer size\n"); } @@ -960,20 +1042,16 @@ */ return_len = total - requested_offset; if (return_len < 0) { - return_len = 0; + return_len = 0; } *start = buf - return_len; if (return_len > requested_len) { - return_len = requested_len; + return_len = requested_len; } /* printk(KERN_DEBUG "return_len: %d\n", return_len); */ return return_len; } -#endif DO_PROC_NET_STRIP_STATUS | DO_PROC_NET_STRIP_TRACE - -#if DO_PROC_NET_STRIP_STATUS - /* * If the time is in the near future, time_delta prints the number of * seconds to go into the buffer and returns the address of the buffer. @@ -991,537 +1069,171 @@ return(buffer); } -/* - * This function prints radio status information into the specified - * buffer. - */ -static int -sprintf_status_info(char *buffer, struct strip *strip_info) +static int sprintf_neighbours(char *buffer, MetricomNodeTable *table, char *title) { - char temp_buffer[32]; - MetricomAddressString addr_string; - char *buf; - - buf = buffer; - buf += sprintf(buf, "Interface name\t\t%s\n", strip_info->if_name); - buf += sprintf(buf, " Radio working:\t\t%s\n", - strip_info->working && - (long)jiffies - strip_info->watchdog_doreset < 0 ? "Yes" : "No"); - (void) radio_address_to_string((MetricomAddress *) - &strip_info->dev.dev_addr, - &addr_string); - buf += sprintf(buf, " Device address:\t%s\n", addr_string.c); - buf += sprintf(buf, " Firmware version:\t%s\n", - !strip_info->working ? "Unknown" : - !strip_info->structured_messages ? "Should be upgraded" : - strip_info->firmware_version.c); - buf += sprintf(buf, " Serial number:\t\t%s\n", strip_info->serial_number.c); - buf += sprintf(buf, " Battery voltage:\t%s\n", strip_info->battery_voltage.c); - buf += sprintf(buf, " Transmit queue (bytes):%d\n", strip_info->tx_left); - buf += sprintf(buf, " Next watchdog probe:\t%s\n", - time_delta(temp_buffer, strip_info->watchdog_doprobe)); - buf += sprintf(buf, " Next watchdog reset:\t%s\n", - time_delta(temp_buffer, strip_info->watchdog_doreset)); - buf += sprintf(buf, " Next gratuitous ARP:\t%s\n", - time_delta(temp_buffer, strip_info->gratuitous_arp)); - buf += sprintf(buf, " Next ARP interval:\t%ld seconds\n", - JIFFIE_TO_SEC(strip_info->arp_interval)); - return buf - buffer; -} - -static int -sprintf_portables(char *buffer, struct strip *strip_info) -{ - - MetricomAddressString addr_string; - MetricomNode *node; - char *buf; - - buf = buffer; - buf += sprintf(buf, " portables: name\t\tpoll_latency\tsignal strength\n"); - for (node = strip_info->neighbor_list; node != NULL; - node = node->next) { - if (!(node->type & NodeValid)) { - break; - } - if (node->type & NodeHasWAN) { - continue; - } - (void) radio_address_to_string(&node->addr, &addr_string); - buf += sprintf(buf, " %s\t\t\t\t%d\t\t%d\n", - addr_string.c, node->poll_latency, node->rssi); - } - return buf - buffer; -} - -static int -sprintf_poletops(char *buffer, struct strip *strip_info) -{ - MetricomNode *node; - char *buf; - - buf = buffer; - buf += sprintf(buf, " poletops: GPS\t\t\tpoll_latency\tsignal strength\n"); - for (node = strip_info->neighbor_list; - node != NULL; node = node->next) { - if (!(node->type & NodeValid)) { - break; - } - if (!(node->type & NodeHasWAN)) { - continue; - } - buf += sprintf(buf, " %s\t\t\t%d\t\t%d\n", - node->gl.s, node->poll_latency, node->rssi); - } - return buf - buffer; + /* We wrap this in a do/while loop, so if the table changes */ + /* while we're reading it, we just go around and try again. */ + struct timeval t; + char *ptr; + do + { + int i; + t = table->timestamp; + ptr = buffer; + if (table->num_nodes) ptr += sprintf(ptr, "\n %s\n", title); + for (i=0; inum_nodes; i++) + { + InterruptStatus intstat = DisableInterrupts(); + MetricomNode node = table->node[i]; + RestoreInterrupts(intstat); + ptr += sprintf(ptr, " %s\n", node.c); + } + } while (table->timestamp.tv_sec != t.tv_sec || table->timestamp.tv_usec != t.tv_usec); + return ptr - buffer; } /* - * This function is exports status information from the STRIP driver through - * the /proc file system. /proc filesystem should be fixed: - * 1) slow (sprintfs here, a memory copy in the proc that calls this one) - * 2) length of buffer not passed - * 3) dummy isn't client data set when the callback was registered - * 4) poorly documented (this function is called until the requested amount - * of data is returned, buffer is only 4K long, dummy is the permissions - * of the file (?), the proc_dir_entry passed to proc_net_register must - * be kmalloc-ed) - */ - -static int -strip_get_status_info(char *buffer, char **start, off_t requested_offset, - int requested_len, int dummy) -{ - char *buf; - int total = 0, slop = 0, len_exceeded; - InterruptStatus i_status; - struct strip *strip_info; - - buf = buffer; - buf += sprintf(buf, "strip_version: %s\n", StripVersion); - - i_status = DisableInterrupts(); - strip_info = struct_strip_list; - RestoreInterrupts(i_status); - - while (strip_info != NULL) { - i_status = DisableInterrupts(); - buf += sprintf_status_info(buf, strip_info); - RestoreInterrupts(i_status); - len_exceeded = shift_buffer(buffer, requested_offset, requested_len, - &total, &slop, &buf); - if (len_exceeded) { - goto done; - } - strip_info->neighbor_list_locked = TRUE; - buf += sprintf_portables(buf, strip_info); - strip_info->neighbor_list_locked = FALSE; - len_exceeded = shift_buffer(buffer, requested_offset, requested_len, - &total, &slop, &buf); - if (len_exceeded) { - goto done; - } - strip_info->neighbor_list_locked = TRUE; - buf += sprintf_poletops(buf, strip_info); - strip_info->neighbor_list_locked = FALSE; - len_exceeded = shift_buffer(buffer, requested_offset, requested_len, - &total, &slop, &buf); - if (len_exceeded) { - goto done; - } - strip_info = strip_info->next; - } -done: - return calc_start_len(buffer, start, requested_offset, requested_len, - total, buf); -} - -#endif DO_PROC_NET_STRIP_STATUS - -#if DO_PROC_NET_STRIP_TRACE - -/* - * Convert an Ethernet protocol to a string - * Returns the number of characters printed. + * This function prints radio status information into the specified buffer. + * I think the buffer size is 4K, so this routine should never print more + * than 4K of data into it. With the maximum of 32 portables and 32 poletops + * reported, the routine outputs 3107 bytes into the buffer. */ - -static int protocol_to_string(int protocol, __u8 *p) -{ - int printed; - - switch (protocol) { - case ETH_P_IP: - printed = sprintf(p, "IP"); - break; - case ETH_P_ARP: - printed = sprintf(p, "ARP"); - break; - default: - printed = sprintf(p, "%d", protocol); - } - return printed; -} - static int -sprintf_log_entry(char *buffer, struct strip *strip_info, int packet_index) +sprintf_status_info(char *buffer, struct strip *strip_info) { - StripLog *entry; + char temp[32]; + char *p = buffer; MetricomAddressString addr_string; - __u8 sig_buf[24], *s; - char *buf, proto_buf[10]; - - entry = &strip_info->packetLog[packet_index]; - if (!entry->valid) { - return 0; - } - buf = buffer; - buf += sprintf(buf, "%-4s %s %7lu ", strip_info->if_name, - ENTRY_TYPE_TO_STRING(entry->entry_type), entry->seqNum); - (void) protocol_to_string(entry->packet_type, proto_buf); - buf += sprintf(buf, "%-4s", proto_buf); - s = entry->sig.print_sig; - sprintf(sig_buf, "%d.%d.%d.%d.%d.%d", s[0], s[1], s[2], s[3], s[4], s[5]); - buf += sprintf(buf, "%-24s", sig_buf); - (void) radio_address_to_string((MetricomAddress *) &entry->src, - &addr_string); - buf += sprintf(buf, "%-10s", addr_string.c); - (void) radio_address_to_string((MetricomAddress *) &entry->dest, - &addr_string); - buf += sprintf(buf, "%-10s", addr_string.c); - buf += sprintf(buf, "%8d %6d %5lu %6lu %5lu\n", entry->timeStamp.tv_sec, - entry->timeStamp.tv_usec, entry->rawSize, - entry->stripSize, entry->slipSize); - return buf - buffer; -} -/* - * This function exports trace information from the STRIP driver through the - * /proc file system. - */ + /* First, we must copy all of our data to a safe place, */ + /* in case a serial interrupt comes in and changes it. */ + InterruptStatus intstat = DisableInterrupts(); + int tx_left = strip_info->tx_left; + unsigned long rx_average_pps = strip_info->rx_average_pps; + unsigned long tx_average_pps = strip_info->tx_average_pps; + unsigned long sx_average_pps = strip_info->sx_average_pps; + int working = strip_info->working; + int firmware_level = strip_info->firmware_level; + long watchdog_doprobe = strip_info->watchdog_doprobe; + long watchdog_doreset = strip_info->watchdog_doreset; + long gratuitous_arp = strip_info->gratuitous_arp; + long arp_interval = strip_info->arp_interval; + FirmwareVersion firmware_version = strip_info->firmware_version; + SerialNumber serial_number = strip_info->serial_number; + BatteryVoltage battery_voltage = strip_info->battery_voltage; + char8 if_name = strip_info->if_name; + MetricomAddress true_dev_addr = strip_info->true_dev_addr; + MetricomAddress dev_dev_addr = *(MetricomAddress*)strip_info->dev.dev_addr; + int manual_dev_addr = strip_info->manual_dev_addr; +#ifdef EXT_COUNTERS + unsigned long rx_bytes = strip_info->rx_bytes; + unsigned long tx_bytes = strip_info->tx_bytes; + unsigned long rx_rbytes = strip_info->rx_rbytes; + unsigned long tx_rbytes = strip_info->tx_rbytes; + unsigned long rx_sbytes = strip_info->rx_sbytes; + unsigned long tx_sbytes = strip_info->tx_sbytes; + unsigned long rx_ebytes = strip_info->rx_ebytes; + unsigned long tx_ebytes = strip_info->tx_ebytes; +#endif + RestoreInterrupts(intstat); -static int -strip_get_trace_info(char *buffer, char **start, off_t requested_offset, - int requested_len, int dummy) -{ - char *buf; - int len_exceeded, total = 0, slop = 0, packet_index, oldest; - InterruptStatus i_status; - struct strip *strip_info; - - buf = buffer; - buf += sprintf(buf, "if s/r seqnum t signature "); - buf += sprintf(buf, - "src dest sec usec raw strip slip\n"); - - i_status = DisableInterrupts(); - strip_info = struct_strip_list; - oldest = strip_info->next_entry; - RestoreInterrupts(i_status); - - /* - * If we disable interrupts for this entire loop, - * characters from the serial port could be lost, - * so we only disable interrupts when accessing - * a log entry. If more than STRIP_LOG_INT_SIZE - * packets are logged before the first entry is - * printed, then some of the entries could be - * printed out of order. - */ - while (strip_info != NULL) { - for (packet_index = oldest + STRIP_LOG_INT_SIZE; - packet_index != oldest; - packet_index = (packet_index + 1) % - ELEMENTS_OF(strip_info->packetLog)) { - i_status = DisableInterrupts(); - buf += sprintf_log_entry(buf, strip_info, packet_index); - RestoreInterrupts(i_status); - len_exceeded = shift_buffer(buffer, requested_offset, - requested_len, &total, &slop, &buf); - if (len_exceeded) { - goto done; - } - } - strip_info = strip_info->next; - } -done: - return calc_start_len(buffer, start, requested_offset, requested_len, - total, buf); -} + p += sprintf(p, "\nInterface name\t\t%s\n", if_name.c); + p += sprintf(p, " Radio working:\t\t%s\n", working ? "Yes" : "No"); + radio_address_to_string(&true_dev_addr, &addr_string); + p += sprintf(p, " Radio address:\t\t%s\n", addr_string.c); + if (manual_dev_addr) + { + radio_address_to_string(&dev_dev_addr, &addr_string); + p += sprintf(p, " Device address:\t%s\n", addr_string.c); + } + p += sprintf(p, " Firmware version:\t%s", !working ? "Unknown" : + !firmware_level ? "Should be upgraded" : + firmware_version.c); + if (firmware_level >= ChecksummedMessages) p += sprintf(p, " (Checksums Enabled)"); + p += sprintf(p, "\n"); + p += sprintf(p, " Serial number:\t\t%s\n", serial_number.c); + p += sprintf(p, " Battery voltage:\t%s\n", battery_voltage.c); + p += sprintf(p, " Transmit queue (bytes):%d\n", tx_left); + p += sprintf(p, " Receive packet rate: %ld packets per second\n", rx_average_pps / 8); + p += sprintf(p, " Transmit packet rate: %ld packets per second\n", tx_average_pps / 8); + p += sprintf(p, " Sent packet rate: %ld packets per second\n", sx_average_pps / 8); + p += sprintf(p, " Next watchdog probe:\t%s\n", time_delta(temp, watchdog_doprobe)); + p += sprintf(p, " Next watchdog reset:\t%s\n", time_delta(temp, watchdog_doreset)); + p += sprintf(p, " Next gratuitous ARP:\t"); -static int slip_len(unsigned char *data, int len) -{ - static const unsigned char SLIP_END=0300; /* indicates end of SLIP frame */ - static const unsigned char SLIP_ESC=0333; /* indicates SLIP byte stuffing */ - int count = len; - while (--len >= 0) + if (!memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address))) + p += sprintf(p, "Disabled\n"); + else { - if (*data == SLIP_END || *data == SLIP_ESC) count++; - data++; + p += sprintf(p, "%s\n", time_delta(temp, gratuitous_arp)); + p += sprintf(p, " Next ARP interval:\t%ld seconds\n", JIFFIE_TO_SEC(arp_interval)); } - return(count); -} - -/* Copied from kernel/sched.c */ -static void jiffiestotimeval(unsigned long jiffies, struct timeval *value) -{ - value->tv_usec = (jiffies % HZ) * (1000000.0 / HZ); - value->tv_sec = jiffies / HZ; - return; -} -/* - * This function logs a packet. - * A pointer to the packet itself is passed so that some of the data can be - * used to compute a signature. The pointer should point the the - * part of the packet following the STRIP_header. - */ - -static void packet_log(struct strip *strip_info, __u8 *packet, - LogEntry entry_type, STRIP_Header *hdr, - int raw_size, int strip_size, int slip_size) -{ - StripLog *entry; - struct iphdr *iphdr; - struct arphdr *arphdr; - - entry = &strip_info->packetLog[strip_info->next_entry]; - if (entry_type == EntrySend) { - entry->seqNum = strip_info->num_sent++; - } - else { - entry->seqNum = strip_info->num_received++; - } - entry->entry_type = entry_type; - entry->packet_type = ntohs(hdr->protocol); - switch (entry->packet_type) { - case ETH_P_IP: - /* - * The signature for IP is the sender's ip address and - * the identification field. - */ - iphdr = (struct iphdr *) packet; - entry->sig.ip_sig.id = iphdr->id; - entry->sig.ip_sig.src.l = iphdr->saddr; - break; - case ETH_P_ARP: - /* - * The signature for ARP is the sender's ip address and - * the operation. - */ - arphdr = (struct arphdr *) packet; - entry->sig.arp_sig.op = arphdr->ar_op; - memcpy(&entry->sig.arp_sig.src.l, packet + 8 + arphdr->ar_hln, - sizeof(entry->sig.arp_sig.src.l)); - entry->sig.arp_sig.src.l = entry->sig.arp_sig.src.l; - break; - default: - printk(KERN_DEBUG "STRIP: packet_log: unknown packet type: %d\n", - entry->packet_type); - break; - } - memcpy(&entry->src, &hdr->src_addr, sizeof(MetricomAddress)); - memcpy(&entry->dest, &hdr->dst_addr, sizeof(MetricomAddress)); - - jiffiestotimeval(jiffies, &(entry->timeStamp)); - entry->rawSize = raw_size; - entry->stripSize = strip_size; - entry->slipSize = slip_size; - entry->valid = 1; + if (working) + { +#ifdef EXT_COUNTERS + p += sprintf(p, "\n"); + p += sprintf(p, " Total bytes: \trx:\t%lu\ttx:\t%lu\n", rx_bytes, tx_bytes); + p += sprintf(p, " thru radio: \trx:\t%lu\ttx:\t%lu\n", rx_rbytes, tx_rbytes); + p += sprintf(p, " thru serial port: \trx:\t%lu\ttx:\t%lu\n", rx_sbytes, tx_sbytes); + p += sprintf(p, " Total stat/err bytes:\trx:\t%lu\ttx:\t%lu\n", rx_ebytes, tx_ebytes); +#endif + p += sprintf_neighbours(p, &strip_info->poletops, "Poletops:"); + p += sprintf_neighbours(p, &strip_info->portables, "Portables:"); + } - strip_info->next_entry = (strip_info->next_entry + 1) % - ELEMENTS_OF(strip_info->packetLog); + return p - buffer; } -#endif DO_PROC_NET_STRIP_TRACE - /* - * This function parses the response to the ATS300? command, - * extracting the radio version and serial number. + * This function is exports status information from the STRIP driver through + * the /proc file system. */ -static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end) -{ - __u8 *p, *value_begin, *value_end; - int len; - - /* Determine the beginning of the second line of the payload */ - p = ptr; - while (p < end && *p != 10) p++; - if (p >= end) return; - p++; - value_begin = p; - - /* Determine the end of line */ - while (p < end && *p != 10) p++; - if (p >= end) return; - value_end = p; - p++; - - len = value_end - value_begin; - len = MIN(len, sizeof(MetricomFirmwareVersion) - 1); - sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); - - /* Look for the first colon */ - while (p < end && *p != ':') p++; - if (p >= end) return; - /* Skip over the space */ - p += 2; - len = sizeof(MetricomSerialNumber) - 1; - if (p + len <= end) { - sprintf(strip_info->serial_number.c, "%.*s", len, p); - } - else { - printk(KERN_ERR "STRIP: radio serial number shorter (%d) than expected (%d)\n", - end - p, len); - } -} -/* - * This function parses the response to the ATS325? command, - * extracting the radio battery voltage. - */ -static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end) +static int get_status_info(char *buffer, char **start, off_t req_offset, int req_len, int dummy) { - int len; + int total = 0, slop = 0; + struct strip *strip_info = struct_strip_list; + char *buf = buffer; - len = sizeof(MetricomBatteryVoltage) - 1; - if (ptr + len <= end) { - sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); - } - else { - printk(KERN_ERR "STRIP: radio voltage string shorter (%d) than expected (%d)\n", - end - ptr, len); - } + buf += sprintf(buf, "strip_version: %s\n", StripVersion); + if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf)) goto exit; + + while (strip_info != NULL) + { + buf += sprintf_status_info(buf, strip_info); + if (shift_buffer(buffer, req_offset, req_len, &total, &slop, &buf)) break; + strip_info = strip_info->next; + } + exit: + return(calc_start_len(buffer, start, req_offset, req_len, total, buf)); } -/* - * This function parses the response to the AT~I2 command, - * which gives the names of the radio's nearest neighbors. - * It relies on the format of the response. - */ -static void get_radio_neighbors(struct strip *strip_info, __u8 *ptr, __u8 *end) +static const char proc_strip_status_name[] = "strip"; +static struct proc_dir_entry proc_strip_get_status_info = { - __u8 *p, *line_begin; - int num_nodes_reported, num_nodes_counted; - MetricomNode *node, *last; - - /* Check if someone is reading the list */ - if (strip_info->neighbor_list_locked) { - return; - } - - /* Determine the number of Nodes */ - p = ptr; - num_nodes_reported = simple_strtoul(p, NULL, 10); - /* printk(KERN_DEBUG "num_nodes: %d\n", num_nodes_reported); */ - - /* Determine the beginning of the next line */ - while (p < end && *p != 10) p++; - if (p >= end) return; - p++; - - /* - * The node list should never be empty because we allocate one empty - * node when the strip_info is allocated. The nodes which were allocated - * when the number of neighbors was high but are no longer needed because - * there aren't as many neighbors any more are marked invalid. Invalid nodes - * are kept at the end of the list. - */ - node = strip_info->neighbor_list; - last = node; - if (node == NULL) { - DumpData("Neighbor list is NULL:", strip_info, p, end); - return; - } - line_begin = p; - num_nodes_counted = 0; - while (line_begin < end) { - /* Check to see if the format is what we expect. */ - if ((line_begin + STRIP_NODE_LEN) > end) { - printk(KERN_ERR "STRIP: radio neighbor node string shorter (%d) than expected (%d)\n", - end - line_begin, STRIP_NODE_LEN); - break; - } - - /* Get a node */ - if (node == NULL) { - node = kmalloc(sizeof(MetricomNode), GFP_ATOMIC); - node->next = NULL; - } - node->type = NodeValid; - - /* Fill the node in */ - - /* Determine if it has a GPS location and fill it in if it does. */ - p = line_begin; - /* printk(KERN_DEBUG "node: %64s\n", p); */ - if (p[0] != STRIP_PORTABLE_CHAR) { - node->type |= NodeHasWAN; - sprintf(node->gl.s, "%.*s", (int) sizeof(GeographicLocation) - 1, p); - } - - /* Determine if it is a router */ - p = line_begin + 18; - if (p[0] == STRIP_ROUTER_CHAR) { - node->type |= NodeIsRouter; - } - - /* Could be a radio address or some weird poletop address. */ - p = line_begin + 20; - /* printk(KERN_DEBUG "before addr: %6s\n", p); */ - string_to_radio_address(&node->addr, p); - /* radio_address_to_string(&node->addr, addr_string); - printk(KERN_DEBUG "after addr: %s\n", addr_string); */ - - if (IS_RADIO_ADDRESS(p)) { - string_to_radio_address(&node->addr, p); - } - else { - memset(&node->addr, 0, sizeof(MetricomAddress)); - } - - /* Get the poll latency. %$#!@ simple_strtoul can't skip white space */ - p = line_begin + 41; - while (isspace(*p) && (p < end)) { - p++; - } - node->poll_latency = simple_strtoul(p, NULL, 10); - - /* Get the signal strength. simple_strtoul doesn't do minus signs */ - p = line_begin + 60; - node->rssi = -simple_strtoul(p, NULL, 10); - - if (last != node) { - last->next = node; - last = node; - } - node = node->next; - line_begin += STRIP_NODE_LEN; - num_nodes_counted++; - } - - /* invalidate all remaining nodes */ - for (;node != NULL; node = node->next) { - node->type &= ~NodeValid; - } - - /* - * If the number of nodes reported is different - * from the number counted, might need to up the number - * requested. - */ - if (num_nodes_reported != num_nodes_counted) { - printk(KERN_DEBUG "nodes reported: %d \tnodes counted: %d\n", - num_nodes_reported, num_nodes_counted); - } -} + PROC_NET_STRIP_STATUS, /* unsigned short low_ino */ + sizeof(proc_strip_status_name)-1, /* unsigned short namelen */ + proc_strip_status_name, /* const char *name */ + S_IFREG | S_IRUGO, /* mode_t mode */ + 1, /* nlink_t nlink */ + 0, 0, 0, /* uid_t uid, gid_t gid, unsigned long size */ + &proc_net_inode_operations, /* struct inode_operations * ops */ + &get_status_info, /* int (*get_info)(...) */ + NULL, /* void (*fill_inode)(struct inode *); */ + NULL, NULL, NULL, /* struct proc_dir_entry *next, *parent, *subdir; */ + NULL /* void *data; */ +}; /************************************************************************/ /* Sending routines */ +#define InitString "ate0q1dt**starmode" + static void ResetRadio(struct strip *strip_info) -{ - static const char InitString[] = "\rat\r\rate0q1dt**starmode\r\r**"; +{ + static const char s[] = "\r" InitString "\r**"; /* If the radio isn't working anymore, we should clear the old status information. */ if (strip_info->working) @@ -1530,14 +1242,32 @@ strip_info->firmware_version.c[0] = '\0'; strip_info->serial_number.c[0] = '\0'; strip_info->battery_voltage.c[0] = '\0'; + strip_info->portables.num_nodes = 0; + do_gettimeofday(&strip_info->portables.timestamp); + strip_info->poletops.num_nodes = 0; + do_gettimeofday(&strip_info->poletops.timestamp); } + + strip_info->pps_timer = jiffies; + strip_info->rx_pps_count = 0; + strip_info->tx_pps_count = 0; + strip_info->sx_pps_count = 0; + strip_info->rx_average_pps = 0; + strip_info->tx_average_pps = 0; + strip_info->sx_average_pps = 0; + /* Mark radio address as unknown */ - *(MetricomAddress*)&strip_info->dev.dev_addr = zero_address; + *(MetricomAddress*)&strip_info->true_dev_addr = zero_address; + if (!strip_info->manual_dev_addr) *(MetricomAddress*)strip_info->dev.dev_addr = zero_address; strip_info->working = FALSE; - strip_info->structured_messages = FALSE; + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; strip_info->watchdog_doprobe = jiffies + 10 * HZ; strip_info->watchdog_doreset = jiffies + 1 * HZ; - strip_info->tty->driver.write(strip_info->tty, 0, (char *)InitString, sizeof(InitString)-1); + strip_info->tty->driver.write(strip_info->tty, 0, (char *)s, sizeof(s)-1); +#ifdef EXT_COUNTERS + strip_info->tx_ebytes += sizeof(s) - 1; +#endif } /* @@ -1573,6 +1303,9 @@ int num_written = tty->driver.write(tty, 0, strip_info->tx_head, strip_info->tx_left); strip_info->tx_left -= num_written; strip_info->tx_head += num_written; +#ifdef EXT_COUNTERS + strip_info->tx_sbytes += num_written; +#endif RestoreInterrupts(intstat); } else /* Else start transmission of another packet */ @@ -1583,12 +1316,21 @@ } } -static unsigned char *strip_make_packet(unsigned char *ptr, struct strip *strip_info, struct sk_buff *skb) +static __u8 *add_checksum(__u8 *buffer, __u8 *end) { -#if DO_PROC_NET_STRIP_TRACE - unsigned char *start_ptr; -#endif DO_PROC_NET_STRIP_TRACE + __u16 sum = 0; + __u8 *p = buffer; + while (p < end) sum += *p++; + end[3] = hextable[sum & 0xF]; sum >>= 4; + end[2] = hextable[sum & 0xF]; sum >>= 4; + end[1] = hextable[sum & 0xF]; sum >>= 4; + end[0] = hextable[sum & 0xF]; + return(end+4); +} +static unsigned char *strip_make_packet(unsigned char *buffer, struct strip *strip_info, struct sk_buff *skb) +{ + __u8 *ptr = buffer; __u8 *stuffstate = NULL; STRIP_Header *header = (STRIP_Header *)skb->data; MetricomAddress haddr = header->dst_addr; @@ -1603,7 +1345,6 @@ { printk(KERN_ERR "%s: strip_make_packet: Unknown packet type 0x%04X\n", strip_info->dev.name, ntohs(header->protocol)); - strip_info->tx_dropped++; return(NULL); } @@ -1611,7 +1352,6 @@ { printk(KERN_ERR "%s: Dropping oversized transmit packet: %d bytes\n", strip_info->dev.name, len); - strip_info->tx_dropped++; return(NULL); } @@ -1629,6 +1369,12 @@ } } + /* + * If we're sending to ourselves, discard the packet. + * (Metricom radios choke if they try to send a packet to their own address.) + */ + if (!memcmp(haddr.c, strip_info->true_dev_addr.c, sizeof(haddr))) + return(NULL); *ptr++ = '*'; *ptr++ = hextable[haddr.c[2] >> 4]; *ptr++ = hextable[haddr.c[2] & 0xF]; @@ -1645,17 +1391,9 @@ *ptr++ = key.c[2]; *ptr++ = key.c[3]; -#if DO_PROC_NET_STRIP_TRACE - start_ptr = ptr; -#endif DO_PROC_NET_STRIP_TRACE - ptr = StuffData(skb->data + sizeof(STRIP_Header), len, ptr, &stuffstate); -#if DO_PROC_NET_STRIP_TRACE - packet_log(strip_info, skb->data + sizeof(STRIP_Header), EntrySend, - header, len, ptr-start_ptr, - slip_len(skb->data + sizeof(STRIP_Header), len)); -#endif DO_PROC_NET_STRIP_TRACE + if (strip_info->firmware_level >= ChecksummedMessages) ptr = add_checksum(buffer+1, ptr); *ptr++ = 0x0D; return(ptr); @@ -1664,57 +1402,108 @@ static void strip_send(struct strip *strip_info, struct sk_buff *skb) { unsigned char *ptr = strip_info->tx_buff; + int doreset = (long)jiffies - strip_info->watchdog_doreset >= 0; + int doprobe = (long)jiffies - strip_info->watchdog_doprobe >= 0 && !doreset; - /* If we have a packet, encapsulate it and put it in the buffer */ + /* + * 1. If we have a packet, encapsulate it and put it in the buffer + */ if (skb) { - ptr = strip_make_packet(ptr, strip_info, skb); - /* If error, unlock and return */ - if (!ptr) { strip_unlock(strip_info); return; } - strip_info->tx_packets++; /* Count another successful packet */ - /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/ - /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/ - } - - /* Set up the strip_info ready to send the data */ - strip_info->tx_head = strip_info->tx_buff; - strip_info->tx_left = ptr - strip_info->tx_buff; - strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); - - /* If watchdog has expired, reset the radio */ - if ((long)jiffies - strip_info->watchdog_doreset >= 0) - { - ResetRadio(strip_info); - return; - /* Note: if there's a packet to send, strip_write_some_more - will do it after the reset has finished */ + char *newptr = strip_make_packet(ptr, strip_info, skb); + strip_info->tx_pps_count++; + if (!newptr) strip_info->tx_dropped++; + else + { + ptr = newptr; + strip_info->sx_pps_count++; + strip_info->tx_packets++; /* Count another successful packet */ +#ifdef EXT_COUNTERS + strip_info->tx_bytes += skb->len; + strip_info->tx_rbytes += ptr - strip_info->tx_buff; +#endif + /*DumpData("Sending:", strip_info, strip_info->tx_buff, ptr);*/ + /*HexDump("Sending", strip_info, strip_info->tx_buff, ptr);*/ + } } - /* No reset. - * If it is time for another tickle, tack it on the end of the packet + /* + * 2. If it is time for another tickle, tack it on, after the packet */ - if ((long)jiffies - strip_info->watchdog_doprobe >= 0) + if (doprobe) { - /* Send tickle to make radio protest */ - /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/ - const char *TickleString = TickleString1; - int length = sizeof(TickleString1)-1; - if (strip_info->structured_messages) + StringDescriptor ts = CommandString[strip_info->next_command]; +#if TICKLE_TIMERS { - TickleString = TickleString2; - length = sizeof(TickleString2)-1; + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** Sending tickle string %d at %02d.%06d\n", + strip_info->next_command, tv.tv_sec % 100, tv.tv_usec); } - memcpy(ptr, TickleString, length); - strip_info->tx_left += length; +#endif + if (ptr == strip_info->tx_buff) *ptr++ = 0x0D; + + *ptr++ = '*'; /* First send "**" to provoke an error message */ + *ptr++ = '*'; + + /* Then add the command */ + memcpy(ptr, ts.string, ts.length); + + /* Add a checksum ? */ + if (strip_info->firmware_level < ChecksummedMessages) ptr += ts.length; + else ptr = add_checksum(ptr, ptr + ts.length); + + *ptr++ = 0x0D; /* Terminate the command with a */ + + /* Cycle to next periodic command? */ + if (strip_info->firmware_level >= StructuredMessages) + if (++strip_info->next_command >= ELEMENTS_OF(CommandString)) + strip_info->next_command = 0; +#ifdef EXT_COUNTERS + strip_info->tx_ebytes += ts.length; +#endif strip_info->watchdog_doprobe = jiffies + 10 * HZ; strip_info->watchdog_doreset = jiffies + 1 * HZ; + /*printk(KERN_INFO "%s: Routine radio test.\n", strip_info->dev.name);*/ } /* - * If it is time for a periodic ARP, queue one up to be sent + * 3. Set up the strip_info ready to send the data (if any). + */ + strip_info->tx_head = strip_info->tx_buff; + strip_info->tx_left = ptr - strip_info->tx_buff; + strip_info->tty->flags |= (1 << TTY_DO_WRITE_WAKEUP); + + /* + * 4. Debugging check to make sure we're not overflowing the buffer. + */ + if (strip_info->tx_size - strip_info->tx_left < 20) + printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name, + strip_info->tx_left, strip_info->tx_size - strip_info->tx_left); + + /* + * 5. If watchdog has expired, reset the radio. Note: if there's data waiting in + * the buffer, strip_write_some_more will send it after the reset has finished + */ + if (doreset) { ResetRadio(strip_info); return; } + + /* + * 6. If it is time for a periodic ARP, queue one up to be sent. + * We only do this if: + * 1. The radio is working + * 2. It's time to send another periodic ARP + * 3. We really know what our address is (and it is not manually set to zero) + * 4. We have a designated broadcast address configured + * If we queue up an ARP packet when we don't have a designated broadcast + * address configured, then the packet will just have to be discarded in + * strip_make_packet. This is not fatal, but it causes misleading information + * to be displayed in tcpdump. tcpdump will report that periodic APRs are + * being sent, when in fact they are not, because they are all being dropped + * in the strip_make_packet routine. */ if (strip_info->working && (long)jiffies - strip_info->gratuitous_arp >= 0 && - memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address))) + memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) && + *strip_info->dev.broadcast!=0xFF) { /*printk(KERN_INFO "%s: Sending gratuitous ARP with interval %ld\n", strip_info->dev.name, strip_info->arp_interval / HZ);*/ @@ -1722,16 +1511,18 @@ strip_info->arp_interval *= 2; if (strip_info->arp_interval > MaxARPInterval) strip_info->arp_interval = MaxARPInterval; - arp_send(ARPOP_REPLY, ETH_P_ARP, strip_info->dev.pa_addr, - &strip_info->dev, strip_info->dev.pa_addr, - NULL, strip_info->dev.dev_addr, NULL); + arp_send(ARPOP_REPLY, ETH_P_ARP, + strip_info->dev.pa_addr, /* Target address of ARP packet is our address */ + &strip_info->dev, /* Device to send packet on */ + strip_info->dev.pa_addr, /* Source IP address this ARP packet comes from */ + NULL, /* Destination HW address is NULL (broadcast it) */ + strip_info->dev.dev_addr, /* Source HW address is our HW address */ + strip_info->dev.dev_addr); /* Target HW address is our HW address (redundant) */ } - if (strip_info->tx_size - strip_info->tx_left < 20) - printk(KERN_ERR "%s: Sending%5d bytes;%5d bytes free.\n", strip_info->dev.name, - strip_info->tx_left, strip_info->tx_size - strip_info->tx_left); - - /* All ready. Start the transmission */ + /* + * 7. All ready. Start the transmission + */ strip_write_some_more(strip_info->tty); } @@ -1752,6 +1543,33 @@ if (strip_info->mtu != strip_info->dev.mtu) strip_changedmtu(strip_info); + if (jiffies - strip_info->pps_timer > HZ) + { + unsigned long t = jiffies - strip_info->pps_timer; + unsigned long rx_pps_count = (strip_info->rx_pps_count * HZ * 8 + t/2) / t; + unsigned long tx_pps_count = (strip_info->tx_pps_count * HZ * 8 + t/2) / t; + unsigned long sx_pps_count = (strip_info->sx_pps_count * HZ * 8 + t/2) / t; + + strip_info->pps_timer = jiffies; + strip_info->rx_pps_count = 0; + strip_info->tx_pps_count = 0; + strip_info->sx_pps_count = 0; + + strip_info->rx_average_pps = (strip_info->rx_average_pps + rx_pps_count + 1) / 2; + strip_info->tx_average_pps = (strip_info->tx_average_pps + tx_pps_count + 1) / 2; + strip_info->sx_average_pps = (strip_info->sx_average_pps + sx_pps_count + 1) / 2; + + if (rx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Receiving %ld packets per second.\n", + strip_info->dev.name, rx_pps_count / 8); + if (tx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Tx %ld packets per second.\n", + strip_info->dev.name, tx_pps_count / 8); + if (sx_pps_count / 8 >= 10) + printk(KERN_INFO "%s: WARNING: Sending %ld packets per second.\n", + strip_info->dev.name, sx_pps_count / 8); + } + strip_send(strip_info, skb); if (skb) dev_kfree_skb(skb, FREE_WRITE); @@ -1759,6 +1577,17 @@ } /* + * IdleTask periodically calls strip_xmit, so even when we have no IP packets + * to send for an extended period of time, the watchdog processing still gets + * done to ensure that the radio stays in Starmode + */ + +static void strip_IdleTask(unsigned long parameter) +{ + strip_xmit(NULL, (struct device *)parameter); +} + +/* * Create the MAC header for an arbitrary protocol layer * * saddr!=NULL means use this specific address (n/a for Metricom) @@ -1772,19 +1601,20 @@ static int strip_header(struct sk_buff *skb, struct device *dev, unsigned short type, void *daddr, void *saddr, unsigned len) { + struct strip *strip_info = (struct strip *)(dev->priv); STRIP_Header *header = (STRIP_Header *)skb_push(skb, sizeof(STRIP_Header)); /*printk(KERN_INFO "%s: strip_header 0x%04X %s\n", dev->name, type, type == ETH_P_IP ? "IP" : type == ETH_P_ARP ? "ARP" : "");*/ - memcpy(header->src_addr.c, dev->dev_addr, dev->addr_len); + header->src_addr = strip_info->true_dev_addr; header->protocol = htons(type); /*HexDump("strip_header", (struct strip *)(dev->priv), skb->data, skb->data + skb->len);*/ if (!daddr) return(-dev->hard_header_len); - memcpy(header->dst_addr.c, daddr, dev->addr_len); + header->dst_addr = *(MetricomAddress*)daddr; return(dev->hard_header_len); } @@ -1811,43 +1641,130 @@ #endif } + +/************************************************************************/ +/* Receiving routines */ + +static int strip_receive_room(struct tty_struct *tty) +{ + return 0x10000; /* We can handle an infinite amount of data. :-) */ +} + /* - * IdleTask periodically calls strip_xmit, so even when we have no IP packets - * to send for an extended period of time, the watchdog processing still gets - * done to ensure that the radio stays in Starmode + * This function parses the response to the ATS300? command, + * extracting the radio version and serial number. */ - -static void strip_IdleTask(unsigned long parameter) +static void get_radio_version(struct strip *strip_info, __u8 *ptr, __u8 *end) { - strip_xmit(NULL, (struct device *)parameter); + __u8 *p, *value_begin, *value_end; + int len; + + /* Determine the beginning of the second line of the payload */ + p = ptr; + while (p < end && *p != 10) p++; + if (p >= end) return; + p++; + value_begin = p; + + /* Determine the end of line */ + while (p < end && *p != 10) p++; + if (p >= end) return; + value_end = p; + p++; + + len = value_end - value_begin; + len = MIN(len, sizeof(FirmwareVersion) - 1); + if (strip_info->firmware_version.c[0] == 0) + printk(KERN_INFO "%s: Radio Firmware: %.*s\n", + strip_info->dev.name, len, value_begin); + sprintf(strip_info->firmware_version.c, "%.*s", len, value_begin); + + /* Look for the first colon */ + while (p < end && *p != ':') p++; + if (p >= end) return; + /* Skip over the space */ + p += 2; + len = sizeof(SerialNumber) - 1; + if (p + len <= end) { + sprintf(strip_info->serial_number.c, "%.*s", len, p); + } + else { + printk(KERN_DEBUG "STRIP: radio serial number shorter (%d) than expected (%d)\n", + end - p, len); + } } +/* + * This function parses the response to the ATS325? command, + * extracting the radio battery voltage. + */ +static void get_radio_voltage(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + int len; -/************************************************************************/ -/* Receiving routines */ + len = sizeof(BatteryVoltage) - 1; + if (ptr + len <= end) { + sprintf(strip_info->battery_voltage.c, "%.*s", len, ptr); + } + else { + printk(KERN_DEBUG "STRIP: radio voltage string shorter (%d) than expected (%d)\n", + end - ptr, len); + } +} -static int strip_receive_room(struct tty_struct *tty) +/* + * This function parses the responses to the AT~LA and ATS311 commands, + * which list the radio's neighbours. + */ +static void get_radio_neighbours(MetricomNodeTable *table, __u8 *ptr, __u8 *end) { - return 0x10000; /* We can handle an infinite amount of data. :-) */ + table->num_nodes = 0; + while (ptr < end && table->num_nodes < NODE_TABLE_SIZE) + { + MetricomNode *node = &table->node[table->num_nodes++]; + char *dst = node->c, *limit = dst + sizeof(*node) - 1; + while (ptr < end && *ptr <= 32) ptr++; + while (ptr < end && dst < limit && *ptr != 10) *dst++ = *ptr++; + *dst++ = 0; + while (ptr < end && ptr[-1] != 10) ptr++; + } + do_gettimeofday(&table->timestamp); } -static void get_radio_address(struct strip *strip_info, __u8 *p) +static int get_radio_address(struct strip *strip_info, __u8 *p) { MetricomAddress addr; - string_to_radio_address(&addr, p); + if (string_to_radio_address(&addr, p)) return(1); /* See if our radio address has changed */ - if (memcmp(strip_info->dev.dev_addr, addr.c, sizeof(addr))) + if (memcmp(strip_info->true_dev_addr.c, addr.c, sizeof(addr))) { MetricomAddressString addr_string; radio_address_to_string(&addr, &addr_string); - printk(KERN_INFO "%s: My radio address = %s\n", strip_info->dev.name, addr_string.c); - memcpy(strip_info->dev.dev_addr, addr.c, sizeof(addr)); + printk(KERN_INFO "%s: Radio address = %s\n", strip_info->dev.name, addr_string.c); + strip_info->true_dev_addr = addr; + if (!strip_info->manual_dev_addr) *(MetricomAddress*)strip_info->dev.dev_addr = addr; /* Give the radio a few seconds to get its head straight, then send an arp */ - strip_info->gratuitous_arp = jiffies + 6 * HZ; + strip_info->gratuitous_arp = jiffies + 15 * HZ; strip_info->arp_interval = 1 * HZ; } + return(0); +} + +static int verify_checksum(struct strip *strip_info) +{ + __u8 *p = strip_info->sx_buff; + __u8 *end = strip_info->sx_buff + strip_info->sx_count - 4; + u_short sum = (READHEX16(end[0]) << 12) | (READHEX16(end[1]) << 8) | + (READHEX16(end[2]) << 4) | (READHEX16(end[3])); + while (p < end) sum -= *p++; + if (sum == 0 && strip_info->firmware_level == StructuredMessages) + { + strip_info->firmware_level = ChecksummedMessages; + printk(KERN_INFO "%s: Radio provides message checksums\n", strip_info->dev.name); + } + return(sum == 0); } static void RecvErr(char *msg, struct strip *strip_info) @@ -1860,114 +1777,156 @@ static void RecvErr_Message(struct strip *strip_info, __u8 *sendername, const __u8 *msg) { - static const char ERR_001[] = "001"; /* Not in StarMode! */ - static const char ERR_002[] = "002"; /* Remap handle */ - static const char ERR_003[] = "003"; /* Can't resolve name */ - static const char ERR_004[] = "004"; /* Name too small or missing */ - static const char ERR_005[] = "005"; /* Bad count specification */ - static const char ERR_006[] = "006"; /* Header too big */ - static const char ERR_007[] = "007"; /* Body too big */ - static const char ERR_008[] = "008"; /* Bad character in name */ - static const char ERR_009[] = "009"; /* No count or line terminator */ - - if (!strncmp(msg, ERR_001, sizeof(ERR_001)-1)) + if (has_prefix(msg, "001")) /* Not in StarMode! */ { RecvErr("Error Msg:", strip_info); printk(KERN_INFO "%s: Radio %s is not in StarMode\n", strip_info->dev.name, sendername); } - else if (!strncmp(msg, ERR_002, sizeof(ERR_002)-1)) + + else if (has_prefix(msg, "002")) /* Remap handle */ { - RecvErr("Error Msg:", strip_info); -#ifdef notyet /*Kernel doesn't have scanf!*/ - int handle; - __u8 newname[64]; - sscanf(msg, "ERR_002 Remap handle &%d to name %s", &handle, newname); - printk(KERN_INFO "%s: Radio name %s is handle %d\n", - strip_info->dev.name, newname, handle); -#endif + /* We ignore "Remap handle" messages for now */ } - else if (!strncmp(msg, ERR_003, sizeof(ERR_003)-1)) + + else if (has_prefix(msg, "003")) /* Can't resolve name */ { RecvErr("Error Msg:", strip_info); printk(KERN_INFO "%s: Destination radio name is unknown\n", strip_info->dev.name); } - else if (!strncmp(msg, ERR_004, sizeof(ERR_004)-1)) + + else if (has_prefix(msg, "004")) /* Name too small or missing */ { strip_info->watchdog_doreset = jiffies + LongTime; +#if TICKLE_TIMERS + { + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** Got ERR_004 response at %02d.%06d\n", + tv.tv_sec % 100, tv.tv_usec); + } +#endif if (!strip_info->working) { strip_info->working = TRUE; - printk(KERN_INFO "%s: Radio now in starmode\n", - strip_info->dev.name); + printk(KERN_INFO "%s: Radio now in starmode\n", strip_info->dev.name); /* * If the radio has just entered a working state, we should do our first * probe ASAP, so that we find out our radio address etc. without delay. */ strip_info->watchdog_doprobe = jiffies; } - if (!strip_info->structured_messages && sendername) + if (strip_info->firmware_level == NoStructure && sendername) { - strip_info->structured_messages = TRUE; - printk(KERN_INFO "%s: Radio provides structured messages\n", - strip_info->dev.name); + strip_info->firmware_level = StructuredMessages; + strip_info->next_command = 0; /* Try to enable checksums ASAP */ + printk(KERN_INFO "%s: Radio provides structured messages\n", strip_info->dev.name); + } + if (strip_info->firmware_level >= StructuredMessages) + { + verify_checksum(strip_info); + /* + * If the radio has structured messages but we don't yet have all our information about it, we should do + * probes without delay, until we have gathered all the information + */ + if (!GOT_ALL_RADIO_INFO(strip_info)) strip_info->watchdog_doprobe = jiffies; } } - else if (!strncmp(msg, ERR_005, sizeof(ERR_005)-1)) + + else if (has_prefix(msg, "005")) /* Bad count specification */ RecvErr("Error Msg:", strip_info); - else if (!strncmp(msg, ERR_006, sizeof(ERR_006)-1)) + + else if (has_prefix(msg, "006")) /* Header too big */ RecvErr("Error Msg:", strip_info); - else if (!strncmp(msg, ERR_007, sizeof(ERR_007)-1)) + + else if (has_prefix(msg, "007")) /* Body too big */ { - /* - * Note: This error knocks the radio back into - * command mode. - */ RecvErr("Error Msg:", strip_info); - printk(KERN_ERR "%s: Error! Packet size too big for radio.", + printk(KERN_ERR "%s: Error! Packet size too big for radio.\n", strip_info->dev.name); - strip_info->watchdog_doreset = jiffies; /* Do reset ASAP */ } - else if (!strncmp(msg, ERR_008, sizeof(ERR_008)-1)) + + else if (has_prefix(msg, "008")) /* Bad character in name */ { RecvErr("Error Msg:", strip_info); printk(KERN_ERR "%s: Radio name contains illegal character\n", strip_info->dev.name); } - else if (!strncmp(msg, ERR_009, sizeof(ERR_009)-1)) + + else if (has_prefix(msg, "009")) /* No count or line terminator */ RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, "010")) /* Invalid checksum */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, "011")) /* Checksum didn't match */ + RecvErr("Error Msg:", strip_info); + + else if (has_prefix(msg, "012")) /* Failed to transmit packet */ + RecvErr("Error Msg:", strip_info); + else RecvErr("Error Msg:", strip_info); } static void process_AT_response(struct strip *strip_info, __u8 *ptr, __u8 *end) { - static const char ATS305[] = "ATS305?"; - static const char ATS300[] = "ATS300?"; - static const char ATS325[] = "ATS325?"; - static const char ATI2[] = "AT~I2 nn"; - - /* Skip to the first newline character */ __u8 *p = ptr; - while (p < end && *p != 10) p++; - if (p >= end) return; - p++; + while (p < end && p[-1] != 10) p++; /* Skip past first newline character */ + /* Now ptr points to the AT command, and p points to the text of the response. */ - if (!strncmp(ptr, ATS305, sizeof(ATS305)-1)) +#if TICKLE_TIMERS { - if (IS_RADIO_ADDRESS(p)) get_radio_address(strip_info, p); - } - else if (!strncmp(ptr, ATS300, sizeof(ATS300)-1)) { - get_radio_version(strip_info, p, end); - } - else if (!strncmp(ptr, ATS325, sizeof(ATS325)-1)) { - get_radio_voltage(strip_info, p, end); + struct timeval tv; + do_gettimeofday(&tv); + printk(KERN_INFO "**** Got AT response %.7s at %02d.%06d\n", + ptr, tv.tv_sec % 100, tv.tv_usec); } - else if (!strncmp(ptr, ATI2, sizeof(ATI2)-1)) { - get_radio_neighbors(strip_info, p, end); +#endif + + if (has_prefix(ptr, "ATS300?" )) get_radio_version(strip_info, p, end); + else if (has_prefix(ptr, "ATS305?" )) get_radio_address(strip_info, p); + else if (has_prefix(ptr, "ATS311?" )) get_radio_neighbours(&strip_info->poletops, p, end); + else if (has_prefix(ptr, "ATS319=7")) verify_checksum(strip_info); + else if (has_prefix(ptr, "ATS325?" )) get_radio_voltage(strip_info, p, end); + else if (has_prefix(ptr, "AT~LA" )) get_radio_neighbours(&strip_info->portables, p, end); + else RecvErr("Unknown AT Response:", strip_info); +} + +static void process_ACK(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + /* Currently we don't do anything with ACKs from the radio */ +} + +static void process_Info(struct strip *strip_info, __u8 *ptr, __u8 *end) +{ + if (ptr+16 > end) RecvErr("Bad Info Msg:", strip_info); +} + +static struct device *get_strip_dev(struct strip *strip_info) +{ + /* If our hardware address is *manually set* to zero, and we know our */ + /* real radio hardware address, try to find another strip device that has been */ + /* manually set to that address that we can 'transfer ownership' of this packet to */ + if (strip_info->manual_dev_addr && + !memcmp(strip_info->dev.dev_addr, zero_address.c, sizeof(zero_address)) && + memcmp(&strip_info->true_dev_addr, zero_address.c, sizeof(zero_address))) + { + struct device *dev = dev_base; + while (dev) + { + if (dev->type == strip_info->dev.type && + !memcmp(dev->dev_addr, &strip_info->true_dev_addr, sizeof(MetricomAddress))) + { + printk(KERN_INFO "%s: Transferred packet ownership to %s.\n", + strip_info->dev.name, dev->name); + return(dev); + } + dev = dev->next; + } } - else RecvErr("Unknown AT Response:", strip_info); + return(&strip_info->dev); } /* @@ -1979,14 +1938,14 @@ struct sk_buff *skb = dev_alloc_skb(sizeof(STRIP_Header) + packetlen); if (!skb) { - printk(KERN_INFO "%s: memory squeeze, dropping packet.\n", strip_info->dev.name); + printk(KERN_ERR "%s: memory squeeze, dropping packet.\n", strip_info->dev.name); strip_info->rx_dropped++; } else { memcpy(skb_put(skb, sizeof(STRIP_Header)), header, sizeof(STRIP_Header)); memcpy(skb_put(skb, packetlen), strip_info->rx_buff, packetlen); - skb->dev = &strip_info->dev; + skb->dev = get_strip_dev(strip_info); skb->protocol = header->protocol; skb->mac.raw = skb->data; @@ -1997,6 +1956,10 @@ /* Finally, hand the packet up to the next layer (e.g. IP or ARP, etc.) */ strip_info->rx_packets++; + strip_info->rx_pps_count++; +#ifdef EXT_COUNTERS + strip_info->rx_bytes += packetlen; +#endif netif_rx(skb); } } @@ -2005,10 +1968,6 @@ { __u16 packetlen; -#if DO_PROC_NET_STRIP_TRACE - __u8 *start_ptr = ptr; -#endif DO_PROC_NET_STRIP_TRACE - /* Decode start of the IP packet header */ ptr = UnStuffData(ptr, end, strip_info->rx_buff, 4); if (!ptr) @@ -2019,9 +1978,9 @@ packetlen = ((__u16)strip_info->rx_buff[2] << 8) | strip_info->rx_buff[3]; - if (packetlen > MAX_STRIP_MTU) + if (packetlen > MAX_RECV_MTU) { - printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n", + printk(KERN_INFO "%s: Dropping oversized received IP packet: %d bytes\n", strip_info->dev.name, packetlen); strip_info->rx_dropped++; return; @@ -2045,11 +2004,6 @@ header->protocol = htons(ETH_P_IP); -#if DO_PROC_NET_STRIP_TRACE - packet_log(strip_info, strip_info->rx_buff, EntryReceive, header, - packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); -#endif DO_PROC_NET_STRIP_TRACE - deliver_packet(strip_info, header, packetlen); } @@ -2058,10 +2012,6 @@ __u16 packetlen; struct arphdr *arphdr = (struct arphdr *)strip_info->rx_buff; -#if DO_PROC_NET_STRIP_TRACE - __u8 *start_ptr = ptr; -#endif DO_PROC_NET_STRIP_TRACE - /* Decode start of the ARP packet */ ptr = UnStuffData(ptr, end, strip_info->rx_buff, 8); if (!ptr) @@ -2072,9 +2022,9 @@ packetlen = 8 + (arphdr->ar_hln + arphdr->ar_pln) * 2; - if (packetlen > MAX_STRIP_MTU) + if (packetlen > MAX_RECV_MTU) { - printk(KERN_ERR "%s: Dropping oversized receive packet: %d bytes\n", + printk(KERN_INFO "%s: Dropping oversized received ARP packet: %d bytes\n", strip_info->dev.name, packetlen); strip_info->rx_dropped++; return; @@ -2100,15 +2050,47 @@ header->protocol = htons(ETH_P_ARP); -#if DO_PROC_NET_STRIP_TRACE - packet_log(strip_info, strip_info->rx_buff, EntryReceive, header, - packetlen, end-start_ptr, slip_len(strip_info->rx_buff, packetlen)); -#endif DO_PROC_NET_STRIP_TRACE - deliver_packet(strip_info, header, packetlen); } -static void process_packet(struct strip *strip_info) +/* + * process_text_message processes a -terminated block of data received + * from the radio that doesn't begin with a '*' character. All normal + * Starmode communication messages with the radio begin with a '*', + * so any text that does not indicates a serial port error, a radio that + * is in Hayes command mode instead of Starmode, or a radio with really + * old firmware that doesn't frame its Starmode responses properly. + */ +static void process_text_message(struct strip *strip_info) +{ + __u8 *msg = strip_info->sx_buff; + int len = strip_info->sx_count; + + /* Check for anything that looks like it might be our radio name */ + /* (This is here for backwards compatibility with old firmware) */ + if (len == 9 && get_radio_address(strip_info, msg) == 0) return; + + if (text_equal(msg, len, "OK" )) return; /* Ignore 'OK' responses from prior commands */ + if (text_equal(msg, len, "ERROR" )) return; /* Ignore 'ERROR' messages */ + if (text_equal(msg, len, InitString)) return; /* Ignore character echo back from the radio */ + + /* Catch other error messages */ + /* (This is here for backwards compatibility with old firmware) */ + if (has_prefix(msg, "ERR_")) { RecvErr_Message(strip_info, NULL, &msg[4]); return; } + + RecvErr("No initial *", strip_info); +} + +/* + * process_message processes a -terminated block of data received + * from the radio. If the radio is not in Starmode or has old firmware, + * it may be a line of text in response to an AT command. Ideally, with + * a current radio that's properly in Starmode, all data received should + * be properly framed and checksummed radio message blocks, containing + * either a starmode packet, or a other communication from the radio + * firmware, like "INF_" Info messages and &COMMAND responses. + */ +static void process_message(struct strip *strip_info) { STRIP_Header header = { zero_address, zero_address, 0 }; __u8 *ptr = strip_info->sx_buff; @@ -2116,29 +2098,11 @@ __u8 sendername[32], *sptr = sendername; MetricomKey key; - /* Ignore 'OK' responses from prior commands */ - if (strip_info->sx_count == 2 && ptr[0] == 'O' && ptr[1] == 'K') return; - - /* Check for anything that looks like it might be our radio name: dddd-dddd */ - /* (This is here for backwards compatibility with old firmware) */ - if (strip_info->sx_count == 9 && IS_RADIO_ADDRESS(ptr)) - { - get_radio_address(strip_info, ptr); - return; - } - /*HexDump("Receiving", strip_info, ptr, end);*/ /* Check for start of address marker, and then skip over it */ - if (*ptr != '*') - { - /* Catch other error messages */ - if (ptr[0] == 'E' && ptr[1] == 'R' && ptr[2] == 'R' && ptr[3] == '_') - RecvErr_Message(strip_info, NULL, &ptr[4]); - else RecvErr("No initial *", strip_info); - return; - } - ptr++; /* Skip the initial '*' */ + if (*ptr == '*') ptr++; + else { process_text_message(strip_info); return; } /* Copy out the return address */ while (ptr < end && *ptr != '*' && sptr < ARRAY_END(sendername)-1) *sptr++ = *ptr++; @@ -2156,16 +2120,39 @@ /* (This is here for backwards compatibility with old firmware) */ if (!strcmp(sendername, "&COMMAND")) { - strip_info->structured_messages = FALSE; + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; return; } - if (ptr+4 >= end) + if (ptr+4 > end) { RecvErr("No proto key", strip_info); return; } + /* Get the protocol key out of the buffer */ + key.c[0] = *ptr++; + key.c[1] = *ptr++; + key.c[2] = *ptr++; + key.c[3] = *ptr++; + + /* If we're using checksums, verify the checksum at the end of the packet */ + if (strip_info->firmware_level >= ChecksummedMessages) + { + end -= 4; /* Chop the last four bytes off the packet (they're the checksum) */ + if (ptr > end) + { + RecvErr("Missing Checksum", strip_info); + return; + } + if (!verify_checksum(strip_info)) + { + RecvErr("Bad Checksum", strip_info); + return; + } + } + /*printk(KERN_INFO "%s: Got packet from \"%s\".\n", strip_info->dev.name, sendername);*/ /* @@ -2173,38 +2160,45 @@ * We assume that the destination address was our address (the radio does not * tell us this). If the radio supplies a source address, then we use it. */ - memcpy(&header.dst_addr, strip_info->dev.dev_addr, sizeof(MetricomAddress)); - if (IS_RADIO_ADDRESS(sendername)) string_to_radio_address(&header.src_addr, sendername); + header.dst_addr = strip_info->true_dev_addr; + string_to_radio_address(&header.src_addr, sendername); - /* Get the protocol key out of the buffer */ - key.c[0] = *ptr++; - key.c[1] = *ptr++; - key.c[2] = *ptr++; - key.c[3] = *ptr++; - - if (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end); - else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end); +#ifdef EXT_COUNTERS + if (key.l == SIP0Key.l) { + strip_info->rx_rbytes += (end - ptr); + process_IP_packet(strip_info, &header, ptr, end); + } else if (key.l == ARP0Key.l) { + strip_info->rx_rbytes += (end - ptr); + process_ARP_packet(strip_info, &header, ptr, end); + } else if (key.l == ATR_Key.l) { + strip_info->rx_ebytes += (end - ptr); + process_AT_response(strip_info, ptr, end); + } else if (key.l == ACK_Key.l) { + strip_info->rx_ebytes += (end - ptr); + process_ACK(strip_info, ptr, end); + } else if (key.l == INF_Key.l) { + strip_info->rx_ebytes += (end - ptr); + process_Info(strip_info, ptr, end); + } else if (key.l == ERR_Key.l) { + strip_info->rx_ebytes += (end - ptr); + RecvErr_Message(strip_info, sendername, ptr); + } else RecvErr("Unrecognized protocol key", strip_info); +#else + if (key.l == SIP0Key.l) process_IP_packet (strip_info, &header, ptr, end); + else if (key.l == ARP0Key.l) process_ARP_packet (strip_info, &header, ptr, end); else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); - else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr); - else /* RecvErr("Unrecognized protocol key", strip_info); */ - - /* Note, this "else" block is temporary, until Metricom fix their */ - /* packet corruption bug */ - { - RecvErr("Unrecognized protocol key (retrying)", strip_info); - ptr -= 3; /* Back up and try again */ - key.c[0] = *ptr++; - key.c[1] = *ptr++; - key.c[2] = *ptr++; - key.c[3] = *ptr++; - if (key.l == SIP0Key.l) process_IP_packet(strip_info, &header, ptr, end); - else if (key.l == ARP0Key.l) process_ARP_packet(strip_info, &header, ptr, end); - else if (key.l == ATR_Key.l) process_AT_response(strip_info, ptr, end); - else if (key.l == ERR_Key.l) RecvErr_Message(strip_info, sendername, ptr); - else RecvErr("Unrecognized protocol key", strip_info); - } + else if (key.l == ACK_Key.l) process_ACK (strip_info, ptr, end); + else if (key.l == INF_Key.l) process_Info (strip_info, ptr, end); + else if (key.l == ERR_Key.l) RecvErr_Message (strip_info, sendername, ptr); + else RecvErr("Unrecognized protocol key", strip_info); +#endif } +#define TTYERROR(X) ((X) == TTY_BREAK ? "Break" : \ + (X) == TTY_FRAME ? "Framing Error" : \ + (X) == TTY_PARITY ? "Parity Error" : \ + (X) == TTY_OVERRUN ? "Hardware Overrun" : "Unknown Error") + /* * Handle the 'receiver data ready' interrupt. * This function is called by the 'tty_io' module in the kernel when @@ -2229,17 +2223,23 @@ { struct timeval tv; do_gettimeofday(&tv); - printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %d.%06d\n", + printk(KERN_INFO "**** strip_receive_buf: %3d bytes at %02d.%06d\n", count, tv.tv_sec % 100, tv.tv_usec); } #endif +#ifdef EXT_COUNTERS + strip_info->rx_sbytes += count; +#endif + /* Read the characters out of the buffer */ while (cp < end) { + if (fp && *fp) printk(KERN_INFO "%s: %s on serial port\n", strip_info->dev.name, TTYERROR(*fp)); if (fp && *fp++ && !strip_info->discard) /* If there's a serial error, record it */ { - strip_info->discard = 1; + /* If we have some characters in the buffer, discard them */ + strip_info->discard = strip_info->sx_count; strip_info->rx_errors++; } @@ -2249,21 +2249,23 @@ if (*cp == 0x0D) /* If end of packet, decide what to do with it */ { if (strip_info->sx_count > 3000) - printk(KERN_INFO "Cut a %d byte packet (%d bytes remaining)%s\n", - strip_info->sx_count, end-cp-1, + printk(KERN_INFO "%s: Cut a %d byte packet (%d bytes remaining)%s\n", + strip_info->dev.name, strip_info->sx_count, end-cp-1, strip_info->discard ? " (discarded)" : ""); if (strip_info->sx_count > strip_info->sx_size) { - strip_info->discard = 1; strip_info->rx_over_errors++; printk(KERN_INFO "%s: sx_buff overflow (%d bytes total)\n", strip_info->dev.name, strip_info->sx_count); } - if (!strip_info->discard) process_packet(strip_info); + else if (strip_info->discard) + printk(KERN_INFO "%s: Discarding bad packet (%d/%d)\n", + strip_info->dev.name, strip_info->discard, strip_info->sx_count); + else process_message(strip_info); strip_info->discard = 0; strip_info->sx_count = 0; } - else if (!strip_info->discard) /* If we're not discarding, store the character */ + else { /* Make sure we have space in the buffer */ if (strip_info->sx_count < strip_info->sx_size) @@ -2279,9 +2281,28 @@ /************************************************************************/ /* General control routines */ -static int strip_set_dev_mac_address(struct device *dev, void *addr) +static int set_mac_address(struct strip *strip_info, MetricomAddress *addr) { - return -1; /* You cannot override a Metricom radio's address */ + /* + * We're using a manually specified address if the address is set + * to anything other than all ones. Setting the address to all ones + * disables manual mode and goes back to automatic address determination + * (tracking the true address that the radio has). + */ + strip_info->manual_dev_addr = memcmp(addr->c, broadcast_address.c, sizeof(broadcast_address)); + if (strip_info->manual_dev_addr) + *(MetricomAddress*)strip_info->dev.dev_addr = *addr; + else *(MetricomAddress*)strip_info->dev.dev_addr = strip_info->true_dev_addr; + return 0; +} + +static int dev_set_mac_address(struct device *dev, void *addr) +{ + struct strip *strip_info = (struct strip *)(dev->priv); + struct sockaddr *sa = addr; + printk(KERN_INFO "%s: strip_set_dev_mac_address called\n", dev->name); + set_mac_address(strip_info, (MetricomAddress *)sa->sa_data); + return 0; } static struct net_device_stats *strip_get_stats(struct device *dev) @@ -2341,7 +2362,8 @@ strip_info->discard = 0; strip_info->working = FALSE; - strip_info->structured_messages = FALSE; + strip_info->firmware_level = NoStructure; + strip_info->next_command = CompatibilityCommand; strip_info->sx_count = 0; strip_info->tx_left = 0; @@ -2442,7 +2464,7 @@ dev->rebuild_header = strip_rebuild_header; /* dev->type_trans unused */ /* dev->set_multicast_list unused */ - dev->set_mac_address = strip_set_dev_mac_address; + dev->set_mac_address = dev_set_mac_address; /* dev->do_ioctl unused */ /* dev->set_config unused */ dev->get_stats = strip_get_stats; @@ -2455,19 +2477,10 @@ static void strip_free(struct strip *strip_info) { - MetricomNode *node, *free; - *(strip_info->referrer) = strip_info->next; if (strip_info->next) strip_info->next->referrer = strip_info->referrer; strip_info->magic = 0; - - for (node = strip_info->neighbor_list; node != NULL; ) - { - free = node; - node = node->next; - kfree(free); - } kfree(strip_info); } @@ -2522,13 +2535,9 @@ strip_info->idle_timer.data = (long)&strip_info->dev; strip_info->idle_timer.function = strip_IdleTask; - strip_info->neighbor_list = kmalloc(sizeof(MetricomNode), GFP_KERNEL); - strip_info->neighbor_list->type = 0; - strip_info->neighbor_list->next = NULL; - /* Note: strip_info->if_name is currently 8 characters long */ - sprintf(strip_info->if_name, "st%d", channel_id); - strip_info->dev.name = strip_info->if_name; + sprintf(strip_info->if_name.c, "st%d", channel_id); + strip_info->dev.name = strip_info->if_name.c; strip_info->dev.base_addr = channel_id; strip_info->dev.priv = (void*)strip_info; strip_info->dev.next = NULL; @@ -2598,6 +2607,9 @@ #ifdef MODULE MOD_INC_USE_COUNT; #endif + + printk(KERN_INFO "STRIP: device \"%s\" activated\n", strip_info->if_name.c); + /* * Done. We have linked the TTY line to a channel. */ @@ -2627,6 +2639,7 @@ tty->disc_data = 0; strip_info->tty = NULL; + printk(KERN_INFO "STRIP: device \"%s\" closed down\n", strip_info->if_name.c); strip_free(strip_info); tty->disc_data = NULL; #ifdef MODULE @@ -2657,12 +2670,17 @@ err = verify_area(VERIFY_WRITE, (void*)arg, 16); if (err) return -err; - copy_to_user((void*)arg, strip_info->dev.name, - strlen(strip_info->dev.name) + 1); - return 0; + return copy_to_user((void*)arg, strip_info->dev.name, + strlen(strip_info->dev.name) + 1)?-EFAULT:0; case SIOCSIFHWADDR: - return -EINVAL; + { + MetricomAddress addr; + printk(KERN_INFO "%s: SIOCSIFHWADDR\n", strip_info->dev.name); + if(copy_from_user(&addr, (void*)arg, sizeof(MetricomAddress))) + return -EFAULT; + return(set_mac_address(strip_info, &addr)); + } /* * Allow stty to read, but not set, the serial port @@ -2683,32 +2701,6 @@ /* Initialization */ /* - * Registers with the /proc file system to create different /proc/net files. - */ - -static int strip_proc_net_register(unsigned short type, char *file_name, - int (*get_info)(char *, char **, off_t, int, int)) -{ - struct proc_dir_entry *strip_entry; - - strip_entry = kmalloc(sizeof(struct proc_dir_entry), GFP_ATOMIC); - - memset(strip_entry, 0, sizeof(struct proc_dir_entry)); - strip_entry->low_ino = type; - strip_entry->namelen = strlen(file_name); - strip_entry->name = file_name; - strip_entry->mode = S_IFREG | S_IRUGO; - strip_entry->nlink = 1; - strip_entry->uid = 0; - strip_entry->gid = 0; - strip_entry->size = 0; - strip_entry->ops = &proc_net_inode_operations; - strip_entry->get_info = get_info; - - return proc_net_register(strip_entry); -} - -/* * Initialize the STRIP driver. * This routine is called at boot time, to bootstrap the multi-channel * STRIP driver @@ -2722,7 +2714,7 @@ static struct tty_ldisc strip_ldisc; int status; - printk("STRIP: version %s (unlimited channels)\n", StripVersion); + printk(KERN_INFO "STRIP: Version %s (unlimited channels)\n", StripVersion); /* * Fill in our line protocol discipline, and register it @@ -2747,24 +2739,12 @@ } /* - * Register the status and trace files with /proc + * Register the status file with /proc */ - -#if DO_PROC_NET_STRIP_STATUS - if (strip_proc_net_register(PROC_NET_STRIP_STATUS, "strip_status", - &strip_get_status_info) != 0) + if (proc_net_register(&proc_strip_get_status_info) != 0) { - printk(KERN_ERR "strip: status strip_proc_net_register() failed.\n"); + printk(KERN_ERR "strip: status proc_net_register() failed.\n"); } -#endif - -#if DO_PROC_NET_STRIP_TRACE - if (strip_proc_net_register(PROC_NET_STRIP_TRACE, "strip_trace", - &strip_get_trace_info) != 0) - { - printk(KERN_ERR "strip: trace strip_proc_net_register() failed.\n"); - } -#endif #ifdef MODULE return status; @@ -2794,16 +2774,12 @@ while (struct_strip_list) strip_free(struct_strip_list); - /* Unregister with the /proc/net files here. */ - -#if DO_PROC_NET_STRIP_TRACE - proc_net_unregister(PROC_NET_STRIP_TRACE); -#endif -#if DO_PROC_NET_STRIP_STATUS + /* Unregister with the /proc/net file here. */ proc_net_unregister(PROC_NET_STRIP_STATUS); -#endif if ((i = tty_register_ldisc(N_STRIP, NULL))) printk(KERN_ERR "STRIP: can't unregister line discipline (err = %d)\n", i); + + printk(KERN_INFO "STRIP: Module Unloaded\n"); } #endif /* MODULE */ diff -u --recursive --new-file v2.1.44/linux/drivers/net/sunhme.c linux/drivers/net/sunhme.c --- v2.1.44/linux/drivers/net/sunhme.c Thu May 15 16:48:03 1997 +++ linux/drivers/net/sunhme.c Wed Jul 16 19:22:51 1997 @@ -946,7 +946,8 @@ /* Because we reserve afterwards. */ skb_put(skb, (ETH_FRAME_LEN + RX_OFFSET)); - hb->happy_meal_rxd[i].rx_addr = (unsigned int) skb->data; + hb->happy_meal_rxd[i].rx_addr = + (u32) ((unsigned long)skb->data); skb_reserve(skb, RX_OFFSET); hb->happy_meal_rxd[i].rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); @@ -1615,7 +1616,8 @@ /* Return it to the Happy meal. */ drop_it: hp->net_stats.rx_dropped++; - this->rx_addr = (unsigned int) hp->rx_skbs[elem]->data; + this->rx_addr = + (u32) ((unsigned long)hp->rx_skbs[elem]->data); this->rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); goto next; @@ -1634,7 +1636,8 @@ hp->rx_skbs[elem] = new_skb; new_skb->dev = dev; skb_put(new_skb, (ETH_FRAME_LEN + RX_OFFSET)); - rxbase[elem].rx_addr = (unsigned int) new_skb->data; + rxbase[elem].rx_addr = + (u32) ((unsigned long)new_skb->data); skb_reserve(new_skb, RX_OFFSET); rxbase[elem].rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); @@ -1655,7 +1658,8 @@ memcpy(copy_skb->data, skb->data, len); /* Reuse original ring buffer. */ - rxbase[elem].rx_addr = (unsigned int) skb->data; + rxbase[elem].rx_addr = + (u32) ((unsigned long)skb->data); rxbase[elem].rx_flags = (RXFLAG_OWN | ((RX_BUF_ALLOC_SIZE - RX_OFFSET) << 16)); @@ -1913,7 +1917,8 @@ SXD(("SX", len, entry)); hp->tx_skbs[entry] = skb; - hp->happy_block->happy_meal_txd[entry].tx_addr = (unsigned int) skb->data; + hp->happy_block->happy_meal_txd[entry].tx_addr = + (u32) ((unsigned long)skb->data); hp->happy_block->happy_meal_txd[entry].tx_flags = (TXFLAG_OWN | TXFLAG_SOP | TXFLAG_EOP | (len & TXFLAG_SIZE)); hp->tx_new = NEXT_TX(entry); @@ -2087,6 +2092,8 @@ printk("\n"); hp = (struct happy_meal *) dev->priv; + memset(hp, 0, sizeof(*hp)); + hp->happy_sbus_dev = sdev; if(sdev->num_registers != 5) { diff -u --recursive --new-file v2.1.44/linux/drivers/net/sunqe.c linux/drivers/net/sunqe.c --- v2.1.44/linux/drivers/net/sunqe.c Tue May 13 22:41:12 1997 +++ linux/drivers/net/sunqe.c Wed Jul 16 19:22:51 1997 @@ -152,8 +152,8 @@ skb_put(skb, ETH_FRAME_LEN); skb_reserve(skb, 34); - /* FIX FOR ULTRA */ - qb->qe_rxd[i].rx_addr = (unsigned int) skb->data; + qb->qe_rxd[i].rx_addr = + (unsigned int) ((unsigned long)skb->data); qb->qe_rxd[i].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); } @@ -491,7 +491,8 @@ drop_it: /* Return it to the QE. */ qep->net_stats.rx_dropped++; - this->rx_addr = (unsigned int) qep->rx_skbs[elem]->data; + this->rx_addr = + (unsigned int) ((unsigned long)qep->rx_skbs[elem]->data); this->rx_flags = (RXD_OWN | (RX_BUF_ALLOC_SIZE & RXD_LENGTH)); goto next; @@ -512,8 +513,8 @@ skb_put(new_skb, ETH_FRAME_LEN); skb_reserve(new_skb, 34); - /* FIX FOR ULTRA */ - rxbase[elem].rx_addr = (unsigned int) new_skb->data; + rxbase[elem].rx_addr = + (unsigned int) ((unsigned long)new_skb->data); rxbase[elem].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); @@ -533,7 +534,8 @@ eth_copy_and_sum(copy_skb, (unsigned char *)skb->data, len, 0); /* Reuse original ring buffer. */ - rxbase[elem].rx_addr = (unsigned int) skb->data; + rxbase[elem].rx_addr = + (unsigned int) ((unsigned long)skb->data); rxbase[elem].rx_flags = (RXD_OWN | ((RX_BUF_ALLOC_SIZE - 34) & RXD_LENGTH)); diff -u --recursive --new-file v2.1.44/linux/drivers/net/tlan.c linux/drivers/net/tlan.c --- v2.1.44/linux/drivers/net/tlan.c Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tlan.c Wed Jul 16 19:22:51 1997 @@ -0,0 +1,2309 @@ +/******************************************************************** + * + * Linux ThunderLAN Driver + * + * tlan.c + * by James Banks, james.banks@caldera.com + * + * (C) 1997 Caldera, Inc. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + ** This file is best viewed/edited with tabstop=4 and colums>=132. + * + ** Useful (if not required) reading: + * + * Texas Instruments, ThunderLAN Programmer's Guide, + * TI Literature Number SPWU013A + * available in PDF format from www.ti.com + * National Semiconductor, DP83840A Data Sheet + * available in PDF format from www.national.com + * Microchip Technology, 24C01A/02A/04A Data Sheet + * available in PDF format from www.microchip.com + * + ********************************************************************/ + + +#include + + +#include "tlan.h" + + +#include +#include +#include +#include + + + + +#ifdef MODULE + static struct device *TLanDevices = NULL; + static int TLanDevicesInstalled = 0; +#endif + static int debug = 0; + static u8 *TLanPadBuffer; + static char TLanSignature[] = "TLAN"; + static int TLanVersionMajor = 0; + static int TLanVersionMinor = 27; + + static TLanPciId TLanDeviceList[] = { + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10, "Compaq Netelligent 10" }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETELLIGENT_10_100, "Compaq Netelligent 10/100" }, + { PCI_VENDOR_ID_COMPAQ, PCI_DEVICE_ID_NETFLEX_3_INTEGRATED, "Compaq Integrated NetFlex-3" }, + { 0, 0, NULL } /* End of List */ + }; + + + static int TLan_MiiReadReg(u16, u16, u16, u16 *); + static void TLan_MiiSendData( u16, u32, unsigned ); + static void TLan_MiiSync(u16); + static void TLan_MiiWriteReg(u16, u16, u16, u16); + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver MII Routines + + These routines are based on the information in Chap. 2 of the + "ThunderLAN Programmer's Guide", pp. 15-24. + +****************************************************************************** +*****************************************************************************/ + + + /************************************************************************* + * TLan_MiiReadReg + * + * Returns: 0 if ack received ok, 1 otherwise. + * Parms: base_port The base IO port of the adapter in question. + * dev The address of the PHY to be queried. + * reg The register whose contents are to be + * retreived. + * val A pointer to a variable to store the retrieved + * value. + * + * This function uses the TLAN's MII bus to retreive the contents of a + * given register on a PHY. It sends the appropriate info and then + * reads the 16-bit register value from the MII bus via the TLAN SIO + * register. + * + ************************************************************************/ + + int TLan_MiiReadReg(u16 base_port, u16 dev, u16 reg, u16 *val) + { + u8 nack; + u16 sio, tmp; + u32 i; + int err; + + err = FALSE; + outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + + cli(); + + TLan_MiiSync(base_port); + + TLan_ClearBit(TLAN_NET_SIO_MINTEN, sio); /* Disable PHY ints */ + + TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */ + TLan_MiiSendData( base_port, 0x2, 2 ); /* Read ( 10b ) */ + TLan_MiiSendData( base_port, dev, 5 ); /* Device # */ + TLan_MiiSendData( base_port, reg, 5 ); /* Register # */ + + + TLan_ClearBit(TLAN_NET_SIO_MTXEN, sio); /* Change direction */ + + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Clock through Idle bit */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Use this to wait 300ns */ + + nack = TLan_GetBit(TLAN_NET_SIO_MDATA, sio); /* Check for ACK */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); /* Finish ACK clock cycle */ + if (nack) { /* No ACK, so fake it */ + for (i = 0; i < 16; i++) { + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + } + tmp = 0xffff; + err = TRUE; + } else { /* ACKed, so read data */ + for (tmp = 0, i = 0x8000; i; i >>= 1) { + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); + if (TLan_GetBit(TLAN_NET_SIO_MDATA, sio)) + tmp |= i; + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + } + } + + + TLan_ClearBit(TLAN_NET_SIO_MCLK, sio); /* Idle cycle */ + TLan_SetBit(TLAN_NET_SIO_MCLK, sio); + + TLan_SetBit(TLAN_NET_SIO_MINTEN, sio); /* Enable PHY ints */ + + *val = tmp; + + sti(); + + return err; + + } /* TLan_MiiReadReg */ + + + + + /************************************************************************* + * TLan_MiiSendData + * + * Returns: Nothing + * Parms: base_port The base IO port of the adapter in question. + * dev The address of the PHY to be queried. + * data The value to be placed on the MII bus. + * num_bits The number of bits in data that are to be + * placed on the MII bus. + * + * This function sends on sequence of bits on the MII configuration + * bus. + * + ************************************************************************/ + + void TLan_MiiSendData( u16 base_port, u32 data, unsigned num_bits ) + { + u16 sio; + u32 i; + + if ( num_bits == 0 ) + return; + + outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + TLan_SetBit( TLAN_NET_SIO_MTXEN, sio ); + + for ( i = ( 0x1 << ( num_bits - 1 ) ); i; i >>= 1 ) { + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); + TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + if ( data & i ) + TLan_SetBit( TLAN_NET_SIO_MDATA, sio ); + else + TLan_ClearBit( TLAN_NET_SIO_MDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + TLan_GetBit( TLAN_NET_SIO_MCLK, sio ); + } + + } /* TLan_MiiSendData */ + + + + + /************************************************************************* + * TLan_MiiSync + * + * Returns: Nothing + * Parms: base_port The base IO port of the adapter in question. + * + * This functions syncs all PHYs in terms of the MII configuration bus. + * + ************************************************************************/ + + void TLan_MiiSync( u16 base_port ) + { + int i; + u16 sio; + + outw( TLAN_NET_SIO, base_port + TLAN_DIO_ADR ); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + + TLan_ClearBit( TLAN_NET_SIO_MTXEN, sio ); + for ( i = 0; i < 32; i++ ) { + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + } + + } /* TLan_MiiSync */ + + + + + /************************************************************************* + * TLan_MiiWriteReg + * + * Returns: Nothing + * Parms: base_port The base IO port of the adapter in question. + * dev The address of the PHY to be written to. + * reg The register whose contents are to be + * written. + * val The value to be written to the register. + * + * This function uses the TLAN's MII bus to write the contents of a + * given register on a PHY. It sends the appropriate info and then + * writes the 16-bit register value from the MII configuration bus + * via the TLAN SIO register. + * + ************************************************************************/ + + void TLan_MiiWriteReg(u16 base_port, u16 dev, u16 reg, u16 val) + { + u16 sio; + + outw(TLAN_NET_SIO, base_port + TLAN_DIO_ADR); + sio = base_port + TLAN_DIO_DATA + TLAN_NET_SIO; + + cli(); + + TLan_MiiSync( base_port ); + + TLan_ClearBit( TLAN_NET_SIO_MINTEN, sio ); + + TLan_MiiSendData( base_port, 0x1, 2 ); /* Start ( 01b ) */ + TLan_MiiSendData( base_port, 0x1, 2 ); /* Write ( 01b ) */ + TLan_MiiSendData( base_port, dev, 5 ); /* Device # */ + TLan_MiiSendData( base_port, reg, 5 ); /* Register # */ + + TLan_MiiSendData( base_port, 0x2, 2 ); /* Send ACK */ + TLan_MiiSendData( base_port, val, 16 ); /* Send Data */ + + TLan_ClearBit( TLAN_NET_SIO_MCLK, sio ); /* Idle cycle */ + TLan_SetBit( TLAN_NET_SIO_MCLK, sio ); + + TLan_SetBit( TLAN_NET_SIO_MINTEN, sio ); + + sti(); + + } /* TLan_MiiWriteReg */ + + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver PHY Layer Routines + + The TLAN chip can drive any number of PHYs (physical devices). Rather + than having lots of 'if' or '#ifdef' statements, I have created a + second driver layer for the PHYs. Each PHY can be identified from its + id in registers 2 and 3, and can be given a Check and Service routine + that will be called when the adapter is reset and when the adapter + receives a Network Status interrupt, respectively. + +****************************************************************************** +*****************************************************************************/ + + static int TLan_PhyNop( struct device * ); + static void TLan_PhyPrint( struct device * ); + static void TLan_PhySelect( struct device * ); + static int TLan_PhyInternalCheck( struct device * ); + static int TLan_PhyInternalService( struct device * ); + static int TLan_PhyDp83840aCheck( struct device * ); + + + + + static TLanPhyIdEntry TLanPhyIdTable[] = { + { 0x4000, 0x5014, &TLan_PhyInternalCheck, &TLan_PhyInternalService, TLAN_PHY_ACTIVITY }, + { 0x4000, 0x5015, &TLan_PhyInternalCheck, &TLan_PhyInternalService, TLAN_PHY_ACTIVITY }, + { 0x2000, 0x5C01, &TLan_PhyDp83840aCheck, &TLan_PhyNop, TLAN_PHY_ACTIVITY | TLAN_PHY_AUTONEG }, + { 0x0000, 0x0000, NULL, NULL, 0 } + }; + + + + + /************************************************************************* + * TLan_PhyPrint + * + * Returns: Nothing + * Parms: dev A pointer to the device structure of the adapter + * which the desired PHY is located. + * + * This function prints the registers a PHY. + * + ************************************************************************/ + + void TLan_PhyPrint( struct device *dev ) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 i, data0, data1, data2, data3, phy; + u32 io; + + phy = priv->phyAddr; + io = dev->base_addr; + + if ( ( phy > 0 ) || ( phy <= TLAN_PHY_MAX_ADDR ) ) { + printk( "TLAN: Device %s, PHY 0x%02x.\n", dev->name, phy ); + printk( "TLAN: Off. +0 +1 +2 +3 \n" ); + for ( i = 0; i < 0x20; i+= 4 ) { + TLan_MiiReadReg( io, phy, i, &data0 ); + TLan_MiiReadReg( io, phy, i + 1, &data1 ); + TLan_MiiReadReg( io, phy, i + 2, &data2 ); + TLan_MiiReadReg( io, phy, i + 3, &data3 ); + printk( "TLAN: 0x%02x 0x%04hx 0x%04hx 0x%04hx 0x%04hx\n", i, data0, data1, data2, data3 ); + } + } else { + printk( "TLAN: Device %s, PHY 0x%02x (Invalid).\n", dev->name, phy ); + } + + } /* TLan_PhyPrint */ + + + + + /************************************************************************* + * TLan_PhySelect + * + * Returns: Nothing + * Parms: dev A pointer to the device structure of the adapter + * for which the PHY needs determined. + * + * This function decides which PHY amoung those attached to the TLAN chip + * is to be used. The TLAN chip can be attached to multiple PHYs, and + * the driver needs to decide which one to talk to. Currently this + * routine picks the PHY with the lowest address as the internal PHY + * address is 0x1F, the highest possible. This strategy assumes that + * there can be only one other PHY, and, if it exists, it is the one to + * be used. If token ring PHYs are ever supported, this routine will + * become a little more interesting... + * + ************************************************************************/ + + void TLan_PhySelect( struct device *dev ) + { + int err; + int phy; + int entry; + u16 id_hi; + u16 id_lo; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 val; + + priv->phyCheck = &TLan_PhyNop; // Make absolutely sure these aren't NULL + priv->phyService = &TLan_PhyNop; + + for ( phy = 0; phy <= TLAN_PHY_MAX_ADDR; phy++ ) { + err = TLan_MiiReadReg( dev->base_addr, phy, 0, &val ); + if ( ! err ) { + TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_HI, &id_hi ); + TLan_MiiReadReg( dev->base_addr, phy, MII_GEN_ID_LO, &id_lo ); + entry = 0; + while ( ( TLanPhyIdTable[entry].idHi != 0 ) && ( TLanPhyIdTable[entry].idLo != 0 ) ) { + if ( ( TLanPhyIdTable[entry].idHi == id_hi ) && ( TLanPhyIdTable[entry].idLo == id_lo ) ) { + priv->phyAddr = phy; + priv->phyEntry = entry; + priv->phyCheck = TLanPhyIdTable[entry].check; + priv->phyService = TLanPhyIdTable[entry].service; + priv->phyFlags = TLanPhyIdTable[entry].flags; + break; + } + entry++; + } + break; + } + } + + } /* TLan_PhySelect */ + + + + + /************************************************************************* + * TLan_PhyNop + * + * Returns: Nothing + * Parms: dev A pointer to a device structure. + * + * This function does nothing and is meant as a stand-in for when + * a Check or Service function would be meaningless. + * + ************************************************************************/ + + int TLan_PhyNop( struct device *dev ) + { + dev = NULL; + return 0; + + } /* TLan_PhyNop */ + + + + + /************************************************************************* + * TLan_PhyInternalCheck + * + * Returns: Nothing + * Parms: dev A pointer to a device structure of the adapter + * holding the PHY to be checked. + * + * This function resets the internal PHY on a TLAN chip. See Chap. 7, + * "Physical Interface (PHY)" of "ThunderLAN Programmer's Guide" + * + ************************************************************************/ + + int TLan_PhyInternalCheck( struct device *dev ) + { + u16 gen_ctl; + int i; + u32 io; + u16 phy; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 value; + + io = dev->base_addr; + phy = priv->phyAddr; + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); + if ( gen_ctl & MII_GC_PDOWN ) { + TLan_MiiSync( io ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); + for ( i = 0; i < 500000; i++ ) + SLOW_DOWN_IO; + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); + TLan_MiiSync( io ); + } + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + while ( value & MII_GC_RESET ) + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); + + for ( i = 0; i < 500000; i++ ) + SLOW_DOWN_IO; + + // Read Possible Latched Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + // Read Real Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + if ( value & MII_GS_LINK ) { + priv->phyOnline = 1; + TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->phyOnline = 0; + TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + } + + // Enable Interrupts + TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); + value |= TLAN_TC_INTEN; + TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); + + return 0; + + } /* TLanPhyInternalCheck */ + + + + + /************************************************************************* + * TLan_PhyInternalService + * + * Returns: Nothing + * Parms: dev A pointer to a device structure of the adapter + * holding the PHY to be serviced. + * + * This function services an interrupt generated by the internal PHY. + * It can turn on/off the link LED. See Chap. 7, + * "Physical Interface (PHY)" of "ThunderLAN Programmer's Guide". + * + ************************************************************************/ + + int TLan_PhyInternalService( struct device *dev ) + { + u16 tlphy_sts; + u16 gen_sts; + u16 an_exp; + u32 io; + u16 phy; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + io = dev->base_addr; + phy = priv->phyAddr; + + TLan_MiiReadReg( io, phy, TLAN_TLPHY_STS, &tlphy_sts ); + TLan_MiiReadReg( io, phy, MII_GEN_STS, &gen_sts ); + TLan_MiiReadReg( io, phy, MII_AN_EXP, &an_exp ); + if ( gen_sts & MII_GS_LINK ) { + priv->phyOnline = 1; + TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->phyOnline = 0; + TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + } + + return 0; + + } /* TLan_PhyInternalService */ + + + + + /************************************************************************* + * TLan_PhyDp83840aCheck + * + * Returns: Nothing + * Parms: dev A pointer to a device structure of the adapter + * holding the PHY to be reset. + * + * This function resets a National Semiconductor DP83840A 10/100 Mb/s + * PHY device. See National Semiconductor's data sheet for more info. + * This PHY is used on Compaq Netelligent 10/100 cards. + * + ************************************************************************/ + + static int TLan_PhyDp83840aCheck( struct device *dev ) + { + u16 gen_ctl; + int i; + u32 io; + u16 phy; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u16 value; + + io = dev->base_addr; + phy = priv->phyAddr; + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &gen_ctl ); + if ( gen_ctl & MII_GC_PDOWN ) { + TLan_MiiSync( io ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_PDOWN | MII_GC_LOOPBK | MII_GC_ISOLATE ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK ); + for ( i = 0; i < 500000; i++ ) + SLOW_DOWN_IO; + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_RESET | MII_GC_LOOPBK ); + TLan_MiiSync( io ); + } + + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + while ( value & MII_GC_RESET ) + TLan_MiiReadReg( io, phy, MII_GEN_CTL, &value ); + + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_LOOPBK | MII_GC_DUPLEX ); + // TLan_MiiWriteReg( io, phy, MII_GEN_CTL, MII_GC_DUPLEX ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0 ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1000 ); + TLan_MiiWriteReg( io, phy, MII_GEN_CTL, 0x1200 ); + + for ( i = 0; i < 50000; i++ ) + SLOW_DOWN_IO; + +/* + // Read Possible Latched Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + // Read Real Link Status + TLan_MiiReadReg( io, phy, MII_GEN_STS, &value ); + if ( value & MII_GS_LINK ) { + priv->phyOnline = 1; + TLan_DioWrite8( io, TLAN_LED_REG, TLAN_LED_LINK ); + } else { + priv->phyOnline = 0; + TLan_DioWrite8( io, TLAN_LED_REG, 0 ); + } + + // Enable Interrupts + TLan_MiiReadReg( io, phy, TLAN_TLPHY_CTL, &value ); + value |= TLAN_TC_INTEN; + TLan_MiiWriteReg( io, phy, TLAN_TLPHY_CTL, value ); +*/ + priv->phyOnline = 1; + + return 0; + + } /* TLan_PhyDp83840aCheck */ + + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Adapter Related Routines + +****************************************************************************** +*****************************************************************************/ + + + + static void TLan_ResetLists( struct device * ); + static void TLan_PrintDio( u16 ); + static void TLan_PrintList( TLanList *, char *, int ); + static void TLan_ReadAndClearStats( struct device *, int ); + static int TLan_Reset( struct device * ); + static void TLan_SetMac( struct device *, int areg, char *mac ); + + + + + /************************************************************************* + * TLan_ResetLists + * + * Returns: Nothing + * Parms: dev The device structure with the list stuctures to + * be reset. + * + * This routine sets the variables associated with managing the TLAN + * lists to their initial values. + * + ************************************************************************/ + + void TLan_ResetLists( struct device *dev ) + { + int i; + TLanList *list; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + priv->txHead = 0; + priv->txTail = 0; + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) { + list = priv->txList + i; + list->cStat = TLAN_CSTAT_UNUSED; + list->buffer[0].address = virt_to_bus( priv->txBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); + list->buffer[2].count = 0; + list->buffer[2].address = 0; + } + + priv->rxHead = 0; + priv->rxTail = TLAN_NUM_RX_LISTS - 1; + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) { + list = priv->rxList + i; + list->cStat = TLAN_CSTAT_READY; + list->frameSize = TLAN_MAX_FRAME_SIZE; + list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; + list->buffer[0].address = virt_to_bus( priv->rxBuffer + ( i * TLAN_MAX_FRAME_SIZE ) ); + list->buffer[1].count = 0; + list->buffer[1].address = 0; + if ( i < TLAN_NUM_RX_LISTS - 1 ) + list->forward = virt_to_bus( list + 1 ); + else + list->forward = 0; + } + + } /* TLan_ResetLists */ + + + + + /************************************************************************* + * TLan_PrintDio + * + * Returns: Nothing + * Parms: io_base Base IO port of the device of which to print + * DIO registers. + * + * This function prints out all the the internal (DIO) registers of a + * TLAN chip. + * + ************************************************************************/ + + void TLan_PrintDio( u16 io_base ) + { + u32 data0, data1; + int i; + + printk( "TLAN: Contents of internal registers for io base 0x%04hx.\n", io_base ); + printk( "TLAN: Off. +0 +4\n" ); + for ( i = 0; i < 0x4C; i+= 8 ) { + data0 = TLan_DioRead32( io_base, i ); + data1 = TLan_DioRead32( io_base, i + 0x4 ); + printk( "TLAN: 0x%02x 0x%08x 0x%08x\n", i, data0, data1 ); + } + + } /* TLan_PrintDio */ + + + + + /************************************************************************* + * TLan_PrintList + * + * Returns: Nothing + * Parms: list A pointer to the TLanList structure to be printed. + * type A string to designate type of list, "Rx" or "Tx". + * num The index of the list. + * + * This function prints out the contents of the list pointed to by the + * list parameter. + * + ************************************************************************/ + + void TLan_PrintList( TLanList *list, char *type, int num) + { + int i; + + printk( "TLAN: %s List %d at 0x%08x\n", type, num, (u32) list ); + printk( "TLAN: Forward = 0x%08x\n", list->forward ); + printk( "TLAN: CSTAT = 0x%04hx\n", list->cStat ); + printk( "TLAN: Frame Size = 0x%04hx\n", list->frameSize ); + for ( i = 0; i < 10; i++ ) { + printk( "TLAN: Buffer[%d].count, addr = 0x%08x, 0x%08x\n", i, list->buffer[i].count, list->buffer[i].address ); + } + + } /* TLan_PrintList */ + + + + + /************************************************************************* + * TLan_ReadAndClearStats + * + * Returns: Nothing + * Parms: dev Pointer to device structure of adapter to which + * to read stats. + * record Flag indicating whether to add + * + * This functions reads all the internal status registers of the TLAN + * chip, which clears them as a side effect. It then either adds the + * values to the device's status struct, or discards them, depending + * on whether record is TLAN_RECORD (!=0) or TLAN_IGNORE (==0). + * + ************************************************************************/ + + void TLan_ReadAndClearStats( struct device *dev, int record ) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + u32 tx_good, tx_under; + u32 rx_good, rx_over; + u32 def_tx, crc, code; + u32 multi_col, single_col; + u32 excess_col, late_col, loss; + + outw( TLAN_GOOD_TX_FRMS, dev->base_addr + TLAN_DIO_ADR ); + tx_good = inb( dev->base_addr + TLAN_DIO_DATA ); + tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + tx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; + tx_under = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_GOOD_RX_FRMS, dev->base_addr + TLAN_DIO_ADR ); + rx_good = inb( dev->base_addr + TLAN_DIO_DATA ); + rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + rx_good += inb( dev->base_addr + TLAN_DIO_DATA + 2 ) << 16; + rx_over = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_DEFERRED_TX, dev->base_addr + TLAN_DIO_ADR ); + def_tx = inb( dev->base_addr + TLAN_DIO_DATA ); + def_tx += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + crc = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + code = inb( dev->base_addr + TLAN_DIO_DATA + 3 ); + + outw( TLAN_MULTICOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); + multi_col = inb( dev->base_addr + TLAN_DIO_DATA ); + multi_col += inb( dev->base_addr + TLAN_DIO_DATA + 1 ) << 8; + single_col = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + single_col += inb( dev->base_addr + TLAN_DIO_DATA + 3 ) << 8; + + outw( TLAN_EXCESSCOL_FRMS, dev->base_addr + TLAN_DIO_ADR ); + excess_col = inb( dev->base_addr + TLAN_DIO_DATA ); + late_col = inb( dev->base_addr + TLAN_DIO_DATA + 1 ); + loss = inb( dev->base_addr + TLAN_DIO_DATA + 2 ); + + if ( record ) { + priv->stats.rx_packets += rx_good; + priv->stats.rx_errors += rx_over + crc + code; + priv->stats.tx_packets += tx_good; + priv->stats.tx_errors += tx_under + loss; + priv->stats.collisions += multi_col + single_col + excess_col + late_col; + + priv->stats.rx_over_errors += rx_over; + priv->stats.rx_crc_errors += crc; + priv->stats.rx_frame_errors += code; + + priv->stats.tx_aborted_errors += tx_under; + priv->stats.tx_carrier_errors += loss; + } + + } /* TLan_ReadAndClearStats */ + + + + + /************************************************************************* + * TLan_Reset + * + * Returns: 0 + * Parms: dev Pointer to device structure of adapter to be + * reset. + * + * This function resets the adapter and it's physical device. See + * Chap. 3, pp. 9-10 of the "ThunderLAN Programmer's Guide" for details. + * The routine tries to implement what is detailed there, though + * adjustments have been made. + * + ************************************************************************/ + + int TLan_Reset( struct device *dev ) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int i; + u32 data; + u8 data8; + + // 1. Assume Stat registers have been dealt with. + // 2. Assert reset bit. + data = inl(dev->base_addr + TLAN_HOST_CMD); + data |= TLAN_HC_AD_RST; + outl(data, dev->base_addr + TLAN_HOST_CMD); + // 3. Turn off interrupts. + data = inl(dev->base_addr + TLAN_HOST_CMD); + data |= TLAN_HC_INT_OFF; + outl(data, dev->base_addr + TLAN_HOST_CMD); + // 4. Setup AREGs and HASHs. + for ( i = TLAN_AREG_0; i <= TLAN_HASH_2; i += 4 ) + TLan_DioWrite32( dev->base_addr, (u16) i, 0 ); + // 5. Setup NetConfig register. + outw(TLAN_NET_CONFIG, dev->base_addr + TLAN_DIO_ADR); + outw(TLAN_NET_CFG_1FRAG | TLAN_NET_CFG_1CHAN | TLAN_NET_CFG_PHY_EN, dev->base_addr + TLAN_DIO_DATA); + // 6. Setup BSIZE register. + // Accept defaults, 0x22, for now. + // 7. Setup TX commit in Acommit. + // Allow it to manage itself. + // 8. Load Ld_Tmr in HOST_CMD. + // I don't know what this value should be. I'll try 3. + outl( TLAN_HC_LD_TMR | 0x0, dev->base_addr + TLAN_HOST_CMD ); + // 9. Load Ld_Thr in HOST_CMD. + // Try 1 for now. + outl( TLAN_HC_LD_THR | 0x1, dev->base_addr + TLAN_HOST_CMD ); + // 10. Unreset the MII by setting NMRST (in NetSio) to 1. + outw( TLAN_NET_SIO, dev->base_addr + TLAN_DIO_ADR ); + TLan_SetBit( TLAN_NET_SIO_NMRST, dev->base_addr + TLAN_DIO_DATA + TLAN_NET_SIO ); + // 10a. Other. + // 12. Setup the NetMask register. + TLan_DioWrite8( dev->base_addr, TLAN_INT_DIS, TLAN_ID_TX_EOC | TLAN_ID_RX_EOC ); + //TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP | TLAN_NET_CMD_DUPLEX | TLAN_NET_CMD_CAF ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, TLAN_NET_CMD_NRESET | TLAN_NET_CMD_NWRAP ); + // 11. Initialize PHYs. + TLan_PhySelect( dev ); + (*priv->phyCheck)( dev ); + if ( debug >= 1 ) + TLan_PhyPrint( dev ); + + //data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK6 | TLAN_NET_MASK_MASK7; + data8 = TLAN_NET_MASK_MASK4 | TLAN_NET_MASK_MASK5 | TLAN_NET_MASK_MASK7; + TLan_DioWrite8( dev->base_addr, TLAN_NET_MASK, data8 ); + TLan_DioWrite16( dev->base_addr, TLAN_MAX_RX, 1550 ); + /* + * 13. Turn on interrupts to host. + * I don't want any interrupts, yet. + */ + /* + data = inl(base_port + TLAN_HOST_CMD); + data |= TLAN_HC_INT_ON; + outl(data, base_port + TLAN_HOST_CMD); + */ + + return 0; + + } /* TLan_Reset */ + + + + + /************************************************************************* + * TLan_SetMac + * + * Returns: Nothing + * Parms: dev Pointer to device structure of adapter on which to + * change the AREG. + * areg The AREG to set the address in (0 - 3). + * mac A pointer to an array of chars. Each element + * stores one byte of the address. IE, it isn't + * in ascii. + * + * This function transfers a MAC address to one of the TLAN AREGs + * (address registers). The TLAN chip locks the register on writing to + * offset 0 and unlocks the register after writing to offset 5. If NULL + * is passed in mac, then the AREG is filled with 0's. + * + ************************************************************************/ + + void TLan_SetMac( struct device *dev, int areg, char *mac ) + { + int i; + + areg *= 6; + + if ( mac != NULL ) { + for ( i = 0; i < 6; i++ ) + TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, mac[i] ); + } else { + for ( i = 0; i < 6; i++ ) + TLan_DioWrite8( dev->base_addr, TLAN_AREG_0 + areg + i, 0 ); + } + + } /* TLan_SetMac */ + + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Eeprom routines + + The Compaq Netelligent 10 and 10/100 cards use a Microchip 24C02A EEPROM. + These functions are based on information in Microchip's data sheet. I + don't know how well this functions will work with other EEPROMs. + +****************************************************************************** +*****************************************************************************/ + + static void TLan_EeSendStart( u16 ); + static int TLan_EeSendByte( u16, u8, int ); + static void TLan_EeReceiveByte( u16, u8 *, int ); + static int TLan_EeReadByte( u16, u8, u8 * ); + + + + + /************************************************************************* + * TLan_EeSendStart + * + * Returns: Nothing + * Parms: io_base The IO port base address for the TLAN device + * with the EEPROM to use. + * + * This function sends a start cycle to an EEPROM attached to a TLAN + * chip. + * + ************************************************************************/ + + void TLan_EeSendStart( u16 io_base ) + { + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + // + // FIXME: Do I really need these SLOW_DOWN_IOs? + // + SLOW_DOWN_IO; + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); + SLOW_DOWN_IO; + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + SLOW_DOWN_IO; + + } /* TLan_EeSendStart */ + + + + + /************************************************************************* + * TLan_EeSendByte + * + * Returns: If the correct ack was received, 0, otherwise 1 + * Parms: io_base The IO port base address for the TLAN device + * with the EEPROM to use. + * data The 8 bits of information to send to the + * EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a stop cycle is + * sent after the byte is sent after the ack is + * read. + * + * This function sends a byte on the serial EEPROM line, driving the + * clock to send each bit. The function then reverses transmission + * direction and reads an acknowledge bit. + * + ************************************************************************/ + + int TLan_EeSendByte( u16 io_base, u8 data, int stop ) + { + int err; + u8 place; + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + + // Assume clock is low, tx is enabled; + for ( place = 0x80; place; place >>= 1 ) { + if ( place & data ) + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + else + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } + TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + err = TLan_GetBit( TLAN_NET_SIO_EDATA, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + + if ( ( ! err ) && stop ) { + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is high + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + } + + return ( err ); + + } /* TLan_EeSendByte */ + + + + + /************************************************************************* + * TLan_EeReceiveByte + * + * Returns: Nothing + * Parms: io_base The IO port base address for the TLAN device + * with the EEPROM to use. + * data An address to a char to hold the data sent + * from the EEPROM. + * stop If TLAN_EEPROM_STOP is passed, a stop cycle is + * sent after the byte is received, and no ack is + * sent. + * + * This function receives 8 bits of data from the EEPROM over the serial + * link. It then sends and ack bit, or no ack and a stop bit. This + * function is used to retrieve data after the address of a byte in the + * EEPROM has been sent. + * + ************************************************************************/ + + void TLan_EeReceiveByte( u16 io_base, u8 *data, int stop ) + { + u8 place; + u16 sio; + + outw( TLAN_NET_SIO, io_base + TLAN_DIO_ADR ); + sio = io_base + TLAN_DIO_DATA + TLAN_NET_SIO; + *data = 0; + + // Assume clock is low, tx is enabled; + TLan_ClearBit( TLAN_NET_SIO_ETXEN, sio ); + for ( place = 0x80; place; place >>= 1 ) { + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + if ( TLan_GetBit( TLAN_NET_SIO_EDATA, sio ) ) + *data |= place; + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } + + TLan_SetBit( TLAN_NET_SIO_ETXEN, sio ); + if ( ! stop ) { + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // Ack = 0 + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + } else { + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); // No ack = 1 (?) + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_ClearBit( TLAN_NET_SIO_EDATA, sio ); // STOP, raise data while clock is high + TLan_SetBit( TLAN_NET_SIO_ECLOK, sio ); + TLan_SetBit( TLAN_NET_SIO_EDATA, sio ); + } + + } /* TLan_EeReceiveByte */ + + + + + /************************************************************************* + * TLan_EeReadByte + * + * Returns: No error = 0, else, the stage at which the error occured. + * Parms: io_base The IO port base address for the TLAN device + * with the EEPROM to use. + * ee_addr The address of the byte in the EEPROM whose + * contents are to be retrieved. + * data An address to a char to hold the data obtained + * from the EEPROM. + * + * This function reads a byte of information from an byte cell in the + * EEPROM. + * + ************************************************************************/ + + int TLan_EeReadByte( u16 io_base, u8 ee_addr, u8 *data ) + { + int err; + + cli(); + + TLan_EeSendStart( io_base ); + err = TLan_EeSendByte( io_base, 0xA0, TLAN_EEPROM_ACK ); + if (err) + return 1; + err = TLan_EeSendByte( io_base, ee_addr, TLAN_EEPROM_ACK ); + if (err) + return 2; + TLan_EeSendStart( io_base ); + err = TLan_EeSendByte( io_base, 0xA1, TLAN_EEPROM_ACK ); + if (err) + return 3; + TLan_EeReceiveByte( io_base, data, TLAN_EEPROM_STOP ); + + sti(); + + return 0; + + } /* TLan_EeReadByte */ + + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Interrupt Vectors and Table + + Please see Chap. 4, "Interrupt Handling" of the + "ThunderLAN Programmer's Guide" for more informations on handling + interrupts generated by TLAN based adapters. + +****************************************************************************** +*****************************************************************************/ + + static u32 TLan_HandleInvalid( struct device *, u16 ); + static u32 TLan_HandleTxEOF( struct device *, u16 ); + static u32 TLan_HandleStatOverflow( struct device *, u16 ); + static u32 TLan_HandleRxEOF( struct device *, u16 ); + static u32 TLan_HandleDummy( struct device *, u16 ); + static u32 TLan_HandleTxEOC( struct device *, u16 ); + static u32 TLan_HandleStatusCheck( struct device *, u16 ); + static u32 TLan_HandleRxEOC( struct device *, u16 ); + + + + + typedef u32 (TLanIntVectorFunc)( struct device *, u16 ); + + + + + /************************************************************************* + * TLan_HandleInvalid + * + * Returns: 0 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This function handles invalid interrupts. This should never happen + * unless some other adapter is trying to use the IRQ line assigned to + * the device. + * + ************************************************************************/ + + u32 TLan_HandleInvalid( struct device *dev, u16 host_int ) + { + host_int = 0; + // printk( "TLAN: Invalid interrupt on %s.\n", dev->name ); + return 0; + + } /* TLan_HandleInvalid */ + + + /************************************************************************* + * TLan_HandleTxEOF + * + * Returns: 1 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This function handles Tx EOF interrupts which are raised by the + * adapter when it has completed sending the contents of a buffer. If + * detemines which list/buffer was completed and resets it. If the + * buffer was the last in the channel (EOC), then the function checks + * to see if another buffer is ready to send, and if so, sends a Tx Go + * command. Finally, the driver activates/continues the activity LED. + * + ************************************************************************/ + + u32 TLan_HandleTxEOF( struct device *dev, u16 host_int ) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int eoc = 0; + TLanList *head_list; + u32 ack = 1; + + // printk( "TLAN: Handling Tx EOF\n" ); + host_int = 0; + head_list = priv->txList + priv->txHead; + if ( head_list->cStat & TLAN_CSTAT_EOC ) + eoc = 1; + if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { + printk( "TLAN: Received interrupt for uncompleted TX frame.\n" ); + } + // printk( "Ack %d CSTAT=%hx\n", priv->txHead, head_list->cStat ); + head_list->cStat = TLAN_CSTAT_UNUSED; + dev->tbusy = 0; + priv->txHead++; + if ( priv->txHead >= TLAN_NUM_TX_LISTS ) + priv->txHead = 0; + if ( eoc ) { + // printk( "TLAN: Handling Tx EOC\n" ); + head_list = priv->txList + priv->txHead; + if ( ( head_list->cStat & TLAN_CSTAT_READY ) == TLAN_CSTAT_READY ) { + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO; + } else { + priv->txInProgress = 0; + } + } + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { + if ( priv->timerSetAt == 0 ) { + // printk("TxEOF Starting timer...\n"); + priv->timerSetAt = jiffies; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timerType = TLAN_TIMER_ACT; + add_timer( &priv->timer ); + } else if ( priv->timerType == TLAN_TIMER_ACT ) { + priv->timerSetAt = jiffies; + // printk("TxEOF continuing timer...\n"); + } + } + + return ack; + + } /* TLan_HandleTxEOF */ + + + + + /************************************************************************* + * TLan_HandleStatOverflow + * + * Returns: 1 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This function handles the Statistics Overflow interrupt which means + * that one or more of the TLAN statistics registers has reached 1/2 + * capacity and needs to be read. + * + ************************************************************************/ + + u32 TLan_HandleStatOverflow( struct device *dev, u16 host_int ) + { + host_int = 0; + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + + return 1; + + } /* TLan_HandleStatOverflow */ + + + + + /************************************************************************* + * TLan_HandleRxEOF + * + * Returns: 1 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This function handles the Rx EOF interrupt which indicates a frame + * has been received by the adapter from the net and the frame has been + * transferred to memory. The function determines the bounce buffer + * the frame has been loaded into, creates a new sk_buff big enough to + * hold the frame, and sends it to protocol stack. It then resets the + * used buffer and appends it to the end of the list. If the frame was + * the last in the Rx channel (EOC), the function restarts the receive + * channel by sending an Rx Go command to the adapter. Then it activates/ + * continues the the activity LED. + * + ************************************************************************/ + + u32 TLan_HandleRxEOF( struct device *dev, u16 host_int ) + { + u32 ack = 1; + int eoc = 0; + u8 *head_buffer; + TLanList *head_list; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + struct sk_buff *skb; + TLanList *tail_list; + void *t; + + // printk( "TLAN: Handling Rx EOF Head=%d Tail=%d\n", priv->rxHead, priv->rxTail ); + host_int = 0; + head_list = priv->rxList + priv->rxHead; + tail_list = priv->rxList + priv->rxTail; + if ( head_list->cStat & TLAN_CSTAT_EOC ) + eoc = 1; + if ( ! head_list->cStat & TLAN_CSTAT_FRM_CMP ) { + printk( "TLAN: Received interrupt for uncompleted RX frame.\n" ); + } else { + skb = dev_alloc_skb( head_list->frameSize + 7 ); + if ( skb == NULL ) { + printk( "TLAN: Couldn't allocate memory for received data.\n" ); + } else { + head_buffer = priv->rxBuffer + ( priv->rxHead * TLAN_MAX_FRAME_SIZE ); + skb->dev = dev; + skb_reserve( skb, 2 ); + t = (void *) skb_put( skb, head_list->frameSize ); + // printk( " %hd %p %p\n", head_list->frameSize, skb->data, t ); + memcpy( t, head_buffer, head_list->frameSize ); + skb->protocol = eth_type_trans( skb, dev ); + netif_rx( skb ); + } + } + head_list->forward = 0; + head_list->frameSize = TLAN_MAX_FRAME_SIZE; + head_list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; + tail_list->forward = virt_to_bus( head_list ); + priv->rxHead++; + if ( priv->rxHead >= TLAN_NUM_RX_LISTS ) + priv->rxHead = 0; + priv->rxTail++; + if ( priv->rxTail >= TLAN_NUM_RX_LISTS ) + priv->rxTail = 0; + if ( eoc ) { + // printk( "TLAN: Handling Rx EOC Head=%d Tail=%d\n", priv->rxHead, priv->rxTail ); + head_list = priv->rxList + priv->rxHead; + outl( virt_to_bus( head_list ), dev->base_addr + TLAN_CH_PARM ); + ack |= TLAN_HC_GO | TLAN_HC_RT; + priv->rxEocCount++; + } + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK | TLAN_LED_ACT ); + if ( priv->phyFlags & TLAN_PHY_ACTIVITY ) { + if ( priv->timerSetAt == 0 ) { + // printk("RxEOF Starting timer...\n"); + priv->timerSetAt = jiffies; + priv->timer.expires = jiffies + TLAN_TIMER_ACT_DELAY; + priv->timerType = TLAN_TIMER_ACT; + add_timer( &priv->timer ); + } else if ( priv->timerType == TLAN_TIMER_ACT ) { + // printk("RxEOF tarting continuing timer...\n"); + priv->timerSetAt = jiffies; + } + } + dev->last_rx = jiffies; + + return ack; + + } /* TLan_HandleRxEOF */ + + + + + /************************************************************************* + * TLan_HandleDummy + * + * Returns: 1 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This function handles the Dummy interrupt, which is raised whenever + * a test interrupt is generated by setting the Req_Int bit of HOST_CMD + * to 1. + * + ************************************************************************/ + + u32 TLan_HandleDummy( struct device *dev, u16 host_int ) + { + host_int = 0; + printk( "TLAN: Dummy interrupt on %s.\n", dev->name ); + return 1; + + } /* TLan_HandleDummy */ + + + + + /************************************************************************* + * TLan_HandleTxEOC + * + * Returns: 1 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This driver is structured to determine EOC occurances by reading the + * CSTAT member of the list structure. Tx EOC interrupts are disabled + * via the DIO INTDIS register. + * + ************************************************************************/ + + u32 TLan_HandleTxEOC( struct device *dev, u16 host_int ) + { + host_int = 0; + printk( "TLAN: Tx EOC interrupt on %s.\n", dev->name ); + return 1; + + } /* TLan_HandleTxEOC */ + + + + + /************************************************************************* + * TLan_HandleStatusCheck + * + * Returns: 0 if Adapter check, 1 if Network Status check. + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This function handles Adapter Check/Network Status interrupts + * generated by the adapter. It checks the vector in the HOST_INT + * register to determine if it is an Adapter Check interrupt. If so, + * it resets the adapter. Otherwise it clears the status registers + * and services the PHY. + * + ************************************************************************/ + + u32 TLan_HandleStatusCheck( struct device *dev, u16 host_int ) + { + u32 ack; + u32 error; + u8 net_sts; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + ack = 1; + if ( host_int & TLAN_HI_IV_MASK ) { + error = inl( dev->base_addr + TLAN_CH_PARM ); + printk( "TLAN: Adaptor Check on device %s err = 0x%x\n", dev->name, error ); + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + TLan_ResetLists( dev ); + TLan_Reset( dev ); + dev->tbusy = 0; + TLan_SetMac( dev, 0, dev->dev_addr ); + if ( priv->timerType == 0 ) { + if ( priv->phyFlags & TLAN_PHY_AUTONEG ) { + priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY; + priv->timerSetAt = jiffies; + priv->timerType = TLAN_TIMER_LINK; + add_timer( &priv->timer ); + } else { + //printk( " RX GO---->\n" ); + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + } + } + ack = 0; + } else { + net_sts = TLan_DioRead8( dev->base_addr, TLAN_NET_STS ); + if ( net_sts ) + TLan_DioWrite8( dev->base_addr, TLAN_NET_STS, net_sts ); + if ( net_sts & TLAN_NET_STS_MIRQ ) + (*priv->phyService)( dev ); + + TLAN_DBG( 1, "TLAN: Status Check! %s Net_Sts=%x\n", dev->name, (unsigned) net_sts ); + } + + return ack; + + } /* TLan_HandleStatusCheck */ + + + + + /************************************************************************* + * TLan_HandleRxEOC + * + * Returns: 1 + * Parms: dev Device assigned the IRQ that was raised. + * host_int The contents of the HOST_INT port. + * + * This driver is structured to determine EOC occurances by reading the + * CSTAT member of the list structure. Rx EOC interrupts are disabled + * via the DIO INTDIS register. + * + ************************************************************************/ + + u32 TLan_HandleRxEOC( struct device *dev, u16 host_int ) + { + host_int = 0; + printk( "TLAN: Rx EOC interrupt on %s.\n", dev->name ); + return 1; + + } /* TLan_HandleRxEOC */ + + + + static TLanIntVectorFunc *TLanIntVector[TLAN_INT_NUMBER_OF_INTS] = { + TLan_HandleInvalid, + TLan_HandleTxEOF, + TLan_HandleStatOverflow, + TLan_HandleRxEOF, + TLan_HandleDummy, + TLan_HandleTxEOC, + TLan_HandleStatusCheck, + TLan_HandleRxEOC + }; + + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Timer Function + +****************************************************************************** +*****************************************************************************/ + + static void TLan_Timer( unsigned long ); + + + + + /************************************************************************* + * TLan_Timer + * + * Returns: Nothing + * Parms: data A value given to add timer when add_timer was + * called. + * + * This function handles timed functionality for the TLAN driver. The + * two current timer uses are for delaying for autonegotionation and + * driving the ACT LED. + * - Autonegotiation requires being allowed about 2 1/2 seconds before + * attempting to transmit a packet. It would be a very bad thing + * to hang the kernel this long, so the driver doesn't allow + * transmission 'til after this time, for certain PHYs. It would + * be much nicer if all PHYs were interrupt-capable like the + * internal PHY. + * - The ACT LED, which shows adapter activity, is driven by the driver, + * and so must be left on for a short period to power up the LED so + * it can be seen. This delay can be changed by changing the + * TLAN_TIMER_ACT_DELAY in tlan.h, if desired. 10 jiffies produces a + * slightly sluggish response. + * + ************************************************************************/ + + void TLan_Timer( unsigned long data ) + { + struct device *dev = (struct device *) data; + u16 gen_sts; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + // printk( "TLAN: %s Entered Timer, type = %d\n", dev->name, priv->timerType ); + + switch ( priv->timerType ) { + case TLAN_TIMER_LINK: + TLan_MiiReadReg( dev->base_addr, priv->phyAddr, MII_GEN_STS, &gen_sts ); + if ( gen_sts & MII_GS_LINK ) { + priv->phyOnline = 1; + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + priv->timerSetAt = 0; + priv->timerType = 0; + } else { + priv->timer.expires = jiffies + ( TLAN_TIMER_LINK_DELAY * 2 ); + add_timer( &priv->timer ); + } + break; + case TLAN_TIMER_ACT: + if ( jiffies - priv->timerSetAt >= TLAN_TIMER_ACT_DELAY ) { + TLan_DioWrite8( dev->base_addr, TLAN_LED_REG, TLAN_LED_LINK ); + priv->timerSetAt = 0; + priv->timerType = 0; + } else { + priv->timer.expires = priv->timerSetAt + TLAN_TIMER_ACT_DELAY; + add_timer( &priv->timer ); + } + break; + default: + break; + } + + } /* TLan_Timer */ + + + + +/***************************************************************************** +****************************************************************************** + + ThunderLAN Driver Primary Functions + + These functions are more or less common to all Linux network drivers. + +****************************************************************************** +*****************************************************************************/ + + static int TLan_PciProbe( u8 *, u8 *, u8 *, u8 *, u32 *, u32 * ); + static int TLan_Init( struct device * ); + static int TLan_Open(struct device *dev); + static int TLan_StartTx(struct sk_buff *, struct device *); + static void TLan_HandleInterrupt(int, void *, struct pt_regs *); + static int TLan_Close(struct device *); + static struct enet_statistics *TLan_GetStats( struct device * ); + static void TLan_SetMulticastList( struct device * ); + + +#ifdef MODULE + + /************************************************************************* + * init_module + * + * Returns: 0 if module installed ok, non-zero if not. + * Parms: None + * + * This function begins the setup of the driver creating a pad buffer, + * finding all TLAN devices (matching TLanDeviceList entries), and + * creating and initializing a device structure for each adapter. + * + ************************************************************************/ + + extern int init_module(void) + { + int failed, found; + size_t dev_size; + struct device *dev; + TLanPrivateInfo *priv; + u8 bus, dfn, irq, rev; + u32 io_base, dl_ix; + + printk("TLAN driver, v%d.%d, (C) 1997 Caldera, Inc.\n", + TLanVersionMajor, + TLanVersionMinor + ); + + TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA ); + if ( TLanPadBuffer == NULL ) { + printk( "TLAN: Could not allocate memory for pad buffer.\n" ); + return -ENOMEM; + } + memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); + + dev_size = sizeof(struct device) + sizeof(TLanPrivateInfo); + while ( ( found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ) ) ) { + dev = (struct device *) kmalloc( dev_size, GFP_KERNEL ); + if ( dev == NULL ) { + printk( "TLAN: Could not allocate memory for device.\n" ); + continue; + } + memset( dev, 0, dev_size ); + + dev->priv = priv = ( (void *) dev ) + sizeof(struct device); + dev->name = priv->devName; + strcpy( priv->devName, " " ); + dev->base_addr = io_base; + dev->irq = irq; + dev->init = TLan_Init; + + priv->pciBus = bus; + priv->pciDeviceFn = dfn; + priv->pciRevision = rev; + priv->pciEntry = dl_ix; + + ether_setup( dev ); + + failed = register_netdev( dev ); + + if ( failed ) { + printk( "TLAN: Could not register network device. Freeing struct.\n" ); + kfree( dev ); + } else { + priv->nextDevice = TLanDevices; + TLanDevices = dev; + TLanDevicesInstalled++; + printk("TLAN: %s irq=%2d io=%04x, %s\n", dev->name, (int) irq, io_base, TLanDeviceList[dl_ix].deviceName ); + } + } + + // printk( "TLAN: Found %d device(s).\n", TLanDevicesInstalled ); + + return ( ( TLanDevicesInstalled >= 0 ) ? 0 : -ENODEV ); + + } /* init_module */ + + + + + /************************************************************************* + * cleanup_module + * + * Returns: Nothing + * Parms: None + * + * Goes through the TLanDevices list and frees the device structs and + * memory associated with each device (lists and buffers). It also + * ureserves the IO port regions associated with this device. + * + ************************************************************************/ + + extern void cleanup_module(void) + { + struct device *dev; + TLanPrivateInfo *priv; + + while (TLanDevicesInstalled) { + dev = TLanDevices; + priv = (TLanPrivateInfo *) dev->priv; + if ( priv->dmaStorage ) + kfree( priv->dmaStorage ); + release_region( dev->base_addr, 0x10 ); + unregister_netdev( dev ); + TLanDevices = priv->nextDevice; + kfree( dev ); + TLanDevicesInstalled--; + } + kfree( TLanPadBuffer ); + + } /* cleanup_module */ + + +#else /* MODULE */ + + + + + /************************************************************************* + * tlan_probe + * + * Returns: 0 on success, error code on error + * Parms: dev device struct to use if adapter is found. + * + * The name is lower case to fit in with all the rest of the + * netcard_probe names. This function looks for a/another TLan based + * adapter, setting it up with the provided device struct if one is + * found. + * + ************************************************************************/ + + extern int tlan_probe( struct device *dev ) + { + static int pad_allocated = 0; + int found; + TLanPrivateInfo *priv; + u8 bus, dfn, irq, rev; + u32 io_base, dl_ix; + + found = TLan_PciProbe( &bus, &dfn, &irq, &rev, &io_base, &dl_ix ); + TLAN_DBG( 1, "TLAN: Probing...\n" ); + if ( found ) { + dev->priv = kmalloc( sizeof(TLanPrivateInfo), GFP_KERNEL ); + if ( dev->priv == NULL ) { + printk( "TLAN: Could not allocate memory for device.\n" ); + } + memset( dev->priv, 0, sizeof(TLanPrivateInfo) ); + priv = (TLanPrivateInfo *) dev->priv; + + dev->name = priv->devName; + strcpy( priv->devName, " " ); + + dev = init_etherdev( dev, sizeof(TLanPrivateInfo) ); + + dev->base_addr = io_base; + dev->irq = irq; + + priv->pciBus = bus; + priv->pciDeviceFn = dfn; + priv->pciRevision = rev; + priv->pciEntry = dl_ix; + + if ( ! pad_allocated ) { + TLanPadBuffer = (u8 *) kmalloc( TLAN_MIN_FRAME_SIZE, GFP_KERNEL | GFP_DMA ); + if ( TLanPadBuffer == NULL ) { + printk( "TLAN: Could not allocate memory for pad buffer.\n" ); + } else { + pad_allocated = 1; + memset( TLanPadBuffer, 0, TLAN_MIN_FRAME_SIZE ); + } + } + printk("TLAN %d.%d: %s irq=%2d io=%04x, %s\n", TLanVersionMajor, + TLanVersionMinor, + dev->name, + (int) irq, + io_base, + TLanDeviceList[dl_ix].deviceName ); + TLan_Init( dev ); + } + + return ( ( found ) ? 0 : -ENODEV ); + + } /* tlan_probe */ + + +#endif /* MODULE */ + + + + + /************************************************************************* + * TLan_PciProbe + * + * Returns: 1 if another TLAN card was found, 0 if not. + * Parms: pci_bus The PCI bus the card was found on. + * pci_dfn The PCI whatever the card was found at. + * pci_irq The IRQ of the found adapter. + * pci_rev The revision of the adapter. + * pci_io_base The first IO port used by the adapter. + * dl_ix The index in the device list of the adapter. + * + * This function searches for an adapter with PCI vendor and device + * IDs matching those in the TLanDeviceList. The function 'remembers' + * the last device it found, and so finds a new device (if anymore are + * to be found) each time the function is called. It then looks up + * pertinent PCI info and returns it to the caller. + * + ************************************************************************/ + + int TLan_PciProbe( u8 *pci_bus, u8 *pci_dfn, u8 *pci_irq, u8 *pci_rev, u32 *pci_io_base, u32 *dl_ix ) + { + static int dl_index = 0; + static int pci_index = 0; + + int not_found; + u8 pci_latency; + u16 pci_command; + + + if ( ! pcibios_present() ) { + printk( "TLAN: PCI Bios not present.\n" ); + return 0; + } + + for (; TLanDeviceList[dl_index].vendorId != 0; dl_index++) { + not_found = pcibios_find_device( TLanDeviceList[dl_index].vendorId, + TLanDeviceList[dl_index].deviceId, + pci_index, + pci_bus, + pci_dfn + ); + if ( ! not_found ) { + TLAN_DBG( 1, "TLAN: found: Vendor Id = 0x%hx, Device Id = 0x%hx\n", + TLanDeviceList[dl_index].vendorId, + TLanDeviceList[dl_index].deviceId + ); + + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_REVISION_ID, pci_rev); + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_INTERRUPT_LINE, pci_irq); + pcibios_read_config_word ( *pci_bus, *pci_dfn, PCI_COMMAND, &pci_command); + pcibios_read_config_dword( *pci_bus, *pci_dfn, PCI_BASE_ADDRESS_0, pci_io_base); + pcibios_read_config_byte ( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, &pci_latency); + + if (pci_latency < 0x10) { + pcibios_write_config_byte( *pci_bus, *pci_dfn, PCI_LATENCY_TIMER, 0xff); + TLAN_DBG( 1, "TLAN: Setting latency timer to max.\n"); + } + + if ((pci_command & PCI_COMMAND_IO) && (*pci_io_base & 0x3)) { + *pci_io_base &= PCI_BASE_ADDRESS_IO_MASK; + TLAN_DBG( 1, "TLAN: IO mapping is available at %x.\n", *pci_io_base); + } else { + *pci_io_base = 0; + printk("TLAN: IO mapping not available, ignoring device.\n"); + } + + if (pci_command & PCI_COMMAND_MASTER) { + TLAN_DBG( 1, "TLAN: Bus mastering is active.\n"); + } + + pci_index++; + + if ( *pci_io_base ) { + *dl_ix = dl_index; + return 1; + } + + } else { + pci_index = 0; + } + } + + return 0; + + } /* TLan_PciProbe */ + + + + + /************************************************************************* + * TLan_Init + * + * Returns: 0 on success, error code otherwise. + * Parms: dev The structure of the device to be init'ed. + * + * This function completes the initialization of the device structure + * and driver. It reserves the IO addresses, allocates memory for the + * lists and bounce buffers, retrieves the MAC address from the eeprom + * and assignes the device's methods. + * + ************************************************************************/ + + int TLan_Init( struct device *dev ) + { + int dma_size; + int err; + int i; + TLanPrivateInfo *priv; + + priv = (TLanPrivateInfo *) dev->priv; + + err = check_region( dev->base_addr, 0x10 ); + if ( err ) { + printk( "TLAN: %s: Io port region 0x%lx size 0x%x in use.\n", dev->name, dev->base_addr, 0x10 ); + return -EIO; + } + request_region( dev->base_addr, 0x10, TLanSignature ); + + dma_size = ( TLAN_NUM_RX_LISTS + TLAN_NUM_TX_LISTS ) * ( sizeof(TLanList) + TLAN_MAX_FRAME_SIZE ); + priv->dmaStorage = kmalloc( dma_size, GFP_KERNEL | GFP_DMA ); + if ( priv->dmaStorage == NULL ) { + printk( "TLAN: Could not allocate lists and buffers for %s.\n", dev->name ); + return -ENOMEM; + } + memset( priv->dmaStorage, 0, dma_size ); + priv->rxList = (TLanList *) ( ( ( (u32) priv->dmaStorage ) + 7 ) & 0xFFFFFFF8 ); + priv->txList = priv->rxList + TLAN_NUM_RX_LISTS; + priv->rxBuffer = (u8 *) ( priv->txList + TLAN_NUM_TX_LISTS ); + priv->txBuffer = priv->rxBuffer + ( TLAN_NUM_RX_LISTS * TLAN_MAX_FRAME_SIZE ); + + err = 0; + for ( i = 0; i < 6 ; i++ ) + err |= TLan_EeReadByte( dev->base_addr, (u8) 0x83 + i, (u8 *) &dev->dev_addr[i] ); + if ( err ) + printk( "TLAN: %s: Error reading MAC Address from eeprom: %d\n", dev->name, err ); + dev->addr_len = 6; + + dev->open = &TLan_Open; + dev->hard_start_xmit = &TLan_StartTx; + dev->stop = &TLan_Close; + dev->get_stats = &TLan_GetStats; + dev->set_multicast_list = &TLan_SetMulticastList; + + return 0; + + } /* TLan_Init */ + + + + + /************************************************************************* + * TLan_Open + * + * Returns: 0 on success, error code otherwise. + * Parms: dev Structure of device to be opened. + * + * This routine puts the driver and TLAN adapter in a state where it is + * ready to send and receive packets. It allocates the IRQ, resets and + * brings the adapter out of reset, and allows interrupts. It also + * delays the startup for autonegotiation or sends a Rx GO command to + * the adapter, as appropriate. + * + ************************************************************************/ + + int TLan_Open( struct device *dev ) + { + int err; + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + err = request_irq( dev->irq, TLan_HandleInterrupt, SA_SHIRQ, TLanSignature, dev ); + if ( err ) { + printk( "TLAN: %s: IRQ %d already in use.\n", dev->name, dev->irq ); + return -EAGAIN; + } + + MOD_INC_USE_COUNT; + + dev->tbusy = 0; + dev->interrupt = 0; + dev->start = 1; + + /* NOTE: It might not be necessary to read the stats before a + reset if you don't care what the values are. + */ + TLan_ResetLists( dev ); + TLan_ReadAndClearStats( dev, TLAN_IGNORE ); + TLan_Reset( dev ); + TLan_SetMac( dev, 0, dev->dev_addr ); + outb( ( TLAN_HC_INT_ON >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); + if ( debug >= 1 ) + outb( ( TLAN_HC_REQ_INT >> 8 ), dev->base_addr + TLAN_HOST_CMD + 1 ); + + init_timer( &priv->timer ); + priv->timer.data = (unsigned long) dev; + priv->timer.function = &TLan_Timer; + if ( priv->phyFlags & TLAN_PHY_AUTONEG ) { + priv->timer.expires = jiffies + TLAN_TIMER_LINK_DELAY; + priv->timerSetAt = jiffies; + priv->timerType = TLAN_TIMER_LINK; + add_timer( &priv->timer ); + } else { + TLAN_DBG( 1, "TLAN: RX GO\n" ); + outl( virt_to_bus( priv->rxList ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_RT, dev->base_addr + TLAN_HOST_CMD ); + } + + TLAN_DBG( 1, "TLAN: Device %s opened.\n", dev->name ); + + return 0; + + } /* TLan_Open */ + + + + + /************************************************************************* + * TLan_StartTx + * + * Returns: 0 on success, non-zero on failure. + * Parms: skb A pointer to the sk_buff containing the frame to + * be sent. + * dev The device to send the data on. + * + * This function adds a frame to the Tx list to be sent ASAP. First it + * verifies that the adapter is ready and there is room in the queue. + * Then it sets up the next available list, copies the frame to the + * corresponding buffer. If the adapter Tx channel is idle, it gives + * adapter a Tx Go command on the list, otherwise it sets the forward + * address of the previous list to point to this one. Then it frees + * the sk_buff. + * + ************************************************************************/ + + int TLan_StartTx( struct sk_buff *skb, struct device *dev ) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + TLanList *tail_list; + u8 *tail_buffer; + int pad; + + // printk( "Entering StartTx\n" ); + if ( ! priv->phyOnline ) { + dev_kfree_skb( skb, FREE_WRITE ); + return 0; + } + + tail_list = priv->txList + priv->txTail; + if ( tail_list->cStat != TLAN_CSTAT_UNUSED ) { + // printk( "TLAN: %s TX is busy, Head=%d Tail=%d\n", dev->name, priv->txHead, priv->txTail ); + dev->tbusy = 1; + // printk( "TLAN: Tx is busy.\n"); + priv->txBusyCount++; + return 1; + } + tail_list->forward = 0; + tail_buffer = priv->txBuffer + ( priv->txTail * TLAN_MAX_FRAME_SIZE ); + memcpy( tail_buffer, skb->data, skb->len ); + pad = TLAN_MIN_FRAME_SIZE - skb->len; + if ( pad > 0 ) { + tail_list->frameSize = (u16) skb->len + pad; + tail_list->buffer[0].count = (u32) skb->len; + tail_list->buffer[1].count = TLAN_LAST_BUFFER | (u32) pad; + tail_list->buffer[1].address = virt_to_bus( TLanPadBuffer ); + } else { + tail_list->frameSize = (u16) skb->len; + tail_list->buffer[0].count = TLAN_LAST_BUFFER | (u32) skb->len; + tail_list->buffer[1].count = 0; + tail_list->buffer[1].address = 0; + } + // are we transferring? + cli(); + tail_list->cStat = TLAN_CSTAT_READY; + if ( ! priv->txInProgress ) { + priv->txInProgress = 1; + outw( 0x4, dev->base_addr + TLAN_HOST_INT ); + // printk("TLAN: Sending GO for 0%d\n", priv->txTail ); + outl( virt_to_bus( tail_list ), dev->base_addr + TLAN_CH_PARM ); + outl( TLAN_HC_GO | TLAN_HC_ACK, dev->base_addr + TLAN_HOST_CMD ); + } else { + // printk("TLAN: Adding 0%d\n", priv->txTail ); + // Assign previous list to point to this one. If previous has + // already been read, the EOC check in the TX EOF interrupt handler + // will start another transfer. + if ( priv->txTail == 0 ) + ( priv->txList + ( TLAN_NUM_TX_LISTS - 1 ) )->forward = virt_to_bus( tail_list ); + else + ( priv->txList + ( priv->txTail - 1 ) )->forward = virt_to_bus( tail_list ); + } + sti(); + priv->txTail++; + if ( priv->txTail >= TLAN_NUM_TX_LISTS ) + priv->txTail = 0; + + dev_kfree_skb( skb, FREE_WRITE ); + + dev->trans_start = jiffies; + // printk( "Leaving StartTx\n" ); + return 0; + + } /* TLan_StartTx */ + + + + + /************************************************************************* + * TLan_HandleInterrupt + * + * Returns: Nothing + * Parms: irq The line on which the interrupt occurred. + * dev_id A pointer to the device assigned to this irq line. + * regs ??? + * + * This function handles an interrupt generated by its assigned TLAN + * adapter. The function deactivates interrupts on its adapter, records + * the type of interrupt, executes the appropriate subhandler, and + * acknowdges the interrupt to the adapter (thus re-enabling adapter + * interrupts. + * + ************************************************************************/ + + void TLan_HandleInterrupt(int irq, void *dev_id, struct pt_regs *regs) + { + u32 ack; + struct device *dev; + u32 host_cmd; + u16 host_int; + int type; + + dev = (struct device *) dev_id; + + if ( dev->interrupt ) + TLAN_DBG( 1, "TLAN: Re-entering interrupt handler for %s: %d.\n" , dev->name, dev->interrupt ); + dev->interrupt++; + + cli(); + + host_int = inw( dev->base_addr + TLAN_HOST_INT ); + outw( host_int, dev->base_addr + TLAN_HOST_INT ); // Deactivate Ints + + type = ( host_int & TLAN_HI_IT_MASK ) >> 2; + + ack = TLanIntVector[type]( dev, host_int ); + + sti(); + + if ( ack ) { + host_cmd = TLAN_HC_ACK | ack | ( type << 18 ); + outl( host_cmd, dev->base_addr + TLAN_HOST_CMD ); + } + + dev->interrupt--; + + } /* TLan_HandleInterrupts */ + + + + + /************************************************************************* + * TLan_Close + * + * Returns: An error code. + * Parms: dev The device structure of the device to close. + * + * This function shuts down the adapter. It records any stats, puts + * the adapter into reset state, deactivates its time as needed, and + * frees the irq it is using. + * + ************************************************************************/ + + int TLan_Close(struct device *dev) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + + dev->start = 0; + dev->tbusy = 1; + + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + outl( TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD ); + if ( priv->timerSetAt != 0 ) + del_timer( &priv->timer ); + free_irq( dev->irq, dev ); + TLAN_DBG( 1, "TLAN: Device %s closed.\n", dev->name ); + + MOD_DEC_USE_COUNT; + + return 0; + + } /* TLan_Close */ + + + + + /************************************************************************* + * TLan_GetStats + * + * Returns: A pointer to the device's statistics structure. + * Parms: dev The device structure to return the stats for. + * + * This function updates the devices statistics by reading the TLAN + * chip's onboard registers. Then it returns the address of the + * statistics structure. + * + ************************************************************************/ + + struct enet_statistics *TLan_GetStats( struct device *dev ) + { + TLanPrivateInfo *priv = (TLanPrivateInfo *) dev->priv; + int i; + + /* Should only read stats if open ? */ + TLan_ReadAndClearStats( dev, TLAN_RECORD ); + printk( "TLAN: %s Rx EOC Count: %d\n", dev->name, priv->rxEocCount ); + printk( "TLAN: %s Tx Busy Count: %d\n", dev->name, priv->txBusyCount ); + // printk( "TLAN: Got stats for %s.\n", dev->name ); + TLan_PrintDio( dev->base_addr ); + TLan_PhyPrint( dev ); + for ( i = 0; i < TLAN_NUM_RX_LISTS; i++ ) + TLan_PrintList( priv->rxList + i, "RX", i ); + for ( i = 0; i < TLAN_NUM_TX_LISTS; i++ ) + TLan_PrintList( priv->txList + i, "TX", i ); + + return ( &( (TLanPrivateInfo *) dev->priv )->stats ); + + } /* TLan_GetStats */ + + + + + /************************************************************************* + * TLan_SetMulticastList + * + * Returns: Nothing + * Parms: dev The device structure to set the multicast list for. + * + * This function sets the TLAN adaptor to various receive modes. If the + * IFF_PROMISC flag is set, promiscuous mode is acitviated. Otherwise, + * promiscuous mode is turned off. If the IFF_ALLMULTI flag is set, then + * the hash table is set to receive all group addresses. Otherwise, the + * first three multicast addresses are stored in AREG_1-3, and the rest + * are selected via the hash table, as necessary. + * + ************************************************************************/ + + void TLan_SetMulticastList( struct device *dev ) + { + struct dev_mc_list *dmi = dev->mc_list; + u32 hash1 = 0; + u32 hash2 = 0; + int i; + u32 offset; + u8 tmp; + + if ( dev->flags & IFF_PROMISC ) { + tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp | TLAN_NET_CMD_CAF ); + } else { + tmp = TLan_DioRead8( dev->base_addr, TLAN_NET_CMD ); + TLan_DioWrite8( dev->base_addr, TLAN_NET_CMD, tmp & ~TLAN_NET_CMD_CAF ); + if ( dev->flags & IFF_ALLMULTI ) { + for ( i = 0; i < 3; i++ ) + TLan_SetMac( dev, i + 1, NULL ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, 0xFFFFFFFF ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, 0xFFFFFFFF ); + } else { + for ( i = 0; i < dev->mc_count; i++ ) { + if ( i < 3 ) { + TLan_SetMac( dev, i + 1, (char *) &dmi->dmi_addr ); + } else { + offset = TLan_HashFunc( (u8 *) &dmi->dmi_addr ); + if ( offset < 32 ) + hash1 |= ( 1 << offset ); + else + hash2 |= ( 1 << ( offset - 32 ) ); + } + dmi = dmi->next; + } + for ( ; i < 3; i++ ) + TLan_SetMac( dev, i + 1, NULL ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_1, hash1 ); + TLan_DioWrite32( dev->base_addr, TLAN_HASH_2, hash2 ); + } + } + + } /* TLan_SetRxMode */ diff -u --recursive --new-file v2.1.44/linux/drivers/net/tlan.h linux/drivers/net/tlan.h --- v2.1.44/linux/drivers/net/tlan.h Wed Dec 31 16:00:00 1969 +++ linux/drivers/net/tlan.h Wed Jul 16 19:22:51 1997 @@ -0,0 +1,485 @@ +/******************************************************************** + * + * Linux ThunderLAN Driver + * + * tlan.h + * by James Banks, james.banks@caldera.com + * + * (C) 1997 Caldera, Inc. + * + * This software may be used and distributed according to the terms + * of the GNU Public License, incorporated herein by reference. + * + ** This file is best viewed/edited with tabstop=4, colums>=132 + * + ********************************************************************/ + +#include +#include +#include + + + + /***************************************************************** + * TLan Definitions + * + ****************************************************************/ + + #define FALSE 0 + #define TRUE 1 + + #define TLAN_MIN_FRAME_SIZE 64 + #define TLAN_MAX_FRAME_SIZE 1600 + + #define TLAN_NUM_RX_LISTS 4 + #define TLAN_NUM_TX_LISTS 8 + + #define TLAN_IGNORE 0 + #define TLAN_RECORD 1 + + #define TLAN_DBG(lvl, format, args...) if ( debug >= lvl ) printk( format, ##args ); + + + + + /***************************************************************** + * Device Identification Definitions + * + ****************************************************************/ + + /* NOTE: These should be moved to pci.h someday */ + #define PCI_DEVICE_ID_NETELLIGENT_10 0xAE34 + #define PCI_DEVICE_ID_NETELLIGENT_10_100 0xAE32 + #define PCI_DEVICE_ID_NETFLEX_3_INTEGRATED 0xAE35 + + + typedef struct tlan_pci_id { + u16 vendorId; + u16 deviceId; + char *deviceName; + } TLanPciId; + + + + + /***************************************************************** + * Rx/Tx List Definitions + * + ****************************************************************/ + + #define TLAN_BUFFERS_PER_LIST 10 + #define TLAN_LAST_BUFFER 0x80000000 + #define TLAN_CSTAT_UNUSED 0x8000 + #define TLAN_CSTAT_FRM_CMP 0x4000 + #define TLAN_CSTAT_READY 0x3000 + #define TLAN_CSTAT_EOC 0x0800 + #define TLAN_CSTAT_RX_ERROR 0x0400 + #define TLAN_CSTAT_PASS_CRC 0x0200 + #define TLAN_CSTAT_DP_PR 0x0100 + + + typedef struct tlan_buffer_ref_tag { + u32 count; + u32 address; + } TLanBufferRef; + + + typedef struct tlan_list_tag { + u32 forward; + u16 cStat; + u16 frameSize; + TLanBufferRef buffer[TLAN_BUFFERS_PER_LIST]; + } TLanList; + + + typedef u8 TLanBuffer[TLAN_MAX_FRAME_SIZE]; + + + + + /***************************************************************** + * PHY definitions + * + ****************************************************************/ + + #define TLAN_PHY_MAX_ADDR 0x1F + #define TLAN_PHY_INTERNAL 0x1F + + #define TLAN_PHY_ACTIVITY 0x00000001 + #define TLAN_PHY_AUTONEG 0x00000002 + + + typedef int (TLanPhyFunc)( struct device * ); + + + typedef struct tlan_phy_id_entry_tag { + u16 idHi; + u16 idLo; + TLanPhyFunc *check; + TLanPhyFunc *service; + u32 flags; + } TLanPhyIdEntry; + + + + + /***************************************************************** + * TLAN Private Information Structure + * + ****************************************************************/ + + typedef struct tlan_private_tag { + struct device *nextDevice; + void *dmaStorage; + u8 *padBuffer; + TLanList *rxList; + u8 *rxBuffer; + u32 rxHead; + u32 rxTail; + u32 rxEocCount; + TLanList *txList; + u8 *txBuffer; + u32 txHead; + u32 txInProgress; + u32 txTail; + u32 txBusyCount; + u32 phyAddr; + u32 phyEntry; + u32 phyOnline; + u32 phyFlags; + TLanPhyFunc *phyCheck; + TLanPhyFunc *phyService; + u32 timerSetAt; + u32 timerType; + struct timer_list timer; + struct enet_statistics stats; + u32 pciEntry; + u8 pciRevision; + u8 pciBus; + u8 pciDeviceFn; + char devName[8]; + } TLanPrivateInfo; + + + + + /***************************************************************** + * TLan Driver Timer Definitions + * + ****************************************************************/ + + #define TLAN_TIMER_LINK 1 + #define TLAN_TIMER_ACT 2 + + #define TLAN_TIMER_LINK_DELAY 230 + #define TLAN_TIMER_ACT_DELAY 10 + + + + + /***************************************************************** + * TLan Driver Eeprom Definitions + * + ****************************************************************/ + + #define TLAN_EEPROM_ACK 0 + #define TLAN_EEPROM_STOP 1 + + + + + /***************************************************************** + * Host Register Offsets and Contents + * + ****************************************************************/ + + #define TLAN_HOST_CMD 0x00 + #define TLAN_HC_GO 0x80000000 + #define TLAN_HC_STOP 0x40000000 + #define TLAN_HC_ACK 0x20000000 + #define TLAN_HC_CS_MASK 0x1FE00000 + #define TLAN_HC_EOC 0x00100000 + #define TLAN_HC_RT 0x00080000 + #define TLAN_HC_NES 0x00040000 + #define TLAN_HC_AD_RST 0x00008000 + #define TLAN_HC_LD_TMR 0x00004000 + #define TLAN_HC_LD_THR 0x00002000 + #define TLAN_HC_REQ_INT 0x00001000 + #define TLAN_HC_INT_OFF 0x00000800 + #define TLAN_HC_INT_ON 0x00000400 + #define TLAN_HC_AC_MASK 0x000000FF + #define TLAN_CH_PARM 0x04 + #define TLAN_DIO_ADR 0x08 + #define TLAN_DA_ADR_INC 0x8000 + #define TLAN_DA_RAM_ADR 0x4000 + #define TLAN_HOST_INT 0x0A + #define TLAN_HI_IV_MASK 0x1FE0 + #define TLAN_HI_IT_MASK 0x001C + #define TLAN_DIO_DATA 0x0C + + +/* ThunderLAN Internal Register DIO Offsets */ + +#define TLAN_NET_CMD 0x00 +#define TLAN_NET_CMD_NRESET 0x80 +#define TLAN_NET_CMD_NWRAP 0x40 +#define TLAN_NET_CMD_CSF 0x20 +#define TLAN_NET_CMD_CAF 0x10 +#define TLAN_NET_CMD_NOBRX 0x08 +#define TLAN_NET_CMD_DUPLEX 0x04 +#define TLAN_NET_CMD_TRFRAM 0x02 +#define TLAN_NET_CMD_TXPACE 0x01 +#define TLAN_NET_SIO 0x01 +#define TLAN_NET_SIO_MINTEN 0x80 +#define TLAN_NET_SIO_ECLOK 0x40 +#define TLAN_NET_SIO_ETXEN 0x20 +#define TLAN_NET_SIO_EDATA 0x10 +#define TLAN_NET_SIO_NMRST 0x08 +#define TLAN_NET_SIO_MCLK 0x04 +#define TLAN_NET_SIO_MTXEN 0x02 +#define TLAN_NET_SIO_MDATA 0x01 +#define TLAN_NET_STS 0x02 +#define TLAN_NET_STS_MIRQ 0x80 +#define TLAN_NET_STS_HBEAT 0x40 +#define TLAN_NET_STS_TXSTOP 0x20 +#define TLAN_NET_STS_RXSTOP 0x10 +#define TLAN_NET_STS_RSRVD 0x0F +#define TLAN_NET_MASK 0x03 +#define TLAN_NET_MASK_MASK7 0x80 +#define TLAN_NET_MASK_MASK6 0x40 +#define TLAN_NET_MASK_MASK5 0x20 +#define TLAN_NET_MASK_MASK4 0x10 +#define TLAN_NET_MASK_RSRVD 0x0F +#define TLAN_NET_CONFIG 0x04 +#define TLAN_NET_CFG_RCLK 0x8000 +#define TLAN_NET_CFG_TCLK 0x4000 +#define TLAN_NET_CFG_BIT 0x2000 +#define TLAN_NET_CFG_RXCRC 0x1000 +#define TLAN_NET_CFG_PEF 0x0800 +#define TLAN_NET_CFG_1FRAG 0x0400 +#define TLAN_NET_CFG_1CHAN 0x0200 +#define TLAN_NET_CFG_MTEST 0x0100 +#define TLAN_NET_CFG_PHY_EN 0x0080 +#define TLAN_NET_CFG_MSMASK 0x007F +#define TLAN_MAN_TEST 0x06 +#define TLAN_DEF_VENDOR_ID 0x08 +#define TLAN_DEF_DEVICE_ID 0x0A +#define TLAN_DEF_REVISION 0x0C +#define TLAN_DEF_SUBCLASS 0x0D +#define TLAN_DEF_MIN_LAT 0x0E +#define TLAN_DEF_MAX_LAT 0x0F +#define TLAN_AREG_0 0x10 +#define TLAN_AREG_1 0x16 +#define TLAN_AREG_2 0x1C +#define TLAN_AREG_3 0x22 +#define TLAN_HASH_1 0x28 +#define TLAN_HASH_2 0x2C +#define TLAN_GOOD_TX_FRMS 0x30 +#define TLAN_TX_UNDERUNS 0x33 +#define TLAN_GOOD_RX_FRMS 0x34 +#define TLAN_RX_OVERRUNS 0x37 +#define TLAN_DEFERRED_TX 0x38 +#define TLAN_CRC_ERRORS 0x3A +#define TLAN_CODE_ERRORS 0x3B +#define TLAN_MULTICOL_FRMS 0x3C +#define TLAN_SINGLECOL_FRMS 0x3E +#define TLAN_EXCESSCOL_FRMS 0x40 +#define TLAN_LATE_COLS 0x41 +#define TLAN_CARRIER_LOSS 0x42 +#define TLAN_ACOMMIT 0x43 +#define TLAN_LED_REG 0x44 +#define TLAN_LED_ACT 0x10 +#define TLAN_LED_LINK 0x01 +#define TLAN_BSIZE_REG 0x45 +#define TLAN_MAX_RX 0x46 +#define TLAN_INT_DIS 0x48 +#define TLAN_ID_TX_EOC 0x04 +#define TLAN_ID_RX_EOF 0x02 +#define TLAN_ID_RX_EOC 0x01 + + + +/* ThunderLAN Interrupt Codes */ + +#define TLAN_INT_NUMBER_OF_INTS 8 + +#define TLAN_INT_NONE 0x0000 +#define TLAN_INT_TX_EOF 0x0001 +#define TLAN_INT_STAT_OVERFLOW 0x0002 +#define TLAN_INT_RX_EOF 0x0003 +#define TLAN_INT_DUMMY 0x0004 +#define TLAN_INT_TX_EOC 0x0005 +#define TLAN_INT_STATUS_CHECK 0x0006 +#define TLAN_INT_RX_EOC 0x0007 + + + +/* ThunderLAN MII Registers */ + +/* Generic MII/PHY Registers */ + +#define MII_GEN_CTL 0x00 +#define MII_GC_RESET 0x8000 +#define MII_GC_LOOPBK 0x4000 +#define MII_GC_SPEEDSEL 0x2000 +#define MII_GC_AUTOENB 0x1000 +#define MII_GC_PDOWN 0x0800 +#define MII_GC_ISOLATE 0x0400 +#define MII_GC_AUTORSRT 0x0200 +#define MII_GC_DUPLEX 0x0100 +#define MII_GC_COLTEST 0x0080 +#define MII_GC_RESERVED 0x007F +#define MII_GEN_STS 0x01 +#define MII_GS_100BT4 0x8000 +#define MII_GS_100BTXFD 0x4000 +#define MII_GS_100BTXHD 0x2000 +#define MII_GS_10BTFD 0x1000 +#define MII_GS_10BTHD 0x0800 +#define MII_GS_RESERVED 0x07C0 +#define MII_GS_AUTOCMPLT 0x0020 +#define MII_GS_RFLT 0x0010 +#define MII_GS_AUTONEG 0x0008 +#define MII_GS_LINK 0x0004 +#define MII_GS_JABBER 0x0002 +#define MII_GS_EXTCAP 0x0001 +#define MII_GEN_ID_HI 0x02 +#define MII_GEN_ID_LO 0x03 +#define MII_GIL_OUI 0xFC00 +#define MII_GIL_MODEL 0x03F0 +#define MII_GIL_REVISION 0x000F +#define MII_AN_ADV 0x04 +#define MII_AN_LPA 0x05 +#define MII_AN_EXP 0x06 + +/* ThunderLAN Specific MII/PHY Registers */ + +#define TLAN_TLPHY_ID 0x10 +#define TLAN_TLPHY_CTL 0x11 +#define TLAN_TC_IGLINK 0x8000 +#define TLAN_TC_SWAPOL 0x4000 +#define TLAN_TC_AUISEL 0x2000 +#define TLAN_TC_SQEEN 0x1000 +#define TLAN_TC_MTEST 0x0800 +#define TLAN_TC_RESERVED 0x07F8 +#define TLAN_TC_NFEW 0x0004 +#define TLAN_TC_INTEN 0x0002 +#define TLAN_TC_TINT 0x0001 +#define TLAN_TLPHY_STS 0x12 +#define TLAN_TS_MINT 0x8000 +#define TLAN_TS_PHOK 0x4000 +#define TLAN_TS_POLOK 0x2000 +#define TLAN_TS_TPENERGY 0x1000 +#define TLAN_TS_RESERVED 0x0FFF + + + +/* Routines to access internal registers. */ + +inline u8 TLan_DioRead8(u16 base_addr, u16 internal_addr) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + return (inb((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x3))); + +} /* TLan_DioRead8 */ + + + + +inline u16 TLan_DioRead16(u16 base_addr, u16 internal_addr) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + return (inw((base_addr + TLAN_DIO_DATA) + (internal_addr & 0x2))); + +} /* TLan_DioRead16 */ + + + + +inline u32 TLan_DioRead32(u16 base_addr, u16 internal_addr) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + return (inl(base_addr + TLAN_DIO_DATA)); + +} /* TLan_DioRead32 */ + + + + +inline void TLan_DioWrite8(u16 base_addr, u16 internal_addr, u8 data) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + outb(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x3)); + +} + + + + +inline void TLan_DioWrite16(u16 base_addr, u16 internal_addr, u16 data) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + outw(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2)); + +} + + + + +inline void TLan_DioWrite32(u16 base_addr, u16 internal_addr, u32 data) +{ + outw(internal_addr, base_addr + TLAN_DIO_ADR); + outl(data, base_addr + TLAN_DIO_DATA + (internal_addr & 0x2)); + +} + + + + +inline void TLan_ClearBit(u8 bit, u16 port) +{ + outb_p(inb_p(port) & ~bit, port); +} + + + + +inline int TLan_GetBit(u8 bit, u16 port) +{ + return ((int) (inb_p(port) & bit)); +} + + + + +inline void TLan_SetBit(u8 bit, u16 port) +{ + outb_p(inb_p(port) | bit, port); +} + + +inline u32 xor( u32 a, u32 b ) +{ + return ( ( a && ! b ) || ( ! a && b ) ); +} +#define XOR8( a, b, c, d, e, f, g, h ) xor( a, xor( b, xor( c, xor( d, xor( e, xor( f, xor( g, h ) ) ) ) ) ) ) +#define DA( a, bit ) ( ( (u8) a[bit/8] ) & ( (u8) ( 1 << bit%8 ) ) ) + +inline u32 TLan_HashFunc( u8 *a ) +{ + u32 hash; + + hash = XOR8( DA(a,0), DA(a, 6), DA(a,12), DA(a,18), DA(a,24), DA(a,30), DA(a,36), DA(a,42) ); + hash |= XOR8( DA(a,1), DA(a, 7), DA(a,13), DA(a,19), DA(a,25), DA(a,31), DA(a,37), DA(a,43) ) << 1; + hash |= XOR8( DA(a,2), DA(a, 8), DA(a,14), DA(a,20), DA(a,26), DA(a,32), DA(a,38), DA(a,44) ) << 2; + hash |= XOR8( DA(a,3), DA(a, 9), DA(a,15), DA(a,21), DA(a,27), DA(a,33), DA(a,39), DA(a,45) ) << 3; + hash |= XOR8( DA(a,4), DA(a,10), DA(a,16), DA(a,22), DA(a,28), DA(a,34), DA(a,40), DA(a,46) ) << 4; + hash |= XOR8( DA(a,5), DA(a,11), DA(a,17), DA(a,23), DA(a,29), DA(a,35), DA(a,41), DA(a,47) ) << 5; + + return hash; + +} + + + + +#endif diff -u --recursive --new-file v2.1.44/linux/drivers/net/tulip.c linux/drivers/net/tulip.c --- v2.1.44/linux/drivers/net/tulip.c Tue May 13 22:41:12 1997 +++ linux/drivers/net/tulip.c Wed Jul 16 19:22:51 1997 @@ -1078,6 +1078,7 @@ skb->protocol = eth_type_trans(skb,dev); netif_rx(skb); lp->stats.rx_packets++; + lp->stats.rx_bytes+=skb->len; } lp->rx_ring[entry].status = TRING_OWN; diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/bwtwo.c linux/drivers/sbus/char/bwtwo.c --- v2.1.44/linux/drivers/sbus/char/bwtwo.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/bwtwo.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: bwtwo.c,v 1.17 1997/06/06 10:56:28 jj Exp $ +/* $Id: bwtwo.c,v 1.18 1997/07/17 02:21:43 davem Exp $ * bwtwo.c: bwtwo console driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -92,9 +92,10 @@ map_offset = get_phys ((unsigned long) fb->base); r = io_remap_page_range (vma->vm_start, map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + if (r) + return -EAGAIN; + + vma->vm_dentry = dget(file->f_dentry); return 0; } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/cgfourteen.c linux/drivers/sbus/char/cgfourteen.c --- v2.1.44/linux/drivers/sbus/char/cgfourteen.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/cgfourteen.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: cgfourteen.c,v 1.23 1997/06/06 10:56:29 jj Exp $ +/* $Id: cgfourteen.c,v 1.24 1997/07/17 02:21:44 davem Exp $ * cgfourteen.c: Sun SparcStation console support. * * Copyright (C) 1995 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -269,11 +269,12 @@ map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; + if (r) + return -EAGAIN; page += map_size; } - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + + vma->vm_dentry = dget(file->f_dentry); return 0; } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/cgsix.c linux/drivers/sbus/char/cgsix.c --- v2.1.44/linux/drivers/sbus/char/cgsix.c Mon Jul 7 08:18:55 1997 +++ linux/drivers/sbus/char/cgsix.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: cgsix.c,v 1.33 1997/07/01 09:12:05 jj Exp $ +/* $Id: cgsix.c,v 1.35 1997/07/17 02:21:45 davem Exp $ * cgsix.c: cgsix frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -321,11 +321,12 @@ map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; + if (r) + return -EAGAIN; page += map_size; } - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + + vma->vm_dentry = dget(file->f_dentry); return 0; } @@ -512,6 +513,10 @@ cg6info->bt->control = 0x73 << 24; cg6info->bt->addr = 0x07 << 24; cg6info->bt->control = 0x00 << 24; + +#ifdef __sparc_v9__ + printk("VA %016lx ", fb->base); +#endif printk("TEC Rev %x ", (cg6info->thc->thc_misc >> CG6_THC_MISC_REV_SHIFT) & diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/cgthree.c linux/drivers/sbus/char/cgthree.c --- v2.1.44/linux/drivers/sbus/char/cgthree.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/cgthree.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: cgthree.c,v 1.22 1997/06/06 10:56:30 jj Exp $ +/* $Id: cgthree.c,v 1.23 1997/07/17 02:21:46 davem Exp $ * cgtree.c: cg3 frame buffer driver * * Copyright (C) 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -128,11 +128,12 @@ map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; + if (r) + return -EAGAIN; page += map_size; } - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + + vma->vm_dentry = dget(file->f_dentry); return 0; } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/creator.c linux/drivers/sbus/char/creator.c --- v2.1.44/linux/drivers/sbus/char/creator.c Mon Jun 16 16:35:56 1997 +++ linux/drivers/sbus/char/creator.c Wed Jul 16 20:37:21 1997 @@ -1,13 +1,13 @@ -/* - * creator.c: Linux/Sun Ultra Creator console support. - * - * Copyright (C) 1997 MIguel de Icaza (miguel@nuclecu.unam.mx) +/* $Id: creator.c,v 1.7 1997/07/17 02:21:47 davem Exp $ + * creator.c: Creator/Creator3D frame buffer driver * + * Copyright (C) 1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) */ #include #include #include #include +#include #include #include @@ -20,31 +20,575 @@ #include #include #include "fb.h" +#include "cg_common.h" + +#define FFB_SFB8R_VOFF 0x00000000 +#define FFB_SFB8G_VOFF 0x00400000 +#define FFB_SFB8B_VOFF 0x00800000 +#define FFB_SFB8X_VOFF 0x00c00000 +#define FFB_SFB32_VOFF 0x01000000 +#define FFB_SFB64_VOFF 0x02000000 +#define FFB_FBC_REGS_VOFF 0x04000000 +#define FFB_BM_FBC_REGS_VOFF 0x04002000 +#define FFB_DFB8R_VOFF 0x04004000 +#define FFB_DFB8G_VOFF 0x04404000 +#define FFB_DFB8B_VOFF 0x04804000 +#define FFB_DFB8X_VOFF 0x04c04000 +#define FFB_DFB24_VOFF 0x05004000 +#define FFB_DFB32_VOFF 0x06004000 +#define FFB_DFB422A_VOFF 0x07004000 /* DFB 422 mode write to A */ +#define FFB_DFB422AD_VOFF 0x07804000 /* DFB 422 mode with line doubling */ +#define FFB_DFB24B_VOFF 0x08004000 /* DFB 24bit mode write to B */ +#define FFB_DFB422B_VOFF 0x09004000 /* DFB 422 mode write to B */ +#define FFB_DFB422BD_VOFF 0x09804000 /* DFB 422 mode with line doubling */ +#define FFB_SFB16Z_VOFF 0x0a004000 /* 16bit mode Z planes */ +#define FFB_SFB8Z_VOFF 0x0a404000 /* 8bit mode Z planes */ +#define FFB_SFB422_VOFF 0x0ac04000 /* SFB 422 mode write to A/B */ +#define FFB_SFB422D_VOFF 0x0b404000 /* SFB 422 mode with line doubling */ +#define FFB_FBC_KREGS_VOFF 0x0bc04000 +#define FFB_DAC_VOFF 0x0bc06000 +#define FFB_PROM_VOFF 0x0bc08000 +#define FFB_EXP_VOFF 0x0bc18000 + +#define FFB_SFB8R_POFF 0x04000000 +#define FFB_SFB8G_POFF 0x04400000 +#define FFB_SFB8B_POFF 0x04800000 +#define FFB_SFB8X_POFF 0x04c00000 +#define FFB_SFB32_POFF 0x05000000 +#define FFB_SFB64_POFF 0x06000000 +#define FFB_FBC_REGS_POFF 0x00600000 +#define FFB_BM_FBC_REGS_POFF 0x00600000 +#define FFB_DFB8R_POFF 0x01000000 +#define FFB_DFB8G_POFF 0x01400000 +#define FFB_DFB8B_POFF 0x01800000 +#define FFB_DFB8X_POFF 0x01c00000 +#define FFB_DFB24_POFF 0x02000000 +#define FFB_DFB32_POFF 0x03000000 +#define FFB_FBC_KREGS_POFF 0x00610000 +#define FFB_DAC_POFF 0x00400000 +#define FFB_PROM_POFF 0x00000000 +#define FFB_EXP_POFF 0x00200000 + +#define FFB_Y_BYTE_ADDR_SHIFT 11 +#define FFB_Y_ADDR_SHIFT 13 + +#define FFB_PPC_ACE_DISABLE 1 +#define FFB_PPC_ACE_AUX_ADD 3 +#define FFB_PPC_ACE_SHIFT 18 +#define FFB_PPC_DCE_DISABLE 2 +#define FFB_PPC_DCE_SHIFT 16 +#define FFB_PPC_ABE_DISABLE 2 +#define FFB_PPC_ABE_SHIFT 14 +#define FFB_PPC_VCE_DISABLE 1 +#define FFB_PPC_VCE_2D 2 +#define FFB_PPC_VCE_SHIFT 12 +#define FFB_PPC_APE_DISABLE 2 +#define FFB_PPC_APE_SHIFT 10 +#define FFB_PPC_CS_VARIABLE 2 +#define FFB_PPC_CS_SHIFT 0 + +#define FFB_FBC_WB_A 1 +#define FFB_FBC_WB_SHIFT 29 +#define FFB_FBC_PGE_MASK 3 +#define FFB_FBC_BE_SHIFT 4 +#define FFB_FBC_GE_SHIFT 2 +#define FFB_FBC_RE_SHIFT 0 + +#define FFB_ROP_NEW 0x83 +#define FFB_ROP_RGB_SHIFT 0 + +#define FFB_UCSR_FIFO_MASK 0x00000fff +#define FFB_UCSR_RP_BUSY 0x02000000 + +struct ffb_fbc { + u8 xxx1[0x200]; + volatile u32 ppc; + u8 xxx2[0x50]; + volatile u32 fbc; + volatile u32 rop; + u8 xxx3[0x34]; + volatile u32 pmask; + u8 xxx4[12]; + volatile u32 clip0min; + volatile u32 clip0max; + volatile u32 clip1min; + volatile u32 clip1max; + volatile u32 clip2min; + volatile u32 clip2max; + volatile u32 clip3min; + volatile u32 clip3max; + u8 xxx5[0x3c]; + volatile u32 unk1; + u8 xxx6[0x500]; + volatile u32 unk2; + u8 xxx7[0xfc]; + volatile u32 ucsr; +}; + +struct ffb_dac { + volatile u32 type; + volatile u32 value; + volatile u32 type2; + volatile u32 value2; +}; + +static void +ffb_restore_palette (fbinfo_t *fbinfo) +{ +} + +static void ffb_blitc(unsigned short, int, int); +static void ffb_setw(int, int, unsigned short, int); +static void ffb_cpyw(int, int, unsigned short *, int); +static void ffb_fill(int, int, int *); + +static struct { + unsigned long voff; + unsigned long poff; + unsigned long size; +} ffbmmap [] = { + { FFB_SFB8R_VOFF, FFB_SFB8R_POFF, 0x0400000 }, + { FFB_SFB8G_VOFF, FFB_SFB8G_POFF, 0x0400000 }, + { FFB_SFB8B_VOFF, FFB_SFB8B_POFF, 0x0400000 }, + { FFB_SFB8X_VOFF, FFB_SFB8X_POFF, 0x0400000 }, + { FFB_SFB32_VOFF, FFB_SFB32_POFF, 0x1000000 }, + { FFB_SFB64_VOFF, FFB_SFB64_POFF, 0x2000000 }, + { FFB_FBC_REGS_VOFF, FFB_FBC_REGS_POFF, 0x0002000 }, + { FFB_BM_FBC_REGS_VOFF, FFB_BM_FBC_REGS_POFF, 0x0002000 }, + { FFB_DFB8R_VOFF, FFB_DFB8R_POFF, 0x0400000 }, + { FFB_DFB8G_VOFF, FFB_DFB8G_POFF, 0x0400000 }, + { FFB_DFB8B_VOFF, FFB_DFB8B_POFF, 0x0400000 }, + { FFB_DFB8X_VOFF, FFB_DFB8X_POFF, 0x0400000 }, + { FFB_DFB24_VOFF, FFB_DFB24_POFF, 0x1000000 }, + { FFB_DFB32_VOFF, FFB_DFB32_POFF, 0x1000000 }, + { FFB_FBC_KREGS_VOFF, FFB_FBC_KREGS_POFF, 0x0002000 }, + { FFB_DAC_VOFF, FFB_DAC_POFF, 0x0002000 }, + { FFB_PROM_VOFF, FFB_PROM_POFF, 0x0010000 }, + { FFB_EXP_VOFF, FFB_EXP_POFF, 0x0002000 } +}; + +/* Ugh: X wants to mmap a bunch of cute stuff at the same time :-( */ +/* So, we just mmap the things that are being asked for */ +static int +ffb_mmap (struct inode *inode, struct file *file, struct vm_area_struct *vma, + long base, fbinfo_t *fb) +{ + uint size, page, r, map_size; + unsigned long map_offset = 0; + int i; + + size = vma->vm_end - vma->vm_start; + if (vma->vm_offset & ~PAGE_MASK) + return -ENXIO; + + /* Try to align RAM */ +#define ALIGNMENT 0x400000 + map_offset = vma->vm_offset + size; + if (vma->vm_offset < FFB_FBC_REGS_VOFF) { + struct vm_area_struct *vmm = find_vma(current->mm, vma->vm_start); + int alignment = ALIGNMENT - ((vma->vm_start - vma->vm_offset) & (ALIGNMENT - 1)); + + if (alignment == ALIGNMENT) alignment = 0; + if (alignment && (!vmm || vmm->vm_start >= vma->vm_end + alignment)) { + vma->vm_start += alignment; + vma->vm_end += alignment; + } + } +#undef ALIGNMENT + + /* To stop the swapper from even considering these pages */ + vma->vm_flags |= FB_MMAP_VM_FLAGS; + + /* Each page, see which map applies */ + for (page = 0; page < size; ){ + map_size = 0; + for (i = 0; i < sizeof (ffbmmap) / sizeof (ffbmmap[0]); i++) + if (ffbmmap[i].voff == vma->vm_offset+page) { + map_size = ffbmmap[i].size; + map_offset = fb->info.ffb.physbase + ffbmmap[i].poff; + } + + if (!map_size){ + page += PAGE_SIZE; + continue; + } + if (page + map_size > size) + map_size = size - page; + r = io_remap_page_range (vma->vm_start+page, + map_offset, + map_size, vma->vm_page_prot, 0); + if (r) + return -EAGAIN; + page += map_size; + } + + vma->vm_dentry = dget(file->f_dentry); + return 0; +} + +/* XXX write body of these two... */ +static inline int +ffb_wid_get (fbinfo_t *fb, struct fb_wid_list *wl) +{ + struct fb_wid_item *wi; + struct fb_wid_list wlt; + struct fb_wid_item wit[30]; + char *km = NULL; + int i, j; + u32 l; + int err; + +#ifdef CONFIG_SPARC32_COMPAT + if (current->tss.flags & SPARC_FLAG_32BIT) { + if (copy_from_user (&wlt, wl, 2 * sizeof (__u32)) || + __get_user ((long)wlt.wl_list, (((__u32 *)wl)+2))) + return -EFAULT; + } else +#endif + if (copy_from_user (&wlt, wl, sizeof (wlt))) + return -EFAULT; + if (wlt.wl_count <= 30) { + if (copy_from_user (wit, wlt.wl_list, wlt.wl_count * sizeof(*wi))) + return -EFAULT; + wi = wit; + } else if (wlt.wl_count > 120) + return -EINVAL; + else { + wi = (struct fb_wid_item *) km = kmalloc (wlt.wl_count * sizeof (*wi), GFP_KERNEL); + if (!wi) return -ENOMEM; + if (copy_from_user (wi, wlt.wl_list, wlt.wl_count * sizeof(*wi))) { + kfree (wi); + return -EFAULT; + } + } + for (i = 0; i < wlt.wl_count; i++, wi++) { + switch (wi->wi_type) { + case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break; + case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break; + default: return -EINVAL; + } + wi->wi_attrs = 0xffff; + for (j = 0; j < 32; j++) + wi->wi_values [j] = 0; + } + err = 0; + if (copy_to_user (wlt.wl_list, km ? km : (char *)wit, wlt.wl_count * sizeof (*wi))) + err = -EFAULT; + if (km) + kfree (km); + return err; +} + +static inline int +ffb_wid_put (fbinfo_t *fb, struct fb_wid_list *wl) +{ + struct fb_wid_item *wi; + struct fb_wid_list wlt; + struct fb_wid_item wit[30]; + char *km = NULL; + int i, j; + u32 l; + +#ifdef CONFIG_SPARC32_COMPAT + if (current->tss.flags & SPARC_FLAG_32BIT) { + if (copy_from_user (&wlt, wl, 2 * sizeof (__u32)) || + __get_user ((long)wlt.wl_list, (((__u32 *)wl)+2))) + return -EFAULT; + } else +#endif + if (copy_from_user (&wlt, wl, sizeof (wlt))) + return -EFAULT; + if (wlt.wl_count <= 30) { + if (copy_from_user (wit, wlt.wl_list, wlt.wl_count * sizeof(*wi))) + return -EFAULT; + wi = wit; + } else if (wlt.wl_count > 120) + return -EINVAL; + else { + wi = (struct fb_wid_item *) km = kmalloc (wlt.wl_count * sizeof (*wi), GFP_KERNEL); + if (!wi) return -ENOMEM; + if (copy_from_user (wi, wlt.wl_list, wlt.wl_count * sizeof(*wi))) { + kfree (wi); + return -EFAULT; + } + } + for (i = 0; i < wlt.wl_count; i++, wi++) { + switch (wi->wi_type) { + case FB_WID_DBL_8: j = (wi->wi_index & 0xf) + 0x40; break; + case FB_WID_DBL_24: j = wi->wi_index & 0x3f; break; + default: return -EINVAL; + } + /* x = wi->wi_values [j] */; + } + if (km) + kfree (km); + return 0; +} + +static inline void +ffb_curs_enable (fbinfo_t *fb, int enable) +{ + struct ffb_dac *dac = fb->info.ffb.dac; + + dac->type2 = 0x100; + if (fb->info.ffb.dac_rev <= 2) + dac->value2 = enable ? 3 : 0; + else + dac->value2 = enable ? 0 : 3; +} + +static void +ffb_setcursormap (fbinfo_t *fb, unsigned char *red, + unsigned char *green, + unsigned char *blue) +{ + struct ffb_dac *dac = fb->info.ffb.dac; + + ffb_curs_enable (fb, 0); + dac->type2 = 0x102; + dac->value2 = (red[0] | (green[0]<<8) | (blue[0]<<16)); + dac->value2 = (red[1] | (green[1]<<8) | (blue[1]<<16)); +} + +/* Set cursor shape */ +static void +ffb_setcurshape (fbinfo_t *fb) +{ + struct ffb_dac *dac = fb->info.ffb.dac; + int i, j; + + ffb_curs_enable (fb, 0); + for (j = 0; j < 2; j++) { + dac->type2 = j ? 0 : 0x80; + for (i = 0; i < 0x40; i++) { + if (fb->cursor.size.fbx <= 32) { + dac->value2 = fb->cursor.bits [j][i]; + dac->value2 = 0; + } else { + dac->value2 = fb->cursor.bits [j][2*i]; + dac->value2 = fb->cursor.bits [j][2*i+1]; + } + } + } +} + +/* Load cursor information */ +static void +ffb_setcursor (fbinfo_t *fb) +{ + struct ffb_dac *dac = fb->info.ffb.dac; + struct cg_cursor *c = &fb->cursor; + + dac->type2 = 0x104; +/* Should this be just 0x7ff?? Should I do some margin handling and setcurshape + in that case? */ + dac->value2 = (((c->cpos.fbx - c->chot.fbx) & 0xffff) << 16) + |((c->cpos.fby - c->chot.fby) & 0xffff); + ffb_curs_enable (fb, fb->cursor.enable); +} + +static void +ffb_blank (fbinfo_t *fb) +{ +/* XXX Write this */ +} + +static void +ffb_unblank (fbinfo_t *fb) +{ +/* XXX Write this */ +} + +static int ffb_clutstore (fbinfo_t *fb, int offset, int count) +{ + int i; + u32 *clut = fb->info.ffb.clut + offset; + struct ffb_dac *dac = fb->info.ffb.dac; + + dac->type = 0x2000 | offset; + for (i = 0; i < count; i++) + dac->value = *clut++; /* Feed the colors in :)) */ + return 0; +} + +static int ffb_clutpost (fbinfo_t *fb, struct fb_clut *fc) +{ + int i; + u32 *clut; + struct fb_clut fct; + u8 red[256], green[256], blue[256]; + +#ifdef CONFIG_SPARC32_COMPAT + if (current->tss.flags & SPARC_FLAG_32BIT) { + if (copy_from_user (&fct, fc, 3 * sizeof (__u32)) || + __get_user ((long)fct.red, &(((struct fb_clut32 *)fc)->red)) || + __get_user ((long)fct.green, &(((struct fb_clut32 *)fc)->green)) || + __get_user ((long)fct.blue, &(((struct fb_clut32 *)fc)->blue))) + return -EFAULT; + } else +#endif + if (copy_from_user (&fct, fc, sizeof (struct fb_clut))) + return -EFAULT; + i = fct.offset + fct.count; + if (fct.clutid || i <= 0 || i > 256) return -EINVAL; + if (copy_from_user (red, fct.red, fct.count) || + copy_from_user (green, fct.green, fct.count) || + copy_from_user (blue, fct.blue, fct.count)) + return -EFAULT; + clut = fb->info.ffb.clut + fct.offset; + for (i = 0; i < fct.count; i++) + *clut++ = ((red[i])|(green[i]<<8)|(blue[i]<<16)); + return ffb_clutstore (fb, fct.offset, fct.count); +} + +static int ffb_clutread (fbinfo_t *fb, struct fb_clut *fc) +{ +/* XXX write this */ + return 0; +} + +static void +ffb_loadcmap (fbinfo_t *fb, int index, int count) +{ + u32 *clut = fb->info.ffb.clut + index; + int i, j = count; + + for (i = index; j--; i++) + *clut++ = ((fb->color_map CM(i,0))) | + ((fb->color_map CM(i,1)) << 8) | + ((fb->color_map CM(i,2)) << 16); + ffb_clutstore (fb, index, count); +} + +/* Handle ffb-specific ioctls */ +static int +ffb_ioctl (struct inode *inode, struct file *file, unsigned cmd, unsigned long arg, fbinfo_t *fb) +{ + int i; + + switch (cmd) { + case FBIO_WID_GET: + return ffb_wid_get (fb, (struct fb_wid_list *)arg); + case FBIO_WID_PUT: + return ffb_wid_put (fb, (struct fb_wid_list *)arg); + case FFB_CLUTPOST: + return ffb_clutpost (fb, (struct fb_clut *)arg); + case FFB_CLUTREAD: + return ffb_clutread (fb, (struct fb_clut *)arg); + + default: + return -ENOSYS; + } +} -__initfunc(void creator_setup (fbinfo_t *fb, int slot, int con_node, unsigned long creator, int creator_io)) +void +ffb_reset (fbinfo_t *fb) { - uint bases [2]; - unsigned long *p; + struct ffb_info *ffb = &(fb->info.ffb); + int fifo; - if (!creator) { - prom_getproperty (con_node, "address", (char *) &bases[0], 4); - prom_printf ("Bases: %x %x\n", bases [0], bases [1]); - p = (unsigned long *) creator = bases[0]; - fb->base = creator; - fb->base = 0xff168000; - } - - fb->type.fb_cmsize = 256; - fb->mmap = 0; - fb->loadcmap = 0; - fb->setcursor = 0; - fb->setcursormap = 0; - fb->setcurshape = 0; - fb->ioctl = 0; - fb->switch_from_graph = 0; - fb->postsetup = sun_cg_postsetup; - fb->reset = 0; - fb->blank = 0; - fb->unblank = 0; - fb->type.fb_depth = 8; + if (fb->setcursor) + sun_hw_hide_cursor (); + + while ((fifo = (ffb->fbc->ucsr & FFB_UCSR_FIFO_MASK)) < 8); + ffb->fbc->ppc = (FFB_PPC_ACE_DISABLE << FFB_PPC_ACE_SHIFT) | + (FFB_PPC_DCE_DISABLE << FFB_PPC_DCE_SHIFT) | + (FFB_PPC_ABE_DISABLE << FFB_PPC_ABE_SHIFT) | + (FFB_PPC_VCE_DISABLE << FFB_PPC_VCE_SHIFT) | + (FFB_PPC_APE_DISABLE << FFB_PPC_APE_SHIFT) | + (FFB_PPC_CS_VARIABLE << FFB_PPC_CS_SHIFT); + ffb->fbc->fbc = (FFB_FBC_WB_A << FFB_FBC_WB_SHIFT) | + (FFB_FBC_PGE_MASK << FFB_FBC_BE_SHIFT) | + (FFB_FBC_PGE_MASK << FFB_FBC_GE_SHIFT) | + (FFB_FBC_PGE_MASK << FFB_FBC_RE_SHIFT); + ffb->fbc->rop = (FFB_ROP_NEW << FFB_ROP_RGB_SHIFT); + ffb->fbc->pmask = 0x00ffffff; + while (ffb->fbc->ucsr & FFB_UCSR_RP_BUSY); +} + +__initfunc(static unsigned long ffb_postsetup (fbinfo_t *fb, unsigned long memory_start)) +{ + fb->info.ffb.clut = (u32 *)(memory_start); + fb->color_map = (u8 *)(memory_start+256*4+256); + return memory_start + 256*4 + 256*3; +} + +__initfunc(void creator_setup (fbinfo_t *fb, int slot, int ffb_node, unsigned long ffb, int ffb_io)) +{ + struct ffb_info *ffbinfo; + struct linux_prom64_registers regs[2*PROMREG_MAX]; + + if (prom_getproperty(ffb_node, "reg", (void *) regs, sizeof(regs)) <= 0) + return; + ffb = regs[0].phys_addr; + printk ("creator%d at 0x%016lx ", slot, ffb); + + fb->base = ffb; /* ??? */ + + /* Fill in parameters we left out */ + fb->type.fb_cmsize = 256; + fb->mmap = ffb_mmap; + fb->loadcmap = ffb_loadcmap; + fb->reset = ffb_reset; + fb->blank = ffb_blank; + fb->unblank = ffb_unblank; + fb->setcursor = ffb_setcursor; + fb->setcursormap = ffb_setcursormap; + fb->setcurshape = ffb_setcurshape; + fb->postsetup = ffb_postsetup; + fb->blitc = ffb_blitc; + fb->setw = ffb_setw; + fb->cpyw = ffb_cpyw; + fb->fill = ffb_fill; + fb->ioctl = ffb_ioctl; + fb->cursor.hwsize.fbx = 64; + fb->cursor.hwsize.fby = 64; + + ffbinfo = (struct ffb_info *) &fb->info.ffb; + + ffbinfo->physbase = ffb; + + ffbinfo->fbc = (struct ffb_fbc *)(ffb + FFB_FBC_REGS_POFF); + ffbinfo->dac = (struct ffb_dac *)(ffb + FFB_DAC_POFF); + + ffbinfo->dac->type = 0x8000; + ffbinfo->dac_rev = (ffbinfo->dac->value >> 0x1c); + + if (slot == sun_prom_console_id) + fb_restore_palette = ffb_restore_palette; + + /* Initialize Brooktree DAC */ + + printk("DAC %d\n", ffbinfo->dac_rev); + + if (slot && sun_prom_console_id == slot) + return; + + /* Reset the ffb */ + ffb_reset(fb); + + if (!slot) { + /* Enable Video */ + ffb_unblank(fb); + } else { + ffb_blank(fb); + } +} + +extern unsigned char vga_font[]; + +static void ffb_blitc(unsigned short charattr, int xoff, int yoff) +{ +} + +static void ffb_setw(int xoff, int yoff, unsigned short c, int count) +{ +} + +static void ffb_cpyw(int xoff, int yoff, unsigned short *p, int count) +{ +} + +static void ffb_fill(int attrib, int count, int *boxes) +{ } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/fb.h linux/drivers/sbus/char/fb.h --- v2.1.44/linux/drivers/sbus/char/fb.h Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/fb.h Wed Jul 16 19:22:51 1997 @@ -1,4 +1,4 @@ -/* $Id: fb.h,v 1.27 1997/06/06 10:56:28 jj Exp $ +/* $Id: fb.h,v 1.29 1997/07/15 09:48:48 jj Exp $ * fb.h: contains the definitions of the structures that various sun * frame buffer can use to do console driver stuff. * @@ -33,7 +33,7 @@ struct fbcurpos chot; /* hot-spot */ struct fbcurpos size; /* size of mask & image fields */ struct fbcurpos hwsize; /* hw max size */ - int bits[2][32]; /* space for mask & image bits */ + int bits[2][128]; /* space for mask & image bits */ char color [6]; /* cursor colors */ }; @@ -57,6 +57,14 @@ int lowdepth; }; +struct ffb_info { + unsigned long physbase; + struct ffb_fbc *fbc; + struct ffb_dac *dac; + int dac_rev; + u32 *clut; +}; + struct leo_info { struct leo_cursor *cursor; struct leo_lc_ss0_krn *lc_ss0_krn; @@ -113,6 +121,7 @@ struct cg14_info cg14; struct tcx_info tcx; struct leo_info leo; + struct ffb_info ffb; } info; /* per frame information */ int space; /* I/O space this card resides in */ int blanked; /* true if video blanked */ diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/leo.c linux/drivers/sbus/char/leo.c --- v2.1.44/linux/drivers/sbus/char/leo.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/leo.c Wed Jul 16 20:37:21 1997 @@ -1,7 +1,7 @@ -/* $Id: leo.c,v 1.19 1997/06/06 10:56:30 jj Exp $ +/* $Id: leo.c,v 1.21 1997/07/17 02:21:48 davem Exp $ * leo.c: SUNW,leo 24/8bit frame buffer driver * - * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) + * Copyright (C) 1996,1997 Jakub Jelinek (jj@sunsite.mff.cuni.cz) * Copyright (C) 1997 Michal Rehacek (Michal.Rehacek@st.mff.cuni.cz) */ @@ -218,11 +218,12 @@ map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; + if (r) + return -EAGAIN; page += map_size; } - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + + vma->vm_dentry = dget(file->f_dentry); return 0; } @@ -376,7 +377,7 @@ return 0; } -static int leo_clutpost (fbinfo_t *fb, struct leo_clut *lc) +static int leo_clutpost (fbinfo_t *fb, struct fb_clut *lc) { int xlate = 0, i; u32 *clut; @@ -398,7 +399,7 @@ return leo_clutstore (fb, lc->clutid); } -static int leo_clutread (fbinfo_t *fb, struct leo_clut *lc) +static int leo_clutread (fbinfo_t *fb, struct fb_clut *lc) { int i; u32 u; @@ -463,29 +464,29 @@ if (i) return i; return leo_wid_put (fb, (struct fb_wid_list *)arg); case LEO_CLUTPOST: - i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut)); + i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_clut)); if (i) return i; - i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count; + i = ((struct fb_clut *)arg)->offset + ((struct fb_clut *)arg)->count; if (i <= 0 || i > 256) return -EINVAL; - i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count); + i = verify_area (VERIFY_READ, ((struct fb_clut *)arg)->red, ((struct fb_clut *)arg)->count); if (i) return i; - i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count); + i = verify_area (VERIFY_READ, ((struct fb_clut *)arg)->green, ((struct fb_clut *)arg)->count); if (i) return i; - i = verify_area (VERIFY_READ, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count); + i = verify_area (VERIFY_READ, ((struct fb_clut *)arg)->blue, ((struct fb_clut *)arg)->count); if (i) return i; - return leo_clutpost (fb, (struct leo_clut *)arg); + return leo_clutpost (fb, (struct fb_clut *)arg); case LEO_CLUTREAD: - i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct leo_clut)); + i = verify_area (VERIFY_READ, (void *)arg, sizeof (struct fb_clut)); if (i) return i; - i = ((struct leo_clut *)arg)->offset + ((struct leo_clut *)arg)->count; + i = ((struct fb_clut *)arg)->offset + ((struct fb_clut *)arg)->count; if (i <= 0 || i > 256) return -EINVAL; - i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->red, ((struct leo_clut *)arg)->count); + i = verify_area (VERIFY_WRITE, ((struct fb_clut *)arg)->red, ((struct fb_clut *)arg)->count); if (i) return i; - i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->green, ((struct leo_clut *)arg)->count); + i = verify_area (VERIFY_WRITE, ((struct fb_clut *)arg)->green, ((struct fb_clut *)arg)->count); if (i) return i; - i = verify_area (VERIFY_WRITE, ((struct leo_clut *)arg)->blue, ((struct leo_clut *)arg)->count); + i = verify_area (VERIFY_WRITE, ((struct fb_clut *)arg)->blue, ((struct fb_clut *)arg)->count); if (i) return i; - return leo_clutread (fb, (struct leo_clut *)arg); + return leo_clutread (fb, (struct fb_clut *)arg); default: return -ENOSYS; diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/suncons.c linux/drivers/sbus/char/suncons.c --- v2.1.44/linux/drivers/sbus/char/suncons.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/suncons.c Wed Jul 16 19:22:51 1997 @@ -1,4 +1,4 @@ -/* $Id: suncons.c,v 1.64 1997/06/06 10:56:25 jj Exp $ +/* $Id: suncons.c,v 1.66 1997/07/15 09:48:47 jj Exp $ * * suncons.c: Sun SparcStation console support. * @@ -828,10 +828,14 @@ { int root, n; +#ifdef __sparc_v9__ root = prom_getchild (prom_root_node); if ((n = prom_searchsiblings (root, "SUNW,ffb")) == 0) return 0; return n; +#else + return 0; +#endif } __initfunc(static void @@ -1108,7 +1112,6 @@ if (!card_found) card_found = cg14 = cg14_present (); if (!card_found){ - prom_printf ("Searching for a creator\n"); card_found = creator = creator_present (); } if (!card_found){ @@ -1172,7 +1175,7 @@ if (creator){ sparc_framebuffer_setup (!sbdprom, creator, FBTYPE_CREATOR, 0, 0, 0, prom_console_node == creator, - prom_getchild (prom_root_node)); + prom_root_node); } break; default: @@ -1654,11 +1657,10 @@ return -EINVAL; if ((uint) f.size.fby > fb->cursor.hwsize.fby) return -EINVAL; - bytes = (f.size.fby * 32)/8; - i = verify_area (VERIFY_READ, f.image, bytes); - if (i) return i; - i = verify_area (VERIFY_READ, f.mask, bytes); - if (i) return i; + if (f.size.fbx > 32) + bytes = f.size.fby << 3; + else + bytes = f.size.fby << 2; } if (op & FB_CUR_SETCMAP){ if (f.cmap.index || f.cmap.count != 2) @@ -1668,15 +1670,6 @@ copy_from_user (blue, f.cmap.blue, 2)) return -EFAULT; } - if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){ - if (op & FB_CUR_SETCUR) - fb->cursor.enable = f.enable; - if (op & FB_CUR_SETPOS) - fb->cursor.cpos = f.pos; - if (op & FB_CUR_SETHOT) - fb->cursor.chot = f.hot; - (*fb->setcursor) (fb); - } if (op & FB_CUR_SETCMAP) (*fb->setcursormap) (fb, red, green, blue); if (op & FB_CUR_SETSHAPE){ @@ -1687,14 +1680,30 @@ if (copy_from_user (fb->cursor.bits [0], f.mask, bytes) || copy_from_user (fb->cursor.bits [1], f.image, bytes)) return -EFAULT; - u = ~0; - if (f.size.fbx < fb->cursor.hwsize.fbx) - u = ~(u >> f.size.fbx); - for (i = fb->cursor.size.fby - 1; i >= 0; i--) { - fb->cursor.bits [0][i] &= u; - fb->cursor.bits [1][i] &= fb->cursor.bits [0][i]; + if (f.size.fbx <= 32) { + u = ~(0xffffffff >> f.size.fbx); + for (i = fb->cursor.size.fby - 1; i >= 0; i--) { + fb->cursor.bits [0][i] &= u; + fb->cursor.bits [1][i] &= fb->cursor.bits [0][i]; + } + } else { + u = ~(0xffffffff >> (f.size.fbx - 32)); + for (i = fb->cursor.size.fby - 1; i >= 0; i--) { + fb->cursor.bits [0][2*i+1] &= u; + fb->cursor.bits [1][2*i] &= fb->cursor.bits [0][2*i]; + fb->cursor.bits [1][2*i+1] &= fb->cursor.bits [0][2*i+1]; + } } (*fb->setcurshape) (fb); + } + if (op & (FB_CUR_SETCUR | FB_CUR_SETPOS | FB_CUR_SETHOT)){ + if (op & FB_CUR_SETCUR) + fb->cursor.enable = f.enable; + if (op & FB_CUR_SETPOS) + fb->cursor.cpos = f.pos; + if (op & FB_CUR_SETHOT) + fb->cursor.chot = f.hot; + (*fb->setcursor) (fb); } return 0; } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/sunfb.c linux/drivers/sbus/char/sunfb.c --- v2.1.44/linux/drivers/sbus/char/sunfb.c Mon Jul 7 08:18:55 1997 +++ linux/drivers/sbus/char/sunfb.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: sunfb.c,v 1.25 1997/07/01 09:12:06 jj Exp $ +/* $Id: sunfb.c,v 1.26 1997/07/17 02:21:48 davem Exp $ * sunfb.c: Sun generic frame buffer support. * * Copyright (C) 1995, 1996 Miguel de Icaza (miguel@nuclecu.unam.mx) @@ -275,7 +275,8 @@ int v; v = (*fb->mmap)(inode, file, vma, fb->base, fb); - if (v) return v; + if (v) + return v; vma->vm_flags |= VM_IO; if (!fb->mmaped) { fb->mmaped = 1; diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/sunserial.h linux/drivers/sbus/char/sunserial.h --- v2.1.44/linux/drivers/sbus/char/sunserial.h Mon Apr 14 16:28:14 1997 +++ linux/drivers/sbus/char/sunserial.h Wed Jul 16 19:22:51 1997 @@ -1,4 +1,4 @@ -/* $Id: sunserial.h,v 1.9 1997/04/12 23:33:12 ecd Exp $ +/* $Id: sunserial.h,v 1.11 1997/07/08 10:17:23 davem Exp $ * serial.h: Definitions for the Sparc Zilog serial driver. * * Copyright (C) 1995 David S. Miller (davem@caip.rutgers.edu) diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/tcx.c linux/drivers/sbus/char/tcx.c --- v2.1.44/linux/drivers/sbus/char/tcx.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/tcx.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: tcx.c,v 1.16 1997/06/06 10:56:31 jj Exp $ +/* $Id: tcx.c,v 1.17 1997/07/17 02:21:50 davem Exp $ * tcx.c: SUNW,tcx 24/8bit frame buffer driver * * Copyright (C) 1996 Jakub Jelinek (jj@sunsite.mff.cuni.cz) @@ -169,11 +169,12 @@ map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; + if (r) + return -EAGAIN; page += map_size; } - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + + vma->vm_dentry = dget(file->f_dentry); return 0; } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/vfc_dev.c linux/drivers/sbus/char/vfc_dev.c --- v2.1.44/linux/drivers/sbus/char/vfc_dev.c Mon Jun 16 16:35:56 1997 +++ linux/drivers/sbus/char/vfc_dev.c Wed Jul 16 19:22:51 1997 @@ -577,11 +577,12 @@ if(vma->vm_offset & ~PAGE_MASK) return -ENXIO; vma->vm_flags |= VM_SHM | VM_LOCKED | VM_IO | VM_MAYREAD | VM_MAYWRITE | VM_MAYSHARE; map_offset=(unsigned int)dev->phys_regs; - ret=io_remap_page_range(vma->vm_start,map_offset,map_size, - vma->vm_page_prot, dev->which_io); - if(ret) return -EAGAIN; - vma->vm_inode=inode; - atomic_inc(&inode->i_count); + ret = io_remap_page_range(vma->vm_start,map_offset,map_size, + vma->vm_page_prot, dev->which_io); + if(ret) + return -EAGAIN; + + vma->vm_dentry = dget(file->f_dentry); return 0; } diff -u --recursive --new-file v2.1.44/linux/drivers/sbus/char/weitek.c linux/drivers/sbus/char/weitek.c --- v2.1.44/linux/drivers/sbus/char/weitek.c Thu Jun 26 12:33:39 1997 +++ linux/drivers/sbus/char/weitek.c Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: weitek.c,v 1.13 1997/06/06 10:56:31 jj Exp $ +/* $Id: weitek.c,v 1.14 1997/07/17 02:21:53 davem Exp $ * weitek.c: Tadpole P9100/P9000 console driver * * Copyright (C) 1996 David Redman (djhr@tadpole.co.uk) @@ -79,11 +79,12 @@ map_offset, map_size, vma->vm_page_prot, fb->space); - if (r) return -EAGAIN; + if (r) + return -EAGAIN; page += map_size; } - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + + vma->vm_dentry = dget(file->f_dentry); return 0; } #endif diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/BusLogic.h linux/drivers/scsi/BusLogic.h --- v2.1.44/linux/drivers/scsi/BusLogic.h Mon Jul 7 16:02:51 1997 +++ linux/drivers/scsi/BusLogic.h Wed Jul 16 20:17:12 1997 @@ -29,6 +29,7 @@ #include + /* Define types for some of the structures that interface with the rest of the Linux Kernel and SCSI Subsystem. diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/advansys.h linux/drivers/scsi/advansys.h --- v2.1.44/linux/drivers/scsi/advansys.h Mon Jul 7 16:02:51 1997 +++ linux/drivers/scsi/advansys.h Wed Jul 16 20:37:21 1997 @@ -1,4 +1,4 @@ -/* $Id: advansys.h,v 1997/05/28 00:23:06 bobf Exp bobf $ */ +/* $Id: advansys.h,v 1.6 1997/05/30 19:25:12 davem Exp $ */ /* * advansys.h - Linux Host Driver for AdvanSys SCSI Adapters diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/qlogicpti.c linux/drivers/scsi/qlogicpti.c --- v2.1.44/linux/drivers/scsi/qlogicpti.c Thu May 29 21:53:08 1997 +++ linux/drivers/scsi/qlogicpti.c Wed Jul 16 19:22:51 1997 @@ -653,7 +653,7 @@ } qpti_host->base = (unsigned char *)qregs; - qpti_host->io_port = (unsigned int) qregs; + qpti_host->io_port = (unsigned int) ((unsigned long)qregs); qpti_host->n_io_port = (unsigned char) qpti->qdev->reg_addrs[0].reg_size; @@ -805,7 +805,7 @@ memset(cmd, 0, sizeof(struct Command_Entry)); cmd->hdr.entry_cnt = 1; cmd->hdr.entry_type = ENTRY_COMMAND; - cmd->handle = (u_int) Cmnd; /* magic mushroom */ + cmd->handle = (u_int) ((unsigned long)Cmnd); /* magic mushroom */ cmd->target_id = Cmnd->target; cmd->target_lun = Cmnd->lun; cmd->cdb_length = Cmnd->cmd_len; @@ -890,7 +890,7 @@ Cmnd->request_bufflen, qpti->qdev->my_bus)); - cmd->dataseg[0].d_base = (u_int) Cmnd->SCp.ptr; + cmd->dataseg[0].d_base = (u_int) ((unsigned long)Cmnd->SCp.ptr); cmd->dataseg[0].d_count = Cmnd->request_bufflen; cmd->segment_cnt = 1; } @@ -1062,7 +1062,7 @@ while(out_ptr != in_ptr) { sts = (struct Status_Entry *) &qpti->res_cpu[out_ptr]; out_ptr = NEXT_RES_PTR(out_ptr); - Cmnd = (Scsi_Cmnd *) sts->handle; /* but_to_virt?!?! */ + Cmnd = (Scsi_Cmnd *) ((unsigned long)sts->handle); if(sts->completion_status == CS_RESET_OCCURRED || sts->completion_status == CS_ABORTED || (sts->status_flags & STF_BUS_RESET)) @@ -1111,8 +1111,8 @@ qlogicpti_disable_irqs(qpti->qregs); param[0] = MBOX_ABORT; param[1] = (((u_short) Cmnd->target) << 8) | Cmnd->lun; - param[2] = ((unsigned int)Cmnd) >> 16; - param[3] = ((unsigned int)Cmnd) & 0xffff; + param[2] = ((unsigned int)((unsigned long)Cmnd)) >> 16; + param[3] = ((unsigned int)((unsigned long)Cmnd)) & 0xffff; if(qlogicpti_mbox_command(qpti, param, 0) || (param[0] != MBOX_COMMAND_COMPLETE)) { printk(KERN_EMERG "qlogicpti : scsi abort failure: %x\n", param[0]); diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/scsi.c linux/drivers/scsi/scsi.c --- v2.1.44/linux/drivers/scsi/scsi.c Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/scsi.c Wed Jul 16 19:22:51 1997 @@ -12,6 +12,7 @@ * Rik Faith * Tommy Thorn * Thomas Wuensche + * Andrea Arcangeli * * Modified by Eric Youngdale eric@aib.com to * add scatter-gather, multiple outstanding request, and other @@ -3508,6 +3509,7 @@ void cleanup_module( void) { + timer_active &= ~(1 << SCSI_TIMER); #if CONFIG_PROC_FS proc_scsi_unregister(0, PROC_SCSI_SCSI); diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/sg.c linux/drivers/scsi/sg.c --- v2.1.44/linux/drivers/scsi/sg.c Fri Apr 4 08:52:23 1997 +++ linux/drivers/scsi/sg.c Mon Jul 14 11:33:25 1997 @@ -488,7 +488,7 @@ static unsigned int sg_poll(struct file *file, poll_table * wait) { - int dev = MINOR(file->f_inode->i_rdev); + int dev = MINOR(file->f_dentry->d_inode->i_rdev); struct scsi_generic *device = &scsi_generics[dev]; unsigned int mask = 0; diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/tmscsim.c linux/drivers/scsi/tmscsim.c --- v2.1.44/linux/drivers/scsi/tmscsim.c Tue May 13 22:41:13 1997 +++ linux/drivers/scsi/tmscsim.c Thu Jul 10 07:55:30 1997 @@ -50,13 +50,8 @@ #include #include #include - -#include -#if LINUX_VERSION_CODE < 66354 /* 1.3.50 */ -#include "../block/blk.h" -#else +#include #include -#endif #include "scsi.h" #include "hosts.h" @@ -69,13 +64,10 @@ #define PCI_DEVICE_ID_AMD53C974 PCI_DEVICE_ID_AMD_SCSI - -#ifndef VERSION_ELF_1_2_13 struct proc_dir_entry proc_scsi_tmscsim ={ PROC_SCSI_DC390T, 7 ,"tmscsim", S_IFDIR | S_IRUGO | S_IXUGO, 2 }; -#endif static USHORT DC390_StartSCSI( PACB pACB, PDCB pDCB, PSRB pSRB ); static void DC390_DataOut_0( PACB pACB, PSRB pSRB, PUCHAR psstatus); @@ -675,11 +667,7 @@ * Description: * Return the disk geometry for the given SCSI device. ***********************************************************************/ -#ifdef VERSION_ELF_1_2_13 -int DC390_bios_param(Disk *disk, int devno, int geom[]) -#else int DC390_bios_param(Disk *disk, kdev_t devno, int geom[]) -#endif { int heads, sectors, cylinders; PACB pACB; @@ -1046,14 +1034,10 @@ ***********************************************************************/ void DC390_initSRB( PSRB psrb ) { -#ifndef VERSION_ELF_1_2_13 #ifdef DC390_DEBUG0 printk("DC390 init: %08lx %08lx,",(ULONG)psrb,(ULONG)virt_to_bus(psrb)); #endif psrb->PhysSRB = virt_to_bus( psrb ); -#else - psrb->PhysSRB = (ULONG) psrb; -#endif } @@ -1084,7 +1068,7 @@ * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ -void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ) +__initfunc(void DC390_initACB( PSH psh, ULONG io_port, UCHAR Irq, USHORT index )) { PACB pACB; USHORT i; @@ -1098,7 +1082,6 @@ pACB = (PACB) psh->hostdata; -#ifndef VERSION_ELF_1_2_13 psh->max_id = 8; #ifdef CONFIG_SCSI_MULTI_LUN if( eepromBuf[index][EE_MODE2] & LUN_CHECK ) @@ -1106,7 +1089,6 @@ else #endif psh->max_lun = 1; -#endif pACB->max_id = 7; if( pACB->max_id == eepromBuf[index][EE_ADAPT_SCSI_ID] ) @@ -1155,7 +1137,7 @@ * Inputs : psh - pointer to this host adapter's structure * ***********************************************************************/ -int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index ) +__initfunc(int DC390_initAdapter( PSH psh, ULONG io_port, UCHAR Irq, USHORT index)) { USHORT ioport; UCHAR bval; @@ -1179,11 +1161,7 @@ if( !used_irq ) { -#ifdef VERSION_ELF_1_2_13 - if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim")) -#else if( request_irq(Irq, DC390_Interrupt, SA_INTERRUPT, "tmscsim", NULL)) -#endif { printk("DC390: register IRQ error!\n"); return( -1 ); @@ -1533,8 +1511,8 @@ * field of the pACB structure MUST have been set. ***********************************************************************/ -static int -DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum) +__initfunc(static int +DC390_init (PSHT psht, ULONG io_port, UCHAR Irq, USHORT index, USHORT MechNum)) { PSH psh; PACB pACB; @@ -1614,8 +1592,8 @@ * ***********************************************************************/ -int -DC390_detect(Scsi_Host_Template *psht) +__initfunc(int +DC390_detect(Scsi_Host_Template *psht)) { #ifdef FOR_PCI_OK UCHAR pci_bus, pci_device_fn; @@ -1626,19 +1604,13 @@ UCHAR irq; UCHAR istatus; -#ifndef VERSION_ELF_1_2_13 UINT io_port; -#else - ULONG io_port; -#endif USHORT adaptCnt = 0; /* Number of boards detected */ USHORT pci_index = 0; /* Device index to PCI BIOS calls */ USHORT MechNum, BusDevFunNum; ULONG wlval; -#ifndef VERSION_ELF_1_2_13 psht->proc_dir = &proc_scsi_tmscsim; -#endif InitialTime = 1; pSHT_start = psht; @@ -1726,8 +1698,6 @@ } -#ifndef VERSION_ELF_1_2_13 - /******************************************************************** * Function: tmscsim_set_info() * @@ -1848,7 +1818,6 @@ else return length; } -#endif /* VERSION_ELF_1_2_13 */ #ifdef MODULE @@ -1909,11 +1878,7 @@ #ifdef DC390_DEBUG0 printk("DC390: Free IRQ %i.",host->irq); #endif -#ifndef VERSION_ELF_1_2_13 free_irq(host->irq,NULL); -#else - free_irq(host->irq); -#endif } } diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/wd33c93.c linux/drivers/scsi/wd33c93.c --- v2.1.44/linux/drivers/scsi/wd33c93.c Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/wd33c93.c Wed Jul 16 19:22:51 1997 @@ -87,8 +87,9 @@ #include "hosts.h" -#define WD33C93_VERSION "1.24" -#define WD33C93_DATE "29/Jan/1997" +#define WD33C93_VERSION "1.25" +#define WD33C93_DATE "09/Jul/1997" +/* NOTE: 1.25 for m68k is related to in2000-1.31 for x86 */ /* * Note - the following defines have been moved to 'wd33c93.h': @@ -107,11 +108,14 @@ /* - * 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: + * 'setup_strings' is a single string used to pass operating parameters and + * settings from the kernel/module command-line to the driver. 'setup_args[]' + * is an array of strings that define the compile-time default values for + * these settings. If Linux boots with an amiboot or insmod command-line, + * those settings are combined with 'setup_args[]'. Note that amiboot + * command-lines are prefixed with "wd33c93=" while insmod uses a + * "setup_strings=" prefix. 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 negotiate for @@ -139,13 +143,11 @@ * _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. + * command-line manner. * - A keyword in the 'nth' comma-separated command-line member will overwrite - * the 'nth' element of setup_strings[]. A blank command-line member (in + * the 'nth' element of setup_args[]. A blank command-line member (in * other words, a comma with no preceding keyword) will _not_ overwrite - * the corresponding setup_strings[] element. + * the corresponding setup_args[] 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. @@ -158,8 +160,16 @@ * - wd33c93=debug:0x1c */ -static char *setup_strings[] = - {"","","","","","","","","","","",""}; +/* Normally, no defaults are specified */ +static char *setup_args[] = + {"","","","","","","","",""}; + +/* filled in by 'insmod' */ +static char *setup_strings = 0; + +#ifdef MODULE_PARM +MODULE_PARM(setup_strings, "s"); +#endif @@ -337,9 +347,24 @@ cmd->SCp.this_residual = cmd->request_bufflen; } -/* Preset the command status to GOOD, since that's the normal case */ +/* WD docs state that at the conclusion of a "LEVEL2" command, the + * status byte can be retrieved from the LUN register. Apparently, + * this is the case only for *uninterrupted* LEVEL2 commands! If + * there are any unexpected phases entered, even if they are 100% + * legal (different devices may choose to do things differently), + * the LEVEL2 command sequence is exited. This often occurs prior + * to receiving the status byte, in which case the driver does a + * status phase interrupt and gets the status byte on its own. + * While such a command can then be "resumed" (ie restarted to + * finish up as a LEVEL2 command), the LUN register will NOT be + * a valid status byte at the command's conclusion, and we must + * use the byte obtained during the earlier interrupt. Here, we + * preset SCp.Status to an illegal value (0xff) so that when + * this command finally completes, we can tell where the actual + * status byte is stored. + */ - cmd->SCp.Status = GOOD; + cmd->SCp.Status = ILLEGAL_STATUS_BYTE; /* * Add the cmd to the end of 'input_Q'. Note that REQUEST SENSE @@ -701,7 +726,8 @@ write_wd33c93(regp, WD_CONTROL, CTRL_IDI | CTRL_EDI | CTRL_DMA); write_wd33c93_count(regp,cmd->SCp.this_residual); - if ((hostdata->level2 >= L2_DATA) || (cmd->SCp.phase == 0)) { + if ((hostdata->level2 >= L2_DATA) || + (hostdata->level2 == L2_BASIC && 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; @@ -786,17 +812,17 @@ hostdata->state = S_UNCONNECTED; cmd->scsi_done(cmd); - /* From esp.c: - * There is a window of time within the scsi_done() path - * of execution where interrupts are turned back on full - * blast and left that way. During that time we could - * reconnect to a disconnected command, then we'd bomb - * out below. We could also end up executing two commands - * at _once_. ...just so you know why the restore_flags() - * is here... - */ + /* From esp.c: + * There is a window of time within the scsi_done() path + * of execution where interrupts are turned back on full + * blast and left that way. During that time we could + * reconnect to a disconnected command, then we'd bomb + * out below. We could also end up executing two commands + * at _once_. ...just so you know why the restore_flags() + * is here... + */ - restore_flags(flags); + restore_flags(flags); /* We are not connected to a target - check to see if there * are commands waiting to be executed. @@ -887,9 +913,10 @@ case CSR_XFER_DONE|PHS_STATUS: case CSR_UNEXP |PHS_STATUS: case CSR_SRV_REQ |PHS_STATUS: -DB(DB_INTR,printk("STATUS")) +DB(DB_INTR,printk("STATUS=")) cmd->SCp.Status = read_1_byte(regp); +DB(DB_INTR,printk("%02x",cmd->SCp.Status)) if (hostdata->level2 >= L2_BASIC) { sr = read_wd33c93(regp, WD_SCSI_STATUS); /* clear interrupt */ hostdata->state = S_RUNNING_LEVEL2; @@ -897,7 +924,6 @@ write_wd33c93_cmd(regp, WD_CMD_SEL_ATN_XFER); } else { -DB(DB_INTR,printk("=%02x",cmd->SCp.Status)) hostdata->state = S_CONNECTED; } break; @@ -1067,21 +1093,22 @@ DB(DB_INTR,printk("SX-DONE-%ld",cmd->pid)) cmd->SCp.Message = COMMAND_COMPLETE; lun = read_wd33c93(regp, WD_TARGET_LUN); - if (cmd->SCp.Status == GOOD) - cmd->SCp.Status = lun; +DB(DB_INTR,printk(":%d.%d",cmd->SCp.Status,lun)) hostdata->connected = NULL; - 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); hostdata->busy[cmd->target] &= ~(1 << cmd->lun); hostdata->state = S_UNCONNECTED; + if (cmd->SCp.Status == ILLEGAL_STATUS_BYTE) + cmd->SCp.Status = lun; + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) + cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + else + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); /* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ - restore_flags(flags); + restore_flags(flags); wd33c93_execute(instance); } else { @@ -1154,17 +1181,17 @@ 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) + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + else + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); /* We are no longer connected to a target - check to see if * there are commands waiting to be executed. */ - /* look above for comments on scsi_done() */ - restore_flags(flags); + /* look above for comments on scsi_done() */ + restore_flags(flags); wd33c93_execute(instance); break; @@ -1186,12 +1213,13 @@ 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) +DB(DB_INTR,printk(":%d",cmd->SCp.Status)) + if (cmd->cmnd[0] == REQUEST_SENSE && cmd->SCp.Status != GOOD) cmd->result = (cmd->result & 0x00ffff) | (DID_ERROR << 16); + else + cmd->result = cmd->SCp.Status | (cmd->SCp.Message << 8); cmd->scsi_done(cmd); - restore_flags(flags); + restore_flags(flags); break; case S_PRE_TMP_DISC: case S_RUNNING_LEVEL2: @@ -1433,7 +1461,7 @@ cmd->result = DID_ABORT << 16; printk("scsi%d: Abort - removing command %ld from input_Q. ", instance->host_no, cmd->pid); - enable_irq(cmd->host->irq); + enable_irq(cmd->host->irq); cmd->scsi_done(cmd); return SCSI_ABORT_SUCCESS; } @@ -1523,7 +1551,7 @@ printk("scsi%d: Abort - command %ld found on disconnected_Q - ", instance->host_no, cmd->pid); printk("returning ABORT_SNOOZE. "); - enable_irq(cmd->host->irq); + enable_irq(cmd->host->irq); return SCSI_ABORT_SNOOZE; } tmp = (Scsi_Cmnd *)tmp->host_scribble; @@ -1551,10 +1579,11 @@ #define MAX_WD33C93_HOSTS 4 -#define MAX_SETUP_STRINGS (sizeof(setup_strings) / sizeof(char *)) +#define MAX_SETUP_ARGS (sizeof(setup_args) / sizeof(char *)) #define SETUP_BUFFER_SIZE 200 static char setup_buffer[SETUP_BUFFER_SIZE]; -static char setup_used[MAX_SETUP_STRINGS]; +static char setup_used[MAX_SETUP_ARGS]; +static int done_setup = 0; void wd33c93_setup (char *str, int *ints) { @@ -1583,45 +1612,46 @@ setup_buffer[SETUP_BUFFER_SIZE - 1] = '\0'; p1 = setup_buffer; i = 0; - while (*p1 && (i < MAX_SETUP_STRINGS)) { + while (*p1 && (i < MAX_SETUP_ARGS)) { p2 = strchr(p1, ','); if (p2) { *p2 = '\0'; if (p1 != p2) - setup_strings[i] = p1; + setup_args[i] = p1; p1 = p2 + 1; i++; } else { - setup_strings[i] = p1; + setup_args[i] = p1; break; } } - for (i=0; ihostdata; hostdata->regp = regs; @@ -1688,26 +1721,29 @@ #endif - if (check_setup_strings("nosync",&flags,&val,buf)) + if (check_setup_args("nosync",&flags,&val,buf)) hostdata->no_sync = val; - if (check_setup_strings("nodma",&flags,&val,buf)) + if (check_setup_args("nodma",&flags,&val,buf)) hostdata->no_dma = (val == -1) ? 1 : val; - if (check_setup_strings("period",&flags,&val,buf)) + if (check_setup_args("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 (check_setup_args("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)) + if (check_setup_args("level2",&flags,&val,buf)) + hostdata->level2 = val; + + if (check_setup_args("debug",&flags,&val,buf)) hostdata->args = val & DB_MASK; - if (check_setup_strings("clock",&flags,&val,buf)) { + if (check_setup_args("clock",&flags,&val,buf)) { if (val>7 && val<11) val = WD33C93_FS_8_10; else if (val>11 && val<16) @@ -1719,13 +1755,13 @@ hostdata->clock_freq = val; } - if ((i = check_setup_strings("next",&flags,&val,buf))) { + if ((i = check_setup_args("next",&flags,&val,buf))) { while (i) setup_used[--i] = 1; } #ifdef PROC_INTERFACE - if (check_setup_strings("proc",&flags,&val,buf)) + if (check_setup_args("proc",&flags,&val,buf)) hostdata->proc = val; #endif @@ -1744,9 +1780,9 @@ #else printk(" debugging=OFF\n"); #endif - printk(" setup_strings="); - for (i=0; ino_dma = simple_strtoul(bp,NULL,0); } + else if (!strncmp(bp,"level2:",7)) { + bp += 7; + hd->level2 = simple_strtoul(bp,NULL,0); + } return len; } @@ -1838,32 +1878,32 @@ sprintf(tbuf,"\nclock_freq=%02x no_sync=%02x no_dma=%d", hd->clock_freq,hd->no_sync,hd->no_dma); strcat(bp,tbuf); - strcat(bp,"\nsync_xfer[] ="); - for (x=0; x<8; x++) { - sprintf(tbuf," %02x",hd->sync_xfer[x]); + strcat(bp,"\nsync_xfer[] = "); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%02x",hd->sync_xfer[x]); strcat(bp,tbuf); } - strcat(bp,"\nsync_stat[] ="); - for (x=0; x<8; x++) { - sprintf(tbuf," %02x",hd->sync_stat[x]); + strcat(bp,"\nsync_stat[] = "); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%02x",hd->sync_stat[x]); strcat(bp,tbuf); } } #ifdef PROC_STATISTICS if (hd->proc & PR_STATISTICS) { strcat(bp,"\ncommands issued: "); - for (x=0; x<8; x++) { - sprintf(tbuf," %ld",hd->cmd_cnt[x]); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%ld",hd->cmd_cnt[x]); strcat(bp,tbuf); } strcat(bp,"\ndisconnects allowed:"); - for (x=0; x<8; x++) { - sprintf(tbuf," %ld",hd->disc_allowed_cnt[x]); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%ld",hd->disc_allowed_cnt[x]); strcat(bp,tbuf); } strcat(bp,"\ndisconnects done: "); - for (x=0; x<8; x++) { - sprintf(tbuf," %ld",hd->disc_done_cnt[x]); + for (x=0; x<7; x++) { + sprintf(tbuf,"\t%ld",hd->disc_done_cnt[x]); strcat(bp,tbuf); } sprintf(tbuf,"\ninterrupts: %ld, DATA_PHASE ints: %ld DMA, %ld PIO", diff -u --recursive --new-file v2.1.44/linux/drivers/scsi/wd33c93.h linux/drivers/scsi/wd33c93.h --- v2.1.44/linux/drivers/scsi/wd33c93.h Wed Apr 23 19:01:22 1997 +++ linux/drivers/scsi/wd33c93.h Wed Jul 16 19:22:51 1997 @@ -2,7 +2,7 @@ * wd33c93.h - Linux device driver definitions for the * Commodore Amiga A2091/590 SCSI controller card * - * IMPORTANT: This file is for version 1.24 - 29/Jan/1997 + * IMPORTANT: This file is for version 1.25 - 09/Jul/1997 * * Copyright (c) 1996 John Shifflett, GeoLog Consulting * john@geolog.com @@ -198,6 +198,8 @@ typedef void (*dma_stop_t) (struct Scsi_Host *instance, Scsi_Cmnd *SCpnt, int status); + +#define ILLEGAL_STATUS_BYTE 0xff #define DEFAULT_SX_PER 376 /* (ns) fairly safe */ #define DEFAULT_SX_OFF 0 /* aka async */ diff -u --recursive --new-file v2.1.44/linux/drivers/sound/Config.in linux/drivers/sound/Config.in --- v2.1.44/linux/drivers/sound/Config.in Wed May 28 10:51:32 1997 +++ linux/drivers/sound/Config.in Wed Jul 16 19:22:51 1997 @@ -1,15 +1,277 @@ -# -# Sound driver configuration -# -#-------- -# There is another confic script which is compatible with rest of -# the kernel. It can be activated by running 'make mkscript' in this -# directory. Please note that this is an _experimental_ feature which -# doesn't work with all cards (PSS, SM Wave, AudioTriX Pro, Maui). -#-------- -# -$MAKE -C drivers/sound config || exit 1 +bool 'ProAudioSpectrum 16 support' CONFIG_PAS +bool '100%% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support' CONFIG_SB +bool 'Generic OPL2/OPL3 FM synthesizer support' CONFIG_ADLIB +bool 'Gravis Ultrasound support' CONFIG_GUS +bool 'MPU-401 support (NOT for SB16)' CONFIG_MPU401 +bool 'PSS (ECHO-ADI2111) support' CONFIG_PSS +bool '16 bit sampling option of GUS (_NOT_ GUS MAX)' CONFIG_GUS16 +bool 'GUS MAX support' CONFIG_GUSMAX +bool 'Microsoft Sound System support' CONFIG_MSS +bool 'Ensoniq SoundScape support' CONFIG_SSCAPE +bool 'MediaTrix AudioTrix Pro support' CONFIG_TRIX +bool 'Support for MAD16 and/or Mozart based cards' CONFIG_MAD16 +bool 'Support for Crystal CS4232 based (PnP) cards' CONFIG_CS4232 +bool 'Support for Turtle Beach Wave Front (Maui, Tropez) synthesizers' CONFIG_MAUI +bool 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 + +if [ "$CONFIG_AEDSP16" = "y" ]; then +hex 'I/O base for Audio Excel DSP 16 220 or 240' AEDSP16_BASE 220 +fi + +if [ "$CONFIG_SB" = "y" ]; then +hex 'I/O base for SB Check from manual of the card' SBC_BASE 220 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'Sound Blaster IRQ Check from manual of the card' SBC_IRQ 7 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'Sound Blaster DMA 0, 1 or 3' SBC_DMA 1 +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'Sound Blaster 16 bit DMA (SB16, Jazz16, SMW) 5, 6 or 7 (use 1 for 8 bit cards)' SB_DMA2 5 +fi + +if [ "$CONFIG_SB" = "y" ]; then +hex 'MPU401 I/O base of SB16, Jazz16 and ES1688 Check from manual of the card' SB_MPU_BASE 330 +fi + + +if [ "$CONFIG_SB" = "y" ]; then +comment 'MPU401 IRQ is only required with Jazz16, SM Wave and ESS1688.' +fi + + +if [ "$CONFIG_SB" = "y" ]; then +comment 'Enter -1 to the following question if you have something else such as SB16/32.' +fi + +if [ "$CONFIG_SB" = "y" ]; then +int 'SB MPU401 IRQ (Jazz16, SM Wave and ES1688) Check from manual of the card' SB_MPU_IRQ -1 +fi + +if [ "$CONFIG_PAS" = "y" ]; then +int 'PAS16 IRQ 3, 4, 5, 7, 9, 10, 11, 12, 14 or 15' PAS_IRQ 10 +fi + +if [ "$CONFIG_PAS" = "y" ]; then +int 'PAS16 DMA 0, 1, 3, 5, 6 or 7' PAS_DMA 3 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +hex 'I/O base for GUS 210, 220, 230, 240, 250 or 260' GUS_BASE 220 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +int 'GUS IRQ 3, 5, 7, 9, 11, 12 or 15' GUS_IRQ 15 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +int 'GUS DMA 1, 3, 5, 6 or 7' GUS_DMA 6 +fi + +if [ "$CONFIG_GUS" = "y" ]; then +int 'Second DMA channel for GUS 1, 3, 5, 6 or 7' GUS_DMA2 -1 +fi + +if [ "$CONFIG_GUS16" = "y" ]; then +hex 'I/O base for the 16 bit daughtercard of GUS 530, 604, E80 or F40' GUS16_BASE 530 +fi + +if [ "$CONFIG_GUS16" = "y" ]; then +int 'GUS 16 bit daughtercard IRQ 3, 4, 5, 7, or 9' GUS16_IRQ 7 +fi + +if [ "$CONFIG_GUS16" = "y" ]; then +int 'GUS DMA 0, 1 or 3' GUS16_DMA 3 +fi + +if [ "$CONFIG_MPU401" = "y" ]; then +hex 'I/O base for MPU401 Check from manual of the card' MPU_BASE 330 +fi + +if [ "$CONFIG_MPU401" = "y" ]; then +int 'MPU401 IRQ Check from manual of the card' MPU_IRQ 9 +fi + + +if [ "$CONFIG_MAUI" = "y" ]; then +comment 'ERROR! You have to use old sound configuration method with Maui.' +fi + +if [ "$CONFIG_MAUI" = "y" ]; then +hex 'I/O base for Maui 210, 230, 260, 290, 300, 320, 338 or 330' MAUI_BASE 330 +fi + +if [ "$CONFIG_MAUI" = "y" ]; then +int 'Maui IRQ 5, 9, 12 or 15' MAUI_IRQ 9 +fi + +if [ "$CONFIG_UART6850" = "y" ]; then +hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0 +fi + +if [ "$CONFIG_UART6850" = "y" ]; then +int 'UART6850 IRQ (Unknown)' U6850_IRQ -1 +fi + + +if [ "$CONFIG_PSS" = "y" ]; then +comment 'ERROR! You have to use old sound configuration method with PSS cards.' +fi + +if [ "$CONFIG_PSS" = "y" ]; then +hex 'PSS I/O base 220 or 240' PSS_BASE 220 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +hex 'PSS audio I/O base 530, 604, E80 or F40' PSS_MSS_BASE 530 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +int 'PSS audio IRQ 7, 9, 10 or 11' PSS_MSS_IRQ 11 +fi +if [ "$CONFIG_PSS" = "y" ]; then +int 'PSS audio DMA 0, 1 or 3' PSS_MSS_DMA 3 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +hex 'PSS MIDI I/O base ' PSS_MPU_BASE 330 +fi + +if [ "$CONFIG_PSS" = "y" ]; then +int 'PSS MIDI IRQ 3, 4, 5, 7 or 9' PSS_MPU_IRQ 9 +fi + +if [ "$CONFIG_MSS" = "y" ]; then +hex 'MSS/WSS I/O base 530, 604, E80 or F40' MSS_BASE 530 +fi + +if [ "$CONFIG_MSS" = "y" ]; then +int 'MSS/WSS IRQ 7, 9, 10 or 11' MSS_IRQ 11 +fi + +if [ "$CONFIG_MSS" = "y" ]; then +int 'MSS/WSS DMA 0, 1 or 3' MSS_DMA 3 +fi + +if [ "$CONFIG_MSS" = "y" ]; then +int 'MSS/WSS second DMA (if possible) 0, 1 or 3' MSS_DMA2 -1 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +hex 'SoundScape MIDI I/O base 320, 330, 340 or 350' SSCAPE_BASE 330 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +int 'SoundScape MIDI IRQ ' SSCAPE_IRQ 9 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +int 'SoundScape initialization DMA 0, 1 or 3' SSCAPE_DMA 3 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +hex 'SoundScape audio I/O base 534, 608, E84 or F44' SSCAPE_MSS_BASE 534 +fi + +if [ "$CONFIG_SSCAPE" = "y" ]; then +int 'SoundScape audio IRQ 7, 9, 10 or 11' SSCAPE_MSS_IRQ 11 +fi + + +if [ "$CONFIG_TRIX" = "y" ]; then +comment 'ERROR! You have to use old sound configuration method with AudioTrix.' +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +hex 'AudioTrix audio I/O base 530, 604, E80 or F40' TRIX_BASE 530 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix audio IRQ 7, 9, 10 or 11' TRIX_IRQ 11 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix audio DMA 0, 1 or 3' TRIX_DMA 0 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix second (duplex) DMA 0, 1 or 3' TRIX_DMA2 3 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +hex 'AudioTrix MIDI I/O base 330, 370, 3B0 or 3F0' TRIX_MPU_BASE 330 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix MIDI IRQ 3, 4, 5, 7 or 9' TRIX_MPU_IRQ 9 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +hex 'AudioTrix SB I/O base 220, 210, 230, 240, 250, 260 or 270' TRIX_SB_BASE 220 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix SB IRQ 3, 4, 5 or 7' TRIX_SB_IRQ 7 +fi + +if [ "$CONFIG_TRIX" = "y" ]; then +int 'AudioTrix SB DMA 1 or 3' TRIX_SB_DMA 1 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +hex 'CS4232 audio I/O base 530, 604, E80 or F40' CS4232_BASE 530 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 audio IRQ 5, 7, 9, 11, 12 or 15' CS4232_IRQ 11 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 audio DMA 0, 1 or 3' CS4232_DMA 0 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 second (duplex) DMA 0, 1 or 3' CS4232_DMA2 3 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +hex 'CS4232 MIDI I/O base 330, 370, 3B0 or 3F0' CS4232_MPU_BASE 330 +fi + +if [ "$CONFIG_CS4232" = "y" ]; then +int 'CS4232 MIDI IRQ 5, 7, 9, 11, 12 or 15' CS4232_MPU_IRQ 9 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +hex 'MAD16 audio I/O base 530, 604, E80 or F40' MAD16_BASE 530 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 audio IRQ 7, 9, 10 or 11' MAD16_IRQ 11 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 audio DMA 0, 1 or 3' MAD16_DMA 3 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 second (duplex) DMA 0, 1 or 3' MAD16_DMA2 0 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +hex 'MAD16 MIDI I/O base 300, 310, 320 or 330 (0 disables)' MAD16_MPU_BASE 330 +fi + +if [ "$CONFIG_MAD16" = "y" ]; then +int 'MAD16 MIDI IRQ 5, 7, 9 or 10' MAD16_MPU_IRQ 9 +fi +# +$MAKE -C drivers/sound kernelconfig || exit 1 bool 'Additional low level drivers' CONFIG_LOWLEVEL_SOUND if [ "$CONFIG_LOWLEVEL_SOUND" = "y" ]; then diff -u --recursive --new-file v2.1.44/linux/drivers/sound/soundcard.c linux/drivers/sound/soundcard.c --- v2.1.44/linux/drivers/sound/soundcard.c Mon Jun 16 16:35:56 1997 +++ linux/drivers/sound/soundcard.c Mon Jul 14 10:37:05 1997 @@ -246,7 +246,7 @@ struct inode *inode; int ret = 0; - inode = file->f_inode; + inode = file->f_dentry->d_inode; if (sound_select (inode, file, SEL_IN, wait)) ret |= POLLIN; @@ -326,8 +326,7 @@ vma->vm_page_prot)) return -EAGAIN; - vma->vm_inode = inode; - atomic_inc(&inode->i_count); + vma->vm_dentry = dget(file->f_dentry); dmap->mapping_flags |= DMA_MAP_MAPPED; diff -u --recursive --new-file v2.1.44/linux/fs/Config.in linux/fs/Config.in --- v2.1.44/linux/fs/Config.in Mon Jun 16 16:35:56 1997 +++ linux/fs/Config.in Thu Jul 10 16:10:15 1997 @@ -5,26 +5,6 @@ comment 'Filesystems' bool 'Quota support' CONFIG_QUOTA -bool 'Preload dcache entries in readdir() [ALPHA, currently dangerous!]' CONFIG_DCACHE_PRELOAD -bool 'Include support for omirr online mirror' CONFIG_OMIRR -bool 'Translate filename suffixes' CONFIG_TRANS_NAMES -if [ "$CONFIG_TRANS_NAMES" = "y" ]; then - bool ' Restrict translation to specific gid' CONFIG_TRANS_RESTRICT - if [ "$CONFIG_TRANS_RESTRICT" = "y" ]; then - int ' Enter gid to compile in' CONFIG_TRANS_GID 4 - fi - bool ' Translate nodename' CONFIG_TR_NODENAME - bool ' Translate compiled-in kernelname' CONFIG_TR_KERNNAME - if [ "$CONFIG_TR_KERNNAME" = "y" ]; then - string ' Enter kernelname string to compile in' CONFIG_KERNNAME banana - fi - bool ' Translate compiled-in kerneltype' CONFIG_TR_KERNTYPE - if [ "$CONFIG_TR_KERNTYPE" = "y" ]; then - string ' Enter kerneltype string to compile in' CONFIG_KERNTYPE default - fi - bool ' Translate machine type' CONFIG_TR_MACHINE - bool ' Translate sysname' CONFIG_TR_SYSNAME -fi tristate 'Minix fs support' CONFIG_MINIX_FS tristate 'Second extended fs support' CONFIG_EXT2_FS diff -u --recursive --new-file v2.1.44/linux/fs/affs/Changes linux/fs/affs/Changes --- v2.1.44/linux/fs/affs/Changes Tue May 13 22:41:13 1997 +++ linux/fs/affs/Changes Wed Jul 16 19:22:51 1997 @@ -13,11 +13,25 @@ reads basically work (but all files are of size 0). Alas, I've got no alpha to debug. :-( - If an affs mounted filesystem is exported via - nfs, it cannot be written to. No networking to - test that, either. :-( + nfs, it cannot be written to. + As soon as I have my network up and running, I'll + try to fix this. +- The partition checker (drivers/block/genhd.c) + doesn't work with devices which have 256 byte + blocks (some very old SCSI drives). Please direct bug reports to: hjw@zvw.de +Version 3.5 +----------- + +- Extension block caches are now allocated on + demand instead of when a file is opened, as + files can be read and written without opening + them (e. g. the loopback device does this). + +- Removed an unused function. + Version 3.4 ----------- @@ -80,7 +94,7 @@ interface in Linux 1.3. - Write support. - Support for hard and symbolic links. -- Lots of things I remeber even less ... +- Lots of things I remember even less ... Version 2.0 ----------- diff -u --recursive --new-file v2.1.44/linux/fs/affs/amigaffs.c linux/fs/affs/amigaffs.c --- v2.1.44/linux/fs/affs/amigaffs.c Tue May 13 22:41:13 1997 +++ linux/fs/affs/amigaffs.c Wed Jul 16 19:22:51 1997 @@ -26,27 +26,6 @@ * */ -/* Find the next used hash entry at or after *HASH_POS in a directory's hash - table. *HASH_POS is assigned that entry's number. DIR_DATA points to - the directory header block in memory. If there are no more entries, - 0 is returned. Otherwise, the key number in the next used hash slot - is returned. */ - -static int -affs_find_next_hash_entry(int hsize, void *dir_data, int *hash_pos) -{ - struct dir_front *dir_front = dir_data; - int i; - - for (i = *hash_pos; i < hsize; i++) - if (dir_front->hashtable[i] != 0) - break; - if (i >= hsize) - return 0; - *hash_pos = i; - return htonl(dir_front->hashtable[i]); -} - /* Set *NAME to point to the file name in a file header block in memory pointed to by FH_DATA. The length of the name is returned. */ diff -u --recursive --new-file v2.1.44/linux/fs/affs/file.c linux/fs/affs/file.c --- v2.1.44/linux/fs/affs/file.c Mon Jun 16 16:35:56 1997 +++ linux/fs/affs/file.c Wed Jul 16 19:22:51 1997 @@ -43,8 +43,8 @@ unsigned long count); static long affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, unsigned long count); -static int affs_open_file(struct inode *inode, struct file *filp); static int affs_release_file(struct inode *inode, struct file *filp); +static int alloc_ext_cache(struct inode *inode); static struct file_operations affs_file_operations = { NULL, /* lseek - default */ @@ -54,7 +54,7 @@ NULL, /* poll - default */ NULL, /* ioctl - default */ generic_file_mmap, /* mmap */ - affs_open_file, /* special open is needed */ + NULL, /* no special open */ affs_release_file, /* release */ file_fsync /* brute force, but works */ }; @@ -87,7 +87,7 @@ NULL, /* poll - default */ NULL, /* ioctl - default */ NULL, /* mmap */ - affs_open_file, /* special open is needed */ + NULL, /* no special open */ affs_release_file, /* release */ file_fsync /* brute force, but works */ }; @@ -248,9 +248,9 @@ return 0; } if (!inode->u.affs_i.i_ec) { - affs_error(inode->i_sb,"bmap","No extension cache for open file (inode=%lu)", - inode->i_ino); - return 0; + if (alloc_ext_cache(inode)) { + return 0; + } } /* Try to find the requested key in the cache. @@ -582,6 +582,12 @@ iput(inode); return -EINVAL; } + if (!inode->u.affs_i.i_ec) { + if (alloc_ext_cache(inode)) { + iput(inode); + return -ENOMEM; + } + } if (filp->f_flags & O_APPEND) { pos = inode->i_size; } else @@ -861,40 +867,6 @@ } static int -affs_open_file(struct inode *inode, struct file *filp) -{ - int error; - u32 key; - int i; - - pr_debug("AFFS: open_file(ino=%lu)\n",inode->i_ino); - - error = 0; - inode->u.affs_i.i_cache_users++; - lock_super(inode->i_sb); - if (!inode->u.affs_i.i_ec) { - inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL); - if (!inode->u.affs_i.i_ec) { - affs_error(inode->i_sb,"open_file","Cache allocation failed"); - error = ENOMEM; - } else { - /* We only have to initialize non-zero values. - * get_free_page() zeroed the page already. - */ - key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; - inode->u.affs_i.i_ec->ec[0] = key; - for (i = 0; i < 4; i++) { - inode->u.affs_i.i_ec->kc[i].kc_this_key = key; - inode->u.affs_i.i_ec->kc[i].kc_last = -1; - } - } - } - unlock_super(inode->i_sb); - - return error; -} - -static int affs_release_file(struct inode *inode, struct file *filp) { struct affs_zone *zone; @@ -916,13 +888,35 @@ unlock_super(inode->i_sb); } } + return 0; +} + +static int +alloc_ext_cache(struct inode *inode) +{ + s32 key; + int i; + lock_super(inode->i_sb); - if (--inode->u.affs_i.i_cache_users == 0) { + if (!inode->u.affs_i.i_ec) { + inode->u.affs_i.i_ec = (struct ext_cache *)get_free_page(GFP_KERNEL); if (inode->u.affs_i.i_ec) { - free_page((unsigned long)inode->u.affs_i.i_ec); - inode->u.affs_i.i_ec = NULL; + /* We only have to initialize non-zero values. + * get_free_page() zeroed the page already. + */ + key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino; + inode->u.affs_i.i_ec->ec[0] = key; + for (i = 0; i < 4; i++) { + inode->u.affs_i.i_ec->kc[i].kc_this_key = key; + inode->u.affs_i.i_ec->kc[i].kc_last = -1; + } } } unlock_super(inode->i_sb); + + if (!inode->u.affs_i.i_ec) { + affs_error(inode->i_sb,"alloc_ext_cache","Cache allocation failed"); + return -ENOMEM; + } return 0; } diff -u --recursive --new-file v2.1.44/linux/fs/affs/inode.c linux/fs/affs/inode.c --- v2.1.44/linux/fs/affs/inode.c Mon Jun 16 16:35:56 1997 +++ linux/fs/affs/inode.c Wed Jul 16 19:22:51 1997 @@ -691,7 +691,6 @@ inode->u.affs_i.i_pa_next = 0; inode->u.affs_i.i_pa_last = 0; inode->u.affs_i.i_ec = NULL; - inode->u.affs_i.i_cache_users = 0; inode->u.affs_i.i_lastblock = -1; inode->i_nlink = 1; inode->i_mode = 0; @@ -870,6 +869,12 @@ affs_put_inode(struct inode *inode) { pr_debug("AFFS: put_inode(ino=%lu, nlink=%u)\n",inode->i_ino,inode->i_nlink); + lock_super(inode->i_sb); + if (inode->u.affs_i.i_ec) { + free_page((unsigned long)inode->u.affs_i.i_ec); + inode->u.affs_i.i_ec = NULL; + } + unlock_super(inode->i_sb); if (inode->i_nlink) { return; } @@ -899,7 +904,7 @@ return NULL; } - atomic_set(&inode->i_count, 1); + inode->i_count = 1; inode->i_nlink = 1; inode->i_dev = sb->s_dev; inode->i_uid = current->fsuid; @@ -921,7 +926,6 @@ inode->u.affs_i.i_pa_next = 0; inode->u.affs_i.i_pa_last = 0; inode->u.affs_i.i_ec = NULL; - inode->u.affs_i.i_cache_users = 0; inode->u.affs_i.i_lastblock = -1; insert_inode_hash(inode); diff -u --recursive --new-file v2.1.44/linux/fs/affs/namei.c linux/fs/affs/namei.c --- v2.1.44/linux/fs/affs/namei.c Thu Jul 3 17:30:26 1997 +++ linux/fs/affs/namei.c Wed Jul 16 19:22:51 1997 @@ -343,7 +343,7 @@ retval = -ENOTEMPTY; goto rmdir_done; } - if (atomic_read(&inode->i_count) > 1) { + if (inode->i_count > 1) { retval = -EBUSY; goto rmdir_done; } @@ -512,7 +512,7 @@ int ino; int result; - atomic_inc(&new_inode->i_count); + new_inode->i_count++; result = 0; for (;;) { if (new_inode == old_inode) { @@ -566,12 +566,12 @@ old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino); if (!old_bh) goto end_rename; - old_inode = __iget(old_dir->i_sb,old_ino); + old_inode = iget(old_dir->i_sb,old_ino); if (!old_inode) goto end_rename; new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino); if (new_bh) { - new_inode = __iget(new_dir->i_sb,new_ino); + new_inode = iget(new_dir->i_sb,new_ino); if (!new_inode) { /* What does this mean? */ affs_brelse(new_bh); new_bh = NULL; @@ -592,7 +592,7 @@ if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode))) goto end_rename; retval = -EBUSY; - if (atomic_read(&new_inode->i_count) > 1) + if (new_inode->i_count > 1) goto end_rename; } if (S_ISDIR(old_inode->i_mode)) { diff -u --recursive --new-file v2.1.44/linux/fs/attr.c linux/fs/attr.c --- v2.1.44/linux/fs/attr.c Mon Jun 16 16:35:56 1997 +++ linux/fs/attr.c Tue Jul 8 14:36:15 1997 @@ -74,7 +74,7 @@ if (!fsuser() && !in_group_p(inode->i_gid)) inode->i_mode &= ~S_ISGID; } - inode->i_dirt = 1; + mark_inode_dirty(inode); } } diff -u --recursive --new-file v2.1.44/linux/fs/autofs/dir.c linux/fs/autofs/dir.c --- v2.1.44/linux/fs/autofs/dir.c Mon Jul 7 12:45:24 1997 +++ linux/fs/autofs/dir.c Wed Jul 16 15:10:58 1997 @@ -37,9 +37,10 @@ /* * No entries except for "." and "..", both of which are handled by the VFS layer */ -static int autofs_dir_lookup(struct inode *dir, struct qstr *str, struct inode **result) +static int autofs_dir_lookup(struct inode *dir, struct dentry * dentry) { - return -ENOENT; /* No other entries */ + d_add(dentry, NULL); + return 0; } static struct file_operations autofs_dir_operations = { diff -u --recursive --new-file v2.1.44/linux/fs/autofs/inode.c linux/fs/autofs/inode.c --- v2.1.44/linux/fs/autofs/inode.c Mon Jul 7 11:10:13 1997 +++ linux/fs/autofs/inode.c Wed Jul 16 13:01:34 1997 @@ -19,11 +19,17 @@ #define __NO_VERSION__ #include +/* + * Dummy functions - do we ever actually want to do + * something here? + */ static void autofs_put_inode(struct inode *inode) { - if (inode->i_nlink) - return; - inode->i_size = 0; +} + +static void autofs_delete_inode(struct inode *inode) +{ + inode->i_size = 0; } static void autofs_put_super(struct super_block *sb) @@ -35,16 +41,16 @@ if ( !sbi->catatonic ) autofs_catatonic_mode(sbi); /* Free wait queues, close pipe */ - lock_super(sb); + lock_super(sb); autofs_hash_nuke(&sbi->dirhash); for ( n = 0 ; n < AUTOFS_MAX_SYMLINKS ; n++ ) { if ( test_bit(n, sbi->symlink_bitmap) ) kfree(sbi->symlink[n].data); } - sb->s_dev = 0; + sb->s_dev = 0; kfree(sb->u.generic_sbp); - unlock_super(sb); + unlock_super(sb); DPRINTK(("autofs: shutting down\n")); @@ -53,95 +59,96 @@ #endif } -static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); +static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz); static void autofs_read_inode(struct inode *inode); static void autofs_write_inode(struct inode *inode); static struct super_operations autofs_sops = { - autofs_read_inode, - NULL, - autofs_write_inode, - autofs_put_inode, - autofs_put_super, - NULL, - autofs_statfs, - NULL + autofs_read_inode, + autofs_write_inode, + autofs_put_inode, + autofs_delete_inode, + NULL, /* notify_change */ + autofs_put_super, + NULL, /* write_super */ + autofs_statfs, + NULL }; static int parse_options(char *options, int *pipefd, uid_t *uid, gid_t *gid, pid_t *pgrp, int *minproto, int *maxproto) { - char *this_char, *value; - - *uid = current->uid; - *gid = current->gid; + char *this_char, *value; + + *uid = current->uid; + *gid = current->gid; *pgrp = current->pgrp; *minproto = *maxproto = AUTOFS_PROTO_VERSION; - *pipefd = -1; + *pipefd = -1; - if ( !options ) return 1; - for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { - if ((value = strchr(this_char,'=')) != NULL) - *value++ = 0; - if (!strcmp(this_char,"fd")) { - if (!value || !*value) - return 1; - *pipefd = simple_strtoul(value,&value,0); - if (*value) - return 1; - } - else if (!strcmp(this_char,"uid")) { - if (!value || !*value) - return 1; - *uid = simple_strtoul(value,&value,0); - if (*value) - return 1; - } - else if (!strcmp(this_char,"gid")) { - if (!value || !*value) - return 1; - *gid = simple_strtoul(value,&value,0); - if (*value) - return 1; - } - else if (!strcmp(this_char,"pgrp")) { - if (!value || !*value) - return 1; - *pgrp = simple_strtoul(value,&value,0); - if (*value) - return 1; - } - else if (!strcmp(this_char,"minproto")) { - if (!value || !*value) - return 1; - *minproto = simple_strtoul(value,&value,0); - if (*value) - return 1; - } - else if (!strcmp(this_char,"maxproto")) { - if (!value || !*value) - return 1; - *maxproto = simple_strtoul(value,&value,0); - if (*value) - return 1; - } - else break; - } - return (*pipefd < 0); + if ( !options ) return 1; + for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) { + if ((value = strchr(this_char,'=')) != NULL) + *value++ = 0; + if (!strcmp(this_char,"fd")) { + if (!value || !*value) + return 1; + *pipefd = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"uid")) { + if (!value || !*value) + return 1; + *uid = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"gid")) { + if (!value || !*value) + return 1; + *gid = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"pgrp")) { + if (!value || !*value) + return 1; + *pgrp = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"minproto")) { + if (!value || !*value) + return 1; + *minproto = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else if (!strcmp(this_char,"maxproto")) { + if (!value || !*value) + return 1; + *maxproto = simple_strtoul(value,&value,0); + if (*value) + return 1; + } + else break; + } + return (*pipefd < 0); } struct super_block *autofs_read_super(struct super_block *s, void *data, - int silent) + int silent) { - int pipefd; + int pipefd; struct autofs_sb_info *sbi; int minproto, maxproto; MOD_INC_USE_COUNT; - lock_super(s); - sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL); + lock_super(s); + sbi = (struct autofs_sb_info *) kmalloc(sizeof(struct autofs_sb_info), GFP_KERNEL); if ( !sbi ) { s->s_dev = 0; MOD_DEC_USE_COUNT; @@ -158,31 +165,31 @@ sbi->queues = NULL; memset(sbi->symlink_bitmap, 0, sizeof(u32)*AUTOFS_SYMLINK_BITMAP_LEN); sbi->next_dir_ino = AUTOFS_FIRST_DIR_INO; - s->s_blocksize = 1024; - s->s_blocksize_bits = 10; - s->s_magic = AUTOFS_SUPER_MAGIC; - s->s_op = &autofs_sops; - unlock_super(s); - s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL); - if (!s->s_root) { - s->s_dev = 0; + s->s_blocksize = 1024; + s->s_blocksize_bits = 10; + s->s_magic = AUTOFS_SUPER_MAGIC; + s->s_op = &autofs_sops; + unlock_super(s); + s->s_root = d_alloc_root(iget(s, AUTOFS_ROOT_INO), NULL); + if (!s->s_root) { + s->s_dev = 0; kfree(sbi); - printk("autofs: get root inode failed\n"); + printk("autofs: get root inode failed\n"); MOD_DEC_USE_COUNT; - return NULL; - } + return NULL; + } - if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) { - d_delete(s->s_root); - s->s_dev = 0; + if ( parse_options(data,&pipefd,&s->s_root->d_inode->i_uid,&s->s_root->d_inode->i_gid,&sbi->oz_pgrp,&minproto,&maxproto) ) { + dput(s->s_root); + s->s_dev = 0; kfree(sbi); - printk("autofs: called with bogus options\n"); + printk("autofs: called with bogus options\n"); MOD_DEC_USE_COUNT; - return NULL; - } + return NULL; + } if ( minproto > AUTOFS_PROTO_VERSION || maxproto < AUTOFS_PROTO_VERSION ) { - d_delete(s->s_root); + dput(s->s_root); s->s_dev = 0; kfree(sbi); printk("autofs: kernel does not match daemon version\n"); @@ -194,60 +201,60 @@ sbi->pipe = fget(pipefd); if ( !sbi->pipe || !sbi->pipe->f_op || !sbi->pipe->f_op->write ) { if ( sbi->pipe ) { - fput(sbi->pipe, sbi->pipe->f_inode); + fput(sbi->pipe); printk("autofs: pipe file descriptor does not contain proper ops\n"); } else { printk("autofs: could not open pipe file descriptor\n"); } - d_delete(s->s_root); + dput(s->s_root); s->s_dev = 0; kfree(sbi); MOD_DEC_USE_COUNT; return NULL; } - return s; + return s; } -static void autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) +static int autofs_statfs(struct super_block *sb, struct statfs *buf, int bufsiz) { - struct statfs tmp; + struct statfs tmp; - tmp.f_type = AUTOFS_SUPER_MAGIC; - tmp.f_bsize = 1024; - tmp.f_blocks = 0; - tmp.f_bfree = 0; - tmp.f_bavail = 0; - tmp.f_files = 0; - tmp.f_ffree = 0; - tmp.f_namelen = NAME_MAX; - copy_to_user(buf, &tmp, bufsiz); + tmp.f_type = AUTOFS_SUPER_MAGIC; + tmp.f_bsize = 1024; + tmp.f_blocks = 0; + tmp.f_bfree = 0; + tmp.f_bavail = 0; + tmp.f_files = 0; + tmp.f_ffree = 0; + tmp.f_namelen = NAME_MAX; + return copy_to_user(buf, &tmp, bufsiz) ? -EFAULT : 0; } static void autofs_read_inode(struct inode *inode) { - ino_t ino = inode->i_ino; + ino_t ino = inode->i_ino; unsigned int n; - struct autofs_sb_info *sbi = + struct autofs_sb_info *sbi = (struct autofs_sb_info *) inode->i_sb->u.generic_sbp; - inode->i_op = NULL; - inode->i_mode = 0; - inode->i_nlink = 2; - inode->i_size = 0; - inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; - inode->i_blocks = 0; - inode->i_blksize = 1024; - - if ( ino == AUTOFS_ROOT_INO ) { - inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; - inode->i_op = &autofs_root_inode_operations; + inode->i_op = NULL; + inode->i_mode = 0; + inode->i_nlink = 2; + inode->i_size = 0; + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + inode->i_blocks = 0; + inode->i_blksize = 1024; + + if ( ino == AUTOFS_ROOT_INO ) { + inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; + inode->i_op = &autofs_root_inode_operations; inode->i_uid = inode->i_gid = 0; /* Changed in read_super */ - return; - } + return; + } + + inode->i_uid = inode->i_sb->s_root->d_inode->i_uid; + inode->i_gid = inode->i_sb->s_root->d_inode->i_gid; - inode->i_uid = inode->i_sb->s_root->d_inode->i_uid; - inode->i_gid = inode->i_sb->s_root->d_inode->i_gid; - if ( ino >= AUTOFS_FIRST_SYMLINK && ino < AUTOFS_FIRST_DIR_INO ) { /* Symlink inode - should be in symlink list */ struct autofs_symlink *sl; @@ -274,5 +281,4 @@ static void autofs_write_inode(struct inode *inode) { - inode->i_dirt = 0; } diff -u --recursive --new-file v2.1.44/linux/fs/autofs/root.c linux/fs/autofs/root.c --- v2.1.44/linux/fs/autofs/root.c Mon Jul 7 13:55:00 1997 +++ linux/fs/autofs/root.c Wed Jul 16 15:28:09 1997 @@ -16,7 +16,7 @@ #include "autofs_i.h" static int autofs_root_readdir(struct inode *,struct file *,void *,filldir_t); -static int autofs_root_lookup(struct inode *,struct qstr *,struct inode **); +static int autofs_root_lookup(struct inode *,struct dentry *); static int autofs_root_symlink(struct inode *,struct dentry *,const char *); static int autofs_root_unlink(struct inode *,struct dentry *); static int autofs_root_rmdir(struct inode *,struct dentry *); @@ -93,63 +93,105 @@ return 0; } -static int autofs_root_lookup(struct inode *dir, struct qstr *str, struct inode **result) +static int try_to_fill_dentry(struct dentry * dentry, struct super_block * sb, struct autofs_sb_info *sbi) { - struct autofs_sb_info *sbi; + struct inode * inode; struct autofs_dir_ent *ent; + + while (!(ent = autofs_hash_lookup(&sbi->dirhash, &dentry->d_name))) { + int status = autofs_wait(sbi, &dentry->d_name); + + /* Turn this into a real negative dentry? */ + if (status == -ENOENT) { + dentry->d_flags = 0; + return 0; + } + if (status) + return status; + } + + if (!dentry->d_inode) { + inode = iget(sb, ent->ino); + if (!inode) + return -EACCES; + + dentry->d_inode = inode; + } + + if (S_ISDIR(dentry->d_inode->i_mode)) { + while (dentry == dentry->d_mounts) + schedule(); + } + dentry->d_flags = 0; + return 0; +} + + +/* + * Revalidate is called on every cache lookup. Some of those + * cache lookups may actually happen while the dentry is not + * yet completely filled in, and revalidate has to delay such + * lookups.. + */ +static struct dentry * autofs_revalidate(struct dentry * dentry) +{ + struct autofs_sb_info *sbi; + struct inode * dir = dentry->d_parent->d_inode; + + sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; + + /* Incomplete dentry? */ + if (dentry->d_flags) { + if (autofs_oz_mode(sbi)) + return dentry; + + try_to_fill_dentry(dentry, dir->i_sb, sbi); + return dentry; + } + + /* Negative dentry.. Should we time these out? */ + if (!dentry->d_inode) + return dentry; + + /* We should update the usage stuff here.. */ + return dentry; +} + +static int autofs_root_lookup(struct inode *dir, struct dentry * dentry) +{ + struct autofs_sb_info *sbi; struct inode *res; - int status, oz_mode; + int oz_mode; DPRINTK(("autofs_root_lookup: name = ")); - autofs_say(str->name,str->len); + autofs_say(dentry->d_name.name,dentry->d_name.len); - *result = NULL; - if (!dir) - return -ENOENT; if (!S_ISDIR(dir->i_mode)) return -ENOTDIR; - *result = res = NULL; + res = NULL; sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; oz_mode = autofs_oz_mode(sbi); DPRINTK(("autofs_lookup: pid = %u, pgrp = %u, catatonic = %d, oz_mode = %d\n", current->pid, current->pgrp, sbi->catatonic, oz_mode)); - do { - while ( !(ent = autofs_hash_lookup(&sbi->dirhash,str)) ) { - DPRINTK(("lookup failed, pid = %u, pgrp = %u\n", current->pid, current->pgrp)); - - if ( oz_mode ) - return -ENOENT; - up(&dir->i_sem); - status = autofs_wait(sbi,str); - down(&dir->i_sem); - DPRINTK(("autofs_wait returned %d\n", status)); - if ( status ) - return status; - } - - DPRINTK(("lookup successful, inode = %08x\n", (unsigned int)ent->ino)); - - if (!(res = iget(dir->i_sb,ent->ino))) { - printk("autofs: iget returned null!\n"); - return -EACCES; - } - - if ( !oz_mode && S_ISDIR(res->i_mode) && res->i_sb == dir->i_sb ) { - /* Not a mount point yet, call 1-800-DAEMON */ - DPRINTK(("autofs: waiting on non-mountpoint dir, inode = %lu, pid = %u, pgrp = %u\n", res->i_ino, current->pid, current->pgrp)); - res = NULL; - up(&dir->i_sem); - status = autofs_wait(sbi,str); - down(&dir->i_sem); - if ( status ) - return status; - } - } while(!res); - autofs_update_usage(&sbi->dirhash,ent); - - *result = res; + /* + * Mark the dentry incomplete, but add it. This is needed so + * that the VFS layer knows about the dentry, and we can count + * on catching any lookups through the revalidate. + * + * Let all the hard work be done by the revalidate function that + * needs to be able to do this anyway.. + * + * We need to do this before we release the directory semaphore. + */ + dentry->d_revalidate = autofs_revalidate; + dentry->d_flags = 1; + d_add(dentry, NULL); + + up(&dir->i_sem); + autofs_revalidate(dentry); + down(&dir->i_sem); return 0; } @@ -163,7 +205,7 @@ struct autofs_symlink *sl; DPRINTK(("autofs_root_symlink: %s <- ", symname)); - autofs_say(name,len); + autofs_say(dentry->d_name.name,dentry->d_name.len); if ( !autofs_oz_mode(sbi) ) return -EPERM; @@ -207,11 +249,22 @@ memcpy(ent->name, dentry->d_name.name,ent->len = dentry->d_name.len); autofs_hash_insert(dh,ent); - d_instantiate(dentry, iget(dir->i_sb,ent->ino), 0); + d_instantiate(dentry, iget(dir->i_sb,ent->ino)); return 0; } +/* + * NOTE! + * + * Normal filesystems would do a "d_delete()" to tell the VFS dcache + * that the file no longer exists. However, doing that means that the + * VFS layer can turn the dentry into a negative dentry, which we + * obviously do not want (we're dropping the entry not because it + * doesn't exist, but because it has timed out). + * + * Also see autofs_root_rmdir().. + */ static int autofs_root_unlink(struct inode *dir, struct dentry *dentry) { struct autofs_sb_info *sbi = (struct autofs_sb_info *) dir->i_sb->u.generic_sbp; @@ -233,7 +286,7 @@ autofs_hash_delete(ent); clear_bit(n,sbi->symlink_bitmap); kfree(sbi->symlink[n].data); - d_delete(dentry); + d_drop(dentry); return 0; } @@ -256,7 +309,7 @@ autofs_hash_delete(ent); dir->i_nlink--; - d_delete(dentry); + d_drop(dentry); return 0; } @@ -294,7 +347,7 @@ ent->ino = sbi->next_dir_ino++; autofs_hash_insert(dh,ent); dir->i_nlink++; - d_instantiate(dentry, iget(dir->i_sb,ent->ino), D_DIR); + d_instantiate(dentry, iget(dir->i_sb,ent->ino)); return 0; } diff -u --recursive --new-file v2.1.44/linux/fs/autofs/waitq.c linux/fs/autofs/waitq.c --- v2.1.44/linux/fs/autofs/waitq.c Mon Jul 7 12:57:29 1997 +++ linux/fs/autofs/waitq.c Mon Jul 14 10:22:52 1997 @@ -37,7 +37,7 @@ wake_up(&wq->queue); wq = nwq; } - fput(sbi->pipe, sbi->pipe->f_inode); /* Close the pipe */ + fput(sbi->pipe); /* Close the pipe */ } static int autofs_write(struct file *file, const void *addr, int bytes) @@ -55,7 +55,7 @@ old_signal = current->signal; - while ( bytes && (written = file->f_op->write(file->f_inode,file,data,bytes)) > 0 ) { + while ( bytes && (written = file->f_op->write(file->f_dentry->d_inode,file,data,bytes)) > 0 ) { data += written; bytes -= written; } diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_aout.c linux/fs/binfmt_aout.c --- v2.1.44/linux/fs/binfmt_aout.c Mon Jun 16 16:35:57 1997 +++ linux/fs/binfmt_aout.c Sun Jul 13 21:20:10 1997 @@ -79,6 +79,7 @@ static inline int do_aout_core_dump(long signr, struct pt_regs * regs) { + struct dentry * dentry = NULL; struct inode * inode = NULL; struct file file; unsigned short fs; @@ -114,10 +115,12 @@ #else corefile[4] = '\0'; #endif - if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { - inode = NULL; + dentry = open_namei(corefile,O_CREAT | 2 | O_TRUNC, 0600); + if (IS_ERR(dentry)) { + dentry = NULL; goto end_coredump; } + inode = dentry->d_inode; if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) @@ -127,7 +130,7 @@ file.f_mode = 3; file.f_flags = 0; file.f_count = 1; - file.f_inode = inode; + file.f_dentry = dentry; file.f_pos = 0; file.f_reada = 0; file.f_op = inode->i_op->default_file_ops; @@ -214,7 +217,6 @@ /* Finally dump the task struct. Not be used by gdb, but could be useful */ set_fs(KERNEL_DS); DUMP_WRITE(current,sizeof(*current)); - inode->i_status |= ST_MODIFIED; close_coredump: if (file.f_op->release) file.f_op->release(inode,&file); @@ -222,7 +224,7 @@ put_write_access(inode); end_coredump: set_fs(fs); - iput(inode); + dput(dentry); return has_dumped; } @@ -318,7 +320,7 @@ if ((N_MAGIC(ex) != ZMAGIC && N_MAGIC(ex) != OMAGIC && N_MAGIC(ex) != QMAGIC && N_MAGIC(ex) != NMAGIC) || N_TRSIZE(ex) || N_DRSIZE(ex) || - bprm->inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { + bprm->dentry->d_inode->i_size < ex.a_text+ex.a_data+N_SYMSIZE(ex)+N_TXTOFF(ex)) { return -ENOEXEC; } @@ -332,7 +334,7 @@ } if (N_MAGIC(ex) == ZMAGIC && ex.a_text && - (fd_offset < bprm->inode->i_sb->s_blocksize)) { + (fd_offset < bprm->dentry->d_inode->i_sb->s_blocksize)) { printk(KERN_NOTICE "N_TXTOFF < BLOCK_SIZE. Please convert binary.\n"); return -ENOEXEC; } @@ -372,12 +374,12 @@ error = do_mmap(NULL, N_TXTADDR(ex), ex.a_text, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), ex.a_text, 0); error = do_mmap(NULL, N_DATADDR(ex), ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset + ex.a_text, (char *) N_DATADDR(ex), + read_exec(bprm->dentry, fd_offset + ex.a_text, (char *) N_DATADDR(ex), ex.a_data, 0); goto beyond_if; } @@ -389,20 +391,20 @@ ex.a_text+ex.a_data + PAGE_SIZE - 1, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset, (char *) N_TXTADDR(ex), + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); #else do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, 32, (char *) 0, ex.a_text+ex.a_data, 0); + read_exec(bprm->dentry, 32, (char *) 0, ex.a_text+ex.a_data, 0); #endif } else { if ((ex.a_text & 0xfff || ex.a_data & 0xfff) && (N_MAGIC(ex) != NMAGIC)) printk(KERN_NOTICE "executable not page aligned\n"); - fd = open_inode(bprm->inode, O_RDONLY); + fd = open_dentry(bprm->dentry, O_RDONLY); if (fd < 0) return fd; @@ -412,7 +414,7 @@ do_mmap(NULL, 0, ex.a_text+ex.a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - read_exec(bprm->inode, fd_offset, + read_exec(bprm->dentry, fd_offset, (char *) N_TXTADDR(ex), ex.a_text+ex.a_data, 0); goto beyond_if; } @@ -482,17 +484,20 @@ { struct file * file; struct exec ex; - struct inode * inode; + struct dentry * dentry; + struct inode * inode; unsigned int len; unsigned int bss; unsigned int start_addr; unsigned long error; file = current->files->fd[fd]; - inode = file->f_inode; if (!file || !file->f_op) return -EACCES; + + dentry = file->f_dentry; + inode = dentry->d_inode; /* Seek into the file */ if (file->f_op->llseek) { diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_elf.c linux/fs/binfmt_elf.c --- v2.1.44/linux/fs/binfmt_elf.c Mon Jul 7 08:18:55 1997 +++ linux/fs/binfmt_elf.c Mon Jul 14 11:42:23 1997 @@ -186,7 +186,7 @@ an ELF header */ static unsigned long load_elf_interp(struct elfhdr * interp_elf_ex, - struct inode * interpreter_inode, + struct dentry * interpreter_dentry, unsigned long *interp_load_addr) { struct file * file; @@ -208,8 +208,8 @@ if ((interp_elf_ex->e_type != ET_EXEC && interp_elf_ex->e_type != ET_DYN) || !elf_check_arch(interp_elf_ex->e_machine) || - (!interpreter_inode->i_op || - !interpreter_inode->i_op->default_file_ops->mmap)){ + (!interpreter_dentry->d_inode->i_op || + !interpreter_dentry->d_inode->i_op->default_file_ops->mmap)){ return ~0UL; } @@ -236,7 +236,7 @@ return ~0UL; } - retval = read_exec(interpreter_inode, interp_elf_ex->e_phoff, + retval = read_exec(interpreter_dentry, interp_elf_ex->e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * interp_elf_ex->e_phnum, 1); @@ -245,7 +245,7 @@ return retval; } - elf_exec_fileno = open_inode(interpreter_inode, O_RDONLY); + elf_exec_fileno = open_dentry(interpreter_dentry, O_RDONLY); if (elf_exec_fileno < 0) { kfree(elf_phdata); return ~0UL; @@ -333,7 +333,7 @@ } static unsigned long load_aout_interp(struct exec * interp_ex, - struct inode * interpreter_inode) + struct dentry * interpreter_dentry) { int retval; unsigned long elf_entry; @@ -348,13 +348,13 @@ do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, 32, (char *) 0, + retval = read_exec(interpreter_dentry, 32, (char *) 0, interp_ex->a_text+interp_ex->a_data, 0); } else if (N_MAGIC(*interp_ex) == ZMAGIC || N_MAGIC(*interp_ex) == QMAGIC) { do_mmap(NULL, 0, interp_ex->a_text+interp_ex->a_data, PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); - retval = read_exec(interpreter_inode, + retval = read_exec(interpreter_dentry, N_TXTOFF(*interp_ex) , (char *) N_TXTADDR(*interp_ex), interp_ex->a_text+interp_ex->a_data, 0); @@ -389,7 +389,7 @@ struct elfhdr interp_elf_ex; struct file * file; struct exec interp_ex; - struct inode *interpreter_inode; + struct dentry *interpreter_dentry; unsigned long load_addr; int load_addr_set = 0; unsigned int interpreter_type = INTERPRETER_NONE; @@ -423,8 +423,8 @@ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || (! elf_check_arch(elf_ex.e_machine)) || - (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || - !bprm->inode->i_op->default_file_ops->mmap)){ + (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops || + !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){ return -ENOEXEC; } @@ -436,7 +436,7 @@ return -ENOMEM; } - retval = read_exec(bprm->inode, elf_ex.e_phoff, (char *) elf_phdata, + retval = read_exec(bprm->dentry, elf_ex.e_phoff, (char *) elf_phdata, elf_ex.e_phentsize * elf_ex.e_phnum, 1); if (retval < 0) { kfree (elf_phdata); @@ -448,7 +448,7 @@ elf_bss = 0; elf_brk = 0; - elf_exec_fileno = open_inode(bprm->inode, O_RDONLY); + elf_exec_fileno = open_dentry(bprm->dentry, O_RDONLY); if (elf_exec_fileno < 0) { kfree (elf_phdata); @@ -486,7 +486,7 @@ return -ENOMEM; } - retval = read_exec(bprm->inode,elf_ppnt->p_offset, + retval = read_exec(bprm->dentry,elf_ppnt->p_offset, elf_interpreter, elf_ppnt->p_filesz, 1); /* If the program interpreter is one of these two, @@ -501,13 +501,14 @@ if (retval >= 0) { old_fs = get_fs(); /* This could probably be optimized */ set_fs(get_ds()); - retval = open_namei(elf_interpreter, 0, 0, - &interpreter_inode, NULL); + interpreter_dentry = open_namei(elf_interpreter, 0, 0); set_fs(old_fs); + if (IS_ERR(interpreter_dentry)) + retval = PTR_ERR(interpreter_dentry); } if (retval >= 0) - retval = read_exec(interpreter_inode,0,bprm->buf,128, 1); + retval = read_exec(interpreter_dentry,0,bprm->buf,128, 1); if (retval >= 0) { interp_ex = *((struct exec *) bprm->buf); /* exec-header */ @@ -643,13 +644,13 @@ if (elf_interpreter) { if (interpreter_type & 1) elf_entry = load_aout_interp(&interp_ex, - interpreter_inode); + interpreter_dentry); else if (interpreter_type & 2) elf_entry = load_elf_interp(&interp_elf_ex, - interpreter_inode, + interpreter_dentry, &interp_load_addr); - iput(interpreter_inode); + dput(interpreter_dentry); kfree(elf_interpreter); if (elf_entry == ~0UL) { @@ -677,8 +678,7 @@ __MOD_INC_USE_COUNT(current->binfmt->module); #ifndef VM_STACK_FLAGS - current->executable = bprm->inode; - atomic_inc(&bprm->inode->i_count); + current->executable = dget(bprm->dentry); #endif #ifdef LOW_ELF_STACK current->start_stack = bprm->p = elf_stack - 4; @@ -763,7 +763,8 @@ struct file * file; struct elfhdr elf_ex; struct elf_phdr *elf_phdata = NULL; - struct inode * inode; + struct dentry * dentry; + struct inode * inode; unsigned long len; int elf_bss; int retval; @@ -773,7 +774,8 @@ len = 0; file = current->files->fd[fd]; - inode = file->f_inode; + dentry = file->f_dentry; + inode = dentry->d_inode; elf_bss = 0; if (!file || !file->f_op) @@ -812,7 +814,7 @@ if (elf_phdata == NULL) return -ENOMEM; - retval = read_exec(inode, elf_ex.e_phoff, (char *) elf_phdata, + retval = read_exec(dentry, elf_ex.e_phoff, (char *) elf_phdata, sizeof(struct elf_phdr) * elf_ex.e_phnum, 1); j = 0; @@ -884,14 +886,13 @@ */ static int dump_write(struct file *file, const void *addr, int nr) { - file->f_inode->i_status |= ST_MODIFIED; - return file->f_op->write(file->f_inode, file, addr, nr) == nr; + return file->f_op->write(file->f_dentry->d_inode, file, addr, nr) == nr; } static int dump_seek(struct file *file, off_t off) { if (file->f_op->llseek) { - if (file->f_op->llseek(file->f_inode, file, off, 0) != off) + if (file->f_op->llseek(file->f_dentry->d_inode, file, off, 0) != off) return 0; } else file->f_pos = off; @@ -1006,6 +1007,7 @@ { int has_dumped = 0; struct file file; + struct dentry *dentry; struct inode *inode; unsigned short fs; char corefile[6+sizeof(current->comm)]; @@ -1079,10 +1081,12 @@ #else corefile[4] = '\0'; #endif - if (open_namei(corefile,O_CREAT | 2 | O_TRUNC,0600,&inode,NULL)) { - inode = NULL; + dentry = open_namei(corefile, O_CREAT | 2 | O_TRUNC, 0600); + if (IS_ERR(dentry)) { + dentry = NULL; goto end_coredump; } + inode = dentry->d_inode; if (!S_ISREG(inode->i_mode)) goto end_coredump; if (!inode->i_op || !inode->i_op->default_file_ops) @@ -1090,7 +1094,7 @@ file.f_mode = 3; file.f_flags = 0; file.f_count = 1; - file.f_inode = inode; + file.f_dentry = dentry; file.f_pos = 0; file.f_reada = 0; file.f_op = inode->i_op->default_file_ops; @@ -1287,7 +1291,7 @@ end_coredump: set_fs(fs); - iput(inode); + dput(dentry); #ifndef CONFIG_BINFMT_ELF MOD_DEC_USE_COUNT; #endif diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_em86.c linux/fs/binfmt_em86.c --- v2.1.44/linux/fs/binfmt_em86.c Wed Apr 23 19:01:22 1997 +++ linux/fs/binfmt_em86.c Sun Jul 13 21:20:10 1997 @@ -23,6 +23,7 @@ static int do_load_em86(struct linux_binprm *bprm,struct pt_regs *regs) { char *interp, *i_name, *i_arg; + struct dentry * dentry; int retval; struct elfhdr elf_ex; @@ -39,14 +40,14 @@ if ((elf_ex.e_type != ET_EXEC && elf_ex.e_type != ET_DYN) || (!((elf_ex.e_machine == EM_386) || (elf_ex.e_machine == EM_486))) || - (!bprm->inode->i_op || !bprm->inode->i_op->default_file_ops || - !bprm->inode->i_op->default_file_ops->mmap)){ + (!bprm->dentry->d_inode->i_op || !bprm->dentry->d_inode->i_op->default_file_ops || + !bprm->dentry->d_inode->i_op->default_file_ops->mmap)){ return -ENOEXEC; } bprm->sh_bang++; /* Well, the bang-shell is implicit... */ - iput(bprm->inode); - bprm->dont_iput = 1; + dput(bprm->dentry); + bprm->dentry = NULL; /* Unlike in the script case, we don't have to do any hairy * parsing to find our interpreter... it's hardcoded! @@ -79,14 +80,17 @@ * Note that we use open_namei() as the name is now in kernel * space, and we don't need to copy it. */ - retval = open_namei(interp, 0, 0, &bprm->inode, NULL); - if (retval) - return retval; - bprm->dont_iput=0; - retval=prepare_binprm(bprm); - if(retval<0) + dentry = open_namei(interp, 0, 0); + if (IS_ERR(dentry)) + return PTR_ERR(dentry); + + bprm->dentry = dentry; + + retval = prepare_binprm(bprm); + if (retval < 0) return retval; - return search_binary_handler(bprm,regs); + + return search_binary_handler(bprm, regs); } static int load_em86(struct linux_binprm *bprm,struct pt_regs *regs) diff -u --recursive --new-file v2.1.44/linux/fs/binfmt_java.c linux/fs/binfmt_java.c --- v2.1.44/linux/fs/binfmt_java.c Wed Apr 23 19:01:22 1997 +++ linux/fs/binfmt_java.c Mon Jul 14 10:28:48 1997 @@ -28,7 +28,9 @@ char *i_name; int len; int retval; + struct dentry * dentry; unsigned char *ucp = (unsigned char *) bprm->buf; + if ((ucp[0] != 0xca) || (ucp[1] != 0xfe) || (ucp[2] != 0xba) || (ucp[3] != 0xbe)) return -ENOEXEC; @@ -42,8 +44,8 @@ bprm->java = 1; - iput(bprm->inode); - bprm->dont_iput=1; + dput(bprm->dentry); + bprm->dentry = NULL; /* * Set args: [0] the name of the java interpreter @@ -75,15 +77,17 @@ if (!bprm->p) return -E2BIG; /* - * OK, now restart the process with the interpreter's inode. + * OK, now restart the process with the interpreter's dentry. */ bprm->filename = binfmt_java_interpreter; - retval = open_namei(binfmt_java_interpreter, 0, 0, &bprm->inode, NULL); - if (retval) + dentry = open_namei(binfmt_java_interpreter, 0, 0); + retval = PTR_ERR(dentry); + if (IS_ERR(dentry)) return retval; - bprm->dont_iput=0; - retval=prepare_binprm(bprm); - if(retval<0) + + bprm->dentry = dentry; + retval = prepare_binprm(bprm); + if (retval < 0) return retval; return search_binary_handler(bprm,regs); @@ -92,12 +96,14 @@ static int do_load_applet(struct linux_binprm *bprm,struct pt_regs *regs) { char *i_name; + struct dentry * dentry; int retval; + if (strncmp (bprm->buf, "