From 21a0a5d37d1b5f5888120cb9f26e36ccf587eeea Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Fri, 23 Nov 2007 15:11:06 -0500 Subject: [PATCH] Import pre2.0.13 --- Documentation/00-INDEX | 69 + Documentation/Changes | 60 +- Documentation/Configure.help | 12 +- Documentation/cdrom/00-INDEX | 29 + Documentation/cdrom/mcdx | 56 +- Documentation/filesystems/00-INDEX | 16 + Documentation/isdn/00-INDEX | 21 + Documentation/modules.txt | 25 +- Documentation/networking/00-INDEX | 31 + Documentation/networking/Configurable | 33 + Documentation/smp.tex | 2 +- Documentation/watchdog.txt | 5 +- Makefile | 2 +- README | 15 +- arch/i386/defconfig | 2 +- arch/i386/kernel/irq.c | 11 +- drivers/block/Config.in | 6 +- drivers/block/ide.c | 2 +- drivers/block/xd.c | 2 +- drivers/cdrom/mcdx.c | 2710 +++++++++++++++---------- drivers/cdrom/sbpcd.c | 80 +- drivers/char/ChangeLog | 50 +- drivers/char/Config.in | 2 +- drivers/char/baycom.c | 510 +++-- drivers/char/pty.c | 2 + drivers/char/random.c | 302 ++- drivers/char/selection.c | 4 + drivers/char/serial.c | 45 +- drivers/char/tty_io.c | 13 + drivers/char/vesa_blank.c | 8 +- drivers/net/lance.c | 8 +- drivers/net/smc-ultra.c | 8 +- drivers/scsi/BusLogic.c | 259 +-- drivers/scsi/BusLogic.h | 71 +- drivers/scsi/Config.in | 6 +- drivers/scsi/README.BusLogic | 10 +- drivers/scsi/in2000.readme | 42 + drivers/scsi/qlogicisp.c | 12 +- drivers/scsi/scsi.h | 3 + fs/Config.in | 3 + fs/file_table.c | 9 +- fs/nfs/rpcsock.c | 4 +- fs/read_write.c | 4 +- fs/smbfs/dir.c | 17 - fs/smbfs/file.c | 17 - fs/smbfs/inode.c | 17 - fs/smbfs/ioctl.c | 18 - fs/smbfs/mmap.c | 17 - fs/smbfs/proc.c | 20 +- fs/smbfs/sock.c | 17 - include/asm-i386/resource.h | 4 +- include/linux/baycom.h | 5 + include/linux/interrupt.h | 1 + include/linux/mcdx.h | 195 +- include/linux/netdevice.h | 2 +- include/linux/random.h | 3 + include/linux/rpcsock.h | 4 +- include/linux/sbpcd.h | 10 + include/linux/smb.h | 18 - include/linux/smb_fs_i.h | 17 - include/linux/smb_mount.h | 2 - include/linux/uio.h | 5 +- include/net/ip_masq.h | 8 +- include/net/sock.h | 5 +- kernel/sys.c | 66 - mm/mmap.c | 82 + mm/vmscan.c | 8 +- net/Config.in | 6 +- net/core/dev.c | 17 +- net/core/skbuff.c | 3 +- net/ipv4/Config.in | 5 +- net/ipv4/arp.c | 39 +- net/ipv4/ip_forward.c | 2 +- net/ipv4/ip_input.c | 2 +- net/ipv4/ip_masq.c | 63 +- net/ipv4/ip_output.c | 201 +- net/ipv4/tcp_input.c | 61 +- net/ipv4/tcp_output.c | 35 +- net/netsyms.c | 1 + net/socket.c | 8 +- scripts/tkgen.c | 8 +- 81 files changed, 3540 insertions(+), 2033 deletions(-) create mode 100644 Documentation/00-INDEX create mode 100644 Documentation/cdrom/00-INDEX create mode 100644 Documentation/filesystems/00-INDEX create mode 100644 Documentation/isdn/00-INDEX create mode 100644 Documentation/networking/00-INDEX create mode 100644 Documentation/networking/Configurable diff --git a/Documentation/00-INDEX b/Documentation/00-INDEX new file mode 100644 index 000000000000..1a6fb3b904a6 --- /dev/null +++ b/Documentation/00-INDEX @@ -0,0 +1,69 @@ +This is a brief list of all the files in ./linux/Documentation and what +they contain. If you add a documentation file, please list it here in +alphabetical order as well. Note that subdirectories have their own +index files too. + Thanks -- Paul. + +00-INDEX + - this file. +BUG-HUNTING + - brute force method of doing binary search of patches to find bug. +Changes + - list of changes that break older software packages. +CodingStyle + - how the boss likes the C code in the kernel to look. +Configure.help + - text file that is used for help when you run "make config" +SMP.txt + - notes, and "To Fix" list for multi-processor Linux. (see smp.tex) +cdrom/ + - directory with information on the CD-ROM drivers that Linux has. +devices.tex + - TeX source listing of all the nodes in /dev/ with major minor #'s +devices.txt + - plain ASCII listing of all the nodes in /dev/ with major minor #'s +digiboard.txt + - info on the Digiboard PC/X{i,e,eve} multiport boards. +filesystems/ + - directory with info on the various filesystems that Linux supports. +ide.txt + - important info for users of ATA devices (IDE/EIDE disks and CD-ROMS) +initrd.txt + - how to use the RAM disk as an initial/temporary root filesystem. +ioctl-number.txt + - how to implement and register device/driver ioctl calls. +isdn/ + - directory with info on the linux ISDN support, and supported cards. +java.txt + - info on the in-kernel binary support for Java(tm) +locks.txt + - info on file locking implementations, flock() vs. fcntl(), etc. +magic-number.txt + - list of magic numbers used to mark/protect kernel data structures. +mandatory.txt + - info on the linux implementation of Sys V mandatory file locking. +modules.txt + - short guide on how to make kernel parts into loadable modules +networking/ + - directory with info on various linux networking aspects. +nfsroot.txt + - short guide on setting up a diskless box with NFS root filesystem +oops-tracing.txt + - how to decode those nasty internal kernel error dump messages. +ramdisk.txt + - short guide on how to set up and use the RAM disk. +riscom8.txt + - notes on using the RISCom/8 multi-port serial driver. +rtc.txt + - notes on how to use the Real Time Clock (aka CMOS clock) driver. +scsi.txt + - short blurb on using SCSI support as a module. +smp.tex + - TeX document describing implementation of Multiprocessor Linux +svga.txt + - short guide on selecting video modes at boot via VGA BIOS. +unicode.txt + - info on the Unicode character/font mapping used in Linux. +watchdog.txt + - how to auto-reboot Linux if it has "fallen and can't get up". ;-) + diff --git a/Documentation/Changes b/Documentation/Changes index dc82670f2430..139be9610e03 100644 --- a/Documentation/Changes +++ b/Documentation/Changes @@ -18,7 +18,7 @@ and was originally written and maintained by Alessandro Sigala Taylor. Check out http://www.cviog.uga.edu/LinuxBleed.html if you prefer a HTML-ized shopping list. -Last updated: June 1, 1996. +Last updated: June 5, 1996. Current Author: Chris Ricker (gt1355b@prism.gatech.edu). Current Releases @@ -34,7 +34,7 @@ Current Releases - Termcap 2.0.8 - Procps 0.99a - Gpm 1.09 -- sysvinit 2.62 +- SysVinit 2.62 - Util-linux 2.5 Upgrade notes @@ -55,6 +55,21 @@ distributions like Caldera). If you're running one of these, edit /etc/sysconfig/network-scripts/ifup-lo, changing the line `route add -net $(IPADDR)' to `route add -net 127.0.0.0' and you should be fine. +Booting Changes +=============== + + The boot stuff in 1.3.x (for arch/i386) has been enhanced so that it +now can load bigger kernels (bzImage) and that the loaders now can load +an initial ramdisk (initrd). For initrd see Documentation/initrd.txt. +For building bigger kernels use one of the following make targets: +bzImage, bzlilo, bzdisk (equivalent to make targets zImage, zlilo, and +zdisk respectively). If you want or need to use the new features +you'll need to upgrade your bootloaders. Lilo can be found at +ftp://lrcftp.epfl.ch/pub/linux/local/lilo/lilo.19.tar.gz. LOADLIN is at +ftp://sunsite.unc.edu/pub/Linux/system/Linux-boot/lodlin16.tgz. If +you're using more unusual loaders like SysLinux or etherboot, the +latest versions are 1.3 and 2.0, respectively. + The Linux C Library =================== @@ -154,8 +169,8 @@ PPP driver latest stable release is 2.2.0f and is available at ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/ppp/ppp-2.2.0f.tar.gz. -Named pipes -=========== +Named pipes (SysVinit) +====================== Linux's handling of named pipes changed (it now does it The Right Way instead of the SunOS way ;-). This broke some programs that depended @@ -164,9 +179,7 @@ or earlier, you will probably get a weird error on shutdown in which your computer shuts down fine but "INIT: error reading initrequest" or words to that effect scroll across your screen hundreds of times. To fix, upgrade to -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.62.tar.gz -ftp://tsx-11.mit.edu/pub/linux/sources/sbin/sysvinit-2.62.tar.gz -ftp://ftp.cistron.nl/pub/people/miquels/software/sysvinit-2.62.tar.gz. +ftp://ftp.cistron.nl/pub/people/miquels/debian/sysvinit-2.62.tar.gz. If you're trying to run NCSA httpd, you have to set pre-spawning of daemons to zero, as it incorrectly assumes SunOS behavior. I recommend @@ -187,6 +200,17 @@ with the Hylafax distribution and change the line changing them to read-write) will fix any program that is broken because of this change. +File Locking (Sendmail) +======================= + + As of pre2.0.6 (aka 1.99.6), mixed-style file locking is no longer +allowed. For example, a file cannot be simultaneously locked with +`flock' (BSD-style) and `lockf' (SYSV-style). Among the programs this +has impacted are older sendmails. If you get a message that sendmail +cannot lock aliases.dir (or other files), you'll need to upgrade to at +least 8.7.x. The latest sendmail is at +ftp://ftp.cs.berkeley.edu/ucb/src/sendmail/sendmail.8.7.5.tar.gz. + Uugetty ======= @@ -299,7 +323,7 @@ Tcsh ==== If tcsh acts funny, get the source from -ftp://tesla.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in +ftp://anise.ee.cornell.edu/pub/tcsh and add #define SYSMALLOC in config_f.h before recompiling tcsh. Binaries can be found in ftp://sunsite.unc.edu/pub/Linux/system/Shells/ and a corrected one will probably wind up there eventually. @@ -351,6 +375,20 @@ This will compile just fine after you copy its mntent.h over to /usr/include/mntent.h. I've uploaded this to sunsite as ftp://sunsite.unc.edu/pub/Linux/system/Admin/quotas-1.51-tar.gz +Process Accounting +================== + + Process accounting support has also been integrated into the new +kernels. To use this feature, you'll need to get +ftp://iguana.hut.fi/pub/linux/Kernel/process_accounting/acct_1.3.73.tar.gz. + +Bdflush +======= + + Bdflush has also been integrated into the new kernels, so those of +you using it on older systems no longer need to hunt for the patches to +implement it once you upgrade to 1.3.x. + APM support =========== @@ -368,7 +406,9 @@ ftp://tsx-11.mit.edu/pub/linux/BETA/ibcs2/ibcs-1.3-960404-ALPHA.tar.gz For a version of Dosemu that works (well, at least as well as DOS ever works ;-), get -ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.8.tgz. +ftp://tsx-11.mit.edu/pub/linux/ALPHA/dosemu/Development/dosemu-0.63.1.19.tgz. +Be sure to follow the instructions in README.newkernels about patching +your include files, or it will not compile. Mtools and Fdutils ================== @@ -500,7 +540,7 @@ ftp://sunsite.unc.edu/pub/Linux/system/Daemons/gpm-1.09.tar.gz SysVinit utilities ================== -ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.60.tar.gz +ftp://sunsite.unc.edu/pub/Linux/system/Daemons/init/sysvinit-2.62.tar.gz Util-linux ========== diff --git a/Documentation/Configure.help b/Documentation/Configure.help index 4057ca90bfeb..955622de7aee 100644 --- a/Documentation/Configure.help +++ b/Documentation/Configure.help @@ -1250,7 +1250,7 @@ CONFIG_SCSI_ADVANSYS whenever you want). If you want to compile it as a module, say M here and read Documentation/modules.txt. -Adaptec AHA152X support +Adaptec AHA152X/2825 support CONFIG_SCSI_AHA152X This is support for a SCSI host adaptor. It is explained in section 3.3 of the SCSI-HOWTO, available via ftp (user: anonymous) at @@ -2992,6 +2992,16 @@ CONFIG_SMB_FS removed from the running kernel whenever you want), say M here and read Documentation/modules.txt. Most people say N, however. +SMB long filename support (EXPERIMENTAL) +CONFIG_SMB_LONG + SMBFS was designed to support long filenames using the LanManager + 2.0 protocol. I had to find out that the support for long filenames + sometimes causes problems, which can even result in kernel OOPSes. I + did not yet find out what the problem is, but hopefully I will find + this bug eventually. As many people seem to run long filenames with + no problems, I leave this support in the kernel as an option. The + careful among you should say N here. + NCP filesystem support (to mount NetWare volumes) CONFIG_NCP_FS NCP (NetWare Core Protocol) is a protocol that runs over IPX and is diff --git a/Documentation/cdrom/00-INDEX b/Documentation/cdrom/00-INDEX new file mode 100644 index 000000000000..a113106084a3 --- /dev/null +++ b/Documentation/cdrom/00-INDEX @@ -0,0 +1,29 @@ +00-INDEX + - this file (info on CD-ROMs and Linux) +aztcd + - info on Aztech/Orchid/Okano/Wearnes/Conrad/CyCDROM driver. +cdrom-standard.tex + - LaTeX document on standardizing the CD-ROM programming interface. +cdu31a + - info on the Sony CDU31A/CDU33A CD-ROM driver. +cm206 + - info on the Philips/LMS cm206/cm260 CD-ROM driver. +gscd + - info on the Goldstar R420 CD-ROM driver. +ide-cd + - info on setting up and using ATAPI (aka IDE) CD-ROMs. +isp16 + - info on the CD-ROM interface on ISP16, MAD16 or Mozart sound card. +mcd + - info on limitations of standard Mitsumi CD-ROM driver. +mcdx + - info on improved Mitsumi CD-ROM driver. +optcd + - info on the Optics Storage 8000 AT CD-ROM driver +sbpcd + - info on the SoundBlaster Pro CD-ROM interface driver. +sjcd + - info on the SANYO CDR-H94A CD-ROM interface driver. +sonycd535 + - info on the Sony CDU-535 (and 531) CD-ROM driver. + diff --git a/Documentation/cdrom/mcdx b/Documentation/cdrom/mcdx index 52a42fd5ca71..fd2c37321a97 100644 --- a/Documentation/cdrom/mcdx +++ b/Documentation/cdrom/mcdx @@ -1,46 +1,44 @@ -This actually is an `improved' driver for the Mitsumi CD-ROM drives. +This is a first attempt to create an `improved' driver for the Mitsumi drives. +It is able to "live together" with mcd.c, if you have at least two Mitsumi +drives: each driver can use his own drive. -We are using the major device number 20 for it. So, you have to do +To allow this "coexistence" as long as mcdx.c is not a superset of mcd.c, +this driver has to use its own device files. We use MAJOR 20 for it. So, +you have to do -~# mknod /dev/mcdx0 b 20 0 -~# mknod /dev/mcdx1 b 20 1 + # mknod /dev/mcdx0 b 20 0 + # mknod /dev/mcdx1 b 20 1 and so on, one entry for each drive to support, once. -If you are using the driver as a module, you can specify the ports and IRQs -like: +If you are using the driver as a module, you can specify your ports and IRQs +like - # insmod mcdx.o mcdx=0x300,11 + # insmod mcdx.o mcdx=0x300,11,0x304,5 -and so on ("address,IRQ" pairs). When You intend to use more then one -drive, it's necessary to edit the mcdx.h file found in -/usr/src/linux/include/linux. Instead of providing the values on the -command line, You can "hardwire" them all in mcdx.h. The command line -values take precedence over the values in mcdx.h. - -WARNING: BE CAREFUL TO SUPPLY THE CORRECT VALUES OTHERWISE THE WHOLE SYSTEM -WILL HANG DURING BOOT-UP OR LOADING OF THE DRIVER!!! +and so on ("address,IRQ" pairs). +This will override the configuration in mcdx.h. This driver: - o Handles XA and multi session CDs as well as ordinary CDs. - o Supports up to 5 drives (of course, you'll need free - IRQs, i/o ports and slots). - o Uses *much* less kernel memory than the standard mcd driver. - o Plays audio like the `old' driver. + o handles XA (and hopefully) multi session CDs as well as + ordinary CDs; + o supports up to 5 drives (of course, you'll need free + IRQs, i/o ports and slots); + o uses much less kernel memory than the standard mcd driver + (no extra driver internal buffers!). + o plays audio (like the `old' driver, I hope) This version doesn't support yet: - o Shared IRQs, due to the fact that otherwise it wouldn't be - possible to distinguish the drives issuing the interrupt in the - corresponding handling routine. + o shared IRQs (but it seems to be possible - I've successfully + connected two drives to the same irq. So it's `only' a + problem of the driver.) This driver never will: - o Read digital audio (i.e. copy directly), due to missing - hardware features. - o Do DMA transfers. This is simply far less efficient with such - a slow device. Further, the SoundBlaster interfaces doesn't - support it, so it's not worth the effort. + o Read digital audio (i.e. copy directly), due to missing + hardware features. + -1996/05/20 Marcin Dalecki +heiko@lotte.sax.de diff --git a/Documentation/filesystems/00-INDEX b/Documentation/filesystems/00-INDEX new file mode 100644 index 000000000000..edb8c52124eb --- /dev/null +++ b/Documentation/filesystems/00-INDEX @@ -0,0 +1,16 @@ +00-INDEX + - this file (info on some of the filesystems supported by linux). +affs.txt + - info and mount options for the Amiga Fast File System. +hpfs.txt + - info and mount options for the OS/2 HPFS. +ncpfs.txt + - info on Novell Netware(tm) filesystem using NCP protocol. +smbfs.txt + - info on using filesystems with the SMB protocol (Win 3.11, Win NT) +sysv-fs.txt + - info on the SystemV/Coherent filesystem. +umsdos.txt + - info on the umsdos extensions to the msdos filesystem. +vfat.txt + - info on using the VFAT filesystem used in Win NT and Win 95 diff --git a/Documentation/isdn/00-INDEX b/Documentation/isdn/00-INDEX new file mode 100644 index 000000000000..b707c346d48b --- /dev/null +++ b/Documentation/isdn/00-INDEX @@ -0,0 +1,21 @@ +00-INDEX + - this file (info on ISDN implementation for Linux) +CREDITS + - list of the kind folks that brought you this stuff. +INTERFACE + - description of Linklevel and Hardwarelevel ISDN interface. +README + - general info on what you need and what to do for Linux ISDN. +README.audio + - info for running audio over ISDN. +README.icn + - info on the ICN-ISDN-card and its driver. +README.pcbit + - info on the PCBIT-D ISDN adapter and driver. +README.syncppp + - info on running Sync PPP over ISDN. +README.teles + - info on driver for Teles compatible ISDN cards. +syncPPP.FAQ + - frequently asked questions about running PPP over ISDN. + diff --git a/Documentation/modules.txt b/Documentation/modules.txt index 8f48fed0a401..12593dcb74d6 100644 --- a/Documentation/modules.txt +++ b/Documentation/modules.txt @@ -6,8 +6,15 @@ and use modules. In this kernel you also have a possibility to create modules that are less dependent on the kernel version. This option can be selected during "make config", by enabling CONFIG_MODVERSIONS. -Note: If you enable CONFIG_MODVERSIONS, you will need some utilities - from the latest module support package: "modules-1.1.8*.tar.gz"! + +Note: You should ensure that the modules-X.Y.Z.tar.gz you are using +is the most up to date one for this kernel. The "X.Y.Z" will reflect +the kernel version at the time of the release of the modules package. +Some older modules packages aren't aware of some of the newer modular +features that the kernel now supports. (If you are unsure, you can +usually find out what the current release of the modules-X.Y.Z.tar.gz +package is by looking up the URL listed for "Bjorn Ekwall" in the +file ./linux/CREDITS) Anyway, your first step is to compile the kernel, as explained in the file README. It generally goes like: @@ -38,12 +45,8 @@ The set of modules is rapidly increasing, but so far these are known: Most low-level SCSI drivers: (i.e. aha1542, in2000) All SCSI high-level drivers: disk, tape, cdrom, generic. - Some ethernet drivers: - plip, slip, dummy, - de600, de620 - 3c501, 3c509 - eexpress, depca, - ewrk3, apricot + Most ethernet drivers: (too many to list, please see the file + ./Documentation/networking/net-modules.txt) Most CDROM drivers: aztcd: Aztech,Orchid,Okano,Wearnes @@ -80,14 +83,12 @@ Now, after you have made all modules, you can also do: This will copy all newly made modules into subdirectories under "/lib/modules/kernel_release/", where "kernel_release" is something -like 1.1.83, or whatever the current kernel version is... +like 2.0.1, or whatever the current kernel version is... Nifty features: -If you have installed the utilities from "modules-1.1.8*.tar.gz", -you will have access to two new utilities: "modprobe" and "depmod" - +You have access to two utilities: "modprobe" and "depmod". Using the modprobe utility, you can load any module like this: /sbin/modprobe module diff --git a/Documentation/networking/00-INDEX b/Documentation/networking/00-INDEX new file mode 100644 index 000000000000..f5182b1c7cc7 --- /dev/null +++ b/Documentation/networking/00-INDEX @@ -0,0 +1,31 @@ +00-INDEX + - this file +3c505.txt + - information on the 3Com EtherLink Plus (3c505) driver. +Configurable + - info on some of the configurable network parameters +alias.txt + - info on using alias network devices +arcnet-hardware.txt + - tons of info on arcnet, hubs, arcnet card jumper settings, etc. +arcnet.txt + - info on the using the arcnet driver itself. +ax25.txt + - info on using AX.25 and NET/ROM code for Linux +framerelay.txt + - info on using Frame Relay/Data Link Connection Identifier (DLCI). +ncsa-telnet + - notes on how NCSA telnet (DOS) breaks with MTU discovery enabled. +net-modules.txt + - info and "insmod" parameters for all network driver modules. +ppp.txt + - info on what software you should use to run PPP. +tcp.txt + - short blurb on how TCP output takes place. +tulip.txt + - info on using DEC 21040/21041/21140 based PCI ethernet cards. +vortex.txt + - info on using 3Com Vortex (3c590, 3c592, 3c595, 3c597) e'net cards. +z8530drv.txt + - info about Linux driver for Z8530 based HDLC cards for AX.25 + diff --git a/Documentation/networking/Configurable b/Documentation/networking/Configurable new file mode 100644 index 000000000000..48be78ba3610 --- /dev/null +++ b/Documentation/networking/Configurable @@ -0,0 +1,33 @@ + +There are a few network parameters that can be tuned to better match +the kernel to your system hardware and intended usage. The defaults +are usually a good choice for 99% of the people 99% of the time, but +you should be aware they do exist and can be changed. + +The current list of parameters can be found in the file: + + ./linux/net/TUNABLE + +Some of these are accessible via the sysctl interface, and many more are +scheduled to be added in this way. For example, some parameters related +to Address Resolution Protocol (ARP) are very easily viewed and altered. + + # cat /proc/sys/net/ipv4/arp_timeout + 6000 + # echo 7000 > /proc/sys/net/ipv4/arp_timeout + # cat /proc/sys/net/ipv4/arp_timeout + 7000 + +Others are already accessible via the related user space programs. +For example, MAX_WINDOW has a default of 32k which is a good choice for +modern hardware, but if you have a slow (8 bit) ethercard and/or a slow +machine, then this will be far too big for the card to keep up with fast +Tx'ing machines on the same net, resulting in overruns and receive errors. +A value of about 4k would be more appropriate, which can be set via: + + # route add -net 192.168.3.0 window 4096 + +The remainder of these can only be presently changed by altering a #define +in the related header file. This means an edit and recompile cycle. + + Paul Gortmaker 06/96 diff --git a/Documentation/smp.tex b/Documentation/smp.tex index cfb30b43da9d..ea582088c34d 100644 --- a/Documentation/smp.tex +++ b/Documentation/smp.tex @@ -67,7 +67,7 @@ effectively atomic with respect to other processes and greatly simplifies many operation. Secondly interrupts may pre-empt a kernel running process, but will always return to that process. A process in kernel mode may disable interrupts on the processor and guarantee such an interruption will -not occur. The final guarantee is that an interrupt will not bne pre-empted +not occur. The final guarantee is that an interrupt will not be pre-empted by a kernel task. That is interrupts will run to completion or be pre-empted by other interrupts only. diff --git a/Documentation/watchdog.txt b/Documentation/watchdog.txt index 376911245281..940313a9448b 100644 --- a/Documentation/watchdog.txt +++ b/Documentation/watchdog.txt @@ -25,8 +25,9 @@ degrees farenheit. Each read returns a single byte giving the temperature. The third interface logs kernel messages on additional alert events. -At the moment only the software watchdog is available in the standard -kernel. +Both software and hardware watchdog drivers are available in the standard +kernel. If you are using the software watchdog, you probably also want +to use "panic=60" as a boot argument as well. Features -------- diff --git a/Makefile b/Makefile index bfce14d5a0f6..bba28043fe0e 100644 --- a/Makefile +++ b/Makefile @@ -1,6 +1,6 @@ VERSION = 1 PATCHLEVEL = 99 -SUBLEVEL = 12 +SUBLEVEL = 13 ARCH = i386 diff --git a/README b/README index 3e7ba5825516..28be1c7350ef 100644 --- a/README +++ b/README @@ -35,8 +35,9 @@ DOCUMENTATION: system: there are much better sources available. - There are various readme's in the kernel Documentation/ subdirectory: - these are mainly used for kernel developers and some very kernel-specific - installation notes for some drivers for example. + these typically contain kernel-specific installation notes for some + drivers for example. See ./Documentation/00-INDEX for a list of what + is contained in each file. INSTALLING the kernel: @@ -105,7 +106,7 @@ CONFIGURING the kernel: - having unnecessary drivers will make the kernel bigger, and can under some circumstances lead to problems: probing for a nonexistent controller card may confuse your other controllers - - compiling the kernel with "-m486" for a number of 486-specific + - compiling the kernel with "Processor type" set higher than 386 will result in a kernel that does NOT work on a 386. The kernel will detect this on bootup, and give up. - A kernel with math-emulation compiled in will still use the @@ -183,7 +184,10 @@ COMPILING the kernel: IF SOMETHING GOES WRONG: - - if you have problems that seem to be due to kernel bugs, please mail + - if you have problems that seem to be due to kernel bugs, please check + the file MAINTAINERS to see if there is a particualr person associated + with the part of the kernel that you are having trouble with. If there + isn't anyone listed there, then the second best thing is to mail them to me (Linus.Torvalds@Helsinki.FI), and possibly to any other relevant mailing-list or to the newsgroup. The mailing-lists are useful especially for SCSI and NETworking problems, as I can't test @@ -210,7 +214,8 @@ IF SOMETHING GOES WRONG: incomprehensible to you, but it does contain information that may help debugging the problem. The text above the dump is also important: it tells something about why the kernel dumped code (in - the above example it's due to a bad kernel pointer) + the above example it's due to a bad kernel pointer). More information + on making sense of the dump is in Documentation/oops-tracing.txt - You can use the "ksymoops" program to make sense of the dump. Find the C++ sources under the scripts/ directory to avoid having to do diff --git a/arch/i386/defconfig b/arch/i386/defconfig index b64e0a678c38..e6ede18d7567 100644 --- a/arch/i386/defconfig +++ b/arch/i386/defconfig @@ -37,7 +37,7 @@ CONFIG_BLK_DEV_FD=y CONFIG_BLK_DEV_IDE=y # -# Please see drivers/block/README.ide for help/info on IDE drives +# Please see Documentation/ide.txt for help/info on IDE drives # # CONFIG_BLK_DEV_HD_IDE is not set CONFIG_BLK_DEV_IDECD=y diff --git a/arch/i386/kernel/irq.c b/arch/i386/kernel/irq.c index 27ca35e39a78..ba14e946ba77 100644 --- a/arch/i386/kernel/irq.c +++ b/arch/i386/kernel/irq.c @@ -343,6 +343,7 @@ int get_smp_prof_list(char *buf) { asmlinkage void do_IRQ(int irq, struct pt_regs * regs) { struct irqaction * action = *(irq + irq_action); + int do_random = 0; #ifdef __SMP__ if(smp_threads_ready && active_kernel_processor!=smp_processor_id()) @@ -354,11 +355,12 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) int_count[smp_processor_id()][irq]++; #endif while (action) { - if (action->flags & SA_SAMPLE_RANDOM) - add_interrupt_randomness(irq); + do_random |= action->flags; action->handler(irq, action->dev_id, regs); action = action->next; } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); } /* @@ -369,6 +371,8 @@ asmlinkage void do_IRQ(int irq, struct pt_regs * regs) asmlinkage void do_fast_IRQ(int irq) { struct irqaction * action = *(irq + irq_action); + int do_random = 0; + #ifdef __SMP__ /* IRQ 13 is allowed - that's a flush tlb */ if(smp_threads_ready && active_kernel_processor!=smp_processor_id() && irq!=13) @@ -380,9 +384,12 @@ asmlinkage void do_fast_IRQ(int irq) int_count[smp_processor_id()][irq]++; #endif while (action) { + do_random |= action->flags; action->handler(irq, action->dev_id, NULL); action = action->next; } + if (do_random & SA_SAMPLE_RANDOM) + add_interrupt_randomness(irq); } int setup_x86_irq(int irq, struct irqaction * new) diff --git a/drivers/block/Config.in b/drivers/block/Config.in index 24ebfe260c15..fb673fbfd2bb 100644 --- a/drivers/block/Config.in +++ b/drivers/block/Config.in @@ -6,7 +6,7 @@ comment 'Floppy, IDE, and other block devices' tristate 'Normal floppy disk support' CONFIG_BLK_DEV_FD bool 'Enhanced IDE/MFM/RLL disk/cdrom/tape support' CONFIG_BLK_DEV_IDE -comment 'Please see drivers/block/README.ide for help/info on IDE drives' +comment 'Please see Documentation/ide.txt for help/info on IDE drives' if [ "$CONFIG_BLK_DEV_IDE" = "n" ]; then bool 'Old harddisk (MFM/RLL/IDE) driver' CONFIG_BLK_DEV_HD_ONLY else @@ -25,7 +25,9 @@ else bool ' ALI M1439/M1445 support' CONFIG_BLK_DEV_ALI14XX bool ' DTC-2278 support' CONFIG_BLK_DEV_DTC2278 bool ' Holtek HT6560B support' CONFIG_BLK_DEV_HT6560B - bool ' PROMISE DC4030 support (ALPHA)' CONFIG_BLK_DEV_PROMISE + if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool ' PROMISE DC4030 support (EXPERIMENTAL)' CONFIG_BLK_DEV_PROMISE + fi bool ' QDI QD6580 support' CONFIG_BLK_DEV_QD6580 bool ' UMC 8672 support' CONFIG_BLK_DEV_UMC8672 fi diff --git a/drivers/block/ide.c b/drivers/block/ide.c index b3ea7ada81e3..01497f130433 100644 --- a/drivers/block/ide.c +++ b/drivers/block/ide.c @@ -3114,7 +3114,7 @@ static int init_irq (ide_hwif_t *hwif) * Allocate the irq, if not already obtained for another hwif */ if (!match || match->irq != hwif->irq) { - if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT|SA_SAMPLE_RANDOM, hwif->name, hwgroup)) { + if (request_irq(hwif->irq, ide_intr, SA_INTERRUPT, hwif->name, hwgroup)) { if (!match) kfree(hwgroup); restore_flags(flags); diff --git a/drivers/block/xd.c b/drivers/block/xd.c index 455a26bcf71e..efe8df595bb8 100644 --- a/drivers/block/xd.c +++ b/drivers/block/xd.c @@ -22,7 +22,7 @@ * */ - +#include #include #include #include diff --git a/drivers/cdrom/mcdx.c b/drivers/cdrom/mcdx.c index 3481b2b95d50..78a0a3fc0291 100644 --- a/drivers/cdrom/mcdx.c +++ b/drivers/cdrom/mcdx.c @@ -1,13 +1,20 @@ /* * The Mitsumi CDROM interface + * Copyright (C) 1995 1996 Heiko Schlittermann + * VERSION: 2.14(hs) * - * (H) Hackright 1996 by Marcin Dalecki - * - * Based on previous work (as of version 1.9) done by: - * Copyright (C) 1995 Heiko Schlittermann + * ... anyway, I'm back again, thanks to Marcin, he adopted + * large portions of my code (at least the parts containing + * my main thoughts ...) + * + ****************** H E L P ********************************* + * If you ever plan to update your CD ROM drive and perhaps + * want to sell or simply give away your Mitsumi FX-001[DS] + * -- Please -- + * mail me (heiko@lotte.sax.de). When my last drive goes + * ballistic no more driver support will be available from me! + ************************************************************* * - * VERSION: 2.5 - * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2, or (at your option) @@ -31,28 +38,19 @@ * Jon Tombs, Bjorn Ekwall (module support) * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) * Gerd Knorr (he lent me his PhotoCD) - * Nils Faerber and Roger E. Wolff (extensively tested the LU portion) - * Andreas Kies (testing the mysterious hangups) + * Nils Faerber and Roger E. Wolff (extensivly tested the LU portion) + * Andreas Kies (testing the mysterious hang up's) + * Heiko Eissfeld (VERIFY_READ/WRITE) + * Marcin Dalecki (improved performance, shortened code) * ... somebody forgotten? - * - * 2.1 1996/04/29 Marcin Dalecki - * Far too many bugfixes/changes to mention them all separately. - * 2.2 1996/05/06 Marcin Dalecki - * Mostly fixes to some silly bugs in the previous release :-). - * (Hi Michael Thimm! Thank's for lending me Your's double speed drive.) - * 2.3 1996/05/15 Marcin Dalecki - * Fixed stereo support. - * 2.5 1996/05/19 Marcin Dalecki - * Overall performance increased by a factor of 1.25 :-). - * I hope Heiko doesn't mind the Hackright change, but there isn't much of - * code left from his version 1.9 anymore. - * Start speedup for Work(Man|Bone). - * - * NOTE: - * There will be probably a 3.0 adhering to the new generic non ATAPI - * CDROM interface in the unforeseen future. + * */ -#define VERSION "2.5" + + +#if RCS +static const char *mcdx_c_version + = "$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $"; +#endif #include #include @@ -71,151 +69,214 @@ #define MAJOR_NR MITSUMI_X_CDROM_MAJOR #include -/* - * for compatible parameter passing with "insmod" - */ -#define mcdx_drive_map mcdx +/* for compatible parameter passing with "insmod" */ +#define mcdx_drive_map mcdx #include -#define REQUEST_SIZE 400 +#ifndef HZ +#error HZ not defined +#endif -enum drivemodes { - TOC, DATA, RAW, COOKED -}; +#define xwarn(fmt, args...) printk(KERN_WARNING MCDX " " fmt, ## args) -#define MODE0 0x00 -#define MODE1 0x01 -#define MODE2 0x02 +#if !MCDX_QUIET +#define xinfo(fmt, args...) printk(KERN_INFO MCDX " " fmt, ## args) +#else +#define xinfo(fmt, args...) { ; } +#endif -#define DOOR_LOCK 0x01 -#define DOOR_UNLOCK 0x00 +#if MCDX_DEBUG +#define xtrace(lvl, fmt, args...) \ + { if (lvl > 0) \ + { printk(KERN_DEBUG MCDX ":: " fmt, ## args); } } +#define xdebug(fmt, args...) printk(KERN_DEBUG MCDX ":: " fmg, ## args) +#else +#define xtrace(lvl, fmt, args...) { ; } +#define xdebug(fmt, args...) { ; } +#endif -/* - * Structs used to gather info reported by the drive. - */ +/* CONSTANTS *******************************************************/ + +/* Following are the number of sectors we _request_ from the drive + every time an access outside the already requested range is done. + The _direct_ size is the number of sectors we're allowed to skip + directly (perfoming a read instead of requesting the new sector + needed */ +const int REQUEST_SIZE = 800; /* should be less then 255 * 4 */ +const int DIRECT_SIZE = 400; /* should be less then REQUEST_SIZE */ + +const unsigned long ACLOSE_INHIBIT = 800; /* 1/100 s of autoclose inhibit */ + +enum drivemodes { TOC, DATA, RAW, COOKED }; +enum datamodes { MODE0, MODE1, MODE2 }; +enum resetmodes { SOFT, HARD }; +const int SINGLE = 0x01; /* single speed drive (FX001S, LU) */ +const int DOUBLE = 0x02; /* double speed drive (FX001D, ..? */ +const int DOOR = 0x04; /* door locking capability */ +const int MULTI = 0x08; /* multi session capability */ + +const unsigned char READ1X = 0xc0; +const unsigned char READ2X = 0xc1; + + +/* DECLARATIONS ****************************************************/ struct s_subqcode { - u_char adr:4; - u_char ctrl:4; - u_char tno; - u_char index; + unsigned char control; + unsigned char tno; + unsigned char index; struct cdrom_msf0 tt; - u_char dummy; /* padding for matching the returned struct */ struct cdrom_msf0 dt; }; +struct s_diskinfo { + unsigned int n_first; + unsigned int n_last; + struct cdrom_msf0 msf_leadout; + struct cdrom_msf0 msf_first; +}; + struct s_multi { unsigned char multi; struct cdrom_msf0 msf_last; }; -struct s_play { - struct cdrom_msf0 start; - struct cdrom_msf0 stop; +struct s_version { + unsigned char code; + unsigned char ver; }; -/* - * Per drive/controller stuff. - */ -struct s_drive_stuff { - struct wait_queue *busyq; - - /* flags */ - u_char used:1; /* locks on open, we allow only - exclusive usage of the drive */ - u_char introk:1; /* status of last irq operation */ - u_char busy:1; /* drive performs an operation */ - u_char eject_sw:1; /* 1 - eject on last close (default 0) */ - u_char autoclose:1; /* 1 - close the door on open (default 1) */ - u_char xxx:1; /* set if changed, reset while open */ - u_char xa:1; /* 1 if xa disk */ - u_char audio:1; /* 1 if audio disk */ - u_char eom:1; /* end of media reached during read request */ - - /* drives capabilities */ - u_char door:1; /* can close/lock tray */ - u_char multi_cap:1; /* multi-session capable */ - u_char double_speed:1; /* double speed drive */ +/* Per drive/controller stuff **************************************/ +struct s_drive_stuff { + /* waitquenes */ + struct wait_queue *busyq; + struct wait_queue *lockq; + struct wait_queue *sleepq; + + /* flags */ + volatile int introk; /* status of last irq operation */ + volatile int busy; /* drive performs an operation */ + volatile int lock; /* exclusive usage */ + int eject_sw; /* 1 - eject on last close (default 0) */ + int autoclose; /* 1 - close the door on open (default 1) */ + /* cd infos */ - u_int first; - u_int last; - struct cdrom_msf0 msf_leadout; + struct s_diskinfo di; struct s_multi multi; - - struct s_subqcode *toc; /* first entry of the toc array */ - struct s_play resume; /* where to resume after pause */ - - int audiostatus; + struct s_subqcode* toc; /* first enty of the toc array */ + struct s_subqcode start; + struct s_subqcode stop; + int xa; /* 1 if xa disk */ + int audio; /* 1 if audio disk */ + int audiostatus; /* `buffer' control */ - u_char valid:1; - int pending; - int border; /* the last sector in sequence we will read, - without reissuing a read command */ - - u_int base; /* base for all registers of the drive */ - int irq; /* irq used by this drive */ - int lastsector; /* last accessible block */ + volatile int valid; /* pending, ..., values are valid */ + volatile int pending; /* next sector to be read */ + volatile int low_border; /* first sector not to be skipped direct */ + volatile int high_border; /* first sector `out of area' */ +#ifdef AK2 + volatile int int_err; +#endif /* AK2 */ + + /* adds and odds */ + void* wreg_data; /* w data */ + void* wreg_reset; /* w hardware reset */ + void* wreg_hcon; /* w hardware conf */ + void* wreg_chn; /* w channel */ + void* rreg_data; /* r data */ + void* rreg_status; /* r status */ + + int irq; /* irq used by this drive */ + int minor; /* minor number of this drive */ + int present; /* drive present and its capabilities */ + unsigned char readcmd; /* read cmd depends on single/double speed */ + unsigned char playcmd; /* play should always be single speed */ + unsigned int xxx; /* set if changed, reset while open */ + unsigned int yyy; /* set if changed, reset by media_changed */ + unsigned long ejected; /* time we called the eject function */ + int users; /* keeps track of open/close */ + int lastsector; /* last block accessible */ + int status; /* last operation's error / status */ + int readerrs; /* # of blocks read w/o error */ }; -/* - * Macros for accessing interface registers - */ -#define DATA_REG (stuffp->base) -#define RESET_REG (stuffp->base+1) -#define STAT_REG (stuffp->base+1) -#define CHAN_REG (stuffp->base+3) -/* - * Access to elements of the mcdx_drive_map members - */ -#define PORT 0 -#define IRQ 1 +/* Prototypes ******************************************************/ -/* - * declared in blk.h - */ +/* The following prototypes are already declared elsewhere. They are + repeated here to show what's going on. And to sense, if they're + changed elsewhere. */ + +/* declared in blk.h */ int mcdx_init(void); void do_mcdx_request(void); +int check_mcdx_media_change(kdev_t); -/* - * already declared in init/main - */ +/* already declared in init/main */ void mcdx_setup(char *, int *); -/* - * Indirect exported functions. These functions are exported by their - * addresses, such as mcdx_open and mcdx_close in the - * structure fops. - */ - -/* - * ??? exported by the mcdx_sigaction struct - */ -static void mcdx_intr(int, void *, struct pt_regs *); - -/* - * exported by file_ops - */ -static int mcdx_open(struct inode *, struct file *); -static void mcdx_close(struct inode *, struct file *); -static int mcdx_ioctl(struct inode *, struct file *, - unsigned int, unsigned long); -static int mcdx_media_change(kdev_t); - -static int mcdx_blksize_size[MCDX_NDRIVES]; +/* Indirect exported functions. These functions are exported by their + addresses, such as mcdx_open and mcdx_close in the + structure fops. */ + +/* ??? exported by the mcdx_sigaction struct */ +static void mcdx_intr(int, void *, struct pt_regs*); + +/* exported by file_ops */ +static int mcdx_open(struct inode*, struct file*); +static void mcdx_close(struct inode*, struct file*); +static int mcdx_ioctl(struct inode*, struct file*, unsigned int, unsigned long); + +/* misc internal support functions */ +static void log2msf(unsigned int, struct cdrom_msf0*); +static unsigned int msf2log(const struct cdrom_msf0*); +static unsigned int uint2bcd(unsigned int); +static unsigned int bcd2uint(unsigned char); +static char *port(int*); +static int irq(int*); +static void mcdx_delay(struct s_drive_stuff*, long jifs); +static int mcdx_transfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors); +static int mcdx_xfer(struct s_drive_stuff*, char* buf, int sector, int nr_sectors); + +static int mcdx_config(struct s_drive_stuff*, int); +static int mcdx_closedoor(struct s_drive_stuff*, int); +static int mcdx_requestversion(struct s_drive_stuff*, struct s_version*, int); +static int mcdx_lockdoor(struct s_drive_stuff*, int, int); +static int mcdx_stop(struct s_drive_stuff*, int); +static int mcdx_hold(struct s_drive_stuff*, int); +static int mcdx_reset(struct s_drive_stuff*, enum resetmodes, int); +static int mcdx_eject(struct s_drive_stuff*, int); +static int mcdx_setdrivemode(struct s_drive_stuff*, enum drivemodes, int); +static int mcdx_setdatamode(struct s_drive_stuff*, enum datamodes, int); +static int mcdx_requestsubqcode(struct s_drive_stuff*, struct s_subqcode*, int); +static int mcdx_requestmultidiskinfo(struct s_drive_stuff*, struct s_multi*, int); +static int mcdx_requesttocdata(struct s_drive_stuff*, struct s_diskinfo*, int); +static int mcdx_getstatus(struct s_drive_stuff*, int); +static int mcdx_getval(struct s_drive_stuff*, int to, int delay, char*); +static int mcdx_talk(struct s_drive_stuff*, + const unsigned char* cmd, size_t, + void *buffer, size_t size, + unsigned int timeout, int); +static int mcdx_readtoc(struct s_drive_stuff*); +static int mcdx_playtrk(struct s_drive_stuff*, const struct cdrom_ti*); +static int mcdx_playmsf(struct s_drive_stuff*, const struct cdrom_msf*); +static int mcdx_setattentuator(struct s_drive_stuff*, struct cdrom_volctrl*, int); + +/* static variables ************************************************/ + +static int mcdx_blocksizes[MCDX_NDRIVES]; static int mcdx_drive_map[][2] = MCDX_DRIVEMAP; -static struct s_drive_stuff *mcdx_stuffp[MCDX_NDRIVES]; -static struct s_drive_stuff *mcdx_irq_map[16] = -{0, 0, 0, 0, 0, 0, 0, 0, - 0, 0, 0, 0, 0, 0, 0, 0}; +static struct s_drive_stuff* mcdx_stuffp[MCDX_NDRIVES]; +static struct s_drive_stuff* mcdx_irq_map[16] = + {0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0}; -static struct file_operations mcdx_fops = -{ +static struct file_operations mcdx_fops = { NULL, /* lseek - use kernel default */ block_read, /* read - general block-dev read */ - block_write, /* write - general block-dev write */ + block_write, /* write - general block-dev write */ NULL, /* no readdir */ NULL, /* no select */ mcdx_ioctl, /* ioctl() */ @@ -223,1118 +284,1647 @@ static struct file_operations mcdx_fops = mcdx_open, /* open() */ mcdx_close, /* close() */ NULL, /* fsync */ - NULL, /* fasync */ - mcdx_media_change, /* media_change */ - NULL /* revalidate */ + NULL, /* fasync */ + check_mcdx_media_change, /* media_change */ + NULL /* revalidate */ }; -/* - * Misc number converters - */ +/* KERNEL INTERFACE FUNCTIONS **************************************/ -static unsigned int bcd2uint(unsigned int c) -{ - return (c >> 4) * 10 + (c & 0x0f); -} +static int +mcdx_ioctl( + struct inode* ip, struct file* fp, + unsigned int cmd, unsigned long arg) +{ + struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; -static unsigned int uint2bcd(unsigned int ival) -{ - return ((ival / 10) << 4) | (ival % 10); -} + if (!stuffp->present) return -ENXIO; + if (!ip) return -EINVAL; -static unsigned int msf2log(const struct cdrom_msf0 *pmsf) -{ - return bcd2uint(pmsf->frame) - + bcd2uint(pmsf->second) * 75 - + bcd2uint(pmsf->minute) * 4500 - - CD_BLOCK_OFFSET; -} + switch (cmd) { + case CDROMSTART: { + xtrace(IOCTL, "ioctl() START\n"); + return 0; + } -/* - * Low level hardware related functions. - */ + case CDROMSTOP: { + xtrace(IOCTL, "ioctl() STOP\n"); + stuffp->audiostatus = CDROM_AUDIO_INVALID; + if (-1 == mcdx_stop(stuffp, 1)) + return -EIO; + return 0; + } -/* - * Return drives status in case of success, -1 otherwise. - * - * First we try to get the status information quickly. - * Then we sleep repeatedly for about 10 usecs, before we finally reach the - * timeout. For this reason this command must be called with the drive being - * locked! - */ -static int get_status(struct s_drive_stuff *stuffp, - unsigned long timeout) -{ - unsigned long bang = jiffies + 2; - timeout += jiffies; + case CDROMPLAYTRKIND: { + int ans; + struct cdrom_ti ti; - do { - if (!(inb(STAT_REG) & MCDX_RBIT_STEN)) { - return (inb(DATA_REG) & 0xff); - } - } while (jiffies < bang); + xtrace(IOCTL, "ioctl() PLAYTRKIND\n"); + if ((ans = verify_area(VERIFY_READ, (void*) arg, sizeof(ti)))) + return ans; + memcpy_fromfs(&ti, (void*) arg, sizeof(ti)); + if ((ti.cdti_trk0 < stuffp->di.n_first) + || (ti.cdti_trk0 > stuffp->di.n_last) + || (ti.cdti_trk1 < stuffp->di.n_first)) + return -EINVAL; + if (ti.cdti_trk1 > stuffp->di.n_last) ti.cdti_trk1 = stuffp->di.n_last; + xtrace(PLAYTRK, "ioctl() track %d to %d\n", ti.cdti_trk0, ti.cdti_trk1); - while (inb(STAT_REG) & MCDX_RBIT_STEN) { - if (jiffies > timeout) - return -1; - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ / 2; - schedule(); - } - return (inb(DATA_REG) & 0xff); -} + return mcdx_playtrk(stuffp, &ti); + } -static void release_toc(struct s_drive_stuff *stuffp) -{ - if (stuffp->toc) { - kfree(stuffp->toc); - stuffp->toc = 0; - } -} + case CDROMPLAYMSF: { + int ans; + struct cdrom_msf msf; -/* Send a command to the drive, wait for the result. - * returns -1 on timeout, drive status otherwise. - * If buffer is not zero, the result (length size) is stored there. - * If buffer is zero the size should be the number of bytes to read - * from the drive. These bytes are discarded. - */ -static int talk(struct s_drive_stuff *stuffp, - const unsigned char command, - void *pars, size_t parslen, - void *buffer, size_t size, - unsigned int timeout) -{ - int st; + xtrace(IOCTL, "ioctl() PLAYMSF\n"); - stuffp->valid = 0; - outb(command, DATA_REG); - if (parslen) - outsb(DATA_REG, pars, parslen); + if ((stuffp->audiostatus == CDROM_AUDIO_PLAY) + && (-1 == mcdx_hold(stuffp, 1))) return -EIO; - if (-1 == (st = get_status(stuffp, timeout))) { - goto end_talk; - } - if (st & MCDX_RBIT_CMDERR) { - printk(KERN_ERR MCDX ": error in command 0x%2x\n", command); - st = -1; - goto end_talk; - } - /* audio status? */ - if (stuffp->audiostatus == CDROM_AUDIO_INVALID) { - stuffp->audiostatus = - (st & MCDX_RBIT_AUDIOBS) ? - CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS; - } else if (stuffp->audiostatus == CDROM_AUDIO_PLAY - && !(st & MCDX_RBIT_AUDIOBS)) { - stuffp->audiostatus = CDROM_AUDIO_COMPLETED; - } - /* media change? */ - if (st & MCDX_RBIT_CHANGED) - stuffp->xxx = 1; - /* now actually get the data */ - while (size--) { - if (-1 == (st = get_status(stuffp, timeout))) { - break; - } - *((char *) buffer) = st; - buffer++; - } - /* The goto's make GCC generate better code. - */ - end_talk: - return st; -} + if ((ans = verify_area( + VERIFY_READ, (void*) arg, sizeof(struct cdrom_msf)))) + return ans; -static int issue_command(struct s_drive_stuff *stuffp, - unsigned char command, - unsigned int timeout) -{ - return talk(stuffp, command, 0, 0, NULL, 0, timeout); -} + memcpy_fromfs(&msf, (void*) arg, sizeof msf); -static inline int set_command(struct s_drive_stuff *stuffp, - const unsigned char command, - void *pars, size_t parlen, - unsigned int timeout) -{ - return talk(stuffp, command, pars, parlen, NULL, 0, timeout); -} + msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0); + msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0); + msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0); -static inline int get_command(struct s_drive_stuff *stuffp, - const unsigned char command, - void *buffer, size_t size, - unsigned int timeout) -{ - return talk(stuffp, command, NULL, 0, buffer, size, timeout); -} + msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1); + msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1); + msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1); -static int request_subq_code(struct s_drive_stuff *stuffp, - struct s_subqcode *sub) -{ - return get_command(stuffp, MCDX_CMD_GET_SUBQ_CODE, - sub, sizeof(struct s_subqcode), 2 * HZ); -} + return mcdx_playmsf(stuffp, &msf); + } -static int request_toc_data(struct s_drive_stuff *stuffp) -{ - char buf[8]; - int ans; + case CDROMRESUME: { + xtrace(IOCTL, "ioctl() RESUME\n"); + return mcdx_playtrk(stuffp, NULL); + } - ans = get_command(stuffp, MCDX_CMD_GET_TOC, buf, sizeof(buf), 2 * HZ); - if (ans == -1) { - stuffp->first = 0; - stuffp->last = 0; - } else { - stuffp->first = bcd2uint(buf[0]); - stuffp->last = bcd2uint(buf[1]); - memcpy(&(stuffp->msf_leadout), buf + 2, 3); - } - return ans; -} + case CDROMREADTOCENTRY: { + struct cdrom_tocentry entry; + struct s_subqcode *tp = NULL; + int ans; -static int set_drive_mode(struct s_drive_stuff *stuffp, enum drivemodes mode) -{ - char value; - if (-1 == get_command(stuffp, MCDX_CMD_GET_DRIVE_MODE, - &value, 1, 5 * HZ)) - return -1; - switch (mode) { - case TOC: - value |= 0x04; - break; - case DATA: - value &= ~0x04; - break; - case RAW: - value |= 0x40; - break; - case COOKED: - value &= ~0x40; - break; - default: - break; - } - return set_command(stuffp, MCDX_CMD_SET_DRIVE_MODE, &value, 1, 5 * HZ); -} + xtrace(IOCTL, "ioctl() READTOCENTRY\n"); -static int config_drive(struct s_drive_stuff *stuffp) -{ - unsigned char buf[2]; - buf[0] = 0x10; /* irq enable */ - buf[1] = 0x05; /* pre, err irq enable */ + if (-1 == mcdx_readtoc(stuffp)) return -1; - if (-1 == set_command(stuffp, MCDX_CMD_CONFIG, buf, - sizeof(buf), 1 * HZ)) - return -1; + if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry)))) return ans; + memcpy_fromfs(&entry, (void *) arg, sizeof(entry)); - buf[0] = 0x02; /* dma select */ - buf[1] = 0x00; /* no dma */ + if (entry.cdte_track == CDROM_LEADOUT) + tp = &stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1]; + else if (entry.cdte_track > stuffp->di.n_last + || entry.cdte_track < stuffp->di.n_first) return -EINVAL; + else tp = &stuffp->toc[entry.cdte_track - stuffp->di.n_first]; - return set_command(stuffp, MCDX_CMD_CONFIG, buf, sizeof(buf), 1 * HZ); -} + if (NULL == tp) xwarn("FATAL.\n"); -/* - * Read the toc entries from the CD. - * Return: -1 on failure, else 0 - */ -int read_toc(struct s_drive_stuff *stuffp) -{ - int trk; - int i; + entry.cdte_adr = tp->control; + entry.cdte_ctrl = tp->control >> 4; - if (stuffp->toc) - return 0; - if (-1 == issue_command(stuffp, MCDX_CMD_HOLD, 2 * HZ)) - return -1; - if (-1 == set_drive_mode(stuffp, TOC)) - return -EIO; + if (entry.cdte_format == CDROM_MSF) { + entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute); + entry.cdte_addr.msf.second = bcd2uint(tp->dt.second); + entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame); + } else if (entry.cdte_format == CDROM_LBA) + entry.cdte_addr.lba = msf2log(&tp->dt); + else return -EINVAL; - /* All seems to be OK so far ... malloc. When this fails all bets - * are off anyway, so we don't check for it. - */ - stuffp->toc = kmalloc(sizeof(struct s_subqcode) * - (stuffp->last - stuffp->first + 1), GFP_KERNEL); - /* now read actually the index tracks */ - for (trk = 0; trk < stuffp->last - stuffp->first + 1; trk++) - stuffp->toc[trk].index = 0; - - for (i = 300; i; --i) { /* why 300? */ - struct s_subqcode q; - unsigned int idx; - - if (-1 == request_subq_code(stuffp, &q)) { - set_drive_mode(stuffp, DATA); - return -EIO; + memcpy_tofs((void*) arg, &entry, sizeof(entry)); + + return 0; } - idx = bcd2uint(q.index); - if (idx > 0 && idx <= stuffp->last && q.tno == 0 - && stuffp->toc[idx - stuffp->first].index == 0) { - stuffp->toc[idx - stuffp->first] = q; - trk--; + case CDROMSUBCHNL: { + int ans; + struct cdrom_subchnl sub; + struct s_subqcode q; + + xtrace(IOCTL, "ioctl() SUBCHNL\n"); + + if ((ans = verify_area(VERIFY_WRITE, + (void*) arg, sizeof(sub)))) return ans; + + memcpy_fromfs(&sub, (void*) arg, sizeof(sub)); + + if (-1 == mcdx_requestsubqcode(stuffp, &q, 2)) return -EIO; + + xtrace(SUBCHNL, "audiostatus: %x\n", stuffp->audiostatus); + sub.cdsc_audiostatus = stuffp->audiostatus; + sub.cdsc_adr = q.control; + sub.cdsc_ctrl = q.control >> 4; + sub.cdsc_trk = bcd2uint(q.tno); + sub.cdsc_ind = bcd2uint(q.index); + + xtrace(SUBCHNL, "trk %d, ind %d\n", + sub.cdsc_trk, sub.cdsc_ind); + + if (sub.cdsc_format == CDROM_LBA) { + sub.cdsc_absaddr.lba = msf2log(&q.dt); + sub.cdsc_reladdr.lba = msf2log(&q.tt); + xtrace(SUBCHNL, "lba: abs %d, rel %d\n", + sub.cdsc_absaddr.lba, + sub.cdsc_reladdr.lba); + } else if (sub.cdsc_format == CDROM_MSF) { + sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute); + sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second); + sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); + sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute); + sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second); + sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); + xtrace(SUBCHNL, + "msf: abs %02d:%02d:%02d, rel %02d:%02d:%02d\n", + sub.cdsc_absaddr.msf.minute, + sub.cdsc_absaddr.msf.second, + sub.cdsc_absaddr.msf.frame, + sub.cdsc_reladdr.msf.minute, + sub.cdsc_reladdr.msf.second, + sub.cdsc_reladdr.msf.frame); + } else return -EINVAL; + + memcpy_tofs((void*) arg, &sub, sizeof(sub)); + + return 0; } - if (trk == 0) - break; - } - i = stuffp->last - stuffp->first + 1; - memset(&stuffp->toc[i], 0, sizeof(stuffp->toc[0])); - stuffp->toc[i].dt = stuffp->msf_leadout; - /* unset toc mode */ - if (-1 == set_drive_mode(stuffp, DATA)) - return -EIO; + case CDROMREADTOCHDR: { + struct cdrom_tochdr toc; + int ans; + + xtrace(IOCTL, "ioctl() READTOCHDR\n"); + if ((ans = verify_area(VERIFY_WRITE, (void*) arg, sizeof toc))) + return ans; + toc.cdth_trk0 = stuffp->di.n_first; + toc.cdth_trk1 = stuffp->di.n_last; + memcpy_tofs((void*) arg, &toc, sizeof toc); + xtrace(TOCHDR, "ioctl() track0 = %d, track1 = %d\n", + stuffp->di.n_first, stuffp->di.n_last); + return 0; + } - return 0; + case CDROMPAUSE: { + xtrace(IOCTL, "ioctl() PAUSE\n"); + if (stuffp->audiostatus != CDROM_AUDIO_PLAY) return -EINVAL; + if (-1 == mcdx_stop(stuffp, 1)) return -EIO; + stuffp->audiostatus = CDROM_AUDIO_PAUSED; + if (-1 == mcdx_requestsubqcode(stuffp, &stuffp->start, 1)) + return -EIO; + return 0; + } + + case CDROMMULTISESSION: { + int ans; + struct cdrom_multisession ms; + xtrace(IOCTL, "ioctl() MULTISESSION\n"); + if (0 != (ans = verify_area(VERIFY_WRITE, (void*) arg, + sizeof(struct cdrom_multisession)))) + return ans; + + memcpy_fromfs(&ms, (void*) arg, sizeof(struct cdrom_multisession)); + if (ms.addr_format == CDROM_MSF) { + ms.addr.msf.minute = bcd2uint(stuffp->multi.msf_last.minute); + ms.addr.msf.second = bcd2uint(stuffp->multi.msf_last.second); + ms.addr.msf.frame = bcd2uint(stuffp->multi.msf_last.frame); + } else if (ms.addr_format == CDROM_LBA) + ms.addr.lba = msf2log(&stuffp->multi.msf_last); + else + return -EINVAL; + ms.xa_flag = !!stuffp->multi.multi; + + memcpy_tofs((void*) arg, &ms, sizeof(struct cdrom_multisession)); + if (ms.addr_format == CDROM_MSF) { + xtrace(MS, + "ioctl() (%d, %02x:%02x.%02x [%02x:%02x.%02x])\n", + ms.xa_flag, + ms.addr.msf.minute, + ms.addr.msf.second, + ms.addr.msf.frame, + stuffp->multi.msf_last.minute, + stuffp->multi.msf_last.second, + stuffp->multi.msf_last.frame); + } else { + xtrace(MS, + "ioctl() (%d, 0x%08x [%02x:%02x.%02x])\n", + ms.xa_flag, + ms.addr.lba, + stuffp->multi.msf_last.minute, + stuffp->multi.msf_last.second, + stuffp->multi.msf_last.frame); + } + return 0; + } + + case CDROMEJECT: { + xtrace(IOCTL, "ioctl() EJECT\n"); + if (stuffp->users > 1) return -EBUSY; + if (-1 == mcdx_eject(stuffp, 1)) return -EIO; + return 0; + } + + case CDROMEJECT_SW: { + stuffp->eject_sw = arg; + return 0; + } + + case CDROMVOLCTRL: { + int ans; + struct cdrom_volctrl volctrl; + + xtrace(IOCTL, "ioctl() VOLCTRL\n"); + if ((ans = verify_area( + VERIFY_READ, + (void*) arg, + sizeof(volctrl)))) + return ans; + + memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); +#if 0 /* not tested! */ + /* adjust for the weirdness of workman (md) */ + /* can't test it (hs) */ + volctrl.channel2 = volctrl.channel1; + volctrl.channel1 = volctrl.channel3 = 0x00; +#endif + return mcdx_setattentuator(stuffp, &volctrl, 2); + } + + default: + xwarn("ioctl(): unknown request 0x%04x\n", cmd); + return -EINVAL; + } } -/* - * Return 0 on success, error value -1 otherwise. - */ -static int play_track(struct s_drive_stuff *stuffp, const struct cdrom_ti *ti) +void do_mcdx_request() { - struct s_play times; + int dev; + struct s_drive_stuff *stuffp; - if (ti) { - if (-1 == read_toc(stuffp)) { - stuffp->audiostatus = CDROM_AUDIO_ERROR; - return -EIO; - } - times.start = stuffp->toc[ti->cdti_trk0 - stuffp->first].dt; - times.stop = stuffp->resume.stop = - stuffp->toc[ti->cdti_trk1 - stuffp->first + 1].dt; - } else { - times = stuffp->resume; + again: + + if (CURRENT == NULL) { + xtrace(REQUEST, "end_request(0): CURRENT == NULL\n"); + return; } - if (-1 == set_command(stuffp, MCDX_CMD_PLAY, - ×, sizeof(times), 5 * HZ)) { - printk(KERN_WARNING MCDX ": play track timeout\n"); - stuffp->audiostatus = CDROM_AUDIO_ERROR; - return -EIO; + + if (CURRENT->rq_status == RQ_INACTIVE) { + xtrace(REQUEST, "end_request(0): rq_status == RQ_INACTIVE\n"); + return; } - stuffp->audiostatus = CDROM_AUDIO_PLAY; - return 0; + INIT_REQUEST; + + dev = MINOR(CURRENT->rq_dev); + stuffp = mcdx_stuffp[dev]; + + if ((dev < 0) + || (dev >= MCDX_NDRIVES) + || !stuffp + || (!stuffp->present)) { + xwarn("do_request(): bad device: %s\n", + kdevname(CURRENT->rq_dev)); + xtrace(REQUEST, "end_request(0): bad device\n"); + end_request(0); return; + } + + if (stuffp->audio) { + xwarn("do_request() attempt to read from audio cd\n"); + xtrace(REQUEST, "end_request(0): read from audio\n"); + end_request(0); return; + } + + xtrace(REQUEST, "do_request() (%lu + %lu)\n", + CURRENT->sector, CURRENT->nr_sectors); + + switch (CURRENT->cmd) { + case WRITE: + xwarn("do_request(): attempt to write to cd!!\n"); + xtrace(REQUEST, "end_request(0): write\n"); + end_request(0); return; + + case READ: + stuffp->status = 0; + while (CURRENT->nr_sectors) { + int i; + + i = mcdx_transfer(stuffp, + CURRENT->buffer, + CURRENT->sector, + CURRENT->nr_sectors); + + if (i == -1) { + end_request(0); + goto again; + } + CURRENT->sector += i; + CURRENT->nr_sectors -= i; + CURRENT->buffer += (i * 512); + } + end_request(1); + goto again; + + xtrace(REQUEST, "end_request(1)\n"); + end_request(1); + break; + + default: + panic(MCDX "do_request: unknown command.\n"); + break; + } + + goto again; } -static int lock_door(struct s_drive_stuff *stuffp, u_char lock) +static int +mcdx_open(struct inode *ip, struct file *fp) +/* actions done on open: + * 1) get the drives status + * 2) set the stuffp.readcmd if a CD is in. + * (return no error if no CD is found, since ioctl() + * needs an opened device */ { - if (stuffp->door) - return set_command(stuffp, MCDX_CMD_LOCK_DOOR, - &lock, sizeof(lock), 5 * HZ); - return 0; -} + struct s_drive_stuff *stuffp; -/* - * KERNEL INTERFACE FUNCTIONS - */ + xtrace(OPENCLOSE, "open()\n"); -static int mcdx_ioctl(struct inode *ip, struct file *fp, - unsigned int command, unsigned long arg) -{ - int ans; - struct cdrom_ti ti; - struct cdrom_msf msf; - struct cdrom_tocentry entry; - struct s_subqcode *tp = NULL; - struct cdrom_subchnl sub; - struct s_subqcode q; - struct cdrom_tochdr toc; - struct cdrom_multisession ms; - struct cdrom_volctrl volctrl; - struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; + stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; + if (!stuffp->present) return -ENXIO; - MCDX_TRACE_IOCTL(("mcdx_ioctl():\n")); + /* Make the modules looking used ... (thanx bjorn). + * But we shouldn't forget to decrement the module counter + * on error return */ + MOD_INC_USE_COUNT; - if (!stuffp) - return -ENXIO; - if (!ip) - return -EINVAL; +#if 0 + /* We don't allow multiple users of a drive. In case of data CDs + * they'll be used by mounting, which ensures anyway exclusive + * usage. In case of audio CDs it's meaningless to try playing to + * different tracks at once! (md) + * - Hey, what about cat /dev/cdrom? Why shouldn't it called by + * more then one process at any time? (hs) */ + if (stuffp->users) { + MOD_DEC_USE_COUNT; + return -EBUSY; + } +#endif - switch (command) { - case CDROMSTART: /* spin up the drive */ - MCDX_TRACE_IOCTL(("CDROMSTART\n")); - /* Don't think we can do this. Even if we could, - * I think the drive times out and stops after a while - * anyway. For now, ignore it. - */ - return 0; + /* this is only done to test if the drive talks with us */ + if (-1 == mcdx_getstatus(stuffp, 1)) { + MOD_DEC_USE_COUNT; + return -EIO; + } - case CDROMSTOP: - MCDX_TRACE_IOCTL(("CDROMSTOP\n")); - stuffp->audiostatus = CDROM_AUDIO_INVALID; - if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ)) + /* close the door, + * This should be explained ... + * - If the door is open and its last close is too recent the + * autoclose wouldn't probably be what we want. + * - If we didn't try to close the door yet, close it and go on. + * - If we autoclosed the door and couldn't succeed in find a valid + * CD we shouln't try autoclose any longer (until a valid CD is + * in.) */ + + if (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_DOOR) { + if (jiffies - stuffp->ejected < ACLOSE_INHIBIT) { + MOD_DEC_USE_COUNT; return -EIO; - return 0; - - case CDROMPLAYTRKIND: - MCDX_TRACE_IOCTL(("CDROMPLAYTRKIND\n")); - - if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(ti)))) - return ans; - memcpy_fromfs(&ti, (void *) arg, sizeof(ti)); - if (ti.cdti_trk0 < stuffp->first - || ti.cdti_trk0 > stuffp->last - || ti.cdti_trk1 < stuffp->first) - return -EINVAL; - if (ti.cdti_trk1 > stuffp->last) - ti.cdti_trk1 = stuffp->last; - return play_track(stuffp, &ti); - - case CDROMPLAYMSF: - MCDX_TRACE_IOCTL(("CDROMPLAYMSF ")); - - if ((ans = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct cdrom_msf)))) - return ans; - memcpy_fromfs(&msf, (void *) arg, sizeof msf); - msf.cdmsf_min0 = uint2bcd(msf.cdmsf_min0); - msf.cdmsf_sec0 = uint2bcd(msf.cdmsf_sec0); - msf.cdmsf_frame0 = uint2bcd(msf.cdmsf_frame0); - stuffp->resume.stop.minute = - msf.cdmsf_min1 = uint2bcd(msf.cdmsf_min1); - stuffp->resume.stop.second = - msf.cdmsf_sec1 = uint2bcd(msf.cdmsf_sec1); - stuffp->resume.stop.frame = - msf.cdmsf_frame1 = uint2bcd(msf.cdmsf_frame1); - if (-1 == set_command(stuffp, MCDX_CMD_PLAY, - &msf, sizeof(msf), 3 * HZ)) { - return -1; } - stuffp->audiostatus = CDROM_AUDIO_PLAY; - return 0; + if (stuffp->autoclose) mcdx_closedoor(stuffp, 1); + else { + MOD_DEC_USE_COUNT; + return -EIO; + } + } + + /* if the media changed we will have to do a little more */ + if (stuffp->xxx) { - case CDROMPAUSE: - MCDX_TRACE_IOCTL(("CDROMPAUSE\n")); + xtrace(OPENCLOSE, "open() media changed\n"); + /* but wait - the time of media change will be set at the + * very last of this block - it seems, some of the following + * talk() will detect a media change ... (I think, config() + * is the reason. */ - if (stuffp->audiostatus != CDROM_AUDIO_PLAY) - return -EINVAL; + stuffp->audiostatus = CDROM_AUDIO_INVALID; + stuffp->readcmd = 0; - if (-1 == issue_command(stuffp, MCDX_CMD_STOP, 2 * HZ)) + /* get the multisession information */ + xtrace(OPENCLOSE, "open() Request multisession info\n"); + if (-1 == mcdx_requestmultidiskinfo( + stuffp, &stuffp->multi, 6)) { + xinfo("No multidiskinfo\n"); + stuffp->autoclose = 0; + /* + MOD_DEC_USE_COUNT; + stuffp->xxx = 0; return -EIO; - if (-1 == request_subq_code(stuffp, &q)) { - stuffp->audiostatus = CDROM_AUDIO_NO_STATUS; - return 0; - } - stuffp->resume.start = q.dt; - stuffp->audiostatus = CDROM_AUDIO_PAUSED; - return 0; + */ + } else { + /* we succeeded, so on next open(2) we could try auto close + * again */ + stuffp->autoclose = 1; + +#if !MCDX_QUIET + if (stuffp->multi.multi > 2) + xinfo("open() unknown multisession value (%d)\n", + stuffp->multi.multi); +#endif - case CDROMRESUME: - MCDX_TRACE_IOCTL(("CDROMRESUME\n")); + /* multisession ? */ + if (!stuffp->multi.multi) + stuffp->multi.msf_last.second = 2; - if (stuffp->audiostatus != CDROM_AUDIO_PAUSED) - return -EINVAL; - return play_track(stuffp, NULL); - case CDROMREADTOCENTRY: - MCDX_TRACE_IOCTL(("CDROMREADTOCENTRY\n")); + xtrace(OPENCLOSE, "open() MS: %d, last @ %02x:%02x.%02x\n", + stuffp->multi.multi, + stuffp->multi.msf_last.minute, + stuffp->multi.msf_last.second, + stuffp->multi.msf_last.frame); - if (-1 == read_toc(stuffp)) - return -1; - if ((ans = verify_area(VERIFY_READ, (void *) arg, sizeof(entry)))) - return ans; - memcpy_fromfs(&entry, (void *) arg, sizeof(entry)); - - if (entry.cdte_track == CDROM_LEADOUT) - tp = &stuffp->toc[stuffp->last - stuffp->first + 1]; - else if (entry.cdte_track > stuffp->last - || entry.cdte_track < stuffp->first) - return -EINVAL; - else - tp = &stuffp->toc[entry.cdte_track - stuffp->first]; - - entry.cdte_adr = tp->adr; - entry.cdte_ctrl = tp->ctrl; - - if (entry.cdte_format == CDROM_MSF) { - entry.cdte_addr.msf.minute = bcd2uint(tp->dt.minute); - entry.cdte_addr.msf.second = bcd2uint(tp->dt.second); - entry.cdte_addr.msf.frame = bcd2uint(tp->dt.frame); - } else if (entry.cdte_format == CDROM_LBA) - entry.cdte_addr.lba = msf2log(&tp->dt); - else - return -EINVAL; - - if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(entry)))) - return ans; - memcpy_tofs((void *) arg, &entry, sizeof(entry)); + { ; } /* got multisession information */ - return 0; + /* request the disks table of contents (aka diskinfo) */ + if (-1 == mcdx_requesttocdata(stuffp, &stuffp->di, 1)) { - case CDROMSUBCHNL: - MCDX_TRACE_IOCTL(("CDROMSUBCHNL\n")); + stuffp->lastsector = -1; - if ((ans = verify_area(VERIFY_READ, - (void *) arg, sizeof(sub)))) - return ans; + } else { + + stuffp->lastsector = (CD_FRAMESIZE / 512) + * msf2log(&stuffp->di.msf_leadout) - 1; + + xtrace(OPENCLOSE, "open() start %d (%02x:%02x.%02x) %d\n", + stuffp->di.n_first, + stuffp->di.msf_first.minute, + stuffp->di.msf_first.second, + stuffp->di.msf_first.frame, + msf2log(&stuffp->di.msf_first)); + xtrace(OPENCLOSE, "open() last %d (%02x:%02x.%02x) %d\n", + stuffp->di.n_last, + stuffp->di.msf_leadout.minute, + stuffp->di.msf_leadout.second, + stuffp->di.msf_leadout.frame, + msf2log(&stuffp->di.msf_leadout)); + } - memcpy_fromfs(&sub, (void *) arg, sizeof(sub)); + if (stuffp->toc) { + xtrace(MALLOC, "open() free old toc @ %p\n", stuffp->toc); + kfree(stuffp->toc); + + stuffp->toc = NULL; + } - if (-1 == request_subq_code(stuffp, &q)) + xtrace(OPENCLOSE, "open() init irq generation\n"); + if (-1 == mcdx_config(stuffp, 1)) { + MOD_DEC_USE_COUNT; return -EIO; + } - sub.cdsc_audiostatus = stuffp->audiostatus; - sub.cdsc_adr = q.adr; - sub.cdsc_ctrl = q.ctrl; - sub.cdsc_trk = bcd2uint(q.tno); - sub.cdsc_ind = bcd2uint(q.index); - - if (sub.cdsc_format == CDROM_LBA) { - sub.cdsc_absaddr.lba = msf2log(&q.dt); - sub.cdsc_reladdr.lba = msf2log(&q.tt); - } else if (sub.cdsc_format == CDROM_MSF) { - sub.cdsc_absaddr.msf.minute = bcd2uint(q.dt.minute); - sub.cdsc_absaddr.msf.second = bcd2uint(q.dt.second); - sub.cdsc_absaddr.msf.frame = bcd2uint(q.dt.frame); - sub.cdsc_reladdr.msf.minute = bcd2uint(q.tt.minute); - sub.cdsc_reladdr.msf.second = bcd2uint(q.tt.second); - sub.cdsc_reladdr.msf.frame = bcd2uint(q.tt.frame); - } else - return -EINVAL; - - if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof(sub)))) - return ans; - memcpy_tofs((void *) arg, &sub, sizeof(sub)); +#if FALLBACK + /* Set the read speed */ + xwarn("AAA %x AAA\n", stuffp->readcmd); + if (stuffp->readerrs) stuffp->readcmd = READ1X; + else stuffp->readcmd = + stuffp->present | SINGLE ? READ1X : READ2X; + xwarn("XXX %x XXX\n", stuffp->readcmd); +#else + stuffp->readcmd = stuffp->present | SINGLE ? READ1X : READ2X; +#endif - return 0; + /* try to get the first sector, iff any ... */ + if (stuffp->lastsector >= 0) { + char buf[512]; + int ans; + int tries; - case CDROMREADTOCHDR: - MCDX_TRACE_IOCTL(("CDROMREADTOCHDR\n")); + stuffp->xa = 0; + stuffp->audio = 0; - if ((ans = verify_area(VERIFY_WRITE, (void *) arg, sizeof toc))) - return ans; - /* - * Make sure, we really read it! - */ - release_toc(stuffp); - if (-1 == request_toc_data(stuffp)) - return -EIO; + for (tries = 6; tries; tries--) { - toc.cdth_trk0 = stuffp->first; - toc.cdth_trk1 = stuffp->last; - memcpy_tofs((void *) arg, &toc, sizeof toc); - return 0; + stuffp->introk = 1; - case CDROMMULTISESSION: - MCDX_TRACE_IOCTL(("CDROMMULTISESSION\n")); - - if ((ans = verify_area(VERIFY_READ, (void *) arg, - sizeof(struct cdrom_multisession)))) - return ans; - - memcpy_fromfs(&ms, - (void *) arg, sizeof(struct cdrom_multisession)); - if (ms.addr_format == CDROM_MSF) { - ms.addr.msf.minute = - bcd2uint(stuffp->multi.msf_last.minute); - ms.addr.msf.second = - bcd2uint(stuffp->multi.msf_last.second); - ms.addr.msf.frame = - bcd2uint(stuffp->multi.msf_last.frame); - } else if (ms.addr_format == CDROM_LBA) - ms.addr.lba = msf2log(&stuffp->multi.msf_last); - else - return -EINVAL; - ms.xa_flag = !!stuffp->multi.multi; - - if ((ans = verify_area(VERIFY_WRITE, (void *) arg, - sizeof(struct cdrom_multisession)))) - return ans; - - memcpy_tofs((void *) arg, - &ms, sizeof(struct cdrom_multisession)); - return 0; + xtrace(OPENCLOSE, "open() try as %s\n", + stuffp->xa ? "XA" : "normal"); - case CDROMEJECT: - MCDX_TRACE_IOCTL(("CDROMEJECT\n")); - if (stuffp->door) { - if (-1 == issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ)) - return -EIO; + /* set data mode */ + if (-1 == (ans = mcdx_setdatamode(stuffp, + stuffp->xa ? MODE2 : MODE1, 1))) { + /* MOD_DEC_USE_COUNT, return -EIO; */ + stuffp->xa = 0; + break; + } + + if ((stuffp->audio = e_audio(ans))) break; + + while (0 == (ans = mcdx_transfer(stuffp, buf, 0, 1))) + ; + + if (ans == 1) break; + stuffp->xa = !stuffp->xa; + } + /* if (!tries) MOD_DEC_USE_COUNT, return -EIO; */ } - /* - * Force rereading of toc next time the disk gets accessed! - */ - release_toc(stuffp); - return 0; + /* xa disks will be read in raw mode, others not */ + if (-1 == mcdx_setdrivemode(stuffp, + stuffp->xa ? RAW : COOKED, 1)) { + MOD_DEC_USE_COUNT; + return -EIO; + } - case CDROMEJECT_SW: - MCDX_TRACE_IOCTL(("CDROMEJECT_SW\n")); + if (stuffp->audio) { + xinfo("open() audio disk found\n"); + } else if (stuffp->lastsector >= 0) { + xinfo("open() %s%s disk found\n", + stuffp->xa ? "XA / " : "", + stuffp->multi.multi ? "Multi Session" : "Single Session"); + } - stuffp->eject_sw = !!arg; - return 0; + /* stuffp->xxx = 0; */ + } - case CDROMVOLCTRL: - MCDX_TRACE_IOCTL(("CDROMVOLCTRL\n")); - - if ((ans = verify_area(VERIFY_READ, - (void *) arg, - sizeof(volctrl)))) - return ans; - - memcpy_fromfs(&volctrl, (char *) arg, sizeof(volctrl)); - /* Adjust for the weirdness of workman. */ - volctrl.channel2 = volctrl.channel1; - volctrl.channel1 = volctrl.channel3 = 0x00; - return talk(stuffp, MCDX_CMD_SET_ATTENATOR, - &volctrl, sizeof(volctrl), - &volctrl, sizeof(volctrl), 2 * HZ); - - default: - printk(KERN_WARNING MCDX - ": unknown ioctl request 0x%04x\n", command); - return -EINVAL; + /* lock the door if not already done */ + if (0 == stuffp->users && (-1 == mcdx_lockdoor(stuffp, 1, 1))) { + MOD_DEC_USE_COUNT; + return -EIO; } + } + + stuffp->xxx = 0; + stuffp->users++; + return 0; + } -/* - * This does actually the transfer from the drive. - * Return: -1 on timeout or other error - */ -static int transfer_data(struct s_drive_stuff *stuffp, - char *p, int sector, int nr_sectors) +static void +mcdx_close(struct inode *ip, struct file *fp) { - int off; - int done = 0; + struct s_drive_stuff *stuffp; - if (!stuffp->valid || sector < stuffp->pending - || sector > stuffp->border) { - unsigned char cmd[6]; + xtrace(OPENCLOSE, "close()\n"); - stuffp->valid = 1; - stuffp->pending = sector & ~3; + stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; - /* do some sanity checks */ - if (stuffp->pending > stuffp->lastsector) { - printk(KERN_ERR MCDX - ": sector %d transfer from nirvana requested.\n", - stuffp->pending); - stuffp->eom = 1; - stuffp->valid = 0; - return -1; - } - if ((stuffp->border = stuffp->pending + REQUEST_SIZE) - > stuffp->lastsector) - stuffp->border = stuffp->lastsector; - { - unsigned int l = (stuffp->pending / 4) - + CD_BLOCK_OFFSET; + if (0 == --stuffp->users) { + sync_dev(ip->i_rdev); /* needed for r/o device? */ - cmd[0] = uint2bcd(l / 4500), l %= 4500; /* minute */ - cmd[1] = uint2bcd(l / 75); /* second */ - cmd[2] = uint2bcd(l % 75); /* frame */ - } + /* invalidate_inodes(ip->i_rdev); */ + invalidate_buffers(ip->i_rdev); - stuffp->busy = 1; - /* - * FIXME: What about the ominous frame length?! - */ - cmd[5] = cmd[4] = cmd[3] = ~0; - - outb(stuffp->double_speed ? MCDX_CMD_PLAY_2X : MCDX_CMD_PLAY, - DATA_REG); - outsb(DATA_REG, cmd, 6); - } - off = sector + nr_sectors; - if (stuffp->border < off) - off = stuffp->border; - do { - /* wait for the drive become idle, but first - * check for possible occurred errors --- the drive - * seems to report them asynchronously - */ - current->timeout = jiffies + 5 * HZ; - while (stuffp->introk && stuffp->busy - && current->timeout) { - interruptible_sleep_on(&stuffp->busyq); - } - /* test for possible errors */ - if (current->timeout == 0 || !stuffp->introk) { - if (current->timeout == 0) { - printk(KERN_ERR MCDX ": transfer timeout.\n"); - } - /* - * We don't report about !stuffp->introk, since this is - * already done in the interrupt routine. - */ - stuffp->busy = 0; - stuffp->valid = 0; - stuffp->introk = 1; - return -1; - } - /* test if it's the first sector of a block, - * there we have to skip some bytes as we read raw data - */ - if (stuffp->xa && (0 == (stuffp->pending & 3))) { - insb(DATA_REG, p, - CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE); - } - /* now actually read the data */ - insb(DATA_REG, p, 512); +#if !MCDX_QUIET + if (-1 == mcdx_lockdoor(stuffp, 0, 3)) + xinfo("close() Cannot unlock the door\n"); +#else + mcdx_lockdoor(stuffp, 0, 3); +#endif - /* test if it's the last sector of a block, - * if so, we have to expect an interrupt and to skip - * some data too - */ - if ((stuffp->busy = (3 == (stuffp->pending & 3))) - && stuffp->xa) { - int i; - for (i = 0; i < CD_XA_TAIL; ++i) - inb(DATA_REG); - } - if (stuffp->pending == sector) { - p += 512; - done++; - sector++; - } - } while (++(stuffp->pending) < off); + /* eject if wished */ + if (stuffp->eject_sw) mcdx_eject(stuffp, 1); - return done; + } + + MOD_DEC_USE_COUNT; + return; } -void do_mcdx_request() +int check_mcdx_media_change(kdev_t full_dev) +/* Return: 1 if media changed since last call to this function + 0 otherwise */ { - int dev; - struct s_drive_stuff *stuffp; + struct s_drive_stuff *stuffp; - again: + xinfo("check_mcdx_media_change called for device %s\n", + kdevname(full_dev)); - if ((CURRENT == NULL) || (CURRENT->rq_status == RQ_INACTIVE)) { - return; - } - stuffp = mcdx_stuffp[MINOR(CURRENT->rq_dev)]; + stuffp = mcdx_stuffp[MINOR(full_dev)]; + mcdx_getstatus(stuffp, 1); - INIT_REQUEST; - dev = MINOR(CURRENT->rq_dev); - if (dev < 0 || dev >= MCDX_NDRIVES || !stuffp || stuffp->audio) { - end_request(0); - goto again; - } - switch (CURRENT->cmd) { - case WRITE: - end_request(0); - break; - - case READ: - stuffp->eom = 0; /* clear end of media flag */ - while (CURRENT->nr_sectors) { - int i; + if (stuffp->yyy == 0) return 0; - i = transfer_data(stuffp, CURRENT->buffer, - CURRENT->sector, CURRENT->nr_sectors); - if (i == -1) { - if (stuffp->eom) { - CURRENT->sector += CURRENT->nr_sectors; - CURRENT->nr_sectors = 0; - } else - break; /* FIXME: drop down speed ??? */ - end_request(0); - goto again; - } - CURRENT->sector += i; - CURRENT->nr_sectors -= i; - CURRENT->buffer += (i * 512); - } - end_request(1); - break; - - default: - panic(MCDX "do_request: unknown command.\n"); - break; - } - - goto again; + stuffp->yyy = 0; + return 1; } -/* - * actions done on open: - * 1) get the drives status - * 2) handle disk changes - */ -static int mcdx_open(struct inode *ip, struct file *fp) +void mcdx_setup(char *str, int *pi) { - struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; - int st = 0; - unsigned long bang; + if (pi[0] > 0) mcdx_drive_map[0][0] = pi[1]; + if (pi[0] > 1) mcdx_drive_map[0][1] = pi[2]; +} - MCDX_TRACE(("mcdx_open()\n")); +/* DIRTY PART ******************************************************/ - if (!stuffp) - return -ENXIO; +static void mcdx_delay(struct s_drive_stuff *stuff, long jifs) +/* This routine is used for sleeping. + * A jifs value <0 means NO sleeping, + * =0 means minimal sleeping (let the kernel + * run for other processes) + * >0 means at least sleep for that amount. + * May be we could use a simple count loop w/ jumps to itself, but + * I wanna make this independend of cpu speed. [1 jiffie is 1/HZ] sec */ +{ + unsigned long tout = jiffies + jifs; + if (jifs < 0) return; + + /* If loaded during kernel boot no *_sleep_on is + * allowed! */ + if (current->pid == 0) { + while (jiffies < tout) { + current->timeout = jiffies; + schedule(); + } + } else { + current->timeout = tout; + xtrace(SLEEP, "*** delay: sleepq\n"); + interruptible_sleep_on(&stuff->sleepq); + xtrace(SLEEP, "delay awoken\n"); + if (current->signal & ~current->blocked) { + xtrace(SLEEP, "got signal\n"); + } + } +} - /* We don't allow multiple users of a drive. In case of data CD's they - * will be only used by mounting, which ensures anyway exclusive usage. - * In case of sound CD's it's anyway meaningless to try playing two - * different tracks at once! This saves us A LOT of trouble. - */ - if (stuffp->used) - return -EBUSY; +static void +mcdx_intr(int irq, void *dev_id, struct pt_regs* regs) +{ + struct s_drive_stuff *stuffp; + unsigned char b; - /* close the door, if necessary (get the door information - * from the hardware status register). - * If we can't read the CD after an autoclose - * no further auto-closes will be tried - */ - if (inb(STAT_REG) & MCDX_RBIT_DOOR) { - if (stuffp->autoclose && (stuffp->door)) - issue_command(stuffp, MCDX_CMD_CLOSE_DOOR, 5 * HZ); - else - return -EIO; - } - /* - * Check if a disk is in. - */ - bang = jiffies + 5 * HZ; - while (jiffies < bang) { - st = issue_command(stuffp, MCDX_CMD_GET_STATUS, 1 * HZ); - if (st != -1 && (st & MCDX_RBIT_DISKSET)) - break; - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + 1 * HZ; - schedule(); - } - if (st == -1 || (st & MCDX_RBIT_DISKSET) == 0) { - printk(KERN_INFO MCDX ": no disk in drive\n"); - return -EIO; - } - /* if the media changed we will have to do a little more - * FIXME: after removing of the mcdx_requestmultisession() it is showed - * that the logics of this may be broken. - */ - if (stuffp->xxx) { - /* but wait - the time of media change will be set at the - * very last of this block. - */ + stuffp = mcdx_irq_map[irq]; - stuffp->audiostatus = CDROM_AUDIO_INVALID; - stuffp->autoclose = 1; + if (stuffp == NULL ) { + xwarn("mcdx: no device for intr %d\n", irq); + return; + } - /* get the multisession information */ +#ifdef AK2 + if ( !stuffp->busy && stuffp->pending ) + stuffp->int_err = 1; - if (stuffp->multi_cap) { - int i = 6; /* number of retries */ +#endif /* AK2 */ + /* get the interrupt status */ + b = inb((unsigned int) stuffp->rreg_status); + stuffp->introk = ~b & MCDX_RBIT_DTEN; - while (i--) - if (-1 != get_command(stuffp, MCDX_CMD_GET_MDISK_INFO, - &stuffp->multi, - sizeof(struct s_multi), - 2 * HZ)) - break; + /* NOTE: We only should get interrupts if the data we + * requested are ready to transfer. + * But the drive seems to generate ``asynchronous'' interrupts + * on several error conditions too. (Despite the err int enable + * setting during initialisation) */ + + /* if not ok, read the next byte as the drives status */ + if (!stuffp->introk) { + xtrace(IRQ, "intr() irq %d hw status 0x%02x\n", irq, b); + if (~b & MCDX_RBIT_STEN) { + xinfo( "intr() irq %d status 0x%02x\n", + irq, inb((unsigned int) stuffp->rreg_data)); + } else { + xinfo( "intr() irq %d ambigous hw status\n", irq); + } + } else { + xtrace(IRQ, "irq() irq %d ok, status %02x\n", irq, b); + } - if (!i) { - stuffp->autoclose = 0; /* don't try it again on next open */ - if (stuffp->door) - issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ); - return -EIO; - } - } else - stuffp->multi.multi = 0; + stuffp->busy = 0; + wake_up_interruptible(&stuffp->busyq); +} - if (!stuffp->multi.multi) - stuffp->multi.msf_last.second = 2; - release_toc(stuffp); /* force rereading */ - if (-1 == request_toc_data(stuffp)) - stuffp->lastsector = -1; - else { - stuffp->lastsector = (CD_FRAMESIZE / 512) - * msf2log(&stuffp->msf_leadout) - 1; - } - if (-1 == config_drive(stuffp)) - return -EIO; - /* try to get the first sector, iff any ... */ - if (stuffp->lastsector >= 0) { - int tries; +static int +mcdx_talk ( + struct s_drive_stuff *stuffp, + const unsigned char *cmd, size_t cmdlen, + void *buffer, size_t size, + unsigned int timeout, int tries) +/* Send a command to the drive, wait for the result. + * returns -1 on timeout, drive status otherwise + * If buffer is not zero, the result (length size) is stored there. + * If buffer is zero the size should be the number of bytes to read + * from the drive. These bytes are discarded. + */ +{ + int st; + char c; + int discard; - stuffp->xa = 0; - stuffp->audio = 0; - for (tries = 6; tries; tries--) { - char buf[512]; - int st; - unsigned char c; - stuffp->introk = 1; + /* Somebody wants the data read? */ + if ((discard = (buffer == NULL))) buffer = &c; - /* set data mode */ - c = stuffp->xa ? MODE2 : MODE1; - st = set_command(stuffp, - MCDX_CMD_SET_DATA_MODE, - &c, sizeof(c), 5 * HZ); - if (-1 == st) { - stuffp->xa = 0; - continue; - } else if (st & MCDX_RBIT_AUDIOTR) { - stuffp->audio = 1; - break; - } - while (0 == (st = transfer_data(stuffp, buf, - 0, 1))); - if (st == 1) - break; - stuffp->xa = !stuffp->xa; - } - /* if (!tries) return -EIO; */ - } - /* xa disks will be read in raw mode, others not */ - if (-1 == set_drive_mode(stuffp, stuffp->xa ? RAW : COOKED)) - return -EIO; - stuffp->xxx = 0; + while (stuffp->lock) { + xtrace(SLEEP, "*** talk: lockq\n"); + interruptible_sleep_on(&stuffp->lockq); + xtrace(SLEEP, "talk: awoken\n"); } - /* lock the door if not already done */ - if (!stuffp->used && (-1 == lock_door(stuffp, DOOR_LOCK))) - return -EIO; - stuffp->used = 1; - MOD_INC_USE_COUNT; - return 0; -} + stuffp->lock = 1; -static void mcdx_close(struct inode *ip, struct file *fp) -{ - struct s_drive_stuff *stuffp = mcdx_stuffp[MINOR(ip->i_rdev)]; + /* An operation other then reading data destroys the + * data already requested and remembered in stuffp->request, ... */ + stuffp->valid = 0; - MCDX_TRACE(("mcdx_close()\n")); +#if MCDX_DEBUG & TALK + { + unsigned char i; + xtrace(TALK, "talk() %d / %d tries, res.size %d, command 0x%02x", + tries, timeout, size, (unsigned char) cmd[0]); + for (i = 1; i < cmdlen; i++) xtrace(TALK, " 0x%02x", cmd[i]); + xtrace(TALK, "\n"); + } +#endif - sync_dev(ip->i_rdev); /* needed for r/o device? */ + /* give up if all tries are done (bad) or if the status + * st != -1 (good) */ + for (st = -1; st == -1 && tries; tries--) { + + char *bp = (char*) buffer; + size_t sz = size; + + outsb((unsigned int) stuffp->wreg_data, cmd, cmdlen); + xtrace(TALK, "talk() command sent\n"); + + /* get the status byte */ + if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { + xinfo("talk() %02x timed out (status), %d tr%s left\n", + cmd[0], tries - 1, tries == 2 ? "y" : "ies"); + continue; + } + st = *bp; + sz--; + if (!discard) bp++; + + xtrace(TALK, "talk() got status 0x%02x\n", st); + + /* command error? */ + if (e_cmderr(st)) { + xwarn("command error cmd = %02x %s \n", + cmd[0], cmdlen > 1 ? "..." : ""); + st = -1; + continue; + } - /* invalidate_inodes(ip->i_rdev); */ - invalidate_buffers(ip->i_rdev); - lock_door(stuffp, DOOR_UNLOCK); + /* audio status? */ + if (stuffp->audiostatus == CDROM_AUDIO_INVALID) + stuffp->audiostatus = + e_audiobusy(st) ? CDROM_AUDIO_PLAY : CDROM_AUDIO_NO_STATUS; + else if (stuffp->audiostatus == CDROM_AUDIO_PLAY + && e_audiobusy(st) == 0) + stuffp->audiostatus = CDROM_AUDIO_COMPLETED; + + /* media change? */ + if (e_changed(st)) { + xinfo("talk() media changed\n"); + stuffp->xxx = stuffp->yyy = 1; + } + + /* now actually get the data */ + while (sz--) { + if (-1 == mcdx_getval(stuffp, timeout, 0, bp)) { + xinfo("talk() %02x timed out (data), %d tr%s left\n", + cmd[0], tries - 1, tries == 2 ? "y" : "ies"); + st = -1; break; + } + if (!discard) bp++; + xtrace(TALK, "talk() got 0x%02x\n", *(bp - 1)); + } + } + +#if !MCDX_QUIET + if (!tries && st == -1) xinfo("talk() giving up\n"); +#endif - /* eject if wished and possible */ - if (stuffp->eject_sw && (stuffp->door)) { - issue_command(stuffp, MCDX_CMD_EJECT, 5 * HZ); - } - stuffp->used = 0; - MOD_DEC_USE_COUNT; + stuffp->lock = 0; + wake_up_interruptible(&stuffp->lockq); + + xtrace(TALK, "talk() done with 0x%02x\n", st); + return st; } -/* - * Return: 1 if media changed since last call to this function, 0 otherwise. - */ -static int mcdx_media_change(kdev_t full_dev) +/* MODULE STUFF ***********************************************************/ +#ifdef MODULE + +int init_module(void) { - struct s_drive_stuff *stuffp; + int i; + int drives = 0; - MCDX_TRACE(("mcdx_media_change()\n")); + mcdx_init(); + for (i = 0; i < MCDX_NDRIVES; i++) { + if (mcdx_stuffp[i]) { + xtrace(INIT, "init_module() drive %d stuff @ %p\n", + i, mcdx_stuffp[i]); + drives++; + } + } - /* - * FIXME: probably this is unneeded or should be simplified! - */ - issue_command(stuffp = mcdx_stuffp[MINOR(full_dev)], - MCDX_CMD_GET_STATUS, 5 * HZ); + if (!drives) + return -EIO; - return stuffp->xxx; + register_symtab(0); + return 0; } -/* Interrupt handler routine. - * This function is called, when during transfer the end of a physical 2048 - * byte block is reached. - */ -static void mcdx_intr(int irq, void *dev_id, struct pt_regs *regs) +void cleanup_module(void) { - struct s_drive_stuff *stuffp; - u_char b; + int i; - if (!(stuffp = mcdx_irq_map[irq])) { - return; /* huh? */ - } - /* NOTE: We only should get interrupts if data were requested. - * But the drive seems to generate ``asynchronous'' interrupts - * on several error conditions too. (Despite the err int enable - * setting during initialization) - */ - b = inb(STAT_REG); - if (!(b & MCDX_RBIT_DTEN)) - stuffp->introk = 1; - else { - stuffp->introk = 0; - if (!(b & MCDX_RBIT_STEN)) { - b = inb(DATA_REG); - if (stuffp->used) - printk(KERN_DEBUG MCDX - ": irq %d status 0x%02x\n", irq, b); - } else - MCDX_TRACE(("irq %d ambiguous hw status\n", irq)); - } - stuffp->busy = 0; - wake_up_interruptible(&stuffp->busyq); + xinfo("cleanup_module called\n"); + + for (i = 0; i < MCDX_NDRIVES; i++) { + struct s_drive_stuff *stuffp; + stuffp = mcdx_stuffp[i]; + if (!stuffp) continue; + release_region((unsigned long) stuffp->wreg_data, MCDX_IO_SIZE); + free_irq(stuffp->irq, NULL); + if (stuffp->toc) { + xtrace(MALLOC, "cleanup_module() free toc @ %p\n", stuffp->toc); + kfree(stuffp->toc); + } + xtrace(MALLOC, "cleanup_module() free stuffp @ %p\n", stuffp); + mcdx_stuffp[i] = NULL; + kfree(stuffp); + } + + if (unregister_blkdev(MAJOR_NR, DEVICE_NAME) != 0) { + xwarn("cleanup() unregister_blkdev() failed\n"); + } +#if !MCDX_QUIET + else xinfo("cleanup() succeeded\n"); +#endif } -/* - * FIXME: - * This seems to hang badly, when the driver is loaded with inappropriate - * port/irq settings! - */ +#endif MODULE + +/* Support functions ************************************************/ + int mcdx_init(void) { int drive; #ifdef MODULE - printk(KERN_INFO "Mitsumi driver V" VERSION " for %s\n", - kernel_version); + xwarn("Version 2.14(hs) for %s\n", kernel_version); #else - printk(KERN_INFO "Mitsumi driver V" VERSION "\n"); + xwarn("Version 2.14(hs) \n"); #endif - for (drive = 0; drive < MCDX_NDRIVES; drive++) { - struct { - u_char code; - u_char version; - } firmware; - int i; - struct s_drive_stuff *stuffp; - int size; - mcdx_blksize_size[drive] = 0; - mcdx_stuffp[drive] = 0; + xwarn("$Id: mcdx.c,v 1.12 1996/06/05 01:38:38 heiko Exp $\n"); + + /* zero the pointer array */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) + mcdx_stuffp[drive] = NULL; + + /* do the initialisation */ + for (drive = 0; drive < MCDX_NDRIVES; drive++) { + struct s_version version; + struct s_drive_stuff* stuffp; + int size; - size = sizeof(*stuffp); + mcdx_blocksizes[drive] = 0; + + size = sizeof(*stuffp); + + xtrace(INIT, "init() try drive %d\n", drive); + + xtrace(INIT, "kmalloc space for stuffpt's\n"); + xtrace(MALLOC, "init() malloc %d bytes\n", size); + if (!(stuffp = kmalloc(size, GFP_KERNEL))) { + xwarn("init() malloc failed\n"); + break; + } - if (!(stuffp = kmalloc(size, GFP_KERNEL))) - break; + xtrace(INIT, "init() got %d bytes for drive stuff @ %p\n", sizeof(*stuffp), stuffp); /* set default values */ memset(stuffp, 0, sizeof(*stuffp)); - stuffp->autoclose = 1; /* close the door on open(2) */ + stuffp->autoclose = 1; /* close the door on open(2) */ - stuffp->base = mcdx_drive_map[drive][PORT]; - stuffp->irq = mcdx_drive_map[drive][IRQ]; + stuffp->present = 0; /* this should be 0 already */ + stuffp->toc = NULL; /* this should be NULL already */ + + /* setup our irq and i/o addresses */ + stuffp->irq = irq(mcdx_drive_map[drive]); + stuffp->wreg_data = stuffp->rreg_data = port(mcdx_drive_map[drive]); + stuffp->wreg_reset = stuffp->rreg_status = stuffp->wreg_data + 1; + stuffp->wreg_hcon = stuffp->wreg_reset + 1; + stuffp->wreg_chn = stuffp->wreg_hcon + 1; /* check if i/o addresses are available */ - if (check_region(stuffp->base, MCDX_IO_SIZE)) { - printk(KERN_WARNING - "Init failed. I/O ports (0x%3x..0x%3x) " - "already in use.\n", - stuffp->base, stuffp->base + MCDX_IO_SIZE - 1); - kfree(stuffp); - continue; /* next drive */ + if (0 != check_region((unsigned int) stuffp->wreg_data, MCDX_IO_SIZE)) { + xwarn("0x%3p,%d: " + "Init failed. I/O ports (0x%3p..0x%3p) already in use.\n", + stuffp->wreg_data, stuffp->irq, + stuffp->wreg_data, + stuffp->wreg_data + MCDX_IO_SIZE - 1); + xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); + kfree(stuffp); + xtrace(INIT, "init() continue at next drive\n"); + continue; /* next drive */ } - /* - * Hardware reset. - */ - outb(0, CHAN_REG); /* no dma, no irq -> hardware */ - outb(0, RESET_REG); /* hw reset */ - - i = 10; /* number of retries */ - while (-1 == get_command(stuffp, MCDX_CMD_GET_FIRMWARE, - &firmware, sizeof(firmware), 2 * HZ)) - --i; - if (!i) { + + xtrace(INIT, "init() i/o port is available at 0x%3p\n", stuffp->wreg_data); + + xtrace(INIT, "init() hardware reset\n"); + mcdx_reset(stuffp, HARD, 1); + + xtrace(INIT, "init() get version\n"); + if (-1 == mcdx_requestversion(stuffp, &version, 4)) { /* failed, next drive */ - printk(KERN_WARNING - "%s=0x%3x,%d: Init failed. Can't get version.\n", - MCDX, stuffp->base, stuffp->irq); - kfree(stuffp); + xwarn("%s=0x%3p,%d: Init failed. Can't get version.\n", + MCDX, + stuffp->wreg_data, stuffp->irq); + xtrace(MALLOC, "init() free stuffp @ %p\n", stuffp); + kfree(stuffp); + xtrace(INIT, "init() continue at next drive\n"); continue; } - switch (firmware.code) { - case 'D': - stuffp->double_speed = stuffp->door = - stuffp->multi_cap = 1; - break; - case 'F': - stuffp->door = stuffp->multi_cap = 1; - break; - case 'M': - break; - default: - kfree(stuffp); + + switch (version.code) { + case 'D': + stuffp->readcmd = READ2X; + stuffp->present = DOUBLE | DOOR | MULTI; + break; + case 'F': + stuffp->readcmd = READ1X; + stuffp->present = SINGLE | DOOR | MULTI; + break; + case 'M': + stuffp->readcmd = READ1X; + stuffp->present = SINGLE; + break; + default: + stuffp->present = 0; break; } - if (!stuffp) - continue; /* next drive */ + stuffp->playcmd = READ1X; + - if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops)) { + if (!stuffp->present) { + xwarn("%s=0x%3p,%d: Init failed. No Mitsumi CD-ROM?.\n", + MCDX, stuffp->wreg_data, stuffp->irq); kfree(stuffp); - continue; /* next drive */ + continue; /* next drive */ } - /* - * CD-ROM's are an example of non 1024 devices - */ - mcdx_blksize_size[drive] = 1024; + + xtrace(INIT, "init() register blkdev\n"); + if (register_blkdev(MAJOR_NR, DEVICE_NAME, &mcdx_fops) != 0) { + xwarn("%s=0x%3p,%d: Init failed. Can't get major %d.\n", + MCDX, + stuffp->wreg_data, stuffp->irq, MAJOR_NR); + kfree(stuffp); + continue; /* next drive */ + } + blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; read_ahead[MAJOR_NR] = READ_AHEAD; - blksize_size[MAJOR_NR] = mcdx_blksize_size; + blksize_size[MAJOR_NR] = mcdx_blocksizes; + + xtrace(INIT, "init() subscribe irq and i/o\n"); mcdx_irq_map[stuffp->irq] = stuffp; - if (request_irq(stuffp->irq, mcdx_intr, - SA_INTERRUPT, DEVICE_NAME, NULL)) { + if (request_irq(stuffp->irq, mcdx_intr, SA_INTERRUPT, DEVICE_NAME, NULL)) { + xwarn("%s=0x%3p,%d: Init failed. Can't get irq (%d).\n", + MCDX, + stuffp->wreg_data, stuffp->irq, stuffp->irq); stuffp->irq = 0; kfree(stuffp); - continue; /* next drive */ + continue; + } + request_region((unsigned int) stuffp->wreg_data, + MCDX_IO_SIZE, + DEVICE_NAME); + + xtrace(INIT, "init() get garbage\n"); + { + int i; + mcdx_delay(stuffp, HZ/2); + for (i = 100; i; i--) (void) inb((unsigned int) stuffp->rreg_status); } - request_region(stuffp->base, MCDX_IO_SIZE, DEVICE_NAME); - /* get junk after some delay. - */ - current->state = TASK_INTERRUPTIBLE; - current->timeout = jiffies + HZ / 2; - schedule(); - for (i = 100; i; i--) - (void) inb(STAT_REG); #if WE_KNOW_WHY - outb(0x50, CHAN_REG); /* irq 11 -> channel register */ + outb(0x50, (unsigned int) stuffp->wreg_chn); /* irq 11 -> channel register */ #endif - config_drive(stuffp); + xtrace(INIT, "init() set non dma but irq mode\n"); + mcdx_config(stuffp, 1); + + stuffp->minor = drive; - printk(KERN_INFO MCDX - "%d: at 0x%3x, irq %d, type: %c, firmware: %x\n", - drive, stuffp->base, stuffp->irq, - firmware.code, firmware.version); + xwarn("(%s) installed at 0x%3p, irq %d." + " (Firmware version %c %x)\n", + DEVICE_NAME, + stuffp->wreg_data, stuffp->irq, version.code, + version.ver); mcdx_stuffp[drive] = stuffp; + xtrace(INIT, "init() mcdx_stuffp[%d] = %p\n", drive, stuffp); } return 0; } -#ifdef MODULE +static int +mcdx_transfer(struct s_drive_stuff *stuffp, + char *p, int sector, int nr_sectors) +/* This seems to do the actually transfer. But it does more. It + keeps track of errors ocurred and will (if possible) fall back + to single speed on error. + Return: -1 on timeout or other error + else status byte (as in stuff->st) */ +{ + int ans; -int init_module(void) + ans = mcdx_xfer(stuffp, p, sector, nr_sectors); + return ans; +#if FALLBACK + if (-1 == ans) stuffp->readerrs++; + else return ans; + + if (stuffp->readerrs && stuffp->readcmd == READ1X) { + xwarn("XXX Alrady reading 1x -- no chance\n"); + return -1; + } + + xwarn("XXX Fallback to 1x\n"); + + stuffp->readcmd = READ1X; + return mcdx_transfer(stuffp, p, sector, nr_sectors); +#endif + +} + + +static int mcdx_xfer(struct s_drive_stuff *stuffp, + char *p, int sector, int nr_sectors) +/* This does actually the transfer from the drive. + Return: -1 on timeout or other error + else status byte (as in stuff->st) */ { - int i; + int border; + int done = 0; + + if (stuffp->audio) { + xwarn("Attempt to read from audio CD.\n"); + return -1; + } - mcdx_init(); - for (i = 0; i < MCDX_NDRIVES; i++) { - if (mcdx_stuffp[i]) { - register_symtab(0); - return 0; + if (!stuffp->readcmd) { + xinfo("Can't transfer from missing disk.\n"); + return -1; + } + + while (stuffp->lock) { + interruptible_sleep_on(&stuffp->lockq); + } + + if (stuffp->valid + && (sector >= stuffp->pending) + && (sector < stuffp->low_border)) { + + /* All (or at least a part of the sectors requested) seems + * to be already requested, so we don't need to bother the + * drive with new requests ... + * Wait for the drive become idle, but first + * check for possible occured errors --- the drive + * seems to report them asynchronously */ + + + border = stuffp->high_border < (border = sector + nr_sectors) + ? stuffp->high_border : border; + + stuffp->lock = current->pid; + + do { + + current->timeout = jiffies + 5 * HZ; + while (stuffp->busy) { + + interruptible_sleep_on(&stuffp->busyq); + + if (!stuffp->introk) { xtrace(XFER, "error via interrupt\n"); } + else if (current->timeout == 0) { xtrace(XFER, "timeout\n"); } + else if (current->signal & ~current->blocked) { + xtrace(XFER, "signal\n"); + } else continue; + + stuffp->lock = 0; + stuffp->busy = 0; + stuffp->valid = 0; + + wake_up_interruptible(&stuffp->lockq); + xtrace(XFER, "transfer() done (-1)\n"); + return -1; + } + + /* check if we need to set the busy flag (as we + * expect an interrupt */ + stuffp->busy = (3 == (stuffp->pending & 3)); + + /* Test if it's the first sector of a block, + * there we have to skip some bytes as we read raw data */ + if (stuffp->xa && (0 == (stuffp->pending & 3))) { + const int HEAD = CD_FRAMESIZE_RAW - CD_XA_TAIL - CD_FRAMESIZE; + insb((unsigned int) stuffp->rreg_data, p, HEAD); } + + /* now actually read the data */ + insb((unsigned int) stuffp->rreg_data, p, 512); + + /* test if it's the last sector of a block, + * if so, we have to handle XA special */ + if ((3 == (stuffp->pending & 3)) && stuffp->xa) { + char dummy[CD_XA_TAIL]; + insb((unsigned int) stuffp->rreg_data, &dummy[0], CD_XA_TAIL); + } + + if (stuffp->pending == sector) { + p += 512; + done++; + sector++; + } + } while (++(stuffp->pending) < border); + + stuffp->lock = 0; + wake_up_interruptible(&stuffp->lockq); + + } else { + + /* The requested sector(s) is/are out of the + * already requested range, so we have to bother the drive + * with a new request. */ + + static unsigned char cmd[] = { + 0, + 0, 0, 0, + 0, 0, 0 + }; + + cmd[0] = stuffp->readcmd; + + /* The numbers held in ->pending, ..., should be valid */ + stuffp->valid = 1; + stuffp->pending = sector & ~3; + + /* do some sanity checks */ + if (stuffp->pending > stuffp->lastsector) { + xwarn("transfer() sector %d from nirvana requested.\n", + stuffp->pending); + stuffp->status = MCDX_ST_EOM; + stuffp->valid = 0; + xtrace(XFER, "transfer() done (-1)\n"); + return -1; + } + + if ((stuffp->low_border = stuffp->pending + DIRECT_SIZE) + > stuffp->lastsector + 1) { + xtrace(XFER, "cut low_border\n"); + stuffp->low_border = stuffp->lastsector + 1; + } + if ((stuffp->high_border = stuffp->pending + REQUEST_SIZE) + > stuffp->lastsector + 1) { + xtrace(XFER, "cut high_border\n"); + stuffp->high_border = stuffp->lastsector + 1; + } + + { /* Convert the sector to be requested to MSF format */ + struct cdrom_msf0 pending; + log2msf(stuffp->pending / 4, &pending); + cmd[1] = pending.minute; + cmd[2] = pending.second; + cmd[3] = pending.frame; + } + + cmd[6] = (unsigned char) ((stuffp->high_border - stuffp->pending) / 4); + xtrace(XFER, "[%2d]\n", cmd[6]); + + stuffp->busy = 1; + /* Now really issue the request command */ + outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd); + + } +#ifdef AK2 + if ( stuffp->int_err ) { + stuffp->valid = 0; + stuffp->int_err = 0; + return -1; } - return -EIO; +#endif /* AK2 */ + + stuffp->low_border = (stuffp->low_border += done) < stuffp->high_border + ? stuffp->low_border : stuffp->high_border; + + return done; } -void cleanup_module(void) + +/* Access to elements of the mcdx_drive_map members */ + +static char* port(int *ip) { return (char*) ip[0]; } +static int irq(int *ip) { return ip[1]; } + +/* Misc number converters */ + +static unsigned int bcd2uint(unsigned char c) +{ return (c >> 4) * 10 + (c & 0x0f); } + +static unsigned int uint2bcd(unsigned int ival) +{ return ((ival / 10) << 4) | (ival % 10); } + +static void log2msf(unsigned int l, struct cdrom_msf0* pmsf) { - int i; + l += CD_BLOCK_OFFSET; + pmsf->minute = uint2bcd(l / 4500), l %= 4500; + pmsf->second = uint2bcd(l / 75); + pmsf->frame = uint2bcd(l % 75); +} - unregister_blkdev(MAJOR_NR, DEVICE_NAME); +static unsigned int msf2log(const struct cdrom_msf0* pmsf) +{ + return bcd2uint(pmsf->frame) + + bcd2uint(pmsf->second) * 75 + + bcd2uint(pmsf->minute) * 4500 + - CD_BLOCK_OFFSET; +} + +int mcdx_readtoc(struct s_drive_stuff* stuffp) +/* Read the toc entries from the CD, + * Return: -1 on failure, else 0 */ +{ - for (i = 0; i < MCDX_NDRIVES; i++) { - struct s_drive_stuff *stuffp; - stuffp = mcdx_stuffp[i]; - if (!stuffp) - continue; - release_region(stuffp->base, MCDX_IO_SIZE); - free_irq(stuffp->irq, NULL); - release_toc(stuffp); - mcdx_stuffp[i] = NULL; - kfree(stuffp); + if (stuffp->toc) { + xtrace(READTOC, "ioctl() toc already read\n"); + return 0; + } + + xtrace(READTOC, "ioctl() readtoc for %d tracks\n", + stuffp->di.n_last - stuffp->di.n_first + 1); + + if (-1 == mcdx_hold(stuffp, 1)) return -1; + + xtrace(READTOC, "ioctl() tocmode\n"); + if (-1 == mcdx_setdrivemode(stuffp, TOC, 1)) return -EIO; + + /* all seems to be ok so far ... malloc */ + { + int size; + size = sizeof(struct s_subqcode) * (stuffp->di.n_last - stuffp->di.n_first + 2); + + xtrace(MALLOC, "ioctl() malloc %d bytes\n", size); + stuffp->toc = kmalloc(size, GFP_KERNEL); + if (!stuffp->toc) { + xwarn("Cannot malloc %d bytes for toc\n", size); + mcdx_setdrivemode(stuffp, DATA, 1); + return -EIO; + } } - blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST; + + /* now read actually the index */ + { + int trk; + int retries; + + for (trk = 0; + trk < (stuffp->di.n_last - stuffp->di.n_first + 1); + trk++) + stuffp->toc[trk].index = 0; + + for (retries = 300; retries; retries--) { /* why 300? */ + struct s_subqcode q; + unsigned int idx; + + if (-1 == mcdx_requestsubqcode(stuffp, &q, 1)) { + mcdx_setdrivemode(stuffp, DATA, 1); + return -EIO; + } + + idx = bcd2uint(q.index); + + if ((idx > 0) + && (idx <= stuffp->di.n_last) + && (q.tno == 0) + && (stuffp->toc[idx - stuffp->di.n_first].index == 0)) { + stuffp->toc[idx - stuffp->di.n_first] = q; + xtrace(READTOC, "ioctl() toc idx %d (trk %d)\n", idx, trk); + trk--; + } + if (trk == 0) break; + } + memset(&stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1], + 0, sizeof(stuffp->toc[0])); + stuffp->toc[stuffp->di.n_last - stuffp->di.n_first + 1].dt + = stuffp->di.msf_leadout; + } + + /* unset toc mode */ + xtrace(READTOC, "ioctl() undo toc mode\n"); + if (-1 == mcdx_setdrivemode(stuffp, DATA, 2)) + return -EIO; + +#if MCDX_DEBUG && READTOC + { int trk; + for (trk = 0; + trk < (stuffp->di.n_last - stuffp->di.n_first + 2); + trk++) + xtrace(READTOC, "ioctl() %d readtoc %02x %02x %02x" + " %02x:%02x.%02x %02x:%02x.%02x\n", + trk + stuffp->di.n_first, + stuffp->toc[trk].control, stuffp->toc[trk].tno, stuffp->toc[trk].index, + stuffp->toc[trk].tt.minute, stuffp->toc[trk].tt.second, stuffp->toc[trk].tt.frame, + stuffp->toc[trk].dt.minute, stuffp->toc[trk].dt.second, stuffp->toc[trk].dt.frame); + } +#endif + + return 0; } -#else /* MODULE */ +static int +mcdx_playmsf(struct s_drive_stuff* stuffp, const struct cdrom_msf* msf) +{ + unsigned char cmd[7] = { + 0, 0, 0, 0, 0, 0, 0 + }; -/* - * This function is used by the kernel in init/main.c to provide semantics - * for the corresponding kernel options. It's unused otherwise. - */ -void mcdx_setup(char *str, int *pi) + if (!stuffp->readcmd) { + xinfo("Can't play from missing disk.\n"); + return -1; + } + + cmd[0] = stuffp->playcmd; + + cmd[1] = msf->cdmsf_min0; + cmd[2] = msf->cdmsf_sec0; + cmd[3] = msf->cdmsf_frame0; + cmd[4] = msf->cdmsf_min1; + cmd[5] = msf->cdmsf_sec1; + cmd[6] = msf->cdmsf_frame1; + + xtrace(PLAYMSF, "ioctl(): play %x " + "%02x:%02x:%02x -- %02x:%02x:%02x\n", + cmd[0], cmd[1], cmd[2], cmd[3], + cmd[4], cmd[5], cmd[6]); + + outsb((unsigned int) stuffp->wreg_data, cmd, sizeof cmd); + + if (-1 == mcdx_getval(stuffp, 3 * HZ, 0, NULL)) { + xwarn("playmsf() timeout\n"); + return -1; + } + + stuffp->audiostatus = CDROM_AUDIO_PLAY; + return 0; +} + +static int +mcdx_playtrk(struct s_drive_stuff* stuffp, const struct cdrom_ti* ti) { - if (pi[0] > 0) - mcdx_drive_map[0][0] = pi[1]; - if (pi[0] > 1) - mcdx_drive_map[0][1] = pi[2]; + struct s_subqcode* p; + struct cdrom_msf msf; + + if (-1 == mcdx_readtoc(stuffp)) return -1; + + if (ti) p = &stuffp->toc[ti->cdti_trk0 - stuffp->di.n_first]; + else p = &stuffp->start; + + msf.cdmsf_min0 = p->dt.minute; + msf.cdmsf_sec0 = p->dt.second; + msf.cdmsf_frame0 = p->dt.frame; + + if (ti) { + p = &stuffp->toc[ti->cdti_trk1 - stuffp->di.n_first + 1]; + stuffp->stop = *p; + } else p = &stuffp->stop; + + msf.cdmsf_min1 = p->dt.minute; + msf.cdmsf_sec1 = p->dt.second; + msf.cdmsf_frame1 = p->dt.frame; + + return mcdx_playmsf(stuffp, &msf); +} + + +/* Drive functions ************************************************/ + +static int +mcdx_closedoor(struct s_drive_stuff *stuffp, int tries) +{ + if (stuffp->present & DOOR) + return mcdx_talk(stuffp, "\xf8", 1, NULL, 1, 5 * HZ, tries); + else + return 0; +} + +static int +mcdx_stop(struct s_drive_stuff *stuffp, int tries) +{ return mcdx_talk(stuffp, "\xf0", 1, NULL, 1, 2 * HZ, tries); } + +static int +mcdx_hold(struct s_drive_stuff *stuffp, int tries) +{ return mcdx_talk(stuffp, "\x70", 1, NULL, 1, 2 * HZ, tries); } + +static int +mcdx_eject(struct s_drive_stuff *stuffp, int tries) +{ + if (stuffp->present & DOOR) { + stuffp->ejected = jiffies; + return mcdx_talk(stuffp, "\xf6", 1, NULL, 1, 5 * HZ, tries); + } else return 0; } -#endif /* MODULE */ + +static int +mcdx_requestsubqcode(struct s_drive_stuff *stuffp, + struct s_subqcode *sub, + int tries) +{ + char buf[11]; + int ans; + + if (-1 == (ans = mcdx_talk( + stuffp, "\x20", 1, buf, sizeof(buf), + 2 * HZ, tries))) + return -1; + sub->control = buf[1]; + sub->tno = buf[2]; + sub->index = buf[3]; + sub->tt.minute = buf[4]; + sub->tt.second = buf[5]; + sub->tt.frame = buf[6]; + sub->dt.minute = buf[8]; + sub->dt.second = buf[9]; + sub->dt.frame = buf[10]; + + return ans; +} + +static int +mcdx_requestmultidiskinfo(struct s_drive_stuff *stuffp, struct s_multi *multi, int tries) +{ + char buf[5]; + int ans; + + if (stuffp->present & MULTI) { + ans = mcdx_talk(stuffp, "\x11", 1, buf, sizeof(buf), 2 * HZ, tries); + multi->multi = buf[1]; + multi->msf_last.minute = buf[2]; + multi->msf_last.second = buf[3]; + multi->msf_last.frame = buf[4]; + return ans; + } else { + multi->multi = 0; + return 0; + } +} + +static int +mcdx_requesttocdata(struct s_drive_stuff *stuffp, struct s_diskinfo *info, int tries) +{ + char buf[9]; + int ans; + ans = mcdx_talk(stuffp, "\x10", 1, buf, sizeof(buf), 2 * HZ, tries); + if (ans == -1) { + info->n_first = 0; + info->n_last = 0; + } else { + info->n_first = bcd2uint(buf[1]); + info->n_last = bcd2uint(buf[2]); + info->msf_leadout.minute = buf[3]; + info->msf_leadout.second = buf[4]; + info->msf_leadout.frame = buf[5]; + info->msf_first.minute = buf[6]; + info->msf_first.second = buf[7]; + info->msf_first.frame = buf[8]; + } + return ans; +} + +static int +mcdx_setdrivemode(struct s_drive_stuff *stuffp, enum drivemodes mode, int tries) +{ + char cmd[2]; + int ans; + + xtrace(HW, "setdrivemode() %d\n", mode); + + if (-1 == (ans = mcdx_talk(stuffp, "\xc2", 1, cmd, sizeof(cmd), 5 * HZ, tries))) + return -1; + + switch (mode) { + case TOC: cmd[1] |= 0x04; break; + case DATA: cmd[1] &= ~0x04; break; + case RAW: cmd[1] |= 0x40; break; + case COOKED: cmd[1] &= ~0x40; break; + default: break; + } + cmd[0] = 0x50; + return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); +} + +static int +mcdx_setdatamode(struct s_drive_stuff *stuffp, enum datamodes mode, int tries) +{ + unsigned char cmd[2] = { 0xa0 }; + xtrace(HW, "setdatamode() %d\n", mode); + switch (mode) { + case MODE0: cmd[1] = 0x00; break; + case MODE1: cmd[1] = 0x01; break; + case MODE2: cmd[1] = 0x02; break; + default: return -EINVAL; + } + return mcdx_talk(stuffp, cmd, 2, NULL, 1, 5 * HZ, tries); +} + +static int +mcdx_config(struct s_drive_stuff *stuffp, int tries) +{ + char cmd[4]; + + xtrace(HW, "config()\n"); + + cmd[0] = 0x90; + + cmd[1] = 0x10; /* irq enable */ + cmd[2] = 0x05; /* pre, err irq enable */ + + if (-1 == mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries)) + return -1; + + cmd[1] = 0x02; /* dma select */ + cmd[2] = 0x00; /* no dma */ + + return mcdx_talk(stuffp, cmd, 3, NULL, 1, 1 * HZ, tries); +} + +static int +mcdx_requestversion(struct s_drive_stuff *stuffp, struct s_version *ver, int tries) +{ + char buf[3]; + int ans; + + if (-1 == (ans = mcdx_talk(stuffp, "\xdc", + 1, buf, sizeof(buf), 2 * HZ, tries))) + return ans; + + ver->code = buf[1]; + ver->ver = buf[2]; + + return ans; +} + +static int +mcdx_reset(struct s_drive_stuff *stuffp, enum resetmodes mode, int tries) +{ + if (mode == HARD) { + outb(0, (unsigned int) stuffp->wreg_chn); /* no dma, no irq -> hardware */ + outb(0, (unsigned int) stuffp->wreg_reset); /* hw reset */ + return 0; + } else return mcdx_talk(stuffp, "\x60", 1, NULL, 1, 5 * HZ, tries); +} + +static int +mcdx_lockdoor(struct s_drive_stuff *stuffp, int lock, int tries) +{ + char cmd[2] = { 0xfe }; + if (stuffp->present & DOOR) { + cmd[1] = lock ? 0x01 : 0x00; + return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 1, 5 * HZ, tries); + } else return 0; +} + +static int +mcdx_getstatus(struct s_drive_stuff *stuffp, int tries) +{ return mcdx_talk(stuffp, "\x40", 1, NULL, 1, 5 * HZ, tries); } + +static int +mcdx_getval(struct s_drive_stuff *stuffp, int to, int delay, char* buf) +{ + unsigned long timeout = to + jiffies; + char c; + + if (!buf) buf = &c; + + while (inb((unsigned int) stuffp->rreg_status) & MCDX_RBIT_STEN) { + if (jiffies > timeout) return -1; + mcdx_delay(stuffp, delay); + } + + *buf = (unsigned char) inb((unsigned int) stuffp->rreg_data) & 0xff; + + return 0; +} + +static int +mcdx_setattentuator( + struct s_drive_stuff* stuffp, + struct cdrom_volctrl* vol, + int tries) +{ + char cmd[5]; + cmd[0] = 0xae; + cmd[1] = vol->channel0; + cmd[2] = 0; + cmd[3] = vol->channel1; + cmd[4] = 0; + + return mcdx_talk(stuffp, cmd, sizeof(cmd), NULL, 5, 200, tries); +} + +/* ex:set ts=4 sw=4 ai si: */ diff --git a/drivers/cdrom/sbpcd.c b/drivers/cdrom/sbpcd.c index 2838359b0416..52be38829ab4 100644 --- a/drivers/cdrom/sbpcd.c +++ b/drivers/cdrom/sbpcd.c @@ -13,7 +13,7 @@ * labelled E2550UA or MK4015 or 2800F). */ -#define VERSION "v4.3 Eberhard Moenkeberg " +#define VERSION "v4.4 Eberhard Moenkeberg " /* Copyright (C) 1993, 1994, 1995 Eberhard Moenkeberg * @@ -278,6 +278,11 @@ * reading the ToC; still trying to solve it. * Removed some redundant verify_area calls (yes, Heiko Eissfeldt * is visiting all the Linux CDROM drivers ;-). + * + * 4.4 Adapted one idea from tiensivu@pilot.msu.edu's "stripping-down" + * experiments: "KLOGD_PAUSE". + * Inhibited "play audio" attempts with data CDs. Provisions for a + * "data-safe" handling of "mixed" (data plus audio) Cds. * * * TODO @@ -689,6 +694,9 @@ static struct { u_char TocEnt_number; u_char TocEnt_format; /* em */ u_int TocEnt_address; +#if SAFE_MIXED + char has_data; +#endif SAFE_MIXED u_char ored_ctl_adr; /* to detect if CDROM contains data tracks */ struct { @@ -751,7 +759,9 @@ static void msg(int level, const char *fmt, ...) vsprintf(&buf[18], fmt, args); va_end(args); printk(buf); - sbp_sleep(55); /* else messages get lost */ +#if KLOGD_PAUSE + sbp_sleep(KLOGD_PAUSE); /* else messages get lost */ +#endif KLOGD_PAUSE return; } /*==========================================================================*/ @@ -1966,7 +1976,7 @@ static int cc_PlayAudio(int pos_audio_start,int pos_audio_end) else if (fam2_drive) { drvcmd[0]=CMD2_PLAY_MSF; - flags_cmd_out = f_putcmd | f_ResponseStatus; + flags_cmd_out = f_putcmd | f_ResponseStatus | f_obey_p_check; } else if (famT_drive) { @@ -3916,6 +3926,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, case CDROMPLAYMSF: msg(DBG_IOC,"ioctl: CDROMPLAYMSF entered.\n"); +#if SAFE_MIXED + if (D_S[d].has_data>1) return (-EBUSY); +#endif SAFE_MIXED if (D_S[d].audio_state==audio_playing) { i=cc_Pause_Resume(1); @@ -3938,15 +3951,21 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, msg(DBG_IOX,"ioctl: CDROMPLAYMSF %08X %08X\n", D_S[d].pos_audio_start,D_S[d].pos_audio_end); i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end); - msg(DBG_IOC,"ioctl: cc_PlayAudio returns %d\n",i); -#if 0 - if (i<0) return (-EIO); -#endif 0 + if (i<0) + { + msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); + DriveReset(); + D_S[d].audio_state=0; + return (-EIO); + } D_S[d].audio_state=audio_playing; return (0); case CDROMPLAYTRKIND: /* Play a track. This currently ignores index. */ msg(DBG_IOC,"ioctl: CDROMPLAYTRKIND entered.\n"); +#if SAFE_MIXED + if (D_S[d].has_data>1) return (-EBUSY); +#endif SAFE_MIXED if (D_S[d].audio_state==audio_playing) { msg(DBG_IOX,"CDROMPLAYTRKIND: already audio_playing.\n"); @@ -3969,9 +3988,13 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, D_S[d].pos_audio_start=D_S[d].TocBuffer[ti.cdti_trk0].address; D_S[d].pos_audio_end=D_S[d].TocBuffer[ti.cdti_trk1+1].address; i=cc_PlayAudio(D_S[d].pos_audio_start,D_S[d].pos_audio_end); -#if 0 - if (i<0) return (-EIO); -#endif 0 + if (i<0) + { + msg(DBG_INF,"ioctl: cc_PlayAudio returns %d\n",i); + DriveReset(); + D_S[d].audio_state=0; + return (-EIO); + } D_S[d].audio_state=audio_playing; return (0); @@ -4015,6 +4038,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, case CDROMSTOP: /* Spin down the drive */ msg(DBG_IOC,"ioctl: CDROMSTOP entered.\n"); +#if SAFE_MIXED + if (D_S[d].has_data>1) return (-EBUSY); +#endif SAFE_MIXED i=cc_Pause_Resume(1); D_S[d].audio_state=0; return (i); @@ -4119,6 +4145,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, case CDROMREADMODE1: msg(DBG_IOC,"ioctl: CDROMREADMODE1 requested.\n"); +#if SAFE_MIXED + if (D_S[d].has_data>1) return (-EBUSY); +#endif SAFE_MIXED cc_ModeSelect(CD_FRAMESIZE); cc_ModeSense(); D_S[d].mode=READ_M1; @@ -4126,6 +4155,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, case CDROMREADMODE2: /* not usable at the moment */ msg(DBG_IOC,"ioctl: CDROMREADMODE2 requested.\n"); +#if SAFE_MIXED + if (D_S[d].has_data>1) return (-EBUSY); +#endif SAFE_MIXED cc_ModeSelect(CD_FRAMESIZE_RAW1); cc_ModeSense(); D_S[d].mode=READ_M2; @@ -4165,6 +4197,9 @@ static int sbpcd_ioctl(struct inode *inode, struct file *file, u_int cmd, if (famL_drive) return (-EINVAL); if (famV_drive) return (-EINVAL); if (famT_drive) return (-EINVAL); +#if SAFE_MIXED + if (D_S[d].has_data>1) return (-EBUSY); +#endif SAFE_MIXED if (D_S[d].aud_buf==NULL) return (-EINVAL); i=verify_area(VERIFY_READ, (void *) arg, sizeof(struct cdrom_read_audio)); if (i) return (i); @@ -4488,6 +4523,9 @@ static void DO_SBPCD_REQUEST(void) sbp_sleep(0); if (sbp_data() != 0) { +#if SAFE_MIXED + D_S[d].has_data=2; /* is really a data disk */ +#endif SAFE_MIXED end_request(1); goto request_loop; } @@ -4959,7 +4997,15 @@ static int sbpcd_open(struct inode *ip, struct file *fp) i=DiskInfo(); if (famT_drive) msg(DBG_TEA,"sbpcd_open: after i=DiskInfo();.\n"); if ((D_S[d].ored_ctl_adr&0x40)==0) + { msg(DBG_INF,"CD contains no data tracks.\n"); +#if SAFE_MIXED + D_S[d].has_data=0; +#endif SAFE_MIXED + } +#if SAFE_MIXED + else if (D_S[d].has_data<1) D_S[d].has_data=1; +#endif SAFE_MIXED } if (!st_spinning) cc_SpinUp(); return (0); @@ -4979,11 +5025,6 @@ static void sbpcd_release(struct inode * ip, struct file * file) return; } switch_drive(i); - - D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1; - sync_dev(ip->i_rdev); /* nonsense if read only device? */ - invalidate_buffers(ip->i_rdev); - /* * try to keep an "open" counter here and unlock the door if 1->0. */ @@ -4994,11 +5035,17 @@ static void sbpcd_release(struct inode * ip, struct file * file) { if (--D_S[d].open_count<=0) { + D_S[d].sbp_first_frame=D_S[d].sbp_last_frame=-1; + sync_dev(ip->i_rdev); /* nonsense if read only device? */ + invalidate_buffers(ip->i_rdev); i=UnLockDoor(); if (D_S[d].audio_state!=audio_playing) if (D_S[d].f_eject) cc_SpinDown(); D_S[d].diskstate_flags &= ~cd_size_bit; D_S[d].open_count=0; +#if SAFE_MIXED + D_S[d].has_data=0; +#endif SAFE_MIXED } } } @@ -5327,6 +5374,9 @@ int SBPCD_INIT(void) { if (D_S[j].drv_id==-1) continue; switch_drive(j); +#if SAFE_MIXED + D_S[j].has_data=0; +#endif SAFE_MIXED /* * allocate memory for the frame buffers */ diff --git a/drivers/char/ChangeLog b/drivers/char/ChangeLog index addeaa453c05..aebe36929359 100644 --- a/drivers/char/ChangeLog +++ b/drivers/char/ChangeLog @@ -1,3 +1,52 @@ +Wed Jun 5 18:52:04 1996 Theodore Ts'o + + * tty_io.c (do_tty_hangup): + * pty.c (pty_close): When closing a pty, make sure packet mode is + cleared. + +Sun May 26 09:33:52 1996 Theodore Ts'o + + * vesa_blank.c (set_vesa_blanking): Add missing verify_area() call. + + * selection.c (set_selection): Add missing verify_area() call. + + * tty_io.c (tty_ioctl): Add missing verify_area() calls. + + * serial.c (rs_ioctl): Add missing verify_area() calls. + (rs_init): Allow initialization of serial driver + configuration from a module. + + * random.c (extract_entropy): Add missing verify_area call. + Don't limit number of characters returned to + 32,768. Extract entropy is now no longer a inlined + function. + + (random_read): Check return value in case extract_entropy + returns an error. + + (secure_tcp_sequence_number): New function which returns a + secure TCP sequence number. This is needed to prevent some + nasty TCP hijacking attacks. + + (init_std_data): Initialize using gettimeofday() instead of + struct timveal xtime. + + (fast_add_entropy_word, add_entropy_word): Rename the + inline function add_entropy_word() to + fast_add_entropy_word(). Make add_entropy_word() be the + non-inlined function which is used in non-timing critical + places, in order to save space. + + (initialize_benchmark, begin_benchmark, end_benchmark): New + functions defined when RANDOM_BENCHMARK is defined. They + allow us to benchmark the speed of the + add_timer_randomness() call. + + (int_ln, rotate_left): Add two new inline functions with + i386 optimized asm instructions. This speeds up the + critical add_entropy_word() and add_timer_randomness() + functions, which are called from interrupt handlers. + Tue May 7 22:51:11 1996 * random.c (add_timer_randomness): Limit the amount randomness @@ -15,7 +64,6 @@ Tue May 7 22:51:11 1996 old ioctl values to be used for backwards compatibility (for a limited amount of time). - Wed Apr 24 14:02:04 1996 Theodore Ts'o * random.c (add_timer_randomness): Use 2nd derivative as well to diff --git a/drivers/char/Config.in b/drivers/char/Config.in index 3ff878adfd38..d4bad619ea60 100644 --- a/drivers/char/Config.in +++ b/drivers/char/Config.in @@ -16,7 +16,7 @@ tristate 'SDL RISCom/8 card support' CONFIG_RISCOM8 tristate 'Parallel printer support' CONFIG_PRINTER -bool 'Bus Mouse Support' CONFIG_MOUSE +bool 'Mouse Support (not serial mice)' CONFIG_MOUSE if [ "$CONFIG_MOUSE" = "y" ]; then tristate 'ATIXL busmouse support' CONFIG_ATIXL_BUSMOUSE tristate 'Logitech busmouse support' CONFIG_BUSMOUSE diff --git a/drivers/char/baycom.c b/drivers/char/baycom.c index 534f0dd6ed65..f604261ddc5e 100644 --- a/drivers/char/baycom.c +++ b/drivers/char/baycom.c @@ -66,6 +66,11 @@ * Various resource allocation cleanups * 0.2 12.05.96 Changed major to allocated 51. Integrated into kernel * source tree + * 0.3 04.06.96 Major bug fixed (forgot to wake up after write) which + * interestingly manifested only with kernel ax25 + * (the slip line discipline) + * introduced bottom half and tq_baycom + * HDLC processing now done with interrupts on */ /*****************************************************************************/ @@ -89,7 +94,8 @@ #include #include #include - +#include +#include #include /* --------------------------------------------------------------------- */ @@ -106,13 +112,12 @@ * circuitry is usually slow. */ -#define BUFLEN_RX 16384 -#define BUFLEN_TX 16384 +#define BUFLEN_RX 8192 +#define BUFLEN_TX 8192 #define NR_PORTS 4 #define KISS_VERBOSE -#undef HDLC_LOOPBACK #define BAYCOM_MAGIC 0x3105bac0 @@ -184,10 +189,11 @@ struct access_params { struct hdlc_state_rx { int rx_state; /* 0 = sync hunt, != 0 receiving */ - unsigned char lastbit; unsigned int bitstream; - unsigned int assembly; - + unsigned int bitbuf; + int numbits; + unsigned int shreg1, shreg2; + int len; unsigned char *bp; unsigned char buffer[BAYCOM_MAXFLEN+2]; /* make room for CRC */ @@ -205,6 +211,10 @@ struct hdlc_state_tx { unsigned int current_byte; unsigned char ptt; + unsigned int bitbuf; + int numbits; + unsigned int shreg1, shreg2; + int len; unsigned char *bp; unsigned char buffer[BAYCOM_MAXFLEN+2]; /* make room for CRC */ @@ -226,12 +236,13 @@ struct modem_state_par96 { unsigned int dcd_shreg; unsigned long descram; unsigned long scram; - unsigned int tx_bits; + unsigned char last_rxbit; }; struct modem_state { unsigned char dcd; short arb_divider; + unsigned char flags; struct modem_state_ser12 ser12; struct modem_state_par96 par96; }; @@ -288,6 +299,10 @@ struct baycom_state { int opened; struct tty_struct *tty; +#ifdef BAYCOM_USE_BH + struct tq_struct tq_receiver, tq_transmitter, tq_arbitrate; +#endif /* BAYCOM_USE_BH */ + struct packet_buffer rx_buf; struct packet_buffer tx_buf; @@ -316,6 +331,10 @@ struct baycom_state { struct baycom_state baycom_state[NR_PORTS]; +#ifdef BAYCOM_USE_BH +DECLARE_TASK_QUEUE(tq_baycom); +#endif /* BAYCOM_USE_BH */ + /* --------------------------------------------------------------------- */ /* @@ -520,16 +539,29 @@ static int store_kiss_packet(struct packet_buffer *buf, unsigned char *data, #ifdef BAYCOM_DEBUG static inline void add_bitbuffer(struct bit_buffer * buf, unsigned int bit) { + unsigned char new; + if (!buf) return; - buf->shreg <<= 1; + new = buf->shreg & 1; + buf->shreg >>= 1; if (bit) - buf->shreg |= 1; - if (buf->shreg & 0x100) { + buf->shreg |= 0x80; + if (new) { buf->buffer[buf->wr] = buf->shreg; buf->wr = (buf->wr+1) % sizeof(buf->buffer); - buf->shreg = 1; + buf->shreg = 0x80; } } + +static inline void add_bitbuffer_word(struct bit_buffer * buf, + unsigned int bits) +{ + buf->buffer[buf->wr] = bits & 0xff; + buf->wr = (buf->wr+1) % sizeof(buf->buffer); + buf->buffer[buf->wr] = (bits >> 8) & 0xff; + buf->wr = (buf->wr+1) % sizeof(buf->buffer); + +} #endif /* BAYCOM_DEBUG */ /* ---------------------------------------------------------------------- */ @@ -553,67 +585,98 @@ static inline unsigned int tenms_to_flags(struct baycom_state *bc, * one bit per call */ -static void hdlc_rx_bit(struct baycom_state *bc, unsigned int bit) +static inline int hdlc_rx_add_bytes(struct baycom_state *bc, + unsigned int bits, int num) { + int added = 0; + while (bc->hdlc_rx.rx_state && num >= 8) { + if (bc->hdlc_rx.len >= sizeof(bc->hdlc_rx.buffer)) { + bc->hdlc_rx.rx_state = 0; + return 0; + } + *bc->hdlc_rx.bp++ = bits >> (32-num); + bc->hdlc_rx.len++; + num -= 8; + added += 8; + } + return added; +} + +static inline void hdlc_rx_flag(struct baycom_state *bc) +{ + if (bc->hdlc_rx.len < 4) + return; + if (!check_crc_ccitt(bc->hdlc_rx.buffer, bc->hdlc_rx.len)) + return; + bc->stat.rx_packets++; + if (!store_kiss_packet(&bc->rx_buf, + bc->hdlc_rx.buffer, + bc->hdlc_rx.len-2)) + bc->stat.rx_bufferoverrun++; +} + +static void hdlc_rx_word(struct baycom_state *bc, unsigned int word) +{ + int i; + unsigned int mask1, mask2, mask3, mask4, mask5, mask6; + if (!bc) return; - bc->hdlc_rx.bitstream <<= 1; - if (bit) - bc->hdlc_rx.bitstream |= 1; + word &= 0xffff; #ifdef BAYCOM_DEBUG - add_bitbuffer(&bc->bitbuf_hdlc, bc->hdlc_rx.bitstream & 1); + add_bitbuffer_word(&bc->bitbuf_hdlc, word); #endif /* BAYCOM_DEBUG */ - if(bc->hdlc_rx.rx_state) { - if ((bc->hdlc_rx.bitstream & 0x3f) != 0x3e) { - /* not a stuffed bit */ - if (bc->hdlc_rx.bitstream & 1) - bc->hdlc_rx.assembly |= 0x100; - if (bc->hdlc_rx.assembly & 1) { - /* store byte */ - if (bc->hdlc_rx.len >= sizeof(bc->hdlc_rx.buffer)) { - bc->hdlc_rx.rx_state = 0; - } else { - *bc->hdlc_rx.bp++ = bc->hdlc_rx.assembly>>1; - bc->hdlc_rx.len++; - bc->hdlc_rx.assembly = 0x80; - } - } else { - bc->hdlc_rx.assembly >>= 1; - } - } - if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7e) { - if (bc->hdlc_rx.len >= 4) { - if (check_crc_ccitt(bc->hdlc_rx.buffer,bc->hdlc_rx.len)) { - bc->stat.rx_packets++; - if (!store_kiss_packet(&bc->rx_buf,bc->hdlc_rx.buffer,bc->hdlc_rx.len-2)) - bc->stat.rx_bufferoverrun++; - } + bc->hdlc_rx.bitstream >>= 16; + bc->hdlc_rx.bitstream |= word << 16; + bc->hdlc_rx.bitbuf >>= 16; + bc->hdlc_rx.bitbuf |= word << 16; + bc->hdlc_rx.numbits += 16; + for(i = 15, mask1 = 0x1fc00, mask2 = 0x1fe00, mask3 = 0x0fc00, + mask4 = 0x1f800, mask5 = 0xf800, mask6 = 0xffff; + i >= 0; + i--, mask1 <<= 1, mask2 <<= 1, mask3 <<= 1, mask4 <<= 1, + mask5 <<= 1, mask6 = (mask6 << 1) | 1) { + if ((bc->hdlc_rx.bitstream & mask1) == mask1) + bc->hdlc_rx.rx_state = 0; /* abort received */ + else if ((bc->hdlc_rx.bitstream & mask2) == mask3) { + /* flag received */ + if (bc->hdlc_rx.rx_state) { + hdlc_rx_add_bytes(bc, bc->hdlc_rx.bitbuf << + (8 + i), bc->hdlc_rx.numbits + - 8 - i); + hdlc_rx_flag(bc); } bc->hdlc_rx.len = 0; bc->hdlc_rx.bp = bc->hdlc_rx.buffer; - bc->hdlc_rx.assembly = 0x80; - } - if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7f) - bc->hdlc_rx.rx_state = 0; - } else { - if ((bc->hdlc_rx.bitstream & 0x7f) == 0x7e) { - bc->hdlc_rx.len = 0; - bc->hdlc_rx.bp = bc->hdlc_rx.buffer; - bc->hdlc_rx.assembly = 0x80; bc->hdlc_rx.rx_state = 1; + bc->hdlc_rx.numbits = i; + } else if ((bc->hdlc_rx.bitstream & mask4) == mask5) { + /* stuffed bit */ + bc->hdlc_rx.numbits--; + bc->hdlc_rx.bitbuf = (bc->hdlc_rx.bitbuf & (~mask6)) | + ((bc->hdlc_rx.bitbuf & mask6) << 1); } } + bc->hdlc_rx.numbits -= hdlc_rx_add_bytes(bc, bc->hdlc_rx.bitbuf, + bc->hdlc_rx.numbits); } /* ---------------------------------------------------------------------- */ -static unsigned char hdlc_tx_bit(struct baycom_state *bc) +static unsigned int hdlc_tx_word(struct baycom_state *bc) { - unsigned char bit; + unsigned int mask1, mask2, mask3; + int i; if (!bc || !bc->hdlc_tx.ptt) return 0; - for(;;) { + for (;;) { + if (bc->hdlc_tx.numbits >= 16) { + unsigned int ret = bc->hdlc_tx.bitbuf & 0xffff; + bc->hdlc_tx.bitbuf >>= 16; + bc->hdlc_tx.numbits -= 16; + return ret; + } switch (bc->hdlc_tx.tx_state) { default: bc->hdlc_tx.ptt = 0; @@ -621,80 +684,68 @@ static unsigned char hdlc_tx_bit(struct baycom_state *bc) return 0; case 0: case 1: - if (bc->hdlc_tx.current_byte > 1) { - /* - * return bit - */ - bit = bc->hdlc_tx.current_byte & 1; - bc->hdlc_tx.current_byte >>= 1; - return bit; - } - /* - * get new bit - */ if (bc->hdlc_tx.numflags) { bc->hdlc_tx.numflags--; - bc->hdlc_tx.current_byte = 0x17e; - } else { - if (bc->hdlc_tx.tx_state == 1) { - bc->hdlc_tx.ptt = 0; - return 0; - } - get_packet(&bc->tx_buf, &bc->hdlc_tx.bp, - &bc->hdlc_tx.len); - if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) { - bc->hdlc_tx.tx_state = 1; - bc->hdlc_tx.current_byte = 0; - bc->hdlc_tx.numflags = tenms_to_flags - (bc, bc->ch_params.tx_tail); - } else if (bc->hdlc_tx.len >= BAYCOM_MAXFLEN) { - bc->hdlc_tx.tx_state = 0; - bc->hdlc_tx.current_byte = 0; - bc->hdlc_tx.numflags = 1; - ack_packet(&bc->tx_buf); - } else { - memcpy(bc->hdlc_tx.buffer, - bc->hdlc_tx.bp, - bc->hdlc_tx.len); - ack_packet(&bc->tx_buf); - bc->hdlc_tx.bp = bc->hdlc_tx.buffer; - append_crc_ccitt(bc->hdlc_tx.buffer, - bc->hdlc_tx.len); - /* the appended CRC */ - bc->hdlc_tx.len += 2; - bc->hdlc_tx.tx_state = 2; - bc->hdlc_tx.current_byte = 0; - bc->hdlc_tx.bitstream = 0; - bc->stat.tx_packets++; - } + bc->hdlc_tx.bitbuf |= + 0x7e7e << bc->hdlc_tx.numbits; + bc->hdlc_tx.numbits += 16; + break; } - break; - case 2: - if ((bc->hdlc_tx.bitstream & 0x1f) == 0x1f) { - /* - * bit stuffing - */ - bc->hdlc_tx.bitstream <<= 1; + if (bc->hdlc_tx.tx_state == 1) { + bc->hdlc_tx.ptt = 0; return 0; } - if (bc->hdlc_tx.current_byte > 1) { - /* - * return bit - */ - bc->hdlc_tx.bitstream <<= 1; - bit = bc->hdlc_tx.current_byte & 1; - bc->hdlc_tx.bitstream |= bit; - bc->hdlc_tx.current_byte >>= 1; - return bit; + get_packet(&bc->tx_buf, &bc->hdlc_tx.bp, + &bc->hdlc_tx.len); + if (!bc->hdlc_tx.bp || !bc->hdlc_tx.len) { + bc->hdlc_tx.tx_state = 1; + bc->hdlc_tx.numflags = tenms_to_flags + (bc, bc->ch_params.tx_tail); + break; + } + if (bc->hdlc_tx.len >= BAYCOM_MAXFLEN) { + bc->hdlc_tx.tx_state = 0; + bc->hdlc_tx.numflags = 1; + ack_packet(&bc->tx_buf); + break; } + memcpy(bc->hdlc_tx.buffer, bc->hdlc_tx.bp, + bc->hdlc_tx.len); + ack_packet(&bc->tx_buf); + bc->hdlc_tx.bp = bc->hdlc_tx.buffer; + append_crc_ccitt(bc->hdlc_tx.buffer, bc->hdlc_tx.len); + /* the appended CRC */ + bc->hdlc_tx.len += 2; + bc->hdlc_tx.tx_state = 2; + bc->hdlc_tx.bitstream = 0; + bc->stat.tx_packets++; + break; + case 2: if (!bc->hdlc_tx.len) { bc->hdlc_tx.tx_state = 0; - bc->hdlc_tx.current_byte = 0; bc->hdlc_tx.numflags = 1; - } else { - bc->hdlc_tx.len--; - bc->hdlc_tx.current_byte = 0x100 | - (*bc->hdlc_tx.bp++); + break; + } + bc->hdlc_tx.len--; + bc->hdlc_tx.bitbuf |= *bc->hdlc_tx.bp << + bc->hdlc_tx.numbits; + bc->hdlc_tx.bitstream >>= 8; + bc->hdlc_tx.bitstream |= (*bc->hdlc_tx.bp++) << 16; + mask1 = 0x1f000; + mask2 = 0x10000; + mask3 = 0xffffffff >> (31-bc->hdlc_tx.numbits); + bc->hdlc_tx.numbits += 8; + for(i = 0; i < 8; i++, mask1 <<= 1, mask2 <<= 1, + mask3 = (mask3 << 1) | 1) { + if ((bc->hdlc_tx.bitstream & mask1) != mask1) + continue; + bc->hdlc_tx.bitstream &= ~mask2; + bc->hdlc_tx.bitbuf = + (bc->hdlc_tx.bitbuf & mask3) | + ((bc->hdlc_tx.bitbuf & + (~mask3)) << 1); + bc->hdlc_tx.numbits++; + mask3 = (mask3 << 1) | 1; } break; } @@ -720,7 +771,7 @@ static inline void tx_arbitrate(struct baycom_state *bc) if (!bc || bc->hdlc_tx.ptt || bc->modem.dcd) return; - get_packet(&bc->tx_buf,&bp,&len); + get_packet(&bc->tx_buf, &bp, &len); if (!bp || !len) return; @@ -845,18 +896,34 @@ static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) * since this may take quite long */ outb(0x0e | (bc->modem.ser12.tx_bit ? 1 : 0), MCR(bc->iobase)); - if (bc->calibrate > 0) { - bc->modem.ser12.tx_bit = !bc->modem.ser12.tx_bit; - bc->calibrate--; - return; - } + if (bc->hdlc_tx.shreg1 <= 1) { + if (bc->calibrate > 0) { + bc->hdlc_tx.shreg1 = 0x10000; + bc->calibrate--; + } else { +#ifdef BAYCOM_USE_BH + bc->hdlc_tx.shreg1 = bc->hdlc_tx.shreg2; + bc->hdlc_tx.shreg2 = 0; + queue_task_irq_off(&bc->tq_transmitter, + &tq_baycom); + mark_bh(BAYCOM_BH); #ifdef HDLC_LOOPBACK - hdlc_rx_bit(bc, bc->modem.ser12.tx_bit == - bc->modem.ser12.last_rxbit); - bc->modem.ser12.last_rxbit = bc->modem.ser12.tx_bit; + bc->hdlc_rx.shreg2 = bc->hdlc_tx.shreg1; + queue_task_irq_off(&bc->tq_receiver, + &tq_baycom); #endif /* HDLC_LOOPBACK */ - if (!hdlc_tx_bit(bc)) +#else /* BAYCOM_USE_BH */ + bc->hdlc_tx.shreg1 = hdlc_tx_word(bc) + | 0x10000; +#ifdef HDLC_LOOPBACK + hdlc_rx_word(bc, bc->hdlc_tx.shreg1); +#endif /* HDLC_LOOPBACK */ +#endif /* BAYCOM_USE_BH */ + } + } + if (!(bc->hdlc_tx.shreg1 & 1)) bc->modem.ser12.tx_bit = !bc->modem.ser12.tx_bit; + bc->hdlc_tx.shreg1 >>= 1; return; } /* @@ -928,8 +995,10 @@ static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) ser12_set_divisor(bc, 4); break; } - hdlc_rx_bit(bc, bc->modem.ser12.last_sample == - bc->modem.ser12.last_rxbit); + bc->hdlc_rx.shreg1 >>= 1; + if (bc->modem.ser12.last_sample == + bc->modem.ser12.last_rxbit) + bc->hdlc_rx.shreg1 |= 0x10000; bc->modem.ser12.last_rxbit = bc->modem.ser12.last_sample; } @@ -965,15 +1034,32 @@ static void baycom_ser12_interrupt(int irq, void *dev_id, struct pt_regs *regs) ser12_set_divisor(bc, 6); break; } - hdlc_rx_bit(bc, bc->modem.ser12.last_sample == - bc->modem.ser12.last_rxbit); + bc->hdlc_rx.shreg1 >>= 1; + if (bc->modem.ser12.last_sample == + bc->modem.ser12.last_rxbit) + bc->hdlc_rx.shreg1 |= 0x10000; bc->modem.ser12.last_rxbit = bc->modem.ser12.last_sample; } bc->modem.ser12.interm_sample = !bc->modem.ser12.interm_sample; } + if (bc->hdlc_rx.shreg1 & 1) { +#ifdef BAYCOM_USE_BH + bc->hdlc_rx.shreg2 = (bc->hdlc_rx.shreg1 >> 1) | 0x10000; + queue_task_irq_off(&bc->tq_receiver, &tq_baycom); + mark_bh(BAYCOM_BH); +#else /* BAYCOM_USE_BH */ + hdlc_rx_word(bc, bc->hdlc_rx.shreg1 >> 1); +#endif /* BAYCOM_USE_BH */ + bc->hdlc_rx.shreg1 = 0x10000; + } if (--bc->modem.arb_divider <= 0) { +#ifdef BAYCOM_USE_BH + queue_task_irq_off(&bc->tq_arbitrate, &tq_baycom); + mark_bh(BAYCOM_BH); +#else /* BAYCOM_USE_BH */ tx_arbitrate(bc); +#endif /* BAYCOM_USE_BH */ bc->modem.arb_divider = bc->ch_params.slottime * SER12_ARB_DIVIDER(bc); } @@ -1126,7 +1212,7 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) { register struct baycom_state *bc = (struct baycom_state *)dev_id; int i; - unsigned int data, mask, mask2; + unsigned int data, rawdata, mask, mask2; if (!bc || bc->magic != BAYCOM_MAGIC) return; @@ -1144,12 +1230,12 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) * transmitter, since this may take quite long * do the differential encoder and the scrambler on the fly */ - data = bc->modem.par96.tx_bits; - for(i = 0; i < PAR96_BURSTBITS; i++, data <<= 1) { + data = bc->hdlc_tx.shreg1; + for(i = 0; i < PAR96_BURSTBITS; i++, data >>= 1) { unsigned char val = PAR97_POWER; bc->modem.par96.scram = ((bc->modem.par96.scram << 1) | (bc->modem.par96.scram & 1)); - if (!(data & 0x8000)) + if (!(data & 1)) bc->modem.par96.scram ^= 1; if (bc->modem.par96.scram & (PAR96_SCRAM_TAP1 << 1)) bc->modem.par96.scram ^= @@ -1160,26 +1246,31 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) outb(val | PAR96_BURST, LPT_DATA(bc->iobase)); } if (bc->calibrate > 0) { - bc->modem.par96.tx_bits = 0; + bc->hdlc_tx.shreg1 = 0x10000; bc->calibrate--; - return; - } + } else { +#ifdef BAYCOM_USE_BH + bc->hdlc_tx.shreg1 = bc->hdlc_tx.shreg2; + bc->hdlc_tx.shreg2 = 0; + queue_task_irq_off(&bc->tq_transmitter, &tq_baycom); + mark_bh(BAYCOM_BH); #ifdef HDLC_LOOPBACK - for(mask = 0x8000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1) - hdlc_rx_bit(bc, bc->modem.par96.tx_bits & mask); + bc->hdlc_rx.shreg2 = bc->hdlc_tx.shreg1; + queue_task_irq_off(&bc->tq_receiver, &tq_baycom); #endif /* HDLC_LOOPBACK */ - bc->modem.par96.tx_bits = 0; - for(i = 0; i < PAR96_BURSTBITS; i++) { - bc->modem.par96.tx_bits <<= 1; - if (hdlc_tx_bit(bc)) - bc->modem.par96.tx_bits |= 1; +#else /* BAYCOM_USE_BH */ + bc->hdlc_tx.shreg1 = hdlc_tx_word(bc); +#ifdef HDLC_LOOPBACK + hdlc_rx_word(bc, bc->hdlc_tx.shreg1); +#endif /* HDLC_LOOPBACK */ +#endif /* BAYCOM_USE_BH */ } return; } /* * do receiver; differential decode and descramble on the fly */ - for(data = i = 0; i < PAR96_BURSTBITS; i++) { + for(rawdata = data = i = 0; i < PAR96_BURSTBITS; i++) { unsigned int descx; bc->modem.par96.descram = (bc->modem.par96.descram << 1); if (inb(LPT_STATUS(bc->iobase)) & PAR96_RXBIT) @@ -1190,19 +1281,31 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) outb(PAR97_POWER | PAR96_PTT, LPT_DATA(bc->iobase)); descx ^= ((descx >> PAR96_DESCRAM_TAPSH1) ^ (descx >> PAR96_DESCRAM_TAPSH2)); - data <<= 1; - data |= !(descx & 1); + if (descx & 1) + bc->modem.par96.last_rxbit = + !bc->modem.par96.last_rxbit; + data >>= 1; + if (bc->modem.par96.last_rxbit) + data |= 0x8000; + rawdata <<= 1; + rawdata |= !(descx & 1); outb(PAR97_POWER | PAR96_PTT | PAR96_BURST, LPT_DATA(bc->iobase)); } - for(mask = 0x8000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1) - hdlc_rx_bit(bc, data & mask); +#ifdef BAYCOM_USE_BH + bc->hdlc_rx.shreg2 = bc->hdlc_rx.shreg1; + bc->hdlc_rx.shreg1 = data | 0x10000; + queue_task_irq_off(&bc->tq_receiver, &tq_baycom); + mark_bh(BAYCOM_BH); +#else /* BAYCOM_USE_BH */ + hdlc_rx_word(bc, data); +#endif /* BAYCOM_USE_BH */ /* * do DCD algorithm */ if (bc->options & BAYCOM_OPTIONS_SOFTDCD) { bc->modem.par96.dcd_shreg = (bc->modem.par96.dcd_shreg << 16) - | data; + | rawdata; /* search for flags and set the dcd counter appropriately */ for(mask = 0x7f8000, mask2 = 0x3f0000, i = 0; i < PAR96_BURSTBITS; i++, mask >>= 1, mask2 >>= 1) @@ -1223,7 +1326,12 @@ static void baycom_par96_interrupt(int irq, void *dev_id, struct pt_regs *regs) bc->modem.dcd = !!(inb(LPT_STATUS(bc->iobase)) & PAR96_DCD); } if (--bc->modem.arb_divider <= 0) { +#ifdef BAYCOM_USE_BH + queue_task_irq_off(&bc->tq_arbitrate, &tq_baycom); + mark_bh(BAYCOM_BH); +#else /* BAYCOM_USE_BH */ tx_arbitrate(bc); +#endif /* BAYCOM_USE_BH */ bc->modem.arb_divider = bc->ch_params.slottime * 6; } } @@ -1318,6 +1426,58 @@ static void par96_on_close(struct baycom_state *bc) free_irq(bc->irq, bc); } +/* --------------------------------------------------------------------- */ +/* + * ===================== Bottom half (soft interrupt) ==================== + */ + +#ifdef BAYCOM_USE_BH +static void bh_receiver(void *private) +{ + struct baycom_state *bc = (struct baycom_state *)private; + unsigned int temp; + + if (!bc || bc->magic != BAYCOM_MAGIC) + return; + if (!bc->hdlc_rx.shreg2) + return; + temp = bc->hdlc_rx.shreg2; + bc->hdlc_rx.shreg2 = 0; + hdlc_rx_word(bc, temp); +} + +/* --------------------------------------------------------------------- */ + +static void bh_transmitter(void *private) +{ + struct baycom_state *bc = (struct baycom_state *)private; + + if (!bc || bc->magic != BAYCOM_MAGIC) + return; + if (bc->hdlc_tx.shreg2) + return; + bc->hdlc_tx.shreg2 = hdlc_tx_word(bc) | 0x10000; +} + +/* --------------------------------------------------------------------- */ + +static void bh_arbitrate(void *private) +{ + struct baycom_state *bc = (struct baycom_state *)private; + + if (!bc || bc->magic != BAYCOM_MAGIC) + return; + tx_arbitrate(bc); +} + +/* --------------------------------------------------------------------- */ + +static void baycom_bottom_half(void) +{ + run_task_queue(&tq_baycom); +} +#endif /* BAYCOM_USE_BH */ + /* --------------------------------------------------------------------- */ /* * ===================== TTY interface routines ========================== @@ -1369,7 +1529,7 @@ static void baycom_put_fend(struct baycom_state *bc) break; bc->ch_params.ppersist = bc->kiss_decode.pkt_buf[1]; #ifdef KISS_VERBOSE - printk("KERN_INFO baycom: p-persistence = %u\n", + printk(KERN_INFO "baycom: p-persistence = %u\n", bc->ch_params.ppersist); #endif /* KISS_VERBOSE */ break; @@ -1379,7 +1539,7 @@ static void baycom_put_fend(struct baycom_state *bc) break; bc->ch_params.slottime = bc->kiss_decode.pkt_buf[1]; #ifdef KISS_VERBOSE - printk("baycom: slottime = %ums\n", + printk(KERN_INFO "baycom: slottime = %ums\n", bc->ch_params.slottime * 10); #endif /* KISS_VERBOSE */ break; @@ -1477,6 +1637,10 @@ static int baycom_write(struct tty_struct * tty, int from_user, for(c = count, bp = buf; c > 0; c--,bp++) baycom_put_char(tty, *bp); } + if ((tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + tty->ldisc.write_wakeup) + (tty->ldisc.write_wakeup)(tty); + wake_up_interruptible(&tty->write_wait); return count; } @@ -1513,10 +1677,10 @@ static int baycom_chars_in_buffer(struct tty_struct *tty) return 0; if (baycom_paranoia_check(bc = tty->driver_data, "chars_in_buffer")) return 0; - - cnt = bc->rx_buf.wr - bc->rx_buf.rd; + + cnt = bc->tx_buf.wr - bc->tx_buf.rd; if (cnt < 0) - cnt += bc->rx_buf.buflen; + cnt += bc->tx_buf.buflen; return cnt; } @@ -1669,7 +1833,7 @@ static int baycom_ioctl(struct tty_struct *tty, struct file * file, case BAYCOMCTL_CALIBRATE: bc->calibrate = arg * ((bc->modem_type == BAYCOM_MODEM_PAR96) ? - 600 : 1200); + 600 : 75); return 0; case BAYCOMCTL_GETPARAMS: @@ -1917,16 +2081,28 @@ static void init_channel(struct baycom_state *bc) #ifdef BAYCOM_DEBUG bc->bitbuf_channel.rd = bc->bitbuf_channel.wr = 0; - bc->bitbuf_channel.shreg = 1; + bc->bitbuf_channel.shreg = 0x80; bc->bitbuf_hdlc.rd = bc->bitbuf_hdlc.wr = 0; - bc->bitbuf_hdlc.shreg = 1; + bc->bitbuf_hdlc.shreg = 0x80; #endif /* BAYCOM_DEBUG */ bc->kiss_decode.dec_state = bc->kiss_decode.escaped = bc->kiss_decode.wr = 0; bc->ch_params = dflt_ch_params; + +#ifdef BAYCOM_USE_BH + bc->tq_receiver.next = bc->tq_transmitter.next = + bc->tq_arbitrate.next = NULL; + bc->tq_receiver.sync = bc->tq_transmitter.sync = + bc->tq_arbitrate.sync = 0; + bc->tq_receiver.data = bc->tq_transmitter.data = + bc->tq_arbitrate.data = bc; + bc->tq_receiver.routine = bh_receiver; + bc->tq_transmitter.routine = bh_transmitter; + bc->tq_arbitrate.routine = bh_arbitrate; +#endif /* BAYCOM_USE_BH */ } static void init_datastructs(void) @@ -1962,6 +2138,12 @@ int baycom_init(void) { * initialize the data structures */ init_datastructs(); + /* + * initialize bottom half handler + */ +#ifdef BAYCOM_USE_BH + init_bh(BAYCOM_BH, baycom_bottom_half); +#endif /* BAYCOM_USE_BH */ /* * register the driver as tty driver */ @@ -2080,7 +2262,7 @@ int init_module(void) if (i) return i; - printk(KERN_INFO "baycom: version 0.2; " + printk(KERN_INFO "baycom: version 0.3; " "(C) 1996 by Thomas Sailer HB9JNX, sailer@ife.ee.ethz.ch\n"); return 0; @@ -2092,10 +2274,6 @@ void cleanup_module(void) { int i; -#if 0 - if (MOD_IN_USE) - printk(KERN_INFO "baycom: device busy, remove delayed\n"); -#endif printk(KERN_INFO "baycom: cleanup_module called\n"); if (tty_unregister_driver(&baycom_driver)) diff --git a/drivers/char/pty.c b/drivers/char/pty.c index b004a33652a9..5d464d966d39 100644 --- a/drivers/char/pty.c +++ b/drivers/char/pty.c @@ -74,8 +74,10 @@ static void pty_close(struct tty_struct * tty, struct file * filp) } wake_up_interruptible(&tty->read_wait); wake_up_interruptible(&tty->write_wait); + tty->packet = 0; if (!tty->link) return; + tty->link->packet = 0; wake_up_interruptible(&tty->link->read_wait); wake_up_interruptible(&tty->link->write_wait); set_bit(TTY_OTHER_CLOSED, &tty->link->flags); diff --git a/drivers/char/random.c b/drivers/char/random.c index 7bc96506b000..0b189bbd2e7a 100644 --- a/drivers/char/random.c +++ b/drivers/char/random.c @@ -1,7 +1,7 @@ /* * random.c -- A strong random number generator * - * Version 0.98, last modified 7-May-96 + * Version 1.00, last modified 26-May-96 * * Copyright Theodore Ts'o, 1994, 1995, 1996. All rights reserved. * @@ -226,7 +226,6 @@ * Eastlake, Steve Crocker, and Jeff Schiller. */ -#include #include #include #include @@ -242,6 +241,8 @@ /* * Configuration information */ +#undef RANDOM_BENCHMARK +#undef BENCHMARK_NOINT /* * The pool is stirred with a primitive polynomial of degree 128 @@ -288,6 +289,29 @@ struct random_bucket { __u32 *pool; }; +#ifdef RANDOM_BENCHMARK +/* For benchmarking only */ +struct random_benchmark { + unsigned long long start_time; + int times; /* # of samples */ + unsigned long min; + unsigned long max; + unsigned long accum; /* accumulator for average */ + const char *descr; + int unit; + unsigned long flags; +}; + +#define BENCHMARK_INTERVAL 500 + +static void initialize_benchmark(struct random_benchmark *bench, + const char *descr, int unit); +static void begin_benchmark(struct random_benchmark *bench); +static void end_benchmark(struct random_benchmark *bench); + +struct random_benchmark timer_benchmark; +#endif + /* There is one of these per entropy source */ struct timer_rand_state { unsigned long last_time; @@ -315,12 +339,73 @@ static int random_write(struct inode * inode, struct file * file, static int random_ioctl(struct inode * inode, struct file * file, unsigned int cmd, unsigned long arg); -static inline void add_entropy_word(struct random_bucket *r, +static inline void fast_add_entropy_word(struct random_bucket *r, + const __u32 input); + +static void add_entropy_word(struct random_bucket *r, const __u32 input); #ifndef MIN #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #endif + +/* + * Unfortunately, while the GCC optimizer for the i386 understands how + * to opimize a static rotate left of x bits, it doesn't know how to + * deal with a variable rotate of x bits. So we use a bit of asm magic. + */ +#if (!defined (__i386__)) +extern inline __u32 rotate_left(int i, __u32 word) +{ + __u32 nbits = 0; + + return (word << i) | (word >> (32 - i)); + +} +#else +extern inline __u32 rotate_left(int i, __u32 word) +{ + __asm__("roll %%cl,%0" + :"=r" (word) + :"0" (word),"c" (i)); + return word; +} +#endif + +/* + * More asm magic.... + * + * For entropy estimation, we need to do an integral base 2 + * logarithm. By default, use an open-coded C version, although we do + * have a version which takes advantage of the Intel's x86's "bsr" + * instruction. + */ +#if (!defined (__i386__)) +static inline __u32 int_ln(__u32 word) +{ + __u32 nbits = 0; + + while (1) { + word >>= 1; + if (!word) + break; + nbits++; + } + return nbits; +} +#else +static inline __u32 int_ln(__u32 word) +{ + __asm__("bsrl %1,%0\n\t" + "jnz 1f\n\t" + "movl $0,%0\n" + "1:" + :"=r" (word) + :"r" (word)); + return word; +} +#endif + /* * Initialize the random pool with standard stuff. @@ -331,9 +416,11 @@ static void init_std_data(struct random_bucket *r) { __u32 word, *p; int i; - - add_entropy_word(r, xtime.tv_sec); - add_entropy_word(r, xtime.tv_usec); + struct timeval tv; + + do_gettimeofday(&tv); + add_entropy_word(r, tv.tv_sec); + add_entropy_word(r, tv.tv_usec); for (p = (__u32 *) &system_utsname, i = sizeof(system_utsname) / sizeof(__u32); @@ -364,6 +451,12 @@ void rand_initialize(void) irq_timer_state[i] = NULL; for (i = 0; i < MAX_BLKDEV; i++) blkdev_timer_state[i] = NULL; + memset(&keyboard_timer_state, 0, sizeof(struct timer_rand_state)); + memset(&mouse_timer_state, 0, sizeof(struct timer_rand_state)); + memset(&extract_timer_state, 0, sizeof(struct timer_rand_state)); +#ifdef RANDOM_BENCHMARK + initialize_benchmark(&timer_benchmark, "timer", 0); +#endif extract_timer_state.dont_count_entropy = 1; random_wait = NULL; } @@ -418,23 +511,25 @@ void rand_initialize_blkdev(int major, int mode) * scancodes, for example), the upper bits of the entropy pool don't * get affected. --- TYT, 10/11/95 */ -static inline void add_entropy_word(struct random_bucket *r, - const __u32 input) +static inline void fast_add_entropy_word(struct random_bucket *r, + const __u32 input) { unsigned i; + int new_rotate; __u32 w; - w = (input << r->input_rotate) | (input >> (32 - r->input_rotate)); + w = rotate_left(r->input_rotate, input); i = r->add_ptr = (r->add_ptr - 1) & (POOLWORDS-1); + /* + * Normally, we add 7 bits of rotation to the pool. At the + * beginning of the pool, add an extra 7 bits rotation, so + * that successive passes spread the input bits across the + * pool evenly. + */ + new_rotate = r->input_rotate + 14; if (i) - r->input_rotate = (r->input_rotate + 7) & 31; - else - /* - * At the beginning of the pool, add an extra 7 bits - * rotation, so that successive passes spread the - * input bits across the pool evenly. - */ - r->input_rotate = (r->input_rotate + 14) & 31; + new_rotate = r->input_rotate + 7; + r->input_rotate = new_rotate & 31; /* XOR in the various taps */ w ^= r->pool[(i+TAP1)&(POOLWORDS-1)]; @@ -447,6 +542,15 @@ static inline void add_entropy_word(struct random_bucket *r, r->pool[i] = (w << 1) | (w >> 31); } +/* + * For places where we don't need the inlined version + */ +static void add_entropy_word(struct random_bucket *r, + const __u32 input) +{ + fast_add_entropy_word(r, input); +} + /* * This function adds entropy to the entropy "pool" by using timing * delays. It uses the timer_rand_state structure to make an estimate @@ -463,9 +567,11 @@ static void add_timer_randomness(struct random_bucket *r, struct timer_rand_state *state, unsigned num) { int delta, delta2, delta3; - unsigned nbits; __u32 time; +#ifdef RANDOM_BENCHMARK + begin_benchmark(&timer_benchmark); +#endif #if defined (__i386__) if (x86_capability & 16) { unsigned long low, high; @@ -480,15 +586,16 @@ static void add_timer_randomness(struct random_bucket *r, time = jiffies; #endif - add_entropy_word(r, (__u32) num); - add_entropy_word(r, time); - + fast_add_entropy_word(r, (__u32) num); + fast_add_entropy_word(r, time); + /* * Calculate number of bits of randomness we probably * added. We take into account the first and second order * deltas in order to make our estimate. */ - if (!state->dont_count_entropy) { + if (!state->dont_count_entropy && + (r->entropy_count < POOLBITS)) { delta = time - state->last_time; state->last_time = time; if (delta < 0) delta = -delta; @@ -502,17 +609,10 @@ static void add_timer_randomness(struct random_bucket *r, if (delta3 < 0) delta3 = -delta3; delta = MIN(MIN(delta, delta2), delta3) >> 1; - for (nbits = 0; delta; nbits++) - delta >>= 1; - - /* - * In no case do we assume we've added more than 12 - * bits of randomness. - */ - if (nbits > 12) - nbits = 12; + /* Limit entropy estimate to 12 bits */ + delta &= (1 << 12) - 1; - r->entropy_count += nbits; + r->entropy_count += int_ln(delta); /* Prevent overflow */ if (r->entropy_count > POOLBITS) @@ -521,7 +621,10 @@ static void add_timer_randomness(struct random_bucket *r, /* Wake up waiting processes, if we have enough entropy. */ if (r->entropy_count >= WAIT_INPUT_BITS) - wake_up_interruptible(&random_wait); + wake_up_interruptible(&random_wait); +#ifdef RANDOM_BENCHMARK + end_benchmark(&timer_benchmark); +#endif } void add_keyboard_randomness(unsigned char scancode) @@ -830,21 +933,24 @@ static void MD5Transform(__u32 buf[4], * bits of entropy are left in the pool, but it does not restrict the * number of bytes that are actually obtained. */ -static inline int extract_entropy(struct random_bucket *r, char * buf, +static int extract_entropy(struct random_bucket *r, char * buf, int nbytes, int to_user) { int ret, i; __u32 tmp[HASH_BUFFER_SIZE]; char *cp,*dp; + + if (to_user) { + ret = verify_area(VERIFY_WRITE, (void *) buf, nbytes); + if (ret) + return(ret); + } add_timer_randomness(r, &extract_timer_state, nbytes); /* Redundant, but just in case... */ if (r->entropy_count > POOLBITS) r->entropy_count = POOLBITS; - /* Why is this here? Left in from Ted Ts'o. Perhaps to limit time. */ - if (nbytes > 32768) - nbytes = 32768; ret = nbytes; if (r->entropy_count / 8 >= nbytes) @@ -947,6 +1053,11 @@ random_read(struct inode * inode, struct file * file, char * buf, int nbytes) continue; } n = extract_entropy(&random_state, buf, n, 1); + if (n < 0) { + if (count == 0) + retval = n; + break; + } count += n; buf += n; nbytes -= n; @@ -1182,3 +1293,120 @@ struct file_operations urandom_fops = { NULL /* no special release code */ }; +/* + * TCP initial sequence number picking. This uses the random number + * generator to pick an initial secret value. This value is hashed + * along with the TCP endpoint information to provide a unique + * starting point for each pair of TCP endpoints. This defeats + * attacks which rely on guessing the initial TCP sequence number. + * This algorithm was suggested by Steve Bellovin. + */ +__u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, + __u16 sport, __u16 dport) +{ + static int is_init = 0; + static __u32 secret[16]; + struct timeval tv; + __u32 tmp[16]; + __u32 seq; + + /* + * Pick a random secret the first time we open a TCP + * connection. + */ + if (is_init == 0) { + get_random_bytes(&secret, sizeof(secret)); + is_init = 1; + } + + memcpy(tmp, secret, sizeof(tmp)); + /* + * Pick a unique starting offset for each + * TCP connection endpoints (saddr, daddr, sport, dport) + */ + tmp[8]=saddr; + tmp[9]=daddr; + tmp[10]=(sport << 16) + dport; + HASH_TRANSFORM(tmp, tmp); + + /* + * As close as possible to RFC 793, which + * suggests using a 250kHz clock. + * Further reading shows this assumes 2MB/s networks. + * For 10MB/s ethernet, a 1MHz clock is appropriate. + * That's funny, Linux has one built in! Use it! + */ + do_gettimeofday(&tv); + seq = tmp[1] + tv.tv_usec+tv.tv_sec*1000000; +#if 0 + printk("init_seq(%lx, %lx, %d, %d) = %d\n", + saddr, daddr, sport, dport, seq); +#endif + return (seq); +} + +#ifdef RANDOM_BENCHMARK +/* + * This is so we can do some benchmarking of the random driver, to see + * how much overhead add_timer_randomness really takes. This only + * works on a Pentium, since it depends on the timer clock... + * + * Note: the results of this benchmark as of this writing (5/27/96) + * + * On a Pentium, add_timer_randomness() takes between 150 and 1000 + * clock cycles, with an average of around 600 clock cycles. On a 75 + * MHz Pentium, this translates to 2 to 13 microseconds, with an + * average time of 8 microseconds. This should be fast enough so we + * can use add_timer_randomness() even with the fastest of interrupts... + */ +static inline unsigned long long get_clock_cnt(void) +{ + unsigned long low, high; + __asm__(".byte 0x0f,0x31" :"=a" (low), "=d" (high)); + return (((unsigned long long) high << 31) | low); +} + +static void initialize_benchmark(struct random_benchmark *bench, + const char *descr, int unit) +{ + bench->times = 0; + bench->accum = 0; + bench->max = 0; + bench->min = 1 << 31; + bench->descr = descr; + bench->unit = unit; +} + +static void begin_benchmark(struct random_benchmark *bench) +{ +#ifdef BENCHMARK_NOINT + save_flags(bench->flags); cli(); +#endif + bench->start_time = get_clock_cnt(); +} + +static void end_benchmark(struct random_benchmark *bench) +{ + unsigned long ticks; + + ticks = (unsigned long) (get_clock_cnt() - bench->start_time); +#ifdef BENCHMARK_NOINT + restore_flags(bench->flags); +#endif + if (ticks < bench->min) + bench->min = ticks; + if (ticks > bench->max) + bench->max = ticks; + bench->accum += ticks; + bench->times++; + if (bench->times == BENCHMARK_INTERVAL) { + printk("Random benchmark: %s %d: %lu min, %lu avg, " + "%lu max\n", bench->descr, bench->unit, bench->min, + bench->accum / BENCHMARK_INTERVAL, bench->max); + bench->times = 0; + bench->accum = 0; + bench->max = 0; + bench->min = 1 << 31; + } +} +#endif /* RANDOM_BENCHMARK */ diff --git a/drivers/char/selection.c b/drivers/char/selection.c index dbdd283efd26..c47a9963edfd 100644 --- a/drivers/char/selection.c +++ b/drivers/char/selection.c @@ -123,6 +123,10 @@ int set_selection(const unsigned long arg, struct tty_struct *tty, int user) args = (unsigned short *)(arg + 1); if (user) { + int err; + err = verify_area(VERIFY_READ, args, sizeof(short) * 5); + if (err) + return err; xs = get_user(args++) - 1; ys = get_user(args++) - 1; xe = get_user(args++) - 1; diff --git a/drivers/char/serial.c b/drivers/char/serial.c index 5904112db6ed..fb50693fc56c 100644 --- a/drivers/char/serial.c +++ b/drivers/char/serial.c @@ -49,7 +49,7 @@ #include static char *serial_name = "Serial driver"; -static char *serial_version = "4.12"; +static char *serial_version = "4.13"; DECLARE_TASK_QUEUE(tq_serial); @@ -90,6 +90,13 @@ static int serial_refcount; #define _INLINE_ inline +#ifdef MODULE +static int io[PORT_MAX] = { 0, }; +static int irq[PORT_MAX] = { 0, }; +static int type[PORT_MAX] = { 0, }; +static int flags[PORT_MAX] = { 0, }; +#endif + #if defined(MODULE) && defined(SERIAL_DEBUG_MCOUNT) #define DBG_CNT(s) printk("(%s): [%x] refc=%d, serc=%d, ttyc=%d -> %s\n", \ kdevname(tty->device), (info->flags), serial_refcount,info->count,tty->count,s) @@ -1944,6 +1951,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, (unsigned long *) arg); return 0; case TIOCSSOFTCAR: + error = verify_area(VERIFY_READ, (void *) arg,sizeof(long)); + if (error) + return error; arg = get_fs_long((unsigned long *) arg); tty->termios->c_cflag = ((tty->termios->c_cflag & ~CLOCAL) | @@ -1967,6 +1977,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return get_serial_info(info, (struct serial_struct *) arg); case TIOCSSERIAL: + error = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_struct)); + if (error) + return error; return set_serial_info(info, (struct serial_struct *) arg); case TIOCSERCONFIG: @@ -1991,6 +2005,9 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, case TIOCSERSWILD: if (!suser()) return -EPERM; + error = verify_area(VERIFY_READ, (void *) arg,sizeof(long)); + if (error) + return error; rs_wild_int_mask = get_fs_long((unsigned long *) arg); if (rs_wild_int_mask < 0) rs_wild_int_mask = check_wild_interrupts(0); @@ -2013,6 +2030,10 @@ static int rs_ioctl(struct tty_struct *tty, struct file * file, return get_multiport_struct(info, (struct serial_multiport_struct *) arg); case TIOCSERSETMULTI: + error = verify_area(VERIFY_READ, (void *) arg, + sizeof(struct serial_multiport_struct)); + if (error) + return error; return set_multiport_struct(info, (struct serial_multiport_struct *) arg); /* @@ -2804,13 +2825,25 @@ int rs_init(void) info->icount.rng = info->icount.dcd = 0; info->next_port = 0; info->prev_port = 0; +#ifdef MODULE + if(irq[i]) + info->irq=irq[i]; + if (io[i]) + info->port=io[i]; + if (type[i]) + info->type = type[i]; + if (flags[i]) + info->flags = flags[i]; +#endif if (info->irq == 2) info->irq = 9; - if (!(info->flags & ASYNC_BOOT_AUTOCONF)) - continue; - autoconfig(info); - if (info->type == PORT_UNKNOWN) - continue; + if (info->type == PORT_UNKNOWN) { + if (!(info->flags & ASYNC_BOOT_AUTOCONF)) + continue; + autoconfig(info); + if (info->type == PORT_UNKNOWN) + continue; + } printk(KERN_INFO "tty%02d%s at 0x%04x (irq = %d)", info->line, (info->flags & ASYNC_FOURPORT) ? " FourPort" : "", info->port, info->irq); diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c index ca4af161f59c..bd1570bd3e9a 100644 --- a/drivers/char/tty_io.c +++ b/drivers/char/tty_io.c @@ -431,6 +431,9 @@ void do_tty_hangup(struct tty_struct * tty, struct file_operations *fops) tty->session = 0; tty->pgrp = -1; tty->ctrl_status = 0; + tty->packet = 0; + if (tty->link) + tty->link->packet = 0; if (tty->driver.flags & TTY_DRIVER_RESET_TERMIOS) *tty->termios = tty->driver.init_termios; if (tty->driver.hangup) @@ -1518,6 +1521,10 @@ static int tty_ioctl(struct inode * inode, struct file * file, return 0; case TIOCSETD: retval = tty_check_change(tty); + if (retval) + return retval; + retval = verify_area(VERIFY_READ, (void *) arg, + sizeof (int)); if (retval) return retval; arg = get_user((int *) arg); @@ -1558,9 +1565,15 @@ static int tty_ioctl(struct inode * inode, struct file * file, * kernel-internal variable; programs not closely * related to the kernel should not use this. */ + retval = verify_area(VERIFY_WRITE, (void *) arg, 1); + if (retval) + return retval; put_user(shift_state,(char *) arg); return 0; case 7: + retval = verify_area(VERIFY_WRITE, (void *) arg, 1); + if (retval) + return retval; put_user(mouse_reporting(),(char *) arg); return 0; case 10: diff --git a/drivers/char/vesa_blank.c b/drivers/char/vesa_blank.c index c3f4f5b3bce0..b4986f318aca 100644 --- a/drivers/char/vesa_blank.c +++ b/drivers/char/vesa_blank.c @@ -44,6 +44,7 @@ #include #include #include +#include extern unsigned short video_port_reg, video_port_val; @@ -267,7 +268,12 @@ void vesa_unblank(void) void set_vesa_blanking(const unsigned long arg) { unsigned char *argp = (unsigned char *)(arg + 1); - unsigned int mode = get_user(argp); + unsigned int mode; + + if (verify_area(VERIFY_READ, argp, 1)) + return; + + mode = get_user(argp); vesa_blanking_mode = suspend_vesa_blanking_mode = ((mode <= VESA_POWERDOWN) ? mode : DEFAULT_VESA_BLANKING_MODE); } diff --git a/drivers/net/lance.c b/drivers/net/lance.c index 6dfcbb18d2ea..42c141ddeabd 100644 --- a/drivers/net/lance.c +++ b/drivers/net/lance.c @@ -165,6 +165,7 @@ tx_full and tbusy flags. * - added support for Linux/Alpha, but removed most of it, because * it worked only for the PCI chip. * - added hook for the 32bit lance driver + * - added PCnetPCI II (79C970A) to chip table * * Paul Gortmaker (gpg109@rsphy1.anu.edu.au): * - hopefully fix above so Linux/Alpha can use ISA cards too. @@ -268,12 +269,15 @@ static struct lance_chip_type { {0x2430, "PCnet32", /* 79C965 PCnet for VL bus. */ LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + LANCE_HAS_MISSED_FRAME}, + {0x2621, "PCnet/PCI-II 79C970A", /* 79C970A PCInetPCI II. */ + LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + + LANCE_HAS_MISSED_FRAME}, {0x0, "PCnet (unknown)", LANCE_ENABLE_AUTOSELECT + LANCE_MUST_REINIT_RING + LANCE_HAS_MISSED_FRAME}, }; -enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, LANCE_UNKNOWN=5}; +enum {OLD_LANCE = 0, PCNET_ISA=1, PCNET_ISAP=2, PCNET_PCI=3, PCNET_VLB=4, PCNET_PCI_II=5, LANCE_UNKNOWN=6}; /* Non-zero only if the current card is a PCI with BIOS-set IRQ. */ static unsigned char pci_irq_line = 0; @@ -437,7 +441,7 @@ void lance_probe1(int ioaddr) #ifdef CONFIG_LANCE32 /* look if it's a PCI or VLB chip */ - if (lance_version == PCNET_PCI || lance_version == PCNET_VLB) { + if (lance_version == PCNET_PCI || lance_version == PCNET_VLB || lance_version == PCNET_PCI_II) { extern void lance32_probe1 (struct device *dev, const char *chipname, int pci_irq_line); lance32_probe1 (dev, chipname, pci_irq_line); diff --git a/drivers/net/smc-ultra.c b/drivers/net/smc-ultra.c index 7ff1e2705e09..5b3968580303 100644 --- a/drivers/net/smc-ultra.c +++ b/drivers/net/smc-ultra.c @@ -40,10 +40,11 @@ Paul Gortmaker : multiple card support for module users. Donald Becker : 4/17/96 PIO support, minor potential problems avoided. + Donald Becker : 6/6/96 correctly set auto-wrap bit. */ static const char *version = - "smc-ultra.c:v1.99 4/17/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; + "smc-ultra.c:v2.00 6/6/96 Donald Becker (becker@cesdis.gsfc.nasa.gov)\n"; #include @@ -256,9 +257,10 @@ ultra_open(struct device *dev) outb(0x00, ioaddr); /* Disable shared memory for safety. */ outb(0x80, ioaddr + 5); - if (ei_status.block_input == &ultra_pio_input) + if (ei_status.block_input == &ultra_pio_input) { outb(0x11, ioaddr + 6); /* Enable interrupts and PIO. */ - else + outb(0x01, ioaddr + 0x19); /* Enable ring read auto-wrap. */ + } else outb(0x01, ioaddr + 6); /* Enable interrupts and memory. */ /* Set the early receive warning level in window 0 high enough not to receive ERW interrupts. */ diff --git a/drivers/scsi/BusLogic.c b/drivers/scsi/BusLogic.c index e86cd8e6cbd7..ce408e7081ee 100644 --- a/drivers/scsi/BusLogic.c +++ b/drivers/scsi/BusLogic.c @@ -24,8 +24,8 @@ */ -#define BusLogic_DriverVersion "2.0.3" -#define BusLogic_DriverDate "17 May 1996" +#define BusLogic_DriverVersion "2.0.4" +#define BusLogic_DriverDate "5 June 1996" #include @@ -100,7 +100,7 @@ static BusLogic_HostAdapter_T which BusLogic Host Adapters may potentially be found. */ -static unsigned short +static unsigned int BusLogic_IO_StandardAddresses[] = { 0x330, 0x334, 0x230, 0x234, 0x130, 0x134, 0 }; @@ -112,19 +112,18 @@ static unsigned short standard BusLogic I/O Addresses. */ -static unsigned short +static unsigned int BusLogic_IO_AddressProbeList[BusLogic_IO_MaxProbeAddresses+1] = { 0 }; /* BusLogic_IRQ_UsageCount stores a count of the number of Host Adapters using a given IRQ Channel, which is necessary to support PCI, EISA, or MCA shared - interrupts. Only IRQ Channels 9, 10, 11, 12, 14, and 15 are supported by - BusLogic Host Adapters. + interrupts. */ -static short - BusLogic_IRQ_UsageCount[7] = { 0 }; +static int + BusLogic_IRQ_UsageCount[NR_IRQS] = { 0 }; /* @@ -319,7 +318,7 @@ static void BusLogic_DestroyCCBs(BusLogic_HostAdapter_T *HostAdapter) static BusLogic_CCB_T *BusLogic_AllocateCCB(BusLogic_HostAdapter_T *HostAdapter) { - static unsigned int SerialNumber = 0; + static unsigned long SerialNumber = 0; BusLogic_CCB_T *CCB; int Allocated; CCB = HostAdapter->Free_CCBs; @@ -406,8 +405,7 @@ static int BusLogic_Command(BusLogic_HostAdapter_T *HostAdapter, unsigned char *ParameterPointer = (unsigned char *) ParameterData; unsigned char *ReplyPointer = (unsigned char *) ReplyData; unsigned char StatusRegister = 0, InterruptRegister; - long TimeoutCounter; - int ReplyBytes = 0; + int ReplyBytes = 0, TimeoutCounter; /* Clear out the Reply Data if provided. */ @@ -591,7 +589,7 @@ static void BusLogic_InitializeAddressProbeList(void) */ if (pcibios_present()) { - unsigned short BusDeviceFunction[BusLogic_IO_MaxProbeAddresses]; + unsigned int BusDeviceFunction[BusLogic_IO_MaxProbeAddresses]; unsigned short Index = 0, VendorID, DeviceID; boolean NonIncreasingScanningOrder = false; unsigned char Bus, DeviceFunction; @@ -668,7 +666,7 @@ static void BusLogic_InitializeAddressProbeList(void) for (j = 0; j < Bound; j++) if (BusDeviceFunction[j] > BusDeviceFunction[j+1]) { - unsigned short Temp; + unsigned int Temp; Temp = BusDeviceFunction[j]; BusDeviceFunction[j] = BusDeviceFunction[j+1]; BusDeviceFunction[j+1] = Temp; @@ -765,7 +763,7 @@ static boolean BusLogic_HardResetHostAdapter(BusLogic_HostAdapter_T *HostAdapter) { boolean TraceHardReset = (BusLogic_GlobalOptions & BusLogic_TraceHardReset); - long TimeoutCounter = loops_per_sec >> 2; + int TimeoutCounter = loops_per_sec >> 2; unsigned char StatusRegister = 0; /* Issue a Hard Reset Command to the Host Adapter. The Host Adapter should @@ -957,18 +955,6 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T sizeof(FirmwareVersion3rdDigit)) != sizeof(FirmwareVersion3rdDigit)) return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE 3RD DIGIT"); - /* - Issue the Inquire Firmware Version Letter command. - */ - FirmwareVersionLetter = '\0'; - if (BoardID.FirmwareVersion1stDigit > '3' || - (BoardID.FirmwareVersion1stDigit == '3' && - BoardID.FirmwareVersion2ndDigit >= '3')) - if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, - NULL, 0, &FirmwareVersionLetter, - sizeof(FirmwareVersionLetter)) - != sizeof(FirmwareVersionLetter)) - return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER"); /* BusLogic Host Adapters can be identified by their model number and the major version number of their firmware as follows: @@ -984,11 +970,54 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T BT-542B/742A (revision G and below) 0.xx AMI FastDisk VLB/EISA BusLogic Clone Host Adapter */ + /* + Save the Model Name and Board Name in the Host Adapter structure. + */ + TargetPointer = HostAdapter->ModelName; + *TargetPointer++ = 'B'; + *TargetPointer++ = 'T'; + *TargetPointer++ = '-'; + for (i = 0; i < sizeof(BoardModelNumber); i++) + { + Character = BoardModelNumber[i]; + if (Character == ' ' || Character == '\0') break; + *TargetPointer++ = Character; + } + *TargetPointer++ = '\0'; + strcpy(HostAdapter->BoardName, "BusLogic "); + strcat(HostAdapter->BoardName, HostAdapter->ModelName); + strcpy(HostAdapter->InterruptLabel, HostAdapter->BoardName); + /* + Save the Firmware Version in the Host Adapter structure. + */ + TargetPointer = HostAdapter->FirmwareVersion; + *TargetPointer++ = BoardID.FirmwareVersion1stDigit; + *TargetPointer++ = '.'; + *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; + if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') + *TargetPointer++ = FirmwareVersion3rdDigit; + *TargetPointer = '\0'; + /* + Issue the Inquire Firmware Version Letter command. + */ + if (strcmp(HostAdapter->FirmwareVersion, "3.3") >= 0) + { + if (BusLogic_Command(HostAdapter, BusLogic_InquireFirmwareVersionLetter, + NULL, 0, &FirmwareVersionLetter, + sizeof(FirmwareVersionLetter)) + != sizeof(FirmwareVersionLetter)) + return BusLogic_Failure(HostAdapter, "INQUIRE FIRMWARE VERSION LETTER"); + if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') + *TargetPointer++ = FirmwareVersionLetter; + *TargetPointer = '\0'; + } /* Issue the Inquire Generic I/O Port Information command to read the - termination information from "W" Series Host Adapters. + IRQ Channel from all PCI Host Adapters, and the Termination Information + from "W" Series Host Adapters. */ - if (BoardID.FirmwareVersion1stDigit == '5') + if (HostAdapter->ModelName[3] == '9' && + strcmp(HostAdapter->FirmwareVersion, "4.25") >= 0) { if (BusLogic_Command(HostAdapter, BusLogic_InquireGenericIOPortInformation, @@ -997,10 +1026,15 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T != sizeof(GenericIOPortInformation)) return BusLogic_Failure(HostAdapter, "INQUIRE GENERIC I/O PORT INFORMATION"); + /* + Save the IRQ Channel in the Host Adapter structure. + */ + HostAdapter->IRQ_Channel = GenericIOPortInformation.PCIAssignedIRQChannel; /* Save the Termination Information in the Host Adapter structure. */ - if (GenericIOPortInformation.Valid) + if (HostAdapter->FirmwareVersion[0] == '5' && + GenericIOPortInformation.Valid) { HostAdapter->TerminationInfoValid = true; HostAdapter->LowByteTerminated = @@ -1010,10 +1044,10 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T } } /* - Issue the Fetch Host Adapter Local RAM command to read the termination - information from the AutoSCSI area of "C" Series Host Adapters. + Issue the Fetch Host Adapter Local RAM command to read the Termination + Information from the AutoSCSI area of "C" Series Host Adapters. */ - if (BoardID.FirmwareVersion1stDigit == '4') + if (HostAdapter->FirmwareVersion[0] == '4') { FetchHostAdapterLocalRAMRequest.ByteOffset = BusLogic_AutoSCSI_BaseOffset + 15; @@ -1033,58 +1067,23 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T HostAdapter->HighByteTerminated = AutoSCSIByte15.HighByteTerminated; } /* - Save the Model Name and Board Name in the Host Adapter structure. + Determine the IRQ Channel and save it in the Host Adapter structure. */ - TargetPointer = HostAdapter->ModelName; - *TargetPointer++ = 'B'; - *TargetPointer++ = 'T'; - *TargetPointer++ = '-'; - for (i = 0; i < sizeof(BoardModelNumber); i++) + if (HostAdapter->IRQ_Channel == 0) { - Character = BoardModelNumber[i]; - if (Character == ' ' || Character == '\0') break; - *TargetPointer++ = Character; + if (Configuration.IRQ_Channel9) + HostAdapter->IRQ_Channel = 9; + else if (Configuration.IRQ_Channel10) + HostAdapter->IRQ_Channel = 10; + else if (Configuration.IRQ_Channel11) + HostAdapter->IRQ_Channel = 11; + else if (Configuration.IRQ_Channel12) + HostAdapter->IRQ_Channel = 12; + else if (Configuration.IRQ_Channel14) + HostAdapter->IRQ_Channel = 14; + else if (Configuration.IRQ_Channel15) + HostAdapter->IRQ_Channel = 15; } - *TargetPointer++ = '\0'; - strcpy(HostAdapter->BoardName, "BusLogic "); - strcat(HostAdapter->BoardName, HostAdapter->ModelName); - strcpy(HostAdapter->InterruptLabel, HostAdapter->BoardName); - /* - Save the Firmware Version in the Host Adapter structure. - */ - TargetPointer = HostAdapter->FirmwareVersion; - *TargetPointer++ = BoardID.FirmwareVersion1stDigit; - *TargetPointer++ = '.'; - *TargetPointer++ = BoardID.FirmwareVersion2ndDigit; - if (FirmwareVersion3rdDigit != ' ' && FirmwareVersion3rdDigit != '\0') - *TargetPointer++ = FirmwareVersion3rdDigit; - if (FirmwareVersionLetter != ' ' && FirmwareVersionLetter != '\0') - *TargetPointer++ = FirmwareVersionLetter; - *TargetPointer++ = '\0'; - /* - Determine the IRQ Channel and save it in the Host Adapter structure. - */ - if (Configuration.IRQ_Channel9) - HostAdapter->IRQ_Channel = 9; - else if (Configuration.IRQ_Channel10) - HostAdapter->IRQ_Channel = 10; - else if (Configuration.IRQ_Channel11) - HostAdapter->IRQ_Channel = 11; - else if (Configuration.IRQ_Channel12) - HostAdapter->IRQ_Channel = 12; - else if (Configuration.IRQ_Channel14) - HostAdapter->IRQ_Channel = 14; - else if (Configuration.IRQ_Channel15) - HostAdapter->IRQ_Channel = 15; - /* - Determine the DMA Channel and save it in the Host Adapter structure. - */ - if (Configuration.DMA_Channel5) - HostAdapter->DMA_Channel = 5; - else if (Configuration.DMA_Channel6) - HostAdapter->DMA_Channel = 6; - else if (Configuration.DMA_Channel7) - HostAdapter->DMA_Channel = 7; /* Save the Host Adapter SCSI ID in the Host Adapter structure. */ @@ -1098,28 +1097,30 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T HostAdapter->ParityChecking = SetupInformation.ParityCheckEnabled; /* Determine the Bus Type and save it in the Host Adapter structure, - overriding the DMA Channel if it is inappropriate for the bus type. + and determine and save the DMA Channel for ISA Host Adapters. */ switch (HostAdapter->ModelName[3]) { case '4': HostAdapter->BusType = BusLogic_VESA_Bus; - HostAdapter->DMA_Channel = 0; break; case '5': HostAdapter->BusType = BusLogic_ISA_Bus; + if (Configuration.DMA_Channel5) + HostAdapter->DMA_Channel = 5; + else if (Configuration.DMA_Channel6) + HostAdapter->DMA_Channel = 6; + else if (Configuration.DMA_Channel7) + HostAdapter->DMA_Channel = 7; break; case '6': HostAdapter->BusType = BusLogic_MCA_Bus; - HostAdapter->DMA_Channel = 0; break; case '7': HostAdapter->BusType = BusLogic_EISA_Bus; - HostAdapter->DMA_Channel = 0; break; case '9': HostAdapter->BusType = BusLogic_PCI_Bus; - HostAdapter->DMA_Channel = 0; break; } /* @@ -1341,7 +1342,7 @@ static boolean BusLogic_ReadHostAdapterConfiguration(BusLogic_HostAdapter_T printk("%d, ", HostAdapter->DMA_Channel); else printk("None, "); if (HostAdapter->BIOS_Address > 0) - printk("BIOS Address: 0x%lX, ", HostAdapter->BIOS_Address); + printk("BIOS Address: 0x%X, ", HostAdapter->BIOS_Address); else printk("BIOS Address: None, "); printk("Host Adapter SCSI ID: %d\n", HostAdapter->SCSI_ID); printk("scsi%d: Scatter/Gather Limit: %d of %d segments, " @@ -1432,13 +1433,13 @@ static boolean BusLogic_AcquireResources(BusLogic_HostAdapter_T *HostAdapter) Acquire exclusive or shared access to the IRQ Channel. A usage count is maintained so that PCI, EISA, or MCA shared interrupts can be supported. */ - if (BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]++ == 0) + if (BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel]++ == 0) { if (request_irq(HostAdapter->IRQ_Channel, BusLogic_InterruptHandler, SA_INTERRUPT | SA_SHIRQ, HostAdapter->InterruptLabel, NULL) < 0) { - BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9]--; + BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel]--; printk("scsi%d: UNABLE TO ACQUIRE IRQ CHANNEL %d - DETACHING\n", HostAdapter->HostNumber, HostAdapter->IRQ_Channel); return false; @@ -1498,7 +1499,7 @@ static void BusLogic_ReleaseResources(BusLogic_HostAdapter_T *HostAdapter) Release exclusive or shared access to the IRQ Channel. */ if (HostAdapter->IRQ_ChannelAcquired) - if (--BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel - 9] == 0) + if (--BusLogic_IRQ_UsageCount[HostAdapter->IRQ_Channel] == 0) free_irq(HostAdapter->IRQ_Channel, NULL); /* Release exclusive access to the DMA Channel. @@ -1601,7 +1602,8 @@ static boolean BusLogic_InitializeHostAdapter(BusLogic_HostAdapter_T Initialize the Host Adapter's Pointer to the Outgoing/Incoming Mailboxes. */ ExtendedMailboxRequest.MailboxCount = HostAdapter->MailboxCount; - ExtendedMailboxRequest.BaseMailboxAddress = HostAdapter->FirstOutgoingMailbox; + ExtendedMailboxRequest.BaseMailboxAddress = + Virtual_to_Bus(HostAdapter->FirstOutgoingMailbox); if (BusLogic_Command(HostAdapter, BusLogic_InitializeExtendedMailbox, &ExtendedMailboxRequest, sizeof(ExtendedMailboxRequest), NULL, 0) < 0) @@ -1858,12 +1860,14 @@ static void BusLogic_SelectQueueDepths(SCSI_Host_T *Host, else UntaggedDeviceCount++; } if (TaggedQueueDepth == 0 && TaggedDeviceCount > 0) - TaggedQueueDepth = - 1 + ((HostAdapter->TotalQueueDepth - - UntaggedDeviceCount * UntaggedQueueDepth) - / TaggedDeviceCount); - if (TaggedQueueDepth > BusLogic_MaxTaggedQueueDepth) - TaggedQueueDepth = BusLogic_MaxTaggedQueueDepth; + { + TaggedQueueDepth = + 1 + ((HostAdapter->TotalQueueDepth + - UntaggedDeviceCount * UntaggedQueueDepth) + / TaggedDeviceCount); + if (TaggedQueueDepth > BusLogic_PreferredTaggedQueueDepth) + TaggedQueueDepth = BusLogic_PreferredTaggedQueueDepth; + } for (Device = DeviceList; Device != NULL; Device = Device->next) if (Device->host == Host) { @@ -2180,7 +2184,8 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, NextIncomingMailbox->CompletionCode) != BusLogic_IncomingMailboxFree) { - BusLogic_CCB_T *CCB = NextIncomingMailbox->CCB; + BusLogic_CCB_T *CCB = + (BusLogic_CCB_T *) Bus_to_Virtual(NextIncomingMailbox->CCB); if (MailboxCompletionCode != BusLogic_AbortedCommandNotFound) if (CCB->Status == BusLogic_CCB_Active || CCB->Status == BusLogic_CCB_Reset) @@ -2211,11 +2216,11 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, is not marked as status Active or Reset, then there is most likely a bug in the Host Adapter firmware. */ - printk("scsi%d: Illegal CCB #%d status %d in " + printk("scsi%d: Illegal CCB #%ld status %d in " "Incoming Mailbox\n", HostAdapter->HostNumber, CCB->SerialNumber, CCB->Status); } - else printk("scsi%d: Aborted CCB #%d to Target %d " + else printk("scsi%d: Aborted CCB #%ld to Target %d " "Not Found\n", HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); NextIncomingMailbox->CompletionCode = @@ -2252,8 +2257,8 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, */ if (CCB->Opcode == BusLogic_BusDeviceReset) { - unsigned char TargetID = CCB->TargetID; - printk("scsi%d: Bus Device Reset CCB #%d to Target %d Completed\n", + int TargetID = CCB->TargetID; + printk("scsi%d: Bus Device Reset CCB #%ld to Target %d Completed\n", HostAdapter->HostNumber, CCB->SerialNumber, TargetID); HostAdapter->TotalCommandCount[TargetID] = 0; HostAdapter->TaggedQueuingActive[TargetID] = false; @@ -2301,7 +2306,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, { case BusLogic_IncomingMailboxFree: case BusLogic_AbortedCommandNotFound: - printk("scsi%d: CCB #%d to Target %d Impossible State\n", + printk("scsi%d: CCB #%ld to Target %d Impossible State\n", HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); break; case BusLogic_CommandCompletedWithoutError: @@ -2309,7 +2314,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, Command->result = DID_OK << 16; break; case BusLogic_CommandAbortedAtHostRequest: - printk("scsi%d: CCB #%d to Target %d Aborted\n", + printk("scsi%d: CCB #%ld to Target %d Aborted\n", HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID); Command->result = DID_ABORT << 16; break; @@ -2321,7 +2326,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, if (CCB->HostAdapterStatus != BusLogic_SCSISelectionTimeout) { int i; - printk("scsi%d: CCB #%d Target %d: Result %X " + printk("scsi%d: CCB #%ld Target %d: Result %X " "Host Adapter Status %02X Target Status %02X\n", HostAdapter->HostNumber, CCB->SerialNumber, CCB->TargetID, Command->result, @@ -2332,7 +2337,7 @@ static void BusLogic_InterruptHandler(int IRQ_Channel, printk("\n"); printk("scsi%d: Sense ", HostAdapter->HostNumber); for (i = 0; i < CCB->SenseDataLength; i++) - printk(" %02X", (*CCB->SenseDataPointer)[i]); + printk(" %02X", Command->sense_buffer[i]); printk("\n"); } break; @@ -2388,7 +2393,7 @@ static boolean BusLogic_WriteOutgoingMailbox(BusLogic_HostAdapter_T the Host Adapter is operating asynchronously and the locking code does not protect against simultaneous access by the Host Adapter. */ - NextOutgoingMailbox->CCB = CCB; + NextOutgoingMailbox->CCB = Virtual_to_Bus(CCB); NextOutgoingMailbox->ActionCode = ActionCode; BusLogic_StartMailboxCommand(HostAdapter); if (++NextOutgoingMailbox > HostAdapter->LastOutgoingMailbox) @@ -2413,9 +2418,9 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command, BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Command->host->hostdata; unsigned char *CDB = Command->cmnd; - unsigned char CDB_Length = Command->cmd_len; - unsigned char TargetID = Command->target; - unsigned char LogicalUnit = Command->lun; + int CDB_Length = Command->cmd_len; + int TargetID = Command->target; + int LogicalUnit = Command->lun; void *BufferPointer = Command->request_buffer; int BufferLength = Command->request_bufflen; int SegmentCount = Command->use_sg; @@ -2461,7 +2466,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command, { CCB->Opcode = BusLogic_InitiatorCCB; CCB->DataLength = BufferLength; - CCB->DataPointer = BufferPointer; + CCB->DataPointer = Virtual_to_Bus(BufferPointer); } else { @@ -2469,13 +2474,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command, int Segment; CCB->Opcode = BusLogic_InitiatorCCB_ScatterGather; CCB->DataLength = SegmentCount * sizeof(BusLogic_ScatterGatherSegment_T); - CCB->DataPointer = CCB->ScatterGatherList; + CCB->DataPointer = Virtual_to_Bus(CCB->ScatterGatherList); for (Segment = 0; Segment < SegmentCount; Segment++) { CCB->ScatterGatherList[Segment].SegmentByteCount = ScatterList[Segment].length; CCB->ScatterGatherList[Segment].SegmentDataPointer = - ScatterList[Segment].address; + Virtual_to_Bus(ScatterList[Segment].address); } } switch (CDB[0]) @@ -2515,13 +2520,13 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command, the Host Adapter and Target Device can establish Synchronous and Wide Transfer before Queue Tag messages can interfere with the Synchronous and Wide Negotiation message. By waiting to enable Tagged Queuing until after - the first BusLogic_MaxTaggedQueueDepth commands have been sent, it is + the first BusLogic_PreferredQueueDepth commands have been sent, it is assured that after a Reset any pending commands are resent before Tagged Queuing is enabled and that the Tagged Queuing message will not occur while the partition table is being printed. */ if (HostAdapter->TotalCommandCount[TargetID]++ == - BusLogic_MaxTaggedQueueDepth && + BusLogic_PreferredTaggedQueueDepth && (HostAdapter->TaggedQueuingPermitted & (1 << TargetID)) && Command->device->tagged_supported) { @@ -2564,7 +2569,7 @@ int BusLogic_QueueCommand(SCSI_Command_T *Command, } } memcpy(CCB->CDB, CDB, CDB_Length); - CCB->SenseDataPointer = (SCSI_SenseData_T *) &Command->sense_buffer; + CCB->SenseDataPointer = Virtual_to_Bus(&Command->sense_buffer); CCB->Command = Command; Command->scsi_done = CompletionRoutine; /* @@ -2608,7 +2613,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command) { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Command->host->hostdata; - unsigned char TargetID = Command->target; + int TargetID = Command->target; BusLogic_Lock_T Lock; BusLogic_CCB_T *CCB; int Result; @@ -2666,7 +2671,7 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command) if (HostAdapter->TaggedQueuingActive[TargetID] && HostAdapter->FirmwareVersion[0] < '5') { - printk("scsi%d: Unable to Abort CCB #%d to Target %d - " + printk("scsi%d: Unable to Abort CCB #%ld to Target %d - " "Abort Tag Not Supported\n", HostAdapter->HostNumber, CCB->SerialNumber, TargetID); Result = SCSI_ABORT_SNOOZE; @@ -2674,13 +2679,13 @@ int BusLogic_AbortCommand(SCSI_Command_T *Command) else if (BusLogic_WriteOutgoingMailbox(HostAdapter, BusLogic_MailboxAbortCommand, CCB)) { - printk("scsi%d: Aborting CCB #%d to Target %d\n", + printk("scsi%d: Aborting CCB #%ld to Target %d\n", HostAdapter->HostNumber, CCB->SerialNumber, TargetID); Result = SCSI_ABORT_PENDING; } else { - printk("scsi%d: Unable to Abort CCB #%d to Target %d - " + printk("scsi%d: Unable to Abort CCB #%ld to Target %d - " "No Outgoing Mailboxes\n", HostAdapter->HostNumber, CCB->SerialNumber, TargetID); Result = SCSI_ABORT_BUSY; @@ -2827,7 +2832,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter, SCSI_Command_T *Command, unsigned int ResetFlags) { - unsigned char TargetID = Command->target; + int TargetID = Command->target; BusLogic_Lock_T Lock; BusLogic_CCB_T *CCB; int Result = -1; @@ -2913,7 +2918,7 @@ static int BusLogic_SendBusDeviceReset(BusLogic_HostAdapter_T *HostAdapter, */ CCB = BusLogic_AllocateCCB(HostAdapter); if (CCB == NULL) goto Done; - printk("scsi%d: Sending Bus Device Reset CCB #%d to Target %d\n", + printk("scsi%d: Sending Bus Device Reset CCB #%ld to Target %d\n", HostAdapter->HostNumber, CCB->SerialNumber, TargetID); CCB->Opcode = BusLogic_BusDeviceReset; CCB->TargetID = TargetID; @@ -2984,9 +2989,8 @@ int BusLogic_ResetCommand(SCSI_Command_T *Command, unsigned int ResetFlags) { BusLogic_HostAdapter_T *HostAdapter = (BusLogic_HostAdapter_T *) Command->host->hostdata; - unsigned char TargetID = Command->target; - unsigned char ErrorRecoveryStrategy = - HostAdapter->ErrorRecoveryStrategy[TargetID]; + int TargetID = Command->target; + int ErrorRecoveryStrategy = HostAdapter->ErrorRecoveryStrategy[TargetID]; /* Disable Tagged Queuing if it is active for this Target Device and if it has been less than 10 minutes since the last reset occurred, or since @@ -3255,7 +3259,8 @@ void BusLogic_Setup(char *Strings, int *Integers) BusLogic_CommandLineEntry_T *CommandLineEntry = &BusLogic_CommandLineEntries[BusLogic_CommandLineEntryCount++]; static int ProbeListIndex = 0; - int IntegerCount = Integers[0], TargetID, i; + int IntegerCount = Integers[0]; + int TargetID, i; CommandLineEntry->IO_Address = 0; CommandLineEntry->TaggedQueueDepth = 0; CommandLineEntry->BusSettleTime = 0; @@ -3269,7 +3274,7 @@ void BusLogic_Setup(char *Strings, int *Integers) printk("BusLogic: Unexpected Command Line Integers ignored\n"); if (IntegerCount >= 1) { - unsigned short IO_Address = Integers[1]; + unsigned int IO_Address = Integers[1]; if (IO_Address > 0) { for (i = 0; ; i++) diff --git a/drivers/scsi/BusLogic.h b/drivers/scsi/BusLogic.h index 5d9cb3d508d3..90b87c03fbe2 100644 --- a/drivers/scsi/BusLogic.h +++ b/drivers/scsi/BusLogic.h @@ -119,12 +119,13 @@ int BusLogic_BIOSDiskParameters(SCSI_Disk_T *, KernelDevice_T, int *); /* - Define the maximum and default Queue Depth to allow for Target Devices - depending on whether or not they support Tagged Queuing and whether or not - ISA Bounce Buffers are required. + Define the maximum, preferred, and default Queue Depth to allow for Target + Devices depending on whether or not they support Tagged Queuing and whether + or not ISA Bounce Buffers are required. */ -#define BusLogic_MaxTaggedQueueDepth 31 +#define BusLogic_MaxTaggedQueueDepth 63 +#define BusLogic_PreferredTaggedQueueDepth 28 #define BusLogic_TaggedQueueDepth_BB 2 #define BusLogic_UntaggedQueueDepth 3 @@ -191,6 +192,13 @@ static char typedef unsigned char boolean; +/* + Define a 32 bit bus address data type. +*/ + +typedef unsigned int bus_address_t; + + /* Define the BusLogic SCSI Host Adapter I/O Register Offsets. */ @@ -401,7 +409,7 @@ BusLogic_SetupInformation_T; typedef struct BusLogic_ExtendedMailboxRequest { unsigned char MailboxCount; /* Byte 0 */ - void *BaseMailboxAddress __attribute__ ((packed)); /* Bytes 1-4 */ + bus_address_t BaseMailboxAddress __attribute__ ((packed)); /* Bytes 1-4 */ } BusLogic_ExtendedMailboxRequest_T; @@ -466,7 +474,7 @@ typedef struct BusLogic_ExtendedSetupInformation unsigned char BIOS_Address; /* Byte 1 */ unsigned short ScatterGatherLimit; /* Bytes 2-3 */ unsigned char MailboxCount; /* Byte 4 */ - void *BaseMailboxAddress __attribute__ ((packed)); /* Bytes 5-8 */ + bus_address_t BaseMailboxAddress __attribute__ ((packed)); /* Bytes 5-8 */ struct { unsigned char :6; /* Byte 9 Bits 0-5 */ boolean LevelSensitiveInterrupts:1; /* Byte 9 Bit 6 */ unsigned char :1; } Misc; /* Byte 9 Bit 7 */ @@ -708,15 +716,6 @@ BusLogic_QueueTag_T; typedef unsigned char SCSI_CDB_T[BusLogic_CDB_MaxLength]; -/* - Define the SCSI Sense Data. -*/ - -#define BusLogic_SenseDataMaxLength 255 - -typedef unsigned char SCSI_SenseData_T[BusLogic_SenseDataMaxLength]; - - /* Define the Scatter/Gather Segment structure required by the Host Adapter Firmware Interface. @@ -724,8 +723,8 @@ typedef unsigned char SCSI_SenseData_T[BusLogic_SenseDataMaxLength]; typedef struct BusLogic_ScatterGatherSegment { - unsigned long SegmentByteCount; /* Bytes 0-3 */ - void *SegmentDataPointer; /* Bytes 4-7 */ + unsigned int SegmentByteCount; /* Bytes 0-3 */ + bus_address_t SegmentDataPointer; /* Bytes 4-7 */ } BusLogic_ScatterGatherSegment_T; @@ -754,8 +753,8 @@ typedef struct BusLogic_CCB BusLogic_QueueTag_T WideModeQueueTag:2; /* Byte 1 Bits 6-7 */ unsigned char CDB_Length; /* Byte 2 */ unsigned char SenseDataLength; /* Byte 3 */ - unsigned long DataLength; /* Bytes 4-7 */ - void *DataPointer; /* Bytes 8-11 */ + unsigned int DataLength; /* Bytes 4-7 */ + bus_address_t DataPointer; /* Bytes 8-11 */ unsigned char :8; /* Byte 12 */ unsigned char :8; /* Byte 13 */ BusLogic_HostAdapterStatus_T HostAdapterStatus:8; /* Byte 14 */ @@ -767,8 +766,8 @@ typedef struct BusLogic_CCB SCSI_CDB_T CDB; /* Bytes 18-29 */ unsigned char :8; /* Byte 30 */ unsigned char :8; /* Byte 31 */ - unsigned long :32; /* Bytes 32-35 */ - SCSI_SenseData_T *SenseDataPointer; /* Bytes 36-39 */ + unsigned int :32; /* Bytes 32-35 */ + bus_address_t SenseDataPointer; /* Bytes 36-39 */ /* BusLogic Linux Driver Portion. */ @@ -779,7 +778,7 @@ typedef struct BusLogic_CCB BusLogic_CCB_Completed = 2, BusLogic_CCB_Reset = 3 } Status; BusLogic_CompletionCode_T MailboxCompletionCode; - unsigned int SerialNumber; + unsigned long SerialNumber; struct BusLogic_CCB *Next; struct BusLogic_CCB *NextAll; BusLogic_ScatterGatherSegment_T @@ -794,8 +793,8 @@ BusLogic_CCB_T; typedef struct BusLogic_OutgoingMailbox { - BusLogic_CCB_T *CCB; /* Bytes 0-3 */ - unsigned long :24; /* Byte 4 */ + bus_address_t CCB; /* Bytes 0-3 */ + unsigned int :24; /* Byte 4 */ BusLogic_ActionCode_T ActionCode:8; /* Bytes 5-7 */ } BusLogic_OutgoingMailbox_T; @@ -807,7 +806,7 @@ BusLogic_OutgoingMailbox_T; typedef struct BusLogic_IncomingMailbox { - BusLogic_CCB_T *CCB; /* Bytes 0-3 */ + bus_address_t CCB; /* Bytes 0-3 */ BusLogic_HostAdapterStatus_T HostAdapterStatus:8; /* Byte 4 */ BusLogic_TargetDeviceStatus_T TargetDeviceStatus:8; /* Byte 5 */ unsigned char :8; /* Byte 6 */ @@ -842,7 +841,7 @@ static char typedef struct BusLogic_CommandLineEntry { - unsigned short IO_Address; + unsigned int IO_Address; unsigned short TaggedQueueDepth; unsigned short BusSettleTime; unsigned short LocalOptions; @@ -860,12 +859,12 @@ BusLogic_CommandLineEntry_T; typedef struct BusLogic_HostAdapter { SCSI_Host_T *SCSI_Host; + unsigned int IO_Address; unsigned char HostNumber; unsigned char ModelName[9]; unsigned char FirmwareVersion[6]; unsigned char BoardName[18]; unsigned char InterruptLabel[62]; - unsigned short IO_Address; unsigned char IRQ_Channel; unsigned char DMA_Channel; unsigned char SCSI_ID; @@ -901,7 +900,7 @@ typedef struct BusLogic_HostAdapter unsigned short LocalOptions; unsigned short DisconnectPermitted; unsigned short TaggedQueuingPermitted; - unsigned long BIOS_Address; + bus_address_t BIOS_Address; BusLogic_InstalledDevices_T InstalledDevices; BusLogic_SynchronousValues_T SynchronousValues; BusLogic_SynchronousPeriod_T SynchronousPeriod; @@ -1063,6 +1062,22 @@ static inline void BusLogic_Delay(int Seconds) } +/* + Virtual_to_Bus and Bus_to_Virtual map between Kernel Virtual Addresses + and PCI/VLB/EISA/ISA Bus Addresses. +*/ + +static inline bus_address_t Virtual_to_Bus(void *VirtualAddress) +{ + return (bus_address_t) virt_to_bus(VirtualAddress); +} + +static inline void *Bus_to_Virtual(bus_address_t BusAddress) +{ + return (void *) bus_to_virt(BusAddress); +} + + /* Define prototypes for the forward referenced BusLogic Driver Internal Functions. diff --git a/drivers/scsi/Config.in b/drivers/scsi/Config.in index 3b376cab08d2..78468da1e091 100644 --- a/drivers/scsi/Config.in +++ b/drivers/scsi/Config.in @@ -15,15 +15,13 @@ mainmenu_option next_comment comment 'SCSI low-level drivers' dep_tristate '7000FASST SCSI support' CONFIG_SCSI_7000FASST $CONFIG_SCSI -dep_tristate 'Adaptec AHA152X support' CONFIG_SCSI_AHA152X $CONFIG_SCSI +dep_tristate 'Adaptec AHA152X/2825 support' CONFIG_SCSI_AHA152X $CONFIG_SCSI dep_tristate 'Adaptec AHA1542 support' CONFIG_SCSI_AHA1542 $CONFIG_SCSI dep_tristate 'Adaptec AHA1740 support' CONFIG_SCSI_AHA1740 $CONFIG_SCSI dep_tristate 'Adaptec AHA274X/284X/294X support' CONFIG_SCSI_AIC7XXX $CONFIG_SCSI dep_tristate 'AdvanSys SCSI support' CONFIG_SCSI_ADVANSYS $CONFIG_SCSI dep_tristate 'Always IN2000 SCSI support' CONFIG_SCSI_IN2000 $CONFIG_SCSI -if [ "$CONFIG_PCI" = "y" ]; then - bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 -fi +bool 'AM53/79C974 PCI SCSI support' CONFIG_SCSI_AM53C974 dep_tristate 'BusLogic SCSI support' CONFIG_SCSI_BUSLOGIC $CONFIG_SCSI dep_tristate 'DTC3180/3280 SCSI support' CONFIG_SCSI_DTC3280 $CONFIG_SCSI dep_tristate 'EATA ISA/EISA (DPT PM2011/021/012/022/122/322) support' CONFIG_SCSI_EATA $CONFIG_SCSI diff --git a/drivers/scsi/README.BusLogic b/drivers/scsi/README.BusLogic index d99797e84eb2..e363b1476c69 100644 --- a/drivers/scsi/README.BusLogic +++ b/drivers/scsi/README.BusLogic @@ -1,9 +1,9 @@ BusLogic MultiMaster SCSI Driver for Linux - Version 1.2.3 for Linux 1.2.13 - Version 2.0.3 for Linux 2.0.0 + Version 1.2.4 for Linux 1.2.13 + Version 2.0.4 for Linux 2.0.0 - 17 May 1996 + 5 June 1996 Leonard N. Zubkoff Dandelion Digital @@ -325,7 +325,7 @@ substantially impact performance. INSTALLATION This distribution was prepared for Linux kernel version 1.2.13 -(BusLogic-1.2.3.tar.gz) or Linux kernel version 2.0.0 (BusLogic-2.0.3.tar.gz). +(BusLogic-1.2.4.tar.gz) or Linux kernel version 2.0.0 (BusLogic-2.0.4.tar.gz). Installation in later versions will probably be successful as well, though BusLogic.patch may not be required. Installation in earlier versions is not recommended. @@ -335,7 +335,7 @@ replacing "/usr/src" with wherever you keep your Linux kernel source tree (substitute "1.2" or "2.0" for "x.y" in the tar command as appropriate): cd /usr/src - tar -xvzf BusLogic-x.y.3.tar.gz + tar -xvzf BusLogic-x.y.4.tar.gz mv README.* BusLogic.[ch] linux/drivers/scsi patch -p < BusLogic.patch (on Linux 1.2.13 only) patch -p < BusLogic.elf_patch (on Linux 1.2.13 ELF systems only) diff --git a/drivers/scsi/in2000.readme b/drivers/scsi/in2000.readme index 80a3a7f0bcc3..1aefc0a6b6e6 100644 --- a/drivers/scsi/in2000.readme +++ b/drivers/scsi/in2000.readme @@ -97,6 +97,48 @@ the bus ever care what it is? Is cable quality a factor here? Regardless, you can choose your own default through the command- line with the 'period' keyword. + +------------------------------------------------ +*********** DIP switch settings ************** +------------------------------------------------ + + sw1-1 sw1-2 BIOS address (hex) + ----------------------------------------- + off off C8000 - CBFF0 + on off D8000 - DBFF0 + off on D0000 - D3FF0 + on on BIOS disabled + + sw1-3 sw1-4 IO port address (hex) + ------------------------------------ + off off 220 - 22F + on off 200 - 20F + off on 110 - 11F + on on 100 - 10F + + sw1-5 sw1-6 sw1-7 Interrupt + ------------------------------ + off off off 15 + off on off 14 + off off on 11 + off on on 10 + on - - disabled + + sw1-8 function depends on BIOS version. In earlier versions this + controlled synchronous data transfer support for MSDOS: + off = disabled + on = enabled + In later ROMs (starting with 01.3 in April 1994) sw1-8 controls + the "greater than 2 disk drive" feature that first appeared in + MSDOS 5.0 (ignored by linux): + off = 2 drives maximum + on = 7 drives maximum + + sw1-9 Floppy controller + -------------------------- + off disabled + on enabled + ------------------------------------------------ I should mention that Drew Eckhardt's 'Generic NCR5380' sources diff --git a/drivers/scsi/qlogicisp.c b/drivers/scsi/qlogicisp.c index 586c02f2117a..875ec8e0911b 100644 --- a/drivers/scsi/qlogicisp.c +++ b/drivers/scsi/qlogicisp.c @@ -48,10 +48,10 @@ #include #include #include -#include +#include +#include #include #include -#include #include "sd.h" #include "hosts.h" @@ -71,10 +71,6 @@ #define USE_NVRAM_DEFAULTS 0 -/* Set this macro to 1 if you want to create a scsi loadable module. */ - -#define MODULE 0 - /* Macros used for debugging */ #define DEBUG_ISP1020 0 @@ -1681,8 +1677,8 @@ int isp1020_return_status(struct Status_Entry *sts) return (sts->scsi_status & STATUS_MASK) | (host_status << 16); } -#if MODULE -Scsi_Host_Template driver_template = ISP1020; +#ifdef MODULE +Scsi_Host_Template driver_template = QLOGICISP; #include "scsi_module.c" #endif /* MODULE */ diff --git a/drivers/scsi/scsi.h b/drivers/scsi/scsi.h index 22c361a9ea92..7c6fae3bcef6 100644 --- a/drivers/scsi/scsi.h +++ b/drivers/scsi/scsi.h @@ -21,6 +21,8 @@ */ #include +#include + /* * Some defs, in case these are not defined elsewhere. @@ -526,6 +528,7 @@ static Scsi_Cmnd * end_scsi_request(Scsi_Cmnd * SCpnt, int uptodate, int sectors if (req->sem != NULL) { up(req->sem); } + add_blkdev_randomness(MAJOR(req->rq_dev)); if (SCpnt->host->block) { struct Scsi_Host * next; diff --git a/fs/Config.in b/fs/Config.in index 770b002c6176..c47e539c3f76 100644 --- a/fs/Config.in +++ b/fs/Config.in @@ -28,6 +28,9 @@ if [ "$CONFIG_INET" = "y" ]; then fi fi tristate 'SMB filesystem support (to mount WfW shares etc..)' CONFIG_SMB_FS + if [ "$CONFIG_SMB_FS" != "n" -a "$CONFIG_EXPERIMENTAL" = "y" ]; then + bool 'SMB long filename support (EXPERIMENTAL)' CONFIG_SMB_LONG + fi fi if [ "$CONFIG_IPX" != "n" ]; then tristate 'NCP filesystem support (to mount NetWare volumes)' CONFIG_NCP_FS diff --git a/fs/file_table.c b/fs/file_table.c index a1f215c73315..00777dc8ad9d 100644 --- a/fs/file_table.c +++ b/fs/file_table.c @@ -101,8 +101,15 @@ unsigned long file_table_init(unsigned long start, unsigned long end) struct file * get_empty_filp(void) { int i; + int max = max_files; struct file * f; + /* + * Reserve a few files for the super-user.. + */ + if (current->euid) + max -= 10; + /* if the return is taken, we are in deep trouble */ if (!first_file && !grow_files()) return NULL; @@ -117,7 +124,7 @@ struct file * get_empty_filp(void) f->f_version = ++event; return f; } - } while (nr_files < max_files && grow_files()); + } while (nr_files < max && grow_files()); return NULL; } diff --git a/fs/nfs/rpcsock.c b/fs/nfs/rpcsock.c index d2d215a01205..9a7b33ec6aae 100644 --- a/fs/nfs/rpcsock.c +++ b/fs/nfs/rpcsock.c @@ -302,7 +302,7 @@ static inline int rpc_send(struct rpc_sock *rsock, struct rpc_wait *slot) { struct rpc_ioreq *req = slot->w_req; - struct iovec iov[MAX_IOVEC]; + struct iovec iov[UIO_MAXIOV]; if (rsock->shutdown) return -EIO; @@ -336,7 +336,7 @@ rpc_grok(struct rpc_sock *rsock) { struct rpc_wait *rovr; struct rpc_ioreq *req; - struct iovec iov[MAX_IOVEC]; + struct iovec iov[UIO_MAXIOV]; u32 xid; int safe, result; diff --git a/fs/read_write.c b/fs/read_write.c index d0db64f7a274..181eb6946da6 100644 --- a/fs/read_write.c +++ b/fs/read_write.c @@ -203,7 +203,7 @@ static int do_readv_writev(int type, struct inode * inode, struct file * file, const struct iovec * vector, unsigned long count) { size_t tot_len; - struct iovec iov[MAX_IOVEC]; + struct iovec iov[UIO_MAXIOV]; int retval, i; IO_fn_t fn; @@ -213,7 +213,7 @@ static int do_readv_writev(int type, struct inode * inode, struct file * file, */ if (!count) return 0; - if (count > MAX_IOVEC) + if (count > UIO_MAXIOV) return -EINVAL; retval = verify_area(VERIFY_READ, vector, count*sizeof(*vector)); if (retval) diff --git a/fs/smbfs/dir.c b/fs/smbfs/dir.c index 2c09443cc82c..1995a790a2b3 100644 --- a/fs/smbfs/dir.c +++ b/fs/smbfs/dir.c @@ -937,20 +937,3 @@ smb_rename(struct inode *old_dir, const char *old_name, int old_len, iput(new_dir); return res; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/fs/smbfs/file.c b/fs/smbfs/file.c index 9a64f012a4c6..6321ad921ece 100644 --- a/fs/smbfs/file.c +++ b/fs/smbfs/file.c @@ -258,20 +258,3 @@ struct inode_operations smb_file_inode_operations = { NULL, /* bmap */ NULL /* truncate */ }; - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/fs/smbfs/inode.c b/fs/smbfs/inode.c index 7dd2e2a35b72..e2374756d21c 100644 --- a/fs/smbfs/inode.c +++ b/fs/smbfs/inode.c @@ -444,20 +444,3 @@ cleanup_module(void) } #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/fs/smbfs/ioctl.c b/fs/smbfs/ioctl.c index 64cc621a945e..00c32245442c 100644 --- a/fs/smbfs/ioctl.c +++ b/fs/smbfs/ioctl.c @@ -31,21 +31,3 @@ smb_ioctl (struct inode * inode, struct file * filp, return -EINVAL; } } - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/fs/smbfs/mmap.c b/fs/smbfs/mmap.c index db97623156d3..1baec2a0ba5c 100644 --- a/fs/smbfs/mmap.c +++ b/fs/smbfs/mmap.c @@ -120,20 +120,3 @@ smb_mmap(struct inode * inode, struct file * file, struct vm_area_struct * vma) vma->vm_ops = &smb_file_mmap; return 0; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/fs/smbfs/proc.c b/fs/smbfs/proc.c index a3627d1083dd..150506aee2cd 100644 --- a/fs/smbfs/proc.c +++ b/fs/smbfs/proc.c @@ -5,6 +5,7 @@ * */ +#include #include #include #include @@ -1603,12 +1604,14 @@ smb_proc_reconnect(struct smb_server *server) { PROTOCOL_LANMAN1,"MICROSOFT NETWORKS 3.0"}, { PROTOCOL_LANMAN1,"LANMAN1.0"}, #endif +#ifdef CONFIG_SMB_LONG #ifdef LANMAN2 { PROTOCOL_LANMAN2,"LM1.2X002"}, #endif #ifdef NT1 { PROTOCOL_NT1,"NT LM 0.12"}, { PROTOCOL_NT1,"NT LANMAN 1.0"}, +#endif #endif {-1, NULL} }; char dev[] = "A:"; @@ -2026,20 +2029,3 @@ smb_printerr(int class, int num) } #endif /* DEBUG_SMB > 0 */ - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/fs/smbfs/sock.c b/fs/smbfs/sock.c index c7d96d247aaf..ae6b1032777d 100644 --- a/fs/smbfs/sock.c +++ b/fs/smbfs/sock.c @@ -768,20 +768,3 @@ smb_request_write_raw(struct smb_server *server, return result; } - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/include/asm-i386/resource.h b/include/asm-i386/resource.h index 83940d16a5ad..3143b5bb29c9 100644 --- a/include/asm-i386/resource.h +++ b/include/asm-i386/resource.h @@ -14,8 +14,9 @@ #define RLIMIT_NPROC 6 /* max number of processes */ #define RLIMIT_NOFILE 7 /* max number of open files */ #define RLIMIT_MEMLOCK 8 /* max locked-in-memory address space */ +#define RLIMIT_AS 9 /* address space limit */ -#define RLIM_NLIMITS 9 +#define RLIM_NLIMITS 10 #ifdef __KERNEL__ @@ -30,6 +31,7 @@ { MAX_TASKS_PER_USER, MAX_TASKS_PER_USER }, \ { NR_OPEN, NR_OPEN }, \ { LONG_MAX, LONG_MAX }, \ + { LONG_MAX, LONG_MAX }, \ } #endif /* __KERNEL__ */ diff --git a/include/linux/baycom.h b/include/linux/baycom.h index ea70a74da4dc..fb656acfd813 100644 --- a/include/linux/baycom.h +++ b/include/linux/baycom.h @@ -52,6 +52,11 @@ struct baycom_params { #define KISS_CMD_TXTAIL 4 #define KISS_CMD_FULLDUP 5 +/* + * use bottom halves? (HDLC processing done with interrupts on or off) + */ +#define BAYCOM_USE_BH + /* * modem types */ diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 77cd07c8f672..d9b59b045b61 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -33,6 +33,7 @@ enum { DIGI_BH, SERIAL_BH, RISCOM8_BH, + BAYCOM_BH, NET_BH, IMMEDIATE_BH, KEYBOARD_BH, diff --git a/include/linux/mcdx.h b/include/linux/mcdx.h index 91d616073e03..318886ca2e07 100644 --- a/include/linux/mcdx.h +++ b/include/linux/mcdx.h @@ -1,7 +1,7 @@ /* * Definitions for the Mitsumi CDROM interface - * (H) Hackright 1996 by Marcin Dalecki - * VERSION: 2.5 + * Copyright (C) 1995 1996 Heiko Schlittermann + * VERSION: @VERSION@ * * 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 @@ -16,102 +16,169 @@ * You should have received a copy of the GNU General Public License * along with this program; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. + * + * Thanks to + * The Linux Community at all and ... + * Martin Harris (he wrote the first Mitsumi Driver) + * Eberhard Moenkeberg (he gave me much support and the initial kick) + * Bernd Huebner, Ruediger Helsch (Unifix-Software Gmbh, they + * improved the original driver) + * Jon Tombs, Bjorn Ekwall (module support) + * Daniel v. Mosnenck (he sent me the Technical and Programming Reference) + * Gerd Knorr (he lent me his PhotoCD) + * Nils Faerber and Roger E. Wolff (extensivly tested the LU portion) + * Andreas Kies (testing the mysterious hang up's) + * ... somebody forgotten? + * Marcin Dalecki + * */ -#ifndef __MCDX_H -#define __MCDX_H /* - * PLEASE CONFIGURE THIS ACCORDING TO YOUR HARDWARE/JUMPER SETTINGS. + * The following lines are for user configuration + * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + * + * {0|1} -- 1 if you want the driver detect your drive, may crash and + * needs a long time to seek. The higher the address the longer the + * seek. * - * o MCDX_NDRIVES : number of used entries of the following table - * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller + * WARNING: AUTOPROBE doesn't work. + */ +#define MCDX_AUTOPROBE 0 + +/* + * Drive specific settings according to the jumpers on the controller + * board(s). + * o MCDX_NDRIVES : number of used entries of the following table + * o MCDX_DRIVEMAP : table of {i/o base, irq} per controller * - * NOTE: Don't even think about connecting the drive to IRQ 9(2). - * In the AT architecture this interrupt is used to cascade the two - * interrupt controllers and isn't therefore usable for anything else! + * NOTE: I didn't get a drive at irq 9(2) working. Not even alone. */ - /* #define I_WAS_IN_MCDX_H */ -#define MCDX_NDRIVES 1 -#define MCDX_DRIVEMAP { {0x230, 11}, \ +#if MCDX_AUTOPROBE == 0 + #define MCDX_NDRIVES 1 + #define MCDX_DRIVEMAP { \ + {0x300, 11}, \ {0x304, 05}, \ {0x000, 00}, \ {0x000, 00}, \ {0x000, 00}, \ -} - -/* - * !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!NO USER INTERVENTION NEEDED BELOW - * If You are sure that all configuration is done, please uncomment the - * line below. - */ + } +#else + #error Autoprobing is not implemented yet. +#endif -#undef MCDX_DEBUG /* This is *REALLY* only for development! */ +#ifndef MCDX_QUIET +#define MCDX_QUIET 1 +#endif -#ifdef MCDX_DEBUG -#define MCDX_TRACE(x) printk x -#define MCDX_TRACE_IOCTL(x) printk x -#else -#define MCDX_TRACE(x) -#define MCDX_TRACE_IOCTL(x) +#ifndef MCDX_DEBUG +#define MCDX_DEBUG 0 #endif -/* The name of the device */ -#define MCDX "mcdx" +/* *** make the following line uncommented, if you're sure, + * *** all configuration is done */ +/* #define I_WAS_HERE */ +#define I_WAS_HERE /* delete this line, it's for heiko only */ -/* - * Per controller 4 bytes i/o are needed. +/* The name of the device */ +#define MCDX "mcdx" + +/* Flags for DEBUGGING */ +#define INIT 0 +#define MALLOC 0 +#define IOCTL 0 +#define PLAYTRK 0 +#define SUBCHNL 0 +#define TOCHDR 0 +#define MS 0 +#define PLAYMSF 0 +#define READTOC 0 +#define OPENCLOSE 0 +#define HW 0 +#define TALK 0 +#define IRQ 0 +#define XFER 0 +#define REQUEST 0 +#define SLEEP 0 + +/* The following addresses are taken from the Mitsumi Reference + * and describe the possible i/o range for the controller. */ +#define MCDX_IO_BEGIN ((char*) 0x300) /* first base of i/o addr */ +#define MCDX_IO_END ((char*) 0x3fc) /* last base of i/o addr */ + +/* Per controller 4 bytes i/o are needed. */ #define MCDX_IO_SIZE 4 -/* - * Masks for the status byte, returned from every command, set if - * the description is true +/* + * Bits */ + +/* The status byte, returned from every command, set if + * the description is true */ #define MCDX_RBIT_OPEN 0x80 /* door is open */ #define MCDX_RBIT_DISKSET 0x40 /* disk set (recognised) */ #define MCDX_RBIT_CHANGED 0x20 /* disk was changed */ #define MCDX_RBIT_CHECK 0x10 /* disk rotates, servo is on */ -#define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */ +#define MCDX_RBIT_AUDIOTR 0x08 /* current track is audio */ #define MCDX_RBIT_RDERR 0x04 /* read error, refer SENSE KEY */ #define MCDX_RBIT_AUDIOBS 0x02 /* currently playing audio */ #define MCDX_RBIT_CMDERR 0x01 /* command, param or format error */ -/* - * The I/O Register holding the h/w status of the drive, - * can be read at i/o base + 1 - */ +/* The I/O Register holding the h/w status of the drive, + * can be read at i/o base + 1 */ #define MCDX_RBIT_DOOR 0x10 /* door is open */ #define MCDX_RBIT_STEN 0x04 /* if 0, i/o base contains drive status */ #define MCDX_RBIT_DTEN 0x02 /* if 0, i/o base contains data */ /* - * The commands. + * The commands. + */ + +#define OPCODE 1 /* offset of opcode */ +#define MCDX_CMD_REQUEST_TOC 1, 0x10 +#define MCDX_CMD_REQUEST_STATUS 1, 0x40 +#define MCDX_CMD_RESET 1, 0x60 +#define MCDX_CMD_REQUEST_DRIVE_MODE 1, 0xc2 +#define MCDX_CMD_SET_INTERLEAVE 2, 0xc8, 0 +#define MCDX_CMD_DATAMODE_SET 2, 0xa0, 0 + #define MCDX_DATAMODE1 0x01 + #define MCDX_DATAMODE2 0x02 +#define MCDX_CMD_LOCK_DOOR 2, 0xfe, 0 + +#define READ_AHEAD 4 /* 8 Sectors (4K) */ + +/* Useful macros */ +#define e_door(x) ((x) & MCDX_RBIT_OPEN) +#define e_check(x) (~(x) & MCDX_RBIT_CHECK) +#define e_notset(x) (~(x) & MCDX_RBIT_DISKSET) +#define e_changed(x) ((x) & MCDX_RBIT_CHANGED) +#define e_audio(x) ((x) & MCDX_RBIT_AUDIOTR) +#define e_audiobusy(x) ((x) & MCDX_RBIT_AUDIOBS) +#define e_cmderr(x) ((x) & MCDX_RBIT_CMDERR) +#define e_readerr(x) ((x) & MCDX_RBIT_RDERR) + +/** no drive specific */ +#define MCDX_CDBLK 2048 /* 2048 cooked data each blk */ + +#define MCDX_DATA_TIMEOUT (HZ/10) /* 0.1 second */ + +/* + * Access to the msf array */ -#define MCDX_CMD_GET_TOC 0x10 -#define MCDX_CMD_GET_MDISK_INFO 0x11 -#define MCDX_CMD_GET_SUBQ_CODE 0x20 -#define MCDX_CMD_GET_STATUS 0x40 -#define MCDX_CMD_SET_DRIVE_MODE 0x50 -#define MCDX_CMD_RESET 0x60 -#define MCDX_CMD_HOLD 0x70 -#define MCDX_CMD_CONFIG 0x90 -#define MCDX_CMD_SET_ATTENATOR 0xae -#define MCDX_CMD_PLAY 0xc0 -#define MCDX_CMD_PLAY_2X 0xc1 -#define MCDX_CMD_GET_DRIVE_MODE 0xc2 -#define MCDX_CMD_SET_INTERLEAVE 0xc8 -#define MCDX_CMD_GET_FIRMWARE 0xdc -#define MCDX_CMD_SET_DATA_MODE 0xa0 -#define MCDX_CMD_STOP 0xf0 -#define MCDX_CMD_EJECT 0xf6 -#define MCDX_CMD_CLOSE_DOOR 0xf8 -#define MCDX_CMD_LOCK_DOOR 0xfe - -#define READ_AHEAD 8 /* 16 Sectors (4K) */ - -#ifndef I_WAS_IN_MCDX_H +#define MSF_MIN 0 /* minute */ +#define MSF_SEC 1 /* second */ +#define MSF_FRM 2 /* frame */ + +/* + * Errors + */ +#define MCDX_E 1 /* unspec error */ +#define MCDX_ST_EOM 0x0100 /* end of media */ +#define MCDX_ST_DRV 0x00ff /* mask to query the drive status */ + +#ifndef I_WAS_HERE #warning You have not edited mcdx.h #warning Perhaps irq and i/o settings are wrong. #endif -#endif /* __MCDX_H */ +/* ex:set ts=4 sw=4: */ diff --git a/include/linux/netdevice.h b/include/linux/netdevice.h index cebd1a500db6..888f5f5d7884 100644 --- a/include/linux/netdevice.h +++ b/include/linux/netdevice.h @@ -28,7 +28,6 @@ #include #include #include -#include /* for future expansion when we will have different priorities. */ #define DEV_NUMBUFFS 3 @@ -205,6 +204,7 @@ struct packet_type { #ifdef __KERNEL__ +#include #include /* Used by dev_rint */ diff --git a/include/linux/random.h b/include/linux/random.h index 4911794401d0..b2706ce031b7 100644 --- a/include/linux/random.h +++ b/include/linux/random.h @@ -53,6 +53,9 @@ extern void add_blkdev_randomness(int major); extern void get_random_bytes(void *buf, int nbytes); +extern __u32 secure_tcp_sequence_number(__u32 saddr, __u32 daddr, + __u16 sport, __u16 dport); + #ifndef MODULE extern struct file_operations random_fops, urandom_fops; #endif diff --git a/include/linux/rpcsock.h b/include/linux/rpcsock.h index ab159fc1201b..9a7f5eae953f 100644 --- a/include/linux/rpcsock.h +++ b/include/linux/rpcsock.h @@ -53,10 +53,10 @@ struct rpc_ioreq { struct rpc_wait * rq_slot; struct sockaddr * rq_addr; int rq_alen; - struct iovec rq_svec[MAX_IOVEC]; + struct iovec rq_svec[UIO_MAXIOV]; unsigned int rq_snr; unsigned long rq_slen; - struct iovec rq_rvec[MAX_IOVEC]; + struct iovec rq_rvec[UIO_MAXIOV]; unsigned int rq_rnr; unsigned long rq_rlen; }; diff --git a/include/linux/sbpcd.h b/include/linux/sbpcd.h index 7c8f3ab3d706..a8ee20f59328 100644 --- a/include/linux/sbpcd.h +++ b/include/linux/sbpcd.h @@ -108,6 +108,7 @@ #if DISTRIBUTION #define READ_AUDIO 0 +#define KLOGD_PAUSE 55 #else /* max. number of audio frames to read with one */ /* request (allocates n* 2352 bytes kernel memory!) */ @@ -115,6 +116,14 @@ /* runtime by use of the CDROMAUDIOBUFSIZ ioctl. */ #define READ_AUDIO 75 +/* + * Time to wait after giving a message. + * This gets important if you enable non-standard DBG_xxx flags. + * You will see what happens if you omit the pause or make it + * too short. Be warned! + */ +#define KLOGD_PAUSE 1 + /* tray control: eject tray if no disk is in (0 or 1) */ #define JUKEBOX 1 @@ -134,6 +143,7 @@ /*==========================================================================*/ #define LONG_TIMING 0 /* test against timeouts with "gold" CDs on CR-521 */ #undef FUTURE +#undef SAFE_MIXED #define TEST_UPC 0 #define SPEA_TEST 0 diff --git a/include/linux/smb.h b/include/linux/smb.h index f85c78b67800..f54894b04547 100644 --- a/include/linux/smb.h +++ b/include/linux/smb.h @@ -104,21 +104,3 @@ struct smb_dirent { #endif /* __KERNEL__ */ #endif /* _LINUX_SMB_H */ - - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/include/linux/smb_fs_i.h b/include/linux/smb_fs_i.h index 436f99ac2977..b6e38fd180d6 100644 --- a/include/linux/smb_fs_i.h +++ b/include/linux/smb_fs_i.h @@ -32,20 +32,3 @@ struct smb_inode_info { #endif #endif - -/* - * Overrides for Emacs so that we follow Linus's tabbing style. - * Emacs will notice this stuff at the end of the file and automatically - * adjust the settings for this buffer only. This must remain at the end - * of the file. - * --------------------------------------------------------------------------- - * Local variables: - * c-indent-level: 8 - * c-brace-imaginary-offset: 0 - * c-brace-offset: -8 - * c-argdecl-indent: 8 - * c-label-offset: -8 - * c-continued-statement-offset: 8 - * c-continued-brace-offset: 0 - * End: - */ diff --git a/include/linux/smb_mount.h b/include/linux/smb_mount.h index 9fd88bd7a38d..994475be791b 100644 --- a/include/linux/smb_mount.h +++ b/include/linux/smb_mount.h @@ -36,5 +36,3 @@ struct smb_mount_data { }; #endif - - diff --git a/include/linux/uio.h b/include/linux/uio.h index 8051b3d00573..8027bc8d7a58 100644 --- a/include/linux/uio.h +++ b/include/linux/uio.h @@ -12,7 +12,7 @@ /* A word of warning: Our uio structure will clash with the C library one (which is now obsolete). Remove the C - library one from sys/uio.h */ + library one from sys/uio.h if you have a very old library set */ struct iovec { @@ -20,6 +20,7 @@ struct iovec int iov_len; }; -#define MAX_IOVEC 8 /* Maximum iovec's in one operation */ +#define UIO_MAXIOV 16 /* Maximum iovec's in one operation + 16 matches BSD */ #endif diff --git a/include/net/ip_masq.h b/include/net/ip_masq.h index f51cc7075f45..d69a3d1d2452 100644 --- a/include/net/ip_masq.h +++ b/include/net/ip_masq.h @@ -26,8 +26,12 @@ #define IP_MASQ_F_NO_DPORT 0x04 /* no dport set yet */ #define IP_MASQ_F_NO_DADDR 0x08 /* no daddr yet */ #define IP_MASQ_F_HASHED 0x10 /* hashed entry */ -#define IP_MASQ_F_SAW_FIN 0x20 /* tcp fin pkt seen */ -#define IP_MASQ_F_SAW_RST 0x40 /* tcp rst pkt seen */ +#define IP_MASQ_F_SAW_RST 0x20 /* tcp rst pkt seen */ +#define IP_MASQ_F_SAW_FIN_IN 0x40 /* tcp fin pkt seen incoming */ +#define IP_MASQ_F_SAW_FIN_OUT 0x80 /* tcp fin pkt seen outgoing */ +#define IP_MASQ_F_SAW_FIN (IP_MASQ_F_SAW_FIN_IN | \ + IP_MASQ_F_SAW_FIN_OUT) + /* tcp fin pkts seen */ #ifdef __KERNEL__ diff --git a/include/net/sock.h b/include/net/sock.h index c61922a68602..044f6525e203 100644 --- a/include/net/sock.h +++ b/include/net/sock.h @@ -214,7 +214,8 @@ struct sock __u32 lastwin_seq; /* sequence number when we last updated the window we offer */ __u32 high_seq; /* sequence number when we did current fast retransmit */ volatile unsigned long ato; /* ack timeout */ - volatile unsigned long lrcvtime; /* jiffies at last rcv */ + volatile unsigned long lrcvtime; /* jiffies at last data rcv */ + volatile unsigned long idletime; /* jiffies at last rcv */ unsigned short bytes_rcv; /* * mss is min(mtu, max_window) @@ -391,7 +392,7 @@ struct proto #define SOCK_DESTROY_TIME (10*HZ) /* - * Sockets 0-1023 can't be bound too unless you are superuser + * Sockets 0-1023 can't be bound to unless you are superuser */ #define PROT_SOCK 1024 diff --git a/kernel/sys.c b/kernel/sys.c index a6821332fa92..ba295172cad1 100644 --- a/kernel/sys.c +++ b/kernel/sys.c @@ -18,8 +18,6 @@ #include #include #include -#include -#include #include #include #include @@ -550,70 +548,6 @@ asmlinkage long sys_times(struct tms * tbuf) return jiffies; } -asmlinkage unsigned long sys_brk(unsigned long brk) -{ - int freepages; - unsigned long rlim; - unsigned long newbrk, oldbrk; - - if (brk < current->mm->end_code) - return current->mm->brk; - newbrk = PAGE_ALIGN(brk); - oldbrk = PAGE_ALIGN(current->mm->brk); - if (oldbrk == newbrk) - return current->mm->brk = brk; - - /* - * Always allow shrinking brk - */ - if (brk <= current->mm->brk) { - current->mm->brk = brk; - do_munmap(newbrk, oldbrk-newbrk); - return brk; - } - /* - * Check against rlimit and stack.. - */ - rlim = current->rlim[RLIMIT_DATA].rlim_cur; - if (rlim >= RLIM_INFINITY) - rlim = ~0; - if (brk - current->mm->end_code > rlim) - return current->mm->brk; - /* - * Check against existing mmap mappings. - */ - if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE)) - return current->mm->brk; - /* - * stupid algorithm to decide if we have enough memory: while - * simple, it hopefully works in most obvious cases.. Easy to - * fool it, but this should catch most mistakes. - */ - freepages = buffermem >> PAGE_SHIFT; - freepages += page_cache_size; - freepages >>= 1; - freepages += nr_free_pages; - freepages += nr_swap_pages; - freepages -= MAP_NR(high_memory) >> 4; - freepages -= (newbrk-oldbrk) >> PAGE_SHIFT; - if (freepages < 0) - return current->mm->brk; -#if 0 - freepages += current->mm->rss; - freepages -= oldbrk >> 12; - if (freepages < 0) - return current->mm->brk; -#endif - /* - * Ok, we have probably got enough memory - let it rip. - */ - current->mm->brk = brk; - do_mmap(NULL, oldbrk, newbrk-oldbrk, - PROT_READ|PROT_WRITE|PROT_EXEC, - MAP_FIXED|MAP_PRIVATE, 0); - return brk; -} - /* * This needs some heavy checking ... * I just haven't the stomach for it. I also don't fully diff --git a/mm/mmap.c b/mm/mmap.c index 047d1c3d14da..a46a3cc06a11 100644 --- a/mm/mmap.c +++ b/mm/mmap.c @@ -12,6 +12,8 @@ #include #include #include +#include +#include #include #include @@ -39,6 +41,78 @@ pgprot_t protection_map[16] = { __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; +/* + * Check that a process has enough memory to allocate a + * new virtual mapping. + */ +static inline int vm_enough_memory(long pages) +{ + /* + * stupid algorithm to decide if we have enough memory: while + * simple, it hopefully works in most obvious cases.. Easy to + * fool it, but this should catch most mistakes. + */ + long freepages; + freepages = buffermem >> PAGE_SHIFT; + freepages += page_cache_size; + freepages >>= 1; + freepages += nr_free_pages; + freepages += nr_swap_pages; + freepages -= MAP_NR(high_memory) >> 4; + return freepages > pages; +} + +asmlinkage unsigned long sys_brk(unsigned long brk) +{ + unsigned long rlim; + unsigned long newbrk, oldbrk; + + if (brk < current->mm->end_code) + return current->mm->brk; + newbrk = PAGE_ALIGN(brk); + oldbrk = PAGE_ALIGN(current->mm->brk); + if (oldbrk == newbrk) + return current->mm->brk = brk; + + /* + * Always allow shrinking brk + */ + if (brk <= current->mm->brk) { + current->mm->brk = brk; + do_munmap(newbrk, oldbrk-newbrk); + return brk; + } + /* + * Check against rlimit and stack.. + */ + rlim = current->rlim[RLIMIT_DATA].rlim_cur; + if (rlim >= RLIM_INFINITY) + rlim = ~0; + if (brk - current->mm->end_code > rlim) + return current->mm->brk; + + /* + * Check against existing mmap mappings. + */ + if (find_vma_intersection(current, oldbrk, newbrk+PAGE_SIZE)) + return current->mm->brk; + + /* + * Check if we have enough memory.. + */ + if (!vm_enough_memory((newbrk-oldbrk) >> PAGE_SHIFT)) + return current->mm->brk; + + /* + * Ok, looks good - let it rip. + */ + current->mm->brk = brk; + do_mmap(NULL, oldbrk, newbrk-oldbrk, + PROT_READ|PROT_WRITE|PROT_EXEC, + MAP_FIXED|MAP_PRIVATE, 0); + return brk; +} + /* * Combine the mmap "prot" and "flags" argument into one "vm_flags" used * internally. Essentially, translate the "PROT_xxx" and "MAP_xxx" bits @@ -179,6 +253,14 @@ unsigned long do_mmap(struct file * file, unsigned long addr, unsigned long len, do_munmap(addr, len); /* Clear old maps */ + /* Private writable mapping? Check memory availability.. */ + if ((vma->vm_flags & (VM_SHARED | VM_WRITE)) == VM_WRITE) { + if (!vm_enough_memory(len >> PAGE_SHIFT)) { + kfree(vma); + return -ENOMEM; + } + } + if (file) { int error = file->f_op->mmap(file->f_inode, file, vma); diff --git a/mm/vmscan.c b/mm/vmscan.c index 67c7e9fe3eab..3815a172d6fa 100644 --- a/mm/vmscan.c +++ b/mm/vmscan.c @@ -334,7 +334,12 @@ int try_to_free_page(int priority, int dma, int wait) { static int state = 0; int i=6; + int stop; + /* we don't try as hard if we're not waiting.. */ + stop = 3; + if (wait) + stop = 0; switch (state) { do { case 0: @@ -349,7 +354,8 @@ int try_to_free_page(int priority, int dma, int wait) if (swap_out(i, dma, wait)) return 1; state = 0; - } while (i--); + i--; + } while ((i - stop) >= 0); } return 0; } diff --git a/net/Config.in b/net/Config.in index bc6e936e2010..8f8705f70bcf 100644 --- a/net/Config.in +++ b/net/Config.in @@ -20,9 +20,9 @@ if [ "$CONFIG_AX25" = "y" ]; then bool 'AX.25 over Ethernet' CONFIG_BPQETHER bool 'Amateur Radio NET/ROM' CONFIG_NETROM fi -if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then - bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE -fi +#if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then +# bool 'Bridging (EXPERIMENTAL)' CONFIG_BRIDGE +#fi bool 'Kernel/User network link driver' CONFIG_NETLINK if [ "$CONFIG_NETLINK" = "y" ]; then bool 'Routing messages' CONFIG_RTNETLINK diff --git a/net/core/dev.c b/net/core/dev.c index ae27303b4baf..93f9e900fe0e 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -413,14 +413,8 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) dev_kfree_skb(skb, FREE_WRITE); return; } - cli(); - skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */ - __skb_queue_tail(list, skb); - skb = __skb_dequeue(list); - skb_device_lock(skb); /* New buffer needs locking down */ - restore_flags(flags); } - + /* copy outgoing packets to any sniffer packet handlers */ if (dev_nit) { struct packet_type *ptype; @@ -442,6 +436,15 @@ static void do_dev_queue_xmit(struct sk_buff *skb, struct device *dev, int pri) } } } + + if (skb_queue_len(list)) { + cli(); + skb_device_unlock(skb); /* Buffer is on the device queue and can be freed safely */ + __skb_queue_tail(list, skb); + skb = __skb_dequeue(list); + skb_device_lock(skb); /* New buffer needs locking down */ + restore_flags(flags); + } } if (dev->hard_start_xmit(skb, dev) == 0) { /* diff --git a/net/core/skbuff.c b/net/core/skbuff.c index f01fe57b67b7..6af7c270a298 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -283,7 +283,6 @@ void skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) void __skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) { - unsigned long flags; struct sk_buff *list = (struct sk_buff *)list_; if (newsk->next || newsk->prev) @@ -308,7 +307,7 @@ void __skb_queue_tail(struct sk_buff_head *list_, struct sk_buff *newsk) struct sk_buff *skb_dequeue(struct sk_buff_head *list_) { - long flags; + unsigned long flags; struct sk_buff *result; struct sk_buff *list = (struct sk_buff *)list_; diff --git a/net/ipv4/Config.in b/net/ipv4/Config.in index 03ec7ec9d452..8f48b81bb449 100644 --- a/net/ipv4/Config.in +++ b/net/ipv4/Config.in @@ -9,9 +9,12 @@ if [ "$CONFIG_FIREWALL" = "y" ]; then bool 'IP: firewall packet logging' CONFIG_IP_FIREWALL_VERBOSE if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then bool 'IP: masquerading (EXPERIMENTAL)' CONFIG_IP_MASQUERADE + if [ "$CONFIG_IP_MASQUERADE" != "n" ]; then + comment 'Protocol-specific masquerading support will be built as modules.' + fi bool 'IP: transparent proxy support (EXPERIMENTAL)' CONFIG_IP_TRANSPARENT_PROXY + bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG fi - bool 'IP: always defragment' CONFIG_IP_ALWAYS_DEFRAG fi fi bool 'IP: accounting' CONFIG_IP_ACCT diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c index 8adcb2b14c2d..f83034bfa914 100644 --- a/net/ipv4/arp.c +++ b/net/ipv4/arp.c @@ -2025,36 +2025,31 @@ static int arp_req_set(struct arpreq *r, struct device * dev) while ((entry = *entryp) != NULL) { - if (entry->ip == ip && entry->mask == mask && entry->dev == dev) - break; + /* User supplied arp entries are definitive - RHP 960603 */ + + if (entry->ip == ip && entry->mask == mask && entry->dev == dev) { + *entryp=entry->next; + arp_free_entry(entry); + continue; + } if ((entry->mask & mask) != mask) - { - entry = NULL; break; - } entryp = &entry->next; } - /* - * Do we need to create a new entry? - */ - + entry = arp_alloc_entry(); if (entry == NULL) { - entry = arp_alloc_entry(); - if (entry == NULL) - { - arp_unlock(); - return -ENOMEM; - } - entry->ip = ip; - entry->dev = dev; - entry->mask = mask; - entry->flags = r->arp_flags; - - entry->next = *entryp; - *entryp = entry; + arp_unlock(); + return -ENOMEM; } + entry->ip = ip; + entry->dev = dev; + entry->mask = mask; + entry->flags = r->arp_flags; + + entry->next = *entryp; + *entryp = entry; ha = r->arp_ha.sa_data; if (empty(ha, dev->addr_len)) diff --git a/net/ipv4/ip_forward.c b/net/ipv4/ip_forward.c index e025d831fc14..54ffe7b64a6b 100644 --- a/net/ipv4/ip_forward.c +++ b/net/ipv4/ip_forward.c @@ -469,7 +469,7 @@ int ip_forward(struct sk_buff *skb, struct device *dev, int is_frag, * Count mapping we shortcut */ - ip_fw_chk(iph,dev2,NULL,ip_acct_chain,IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_OUT); + ip_fw_chk(iph,dev2,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT); #endif /* diff --git a/net/ipv4/ip_input.c b/net/ipv4/ip_input.c index 20a98e65b5ac..d11c646adbdc 100644 --- a/net/ipv4/ip_input.c +++ b/net/ipv4/ip_input.c @@ -257,7 +257,7 @@ int ip_rcv(struct sk_buff *skb, struct device *dev, struct packet_type *pt) */ #ifdef CONFIG_IP_ACCT - ip_fw_chk(iph,dev,NULL,ip_acct_chain,IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_IN); + ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_IN); #endif /* diff --git a/net/ipv4/ip_masq.c b/net/ipv4/ip_masq.c index f730828dfb66..5505a6fd5951 100644 --- a/net/ipv4/ip_masq.c +++ b/net/ipv4/ip_masq.c @@ -14,6 +14,7 @@ * Juan Jose Ciarlante : Added NO_ADDR status flag. * Nigel Metheringham : Added ICMP handling for demasquerade * Nigel Metheringham : Checksum checking of masqueraded data + * Nigel Metheringham : Better handling of timeouts of TCP conns * * */ @@ -539,20 +540,29 @@ int ip_fw_masquerade(struct sk_buff **skb_ptr, struct device *dev) struct tcphdr *th; th = (struct tcphdr *)portptr; + /* Set the flags up correctly... */ + if (th->fin) + { + ms->flags |= IP_MASQ_F_SAW_FIN_OUT; + } + + if (th->rst) + { + ms->flags |= IP_MASQ_F_SAW_RST; + } + /* - * Timeout depends if FIN packet was seen + * Timeout depends if FIN packet has been seen * Very short timeout if RST packet seen. */ - if (ms->flags & IP_MASQ_F_SAW_RST || th->rst) - { + if (ms->flags & IP_MASQ_F_SAW_RST) + { timeout = 1; - ms->flags |= IP_MASQ_F_SAW_RST; - } - else if (ms->flags & IP_MASQ_F_SAW_FIN || th->fin) - { + } + else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) + { timeout = ip_masq_expire->tcp_fin_timeout; - ms->flags |= IP_MASQ_F_SAW_FIN; - } + } else timeout = ip_masq_expire->tcp_timeout; skb->csum = csum_partial((void *)(th + 1), size - sizeof(*th), 0); @@ -775,6 +785,7 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) __u16 *portptr; struct ip_masq *ms; unsigned short len; + unsigned long timeout; switch (iph->protocol) { case IPPROTO_ICMP: @@ -827,6 +838,9 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) if (ms != NULL) { + /* Stop the timer ticking.... */ + ip_masq_set_expire(ms,0); + /* * Set dport if not defined yet. */ @@ -869,16 +883,13 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) /* * Yug! adjust UDP/TCP and IP checksums, also update - * UDP timeouts since you cannot depend on traffic - * going through the other way to hold the timeout open. - * (With TCP the ACK packets hold the tunnel open). - * If a TCP RST is seen collapse the tunnel! + * timeouts. + * If a TCP RST is seen collapse the tunnel (by using short timeout)! */ if (iph->protocol==IPPROTO_UDP) { recalc_check((struct udphdr *)portptr,iph->saddr,iph->daddr,len); - ip_masq_set_expire(ms, 0); - ip_masq_set_expire(ms, ip_masq_expire->udp_timeout); + timeout = ip_masq_expire->udp_timeout; } else { @@ -886,16 +897,30 @@ int ip_fw_demasquerade(struct sk_buff **skb_p, struct device *dev) skb->csum = csum_partial((void *)(((struct tcphdr *)portptr) + 1), len - sizeof(struct tcphdr), 0); tcp_send_check((struct tcphdr *)portptr,iph->saddr,iph->daddr,len,skb); - /* Check if TCP RST */ + + /* Check if TCP FIN or RST */ th = (struct tcphdr *)portptr; + if (th->fin) + { + ms->flags |= IP_MASQ_F_SAW_FIN_IN; + } if (th->rst) { - ip_masq_set_expire(ms, 0); ms->flags |= IP_MASQ_F_SAW_RST; - ip_masq_set_expire(ms, 1); } - + + /* Now set the timeouts */ + if (ms->flags & IP_MASQ_F_SAW_RST) + { + timeout = 1; + } + else if ((ms->flags & IP_MASQ_F_SAW_FIN) == IP_MASQ_F_SAW_FIN) + { + timeout = ip_masq_expire->tcp_fin_timeout; + } + else timeout = ip_masq_expire->tcp_timeout; } + ip_masq_set_expire(ms, timeout); ip_send_check(iph); #ifdef DEBUG_CONFIG_IP_MASQUERADE printk("I-routed to %lX:%X\n",ntohl(iph->daddr),ntohs(portptr[1])); diff --git a/net/ipv4/ip_output.c b/net/ipv4/ip_output.c index a2b1a1daf32c..41771042168e 100644 --- a/net/ipv4/ip_output.c +++ b/net/ipv4/ip_output.c @@ -320,6 +320,44 @@ void ip_send_check(struct iphdr *iph) iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); } + +/* + * If a sender wishes the packet to remain unfreed + * we add it to his send queue. This arguably belongs + * in the TCP level since nobody else uses it. BUT + * remember IPng might change all the rules. + */ +static inline void add_to_send_queue(struct sock * sk, struct sk_buff * skb) +{ + unsigned long flags; + + /* The socket now has more outstanding blocks */ + sk->packets_out++; + + /* Protect the list for a moment */ + save_flags(flags); + cli(); + + if (skb->link3 != NULL) + { + NETDEBUG(printk("ip.c: link3 != NULL\n")); + skb->link3 = NULL; + } + if (sk->send_head == NULL) + { + sk->send_tail = skb; + sk->send_head = skb; + sk->send_next = skb; + } + else + { + sk->send_tail->link3 = skb; + sk->send_tail = skb; + } + restore_flags(flags); +} + + /* * Queues a packet to be sent, and starts the transmitter * if necessary. if free = 1 then we free the block after @@ -332,15 +370,8 @@ void ip_send_check(struct iphdr *iph) void ip_queue_xmit(struct sock *sk, struct device *dev, struct sk_buff *skb, int free) { + unsigned int tot_len; struct iphdr *iph; -/* unsigned char *ptr;*/ - - /* Sanity check */ - if (dev == NULL) - { - NETDEBUG(printk("IP: ip_queue_xmit dev = NULL\n")); - return; - } IS_SKB(skb); @@ -348,7 +379,7 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, * Do some book-keeping in the packet for later */ - + skb->sk = sk; skb->dev = dev; skb->when = jiffies; @@ -361,32 +392,30 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, */ iph = skb->ip_hdr; - iph->tot_len = htons(skb->len-(((unsigned char *)iph)-skb->data)); - - /* - * No reassigning numbers to fragments... - */ - - if(free!=2) - iph->id = htons(ip_id_count++); - else - free=1; - - /* All buffers without an owner socket get freed */ - if (sk == NULL) - free = 1; + tot_len = skb->len - (((unsigned char *)iph) - skb->data); + iph->tot_len = htons(tot_len); + + switch (free) { + /* No reassigning numbers to fragments... */ + default: + free = 1; + break; + case 0: + add_to_send_queue(sk, skb); + /* fall through */ + case 1: + iph->id = htons(ip_id_count++); + } skb->free = free; + /* Sanity check */ + if (dev == NULL) + goto no_device; + #ifdef CONFIG_FIREWALL - if(call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) { - /* just don't send this packet */ - /* and free socket buffers ;) */ - if (free) - skb->sk = sk; /* I am not sure *this* really need, */ - kfree_skb(skb, FREE_WRITE); /* but *this* must be here */ - return; - } + if (call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) + goto out; #endif /* @@ -395,13 +424,8 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, * bits of it. */ - if(ntohs(iph->tot_len)> dev->mtu) - { - ip_fragment(sk,skb,dev,0); - IS_SKB(skb); - kfree_skb(skb,FREE_WRITE); - return; - } + if (tot_len > dev->mtu) + goto fragment; /* * Add an IP checksum @@ -409,10 +433,6 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, ip_send_check(iph); - /* - * Print the frame when debugging - */ - /* * More debugging. You cannot queue a packet already on a list * Spot this and moan loudly. @@ -423,58 +443,15 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, skb_unlink(skb); } - /* - * If a sender wishes the packet to remain unfreed - * we add it to his send queue. This arguably belongs - * in the TCP level since nobody else uses it. BUT - * remember IPng might change all the rules. - */ - - if (!free) - { - unsigned long flags; - /* The socket now has more outstanding blocks */ - - sk->packets_out++; - - /* Protect the list for a moment */ - save_flags(flags); - cli(); - - if (skb->link3 != NULL) - { - NETDEBUG(printk("ip.c: link3 != NULL\n")); - skb->link3 = NULL; - } - if (sk->send_head == NULL) - { - sk->send_tail = skb; - sk->send_head = skb; - sk->send_next = skb; - } - else - { - sk->send_tail->link3 = skb; - sk->send_tail = skb; - } - /* skb->link3 is NULL */ - - /* Interrupt restore */ - restore_flags(flags); - } - else - /* Remember who owns the buffer */ - skb->sk = sk; - /* * If the indicated interface is up and running, send the packet. */ ip_statistics.IpOutRequests++; #ifdef CONFIG_IP_ACCT - ip_fw_chk(iph,dev,NULL,ip_acct_chain,IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_OUT); + ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT); #endif - + #ifdef CONFIG_IP_MULTICAST /* @@ -505,14 +482,12 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, } /* Multicasts with ttl 0 must not go beyond the host */ - if(skb->ip_hdr->ttl==0) - { - kfree_skb(skb, FREE_READ); - return; - } + if (iph->ttl==0) + goto out; } #endif - if((dev->flags&IFF_BROADCAST) && (iph->daddr==dev->pa_brdaddr||iph->daddr==0xFFFFFFFF) && !(dev->flags&IFF_LOOPBACK)) + if ((dev->flags & IFF_BROADCAST) && !(dev->flags & IFF_LOOPBACK) + && (iph->daddr==dev->pa_brdaddr || iph->daddr==0xFFFFFFFF)) ip_loopback(dev,skb); if (dev->flags & IFF_UP) @@ -521,24 +496,28 @@ void ip_queue_xmit(struct sock *sk, struct device *dev, * If we have an owner use its priority setting, * otherwise use NORMAL */ + int priority = SOPRI_NORMAL; + if (sk) + priority = sk->priority; - if (sk != NULL) - { - dev_queue_xmit(skb, dev, sk->priority); - } - else - { - dev_queue_xmit(skb, dev, SOPRI_NORMAL); - } - } - else - { - if(sk) - sk->err = ENETDOWN; - ip_statistics.IpOutDiscards++; - if (free) - kfree_skb(skb, FREE_WRITE); + dev_queue_xmit(skb, dev, priority); + return; } + if(sk) + sk->err = ENETDOWN; + ip_statistics.IpOutDiscards++; +out: + if (free) + kfree_skb(skb, FREE_WRITE); + return; + +no_device: + NETDEBUG(printk("IP: ip_queue_xmit dev = NULL\n")); + goto out; + +fragment: + ip_fragment(sk,skb,dev,0); + goto out; } @@ -720,7 +699,7 @@ int ip_build_xmit(struct sock *sk, } #endif #ifdef CONFIG_IP_ACCT - ip_fw_chk(iph,dev,NULL,ip_acct_chain, IP_FW_F_ACCEPT,IP_FW_MODE_ACCT_OUT); + ip_fw_chk(iph,dev,NULL,ip_acct_chain,0,IP_FW_MODE_ACCT_OUT); #endif if(dev->flags&IFF_UP) dev_queue_xmit(skb,dev,sk->priority); @@ -926,7 +905,7 @@ int ip_build_xmit(struct sock *sk, #endif #ifdef CONFIG_IP_ACCT if(!offset) - ip_fw_chk(iph, dev, NULL, ip_acct_chain, IP_FW_F_ACCEPT, IP_FW_MODE_ACCT_OUT); + ip_fw_chk(iph, dev, NULL, ip_acct_chain, 0, IP_FW_MODE_ACCT_OUT); #endif offset -= (maxfraglen-fragheaderlen); fraglen = maxfraglen; diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c index ae14060da1ba..20b26eaed081 100644 --- a/net/ipv4/tcp_input.c +++ b/net/ipv4/tcp_input.c @@ -104,6 +104,7 @@ extern __inline__ void tcp_rtt_estimator(struct sock *sk, struct sk_buff *oskb) */ m = jiffies - oskb->when; /* RTT */ + if (sk->rtt != 0) { if(m<=0) m=1; /* IS THIS RIGHT FOR <0 ??? */ @@ -421,6 +422,8 @@ static void tcp_conn_request(struct sock *sk, struct sk_buff *skb, newsk->cong_count = 0; newsk->ssthresh = 0x7fffffff; + newsk->lrcvtime = 0; + newsk->idletime = 0; newsk->high_seq = 0; newsk->backoff = 0; newsk->blog = 0; @@ -652,13 +655,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) if (after(ack, sk->sent_seq) || before(ack, sk->rcv_ack_seq)) goto uninteresting_ack; - /* - * If there is data set flag 1 - */ - - if (len != th->doff*4) - flag |= 1; - /* * Have we discovered a larger window */ @@ -679,10 +675,8 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) /* * See if our window has been shrunk. */ - if (after(sk->window_seq, window_seq)) { - flag |= 4; + if (after(sk->window_seq, window_seq)) tcp_window_shrunk(sk, window_seq); - } /* * Pipe has emptied @@ -758,7 +752,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) if (sk->rcv_ack_seq == ack && sk->window_seq == window_seq - && !(flag&1) + && len != th->doff*4 && before(ack, sk->sent_seq) && after(ack, sk->high_seq)) { @@ -777,9 +771,16 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) * of what we are doing here. */ if (sk->rcv_ack_cnt == MAX_DUP_ACKS+1) { + int tmp; + + /* We need to be a bit careful to preserve the + * count of packets that are out in the system here. + */ sk->ssthresh = max(sk->cong_window >> 1, 2); sk->cong_window = sk->ssthresh+MAX_DUP_ACKS+1; + tmp = sk->packets_out; tcp_do_retransmit(sk,0); + sk->packets_out = tmp; } else if (sk->rcv_ack_cnt > MAX_DUP_ACKS+1) { sk->cong_window++; /* @@ -884,6 +885,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) if ((sk->send_head = skb->link3) == NULL) { sk->send_tail = NULL; + sk->send_next = NULL; sk->retransmits = 0; } @@ -912,10 +914,15 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) if (sk->packets_out > 0) sk->packets_out --; + /* This is really only supposed to be called when we + * are actually ACKing new data, which should exclude + * the ACK handshake on an initial SYN packet as well. + * Rather than introducing a new test here for this + * special case, we just reset the initial values for + * rtt immediatly after we move to the established state. + */ if (!(flag&2)) /* Not retransmitting */ tcp_rtt_estimator(sk,skb); - flag |= (2|4); /* 2 is really more like 'don't adjust the rtt - In this case as we just set it up */ IS_SKB(skb); /* @@ -949,7 +956,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) /* * Add more data to the send queue. */ - flag |= 1; tcp_write_xmit(sk); } @@ -1034,7 +1040,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) && skb_queue_empty(&sk->write_queue) && sk->send_head == NULL) { - flag |= 1; tcp_send_partial(sk); } @@ -1055,7 +1060,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) sk->rcv_ack_seq,sk->write_seq,sk->acked_seq,sk->fin_seq); if (sk->rcv_ack_seq == sk->write_seq /*&& sk->acked_seq == sk->fin_seq*/) { - flag |= 1; sk->shutdown = SHUTDOWN_MASK; tcp_set_state(sk,TCP_CLOSE); return 1; @@ -1076,7 +1080,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) sk->state_change(sk); if (sk->rcv_ack_seq == sk->write_seq) { - flag |= 1; sk->shutdown |= SEND_SHUTDOWN; tcp_set_state(sk, TCP_FIN_WAIT2); /* If the socket is dead, then there is no @@ -1101,7 +1104,6 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) sk->state_change(sk); if (sk->rcv_ack_seq == sk->write_seq) { - flag |= 1; tcp_time_wait(sk); } } @@ -1110,7 +1112,7 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) * Final ack of a three way shake */ - if(sk->state==TCP_SYN_RECV) + if (sk->state==TCP_SYN_RECV) { tcp_set_state(sk, TCP_ESTABLISHED); tcp_options(sk,th); @@ -1123,6 +1125,13 @@ static int tcp_ack(struct sock *sk, struct tcphdr *th, u32 ack, int len) sk->max_window=32; /* Sanity check */ sk->mss=min(sk->max_window,sk->mtu); } + /* Reset the RTT estimator to the initial + * state rather than testing to avoid + * updating it on the ACK to the SYN packet. + */ + sk->rtt = 0; + sk->rto = TCP_TIMEOUT_INIT; + sk->mdev = TCP_TIMEOUT_INIT; } /* @@ -1679,7 +1688,7 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, struct sock *sk; int syn_ok=0; #ifdef CONFIG_IP_TRANSPARENT_PROXY - int r=0; + int r; #endif /* @@ -1763,6 +1772,11 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, skb->sk=sk; atomic_add(skb->truesize, &sk->rmem_alloc); + + /* + * Mark the time of the last received packet. + */ + sk->idletime = jiffies; /* * We should now do header prediction. @@ -1897,6 +1911,13 @@ int tcp_rcv(struct sk_buff *skb, struct device *dev, struct options *opt, sk->max_window = 32; sk->mss = min(sk->max_window, sk->mtu); } + /* Reset the RTT estimator to the initial + * state rather than testing to avoid + * updating it on the ACK to the SYN packet. + */ + sk->rtt = 0; + sk->rto = TCP_TIMEOUT_INIT; + sk->mdev = TCP_TIMEOUT_INIT; } else { diff --git a/net/ipv4/tcp_output.c b/net/ipv4/tcp_output.c index f25d0fdbc49b..0a71b4bf93a0 100644 --- a/net/ipv4/tcp_output.c +++ b/net/ipv4/tcp_output.c @@ -25,9 +25,11 @@ #include #include - +#include +#include #include + /* * RFC 1122 says: * @@ -145,14 +147,23 @@ void tcp_send_skb(struct sock *sk, struct sk_buff *skb) } } + /* + * Jacobson recommends this in the appendix of his SIGCOMM'88 paper. + * The idea is to do a slow start again if we haven't been doing + * anything for a long time, in which case we have no reason to + * believe that our congestion window is still correct. + */ + if (sk->send_head == 0 && (jiffies - sk->idletime) > sk->rto) + sk->cong_window = 1; + /* * Actual processing. */ - + tcp_statistics.TcpOutSegs++; skb->seq = ntohl(th->seq); skb->end_seq = skb->seq + size - 4*th->doff; - + /* * We must queue if * @@ -394,7 +405,7 @@ void tcp_do_retransmit(struct sock *sk, int all) sk->send_next = sk->send_head; sk->packets_out = 0; } - skb = sk->send_head; + skb = sk->send_next; while (skb != NULL) { @@ -468,6 +479,11 @@ void tcp_do_retransmit(struct sock *sk, int all) skb->sk->err_soft=ENETUNREACH; skb->sk->error_report(skb->sk); } + /* Can't transmit this packet, no reason + * to transmit the later ones, even if + * the congestion window allows. + */ + break; } else { @@ -475,6 +491,17 @@ void tcp_do_retransmit(struct sock *sk, int all) skb->raddr=rt->rt_gateway; skb->dev=dev; skb->arp=1; +#ifdef CONFIG_FIREWALL + if (call_out_firewall(PF_INET, skb->dev, iph, NULL) < FW_ACCEPT) { + /* The firewall wants us to dump the packet. + * We have to check this here, because + * the drop in ip_queue_xmit only catches the + * first time we send it. We must drop on + * every resend as well. + */ + break; + } +#endif if (rt->rt_hh) { memcpy(skb_push(skb,dev->hard_header_len),rt->rt_hh->hh_data,dev->hard_header_len); diff --git a/net/netsyms.c b/net/netsyms.c index 7a86cf280e86..cd0b9c2ca6a1 100644 --- a/net/netsyms.c +++ b/net/netsyms.c @@ -180,6 +180,7 @@ static struct symbol_table net_syms = { #ifdef CONFIG_NETLINK X(netlink_attach), X(netlink_detach), + X(netlink_donothing), X(netlink_post), #endif /* CONFIG_NETLINK */ diff --git a/net/socket.c b/net/socket.c index 69c22cea1123..85483f6c879a 100644 --- a/net/socket.c +++ b/net/socket.c @@ -1113,7 +1113,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags) struct socket *sock; struct file *file; char address[MAX_SOCK_ADDR]; - struct iovec iov[MAX_IOVEC]; + struct iovec iov[UIO_MAXIOV]; struct msghdr msg_sys; int err; int total_len; @@ -1134,7 +1134,7 @@ asmlinkage int sys_sendmsg(int fd, struct msghdr *msg, unsigned int flags) memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr)); /* do not move before msg_sys is valid */ - if(msg_sys.msg_iovlen>MAX_IOVEC) + if(msg_sys.msg_iovlen>UIO_MAXIOV) return -EINVAL; /* This will also move the address data into kernel space */ @@ -1154,7 +1154,7 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) { struct socket *sock; struct file *file; - struct iovec iov[MAX_IOVEC]; + struct iovec iov[UIO_MAXIOV]; struct msghdr msg_sys; int err; int total_len; @@ -1177,7 +1177,7 @@ asmlinkage int sys_recvmsg(int fd, struct msghdr *msg, unsigned int flags) if(err) return err; memcpy_fromfs(&msg_sys,msg,sizeof(struct msghdr)); - if(msg_sys.msg_iovlen>MAX_IOVEC) + if(msg_sys.msg_iovlen>UIO_MAXIOV) return -EINVAL; /* diff --git a/scripts/tkgen.c b/scripts/tkgen.c index eb549023d86c..fc9338db39de 100644 --- a/scripts/tkgen.c +++ b/scripts/tkgen.c @@ -989,9 +989,11 @@ void dump_tk_script(struct kconfig *scfg) case tok_dep_tristate: case tok_define: case tok_choose: - if(cfg->flags & GLOBAL_WRITTEN) break; - cfg->flags |= GLOBAL_WRITTEN; - printf("\tglobal %s\n", cfg->optionname); + if(!(cfg->flags & GLOBAL_WRITTEN)) + { + cfg->flags |= GLOBAL_WRITTEN; + printf("\tglobal %s\n", cfg->optionname); + } /* fall through */ case tok_make: case tok_comment: -- 2.39.5