]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.122pre3 2.1.122pre3
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:41 +0000 (15:16 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:16:41 +0000 (15:16 -0500)
117 files changed:
CREDITS
Documentation/Configure.help
Documentation/networking/arcnet-hardware.txt
Documentation/networking/arcnet.txt
Documentation/networking/cs89x0.txt
Documentation/sound/ChangeLog.multisound
Documentation/sound/Wavefront
MAINTAINERS
arch/alpha/kernel/osf_sys.c
arch/i386/kernel/apm.c
arch/i386/kernel/desc.h [deleted file]
arch/i386/kernel/init_task.c
arch/i386/kernel/io_apic.c
arch/i386/kernel/irq.c
arch/i386/kernel/ldt.c
arch/i386/kernel/process.c
arch/i386/kernel/ptrace.c
arch/i386/kernel/setup.c
arch/i386/kernel/traps.c
arch/i386/math-emu/fpu_entry.c
arch/i386/math-emu/get_address.c
drivers/block/Makefile
drivers/block/floppy.c
drivers/block/loop.c
drivers/cdrom/cdu31a.c
drivers/cdrom/cm206.c
drivers/cdrom/sbpcd.c
drivers/char/Config.in
drivers/char/bttv.c
drivers/net/3c523.c
drivers/net/82596.c
drivers/net/Config.in
drivers/net/arc-rimi.c
drivers/net/arcnet.c
drivers/net/ariadne.c
drivers/net/com20020.c
drivers/net/com90io.c
drivers/net/com90xx.c
drivers/net/daynaport.c
drivers/net/hamradio/dmascc.c
drivers/net/hamradio/z8530.h
drivers/net/plip.c
drivers/nubus/nubus.c
drivers/scsi/Config.in
drivers/scsi/Makefile
drivers/scsi/README.ppa
drivers/scsi/hosts.c
drivers/scsi/imm.c [new file with mode: 0644]
drivers/scsi/imm.h [new file with mode: 0644]
drivers/scsi/ppa.c
drivers/scsi/ppa.h
drivers/scsi/scsi.c
drivers/scsi/scsi.h
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/ad1848.c
drivers/sound/dev_table.c
drivers/sound/mad16.c
drivers/sound/msnd.c
drivers/sound/msnd.h
drivers/sound/msnd_classic.h
drivers/sound/msnd_pinnacle.c
drivers/sound/msnd_pinnacle.h
drivers/sound/pss.c
drivers/sound/sb.h
drivers/sound/sb_card.c
drivers/sound/sb_common.c
drivers/sound/sb_midi.c
drivers/sound/sb_mixer.c
drivers/sound/sequencer.c
drivers/sound/trix.c
drivers/sound/wavfront.c
fs/binfmt_elf.c
fs/devpts/root.c
fs/fat/inode.c
fs/hfs/ChangeLog
fs/hfs/file.c
fs/hfs/file_cap.c
fs/hfs/file_hdr.c
fs/hfs/mdb.c
fs/isofs/namei.c
fs/msdos/namei.c
fs/proc/array.c
fs/sysv/balloc.c
fs/sysv/fsync.c
fs/sysv/inode.c
fs/sysv/truncate.c
fs/umsdos/dir.c
fs/umsdos/emd.c
fs/umsdos/file.c
fs/umsdos/inode.c
fs/umsdos/ioctl.c
fs/umsdos/namei.c
fs/umsdos/rdir.c
fs/umsdos/specs
fs/umsdos/symlink.c
include/asm-i386/desc.h [new file with mode: 0644]
include/linux/loop.h
include/linux/proc_fs.h
include/linux/sysv_fs.h
include/linux/sysv_fs_i.h
include/linux/sysv_fs_sb.h
include/linux/umsdos_fs.p
include/linux/videodev.h
include/linux/wavefront.h
kernel/exit.c
kernel/ksyms.c
kernel/signal.c
mm/memory.c
net/Config.in
net/ax25/af_ax25.c
net/core/skbuff.c
net/ipv4/tcp_input.c
net/ipv4/udp.c
net/ipv6/af_inet6.c
net/netsyms.c
net/sunrpc/svcsock.c

diff --git a/CREDITS b/CREDITS
index f62977ca83267a78d429021f5eb3917a337f17ed..2d56f8b27603b0c1ff122ae63f2e3d63619bd308 100644 (file)
--- a/CREDITS
+++ b/CREDITS
 ----------
 
 N: Matti Aarnio
-E: mea@utu.fi
-D: LILO for AHA1542, modularized several of drivers/net/,
-D: dynamic SLIP devices, dynamic /proc/net/, true size /proc/ksyms,
-D: and other hacks..
-D: Documenting various parts of network subsystem (kernel side)
+E: mea@nic.funet.fi
+D: Alpha systems hacking, IPv6 and other network related stuff
+D: One of assisting postmasters for vger.rutgers.edu's lists
+S: (ask for current address)
+S: Finland
 
 N: Werner Almesberger
 E: werner.almesberger@lrc.di.epfl.ch
@@ -1403,7 +1403,8 @@ S: Albuquerque, New Mexico 87131
 S: USA
 
 N: Avery Pennarun
-E: apenwarr@bond.net
+E: apenwarr@worldvisions.ca
+W: http://www.worldvisions.ca/~apenwarr/
 D: ARCnet driver
 D: "make xconfig" improvements
 D: Various minor hacking
@@ -1696,6 +1697,14 @@ S: 22 Irvington Cres.
 S: Willowdale, Ontario
 S: Canada M2N 2Z1
 
+N: Adrian Sun
+E: asun@u.washington.edu
+D: hfs support
+D: alpha rtc port, random appletalk fixes
+S: Department of Zoology, University of Washington
+S: Seattle, WA  98195-1800
+S: USA
+
 N: Tommy Thorn
 E: Tommy.Thorn@irisa.fr
 W: http://www.irisa.fr/prive/thorn/index.html
@@ -1883,9 +1892,9 @@ S: The Netherlands
 N: Tim Waugh
 E: tim@cyberelk.demon.co.uk
 D: Co-architect of the parallel-port sharing system
-S: 110 Twyford Road
-S: EASTLEIGH
-S: SO50 4HN
+S: 4 Fox Close
+S: Bishopstoke
+S: SO50 8NB
 S: United Kingdom
 
 N: Juergen Weigert
index 9b1a00fa9d09c0bde587c1e100b87a4f423ef1ac..b265dbd3237821c0ef4b451166bb447a94c56b31 100644 (file)
@@ -113,14 +113,14 @@ CONFIG_MATH_EMULATION
   If you are not sure, say Y; apart from resulting in a 45kB bigger
   kernel, it won't hurt.
 
-Normal floppy disk support
+Normal PC floppy disk support
 CONFIG_BLK_DEV_FD
-  If you want to use your floppy disk drive(s) under Linux, say
-  Y. Information about this driver, especially important for IBM
+  If you want to use the floppy disk drive(s) of your PC under Linux,
+  say Y. Information about this driver, especially important for IBM
   Thinkpad users, is contained in drivers/block/README.fd. This file
   also contains the location of the Floppy driver FAQ as well as
   location of the fdutils package used to configure additional
-  parameters of the driver at run time. 
+  parameters of the driver at run time.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -174,12 +174,13 @@ CONFIG_BLK_DEV_LOOP
   ftp://ftp.replay.com/pub/crypto/linux/all, and then you need to say
   Y to this option.
 
-  Note that alternative ways use encrypted filesystems are provided by
-  the cfs package, which can be gotten via FTP (user: anonymous) from
-  ftp://ftp.replay.com/pub/crypto/disk/, and the newer tcfs package,
-  available at http://tcfs.dia.unisa.it/. These do not require any
-  kernel support and you can say N here if you want to use one of
-  them.
+  Note that alternative ways to use encrypted filesystems are provided
+  by the cfs package, which can be gotten via FTP (user: anonymous)
+  from ftp://ftp.replay.com/pub/crypto/disk/, and the newer tcfs
+  package, available at http://tcfs.dia.unisa.it/. You do not need to
+  say Y here if you want to use one of these. However, using cfs
+  requires saying Y to "NFS filesystem support" below while using tcfs
+  requires applying a kernel patch.
 
   To use the loop device, you need the losetup utility and a recent
   version of the mount program, both contained in the util-linux
@@ -199,7 +200,7 @@ CONFIG_BLK_DEV_LOOP
 Network Block Device support
 CONFIG_BLK_DEV_NBD
   Saying Y here will allow your computer to be a client for network
-  block devices - it will be able to use block devices exported by
+  block devices -- it will be able to use block devices exported by
   servers (mount filesystems on them etc.). Communication between
   client and server works over TCP/IP networking, but to the client
   program this is hidden: it looks like a regular local file access to
@@ -285,7 +286,7 @@ CONFIG_BLK_DEV_IDEDISK
 Include IDE/ATAPI CDROM support
 CONFIG_BLK_DEV_IDECD
   If you have a CDROM drive using the ATAPI protocol, say Y. ATAPI is
-  a new protocol used by IDE CDROM and TAPE drives, similar to the
+  a newer protocol used by IDE CDROM and TAPE drives, similar to the
   SCSI protocol. Most new CDROM drives use ATAPI, including the
   NEC-260, Mitsumi FX400, Sony 55E, and just about all non-SCSI
   double(2X), quad(4X), and six(6X) speed drives.
@@ -311,7 +312,7 @@ CONFIG_BLK_DEV_IDECD
 Include IDE/ATAPI TAPE support
 CONFIG_BLK_DEV_IDETAPE
   If you have an IDE tape drive using the ATAPI protocol, say Y.
-  ATAPI is a new protocol used by IDE tape and CDROM drives, similar
+  ATAPI is a newer protocol used by IDE tape and CDROM drives, similar
   to the SCSI protocol.  
 
   If you say Y here, the tape drive will be identified at boot time
@@ -329,7 +330,7 @@ CONFIG_BLK_DEV_IDETAPE
 Include IDE/ATAPI FLOPPY support
 CONFIG_BLK_DEV_IDEFLOPPY
   If you have an IDE floppy drive which uses the ATAPI protocol, say
-  Y.  ATAPI is a new protocol used by IDE CDROM/tape/floppy drives,
+  Y.  ATAPI is a newer protocol used by IDE CDROM/tape/floppy drives,
   similar to the SCSI protocol.  IDE floppy drives include the LS-120
   and the ATAPI ZIP (ATAPI PD-CD/CDR drives are not supported by this
   driver; support for PD-CD/CDR drives is available if you say Y to
@@ -417,11 +418,13 @@ Generic PCI bus-master DMA support
 CONFIG_BLK_DEV_IDEDMA
   If your PCI system uses IDE drive(s) (as opposed to SCSI, say) and
   is capable of bus-master DMA operation (most Pentium PCI systems),
-  you will want to say Y here to reduce CPU overhead.
-  You can use the "hdparm" utility to enable DMA for drives which
-  were not enabled automatically.  You can get the latest version of
-  the hdparm utility via anonymous FTP from
-  ftp://sunsite.unc.edu/pub/Linux/system/hardware/. 
+  you will want to say Y here to reduce CPU overhead. You can then use
+  the "hdparm" utility to enable DMA for drives for which it was not
+  enabled automatically. By default, DMA is not enabled automatically
+  for these drives, but you can change that by saying Y to the
+  following question "Use DMA by default when available". You can get
+  the latest version of the hdparm utility via anonymous FTP from
+  ftp://sunsite.unc.edu/pub/Linux/system/hardware/.
 
   Read the comments at the beginning of drivers/block/idedma.c and the
   file Documentation/ide.txt for more information. 
@@ -435,6 +438,7 @@ CONFIG_IDEDMA_AUTO
   about a couple of cases where buggy hardware may have caused damage,
   the default is now to NOT use DMA automatically.  To revert to the
   previous behaviour, say Y to this question.
+
   If you suspect your hardware is at all flakey, say N here.
   Do NOT email the IDE kernel people regarding this issue!
 
@@ -576,7 +580,7 @@ CONFIG_PARIDE
   etc.).
 
 Parallel port IDE disks
-CONFIG_PARIDE_PD 
+CONFIG_PARIDE_PD
   This option enables the high-level driver for IDE-type disk devices 
   connected through a parallel port.  If you chose to build PARIDE 
   support into your kernel, you may answer Y here to build in the 
@@ -588,7 +592,7 @@ CONFIG_PARIDE_PD
   hard drives from MicroSolutions.
 
 Parallel port ATAPI CD-ROMs
-CONFIG_PARIDE_PCD 
+CONFIG_PARIDE_PCD
   This option enables the high-level driver for ATAPI CD-ROM devices
   connected through a parallel port. If you chose to build PARIDE
   support into your kernel, you may answer Y here to build in the
@@ -602,7 +606,7 @@ CONFIG_PARIDE_PCD
   on CDROMs.
 
 Parallel port ATAPI disks
-CONFIG_PARIDE_PF 
+CONFIG_PARIDE_PF
   This option enables the high-level driver for ATAPI disk devices
   connected through a parallel port.  If you chose to build PARIDE
   support into your kernel, you may answer Y here to build in the
@@ -640,7 +644,7 @@ CONFIG_PARIDE_PG
   the required patches to cdrecord.
 
 ATEN EH-100 protocol
-CONFIG_PARIDE_ATEN 
+CONFIG_PARIDE_ATEN
   This option enables support for the ATEN EH-100 parallel port IDE
   protocol.  This protocol is used in some inexpensive low performance 
   parallel port kits made in Hong Kong. If you chose to build PARIDE 
@@ -651,7 +655,7 @@ CONFIG_PARIDE_ATEN
   support.
 
 MicroSolutions backpack protocol
-CONFIG_PARIDE_BPCK 
+CONFIG_PARIDE_BPCK
   This option enables support for the MicroSolutions backpack 
   parallel port IDE protocol.  If you chose to build PARIDE support
   into your kernel, you may answer Y here to build in the protocol
@@ -660,7 +664,7 @@ CONFIG_PARIDE_BPCK
   a high-level driver for the type of device that you want to support.
 
 DataStor Commuter protocol
-CONFIG_PARIDE_COMM 
+CONFIG_PARIDE_COMM
   This option enables support for the Commuter parallel port IDE 
   protocol from DataStor.  If you chose to build PARIDE support
   into your kernel, you may answer Y here to build in the protocol
@@ -669,7 +673,7 @@ CONFIG_PARIDE_COMM
   a high-level driver for the type of device that you want to support.
 
 DataStor EP-2000 protocol
-CONFIG_PARIDE_DSTR 
+CONFIG_PARIDE_DSTR
   This option enables support for the EP-2000 parallel port IDE 
   protocol from DataStor.  If you chose to build PARIDE support
   into your kernel, you may answer Y here to build in the protocol
@@ -678,37 +682,37 @@ CONFIG_PARIDE_DSTR
   a high-level driver for the type of device that you want to support.
 
 Shuttle EPAT/EPEZ protocol
-CONFIG_PARIDE_EPAT 
-  This option enables support for the EPAT parallel port IDE 
-  protocol.  EPAT is a parallel port IDE adapter manufactured by
-  Shuttle Technology and widely used in devices from major vendors
-  such as Hewlett-Packard, SyQuest, Imation and Avatar. If you 
-  chose to build PARIDE support into your kernel, you may answer Y 
-  here to build in the protocol driver, otherwise you should answer M 
-  to build it as a loadable module.  The module will be called epat.o.  
-  You must also have a high-level driver for the type of device that 
-  you want to support.
+CONFIG_PARIDE_EPAT
+  This option enables support for the EPAT parallel port IDE protocol.
+  EPAT is a parallel port IDE adapter manufactured by Shuttle
+  Technology and widely used in devices from major vendors such as
+  Hewlett-Packard, SyQuest, Imation and Avatar. If you chose to build
+  PARIDE support into your kernel, you may answer Y here to build in
+  the protocol driver, otherwise you should answer M to build it as a
+  loadable module. The module will be called epat.o. You must also
+  have a high-level driver for the type of device that you want to
+  support.
 
 Shuttle EPIA protocol
-CONFIG_PARIDE_EPIA 
-  This option enables support for the (obsolete) EPIA parallel port 
-  IDE protocol from Shuttle Technology.  This adapter can still be found
-  in some no-name kits. If you chose to build PARIDE support into your 
-  kernel, you may answer Y here to build in the protocol driver,
-  otherwise you should answer M to build it as a loadable module.  
-  The module will be called epia.o.  You must also have a high-level 
-  driver for the type of device that you want to support.
+CONFIG_PARIDE_EPIA
+  This option enables support for the (obsolete) EPIA parallel port
+  IDE protocol from Shuttle Technology. This adapter can still be
+  found in some no-name kits. If you chose to build PARIDE support
+  into your kernel, you may answer Y here to build in the protocol
+  driver, otherwise you should answer M to build it as a loadable
+  module. The module will be called epia.o. You must also have a
+  high-level driver for the type of device that you want to support.
 
 FIT TD-2000 protocol
 CONFIG_PARIDE_FIT2
-  This option enables support for the TD-2000 parallel port IDE protocol
-  from Fidelity International Technology.  This is a simple (low speed) 
-  adapter that is used in some portable hard drives.  If you chose to 
-  build PARIDE support into your kernel, you may answer Y here to 
-  build in the protocol driver, otherwise you should answer M to 
-  build it as a loadable module.  The module will be called ktti.o.  
-  You must also have a high-level driver for the type of device 
-  that you want to support.
+  This option enables support for the TD-2000 parallel port IDE
+  protocol from Fidelity International Technology. This is a simple
+  (low speed) adapter that is used in some portable hard drives. If
+  you chose to build PARIDE support into your kernel, you may answer Y
+  here to build in the protocol driver, otherwise you should answer M
+  to build it as a loadable module. The module will be called ktti.o.
+  You must also have a high-level driver for the type of device that
+  you want to support.
 
 FIT TD-3000 protocol
 CONFIG_PARIDE_FIT3
@@ -722,7 +726,7 @@ CONFIG_PARIDE_FIT3
   of device that you want to support.
 
 FreeCom power protocol
-CONFIG_PARIDE_FRPW 
+CONFIG_PARIDE_FRPW
   This option enables support for the Freecom power parallel port IDE 
   protocol.  If you chose to build PARIDE support into your kernel, you 
   may answer Y here to build in the protocol driver, otherwise you 
@@ -731,15 +735,15 @@ CONFIG_PARIDE_FRPW
   of device that you want to support.
 
 KingByte KBIC-951A/971A protocols
-CONFIG_PARIDE_KBIC 
-  This option enables support for the KBIC-951A and KBIC-971A parallel 
-  port IDE protocols from KingByte Information Corp.  KingByte's adapters
-  appear in many no-name portable disk and CD-ROM products, especially 
-  in Europe. If you chose to build PARIDE support into your kernel, you 
-  may answer Y here to build in the protocol driver, otherwise you should 
-  answer M to build it as a loadable module.  The module will be called 
-  kbic.o.  You must also have a high-level driver for the type of device 
-  that you want to support.
+CONFIG_PARIDE_KBIC
+  This option enables support for the KBIC-951A and KBIC-971A parallel
+  port IDE protocols from KingByte Information Corp. KingByte's
+  adapters appear in many no-name portable disk and CD-ROM products,
+  especially in Europe. If you chose to build PARIDE support into your
+  kernel, you may answer Y here to build in the protocol driver,
+  otherwise you should answer M to build it as a loadable module. The
+  module will be called kbic.o. You must also have a high-level driver
+  for the type of device that you want to support.
 
 KT PHd protocol
 CONFIG_PARIDE_KTTI
@@ -753,7 +757,7 @@ CONFIG_PARIDE_KTTI
   support.
 
 OnSpec 90c20 protocol
-CONFIG_PARIDE_ON20 
+CONFIG_PARIDE_ON20
   This option enables support for the (obsolete) 90c20 parallel port 
   IDE protocol from OnSpec (often marketed under the ValuStore brand
   name).  If you chose to build PARIDE support into your kernel, you 
@@ -763,7 +767,7 @@ CONFIG_PARIDE_ON20
   type of device that you want to support.
 
 OnSpec 90c26 protocol
-CONFIG_PARIDE_ON26 
+CONFIG_PARIDE_ON26
   This option enables support for the 90c26 parallel port IDE protocol 
   from OnSpec Electronics (often marketed under the ValuStore brand
   name).  If you chose to build PARIDE support into your kernel, you 
@@ -848,24 +852,6 @@ CONFIG_MD_RAID5
   want to compile it as a module, say M here and read
   Documentation/modules.txt. If unsure, say Y.
 
-IDE card support
-CONFIG_BLK_DEV_IDE_CARDS
-  On Acorn systems, say Y here if you wish to use an IDE interface
-  expansion card. If you do not or are unsure, say N.
-
-ICS IDE interface
-CONFIG_BLK_DEV_IDE_ICS
-  On Acorn systems, say Y here if you wish to use the ICS IDE
-  interface card. This is not required for ICS partition support. If
-  you are unsure, say.
-
-ADFS partition support
-CONFIG_BLK_DEV_PART
-  This allows Linux on Acorn systems to determine its partitions in
-  the 'non-ADFS' partition area of the hard disk - usually located
-  after the ADFS partition.  You are probably using this system, so
-  you should say Y here.
-
 Boot support (linear, striped)
 CONFIG_MD_BOOT
   To boot with an initial linear or striped md device you have to say
@@ -1008,7 +994,7 @@ CONFIG_FIREWALL
   network think they're talking to a remote computer, while in reality
   the traffic is redirected by your Linux firewall to a local proxy
   server).
-  
+
   Make sure to say N to "Fast switching" below if you intend to say Y
   here.
 
@@ -1110,7 +1096,7 @@ CONFIG_ALPHA_SRM
 
 Non-standard serial port support
 CONFIG_SERIAL_NONSTANDARD
-  Say Y here if you have any non-standard serial boards --- boards
+  Say Y here if you have any non-standard serial boards -- boards
   which aren't supported using the standard "dumb" serial driver.
   This includes intelligent serial boards such as Cyclades,
   Digiboards, etc. These are usually used for systems that need many
@@ -1170,26 +1156,6 @@ CONFIG_HUB6
   Say Y here to enable support in the dumb serial driver to support
   the HUB6 card.
 
-Unix98 PTY support
-CONFIG_UNIX98_PTYS
-  Linux traditionally uses BSD-like /dev/ptyxx and /dev/ttyxx names
-  for pseudo-ttys (PTYs).  This scheme has a number or problems.  The
-  GNU C library 2.1 and later, however, supports the Unix98 naming
-  standard, using a cloning device /dev/ptmx and numbered devices in a
-  subdirectory /dev/pts/xxx.  The device nodes in /dev/pts can be
-  automatically generated by the devpts virtual filesystem.
-
-  Say Y here if you are uncertain, unless you are very short on memory.
-
-Maximum number of Unix98 PTYs in use (0-2048)
-CONFIG_UNIX98_PTY_COUNT
-  The maximum number of Unix98 PTYs that can be used at any one time.
-  The default is 256, and should be enough for desktop systems,
-  however, server machines which support incoming telnet/rlogin/ssh
-  connections may want to increase this.  When not in use, each
-  additional set of 256 PTYs occupy approximately 8K of kernel memory
-  on 32-bit architectures.
-
 TGA Console Support
 CONFIG_TGA_CONSOLE
   Many Alpha systems (e.g the Multia) are shipped with a graphics card
@@ -1328,7 +1294,7 @@ CONFIG_BINFMT_ELF
   want to say Y here. 
 
   Information about ELF is on the WWW at
-  http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (To browse the
+  http://www.sjc.ox.ac.uk/users/barlow/elf-howto.html (to browse the
   WWW, you need to have access to a machine on the Internet that has a
   program like lynx or netscape). If you find that after upgrading
   from Linux kernel 1.2 and saying Y here, you still can't run any ELF
@@ -1382,8 +1348,8 @@ CONFIG_BINFMT_JAVA
   any other Linux program: by simply typing in its name. (You also
   need to have the JDK installed for this to work).  As more and more
   Java programs become available, the use for this will gradually
-  increase. You can even execute HTML files containing JAVA applets (=
-  JAVA binaries) if those files start with the string
+  increase. You can even execute HTML files containing JAVA applets 
+  (= JAVA binaries) if those files start with the string
   "<!--applet-->". If you want to use this, say Y here and read
   Documentation/java.txt. 
 
@@ -1412,12 +1378,15 @@ CONFIG_BINFMT_EM86
 
 Kernel support for MISC binaries
 CONFIG_BINFMT_MISC
-  This enables the possibility to plug wrapper-driven binary formats
-  into the kernel. You will like this especially when you use programs
-  that need an interpreter to run like Java, Python or Emacs-Lisp.
-  Once you have registered such a binary class with the kernel, you
-  can start such a program simply by typing in its name; Linux will
-  feed it to the correct interpreter.
+  If you say Y here, it will be possible to plug wrapper-driven binary
+  formats into the kernel. You will like this especially when you use
+  programs that need an interpreter to run like Java, Python or
+  Emacs-Lisp. It's also useful if you often run DOS executables under
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). Once you have
+  registered such a binary class with the kernel, you can start one of
+  those programs simply by typing in its name at a shell prompt; Linux
+  will automatically feed it to the correct interpreter.
 
   If you say Y here, you won't need "Kernel support for JAVA binaries"
   (CONFIG_BINFMT_JAVA) or "Kernel support for Linux/Intel ELF
@@ -1428,10 +1397,10 @@ CONFIG_BINFMT_MISC
   Documentation/java.txt for information about how to include Java
   support.
 
-  You must enable the "proc filesystem support" (CONFIG_PROC_FS) to
+  You must say Y to "proc filesystem support" (CONFIG_PROC_FS) to
   use this part of the kernel.
 
-  You may answer M for module support and later load the module when
+  You may say M here for module support and later load the module when
   you have use for it; the module is called binfmt_misc.o. If you
   don't know what to answer at this point, say Y.
 
@@ -1503,20 +1472,26 @@ CONFIG_FB
   hardware. It represents the frame buffer of some video hardware and
   allows application software to access the graphics hardware through
   a well-defined interface, so the software doesn't need to know
-  anything about the low-level (hardware register) stuff. This works
-  across the different architectures supported by Linux and makes the
-  implementation of application programs easier and more portable; at
-  this point, an X server exists which uses the frame buffer device
-  exclusively.
-
+  anything about the low-level (hardware register) stuff. 
+
+  Frame buffer devices work identically across the different
+  architectures supported by Linux and make the implementation of
+  application programs easier and more portable; at this point, an X
+  server exists which uses the frame buffer device exclusively.
+  On several non-X86 architectures, the frame buffer device is the
+  only way to use the graphics hardware.
   The device is accessed through special device nodes, usually located
   in the /dev directory, i.e. /dev/fb*.
 
-  Please read the file Documentation/fb/framebuffer.txt for more
-  information.
+  You need an utility program called fbset to make full use of frame
+  buffer devices. Please read the file
+  Documentation/fb/framebuffer.txt for more information.
 
-  If you want to play with it, say Y here and to the driver for your
-  graphics board, below. If unsure, say N.
+  If you want to play with it, say Y here and also to the driver for
+  your graphics board, below. If unsure, say N, unless you are
+  compiling a kernel for a non-X86 architecture, in which case you
+  should say Y.
 
 Acorn VIDC support
 CONFIG_FB_ACORN
@@ -1555,33 +1530,34 @@ CONFIG_FB_AMIGA_AGA
 
 Amiga CyberVision support
 CONFIG_FB_CYBER
-  This enables support for the Cybervision 64 graphics card from Phase5.
-  Please note that its use is not all that intuitive (i.e. if you have
-  any questions, be sure to ask!).  Say N unless you have a Cybervision
-  64 or plan to get one before you next recompile the kernel.         
-  Please note that this driver DOES NOT support the Cybervision 64 3D
-  card, as they use incompatible video chips.           
+  This enables support for the Cybervision 64 graphics card from
+  Phase5. Please note that its use is not all that intuitive (i.e. if
+  you have any questions, be sure to ask!). Say N unless you have a
+  Cybervision 64 or plan to get one before you next recompile the
+  kernel. Please note that this driver DOES NOT support the
+  Cybervision 64 3D card, as they use incompatible video chips.
 
 Amiga CyberVision3D support (EXPERIMENTAL)
 CONFIG_FB_VIRGE
-  This enables support for the Cybervision 64/3D graphics card from Phase5.
-  Please note that its use is not all that intuitive (i.e. if you have
-  any questions, be sure to ask!).  Say N unless you have a Cybervision
-  64/3D or plan to get one before you next recompile the kernel.         
-  Please note that this driver DOES NOT support the older Cybervision 64
-  card, as they use incompatible video chips.           
+  This enables support for the Cybervision 64/3D graphics card from
+  Phase5. Please note that its use is not all that intuitive (i.e. if
+  you have any questions, be sure to ask!). Say N unless you have a
+  Cybervision 64/3D or plan to get one before you next recompile the
+  kernel. Please note that this driver DOES NOT support the older
+  Cybervision 64 card, as they use incompatible video chips.
 
 Amiga RetinaZ3 support (EXPERIMENTAL)
 CONFIG_FB_RETINAZ3
-  This enables support for the Retina Z3 graphics card. Say N unless you
-  have a Retina Z3 or plan to get one before you next recompile the kernel.
+  This enables support for the Retina Z3 graphics card. Say N unless
+  you have a Retina Z3 or plan to get one before you next recompile
+  the kernel.
 
 Amiga CLgen driver (EXPERIMENTAL)
 CONFIG_FB_CLGEN
-  This enables support for Cirrus Logic GD542x/543x based boards on Amiga:
-  SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.  Say N
-  unless you have such a graphics board or plan to get one before you next
-  recompile the kernel.
+  This enables support for Cirrus Logic GD542x/543x based boards on
+  Amiga: SD64, Piccolo, Picasso II/II+, Picasso IV, or EGS Spectrum.
+  Say N unless you have such a graphics board or plan to get one
+  before you next recompile the kernel.
 
 Atari native chipset support
 CONFIG_FB_ATARI
@@ -1628,8 +1604,10 @@ CONFIG_FB_HP300
 VGA chipset support (text only)
 CONFIG_FB_VGA
   This is the frame buffer device driver for generic VGA chips. This
-  driver works only in text mode; if you want graphics mode, say Y to
-  "VESA VGA graphics console" as well.
+  driver works only in text mode and is deprecated; it is preferable
+  to say Y to "VGA text console" instead. For a graphical frame buffer
+  device driver that works for VGA cards, say Y to "VESA VGA graphics
+  console" below.
 
 TGA frame buffer support' 
 CONFIG_FB_TGA
@@ -1638,15 +1616,17 @@ CONFIG_FB_TGA
 
 VESA VGA graphics console
 CONFIG_FB_VESA
-  This is the frame buffer device driver for generic VESA graphic cards.
-  Please read Documentation/fb/vesafb.txt.
+  This is the frame buffer device driver for generic VESA graphic
+  cards. You will get a boot time penguin logo at no additional cost.
+  Please read Documentation/fb/vesafb.txt. If unsure, say Y.
 
 MDA dual-headed support
 CONFIG_FB_MDA
   Say Y here if you have an old MDA or monochrome Hercules graphics
-  adapter in your system acting as a second head ( = video card).  Do 
-  not enable this driver if your MDA card is the primary card in your
-  system; the normal VGA driver will handle it.
+  adapter in your system acting as a second head ( = video card). You
+  will then be able to use two monitors with your Linux system. Do not
+  say Y here if your MDA card is the primary card in your system; the
+  normal VGA driver will handle it.
   
   This driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want).
@@ -1683,13 +1663,14 @@ CONFIG_FB_TCX
 
 Virtual Frame Buffer support (ONLY FOR TESTING!)
 CONFIG_FB_VIRTUAL
-  This is a `virtual' frame buffer device.  It operates on a chunk of
-  unswapable kernel memory instead of on the memory of a graphics board.
-  This means you cannot see any output sent to this frame buffer device,
-  while it does consume precious memory.  The main use of this frame
-  buffer device is testing and debugging the frame buffer subsystem. Do
-  NOT enable it for normal systems! To protect the innocent, it has to
-  be enabled explicitly on boot time using the kernel option `video=vfb:'.
+  This is a `virtual' frame buffer device. It operates on a chunk of
+  unswapable kernel memory instead of on the memory of a graphics
+  board. This means you cannot see any output sent to this frame
+  buffer device, while it does consume precious memory. The main use
+  of this frame buffer device is testing and debugging the frame
+  buffer subsystem. Do NOT enable it for normal systems! To protect
+  the innocent, it has to be enabled explicitly at boot time using the
+  kernel option `video=vfb:'.
 
   This driver is also available as a module ( = code which can be
   inserted and removed from the running kernel whenever you want).
@@ -1706,12 +1687,12 @@ CONFIG_FBCON_ADVANCED
   drivers. Note that they are used for text console output only; they are
   NOT needed for graphical applications.
 
-  If you do not enable this option, the needed low level drivers are
-  automatically enabled, depending on what frame buffer devices you
-  selected. This is recommended for most users.
+  If you say N here, the needed low level drivers are automatically
+  enabled, depending on what frame buffer devices you selected above.
+  This is recommended for most users.
 
-  If you enable this option, you have more fine-grained control over which
-  low level drivers are enabled. You can e.g. leave out low level drivers
+  If you say Y here, you have more fine-grained control over which low
+  level drivers are enabled. You can e.g. leave out low level drivers
   for color depths you do not intend to use for text consoles.
 
   Low level frame buffer console drivers can be modules ( = code which
@@ -1785,13 +1766,13 @@ CONFIG_FBCON_IPLAN2P8
 Mac variable bpp packed pixels support
 CONFIG_FBCON_MAC
   This is the low level frame buffer console driver for 1/2/4/8/16/32
-  bits per pixel packed pixels on Mac. It supports variable fontwidths
+  bits per pixel packed pixels on Mac. It supports variable font widths
   for low resolution screens.
   
 VGA characters/attributes support
 CONFIG_FBCON_VGA
-  This is the low level frame buffer console driver for VGA text mode, as
-  used by vgafb.
+  This is the low level frame buffer console driver for VGA text mode;
+  it is used if you said Y to "VGA chipset support (text only)" above.
 
 Parallel-port support
 CONFIG_PARPORT
@@ -1809,8 +1790,8 @@ CONFIG_PARPORT
 
   It is possible to share a single parallel port among several devices
   and it is safe to compile all the corresponding drivers into the
-  kernel. If you want to compile parallel port support as a module ( =
-  code which can be inserted in and removed from the running kernel
+  kernel. If you want to compile parallel port support as a module 
+  ( = code which can be inserted in and removed from the running kernel
   whenever you want), say M here and read Documentation/modules.txt.
   The module will be called parport.o. If you have more than one
   parallel port and want to specify which port and IRQ to be used by
@@ -1851,8 +1832,8 @@ CONFIG_CPU_LITTLE_ENDIAN
 
 Plug and Play support
 CONFIG_PNP
-  Plug and Play support allows the kernel to automatically configure some
-  peripheral devices.  Say Y to enable PnP.
+  Plug and Play support allows the kernel to automatically configure
+  some peripheral devices. Say Y to enable PnP.
 
 Auto-probe for parallel devices
 CONFIG_PNP_PARPORT
@@ -2088,11 +2069,10 @@ CONFIG_IP_FIREWALL
 
 IP: firewall packet netlink device
 CONFIG_IP_FIREWALL_NETLINK
-  If you say Y here and then packets hit your Linux firewall and are
-  blocked, the first 128 bytes of each such packet are passed on to
-  optional user space monitoring software that can then look for
-  attacks and take actions such as paging the administrator of the
-  site. 
+  If you say Y here, then the first 128 bytes of each packet that hit
+  your Linux firewall and was blocked are passed on to optional user
+  space monitoring software that can then look for attacks and take
+  actions such as paging the administrator of the site.
 
   To use this, you need to create a character special file under /dev
   with major number 36 and minor number 3 using mknod ("man mknod"),
@@ -2218,13 +2198,14 @@ CONFIG_IP_MASQUERADE
   http://www.tor.shaw.wave.ca/~ambrose/kernel21.html. 
 
   If you say Y here, you should also say Y to "IP: always defragment",
-  below. If you say Y here, then the modules ip_masq_ftp.o (for ftp
-  transfers through the firewall), ip_masq_irc.o (for irc chats
-  through the firewall), and ip_masq_raudio.o (for RealAudio downloads
-  through the firewall) will automatically be compiled. Modules are
-  pieces of code which can be inserted in and removed from the running
-  kernel whenever you want; read Documentation/modules.txt for
-  details.
+  below. 
+
+  If you say Y here, then the modules ip_masq_ftp.o (for ftp transfers
+  through the firewall), ip_masq_irc.o (for irc chats through the
+  firewall), and ip_masq_raudio.o (for RealAudio downloads through the
+  firewall) will automatically be compiled. Modules are pieces of code
+  which can be inserted in and removed from the running kernel
+  whenever you want; read Documentation/modules.txt for details.
 
 IP: ICMP masquerading
 CONFIG_IP_MASQUERADE_ICMP
@@ -2441,16 +2422,16 @@ CONFIG_IP_NOSR
 
 IP: Allow large windows (not recommended if <16Mb of memory)
 CONFIG_SKB_LARGE
-  On high speed, long distance networks the performance limit on 
+  On high speed, long distance networks the performance limit on
   networking becomes the amount of data a machine can buffer until the
   other end confirms its reception. (At 45Mbit/second there are a lot
-  of bits between New York and London ..). This option allows larger
-  amounts of data to be "in flight" at a given time. It also means a user
-  process can require a lot more memory for network buffers and thus this
-  option is best only used on machines with 16Mb of memory or higher. 
-  Unless you are using long links with end to end speeds of over 2Mbit
-  a second or satellite links this option will make no difference to
-  performance.
+  of bits between New York and London ...). This option allows larger
+  amounts of data to be "in flight" at a given time. It also means a
+  user process can require a lot more memory for network buffers and
+  thus this option is best used only on machines with 16Mb of memory
+  or higher. Unless you are using long links with end to end speeds of
+  over 2Mbit a second or satellite links this option will make no
+  difference to performance.
 
 Unix domain sockets
 CONFIG_UNIX
@@ -2484,13 +2465,10 @@ CONFIG_IPV6
   and the file net/ipv6/README in the kernel source. 
 
   If you want to use IPv6, please upgrade to the newest net-tools as
-  given in Documentation/Changes.
+  given in Documentation/Changes. You will still be able to do regular
+  IPv4 networking as well.
 
-  The IPv6 support is also available as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want).
-  The module will be called ipv6.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt. It's safe to
-  say N for now.
+  It is safe to say N here for now.
 
 IPv6: enable EUI-64 token format
 CONFIG_IPV6_EUI64
@@ -2522,7 +2500,7 @@ CONFIG_IPX
   to access Novell NetWare file or print servers using the Linux
   Novell client ncpfs (available via FTP (user: anonymous) from
   ftp://sunsite.unc.edu/pub/Linux/system/filesystems/) or from within
-  the Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
+  the Linux DOS emulator DOSEMU (read the DOSEMU-HOWTO, available in
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO). In order to do the
   former, you'll also have to say Y to "NCP filesystem support",
   below.
@@ -2533,9 +2511,9 @@ CONFIG_IPX
 
   To turn your Linux box into a fully featured NetWare file server and
   IPX router, say Y here and fetch either lwared from
-  ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe from
-  ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information, read the
-  IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
+  ftp://sunsite.unc.edu/pub/Linux/system/network/daemons/ or mars_nwe
+  from ftp://ftp.gwdg.de/pub/linux/misc/ncpfs. For more information,
+  read the IPX-HOWTO in ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.
 
   General information about how to connect Linux, Windows machines and
   Macs is on the WWW at http://www.eats.com/linux_mac_win.html (to
@@ -2774,9 +2752,9 @@ CONFIG_ROSE
   A comprehensive listing of all the software for Linux amateur radio
   users as well as information about how to configure an AX.25 port is
   contained in the AX25-HOWTO, available via FTP (user: anonymous) in
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You also might want to check
-  out the file Documentation/networking/ax25.txt. More information
-  about digital amateur radio in general is on the WWW at
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. You also might want to
+  check out the file Documentation/networking/ax25.txt. More
+  information about digital amateur radio in general is on the WWW at
   http://www.tapr.org/tapr/html/pkthome.html (To browse the WWW, you
   need to have access to a machine on the Internet that has a program
   like lynx or netscape).
@@ -2836,9 +2814,9 @@ CONFIG_DMASCC
 
   Currently, this driver supports Ottawa PI/PI2
   (http://hydra.carleton.ca/info/pi2.html) and Gracilis PackeTwin
-  (http://www.paccomm.com/) boards. They are detected automatically.
-  If you have one of these cards, say Y here and read the HAM-HOWTO,
-  available via FTP (user: anonymous) in
+  (http://www.paccomm.com/gracilis.html) boards. They are detected
+  automatically. If you have one of these cards, say Y here and read
+  the AX25-HOWTO, available via FTP (user: anonymous) in
   ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO/.
 
   This driver can operate multiple boards simultaneously. If you compile
@@ -2862,11 +2840,11 @@ CONFIG_DMASCC
 Z8530 SCC driver for AX.25
 CONFIG_SCC
   These cards are used to connect your Linux box to an amateur radio
-  in order to communicate with other computers.  If you want to use
+  in order to communicate with other computers. If you want to use
   this, read Documentation/networking/z8530drv.txt and the
-  AX.25-HOWTO, available via FTP (user: anonymous) at
-  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO.  Also make sure to say Y to
-  "Amateur Radio AX.25 Level 2" support. 
+  AX25-HOWTO, available via FTP (user: anonymous) at
+  ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. Also make sure to say Y
+  to "Amateur Radio AX.25 Level 2" support.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -3383,7 +3361,7 @@ CONFIG_OVERRIDE_CMDS
 Maximum number of commands per LUN
 CONFIG_AIC7XXX_CMDS_PER_LUN
   Specify the maximum number of commands you would like to allocate
-  per LUN (a LUN is a Logical Unit Number - some physical SCSI devices,
+  per LUN (a LUN is a Logical Unit Number -- some physical SCSI devices,
   e.g. CD jukeboxes, act logically as several separate units, each of
   which gets its own number).  
 
@@ -3618,7 +3596,7 @@ CONFIG_SCSI_NCR53C8XX_SYNC
   rates: FAST-5, FAST-10, FAST-20 and FAST-40. The numbers are
   respectively the maximum data transfer rates in mega-transfers per
   second for each class. For example, a FAST-20 Wide 16 device is able
-  to transfer data at 40 million 16 bit packets per second for a total
+  to transfer data at 20 million 16 bit packets per second for a total
   rate of 40 MB/s.
 
   You may specify 0 if you want to only use asynchronous data
@@ -3753,26 +3731,27 @@ Standard SCSI-order
 CONFIG_IBMMCA_SCSI_ORDER_STANDARD
   In the PC-world and in most modern SCSI-BIOS-setups, SCSI-hard disks
   are assigned to the drive letters, starting with the lowest SCSI-id
-  (physical number - pun) to be drive C:, as seen from DOS and similar
-  operating systems. When looking into papers describing the
+  (physical number -- pun) to be drive C:, as seen from DOS and
+  similar operating systems. When looking into papers describing the
   ANSI-SCSI-standard, this assignment of drives appears to be wrong.
-  The SCSI-standard follows a hardware-hierarchy which says that
-  id 7 has the highest priority and id 0 the lowest. Therefore, the
-  host adapters are still today everywhere placed as SCSI-id 7 by
-  default. In the SCSI-standard, the drive letters express the priority
-  of the disk. C: should be the hard disk, or a partition on it, with the
+  The SCSI-standard follows a hardware-hierarchy which says that id 7
+  has the highest priority and id 0 the lowest. Therefore, the host
+  adapters are still today everywhere placed as SCSI-id 7 by default.
+  In the SCSI-standard, the drive letters express the priority of the
+  disk. C: should be the hard disk, or a partition on it, with the
   highest priority. This must therefore be the disk with the highest
   SCSI-id (e.g. 6) and not the one with the lowest! IBM-BIOS kept the
   original definition of the SCSI-standard as also industrial- and
   process-control-machines, like VME-CPUs running under realtime-OSs
   (e.g. LynxOS, OS9) do.
 
-  If you like to run Linux on your MCA-machine with the same assignment
-  of hard disks as seen from e.g. DOS or OS/2 on your machine, which
-  is in addition conformant to the SCSI-standard, you must say Y here.
-  This is also necessary for MCA-Linux-users who want to keep downward-
-  compatibility to older releases of the IBM-MCA-SCSI-driver (older than
-  driver-release 2.00 and older than June 1997).
+  If you like to run Linux on your MCA-machine with the same
+  assignment of hard disks as seen from e.g. DOS or OS/2 on your
+  machine, which is in addition conformant to the SCSI-standard, you
+  must say Y here. This is also necessary for MCA-Linux users who want
+  to keep downward- compatibility to older releases of the
+  IBM-MCA-SCSI-driver (older than driver-release 2.00 and older than
+  June 1997).
 
   If you like to have the lowest SCSI-id assigned as drive C:, as
   modern SCSI-BIOSes do, which does not conform to the standard, but
@@ -4073,6 +4052,7 @@ CONFIG_FC4
   support, as well as the drivers for the storage array itself and
   for the interface adapter such as SOC. This subsystem could even
   serve for IP networking, with some code extensions.
+
   If unsure, say N.
 
 Sun SOC
@@ -4124,7 +4104,7 @@ CONFIG_SCSI_CUMANA_2
 
 EcoSCSI support
 CONFIG_SCSI_ECOSCSI
-  This enables support for the EcoSCSI card - a small card that sits in
+  This enables support for the EcoSCSI card -- a small card that sits in
   the Econet socket.  If you have an Acorn system with one of these,
   say Y.  If unsure, say N.
 
@@ -4354,58 +4334,6 @@ CONFIG_WAVELAN
   module, say M here and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt.
 
-AIMSlab RadioTrack (aka RadioReveal) support
-CONFIG_RADIO_RTRACK
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
-
-  In order to control your radio card, you will need to use programs
-  that are compatible with the Video for Linux API.  Information on 
-  this API and pointers to "v4l" programs may be found on the WWW at
-  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
-  you need to have access to a machine on the Internet that has a 
-  program like lynx or netscape.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called radio-aimslab.o.
-
-RadioTrack i/o port
-CONFIG_RADIO_RTRACK_PORT
-  Enter either 0x30f or 0x20f here.  The card default is 0x30f, if you
-  haven't changed the jumper setting on the card.
-
-Aztech/Packard Bell Radio
-CONFIG_RADIO_AZTECH
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
-  
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called radio-aztech.o.
-
-Aztech/Packard Bell radio card i/o port
-CONFIG_RADIO_AZTECH_PORT
-  Enter either 0x350 or 0x358 here.  The card default is 0x350, if you
-  haven't changed the setting of jumper JP3 on the card.  Removing the
-  jumper sets the card to 0x358.
-
-SF16FMI Radio
-CONFIG_RADIO_SF16FMI
-  Choose Y here if you have one of these FM radio cards, and then fill
-  in the port address below.
-
-  If you want to compile this driver as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called radio-sf16fmi.o
-
-SF16FMI I/O port (0x284 or 0x384)
-CONFIG_RADIO_SF16FMI_PORT
-  Enter the I/O port of your SF16FMI radio card.
-
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
   This is a driver for a pseudo device (typically called /dev/lapb0)
@@ -4645,7 +4573,7 @@ Forwarding between high speed interfaces
 CONFIG_NET_HW_FLOWCONTROL
   This option enables NIC (Network Interface Card) hardware throttling
   during periods of extremal congestion. At the moment only a couple
-  of device drivers support it (really only one ---tulip, modified
+  of device drivers support it (really only one -- tulip, modified
   8390 can be found at
   ftp://ftp.inr.ac.ru/ip-routing/fastroute-8390.tar.gz). Really, this
   option is applicable to any machine attached to a fast enough
@@ -4827,11 +4755,17 @@ CONFIG_NET_PROFILE
   performance will be written to /proc/net/profile. If you don't know
   what it is about, you don't need it: say N.
 
+#Comtrol Hostess SV-11 support
+#CONFIG_HOSTESS_SV11
+###
+### I don't know what this is.
+###  
+
 WAN Drivers
 CONFIG_WAN_DRIVERS
   Say Y to this option if your Linux box contains a WAN card and you
-  are planning to use the box as a WAN ( = Wide Area Network) router (
-  = device used to interconnect local area networks over wide area
+  are planning to use the box as a WAN ( = Wide Area Network) router
+  = device used to interconnect local area networks over wide area
   communication links, such as leased lines and public data networks,
   e.g. X.25 and frame relay) and you will be offered a list of drivers
   for WAN cards currently available. For more information, read
@@ -5650,7 +5584,7 @@ CONFIG_TLAN
 
   Devices currently supported by this driver are Compaq Netelligent,
   Compaq NetFlex and Olicom cards. Please read the file
-  Documentation/tlan.txt for details.
+  Documentation/networking/tlan.txt for more details.
 
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
@@ -5974,8 +5908,8 @@ Aztech/Orchid/Okano/Wearnes/TXC/CyDROM CDROM support
 CONFIG_AZTCD
   This is your driver if you have an Aztech CDA268-01A, Orchid
   CD-3110, Okano or Wearnes CDD110, Conrad TXC, or CyCDROM CR520 or
-  CR540 CDROM drive.  This driver - just like all these CDROM drivers
-  - is NOT for CDROM drives with IDE/ATAPI interfaces, such as Aztech
+  CR540 CDROM drive.  This driver -- just like all these CDROM drivers
+  -- is NOT for CDROM drives with IDE/ATAPI interfaces, such as Aztech
   CDA269-031SE. Please read the file Documentation/cdrom/aztcd. 
 
   If you say Y here, you should also say Y or M to "ISO 9660 CDROM
@@ -6143,8 +6077,10 @@ CONFIG_EXT2_FS
   directories on ext2 filesystems, use chattr ("man chattr").
   
   Ext2fs partitions can be read from within DOS using the ext2tool
-  package available via FTP (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2.
+  package (available via FTP (user: anonymous) from
+  ftp://sunsite.unc.edu/pub/Linux/system/filesystems/ext2) and from
+  within Windows 95 and Windows NT using the ex2fs explorer available
+  from http://jnewbigin-pc.it.swin.edu.au/Linux/Explore2fs.htm.
 
   If you want to compile this filesystem as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -6198,7 +6134,7 @@ CONFIG_FAT_FS
   want), say M here and read Documentation/modules.txt. The module
   will be called fat.o. Note that if you compile the FAT support as a
   module, you cannot compile any of the FAT-based filesystems into the
-  kernel - they will have to be modules as well. The filesystem of
+  kernel -- they will have to be modules as well. The filesystem of
   your root partition cannot be a module, so don't say M here if you
   intend to use UMSDOS as your root filesystem.
 
@@ -6288,7 +6224,7 @@ CONFIG_PROC_FS
   It's totally cool; for example, "cat /proc/interrupts" gives
   information about what the different IRQs are used for at the moment
   (there is a small number of Interrupt ReQuest lines in your computer
-  that are used by the attached devices to gain the CPU's attention -
+  that are used by the attached devices to gain the CPU's attention --
   often a source of trouble if two devices are mistakenly configured
   to use the same IRQ). This option will enlarge your kernel by about
   18 kB. Several programs depend on this, so everyone should say Y
@@ -6308,8 +6244,8 @@ CONFIG_NFS_FS
   ftp://sunsite.unc.edu/pub/Linux/docs/LDP, on its man page: "man
   nfs", and in the NFS-HOWTO.
   
-  An alternative to NFS is provided by the Coda filesystem; see "Coda
-  filesystem support" below.
+  An superior but less widely used alternative to NFS is provided by
+  the Coda filesystem; see "Coda filesystem support" below.
 
   If you say Y here, you should have said Y to TCP/IP networking also.
   This option would enlarge your kernel by about 27 kB. 
@@ -6480,8 +6416,8 @@ CONFIG_ROMFS_FS
 
 QNX filesystem support (EXPERIMENTAL)
 CONFIG_QNX4FS_FS  
-  This is the filesystem used by QNX 4. Say Y if you intend to mount
-  QNX hard disks and floppies.
+  This is the filesystem used by the operating system QNX 4. Say Y if
+  you intend to mount QNX hard disks or floppies.
 
   This filesystem support is also available as a module ( = code which
   can be inserted in and removed from the running kernel whenever you
@@ -6498,8 +6434,8 @@ CONFIG_AUTOFS_FS
   automounter (amd), which is a pure user space daemon.
 
   To use the automounter you need the user-space tools from
-  ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say Y to
-  "NFS filesystem support", above. 
+  ftp://ftp.kernel.org/pub/linux/daemons/autofs; you also want to say
+  Y to "NFS filesystem support", above.
 
   If you want to compile this as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -6509,31 +6445,33 @@ CONFIG_AUTOFS_FS
   If you are not a part of a fairly large, distributed network, you
   probably do not need an automounter, and can say N here.
 
-UFS filesystem support (read only)
+UFS filesystem support
 CONFIG_UFS_FS
   BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD,
   OpenBSD and NeXTstep) use a filesystem called UFS. Some System V
   Unixes can create and mount hard disk partitions and diskettes using
   this filesystem as well. Saying Y here allows you to mount these
-  partitions and diskettes read-only.
+  partitions and diskettes.
 
   If you only intend to mount files from some other Unix over the
   network using NFS, you don't need the UFS filesystem support (but
-  you need NFS filesystem support obviously). Note that this option is
-  generally not needed for floppies, since a good portable way to
-  transport files and directories between unixes (and even other
-  operating systems) is given by the tar program ("man tar" or
-  preferably "info tar"). 
+  you need NFS filesystem support obviously). 
+
+  Note that this option is generally not needed for floppies, since a
+  good portable way to transport files and directories between unixes
+  (and even other operating systems) is given by the tar program ("man
+  tar" or preferably "info tar").
 
   When accessing NeXTstep files, you may need to convert them from the
   NeXT character set to the Latin1 character set; use the program
   recode ("info recode") for this purpose. 
 
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt. The module will be
-  called ufs.o. If you haven't heard about all of this before, it's
-  safe to say N.
+  If you want to compile the UFS filesystem support as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want), say M here and read Documentation/modules.txt.
+  The module will be called ufs.o. 
+
+  If you haven't heard about all of this before, it's safe to say N.
 
 BSD disklabel (FreeBSD partition tables) support
 CONFIG_BSD_DISKLABEL
@@ -6588,18 +6526,22 @@ CONFIG_ADFS_FS
 
 /dev/pts filesystem (experimental)
 CONFIG_DEVPTS_FS
-  If you say Y here, you'll get a virtual filesystem which can be
-  mounted on /dev/pts with "mount -t devpts". This, together with the
-  pseudo terminal master multiplexer /dev/ptmx, is used for pseudo
-  terminal support as described in the Open Group's Unix98 standard:
-  in order to acquire a pseudo terminal, a process opens /dev/ptmx;
-  the number of the pseudo terminal is then made available to the
-  process and the pseudo terminal slave can be accessed as
-  /dev/pts/<number>. What was traditionally /dev/ttyp2 will then be
-  /dev/pts/2, for example. The GNU C library glibc 2.1 contains the
-  requisite support for this mode of operation.
-
-  Say Y here if you have enabled support for Unix98 PTYs.
+  You should say Y here if you said Y to "Unix98 PTY support" above.
+  You'll then get a virtual filesystem which can be mounted on
+  /dev/pts with "mount -t devpts". This, together with the pseudo
+  terminal master multiplexer /dev/ptmx, is used for pseudo terminal
+  support as described in the Open Group's Unix98 standard: in order
+  to acquire a pseudo terminal, a process opens /dev/ptmx; the number
+  of the pseudo terminal is then made available to the process and the
+  pseudo terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example. The
+  GNU C library glibc 2.1 contains the requisite support for this mode
+  of operation.
+
+  This code is also available as a module called devpts.o ( = code
+  which can be inserted in and removed from the running kernel
+  whenever you want). If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 Macintosh partition map support
 CONFIG_MAC_PARTITION
@@ -6804,7 +6746,7 @@ CONFIG_NLS_CODEPAGE_850
   DOS/Windows partitions correctly. This does apply to the filenames
   only, not to the file contents. You can include several codepages;
   say Y here if you want to include the DOS codepage that is used for
-  much of Europe--United Kingdom, Germany, Spain, Italy, and [add more
+  much of Europe -- United Kingdom, Germany, Spain, Italy, and [add more
   countries here]. It has some characters useful to many European
   languages that are not part of the US codepage 437. If unsure, say
   Y.
@@ -7235,6 +7177,42 @@ CONFIG_ESPSERIAL
   and read Documentation/modules.txt. The module will be called esp.o.
   If unsure, say N.
 
+Unix98 PTY support
+CONFIG_UNIX98_PTYS
+  A pseudo terminal (PTY) is a software device consisting of two
+  halves: a master and a slave. The slave device behaves identical to
+  a physical terminal; the master device is used by a process to
+  read data from and write data to the slave, thereby emulating a
+  terminal. Typical programs for the master side are xterm and telnet
+  servers. 
+  
+  Linux has traditionally used the BSD-like names /dev/ptyxx for
+  masters and /dev/ttyxx for slaves of pseudo terminals. This scheme
+  has a number of problems. The GNU C library glibc 2.1 and later,
+  however, supports the Unix98 naming standard: in order to acquire a
+  pseudo terminal, a process opens /dev/ptmx; the number of the pseudo
+  terminal is then made available to the process and the pseudo
+  terminal slave can be accessed as /dev/pts/<number>. What was
+  traditionally /dev/ttyp2 will then be /dev/pts/2, for example.
+
+  The entries in /dev/pts/ are created on the fly by a virtual
+  filesystem; therefore, if you say Y here you should say Y to
+  "/dev/pts filesystem for Unix98 PTYs" as well.
+
+  Say Y here if you are uncertain, unless you are very short on
+  memory.
+
+Maximum number of Unix98 PTYs in use (0-2048)
+CONFIG_UNIX98_PTY_COUNT
+  The maximum number of Unix98 PTYs that can be used at any one time.
+  The default is 256, and should be enough for desktop systems. Server
+  machines which support incoming telnet/rlogin/ssh connections and/or
+  serve several X terminals may want to increase this: every incoming
+  connection and every xterm uses up one PTY.
+
+  When not in use, each additional set of 256 PTYs occupy
+  approximately 8K of kernel memory on 32-bit architectures.
+
 Parallel printer support
 CONFIG_PRINTER
   If you intend to attach a printer to the parallel port of your Linux
@@ -7355,7 +7333,7 @@ CONFIG_MS_BUSMOUSE
 
   If you are unsure, say N and read the HOWTO nevertheless: it will
   tell you what you have. Also be aware that several vendors talk
-  about 'Microsoft busmouse' and actually mean PS/2 busmouse - so
+  about 'Microsoft busmouse' and actually mean PS/2 busmouse -- so
   count the pins on the connector.
 
   If you want to compile this as a module ( = code which can be
@@ -7807,12 +7785,12 @@ CONFIG_APM_DO_ENABLE
 Do CPU IDLE calls
 CONFIG_APM_CPU_IDLE
   Enable calls to APM CPU Idle/CPU Busy inside the kernel's idle loop.
-  On some machines, this can activate improved power savings, such as a
-  slowed CPU clock rate, when the machine is idle.  These idle calls are
-  made after the idle loop has run for some length of time (e.g., 333
-  mS).  On some machines, this will cause a hang at boot time or whenever
-  the CPU becomes idle.  (On machines with more than one CPU, this option
-  does nothing.)
+  On some machines, this can activate improved power savings, such as
+  a slowed CPU clock rate, when the machine is idle. These idle calls
+  are made after the idle loop has run for some length of time (e.g.,
+  333 mS). On some machines, this will cause a hang at boot time or
+  whenever the CPU becomes idle. (On machines with more than one CPU,
+  this option does nothing.)
 
 Enable console blanking using APM
 CONFIG_APM_DISPLAY_BLANK
@@ -7899,8 +7877,8 @@ CONFIG_WDT_501
 
 Fan Tachometer
 CONFIG_WDT_501_FAN
-  Enable the Fan Tachometer on the WDT501. Only do this if you have a fan
-  tachometer actually set up.
+  Enable the Fan Tachometer on the WDT501. Only do this if you have a
+  fan tachometer actually set up.
 
 Software Watchdog
 CONFIG_SOFT_WATCHDOG
@@ -8027,7 +8005,7 @@ CONFIG_SOUND
   from ftp://sunsite.unc.edu/pub/Linux/docs/HOWTO. There is also some
   information in various README files in drivers/sound, esp. in
   Readme.cards which you should read first to find out whether your
-  card is supported by Linux.
+  card is supported by Linux, and, if yes, which driver to use.
 
   If you have a PnP sound card and you want to configure it at boot
   time using the ISA PnP tools (read
@@ -8046,11 +8024,25 @@ CONFIG_SOUND
   ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console/ and in the
   pcsp patch at ftp://dwmw2.robinson.cam.ac.uk/pub/kernel/ .
 
+OSS sound modules
+CONFIG_SOUND_OSS
+  OSS is the Open Sound System suite of sound card drivers. They make
+  sound programming easier since they provide a common API. Say Y or M
+  here (the module will be called sound.o) if you haven't found a
+  driver for your sound card above, then pick your driver from the
+  list below.
 Support for Aztech Sound Galaxy (non-PnP) cards
 CONFIG_SOUND_SGALAXY
-  This module initializes the older non Plug and Play sound galaxy cards
-  from Aztech. It supports the Waverider Pro 32 - 3D and the Galaxy
-  Washington 16.
+  This module initializes the older non Plug and Play sound galaxy
+  cards from Aztech. It supports the Waverider Pro 32 - 3D and the
+  Galaxy Washington 16.
+
+Yamaha OPL3-SA1 audio controller
+CONFIG_SOUND_OPL3SA1
+  Say Y or M if you have a Yamaha OPL3-SA1 sound chip, which is
+  usually built into motherboards. Read Documentation/sound/OPL3-SA
+  for details.
 
 ProAudioSpectrum 16 support
 CONFIG_SOUND_PAS
@@ -8065,15 +8057,21 @@ CONFIG_SOUND_SB
   Creative Labs or a 100% hardware compatible clone (like the
   Thunderboard or SM Games). If your card was in the list of supported
   cards look at the card specific instructions in the
-  drivers/sound/Readme.cards file before answering this question. For
+  drivers/sound/Readme.cards file before answering this question.  For
   an unknown card you may answer Y if the card claims to be
   Sound Blaster-compatible. 
 
-  Please read Documentation/sound/Soundblaster.
+  You can say M here to compile this driver as a module; the module is
+  called sb.o.
 
-  If you have an SB AWE 32 or SB AWE 64, say
-  Y here and to "Additional lowlevel drivers" and to "SB32/AWE
-  support" below.
+  You should also say Y here for cards based on the Avance Logic
+  ALS-007 chip (read Documentation/sound/ALS007) and for ESS1688 and
+  ESS1868 cards (read Documentation/sound/ESS1868). If you have an SB
+  AWE 32 or SB AWE 64, say Y here and also to "Additional lowlevel
+  drivers" and to "SB32/AWE support" below. If you have an IBM Mwave
+  card, say Y here and read Documentation/sound/mwave.
+  
+  Please read Documentation/sound/Soundblaster.
 
 Generic OPL2/OPL3 FM synthesizer support
 CONFIG_SOUND_ADLIB
@@ -8081,7 +8079,13 @@ CONFIG_SOUND_ADLIB
   Answering Y is usually a safe and recommended choice, however some
   cards may have software (TSR) FM emulation. Enabling FM support with
   these cards may cause trouble (I don't currently know of any such
-  cards, however). If unsure, say Y.
+  cards, however). 
+
+  Please read the file Documentation/sound/OPL3 if your card has an
+  OPL3 chip.
+
+  If unsure, say Y.
+  
 
 #Loopback MIDI device support
 #CONFIG_SOUND_VMIDI
@@ -8114,24 +8118,33 @@ CONFIG_SOUND_UART6850
 
 PSS (AD1848, ADSP-2115, ESC614) support
 CONFIG_SOUND_PSS
-  Answer Y only if you have Orchid SW32, Cardinal DSP16 or some other
-  card based on the PSS chipset (AD1848 codec + ADSP-2115 DSP chip +
-  Echo ESC614 ASIC CHIP).
+  Answer Y or M if you have an Orchid SW32, Cardinal DSP16, Beethoven
+  ADSP-16 or some other card based on the PSS chipset (AD1848 codec +
+  ADSP-2115 DSP chip + Echo ESC614 ASIC CHIP). For more information on
+  how to compile it into the kernel or as a module see the file
+  Documentation/sound/PSS.
+
+Enable PSS mixer (Beethoven ADSP-16 and other compatible)
+CONFIG_PSS_MIXER
+  Answer Y for Beethoven ADSP-16. You may try to say Y also for other
+  cards if they have master volume, bass, treble, and you can't
+  control it under Linux. If you answer N for Beethoven ADSP-16, you
+  can't control master volume, bass, treble and synth volume.
+
+  If you said M to "PSS support" above, you may enable or disable this
+  PSS mixer with the module parameter pss_mixer. For more information
+  see the file Documentation/sound/PSS.
 
-#Enable PSS mixer (Beethoven ADSP-16 and other compatible)
-#CONFIG_PSS_MIXER
-###
-### Don't know what this is
-###
-#
 Have DSPxxx.LD firmware file
 CONFIG_PSS_HAVE_BOOT
-  If you want to emulate the Sound Blaster card and you have a DSPxxx.LD
-  file, then answer Y here to include this file.
+  If you have the DSPxxx.LD file or SYNTH.LD file for you card, answer
+  Y to include this file. Without this file the synth device (OPL) may
+  not work.
 
 Full pathname of DSPxxx.LD firmware file
 CONFIG_PSS_BOOT_FILE
-  Enter the full pathname of your DSPxxx.LD file, starting from /.
+  Enter the full pathname of your DSPxxx.LD file or SYNTH.LD file,
+  starting from /.
 
 16 bit sampling option of GUS (_NOT_ GUS MAX)
 CONFIG_SOUND_GUS16
@@ -8200,9 +8213,19 @@ CONFIG_SOUND_MAD16
   quite common so it's possible that many no-name cards have one of
   them. In addition the MAD16 chip is used in some cards made by known
   manufacturers such as Turtle Beach (Tropez), Reveal (some models)
-  and Diamond (latest ones). See also Documentation/sound/Opti for
+  and Diamond (latest ones). Note however that the Tropez sound cards
+  have their own driver; if you have one of those, say N here and Y or
+  M to "Full support for Turtle Beach WaveFront", below. 
+
+  See also Documentation/sound/Opti and Documentation/sound/MAD16 for
   more information on setting these cards up as modules.
 
+Full support for Turtle Beach WaveFront synth/sound cards
+CONFIG_SOUND_WAVEFRONT
+  Answer Y or M if you have a Tropez Plus, Tropez or Maui sound card
+  and read the files Documentation/sound/Wavefront and
+  Documentation/sound/Tropez+.
+  
 Support MIDI in older MAD16 based cards (requires SB)
 CONFIG_MAD16_OLDCARD
   Answer Y (or M) if you have an older card based on the C928
@@ -8272,7 +8295,15 @@ CONFIG_MSNDPIN_PERM_FILE
   obtained from Turtle Beach.  See Documentation/sound/MultiSound for
   information on how to obtain this.
 
-MSND Pinnacle Non-PnP Mode
+MSND Pinnacle have S/PDIF I/O
+CONFIG_MSNDPIN_DIGITAL
+  If you have the S/PDIF daughterboard for the Pinnacle or Fiji, say Y
+  here; otherwise, say N.  If you have this, you will be able to play
+  and record from the S/PDIF port (digital signal). See
+  Documentation/sound/MultiSound for information on how to make use of
+  this capability.
+
+MSND Pinnacle non-PnP Mode
 CONFIG_MSNDPIN_NONPNP
   The Pinnacle and Fiji card resources can be configured either with
   PnP, or through a configuration port.  For the Pinnacle,
@@ -8283,13 +8314,20 @@ CONFIG_MSNDPIN_NONPNP
   you must say N here and use isapnptools to configure the card's
   resources.
 
-MSND Pinnacle Config Port
+MSND Pinnacle config port
 CONFIG_MSNDPIN_CFG
   This is the port which the Pinnacle and Fiji uses to configure
   the card's resources when not in PnP mode.  If your card is in
   PnP mode, then be sure to say N to the previous option,
   CONFIG_MSNDPIN_NONPNP.
 
+MSND buffer size (kB)
+CONFIG_MSND_FIFOSIZE
+  Configures the size of each audio buffer, in kilobytes, for
+  recording and playing in the MultiSound drivers (both the Classic
+  and Pinnacle).  Larger values reduce the chance of data overruns at
+  the expense of overall latency. If unsure, use the default.
+
 /dev/dsp and /dev/audio support
 CONFIG_SOUND_AUDIO
   Answering N disables /dev/dsp and /dev/audio, the A/D and D/A
@@ -8339,18 +8377,22 @@ CONFIG_AWE32_SYNTH
 
 Gallant's Audio Excel DSP 16 support (SC-6000 and SC-6600)
 CONFIG_AEDSP16
-  Answer Y if you have a Gallant's Audio Excel DSP 16 card. This card
-  can emulate either an SBPro or a Microsoft Sound System card, so you
-  should have said Y to either "Sound Blaster (SB, SBPro, SB16, clones)
-  support" or "Microsoft Sound System support", above, and you need to
-  answer the "MSS emulation" and "SBPro emulation" questions below
+  Answer Y if you have a Gallant's Audio Excel DSP 16 card. This
+  driver supports Audio Excel DSP 16 but not the III nor PnP versions
+  of this card.
+
+  The Gallant's Audio Excel DSP 16 card can emulate either an SBPro or
+  a Microsoft Sound System card, so you should have said Y to either
+  "100% Sound Blaster compatibles (SB16/32/64, ESS, Jazz16) support"
+  or "Microsoft Sound System support", above, and you need to answer
+  the "MSS emulation" and "SBPro emulation" questions below
   accordingly. You should say Y to one and only one of these two
-  questions.  Read the drivers/sound/lowlevel/README.aedsp16 file and
-  the head of drivers/sound/lowlevel/aedsp16.c to get more information
-  about this driver and its configuration.  This driver supports Audio
-  Excel DSP 16 but not the III nor PnP versions of this card. Read
-  drivers/sound/lowlevel/README.aedsp16 if you want to know something
-  more on how to use the III version with this sound driver.
+  questions.
+
+  Read the drivers/sound/lowlevel/README.aedsp16 file and the head of
+  drivers/sound/lowlevel/aedsp16.c as well as
+  Documentation/sound/AudioExcelDSP16 to get more information about
+  this driver and its configuration.
 
 SC-6600 based audio cards (new Audio Excel DSP 16)
 CONFIG_SC6600
@@ -8367,8 +8409,9 @@ CONFIG_AEDSP16_MSS
 Audio Excel DSP 16 (SBPro emulation)
 CONFIG_AEDSP16_SBPRO
   Answer Y if you want your audio card to emulate Sound Blaster Pro.
-  You should then say Y to "Sound Blaster (SB, SBPro, SB16, clones)
-  support" and N to "Audio Excel DSP 16 (MSS emulation)".
+  You should then say Y to "100% Sound Blaster compatibles
+  (SB16/32/64, ESS, Jazz16) support" and N to "Audio Excel DSP 16 (MSS
+  emulation)".
 
 Ensoniq ES1370 based PCI sound cards
 CONFIG_SOUND_ES1370
@@ -8404,11 +8447,11 @@ Magic System Request Key support
 CONFIG_MAGIC_SYSRQ
   If you say Y here, you will have some control over the system even
   if the system crashes for example during kernel debugging (e.g., you
-  will be able to flush the disks, reboot the system immediately or
-  dump some status information). This is accomplished by pressing
-  various keys while holding SysRq (Alt+PrintScreen). The keys are
-  documented in Documentation/sysrq.txt. Don't say Y unless you really
-  know what this hack does.
+  will be able to flush the buffer cache to disk, reboot the system
+  immediately or dump some status information). This is accomplished
+  by pressing various keys while holding SysRq (Alt+PrintScreen). The
+  keys are documented in Documentation/sysrq.txt. Don't say Y unless
+  you really know what this hack does.
 
 ISDN subsystem
 CONFIG_ISDN
@@ -8640,8 +8683,8 @@ Support for German tariff info
 CONFIG_DE_AOC
   If you want that the HiSax hardware driver sends messages to the
   upper level of the isdn code on each AOCD (Advice Of Charge, During
-  the call - transmission of the fee information during a call) and on
-  each AOCE (Advice Of Charge, at the End of the call - transmission
+  the call -- transmission of the fee information during a call) and on
+  each AOCE (Advice Of Charge, at the End of the call -- transmission
   of fee information at the end of the call), say Y here. This works
   only in Germany.
 
@@ -8719,9 +8762,9 @@ IBM Active 2000 support (EXPERIMENTAL)
 CONFIG_ISDN_DRV_ACT2000
   Say Y here if you have an IBM Active 2000 ISDN card. In order to use
   this card, additional firmware is necessary, which has to be loaded
-  into the card using a utility which is part of the latest isdn4k-utils
-  package. Please read the file Documentation/isdn/README.act2000 for
-  more information.
+  into the card using a utility which is part of the latest
+  isdn4k-utils package. Please read the file
+  Documentation/isdn/README.act2000 for more information.
 
 Support for AP1000 multicomputer
 CONFIG_AP1000
@@ -8733,9 +8776,9 @@ CONFIG_AP1000
 
 Support for Sun4 architecture
 CONFIG_SUN4
-  Use this option if, and only if, your machine is sun4. Note that
-  kernel compiled with this option will run on sun4 only.
-  (And in current version, it will probably work on sun4/330, only.)
+  Say Y here if, and only if, your machine is a Sun4. Note that
+  a kernel compiled with this option will run only on Sun4.
+  (And the current version will probably work only on sun4/330.)
 
 SPARC ESP SCSI support
 CONFIG_SCSI_SUNESP
@@ -8760,6 +8803,7 @@ CONFIG_SUN_OPENPROMIO
 ###
 ### Please someone fill these in.
 ###
+
 #
 # m68k-specific kernel options
 # Documented by Chris Lawrence <quango@themall.net> et al.
@@ -8844,14 +8888,14 @@ Use read-modify-write instructions
 CONFIG_RMW_INSNS
   This allows to use certain instructions that work with indivisible
   read-modify-write bus cycles. While this is faster than the
-  workaround of disabling interrupts, it can conflict with DMA (=
-  direct memory access) on many Amiga systems, and it is also said to
-  destabilize other machines. It is very likely that this will cause
-  serious problems on any Amiga or Atari Medusa if set. The only
+  workaround of disabling interrupts, it can conflict with DMA 
+  ( = direct memory access) on many Amiga systems, and it is also said
+  to destabilize other machines. It is very likely that this will
+  cause serious problems on any Amiga or Atari Medusa if set. The only
   configuration where it should work are 68030-based Ataris, where it
   apparently improves performance. But you've been warned! Unless you
-  really know what you are doing, say N. Try Y only if you're
-  quite adventurous.
+  really know what you are doing, say N. Try Y only if you're quite
+  adventurous.
 
 Amiga AutoConfig Identification
 CONFIG_ZORRO
@@ -8885,15 +8929,6 @@ CONFIG_AMIFB_AGA
   and CD32.  If you intend to run Linux on any of these systems, say Y;
   otherwise say N.
 
-Amiga Cybervision support
-CONFIG_FB_CYBER
-  This enables support for the Cybervision 64 graphics card from Phase5.
-  Please note that its use is not all that intuitive (i.e. if you have
-  any questions, be sure to ask!).  Say N unless you have a Cybervision
-  64 or plan to get one before you next recompile the kernel.
-  Please note that this driver DOES NOT support the Cybervision 64 3D
-  card at present, as they use incompatible video chips.
-
 Amiga GSP (TMS340x0) support
 CONFIG_AMIGA_GSP
   Include support for Amiga graphics cards that use the Texas
@@ -8915,17 +8950,17 @@ Amiga Zorro II ramdisk support
 CONFIG_AMIGA_Z2RAM
   This enables support for using Chip RAM and Zorro II RAM as a
   ramdisk or as a swap partition.  Say Y if you want to include this
-  driver in the kernel.  This driver is also available as a module ( =
-  code which can be inserted in and removed from the running kernel
-  whenever you want). The module is called z2ram.o. If you want to
-  compile it as a module, say M here and read
+  driver in the kernel.  This driver is also available as a module 
+  ( = code which can be inserted in and removed from the running
+  kernel whenever you want). The module is called z2ram.o. If you want
+  to compile it as a module, say M here and read
   Documentation/modules.txt.
 
 Atari ST-RAM swap support
 CONFIG_STRAM_SWAP
   This enables support for using (parts of) ST-RAM as swap space,
   instead of as normal system memory. This can first enhance system
-  performace if you have lots of alternate RAM (compared to the size
+  performance if you have lots of alternate RAM (compared to the size
   of ST-RAM), because executable code always will reside in faster
   memory. ST-RAM will remain as ultra-fast swap space. On the other
   hand, it allows much improved dynamic allocations of ST-RAM buffers
@@ -9006,12 +9041,13 @@ CONFIG_CYBERSTORM_SCSI
 Cyberstorm II SCSI support
 CONFIG_CYBERSTORMII_SCSI
   If you have an Amiga with a Phase5 Cyberstorm MkII accelerator board
-  and the optional Cyberstorm SCSI controller, say Y.  Otherwise, say N.
+  and the optional Cyberstorm SCSI controller, say Y. Otherwise, say
+  N.
 
 Blizzard 2060 SCSI support
 CONFIG_BLZ2060_SCSI
   If you have an Amiga with a Phase5 Blizzard 2060 accelerator board
-  and want to use the onboard SCSI controller, say Y.  Otherwise, say
+  and want to use the onboard SCSI controller, say Y. Otherwise, say
   N.
 
 Blizzard 1230IV/1260 SCSI support
@@ -9235,17 +9271,6 @@ CONFIG_MSDOS_PARTITION
   Say Y if you need this feature; users who are only using their
   system-native partitioning scheme can say N here.
 
-Board Type
-CONFIG_PMAC
-  There are currently several different kinds of PowerPC-based machines
-  available: Apple Power Macintoshes and clones (such as the Motorola
-  Starmax series, PReP (PowerPC Reference Platform) machines such
-  as the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP and the
-  embedded MBX boards from Motorola.  Currently, a single kernel binary
-  only supports one type or the other.  However, there is very early work
-  on support CHRP, PReP and PowerMac's from a single binary.
-
-
 Processor Type
 CONFIG_6xx
   There are two types of PowerPC chips supported.  The more common
@@ -9253,6 +9278,17 @@ CONFIG_6xx
   Unless you are building a kernel for one of the embedded boards using
   the 821 or 860 choose 6xx.
 
+Machine Type
+CONFIG_PMAC
+  Linux currently supports several different kinds of PowerPC-based
+  machines: Apple Power Macintoshes and clones (such as the
+  Motorola Starmax series), PReP (PowerPC Reference Platform) machines
+  such as the Motorola PowerStack, Amiga Power-Up systems (APUS), CHRP
+  and the embedded MBX boards from Motorola. Currently, a single
+  kernel binary only supports one type or the other. However, there is
+  very early work on support for CHRP, PReP and PowerMac's from a
+  single binary.
+
 Support for Open Firmware device tree in /proc
 CONFIG_PROC_DEVICETREE
   This option adds a device-tree directory under /proc which contains
@@ -9275,10 +9311,10 @@ CONFIG_SCSI_MESH
   Many Power Macintoshes and clones have a MESH (Macintosh Enhanced
   SCSI Hardware) SCSI bus adaptor (the 7200 doesn't, but all of the
   other Power Macintoshes do).  Say Y to include support for this SCSI
-  adaptor.  This driver is also available as a module called mesh.o (
-  = code which can be inserted in and removed from the running kernel
-  whenever you want). If you want to compile it as a module, say M
-  here and read Documentation/modules.txt.
+  adaptor.  This driver is also available as a module called mesh.o
+  ( = code which can be inserted in and removed from the running
+  kernel whenever you want). If you want to compile it as a module,
+  say M here and read Documentation/modules.txt.
 
 Maximum synchronous transfer rate
 CONFIG_SCSI_MESH_SYNC_RATE
@@ -9309,6 +9345,11 @@ CONFIG_MACE
   motherboard will usually use a MACE (Medium Access Control for
   Ethernet) interface.  Say Y to include support for the MACE chip.
 
+BMAC (G3 ethernet) support
+CONFIG_BMAC
+  Say Y for support of BMAC Ethernet interfaces. These are used on G3
+  computers. 
+
 Video For Linux
 CONFIG_VIDEO_DEV
   Support for audio/video capture and overlay devices and FM radio
@@ -9316,6 +9357,10 @@ CONFIG_VIDEO_DEV
   this are available from
   ftp://ftp.uk.linux.org/pub/linux/video4linux.
 
+  If you are interested in writing a driver for such an audio/video
+  device or user software interacting with such a driver, please read
+  the file Documentation/video4linux/API.html.
+
   This driver is also available as a module called videodev.o ( = code
   which can be inserted in and removed from the running kernel
   whenever you want). If you want to compile it as a module, say M
@@ -9326,16 +9371,17 @@ CONFIG_RADIO_RTRACK
   Choose Y here if you have one of these FM radio cards, and then fill
   in the port address below.
 
-  Note that newer AIMSlab RadioTrack cards have a different chipset,
-  not supported by this driver.  For these cards, use the RadioTrack II
-  driver below.  
+  Note that newer AIMSlab RadioTrack cards have a different chipset
+  and are not supported by this driver. For these cards, use the
+  RadioTrack II driver below.
 
   In order to control your radio card, you will need to use programs
   that are compatible with the Video for Linux API.  Information on 
   this API and pointers to "v4l" programs may be found on the WWW at
   http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
   you need to have access to a machine on the Internet that has a 
-  program like lynx or netscape.
+  program like lynx or netscape. More information is contained in the
+  file Documentation/video4linux/radiotrack.txt.
 
   If you want to compile this driver as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want),
@@ -9434,10 +9480,28 @@ ZOLTRIX I/O port (0x20c or 0x30c)
 CONFIG_RADIO_ZOLTRIX_PORT
   Enter the I/O port of your Zoltrix radio card.
 
+Miro PCM20 Radio
+CONFIG_RADIO_MIROPCM20
+  Choose Y here if you have one of these FM radio cards, and then fill
+  in the port address below.
+
+  In order to control your radio card, you will need to use programs
+  that are compatible with the Video for Linux API.  Information on 
+  this API and pointers to "v4l" programs may be found on the WWW at
+  http://roadrunner.swansea.uk.linux.org/v4l.shtml; to browse the WWW,
+  you need to have access to a machine on the Internet that has a 
+  program like lynx or netscape.
+
+  If you want to compile this driver as a module ( = code which can be
+  inserted in and removed from the running kernel whenever you want),
+  say M here and read Documentation/modules.txt. The module will be
+  called radio-miropcm20.o
+
 BT848 Video For Linux
 CONFIG_VIDEO_BT848
   Support for BT848 based frame grabber/overlay boards. This includes
-  the Miro, Hauppauge and STB boards. 
+  the Miro, Hauppauge and STB boards. Please read the material in
+  Documentation/video4linux/bttv for more information.
 
   This driver is also available as a module called bttv.o ( = code
   which can be inserted in and removed from the running kernel
@@ -9497,13 +9561,15 @@ CONFIG_ARCH_ARC
 
 Build Tools Selection
 CONFIG_BINUTILS_NEW
-  Say Y here if you're using GCC 2.8.1/EGCS with a binutils 
-  version >= 2.8.1 to compile the kernel. Otherwise, say N.
+  Say Y here if and only if you're using GCC 2.8.1/EGCS with a
+  binutils version >= 2.8.1 to compile the kernel (check with "gcc
+  --version" and "ld -v").
 
 Compile kernel with frame pointer
 CONFIG_FRAME_POINTER
-  In order to give useful debugging/error results, say Y here, otherwise
-  say N.
+  If you say Y here, the resulting kernel will be slightly larger, but
+  it will give useful debugging/error results. If you don't debug the
+  kernel, you can say N.
 
 VIDC Sound
 CONFIG_VIDC_SOUND
@@ -9515,7 +9581,7 @@ CONFIG_VIDC_SOUND
 #   capitalize: AppleTalk, Ethernet, DMA, FTP, Internet, Intel, IRQ, 
 #               Linux, NetWare, NFS, PCI, SCSI, SPARC
 #   two words:  hard drive, hard disk, sound card, home page
-#   other:      it's safe to save; daemon
+#   other:      it's safe to save; daemon; use --, not - or ---
 #
 # This is used by Emacs' spell checker ispell.el:
 #
@@ -9605,7 +9671,7 @@ CONFIG_VIDC_SOUND
 # LocalWords:  YAMADA tetsu cauchy nslab ntt nevod perm su doc kaf kheops wsc
 # LocalWords:  traduc Bourgin dbourgin menuconfig kfill READMEs HOWTOs Virge WA
 # LocalWords:  IDEDISK IDEFLOPPY EIDE firewalls QMAGIC ZMAGIC LocalWords opti
-# LocalWords:  SVGATextMode vga svga Xterminal Xkernel syr jmwobus comfaqs dhcp
+# LocalWords:  SVGATextMode vga svga Xkernel syr jmwobus comfaqs dhcp flakey GD
 # LocalWords:  IPv IPng interoperability ipng ipv radio's tapr pkthome PLP nano
 # LocalWords:  Ses Mhz sethdlc SOUNDMODEM WindowsSoundSystem smdiag pcf inka ES
 # LocalWords:  smmixer ptt circ soundmodem MKISS FDDI DEFEA DEFPA DEFXX redhat
@@ -9646,7 +9712,7 @@ CONFIG_VIDC_SOUND
 # LocalWords:  hardlinked NAMETRANS env mtab fstab umount nologin runlevel gid
 # LocalWords:  transname filespace adm Nodename hostname uname Kernelname bootp
 # LocalWords:  KERNNAME kname ktype kernelname Kerneltype KERNTYPE Alt RX mdafb
-# LocalWords:  dataless kerneltype SYSNAME Comtrol Rocketport palmtop
+# LocalWords:  dataless kerneltype SYSNAME Comtrol Rocketport palmtop fbset EGS
 # LocalWords:  nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
 # LocalWords:  HFMODEM shortwave Sitor Amtor Pactor GTOR hfmodem hayes TX TMOUT
 # LocalWords:  IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
@@ -9693,10 +9759,16 @@ CONFIG_VIDC_SOUND
 # LocalWords:  AcornSCSI EcoSCSI EESOX EESOXSCSI Powertec POWERTECSCSI dec SF
 # LocalWords:  RadioReveal gatekeeper aimslab aztech FMI sf fmi RTL rtl cesdis
 # LocalWords:  Yellowfin gsfc nasa gov yellowfin pcnet Mylex LNE lne EtherH hs
-# LocalWords:  EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson
+# LocalWords:  EBSA chattr RiscOS Winmodem AGP Atomwide DUALSP pcsp robinson CT
 # LocalWords:  SGALAXY Waverider DSPxxx TRXPRO AudioTrix OSWF MOT CFB DSY kbps
 # LocalWords:  tuwien kkudielk LVD mega lun MAXTAGS Gbps arcnet Olicom SKTR SNA
-# LocalWords:  SysKonnect sktr sna etherboot ufs NetBEUI MultiSound MSNDCLAS
-# LocalWords:  MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's
-# LocalWords:  AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner
+# LocalWords:  SysKonnect sktr sna etherboot ufs NetBEUI MultiSound MSNDCLAS GX
+# LocalWords:  MSNDINIT MSNDPERM MSNDPIN PNDSPINI PNDSPERM Ensoniq's RetinaZ SS
+# LocalWords:  AudioPCI lspci SonicVibes sonicvibes SPARCs roadrunner CLgen UPA
 # LocalWords:  swansea shtml Zoltrix zoltrix BINUTILS EGCS binutils VIDC DACs
+# LocalWords:  CyberVision Cirrus PowerBooks Topcat SBUS CGsix TurboGX BWtwo SS
+# LocalWords:  CGthree TCX unswapable vfb fbcon hicolor truecolor AFB ILBM SOC
+# LocalWords:  IPLAN gracilis Fibre SBus SparcSTORAGE SV jnewbigin swin QNX qnx
+# LocalWords:  PTY PTYS ptyxx ttyxx PTYs ssh sb Avance ALS pss
+# LocalWords:  synth WaveFront MSND NONPNP AudioExcelDSP STRAM APUS CHRP MBX
+# LocalWords:  PowerMac's BMAC radiotrack rtrack miropcm
index ce623ed5cb8a4fcfc30bceda9e1880fa8e6550fe..ffebd188e9bee0da132459721a560a5347d6aabb 100644 (file)
@@ -10,8 +10,8 @@
 Because so many people (myself included) seem to have obtained ARCnet cards
 without manuals, this file contains a quick introduction to ARCnet hardware,
 some cabling tips, and a listing of all jumper settings I can find. Please
-e-mail apenwarr@bond.net with any settings for your particular card, or any
-other information you have!
+e-mail apenwarr@worldvisions.ca with any settings for your particular card,
+or any other information you have!
 
 
 INTRODUCTION TO ARCNET
@@ -80,7 +80,7 @@ CABLING ARCNET NETWORKS
 This section was rewritten by 
         Vojtech Pavlik     <Vojtech.Pavlik@st.mff.cuni.cz>
 using information from several people, including:
-        Avery Pennraun     <apenwarr@bond.net>
+        Avery Pennraun     <apenwarr@worldvisions.ca>
        Stephen A. Wood    <saw@hallc1.cebaf.gov>
        John Paul Morrison <jmorriso@bogomips.ee.ubc.ca>
        Joachim Koenig     <jojo@repas.de>
@@ -438,8 +438,8 @@ Unclassified Stuff
 PC100, PC110, PC120, PC130 (8-bit cards)
 PC500, PC600 (16-bit cards)
 ---------------------------------
-  - mainly from Avery Pennarun <apenwarr@foxnet.net>.  Values depicted are
-    from Avery's setup.
+  - mainly from Avery Pennarun <apenwarr@worldvisions.ca>.  Values depicted
+    are from Avery's setup.
   - special thanks to Timo Hilbrink <timoh@xs4all.nl> for noting that PC120,
     130, 500, and 600 all have the same switches as Avery's PC100. 
     PC500/600 have several extra, undocumented pins though. (?)
@@ -3129,6 +3129,6 @@ Other Cards
 
 I have no information on other models of ARCnet cards at the moment.  Please
 send any and all info to:
-       apenwarr@bond.net
+       apenwarr@worldvisions.ca
 
 Thanks.
index 17f40fb5332cf9d5e8469da10dce1d46c6f9e16b..3bb2f6d961937207b206554590316b416d1949ee 100644 (file)
@@ -37,7 +37,7 @@ If you think so, why not flame me in a quick little e-mail?  Please also
 include the type of card(s) you're using, software, size of network, and
 whether it's working or not.)
 
-My e-mail address is: apenwarr@bond.net
+My e-mail address is: apenwarr@worldvisions.ca
 
 
 ---------------------------------------------------------------------------
@@ -79,9 +79,8 @@ may not work right in the first place.
 Other Drivers and Info
 ----------------------
 
-You can (could - foxnet.net is no more - DW.) try my ARCNET page on the 
-World Wide Web at:
-       http://www.foxnet.net/~apenwarr/arcnet/
+You can try my ARCNET page on the World Wide Web at:
+       http://www.worldvisions.ca/~apenwarr/arcnet/
 
 Also, SMC (one of the companies that makes ARCnet cards) has a WWW site you
 might be interested in, which includes several drivers for various cards
@@ -494,7 +493,7 @@ It works: what now?
 Send mail describing your setup, preferably including driver version, kernel
 version, ARCnet card model, CPU type, number of systems on your network, and
 list of software in use to me at the following address:
-       apenwarr@bond.net
+       apenwarr@worldvisions.ca
 
 I do send (sometimes automated) replies to all messages I receive.  My email
 can be weird (and also usually gets forwarded all over the place along the
index 78561b9f4fffbf03b3cb88755590f5855c3b70ec..839db8eceb5bc0c5a37cb8a17773a741c3b28636 100644 (file)
@@ -612,7 +612,7 @@ software-update notification.
 6.3.1 CRYSTAL'S WEB SITE
 
 Crystal Semiconductor maintains a web page at http://www.crystal.com with the
-the latest drivers and technical publications.
+latest drivers and technical publications.
 
 
 6.3.2 CRYSTAL'S BULLETIN BOARD SERVICE
index a25f465b71a3bc6524b63830fb19cbde4b1e0808..bd329565214e542c3d9b63ccab6e906e32ea5977 100644 (file)
@@ -1,3 +1,66 @@
+1998-09-10  Andrew Veliath  <andrewtv@usa.net>
+
+       * Update version to 0.8.2
+
+       * Add SNDCTL_DSP_GETOSPACE and SNDCTL_DSP_GETISPACE ioctls.
+
+1998-09-09  Andrew Veliath  <andrewtv@usa.net>
+
+       * Update version to 0.8.1
+       
+       * msnd_pinnacle.c: Fix resetting of default audio parameters. Turn
+       flush code from dsp_halt into dsp_write_flush, and use that for
+       SNDCTL_DSP_SYNC.
+
+1998-09-07  Andrew Veliath  <andrewtv@usa.net>
+
+       * Update version to 0.8.0
+
+       * Provide separate signal parameters for play and record.
+       
+       * Cleanups to locking and interrupt handling, change default
+       fifosize to 128kB.
+
+       * Update version to 0.7.15
+
+       * Interprocess full-duplex support (ie `cat /dev/dsp > /dev/dsp').
+
+       * More mutex sections for read and write fifos (read + write locks
+       added).
+
+1998-09-05  Andrew Veliath  <andrewtv@usa.net>
+
+       * msnd_pinnacle.c: (chk_send_dsp_cmd) Do full DSP reset upon DSP
+       timeout (when not in interrupt; maintains mixer settings).  Fixes
+       to flushing and IRQ ref counting. Rewrote queuing for smoother
+       playback and fixed initial playback cutoff problem.
+
+1998-09-03  Andrew Veliath  <andrewtv@usa.net>
+
+       * Replaced packed structure accesses with standard C equivalents.
+
+1998-09-01  Andrew Veliath  <andrewtv@usa.net>
+
+       * msnd_pinnacle.c: Add non-PnP configuration to driver code, which
+         will facilitate compiled-in operation.
+
+1998-08-29  Andrew Veliath  <andrewtv@usa.net>
+
+       * Update version to 0.7.6
+       
+       * msnd_pinnacle.c (dsp_ioctl): Add DSP_GETFMTS, change SAMPLESIZE
+         to DSP_SETFMT.
+
+       * Update version to 0.7.5
+       
+       * Create pinnaclecfg.c and turn MultiSound doc into a shell
+         archive with pinnaclecfg.c included.  pinnaclecfg.c can
+         now fully configure the card in non-PnP mode, including the
+         joystick and IDE controller.  Also add an isapnp conf
+         example.
+
+       * Reduce DSP reset timeout from 20000 to 100
+
 1998-08-06  Andrew Veliath  <andrewtv@usa.net>
 
        * Update version to 0.7.2
index aadbfd23ff434eac1568316d96c00d6371f492d6..58cd7f14fe30879c56469e4029d45a0e53da336c 100644 (file)
@@ -3,15 +3,15 @@
 
                     Paul Barton-Davis, July 1998
 
-                         VERSION 0.2.4
+                         VERSION 0.2.5
 
 Driver Status
 -------------
 
-Requires: Kernel 2.1.106 or later (a version of the driver is included
-with kernels 2.1.109 and above)
+Requires: Kernel 2.1.106 or later (the driver is included with kernels
+2.1.109 and above)
          
-As of 7/20/1998, this driver is currently in *BETA* state. This means
+As of 7/22/1998, this driver is currently in *BETA* state. This means
 that it compiles and runs, and that I use it on my system (Linux
 2.1.106) with some reasonably demanding applications and uses.  I
 believe the code is approaching an initial "finished" state that
index 322063663e679e8bb10a90bc622ef2c90201a2ef..b14429d6bb6968612dbe58cd8f07fad929f7d19b 100644 (file)
@@ -292,6 +292,12 @@ L: linux-kernel@vger.rutgers.edu
 W:     http://www.nyx.net/~arobinso
 S:     Maintainted
 
+HFS FILESYSTEM
+P:      Adrian Sun
+M:      asun@u.washington.edu
+L:      linux-kernel@vger.rutgers.edu
+S:      Maintained
+
 HIGH-SPEED SCC DRIVER FOR AX.25
 P:     Klaus Kudielka
 M:     oe1kib@oe1kib.ampr.org
@@ -593,12 +599,6 @@ M: Jay.Schulist@spacs.k12.wi.us
 L:     linux-net@vger.rutgers.edu
 S:     Supported
 
-SPX NETWORK LAYER
-P:     Jay Schulist
-M:     Jay.Schulist@spacs.k12.wi.us
-L:     linux-net@vger.rutgers.edu
-S:     Supported
-
 STALLION TECHNOLOGIES MULTIPORT SERIAL BOARDS
 P:     Greg Ungerer
 M:     support@stallion.oz.au
index a8e2f8761112d4bceda2f0a73243deb843a072e1..eea674aa68ef96417afbcd43048918888af157e3 100644 (file)
@@ -253,9 +253,11 @@ asmlinkage unsigned long osf_mmap(unsigned long addr, unsigned long len,
        unsigned long ret = -EBADF;
 
        lock_kernel();
+#if 0
        if (flags & (_MAP_HASSEMAPHORE | _MAP_INHERIT | _MAP_UNALIGNED))
                printk("%s: unimplemented OSF mmap flags %04lx\n", 
                        current->comm, flags);
+#endif
        if (!(flags & MAP_ANONYMOUS)) {
                file = fget(fd);
                if (!file)
index 65b26ffc4930879f7f2754c08e961fcc501e1133..d2be68e5761e42950cdcb64be8e2f346a8fe338f 100644 (file)
@@ -78,9 +78,6 @@
 #include <linux/config.h>
 #include <linux/module.h>
 
-#include <asm/system.h>
-#include <asm/uaccess.h>
-
 #include <linux/poll.h>
 #include <linux/types.h>
 #include <linux/stddef.h>
@@ -96,7 +93,9 @@
 #include <linux/apm_bios.h>
 #include <linux/init.h>
 
-#include "desc.h"
+#include <asm/system.h>
+#include <asm/uaccess.h>
+#include <asm/desc.h>
 
 EXPORT_SYMBOL(apm_register_callback);
 EXPORT_SYMBOL(apm_unregister_callback);
diff --git a/arch/i386/kernel/desc.h b/arch/i386/kernel/desc.h
deleted file mode 100644 (file)
index e91580e..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-#ifndef __ARCH_DESC_H
-#define __ARCH_DESC_H
-
-struct desc_struct {
-       unsigned long a,b;
-};
-
-extern struct desc_struct gdt_table[];
-extern struct desc_struct *idt, *gdt;
-
-struct Xgt_desc_struct {
-       unsigned short size;
-       unsigned long address __attribute__((packed));
-};
-
-#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
-#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
-
-/*
- * Entry into gdt where to find first TSS. GDT layout:
- *   0 - null
- *   1 - not used
- *   2 - kernel code segment
- *   3 - kernel data segment
- *   4 - user code segment
- *   5 - user data segment
- *   6 - not used
- *   7 - not used
- *   8 - APM BIOS support
- *   9 - APM BIOS support
- *  10 - APM BIOS support
- *  11 - APM BIOS support
- *  12 - TSS #0
- *  13 - LDT #0
- *  14 - TSS #1
- *  15 - LDT #1
- */
-#define FIRST_TSS_ENTRY 12
-#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
-#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
-#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
-#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
-#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
-#define store_TR(n) \
-__asm__("str %%ax\n\t" \
-       "subl %2,%%eax\n\t" \
-       "shrl $4,%%eax" \
-       :"=a" (n) \
-       :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
-
-extern void set_intr_gate(unsigned int irq, void * addr);
-extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
-extern void set_tss_desc(unsigned int n, void *addr);
-
-/*
- * This is the ldt that every process will get unless we need
- * something other than this.
- */
-extern struct desc_struct default_ldt;
-
-#endif
index 4381719ae8e16152cc7197b49be14ca6c445cbb8..d3b395732c541c6d5aee03cbd8c83e1f374d04bd 100644 (file)
@@ -3,8 +3,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/pgtable.h>
-
-#include "desc.h"
+#include <asm/desc.h>
 
 static struct vm_area_struct init_mmap = INIT_MMAP;
 static struct fs_struct init_fs = INIT_FS;
index e2e107c9e84ecb8bc1fd5ff421ac7e57d69e778c..1c61c8841a52d8e9ba5f1600286524dcee5c3f1a 100644 (file)
@@ -1224,7 +1224,27 @@ void __init setup_IO_APIC(void)
        setup_IO_APIC_irqs();
        init_IRQ_SMP();
        check_timer();
+
+       /*
+        * Get rid of any pending interrupt sources by just blindly
+        * ACK'ing the IO-APIC. There is apparently no other way to
+        * remove stale bits in the ISR.
+        *
+        * I'd love to be proven wrong, please tell me how to clear
+        * the ISR bit for specific interrupts..
+        *
+        * Oh, how do we clear the IRR bit? I'd like to be able to
+        * make sure that we get one interrupt for something that 
+        * is pending when we enable it, even if it is edge-triggered.
+        * How to fool the IO-APIC to think it got an edge when
+        * enabled?
+        */
+       {
+               int i = 10;
+               do {
+                       ack_APIC_irq();
+               } while (--i);
+       }
+
        print_IO_APIC();
 }
-
index e5bc7e8d21e6658e974ae7744406bedfc23b2fff..2ec0dffc959c0edbad3df3b1f45ffc8574c93ee4 100644 (file)
@@ -37,9 +37,9 @@
 #include <asm/smp.h>
 #include <asm/pgtable.h>
 #include <asm/delay.h>
+#include <asm/desc.h>
 
 #include "irq.h"
-#include "desc.h"
 
 unsigned int local_bh_count[NR_CPUS];
 unsigned int local_irq_count[NR_CPUS];
@@ -683,7 +683,8 @@ void disable_irq(unsigned int irq)
        irq_desc[irq].handler->disable(irq);
        spin_unlock_irqrestore(&irq_controller_lock, flags);
 
-       synchronize_irq();
+       if (irq_desc[irq].status & IRQ_INPROGRESS)
+               synchronize_irq();
 }
 
 void enable_irq(unsigned int irq)
@@ -886,7 +887,7 @@ unsigned long probe_irq_on(void)
        for (i = NR_IRQS-1; i > 0; i--) {
                if (!irq_desc[i].action) {
                        unsigned int status = irq_desc[i].status | IRQ_AUTODETECT;
-                       irq_desc[i].status = status & ~(IRQ_INPROGRESS | IRQ_PENDING);
+                       irq_desc[i].status = status & ~IRQ_INPROGRESS;
                        irq_desc[i].handler->enable(i);
                }
        }
index 4f41b8a330cdf4ed04c784d5af91fcf124476c06..25e8deec44e867023cbd875735317238a2eaa60d 100644 (file)
@@ -15,8 +15,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <asm/ldt.h>
-
-#include "desc.h"
+#include <asm/desc.h>
 
 static int read_ldt(void * ptr, unsigned long bytecount)
 {
index bd6113cbb46b161327ad2f7818e2fdc834fb726c..039a9e5590858a157b3c88366c41e73c72b3a426 100644 (file)
 #include <asm/io.h>
 #include <asm/ldt.h>
 #include <asm/processor.h>
+#include <asm/desc.h>
 #ifdef CONFIG_MATH_EMULATION
 #include <asm/math_emu.h>
 #endif
 
 #include "irq.h"
-#include "desc.h"
 
 spinlock_t semaphore_wake_lock = SPIN_LOCK_UNLOCKED;
 
index dfa3b9848a6497a092cde3c9b89d4afe19a87809..8968b334e1f76dd9d1641a5161df45885120b137 100644 (file)
@@ -507,10 +507,10 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        else
                                child->flags &= ~PF_TRACESYS;
                        child->exit_code = data;
-                       wake_up_process(child);
        /* make sure the single step bit is not set. */
                        tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
                        put_stack_long(child, EFL_OFFSET,tmp);
+                       wake_up_process(child);
                        ret = 0;
                        goto out;
                }
@@ -526,11 +526,11 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        ret = 0;
                        if (child->state == TASK_ZOMBIE)        /* already dead */
                                goto out;
-                       wake_up_process(child);
                        child->exit_code = SIGKILL;
        /* make sure the single step bit is not set. */
                        tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
                        put_stack_long(child, EFL_OFFSET, tmp);
+                       wake_up_process(child);
                        goto out;
                }
 
@@ -543,9 +543,9 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        child->flags &= ~PF_TRACESYS;
                        tmp = get_stack_long(child, EFL_OFFSET) | TRAP_FLAG;
                        put_stack_long(child, EFL_OFFSET, tmp);
-                       wake_up_process(child);
                        child->exit_code = data;
        /* give it a chance to run. */
+                       wake_up_process(child);
                        ret = 0;
                        goto out;
                }
@@ -558,16 +558,16 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                        if ((unsigned long) data > _NSIG)
                                goto out;
                        child->flags &= ~(PF_PTRACED|PF_TRACESYS);
-                       wake_up_process(child);
                        child->exit_code = data;
                        write_lock_irqsave(&tasklist_lock, flags);
                        REMOVE_LINKS(child);
                        child->p_pptr = child->p_opptr;
                        SET_LINKS(child);
                        write_unlock_irqrestore(&tasklist_lock, flags);
-                       /* make sure the single step bit is not set. */
+       /* make sure the single step bit is not set. */
                        tmp = get_stack_long(child, EFL_OFFSET) & ~TRAP_FLAG;
                        put_stack_long(child, EFL_OFFSET, tmp);
+                       wake_up_process(child);
                        ret = 0;
                        goto out;
                }
index 498820ec8caa127a5bc9926389cb2395b75ec506..7db4f3fb3bf835f4b94a663529ad4044bc80cce4 100644 (file)
@@ -493,6 +493,7 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
                        switch (edx) {
                                case 0x40:
                                        cache_size = 0;
+                                       break;
 
                                case 0x41:
                                        cache_size = 128;
@@ -532,7 +533,7 @@ __initfunc(void identify_cpu(struct cpuinfo_x86 *c))
                            && (cpu_models[i].x86 == 6) 
                            && (c->x86_model == 5)
                            && (c->x86_cache_size == 0)) {
-                               p = "Celeron";
+                               p = "Celeron (Covington)";
                        }
                }
                        
index 6d60aeb40be9db5e05c35d022977234b21ca241d..d919ba06dcf420b91da3c57bd738532af7d91274 100644 (file)
@@ -27,8 +27,7 @@
 #include <asm/spinlock.h>
 #include <asm/atomic.h>
 #include <asm/debugreg.h>
-
-#include "desc.h"
+#include <asm/desc.h>
 
 asmlinkage int system_call(void);
 asmlinkage void lcall7(void);
@@ -205,6 +204,14 @@ static void die_if_no_fixup(const char * str, struct pt_regs * regs, long err)
                unsigned long fixup;
                fixup = search_exception_table(regs->eip);
                if (fixup) {
+                       /*
+                        * The GP fault might have been due to
+                        * bad segments, so clean up the ones
+                        * we care about here..
+                        */
+                       regs->xds = __KERNEL_DS;
+                       regs->xes = __KERNEL_DS;
+                       regs->xss = __KERNEL_DS;
                        regs->eip = fixup;
                        return;
                }
index 9be6cc0fcaaa3472cf9790af2cf8d853e14941ca..1c5d30e1db394dac9b1aed518a3069228e6b5fbb 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/signal.h>
 
 #include <asm/uaccess.h>
+#include <asm/desc.h>
 
 #include "fpu_system.h"
 #include "fpu_emu.h"
index 1e7009a23158f42ad5aa37d8763d56d326e4a054..6462f0fa2415202de60539f75d268a5fb70db355 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/stddef.h>
 
 #include <asm/uaccess.h>
+#include <asm/desc.h>
 
 #include "fpu_system.h"
 #include "exception.h"
index fa943cc48048297bf79820916c8cac86eea90c34..82bfb047495210c993160e4f1cdffe3cedd3cfc2 100644 (file)
@@ -87,10 +87,10 @@ else
 endif
 
 ifeq ($(CONFIG_BLK_DEV_LOOP),y)
-L_OBJS += loop.o
+LX_OBJS += loop.o
 else
   ifeq ($(CONFIG_BLK_DEV_LOOP),m)
-  M_OBJS += loop.o
+  MX_OBJS += loop.o
   endif
 endif
 
index 7425bf25131c01124d209dcea55ef3e2bf583040..6ba340cb326c5c7e51a555a864fdbe2e17cf275d 100644 (file)
@@ -4115,7 +4115,9 @@ __initfunc(int floppy_init(void))
        for (drive = 0; drive < N_DRIVE; drive++) {
                CLEARSTRUCT(UDRS);
                CLEARSTRUCT(UDRWE);
-               UDRS->flags = FD_VERIFY | FD_DISK_NEWCHANGE | FD_DISK_CHANGED;
+               USETF(FD_DISK_NEWCHANGE);
+               USETF(FD_DISK_CHANGED);
+               USETF(FD_VERIFY);
                UDRS->fd_device = -1;
                floppy_track_buffer = NULL;
                max_buffer_sectors = 0;
index 5a936899fd1d9fc023b31ad14563539f2541954d..196f6dc4ca6d59e8b747c4579fa4995f03d5f0a0 100644 (file)
  * Fixed do_loop_request() re-entrancy - Vincent.Renardias@waw.com Mar 20, 1997
  *
  * Handle sparse backing files correctly - Kenn Humborg, Jun 28, 1998
+ *
+ * Loadable modules and other fixes by AK, 1998
+ * 
+ * Still To Fix:
+ * - Advisory locking is ignored here. 
+ * - Should use an own CAP_* category instead of CAP_SYS_ADMIN 
  */
 
 #include <linux/module.h>
 #include <linux/stat.h>
 #include <linux/errno.h>
 #include <linux/major.h>
+
 #include <linux/init.h>
 
 #include <asm/uaccess.h>
 
-#ifdef CONFIG_BLK_DEV_LOOP_DES
-# /*nodep*/ include <linux/des.h>
-#endif
-
-#ifdef CONFIG_BLK_DEV_LOOP_IDEA
-# /*nodep*/ include <linux/idea.h>
-#endif
-
-#include <linux/loop.h>                /* must follow des.h */
+#include <linux/loop.h>                
 
 #define MAJOR_NR LOOP_MAJOR
 
@@ -63,7 +62,6 @@ static int loop_blksizes[MAX_LOOP];
    backing file (can happen if the backing file is sparse) */
 static int create_missing_block(struct loop_device *lo, int block, int blksize);
 
-
 /*
  * Transfer functions
  */
@@ -97,80 +95,38 @@ static int transfer_xor(struct loop_device *lo, int cmd, char *raw_buf,
        return 0;
 }
 
-#ifdef DES_AVAILABLE
-static int transfer_des(struct loop_device *lo, int cmd, char *raw_buf,
-                 char *loop_buf, int size)
+static int none_status(struct loop_device *lo, struct loop_info *info)
 {
-       unsigned long tmp[2];
-       unsigned long x0,x1,p0,p1;
+       return 0; 
+} 
 
-       if (size & 7)
+static int xor_status(struct loop_device *lo, struct loop_info *info)
+{
+       if (info->lo_encrypt_key_size < 0)
                return -EINVAL;
-       x0 = lo->lo_des_init[0];
-       x1 = lo->lo_des_init[1];
-       while (size) {
-               if (cmd == READ) {
-                       tmp[0] = (p0 = ((unsigned long *) raw_buf)[0])^x0;
-                       tmp[1] = (p1 = ((unsigned long *) raw_buf)[1])^x1;
-                       des_ecb_encrypt((des_cblock *) tmp,(des_cblock *)
-                           loop_buf,lo->lo_des_key,DES_ENCRYPT);
-                       x0 = p0^((unsigned long *) loop_buf)[0];
-                       x1 = p1^((unsigned long *) loop_buf)[1];
-               }
-               else {
-                       p0 = ((unsigned long *) loop_buf)[0];
-                       p1 = ((unsigned long *) loop_buf)[1];
-                       des_ecb_encrypt((des_cblock *) loop_buf,(des_cblock *)
-                           raw_buf,lo->lo_des_key,DES_DECRYPT);
-                       ((unsigned long *) raw_buf)[0] ^= x0;
-                       ((unsigned long *) raw_buf)[1] ^= x1;
-                       x0 = p0^((unsigned long *) raw_buf)[0];
-                       x1 = p1^((unsigned long *) raw_buf)[1];
-               }
-               size -= 8;
-               raw_buf += 8;
-               loop_buf += 8;
-       }
        return 0;
 }
-#endif
-
-#ifdef IDEA_AVAILABLE
 
-extern void idea_encrypt_block(idea_key,char *,char *,int);
-
-static int transfer_idea(struct loop_device *lo, int cmd, char *raw_buf,
-                 char *loop_buf, int size)
-{
-  if (cmd==READ) {
-    idea_encrypt_block(lo->lo_idea_en_key,raw_buf,loop_buf,size);
-  }
-  else {
-    idea_encrypt_block(lo->lo_idea_de_key,loop_buf,raw_buf,size);
-  }
-  return 0;
-}
-#endif
-
-static transfer_proc_t xfer_funcs[MAX_LOOP] = {
-       transfer_none,          /* LO_CRYPT_NONE */
-       transfer_xor,           /* LO_CRYPT_XOR */
-#ifdef DES_AVAILABLE
-       transfer_des,           /* LO_CRYPT_DES */
-#else
-       NULL,                   /* LO_CRYPT_DES */
-#endif
-#ifdef IDEA_AVAILABLE           /* LO_CRYPT_IDEA */
-       transfer_idea
-#else
-       NULL
-#endif
+struct loop_func_table none_funcs = { 
+       number: LO_CRYPT_NONE,
+       transfer: transfer_none,
+       init: none_status
+};     
+
+struct loop_func_table xor_funcs = { 
+       number: LO_CRYPT_XOR,
+       transfer: transfer_xor,
+       init: xor_status
+};     
+
+/* xfer_funcs[0] is special - its release function is never called */ 
+struct loop_func_table *xfer_funcs[MAX_LO_CRYPT] = {
+       &none_funcs,
+       &xor_funcs  
 };
 
-
 #define MAX_DISK_SIZE 1024*1024*1024
 
-
 static void figure_loop_size(struct loop_device *lo)
 {
        int     size;
@@ -326,6 +282,7 @@ static int create_missing_block(struct loop_device *lo, int block, int blksize)
        char            zero_buf[1] = { 0 };
        ssize_t         retval;
        mm_segment_t    old_fs;
+       struct inode    *inode;
 
        file = lo->lo_backing_file;
        if (file == NULL) {
@@ -349,16 +306,19 @@ static int create_missing_block(struct loop_device *lo, int block, int blksize)
                file->f_version = ++event;
        }
 
-       if (file->f_op->write == NULL) {
-               printk(KERN_WARNING "loop: cannot create block - no write file op\n");
+       if ((file->f_mode & FMODE_WRITE) == 0 ||  file->f_op->write == NULL) {
+               printk(KERN_WARNING "loop: cannot create block - file not writeable\n");
                return FALSE;
        }
 
        old_fs = get_fs();
        set_fs(get_ds());
 
+       inode = file->f_dentry->d_inode;
+       down(&inode->i_sem); 
        retval = file->f_op->write(file, zero_buf, 1, &file->f_pos);
-
+       up(&inode->i_sem);
+       
        set_fs(old_fs);
 
        if (retval < 0) {
@@ -447,6 +407,7 @@ static int loop_set_fd(struct loop_device *lo, kdev_t dev, unsigned int arg)
        lo->lo_dentry = file->f_dentry;
        lo->lo_dentry->d_count++;
        lo->transfer = NULL;
+       lo->ioctl = NULL;
        figure_loop_size(lo);
 
 out_putf:
@@ -457,6 +418,19 @@ out:
        return error;
 }
 
+static int loop_release_xfer(struct loop_device *lo)
+{
+       int err = 0; 
+       if (lo->lo_encrypt_type) {
+               if (xfer_funcs[lo->lo_encrypt_type] && 
+                   xfer_funcs[lo->lo_encrypt_type]->release) { 
+                       err = xfer_funcs[lo->lo_encrypt_type]->release(lo);
+               }
+               lo->lo_encrypt_type = 0;
+       }
+       return err;
+}
+
 static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
 {
        struct dentry *dentry = lo->lo_dentry;
@@ -477,6 +451,8 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
                dput(dentry);
        }
 
+       lo->transfer = NULL;
+       lo->ioctl = NULL;
        lo->lo_device = 0;
        lo->lo_encrypt_type = 0;
        lo->lo_offset = 0;
@@ -491,60 +467,44 @@ static int loop_clr_fd(struct loop_device *lo, kdev_t dev)
 
 static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
 {
-       struct loop_info info;
+       struct loop_info info; 
        int err;
+       unsigned int type;
 
+       if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && 
+           !capable(CAP_SYS_ADMIN))
+               return -EPERM;
        if (!lo->lo_dentry)
                return -ENXIO;
-       if (!arg)
-               return -EINVAL;
-       err = verify_area(VERIFY_READ, arg, sizeof(info));
-       if (err)
-               return err;
-       copy_from_user(&info, arg, sizeof(info));
+       if (copy_from_user(&info, arg, sizeof (struct loop_info)))
+               return -EFAULT; 
        if ((unsigned int) info.lo_encrypt_key_size > LO_KEY_SIZE)
                return -EINVAL;
-       switch (info.lo_encrypt_type) {
-       case LO_CRYPT_NONE:
-               break;
-       case LO_CRYPT_XOR:
-               if (info.lo_encrypt_key_size < 0)
-                       return -EINVAL;
-               break;
-#ifdef DES_AVAILABLE
-       case LO_CRYPT_DES:
-               if (info.lo_encrypt_key_size != 8)
-                       return -EINVAL;
-               des_set_key((des_cblock *) lo->lo_encrypt_key,
-                  lo->lo_des_key);
-               memcpy(lo->lo_des_init,info.lo_init,8);
-               break;
-#endif
-#ifdef IDEA_AVAILABLE
-       case LO_CRYPT_IDEA:
-         {
-               uint16 tmpkey[8];
-
-               if (info.lo_encrypt_key_size != IDEAKEYSIZE)
-                       return -EINVAL;
-                /* create key in lo-> from info.lo_encrypt_key */
-               memcpy(tmpkey,info.lo_encrypt_key,sizeof(tmpkey));
-               en_key_idea(tmpkey,lo->lo_idea_en_key);
-               de_key_idea(lo->lo_idea_en_key,lo->lo_idea_de_key);
-               break;
-         }
-#endif
-       default:
+       type = info.lo_encrypt_type; 
+       if (type >= MAX_LO_CRYPT || xfer_funcs[type] == NULL)
                return -EINVAL;
-       }
+       err = loop_release_xfer(lo); 
+       if (err)
+               return err;
+       if (xfer_funcs[type]->init) 
+               err = xfer_funcs[type]->init(lo, &info);
+       if (err)
+               return err;
+
        lo->lo_offset = info.lo_offset;
        strncpy(lo->lo_name, info.lo_name, LO_NAME_SIZE);
-       lo->lo_encrypt_type = info.lo_encrypt_type;
-       lo->transfer = xfer_funcs[lo->lo_encrypt_type];
+       lo->lo_encrypt_type = type; 
+
+       lo->transfer = xfer_funcs[type]->transfer;
+       lo->ioctl = xfer_funcs[type]->ioctl;
        lo->lo_encrypt_key_size = info.lo_encrypt_key_size;
-       if (info.lo_encrypt_key_size)
-               memcpy(lo->lo_encrypt_key, info.lo_encrypt_key,
+       lo->lo_init[0] = info.lo_init[0];
+       lo->lo_init[1] = info.lo_init[1];
+       if (info.lo_encrypt_key_size) {
+               memcpy(lo->lo_encrypt_key, info.lo_encrypt_key, 
                       info.lo_encrypt_key_size);
+               lo->lo_key_owner = current->uid; 
+       }       
        figure_loop_size(lo);
        return 0;
 }
@@ -552,15 +512,11 @@ static int loop_set_status(struct loop_device *lo, struct loop_info *arg)
 static int loop_get_status(struct loop_device *lo, struct loop_info *arg)
 {
        struct loop_info        info;
-       int err;
-       
+
        if (!lo->lo_dentry)
                return -ENXIO;
        if (!arg)
                return -EINVAL;
-       err = verify_area(VERIFY_WRITE, arg, sizeof(info));
-       if (err)
-               return err;
        memset(&info, 0, sizeof(info));
        info.lo_number = lo->lo_number;
        info.lo_device = kdev_t_to_nr(lo->lo_dentry->d_inode->i_dev);
@@ -575,8 +531,7 @@ static int loop_get_status(struct loop_device *lo, struct loop_info *arg)
                memcpy(info.lo_encrypt_key, lo->lo_encrypt_key,
                       lo->lo_encrypt_key_size);
        }
-       copy_to_user(arg, &info, sizeof(info));
-       return 0;
+       return copy_to_user(arg, &info, sizeof(info)) ? -EFAULT : 0;
 }
 
 static int lo_ioctl(struct inode * inode, struct file * file,
@@ -611,7 +566,7 @@ static int lo_ioctl(struct inode * inode, struct file * file,
                        return -EINVAL;
                return put_user(loop_sizes[lo->lo_number] << 1, (long *) arg);
        default:
-               return -EINVAL;
+               return lo->ioctl ? lo->ioctl(lo, cmd, arg) : -EINVAL;
        }
        return 0;
 }
@@ -628,8 +583,9 @@ static int lo_open(struct inode *inode, struct file *file)
                return -ENODEV;
        }
        dev = MINOR(inode->i_rdev);
-       if (dev >= MAX_LOOP)
+       if (dev >= MAX_LOOP) {
                return -ENODEV;
+       }
        lo = &loop_dev[dev];
        lo->lo_refcnt++;
        MOD_INC_USE_COUNT;
@@ -639,7 +595,7 @@ static int lo_open(struct inode *inode, struct file *file)
 static int lo_release(struct inode *inode, struct file *file)
 {
        struct loop_device *lo;
-       int     dev;
+       int     dev, err = 0;
 
        if (!inode)
                return 0;
@@ -650,15 +606,18 @@ static int lo_release(struct inode *inode, struct file *file)
        dev = MINOR(inode->i_rdev);
        if (dev >= MAX_LOOP)
                return 0;
-       fsync_dev(inode->i_rdev);
+       err = fsync_dev(inode->i_rdev);
+       if (err < 0) 
+               return err; 
        lo = &loop_dev[dev];
        if (lo->lo_refcnt <= 0)
                printk(KERN_ERR "lo_release: refcount(%d) <= 0\n", lo->lo_refcnt);
        else  {
-               lo->lo_refcnt--;
+               if (--lo->lo_refcnt == 0) 
+                       err = loop_release_xfer(lo);
                MOD_DEC_USE_COUNT;
        }
-       return 0;
+       return err;
 }
 
 static struct file_operations lo_fops = {
@@ -681,8 +640,28 @@ static struct file_operations lo_fops = {
 #define loop_init init_module
 #endif
 
-__initfunc(int
-loop_init( void )) {
+int loop_register_transfer(struct loop_func_table *funcs)
+{
+       if ((unsigned)funcs->number > MAX_LO_CRYPT || xfer_funcs[funcs->number])
+               return -EINVAL;
+       xfer_funcs[funcs->number] = funcs;
+       return 0; 
+}
+
+/* Usage checking must be done by the caller - usually with MOD_INC/DEC_* */  
+int loop_unregister_transfer(int number)
+{
+       if ((unsigned)number >= MAX_LO_CRYPT)
+               return -EINVAL; 
+       xfer_funcs[number] = NULL; 
+       return 0; 
+}
+
+EXPORT_SYMBOL(loop_register_transfer);
+EXPORT_SYMBOL(loop_unregister_transfer);
+
+int __init loop_init(void) 
+{
        int     i;
 
        if (register_blkdev(MAJOR_NR, "loop", &lo_fops)) {
@@ -692,12 +671,6 @@ loop_init( void )) {
        }
 #ifndef MODULE
        printk(KERN_INFO "loop: registered device at major %d\n", MAJOR_NR);
-#ifdef DES_AVAILABLE
-       printk(KERN_INFO "loop: DES encryption available\n");
-#endif
-#ifdef IDEA_AVAILABLE
-       printk(KERN_INFO "loop: IDEA encryption available\n");
-#endif
 #endif
 
        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
@@ -714,9 +687,9 @@ loop_init( void )) {
 }
 
 #ifdef MODULE
-void
-cleanup_module( void ) {
-  if (unregister_blkdev(MAJOR_NR, "loop") != 0)
-    printk(KERN_WARNING "loop: cleanup_module failed\n");
+void cleanup_module(void) 
+{
+       if (unregister_blkdev(MAJOR_NR, "loop") != 0)
+               printk(KERN_WARNING "loop: cannot unregister blkdev\n");
 }
 #endif
index 465d245454b045b0b50d31f85f1e47b26880e64d..ba5fbf53d3f4b6960fd6cf794d5adf8cc5b2fb70 100644 (file)
 #include <linux/string.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -1690,7 +1691,7 @@ do_cdu31a_request(void)
    /* Make sure we have a valid TOC. */
    sony_get_toc(); 
 
-   sti();
+   spin_unlock_irq(&io_request_lock);
 
    /* Make sure the timer is cancelled. */
    del_timer(&cdu31a_abort_timer);
@@ -1849,7 +1850,7 @@ try_read_again:
    }
 
 end_do_cdu31a_request:
-   cli();
+   spin_lock_irq(&io_request_lock);
 #if 0
    /* After finished, cancel any pending operations. */
    abort_read();
index d1e1143013967f4f382ed41e1e294a5a78bbe8f5..f5fdc65db0050d17ab2c575f6cd03a3bcd056549 100644 (file)
@@ -186,6 +186,7 @@ History:
 #include <linux/mm.h>
 #include <linux/malloc.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 /* #include <linux/ucdrom.h> */
 
@@ -816,6 +817,7 @@ static void do_cm206_request(void)
       end_request(0);
       continue;
     }
+    spin_unlock_irq(&io_request_lock);
     error=0;
     for (i=0; i<CURRENT->nr_sectors; i++) {
       int e1, e2;
@@ -838,6 +840,7 @@ static void do_cm206_request(void)
        debug(("cm206_request: %d %d\n", e1, e2));
       }
     }
+    spin_lock_irq(&io_request_lock);
     end_request(!error);
   }
 }
index 11b99e645aacea75ac6cd0dba2ea04cef7b1049d..de9009a8c0a1d668562fe6aed29d8c5f93d4d11d 100644 (file)
 #include <linux/string.h>
 #include <linux/vmalloc.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
@@ -1487,13 +1488,14 @@ static int cmd_out(void)
        
        if (flags_cmd_out&f_putcmd)
        { 
+               unsigned long flags;
                for (i=0;i<7;i++)
                        sprintf(&msgbuf[i*3], " %02X", drvcmd[i]);
                msgbuf[i*3]=0;
                msg(DBG_CMD,"cmd_out:%s\n", msgbuf);
-               cli();
+               save_flags(flags); cli();
                for (i=0;i<7;i++) OUT(CDo_command,drvcmd[i]);
-               sti();
+               restore_flags(flags);
        }
        if (response_count!=0)
        {
@@ -4824,7 +4826,7 @@ static void DO_SBPCD_REQUEST(void)
        INIT_REQUEST;
        req=CURRENT;            /* take out our request so no other */
        CURRENT=req->next;      /* task can fuck it up         GTL  */
-       sti();
+       spin_unlock_irq(&io_request_lock);              /* FIXME!!!! */
        
        down(&ioctl_read_sem);
        if (req->rq_status == RQ_INACTIVE)
@@ -4869,6 +4871,7 @@ static void DO_SBPCD_REQUEST(void)
                        xnr, req, req->sector, req->nr_sectors, jiffies);
 #endif
                sbpcd_end_request(req, 1);
+               spin_lock_irq(&io_request_lock);                /* FIXME!!!! */
                goto request_loop;
        }
 
@@ -4908,6 +4911,7 @@ static void DO_SBPCD_REQUEST(void)
                                xnr, req, req->sector, req->nr_sectors, jiffies);
 #endif
                        sbpcd_end_request(req, 1);
+                       spin_lock_irq(&io_request_lock);        /* FIXME!!!! */
                        goto request_loop;
                }
        }
@@ -4922,6 +4926,7 @@ static void DO_SBPCD_REQUEST(void)
 #endif
        sbpcd_end_request(req, 0);
        sbp_sleep(0);    /* wait a bit, try again */
+       spin_lock_irq(&io_request_lock);                /* FIXME!!!! */
        goto request_loop;
 }
 /*==========================================================================*/
@@ -5098,13 +5103,11 @@ static int sbp_data(struct request *req)
                {
                        msg(DBG_INF,"sbp_data: CDi_status timeout (timed_out_data) (%02X).\n", j);
                        error_flag++;
-                       break;
                }
                if (try==0)
                {
                        msg(DBG_INF,"sbp_data: CDi_status timeout (try=0) (%02X).\n", j);
                        error_flag++;
-                       break;
                }
                if (!(j&s_not_result_ready))
                {
@@ -5119,10 +5122,10 @@ static int sbp_data(struct request *req)
                                msg(DBG_INF, "CD contains no data tracks.\n");
                        else msg(DBG_INF, "sbp_data: DATA_READY timeout (%02X).\n", j);
                        error_flag++;
-                       break;
                }
                SBPCD_STI;
-               error_flag=0;
+               if (error_flag) break;
+
                msg(DBG_000, "sbp_data: beginning to read.\n");
                p = D_S[d].sbp_buf + frame *  CD_FRAMESIZE;
                if (sbpro_type==1) OUT(CDo_sel_i_d,1);
index 5c5ea7b1b442cc6cc7462f1aec61c95dbfdf9d59..a2a9139cbb16e3f34d4c7e2cbce5fa33ef28da09 100644 (file)
@@ -125,7 +125,7 @@ if [ "$CONFIG_VIDEO_DEV" != "n" ]; then
     hex '  SF16FMI I/O port (0x284 or 0x384)' CONFIG_RADIO_SF16FMI_PORT 284
   fi
   dep_tristate 'Zoltrix Radio' CONFIG_RADIO_ZOLTRIX $CONFIG_VIDEO_DEV
-  if [ "$CONFIG_RADIO_ZOLTRIX" != "n" ]; then
+  if [ "$CONFIG_RADIO_ZOLTRIX" = "y" ]; then
     hex '  ZOLTRIX I/O port (0x20c or 0x30c)' CONFIG_RADIO_ZOLTRIX_PORT 20c
   fi
 fi
index 19c30d6fdb36eb04e0cf242d254f129a96d0950c..f6667efb003cd0e5f89dd3c5a44c22e6bfe78ecc 100644 (file)
@@ -684,7 +684,7 @@ int palette2fmt[] = {
        BT848_COLOR_FMT_YCrCb422,
        BT848_COLOR_FMT_YCrCb411,
 };
-#define PALETTEFMT_MAX 11
+#define PALETTEFMT_MAX 15
 
 static int make_rawrisctab(struct bttv *btv, unsigned int *ro,
                             unsigned int *re, unsigned int *vbuf)
@@ -2924,7 +2924,7 @@ int configure_bt848(struct pci_dev *dev, int bttv_num)
         printk("memory: 0x%08x.\n", btv->bt848_adr);
         
         btv->pll.pll_ifreq=0;
-        btv->pll.pll_ifreq=0;
+        btv->pll.pll_ofreq=0;
         btv->pll.pll_crystal=0;
         if(pll[btv->nr])
                 if (!(btv->id==848 && btv->revision==0x11))
index 9a818d4d43c7580d5839109c9a446e0dd4ee71ca..6a65c8cfad8ca2f305948fe0adc956ae5e5c0e71 100644 (file)
@@ -474,7 +474,7 @@ elmc_probe(struct device *dev)) {
        to use.  I suspect that whoever sets the thing up initially would
        prefer we don't screw with those things.
 
-       Note we we read the status info when we found the card...
+       Note that we read the status info when we found the card...
 
        See 3c523.h for more details.
        */
index 43db9bc8deb0e4d5f935efcb4bb77e624e994f00..6a9c0990c004a414ded3c81d04823820b762a9c7 100644 (file)
@@ -1194,7 +1194,7 @@ static int i596_close(struct device *dev)
 
        while (lp->scb.command)
                if (--boguscnt == 0) {
-                       printk("%s: close1 timed timed out with status %4.4x, cmd %4.4x.\n",
+                       printk("%s: close1 timed out with status %4.4x, cmd %4.4x.\n",
                             dev->name, lp->scb.status, lp->scb.command);
                        break;
                }
@@ -1205,7 +1205,7 @@ static int i596_close(struct device *dev)
 
        while (lp->scb.command)
                if (--boguscnt == 0) {
-                       printk("%s: close2 timed timed out with status %4.4x, cmd %4.4x.\n",
+                       printk("%s: close2 timed out with status %4.4x, cmd %4.4x.\n",
                             dev->name, lp->scb.status, lp->scb.command);
                        break;
                }
index b7f36ee144e2cdbb287c0e44c7daf17a18811eb9..b51140858776eed00cc4486cf4337eab807a7b9d 100644 (file)
@@ -152,12 +152,12 @@ fi
 #
 # AppleTalk
 #
-if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
+if [ "$CONFIG_ATALK" != "n" ]; then
   dep_tristate 'Apple/Farallon LocalTalk PC support' CONFIG_LTPC $CONFIG_ATALK
-  dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS
+  dep_tristate 'COPS LocalTalk PC support' CONFIG_COPS $CONFIG_ATALK
   if [ "$CONFIG_COPS" != "n" ]; then
-    bool 'Dayna firmware support' CONFIG_COPS_DAYNA
-    bool 'Tangent firmware support' CONFIG_COPS_TANGENT
+     bool 'Dayna firmware support' CONFIG_COPS_DAYNA
+     bool 'Tangent firmware support' CONFIG_COPS_TANGENT
   fi
   dep_tristate 'Appletalk-IP driver support' CONFIG_IPDDP $CONFIG_ATALK
   if [ "$CONFIG_IPDDP" != "n" ]; then
index e260d0e5841051cd978acb4ec95ee4a5186a05d5..d27fbee7cb747d23a890f79d67eb07a9f4269ff8 100644 (file)
@@ -4,9 +4,6 @@
         Written 1994-1996 by Avery Pennarun,
        which was in turn derived from skeleton.c by Donald Becker.
 
-       Contact Avery at: apenwarr@bond.net or
-       RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
-
        **********************
 
        The original copyright of skeleton.c was as follows:
@@ -130,7 +127,7 @@ extern int arcnet_num_devs;
 #define SETCONF        writeb(lp->config,_CONFIG)
 
 static const char *version =
-"arc-rimi.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+"arc-rimi.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
 
 /****************************************************************************
  *                                                                          *
index 8926902a5cd79cf8eb5413cca84bdc5dae4aa84c..1111e19c73ee2af482e937de0db19f5df9acb891 100644 (file)
@@ -3,9 +3,6 @@
        Written 1994-1996 by Avery Pennarun,
        derived from skeleton.c by Donald Becker.
 
-       Contact Avery at: apenwarr@bond.net or
-       RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
-
        **********************
 
        The original copyright was as follows:
@@ -88,7 +85,7 @@
 
        The following has been SUMMARIZED.  The complete ChangeLog is
        available in the full Linux-ARCnet package at
-               http://www.foxnet.net/~apenwarr/arcnet
+               http://www.worldvisions.ca/~apenwarr/arcnet
 
        v2.50 (96/02/24)
          - Massively improved autoprobe routines; they now work even as a
 */
 
 static const char *version =
- "arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "arcnet.c: v3.02 98/06/07 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
 
 #include <linux/module.h>
 #include <linux/config.h>
index 232b714a8822b7be41ec55cbd8728b0aa71f30bf..baaa5969298dce9b21fb961a481af65fed085a13 100644 (file)
@@ -545,6 +545,7 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
     struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
     struct AriadneBoard *board = priv->board;
     int entry;
+    unsigned long flags;
 
     /* Transmitter timeout, serious problems. */
     if (dev->tbusy) {
@@ -625,6 +626,9 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
     printk(" data 0x%08x len %d\n", (int)skb->data, (int)skb->len);
 #endif
 
+    save_flags(flags);
+    cli();
+
     entry = priv->cur_tx % TX_RING_SIZE;
 
     /* Caution: the write order is important here, set the base address with
@@ -675,13 +679,12 @@ static int ariadne_start_xmit(struct sk_buff *skb, struct device *dev)
 
     dev->trans_start = jiffies;
 
-    cli();
     priv->lock = 0;
     if (lowb(priv->tx_ring[(entry+1) % TX_RING_SIZE]->TMD1) == 0)
        dev->tbusy = 0;
     else
        priv->tx_full = 1;
-    sti();
+    restore_flags(flags);
 
     return(0);
 }
@@ -780,13 +783,15 @@ static struct net_device_stats *ariadne_get_stats(struct device *dev)
     struct ariadne_private *priv = (struct ariadne_private *)dev->priv;
     struct AriadneBoard *board = priv->board;
     short saved_addr;
+    unsigned long flags;
 
+    save_flags(flags);
     cli();
     saved_addr = board->Lance.RAP;
     board->Lance.RAP = CSR112; /* Missed Frame Count */
     priv->stats.rx_missed_errors = swapw(board->Lance.RDP);
     board->Lance.RAP = saved_addr;
-    sti();
+    restore_flags(flags);
 
     return(&priv->stats);
 }
index 5c9ac32ab5a7a5fc1a57b93c860757ec0dfd2cce..093a5acf00c8e8c4cdf529fedbc47e273e9879f0 100644 (file)
@@ -6,9 +6,6 @@
        Written 1994-1996 by Avery Pennarun,
        which was in turn derived from skeleton.c by Donald Becker.
 
-       Contact Avery at: apenwarr@bond.net or
-       RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
-
        **********************
 
        The original copyright of skeleton.c was as follows:
@@ -214,7 +211,7 @@ void put_whole_buffer (struct device *dev, unsigned offset, unsigned length, cha
 
 
 static const char *version =
- "com20020.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "com20020.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
 
 /****************************************************************************
  *                                                                          *
index 46f5d6f2ec57555df1d89036242983ee03e91943..3096544602b37e98720e4960055fec52a7e146b0 100644 (file)
@@ -6,9 +6,6 @@
        Written 1994-1996 by Avery Pennarun,
        which was in turn derived from skeleton.c by Donald Becker.
 
-       Contact Avery at: apenwarr@bond.net or
-       RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
-
        **********************
 
        The original copyright of skeleton.c was as follows:
@@ -183,7 +180,7 @@ void put_whole_buffer (struct device *dev, unsigned offset, unsigned length, cha
 
 
 static const char *version =
- "com90io.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+ "com90io.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
 
 
 /****************************************************************************
index f605ce20b3f54047b5cf3b8967a0f4fca32df028..3ca5a5ef88f61577ea4f1725e778485d21ce7578 100644 (file)
@@ -4,9 +4,6 @@
    Written 1994-1996 by Avery Pennarun,
    which was in turn derived from skeleton.c by Donald Becker.
 
-   Contact Avery at: apenwarr@bond.net or
-   RR #5 Pole Line Road, Thunder Bay, ON, Canada P7C 5M9
-
    **********************
 
    The original copyright of skeleton.c was as follows:
@@ -153,7 +150,7 @@ extern int arcnet_num_devs;
 #define ARCRESET       inb(_RESET)
 
 static const char *version =
-"com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@bond.net> et al.\n";
+"com90xx.c: v3.00 97/11/09 Avery Pennarun <apenwarr@worldvisions.ca> et al.\n";
 
 
 /****************************************************************************
index 0b550fd570d94c14aaf149d8ae596dfa012f2bc2..1c563cce9b3d14a0fa1711e5a59e740f84d2a9e7 100644 (file)
@@ -30,6 +30,8 @@ static const char *version =
 #include <linux/nubus.h>
 #include <asm/io.h>
 #include <asm/system.h>
+#include <asm/hwtest.h>
+#include <linux/delay.h>
 
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
@@ -57,6 +59,13 @@ static void sane_block_input(struct device *dev, int count,
 static void sane_block_output(struct device *dev, int count,
                                                        const unsigned char *buf, const start_page);
 
+static void slow_sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr,
+                                               int ring_page);
+static void slow_sane_block_input(struct device *dev, int count,
+                                                 struct sk_buff *skb, int ring_offset);
+static void slow_sane_block_output(struct device *dev, int count,
+                                                  const unsigned char *buf, const int start_page);
+
 \f
 #define WD_START_PG    0x00    /* First page of TX buffer */
 #define WD03_STOP_PG   0x20    /* Last page +1 of RX ring */
@@ -81,11 +90,11 @@ static int test_8390(volatile char *ptr, int scale)
        int regd;
        int v;
        
-       if(nubus_hwreg_present(&ptr[0x00])==0)
+       if(hwreg_present(&ptr[0x00])==0)
                return -EIO;
-       if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+       if(hwreg_present(&ptr[0x0D<<scale])==0)
                return -EIO;
-       if(nubus_hwreg_present(&ptr[0x0D<<scale])==0)
+       if(hwreg_present(&ptr[0x0D<<scale])==0)
                return -EIO;
        ptr[0x00]=E8390_NODMA+E8390_PAGE1+E8390_STOP;
        regd=ptr[0x0D<<scale];
@@ -135,6 +144,51 @@ int ns8390_ident(struct nubus_type *nb)
        return -1;
 }
 
+/*
+ *     Memory probe for 8390 cards
+ */
+int apple_8390_mem_probe(volatile unsigned short *p)
+{
+       int i, j;
+       /*
+        *      Algorithm.
+        *      1.      Check each block size of memory doesn't fault
+        *      2.      Write a value to it
+        *      3.      Check all previous blocks are unaffected
+        */
+       
+       for(i=0;i<2;i++)
+       {
+               volatile unsigned short *m=p+4096*i;
+               /* Unwriteable - we have a fully decoded card and the
+                  RAM end located */
+                  
+               if(hwreg_present(m)==0)
+                       return 8192*i;
+                       
+               *m=0xA5A0|i;
+               
+               for(j=0;j<i;j++)
+               {
+                       /* Partial decode and wrap ? */
+                       if(p[4096*j]!=(0xA5A0|j))
+                       {
+                               /* This is the first misdecode, so it had
+                                  one less page than we tried */
+                               return 8192*i;
+                       }
+                       j++;
+               }
+               /* Ok it still decodes.. move on 8K */
+       }
+       /* 
+        *      We don't look past 16K. That should cover most cards
+        *      and above 16K there isnt really any gain.
+        */
+       return 16384;
+ }
+               
 /*
  *    Probe for 8390 cards.  
  *    The ns8390_probe1() routine initializes the card and fills the
@@ -216,16 +270,21 @@ int ns8390_probe(struct nubus_device_specifier *d, int slot, struct nubus_type *
        /* Apple, Farallon, Asante */
        if(id==NS8390_APPLE|| id==NS8390_FARALLON || id==NS8390_ASANTE)
        {
+               int memsize;
+               
                dev->base_addr=(int)(nubus_slot_addr(slot)+APPLE_8390_BASE);
                dev->mem_start=(int)(nubus_slot_addr(slot)+APPLE_8390_MEM);
-               dev->mem_end=dev->mem_start+APPLE_MEMSIZE; /* 8K it seems */
+               
+               memsize = apple_8390_mem_probe((void *)dev->mem_start);
+               
+               dev->mem_end=dev->mem_start+memsize;
                dev->irq=slot;
                printk("apple/clone: testing board: ");
 
-               printk("memory - ");            
+               printk("%dK memory - ", memsize>>10);           
 
                i=(void *)dev->mem_start;
-               memset((void *)i,0xAA, DAYNA_MEMSIZE);
+               memset((void *)i,0xAA, memsize);
                while(i<(volatile unsigned short *)dev->mem_end)
                {
                        if(*i!=0xAAAA)
@@ -366,8 +425,15 @@ int ns8390_probe1(struct device *dev, int word16, char *model_name, int type, in
                        ei_status.get_8390_hdr = &dayna_get_8390_hdr;
                        ei_status.reg_offset = fwrd4_offsets;
                        break;
-               case NS8390_APPLE:      /* Apple/Asante/Farallon */
                case NS8390_FARALLON:
+               case NS8390_APPLE:      /* Apple/Asante/Farallon */
+                       /*      16 bit card, register map is reversed */
+                       ei_status.reset_8390 = &ns8390_no_reset;
+                       ei_status.block_input = &slow_sane_block_input;
+                       ei_status.block_output = &slow_sane_block_output;
+                       ei_status.get_8390_hdr = &slow_sane_get_8390_hdr;
+                       ei_status.reg_offset = back4_offsets;
+                       break;
                case NS8390_ASANTE:
                        /*      16 bit card, register map is reversed */
                        ei_status.reset_8390 = &ns8390_no_reset;
@@ -442,7 +508,7 @@ static void interlan_reset(struct device *dev)
 {
        unsigned char *target=nubus_slot_addr(dev->irq);
        if (ei_debug > 1) 
-       printk("Need to reset the NS8390 t=%lu...", jiffies);
+               printk("Need to reset the NS8390 t=%lu...", jiffies);
        ei_status.txing = 0;
        /* This write resets the card */
        target[0xC0000]=0;
@@ -585,6 +651,7 @@ static void sane_block_input(struct device *dev, int count, struct sk_buff *skb,
        }
 }
 
+
 static void sane_block_output(struct device *dev, int count, const unsigned char *buf,
                                int start_page)
 {
@@ -593,6 +660,81 @@ static void sane_block_output(struct device *dev, int count, const unsigned char
        memcpy((char *)dev->mem_start+shmem, buf, count);
 }
 
+static void word_memcpy_tocard(void *tp, const void *fp, int count)
+{
+       volatile unsigned short *to = tp;
+       const unsigned short *from = fp;
+       
+       count++;
+       count/=2;
+       
+       while(count--)
+               *to++=*from++;
+}
+
+static void word_memcpy_fromcard(void *tp, const void *fp, int count)
+{
+       unsigned short *to = tp;
+       const volatile unsigned short *from = fp;
+       
+       count++;
+       count/=2;
+       
+       while(count--)
+               *to++=*from++;
+}
+
+static void slow_sane_get_8390_hdr(struct device *dev, struct e8390_pkt_hdr *hdr, int ring_page)
+{
+       unsigned long hdr_start = (ring_page - WD_START_PG)<<8;
+       word_memcpy_fromcard((void *)hdr, (char *)dev->mem_start+hdr_start, 4);
+       /* Register endianism - fix here rather than 8390.c */
+       hdr->count=(hdr->count&0xFF)<<8|(hdr->count>>8);
+}
+
+static void slow_sane_block_input(struct device *dev, int count, struct sk_buff *skb, int ring_offset)
+{
+       unsigned long xfer_base = ring_offset - (WD_START_PG<<8);
+       unsigned long xfer_start = xfer_base+dev->mem_start;
+
+       if (xfer_start + count > dev->rmem_end) 
+       {
+               /* We must wrap the input move. */
+               int semi_count = dev->rmem_end - xfer_start;
+               word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, semi_count);
+               count -= semi_count;
+               word_memcpy_fromcard(skb->data + semi_count, 
+                       (char *)dev->rmem_start, count);
+       }
+       else
+       {
+               word_memcpy_fromcard(skb->data, (char *)dev->mem_start+xfer_base, count);
+       }
+}
+
+static void slow_sane_block_output(struct device *dev, int count, const unsigned char *buf,
+                               int start_page)
+{
+       long shmem = (start_page - WD_START_PG)<<8;
+       
+       word_memcpy_tocard((char *)dev->mem_start+shmem, buf, count);
+#if 0
+       long shmem = (start_page - WD_START_PG)<<8;
+       volatile unsigned short *to=(unsigned short *)(dev->mem_start+shmem);
+       volatile int p;
+       unsigned short *bp=(unsigned short *)buf;
+       
+       count=(count+1)/2;
+       
+       while(count--)
+       {
+               *to++=*bp++;
+               for(p=0;p<10;p++)
+                       p++;
+       }
+#endif 
+}
+
 /*
  * Local variables:
  *  compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/net/inet -Wall -Wstrict-prototypes -O6 -m486 -c daynaport.c"
index bf453dc53c582471b3cd6cdce490b10c6cf51d9a..fd257f11f2a478409f0bdc2284cab56900384605 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * $Id: dmascc.c,v 1.2.1.4 1998/06/10 02:24:11 kudielka Exp $
+ * $Id: dmascc.c,v 1.3 1998/09/07 04:41:56 kudielka Exp $
  *
  * Driver for high-speed SCC boards (those with DMA support)
  * Copyright (C) 1997 Klaus Kudielka
 #define test_and_set_bit(x,y) set_bit(x,y)
 #define register_netdevice(x) register_netdev(x)
 #define unregister_netdevice(x) unregister_netdev(x)
+#define dev_kfree_skb(x) dev_kfree_skb(x,FREE_WRITE)
+#define SET_DEV_INIT(x) (x=dmascc_dev_init)
+
+#define SHDLCE  0x01 /* WR15 */
+
+#define AUTOEOM 0x02 /* WR7' */
+#define RXFIFOH 0x08
+#define TXFIFOE 0x20
 
 static int dmascc_dev_init(struct device *dev)
 {
@@ -83,7 +91,7 @@ static void dev_init_buffers(struct device *dev)
 #include <linux/init.h>
 #include <asm/uaccess.h>
 
-#define dmascc_dev_init NULL
+#define SET_DEV_INIT(x)
 
 
 #endif
@@ -286,7 +294,7 @@ static unsigned long rand;
 #ifdef MODULE
 
 
-MODULE_AUTHOR("Klaus Kudielka <oe1kib@oe1xtu.ampr.org>");
+MODULE_AUTHOR("Klaus Kudielka");
 MODULE_DESCRIPTION("Driver for high-speed SCC boards");
 MODULE_PARM(io, "1-" __MODULE_STRING(MAX_NUM_DEVS) "i");
 
@@ -462,8 +470,8 @@ __initfunc(int setup_adapter(int io, int h, int n))
   /* Reset 8530 */
   write_scc(cmd, R9, FHWRES | MIE | NV);
 
-  /* Determine type of chip */
-  write_scc(cmd, R15, 1);
+  /* Determine type of chip by enabling SDLC/HDLC enhancements */
+  write_scc(cmd, R15, SHDLCE);
   if (!read_scc(cmd, R15)) {
     /* WR7' not present. This is an ordinary Z8530 SCC. */
     chip = Z8530;
@@ -575,7 +583,7 @@ __initfunc(int setup_adapter(int io, int h, int n))
     dev->hard_header = ax25_encapsulate;
     dev->rebuild_header = ax25_rebuild_header;
     dev->set_mac_address = scc_set_mac_address;
-    dev->init = dmascc_dev_init;
+    SET_DEV_INIT(dev->init);
     dev->type = ARPHRD_AX25;
     dev->hard_header_len = 73;
     dev->mtu = 1500;
@@ -662,17 +670,17 @@ static int scc_open(struct device *dev)
   switch (info->chip) {
   case Z85C30:
     /* Select WR7' */
-    write_scc(cmd, R15, 1);
+    write_scc(cmd, R15, SHDLCE);
     /* Auto EOM reset */
-    write_scc(cmd, R7, 0x02);
+    write_scc(cmd, R7, AUTOEOM);
     write_scc(cmd, R15, 0);
     break;
   case Z85230:
     /* Select WR7' */
-    write_scc(cmd, R15, 1);
+    write_scc(cmd, R15, SHDLCE);
     /* RX FIFO half full (interrupt only), Auto EOM reset,
        TX FIFO empty (DMA only) */
-    write_scc(cmd, R7, dev->dma ? 0x22 : 0x0a);
+    write_scc(cmd, R7, AUTOEOM | (dev->dma ? TXFIFOE : RXFIFOH));
     write_scc(cmd, R15, 0);
     break;
   }
index 3d4a918d7d7bf7567a5a7b4a35bb006fe3ca680c..8bef548572aa460241149fc7abda64eaf0d5f351 100644 (file)
 
 /* Read Register 15 (value of WR 15) */
 
-/* 8580/85180/85280 Enhanced SCC register definitions */
+/* Z85C30/Z85230 Enhanced SCC register definitions */
 
 /* Write Register 7' (SDLC/HDLC Programmable Enhancements) */
 #define AUTOTXF        0x01            /* Auto Tx Flag */
 #define AUTOEOM 0x02           /* Auto EOM Latch Reset */
 #define AUTORTS        0x04            /* Auto RTS */
 #define TXDNRZI 0x08           /* TxD Pulled High in SDLC NRZI mode */
+#define RXFIFOH 0x08           /* Z85230: Int on RX FIFO half full */
 #define FASTDTR 0x10           /* Fast DTR/REQ Mode */
 #define CRCCBCR        0x20            /* CRC Check Bytes Completely Received */
+#define TXFIFOE 0x20           /* Z85230: Int on TX FIFO completely empty */
 #define EXTRDEN        0x40            /* Extended Read Enabled */
 
 /* Write Register 15 (external/status interrupt control) */
 /* Read Register 7 (frame status FIFO) */
 #define BCMSB  0x3f            /* MSB of 14 bits count */
 #define FDA    0x40            /* FIFO Data Available Status */
-#define FOY    0x80            /* FIFO Overflow Status */
+#define FOS    0x80            /* FIFO Overflow Status */
index 5dd8d1d54f011640bd48c44243ea59d0865ec03c..89193380683b467f3d871dcc519d5dca8725313a 100644 (file)
@@ -1175,7 +1175,7 @@ void plip_setup(char *str, int *ints)
                timid = 1;
        } else {
                if (ints[0] == 0 || ints[1] == 0) {
-                       /* disable driver on "parport=" or "parport=0" */
+                       /* disable driver on "plip=" or "plip=0" */
                        parport[0] = -2;
                } else {
                        printk(KERN_WARNING "warning: 'plip=0x%x' ignored\n", 
index d266c64b76e9130c9eb029606fa71895eaa08f43..84bfe986355938378314203073081182f3b6f0f7 100644 (file)
 #include <asm/setup.h>
 #include <asm/system.h>
 #include <asm/page.h>
+#include <asm/hwtest.h>
 /* for LCIII stuff; better find a general way like MACH_HAS_NUBUS */
 #include <asm/macintosh.h>
+#include <linux/proc_fs.h>
+
 
 #undef LCIII_WEIRDNESS
  
@@ -26,49 +29,6 @@ static struct nubus_slot nubus_slots[16];
  *                             -- Alan
  */
  
-/* This function tests for the presence of an address, specially a
- * hardware register address. It is called very early in the kernel
- * initialization process, when the VBR register isn't set up yet. On
- * an Atari, it still points to address 0, which is unmapped. So a bus
- * error would cause another bus error while fetching the exception
- * vector, and the CPU would do nothing at all. So we needed to set up
- * a temporary VBR and a vector table for the duration of the test.
- *
- * See the atari/config.c code we nicked it from for more clues.
- */
-
-int nubus_hwreg_present( volatile void *regp )
-{
-    int        ret = 0;
-    long       save_sp, save_vbr;
-    long       tmp_vectors[3];
-    unsigned long flags;
-    
-    save_flags(flags);
-    cli();
-
-    __asm__ __volatile__
-       (       "movec  %/vbr,%2\n\t"
-               "movel  #Lberr1,%4@(8)\n\t"
-                "movec %4,%/vbr\n\t"
-               "movel  %/sp,%1\n\t"
-               "moveq  #0,%0\n\t"
-               "tstb   %3@\n\t"  
-               "nop\n\t"
-               "moveq  #1,%0\n"
-                "Lberr1:\n\t"
-               "movel  %1,%/sp\n\t"
-               "movec  %2,%/vbr"
-               : "=&d" (ret), "=&r" (save_sp), "=&r" (save_vbr)
-               : "a" (regp), "a" (tmp_vectors)
-                );
-    restore_flags(flags);
-    return( ret );
-}
-
-
 
 /*
  *     Yes this sucks. The ROM can appear on arbitary bytes of the long
@@ -104,7 +64,7 @@ static void nubus_rewind(unsigned char **ptr, int len, int map)
 {
        unsigned char *p=*ptr;
        
-       if(len>8192)
+       if(len>65536)
                printk("rewind of %d!\n", len);
        while(len)
        {
@@ -121,7 +81,7 @@ static void nubus_rewind(unsigned char **ptr, int len, int map)
 static void nubus_advance(unsigned char **ptr, int len, int map)
 {
        unsigned char *p=*ptr;
-       if(len>8192)
+       if(len>65536)
                printk("advance of %d!\n", len);
        while(len)
        {
@@ -375,7 +335,7 @@ void nubus_probe_slot(int slot, int mode)
        {
                rp--;
                
-               if(!nubus_hwreg_present(rp))
+               if(!hwreg_present(rp))
                        continue;
                        
                dp=*rp;
@@ -596,6 +556,52 @@ int nubus_ethernet_addr(int slot, unsigned char *addr)
        return ng;
 }
 
+#ifdef CONFIG_PROC_FS
+
+/*
+ *     /proc for Nubus devices
+ */
+static int sprint_nubus_config(int slot, char *ptr, int len)
+{
+       if(len<150)
+               return -1;
+       sprintf(ptr, "Device: %s %s\n", nubus_slots[slot].slot_cardname,
+               (nubus_slots[slot].slot_flags&NUBUS_DEVICE_ACTIVE)?
+                       "[active]":"[unused]");
+       return strlen(ptr);
+}
+
+int get_nubus_list(char *buf)
+{
+       int nprinted, len, size;
+       int slot;
+#define MSG "\nwarning: page-size limit reached!\n"
+
+       /* reserve same for truncation warning message: */
+       size  = PAGE_SIZE - (strlen(MSG) + 1);
+       len   = sprintf(buf, "Nubus devices found:\n");
+
+       for (slot=0; slot< 16; slot++) 
+       {
+               if(!(nubus_slots[slot].slot_flags&NUBUS_DEVICE_PRESENT))
+                       continue;
+               nprinted = sprint_nubus_config(slot, buf + len, size - len);
+               if (nprinted < 0) {
+                       return len + sprintf(buf + len, MSG);
+               }
+               len += nprinted;
+       }
+       return len;
+}
+
+static struct proc_dir_entry proc_nubus = {
+       PROC_NUBUS, 5, "nubus",
+       S_IFREG | S_IRUGO, 1, 0, 0,
+       0, &proc_array_inode_operations
+};
+#endif
+
 void nubus_init(void)
 {
        /* 
@@ -626,4 +632,7 @@ void nubus_init(void)
        nubus_init_via();
        printk("Scanning nubus slots.\n");
        nubus_probe_bus();
+       proc_register(&proc_root, &proc_nubus);
 }
+
+       
\ No newline at end of file
index ad397c1206be4443e09da495ad71e14e3792fde4..61d35daeb065abf4be6869461c41c4c84249bfd2 100644 (file)
@@ -50,6 +50,13 @@ dep_tristate 'EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) supp
 dep_tristate 'Future Domain 16xx SCSI/AHA 2920 support' CONFIG_SCSI_FUTURE_DOMAIN $CONFIG_SCSI
 dep_tristate 'GDT SCSI Disk Array Controller support' CONFIG_SCSI_GDTH $CONFIG_SCSI
 dep_tristate 'Generic NCR5380/53c400 SCSI support' CONFIG_SCSI_GENERIC_NCR5380 $CONFIG_SCSI
+if [ "$CONFIG_PARPORT" != "n" ]; then
+  dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
+  if [ "$CONFIG_SCSI_PPA" != "n" ]; then
+    int  '  Pedantic EPP-checking'   CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
+  fi
+  dep_tristate 'IOMEGA ZIP Plus drive SCSI support' CONFIG_SCSI_IMM $CONFIG_SCSI $CONFIG_PARPORT
+fi
 if [ "$CONFIG_SCSI_GENERIC_NCR5380" != "n" ]; then
        bool '   Enable NCR53c400 extensions' CONFIG_SCSI_GENERIC_NCR53C400
        choice 'NCR5380/53c400 mapping method (use Port for T130B)' \
@@ -88,12 +95,6 @@ if [ "$CONFIG_MCA" = "y" ]; then
      bool '  Reset SCSI-devices at boottime' CONFIG_IBMMCA_SCSI_DEV_RESET
   fi
 fi
-if [ "$CONFIG_PARPORT" != "n" ]; then
-  dep_tristate 'IOMEGA Parallel Port ZIP drive SCSI support' CONFIG_SCSI_PPA $CONFIG_SCSI $CONFIG_PARPORT
-  if [ "$CONFIG_SCSI_PPA" != "n" ]; then
-    int  '  Pedantic EPP-checking'   CONFIG_SCSI_PPA_HAVE_PEDANTIC 2 0 3
-  fi
-fi
 dep_tristate 'PAS16 SCSI support' CONFIG_SCSI_PAS16 $CONFIG_SCSI
 dep_tristate 'PCI2000 support' CONFIG_SCSI_PCI2000 $CONFIG_SCSI
 dep_tristate 'PCI2220i support' CONFIG_SCSI_PCI2220I $CONFIG_SCSI
index 6441113acc8d541e7ee1551817d3ccf17fb8b235..7caa67ed333c6ad604bb33b4925f3cef13ea0bdd 100644 (file)
@@ -243,6 +243,14 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_SCSI_IMM),y)
+L_OBJS += imm.o
+else
+  ifeq ($(CONFIG_SCSI_IMM),m)
+  M_OBJS += imm.o
+  endif
+endif
+
 ifeq ($(CONFIG_SCSI_QLOGIC_FAS),y)
 L_OBJS += qlogicfas.o
 else
index 509541d7a8fba832a5e0b4411c27b348ec18d43b..0dac88d86d87406a95b5b98e76433f323c8d4a57 100644 (file)
-README.ppa (c) 1996   Grant R. Guenther,  grant@torque.net
+-------- Terse where to get ZIP Drive help info --------
 
+General Iomega ZIP drive page for Linux:
+http://www.torque.net/~campbell/
 
-         The IOMEGA PPA3 parallel port SCSI Host Bus Adapter
+Driver achive for old drivers:
+http://www.torque.net/~campbell/ppa/
 
-                     as embedded in the ZIP drive
+Linux Parport page (parallel port)
+http://www.torque.net/parport/
 
+Email list for Linux Parport
+linux-parport@torque.net
 
-This README documents the Linux support for the parallel port version of
-IOMEGA's ZIP100.  The ZIP100 is an inexpensive and popular, but relatively 
-low performance, removable medium disk device.  The drive is also available
-as a regular SCSI device, but the driver documented here is for the
-parallel port version.  IOMEGA implemented the parallel port version by
-integrating (or emulating ?) their PPA3 parallel to SCSI converter into
-the ZIP drive.
-
-I have implemented a low-level driver, ppa.c,  for this parallel port 
-host bus adapter, thereby supporting the parallel port ZIP drive as a 
-regular SCSI device under Linux.
-
-It is possible that this driver will also work with the original PPA3
-device (to access a CDrom, for instance). But, the PPA3 is hard to find 
-and costs as much as the ZIP drive itself, so no-one has actually tried
-this, to the best of my knowledge.
-
-The driver was developed without the benefit of any technical specifications 
-for the interface.  Instead, a modified version of DOSemu was used to 
-monitor the protocol used by the DOS driver, 'guest.exe', for this adapter.
-I have no idea how my programming model relates to IOMEGA's design.
-(One technical consequence of this method:  I have never observed a
-SCSI message byte in the protocol transactions between guest.exe and
-the ZIP drive, so I do not know how they are delivered.  My working 
-hypothesis is that we don't have to worry about them if we don't
-send linked commands to the drive.)
-
-I'd like to thank Byron Jeff (byron@cc.gatech.edu) for publishing his
-observation that the 'guest' driver loads under DOSemu.  His remark was
-the stimulus that began this project.
-
-The ppa driver can detect and adapt to 4- and 8-bit parallel ports, but 
-there is currently no support for EPP or ECP ports, as I have been unable 
-to make the DOS drivers work in these modes on my test rig.
-
-The driver may be built in to the kernel, or loaded as a module.  It
-may be configured on the command line in both cases, although the syntax
-is different.  It may also be configured by editing the source file.
-
-Built-in drivers accept parameters using this LILO/LOADLIN command line
-syntax (omitted parameters retain their default values):
-
-        ppa=base[,speed_high[,speed_low[,nybble]]]
-
-For example:    ppa=0x378,0,3
-
-If a driver is loaded as a module the parameters may be set on the
-insmod command line, but each one must be specified by name:
-
-For example:    insmod ppa.o ppa_base=0x378 ppa_nybble=1
-
-(Notice the ppa_ prefix on each of the parameters in the insmod form.)
-
-Here are the parameters and their functions:
-
-Variable        Default    Description
-
-ppa_base        0x378   The base address of PPA's parallel port.
-ppa_speed_high  1       Microsecond i/o delay used in data transfers
-ppa_speed_low   6       Microsecond delay used in other operations
-ppa_nybble      0       1 to force the driver to use 4-bit mode.
-
-A word about the timing parameters:  the ppa_speed_low parameter controls 
-the widths of a large number of pulses that are sent over the parallel bus, 
-the narrower the pulses, the faster things go, but the greater the risk of 
-distortion by noise damping circuits in the parallel ports.  The 
-ppa_speed_high parameter controls the same delays, but during the data 
-transfer phase only.   In this phase, there is a lot of handshaking going 
-on and the pulse shaping should not be so much of an issue, but if you 
-see data corruption, you can increase this parameter as well.
-
-You might also want to reduce the timing values to attempt to increase
-the transfer rates on your system.  Please be careful to watch for
-SCSI timeout errors in your log files.  If you are getting timeouts, you
-have set these parameters too low.  The default values appear to be
-safe on most machines.
-
-If you have both the lp and ppa drivers in your kernel, you must ensure
-that they access different parallel ports.  By default, the lp driver is
-initialised early in the booting process, and it claims all parallel
-ports that it can find.  You may control this behaviour with a LILO or
-LOADLIN command line argument of the form:
-
-        lp=base0[,irq0[,base1[,irq1[,base2[,irq2]]]]]
-
-For example:    lp=0x278,7
-
-If you use this method, only the ports named will be adopted by the lp
-driver.  You can disable them all with lp=0 .
-
-So, if you have a printer on 0x3bc and a ZIP drive on 0x278 you would
-give the following options on your boot command:
-
-        lp=0x3bc ppa=0x278
-
-In this case lp would use the polling driver, since an interrupt was not 
-specified.
-
-If you want to share the same parallel port between a ZIP drive and a
-printer, you should build both the lp and ppa drivers as modules and
-load and unload one or the other as required.  This is clumsy but we
-currently have no protocol for synchronising access to shared parallel
-ports.
-
-For information about using the ZIP drive, please read the generic
-instructions in the SCSI-HOWTO and the man pages for the normal disk
-management tools,  fdisk, mkfs, mount, umount, etc.  There is a mini-HOWTO
-circulating concerning the use of the normal SCSI version of the ZIP
-drive, most of its comments will apply to disks connected through the
-ppa driver as well.
-
+Email for problems with ZIP or ZIP Plus drivers
+campbell@torque.net
index 276930d52e26ba3b8ff5c11fbae8e8dd13472a67..2567195895b89887f8892ba455bf8dec172abb7b 100644 (file)
 #include "AM53C974.h"
 #endif
 
-#ifdef CONFIG_SCSI_PPA
-#include "ppa.h"
-#endif
-
 #ifdef CONFIG_SCSI_SUNESP
 #include "esp.h"
 #endif
 #include "jazz_esp.h"
 #endif
 
+/*
+ * Moved ppa driver to the end of the probe list
+ * since it is a removable host adapter.
+ * This means the parallel ZIP drive will not bump
+ * the order of the /dev/sd devices - campbell@torque.net
+ */
+#ifdef CONFIG_SCSI_PPA
+#include "ppa.h"
+#endif
+
+#ifdef CONFIG_SCSI_IMM
+#include "imm.h"
+#endif
+
 /*
 static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/hosts.c,v 1.20 1996/12/12 19:18:32 davem Exp $";
 */
@@ -441,9 +451,6 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
 #ifdef CONFIG_SCSI_AM53C974
     AM53C974,
 #endif
-#ifdef CONFIG_SCSI_PPA
-    PPA,
-#endif
 #ifdef CONFIG_SCSI_SUNESP
     SCSI_SPARC_ESP,
 #endif
@@ -485,6 +492,13 @@ static Scsi_Host_Template builtin_scsi_hosts[] =
     POWERTECSCSI,
 #endif
 #endif
+/* "Removable host adapters" below this line (Parallel Port/USB/other) */
+#ifdef CONFIG_SCSI_PPA
+    PPA,
+#endif
+#ifdef CONFIG_SCSI_IMM
+    IMM,
+#endif
 #ifdef CONFIG_SCSI_DEBUG
     SCSI_DEBUG,
 #endif
diff --git a/drivers/scsi/imm.c b/drivers/scsi/imm.c
new file mode 100644 (file)
index 0000000..eedd71b
--- /dev/null
@@ -0,0 +1,1321 @@
+/* imm.c   --  low level driver for the IOMEGA MatchMaker
+ * parallel port SCSI host adapter.
+ * 
+ * (The IMM is the embedded controller in the ZIP Plus drive.)
+ * 
+ * Current Maintainer: David Campbell (Perth, Western Australia)
+ *                     campbell@gear.torque.net
+ *                     dcampbel@p01.as17.honeywell.com.au
+ *
+ * My unoffical company acronym list is 21 pages long:
+ *      FLA:    Four letter acronym with built in facility for
+ *              future expansion to five letters.
+ */
+
+#include <linux/config.h>
+
+/* The following #define is to avoid a clash with hosts.c */
+#define IMM_CODE 1
+#define IMM_PROBE_SPP   0x0001
+#define IMM_PROBE_PS2   0x0002
+#define IMM_PROBE_ECR   0x0010
+#define IMM_PROBE_EPP17 0x0100
+#define IMM_PROBE_EPP19 0x0200
+
+void imm_reset_pulse(unsigned int base);
+static int device_check(int host_no);
+
+#include <linux/blk.h>
+#include <asm/io.h>
+#include <linux/parport.h>
+#include "sd.h"
+#include "hosts.h"
+typedef struct {
+    struct pardevice *dev;      /* Parport device entry         */
+    int base;                  /* Actual port address          */
+    int mode;                  /* Transfer mode                */
+    int host;                  /* Host number (for proc)       */
+    Scsi_Cmnd *cur_cmd;                /* Current queued command       */
+    struct tq_struct imm_tq;   /* Polling interupt stuff       */
+    unsigned long jstart;      /* Jiffies at start             */
+    unsigned failed:1;         /* Failure flag                 */
+    unsigned dp:1;             /* Data phase present           */
+    unsigned rd:1;             /* Read data in data phase      */
+    unsigned p_busy:1;         /* Parport sharing busy flag    */
+} imm_struct;
+
+#define IMM_EMPTY \
+{      dev:            NULL,           \
+       base:           -1,             \
+       mode:           IMM_AUTODETECT, \
+       host:           -1,             \
+       cur_cmd:        NULL,           \
+       imm_tq:         {0, 0, imm_interrupt, NULL},    \
+       jstart:         0,              \
+       failed:         0,              \
+       dp:             0,              \
+       rd:             0,              \
+       p_busy:         0               \
+}
+
+#include "imm.h"
+#define NO_HOSTS 4
+static imm_struct imm_hosts[NO_HOSTS] =
+{IMM_EMPTY, IMM_EMPTY, IMM_EMPTY, IMM_EMPTY};
+
+#define IMM_BASE(x)    imm_hosts[(x)].base
+
+int base[NO_HOSTS] =
+{0x03bc, 0x0378, 0x0278, 0x0000};
+
+void imm_wakeup(void *ref)
+{
+    imm_struct *imm_dev = (imm_struct *) ref;
+
+    if (!imm_dev->p_busy)
+        return;
+
+    if (parport_claim(imm_dev->dev)) {
+        printk("imm: bug in imm_wakeup\n");
+        return;
+    }
+    imm_dev->p_busy = 0;
+    imm_dev->base = imm_dev->dev->port->base;
+    if (imm_dev->cur_cmd)
+        imm_dev->cur_cmd->SCp.phase++;
+    return;
+}
+
+int imm_release(struct Scsi_Host *host)
+{
+    int host_no = host->unique_id;
+
+    printk("Releasing imm%i\n", host_no);
+    parport_unregister_device(imm_hosts[host_no].dev);
+    return 0;
+}
+
+static int imm_pb_claim(int host_no)
+{
+    if (parport_claim(imm_hosts[host_no].dev)) {
+        imm_hosts[host_no].p_busy = 1;
+        return 1;
+    }
+
+    if (imm_hosts[host_no].cur_cmd)
+        imm_hosts[host_no].cur_cmd->SCp.phase++;
+    return 0;
+}
+
+#define imm_pb_release(x) parport_release(imm_hosts[(x)].dev)
+
+/***************************************************************************
+ *                   Parallel port probing routines                        *
+ ***************************************************************************/
+
+#ifndef MODULE
+/*
+ * Command line parameters (for built-in driver):
+ *
+ * Syntax:  imm=base[,mode[,use_sg]]
+ *
+ * For example:  imm=0x378   or   imm=0x378,0,3
+ *
+ */
+
+void imm_setup(char *str, int *ints)
+{
+    static int x = 0;
+
+    if (x == 0) {              /* Disable ALL known ports */
+       int i;
+
+       for (i = 0; i < NO_HOSTS; i++)
+           parbus_base[i] = 0x0000;
+    }
+    switch (ints[0]) {
+    case 3:
+       imm_sg = ints[3];
+    case 2:
+       imm_hosts[x].mode = ints[2];
+       parbus_base[x] = ints[1];
+       break;
+    default:
+       printk("IMM: I only use between 2 to 3 parameters.\n");
+       break;
+    }
+    x++;
+}
+#else
+Scsi_Host_Template driver_template = IMM;
+#include  "scsi_module.c"
+#endif
+
+int imm_detect(Scsi_Host_Template * host)
+{
+    struct Scsi_Host *hreg;
+    int ports;
+    int i, nhosts, try_again;
+    struct parport *pb = parport_enumerate();
+
+    printk("imm: Version %s\n", IMM_VERSION);
+    nhosts = 0;
+    try_again = 0;
+
+    if (!pb) {
+        printk("imm: parport reports no devices.\n");
+        return 0;
+    }
+
+  retry_entry:
+    for (i = 0; pb; i++, pb = pb->next) {
+        int modes, ppb;
+
+        imm_hosts[i].dev =
+            parport_register_device(pb, "imm", NULL, imm_wakeup,
+                         NULL, PARPORT_DEV_TRAN, (void *) &imm_hosts[i]);
+
+        /* Claim the bus so it remembers what we do to the control
+         * registers. [ CTR and ECP ]
+         */
+        if (imm_pb_claim(i))
+            while (imm_hosts[i].p_busy)
+                schedule();     /* We are safe to schedule here */
+
+        ppb = IMM_BASE(i) = imm_hosts[i].dev->port->base;
+        w_ctr(ppb, 0x0c);
+        modes = imm_hosts[i].dev->port->modes;
+
+        /* Mode detection works up the chain of speed
+         * This avoids a nasty if-then-else-if-... tree
+         */
+        imm_hosts[i].mode = IMM_NIBBLE;
+
+        if (modes & PARPORT_MODE_PCPS2)
+            imm_hosts[i].mode = IMM_PS2;
+
+        if (modes & PARPORT_MODE_PCECPPS2) {
+            w_ecr(ppb, 0x20);
+            imm_hosts[i].mode = IMM_PS2;
+        }
+        if (modes & PARPORT_MODE_PCECPEPP)
+            w_ecr(ppb, 0x80);
+
+        /* Done configuration */
+        imm_pb_release(i);
+
+        if (imm_init(i)) {
+            parport_unregister_device(imm_hosts[i].dev);
+            continue;
+        }
+        /* now the glue ... */
+        switch (imm_hosts[i].mode) {
+        case IMM_NIBBLE:
+            ports = 3;
+            break;
+        case IMM_PS2:
+            ports = 3;
+            break;
+        case IMM_EPP_8:
+        case IMM_EPP_16:
+        case IMM_EPP_32:
+            ports = 8;
+            break;
+        default:                /* Never gets here */
+            continue;
+        }
+
+        host->can_queue = IMM_CAN_QUEUE;
+        host->sg_tablesize = imm_sg;
+        hreg = scsi_register(host, 0);
+        hreg->io_port = pb->base;
+        hreg->n_io_port = ports;
+        hreg->dma_channel = -1;
+        hreg->unique_id = i;
+        imm_hosts[i].host = hreg->host_no;
+        nhosts++;
+    }
+    if (nhosts == 0) {
+        if (try_again == 1)
+            return 0;
+        try_again = 1;
+        goto retry_entry;
+    } else
+        return 1;               /* return number of hosts detected */
+}
+
+/* This is to give the imm driver a way to modify the timings (and other
+ * parameters) by writing to the /proc/scsi/imm/0 file.
+ * Very simple method really... (To simple, no error checking :( )
+ * Reason: Kernel hackers HATE having to unload and reload modules for
+ * testing...
+ * Also gives a method to use a script to obtain optimum timings (TODO)
+ */
+
+static inline int imm_strncmp(const char *a, const char *b, int len)
+{
+    int loop;
+    for (loop = 0; loop < len; loop++)
+       if (a[loop] != b[loop])
+           return 1;
+
+    return 0;
+}
+
+static inline int imm_proc_write(int hostno, char *buffer, int length)
+{
+    unsigned long x;
+
+    if ((length > 5) && (imm_strncmp(buffer, "mode=", 5) == 0)) {
+       x = simple_strtoul(buffer + 5, NULL, 0);
+       imm_hosts[hostno].mode = x;
+       return length;
+    }
+    printk("imm /proc: invalid variable\n");
+    return (-EINVAL);
+}
+
+int imm_proc_info(char *buffer, char **start, off_t offset,
+                 int length, int hostno, int inout)
+{
+    int i;
+    int len = 0;
+
+    for (i = 0; i < 4; i++)
+       if (imm_hosts[i].host == hostno)
+           break;
+
+    if (inout)
+       return imm_proc_write(i, buffer, length);
+
+    len += sprintf(buffer + len, "Version : %s\n", IMM_VERSION);
+    len += sprintf(buffer + len, "Parport : %s\n", imm_hosts[i].dev->port->name);
+    len += sprintf(buffer + len, "Mode    : %s\n", IMM_MODE_STRING[imm_hosts[i].mode]);
+
+    /* Request for beyond end of buffer */
+    if (offset > len)
+       return 0;
+
+    *start = buffer + offset;
+    len -= offset;
+    if (len > length)
+       len = length;
+    return len;
+}
+
+#if IMM_DEBUG > 0
+#define imm_fail(x,y) printk("imm: imm_fail(%i) from %s at line %d\n",\
+          y, __FUNCTION__, __LINE__); imm_fail_func(x,y);
+static inline void imm_fail_func(int host_no, int error_code)
+#else
+static inline void imm_fail(int host_no, int error_code)
+#endif
+{
+    /* If we fail a device then we trash status / message bytes */
+    if (imm_hosts[host_no].cur_cmd) {
+       imm_hosts[host_no].cur_cmd->result = error_code << 16;
+       imm_hosts[host_no].failed = 1;
+    }
+}
+
+/*
+ * Wait for the high bit to be set.
+ * 
+ * In principle, this could be tied to an interrupt, but the adapter
+ * doesn't appear to be designed to support interrupts.  We spin on
+ * the 0x80 ready bit. 
+ */
+static unsigned char imm_wait(int host_no)
+{
+    int k;
+    unsigned short ppb = IMM_BASE(host_no);
+    unsigned char r;
+
+    w_ctr(ppb, 0x0c);
+
+    k = IMM_SPIN_TMO;
+    do {
+       r = r_str(ppb);
+       k--;
+       udelay(1);
+    }
+    while (!(r & 0x80) && (k));
+
+    /*
+     * STR register (LPT base+1) to SCSI mapping:
+     *
+     * STR      imm     imm
+     * ===================================
+     * 0x80     S_REQ   S_REQ
+     * 0x40     !S_BSY  (????)
+     * 0x20     !S_CD   !S_CD
+     * 0x10     !S_IO   !S_IO
+     * 0x08     (????)  !S_BSY
+     *
+     * imm      imm     meaning
+     * ==================================
+     * 0xf0     0xb8    Bit mask
+     * 0xc0     0x88    ZIP wants more data
+     * 0xd0     0x98    ZIP wants to send more data
+     * 0xe0     0xa8    ZIP is expecting SCSI command data
+     * 0xf0     0xb8    end of transfer, ZIP is sending status
+     */
+    w_ctr(ppb, 0x04);
+    if (k)
+       return (r & 0xb8);
+
+    /* Counter expired - Time out occured */
+    imm_fail(host_no, DID_TIME_OUT);
+    printk("imm timeout in imm_wait\n");
+    return 0;                  /* command timed out */
+}
+
+static int imm_negotiate(imm_struct * tmp)
+{
+    /*
+     * The following is supposedly the IEEE 1248-1994 negotiate
+     * sequence. I have yet to obtain a copy of the above standard
+     * so this is a bit of a guess...
+     *
+     * A fair chunk of this is based on the Linux parport implementation
+     * of IEEE 1284.
+     *
+     * Return 0 if data available
+     *        1 if no data available
+     */
+
+    unsigned short base = tmp->base;
+    unsigned char a, mode;
+
+    switch (tmp->mode) {
+    case IMM_NIBBLE:
+       mode = 0x00;
+       break;
+    case IMM_PS2:
+       mode = 0x01;
+       break;
+    default:
+       return 0;
+    }
+
+    w_ctr(base, 0x04);
+    udelay(5);
+    w_dtr(base, mode);
+    udelay(100);
+    w_ctr(base, 0x06);
+    udelay(5);
+    a = (r_str(base) & 0x20) ? 0 : 1;
+    udelay(5);
+    w_ctr(base, 0x07);
+    udelay(5);
+    w_ctr(base, 0x06);
+
+    if (a) {
+       printk("IMM: IEEE1284 negotiate indicates no data available.\n");
+       imm_fail(tmp->host, DID_ERROR);
+    }
+    return a;
+}
+
+static inline void epp_reset(unsigned short ppb)
+{
+    int i;
+
+    i = r_str(ppb);
+    w_str(ppb, i);
+    w_str(ppb, i & 0xfe);
+}
+
+static inline void ecp_sync(unsigned short ppb)
+{
+    int i;
+
+    if ((r_ecr(ppb) & 0xe0) != 0x80)
+        return;
+
+    for (i = 0; i < 100; i++) {
+        if (r_ecr(ppb) & 0x01)
+            return;
+        udelay(5);
+    }
+    printk("imm: ECP sync failed as data still present in FIFO.\n");
+}
+
+static inline int imm_byte_out(unsigned short base, const char *buffer, int len)
+{
+    int i;
+
+    w_ctr(base, 0x4);          /* aimmrently a sane mode */
+    for (i = len >> 1; i; i--) {
+       w_dtr(base, *buffer++);
+       w_ctr(base, 0x5);       /* Drop STROBE low */
+       w_dtr(base, *buffer++);
+       w_ctr(base, 0x0);       /* STROBE high + INIT low */
+    }
+    w_ctr(base, 0x4);          /* aimmrently a sane mode */
+    return 1;                  /* All went well - we hope! */
+}
+
+static inline int imm_epp_out(unsigned short base, char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--)
+       w_epp(base, *buffer++);
+    return 1;
+}
+
+static inline int imm_nibble_in(unsigned short base, char *buffer, int len)
+{
+    unsigned char h, l;
+    int i;
+
+    /*
+     * The following is based on documented timing signals
+     */
+    w_ctr(base, 0x4);
+    for (i = len; i; i--) {
+       w_ctr(base, 0x6);
+       l = r_str(base);
+       w_ctr(base, 0x5);
+       h = r_str(base);
+       w_ctr(base, 0x4);
+       *buffer++ = (h & 0xf0) | ((l & 0xf0) >> 4);
+    }
+    return 1;                  /* All went well - we hope! */
+}
+
+static inline int imm_byte_in(unsigned short base, char *buffer, int len)
+{
+    int i;
+
+    /*
+     * The following is based on documented timing signals
+     */
+    w_ctr(base, 0x4);
+    for (i = len; i; i--) {
+       w_ctr(base, 0x26);
+       *buffer++ = r_dtr(base);
+       w_ctr(base, 0x25);
+    }
+    return 1;                  /* All went well - we hope! */
+}
+
+static inline int imm_epp_in(unsigned short base, char *buffer, int len)
+{
+    int i;
+    for (i = len; i; i--)
+       *buffer++ = r_epp(base);
+    return 1;
+}
+
+static int imm_out(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = IMM_BASE(host_no);
+
+    r = imm_wait(host_no);
+
+    /*
+     * Make sure that:
+     * a) the SCSI bus is BUSY (device still listening)
+     * b) the device is listening
+     */
+    if ((r & 0x18) != 0x08) {
+       imm_fail(host_no, DID_ERROR);
+       printk("IMM: returned SCSI status %2x\n", r);
+       return 0;
+    }
+    switch (imm_hosts[host_no].mode) {
+    case IMM_EPP_32:
+    case IMM_EPP_16:
+    case IMM_EPP_8:
+        epp_reset(ppb);
+        w_ctr(ppb, 0x4);
+       r = imm_epp_out(ppb, buffer, len);
+        w_ctr(ppb, 0xc);
+        ecp_sync(ppb);
+       break;
+
+    case IMM_NIBBLE:
+    case IMM_PS2:
+       /* 8 bit output, with a loop */
+       r = imm_byte_out(ppb, buffer, len);
+       break;
+
+    default:
+       printk("IMM: bug in imm_out()\n");
+       r = 0;
+    }
+    return r;
+}
+
+static int imm_in(int host_no, char *buffer, int len)
+{
+    int r;
+    unsigned short ppb = IMM_BASE(host_no);
+
+    r = imm_wait(host_no);
+
+    /*
+     * Make sure that:
+     * a) the SCSI bus is BUSY (device still listening)
+     * b) the device is sending data
+     */
+    if ((r & 0x18) != 0x18) {
+       imm_fail(host_no, DID_ERROR);
+       return 0;
+    }
+    switch (imm_hosts[host_no].mode) {
+    case IMM_NIBBLE:
+       /* 4 bit input, with a loop */
+       r = imm_nibble_in(ppb, buffer, len);
+       w_ctr(ppb, 0xc);
+       break;
+
+    case IMM_PS2:
+       /* 8 bit input, with a loop */
+       r = imm_byte_in(ppb, buffer, len);
+       w_ctr(ppb, 0xc);
+       break;
+
+    case IMM_EPP_32:
+    case IMM_EPP_16:
+    case IMM_EPP_8:
+        epp_reset(ppb);
+        w_ctr(ppb, 0x24);
+       r = imm_epp_in(ppb, buffer, len);
+        w_ctr(ppb, 0x2c);
+        ecp_sync(ppb);
+       break;
+
+    default:
+       printk("IMM: bug in imm_ins()\n");
+       r = 0;
+       break;
+    }
+    return r;
+}
+
+static int imm_cpp(unsigned short ppb, unsigned char b)
+{
+    /*
+     * Comments on udelay values refer to the
+     * Command Packet Protocol (CPP) timing diagram.
+     */
+
+    unsigned char s1, s2, s3;
+    w_ctr(ppb, 0x0c);
+    udelay(2);                 /* 1 usec - infinite */
+    w_dtr(ppb, 0xaa);
+    udelay(10);                        /* 7 usec - infinite */
+    w_dtr(ppb, 0x55);
+    udelay(10);                        /* 7 usec - infinite */
+    w_dtr(ppb, 0x00);
+    udelay(10);                        /* 7 usec - infinite */
+    w_dtr(ppb, 0xff);
+    udelay(10);                        /* 7 usec - infinite */
+    s1 = r_str(ppb) & 0xb8;
+    w_dtr(ppb, 0x87);
+    udelay(10);                        /* 7 usec - infinite */
+    s2 = r_str(ppb) & 0xb8;
+    w_dtr(ppb, 0x78);
+    udelay(10);                        /* 7 usec - infinite */
+    s3 = r_str(ppb) & 0x38;
+    /*
+     * Values for b are:
+     * 0000 00aa    Assign address aa to current device
+     * 0010 00aa    Select device aa in EPP Winbond mode
+     * 0010 10aa    Select device aa in EPP mode
+     * 0011 xxxx    Deselect all devices
+     * 0110 00aa    Test device aa
+     * 1101 00aa    Select device aa in ECP mode
+     * 1110 00aa    Select device aa in Compatible mode
+     */
+    w_dtr(ppb, b);
+    udelay(2);                 /* 1 usec - infinite */
+    w_ctr(ppb, 0x0c);
+    udelay(10);                        /* 7 usec - infinite */
+    w_ctr(ppb, 0x0d);
+    udelay(2);                 /* 1 usec - infinite */
+    w_ctr(ppb, 0x0c);
+    udelay(10);                        /* 7 usec - infinite */
+    w_dtr(ppb, 0xff);
+    udelay(10);                        /* 7 usec - infinite */
+
+    /*
+     * The following table is electrical pin values.
+     * (BSY is inverted at the CTR register)
+     *
+     *       BSY  ACK  POut SEL  Fault
+     * S1    0    X    1    1    1
+     * S2    1    X    0    1    1
+     * S3    L    X    1    1    S
+     *
+     * L => Last device in chain
+     * S => Selected
+     *
+     * Observered values for S1,S2,S3 are:
+     * Disconnect => f8/58/78
+     * Connect    => f8/58/70
+     */
+    if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x30))
+       return 1;               /* Connected */
+    if ((s1 == 0xb8) && (s2 == 0x18) && (s3 == 0x38))
+       return 0;               /* Disconnected */
+
+    return -1;                 /* No device present */
+}
+
+static inline int imm_connect(int host_no, int flag)
+{
+    unsigned short ppb = IMM_BASE(host_no);
+
+    imm_cpp(ppb, 0xe0);                /* Select device 0 in compatible mode */
+    imm_cpp(ppb, 0x30);                /* Disconnect all devices */
+
+    if ((imm_hosts[host_no].mode == IMM_EPP_8) ||
+       (imm_hosts[host_no].mode == IMM_EPP_16) ||
+       (imm_hosts[host_no].mode == IMM_EPP_32))
+       return imm_cpp(ppb, 0x28);      /* Select device 0 in EPP mode */
+    return imm_cpp(ppb, 0xe0); /* Select device 0 in compatible mode */
+}
+
+static void imm_disconnect(int host_no)
+{
+    unsigned short ppb = IMM_BASE(host_no);
+
+    imm_cpp(ppb, 0x30);                /* Disconnect all devices */
+}
+
+static int imm_select(int host_no, int target)
+{
+    int k;
+    unsigned short ppb = IMM_BASE(host_no);
+
+    /*
+     * Firstly we want to make sure there is nothing
+     * holding onto the SCSI bus.
+     */
+    w_ctr(ppb, 0xc);
+
+    k = IMM_SELECT_TMO;
+    do {
+       k--;
+    } while ((r_str(ppb) & 0x08) && (k));
+
+    if (!k)
+       return 0;
+
+    /*
+     * Now assert the SCSI ID (HOST and TARGET) on the data bus
+     */
+    w_ctr(ppb, 0x4);
+    w_dtr(ppb, 0x80 | (1 << target));
+    udelay(1);
+
+    /*
+     * Deassert SELIN first followed by STROBE
+     */
+    w_ctr(ppb, 0xc);
+    w_ctr(ppb, 0xd);
+
+    /*
+     * ACK should drop low while SELIN is deasserted.
+     * FAULT should drop low when the SCSI device latches the bus.
+     */
+    k = IMM_SELECT_TMO;
+    do {
+       k--;
+    }
+    while (!(r_str(ppb) & 0x08) && (k));
+
+    /*
+     * Place the interface back into a sane state (status mode)
+     */
+    w_ctr(ppb, 0xc);
+    return (k) ? 1 : 0;
+}
+
+static int imm_init(int host_no)
+{
+    int retv;
+
+#if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE)
+    if (imm_pb_claim(host_no))
+        while (imm_hosts[host_no].p_busy)
+            schedule();         /* We can safe schedule here */
+#endif
+    retv = imm_connect(host_no, 0);
+
+    if (retv == 1) {
+       imm_reset_pulse(IMM_BASE(host_no));
+       udelay(1000);           /* Delay to allow devices to settle */
+       imm_disconnect(host_no);
+       udelay(1000);           /* Another delay to allow devices to settle */
+       retv = device_check(host_no);
+       imm_pb_release(host_no);
+       return retv;
+    }
+
+    imm_pb_release(host_no);
+    return 1;
+}
+
+static inline int imm_send_command(Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    int k;
+
+    /* NOTE: IMM uses byte pairs */
+    for (k = 0; k < cmd->cmd_len; k += 2)
+       if (!imm_out(host_no, &cmd->cmnd[k], 2))
+           return 0;
+    return 1;
+}
+
+/*
+ * The bulk flag enables some optimisations in the data transfer loops,
+ * it should be true for any command that transfers data in integral
+ * numbers of sectors.
+ * 
+ * The driver appears to remain stable if we speed up the parallel port
+ * i/o in this function, but not elsewhere.
+ */
+static int imm_completion(Scsi_Cmnd * cmd)
+{
+    /* Return codes:
+     * -1     Error
+     *  0     Told to schedule
+     *  1     Finished data transfer
+     */
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = IMM_BASE(host_no);
+    unsigned long start_jiffies = jiffies;
+
+    unsigned char r, v;
+    int fast, bulk, status;
+
+    v = cmd->cmnd[0];
+    bulk = ((v == READ_6) ||
+           (v == READ_10) ||
+           (v == WRITE_6) ||
+           (v == WRITE_10));
+
+    /*
+     * We only get here if the drive is ready to comunicate,
+     * hence no need for a full imm_wait.
+     */
+    w_ctr(ppb, 0x0c);
+    r = (r_str(ppb) & 0xb8);
+
+    /*
+     * while (device is not ready to send status byte)
+     *     loop;
+     */
+    while (r != (unsigned char) 0xb8) {
+       /*
+        * If we have been running for more than a full timer tick
+        * then take a rest.
+        */
+       if (jiffies > start_jiffies + 1)
+           return 0;
+
+       /*
+        * FAIL if:
+        * a) Drive status is screwy (!ready && !present)
+        * b) Drive is requesting/sending more data than expected
+        */
+       if (((r & 0x88) != 0x88) || (cmd->SCp.this_residual <= 0)) {
+           imm_fail(host_no, DID_ERROR);
+           return -1;          /* ERROR_RETURN */
+       }
+       /* determine if we should use burst I/O */
+       if (imm_hosts[host_no].rd == 0) {
+           fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 2;
+           status = imm_out(host_no, cmd->SCp.ptr, fast);
+       } else {
+           fast = (bulk && (cmd->SCp.this_residual >= IMM_BURST_SIZE)) ? IMM_BURST_SIZE : 1;
+           status = imm_in(host_no, cmd->SCp.ptr, fast);
+       }
+
+       cmd->SCp.ptr += fast;
+       cmd->SCp.this_residual -= fast;
+
+       if (!status) {
+           imm_fail(host_no, DID_BUS_BUSY);
+           return -1;          /* ERROR_RETURN */
+       }
+       if (cmd->SCp.buffer && !cmd->SCp.this_residual) {
+           /* if scatter/gather, advance to the next segment */
+           if (cmd->SCp.buffers_residual--) {
+               cmd->SCp.buffer++;
+               cmd->SCp.this_residual = cmd->SCp.buffer->length;
+               cmd->SCp.ptr = cmd->SCp.buffer->address;
+
+               /*
+                * Make sure that we transfer even number of bytes
+                * otherwise it makes imm_byte_out() messy.
+                */
+               if (cmd->SCp.this_residual & 0x01) {
+                   cmd->SCp.this_residual++;
+                   printk("IMM: adjusted buffer for 16 bit transfer\n");
+               }
+           }
+       }
+       /* Now check to see if the drive is ready to comunicate */
+       w_ctr(ppb, 0x0c);
+       r = (r_str(ppb) & 0xb8);
+
+       /* If not, drop back down to the scheduler and wait a timer tick */
+       if (!(r & 0x80))
+           return 0;
+    }
+    return 1;                  /* FINISH_RETURN */
+}
+
+/* deprecated synchronous interface */
+int imm_command(Scsi_Cmnd * cmd)
+{
+    static int first_pass = 1;
+    int host_no = cmd->host->unique_id;
+
+    if (first_pass) {
+       printk("imm: using non-queuing interface\n");
+       first_pass = 0;
+    }
+    if (imm_hosts[host_no].cur_cmd) {
+       printk("IMM: bug in imm_command\n");
+       return 0;
+    }
+    imm_hosts[host_no].failed = 0;
+    imm_hosts[host_no].jstart = jiffies;
+    imm_hosts[host_no].cur_cmd = cmd;
+    cmd->result = DID_ERROR << 16;     /* default return code */
+    cmd->SCp.phase = 0;
+
+    imm_pb_claim(host_no);
+
+    while (imm_engine(&imm_hosts[host_no], cmd))
+       schedule();
+
+    if (cmd->SCp.phase)                /* Only disconnect if we have connected */
+       imm_disconnect(cmd->host->unique_id);
+
+    imm_pb_release(host_no);
+    imm_hosts[host_no].cur_cmd = 0;
+    return cmd->result;
+}
+
+/*
+ * Since the IMM itself doesn't generate interrupts, we use
+ * the scheduler's task queue to generate a stream of call-backs and
+ * complete the request when the drive is ready.
+ */
+static void imm_interrupt(void *data)
+{
+    imm_struct *tmp = (imm_struct *) data;
+    Scsi_Cmnd *cmd = tmp->cur_cmd;
+
+    if (!cmd) {
+       printk("IMM: bug in imm_interrupt\n");
+       return;
+    }
+    if (imm_engine(tmp, cmd)) {
+       tmp->imm_tq.data = (void *) tmp;
+       tmp->imm_tq.sync = 0;
+       queue_task(&tmp->imm_tq, &tq_timer);
+       return;
+    }
+    /* Command must of completed hence it is safe to let go... */
+#if IMM_DEBUG > 0
+    switch ((cmd->result >> 16) & 0xff) {
+    case DID_OK:
+       break;
+    case DID_NO_CONNECT:
+       printk("imm: no device at SCSI ID %i\n", cmd->target);
+       break;
+    case DID_BUS_BUSY:
+       printk("imm: BUS BUSY - EPP timeout detected\n");
+       break;
+    case DID_TIME_OUT:
+       printk("imm: unknown timeout\n");
+       break;
+    case DID_ABORT:
+       printk("imm: told to abort\n");
+       break;
+    case DID_PARITY:
+       printk("imm: parity error (???)\n");
+       break;
+    case DID_ERROR:
+       printk("imm: internal driver error\n");
+       break;
+    case DID_RESET:
+       printk("imm: told to reset device\n");
+       break;
+    case DID_BAD_INTR:
+       printk("imm: bad interrupt (???)\n");
+       break;
+    default:
+       printk("imm: bad return code (%02x)\n", (cmd->result >> 16) & 0xff);
+    }
+#endif
+
+    if (cmd->SCp.phase > 1)
+       imm_disconnect(cmd->host->unique_id);
+    if (cmd->SCp.phase > 0)
+       imm_pb_release(cmd->host->unique_id);
+
+    tmp->cur_cmd = 0;
+    cmd->scsi_done(cmd);
+    return;
+}
+
+static int imm_engine(imm_struct * tmp, Scsi_Cmnd * cmd)
+{
+    int host_no = cmd->host->unique_id;
+    unsigned short ppb = IMM_BASE(host_no);
+    unsigned char l = 0, h = 0;
+    int retv, x;
+
+    /* First check for any errors that may of occured
+     * Here we check for internal errors
+     */
+    if (tmp->failed)
+       return 0;
+
+    switch (cmd->SCp.phase) {
+    case 0:                    /* Phase 0 - Waiting for parport */
+       if ((jiffies - tmp->jstart) > HZ) {
+           /*
+            * We waited more than a second
+            * for parport to call us
+            */
+           imm_fail(host_no, DID_BUS_BUSY);
+           return 0;
+       }
+       return 1;               /* wait until imm_wakeup claims parport */
+       /* Phase 1 - Connected */
+    case 1:
+       imm_connect(host_no, CONNECT_EPP_MAYBE);
+       cmd->SCp.phase++;
+
+       /* Phase 2 - We are now talking to the scsi bus */
+    case 2:
+       if (!imm_select(host_no, cmd->target)) {
+           imm_fail(host_no, DID_NO_CONNECT);
+           return 0;
+       }
+       cmd->SCp.phase++;
+
+       /* Phase 3 - Ready to accept a command */
+    case 3:
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       if (!imm_send_command(cmd))
+           return 0;
+       cmd->SCp.phase++;
+
+       /* Phase 4 - Setup scatter/gather buffers */
+    case 4:
+       if (cmd->use_sg) {
+           /* if many buffers are available, start filling the first */
+           cmd->SCp.buffer = (struct scatterlist *) cmd->request_buffer;
+           cmd->SCp.this_residual = cmd->SCp.buffer->length;
+           cmd->SCp.ptr = cmd->SCp.buffer->address;
+       } else {
+           /* else fill the only available buffer */
+           cmd->SCp.buffer = NULL;
+           cmd->SCp.this_residual = cmd->request_bufflen;
+           cmd->SCp.ptr = cmd->request_buffer;
+       }
+       cmd->SCp.buffers_residual = cmd->use_sg;
+       cmd->SCp.phase++;
+       if (cmd->SCp.this_residual & 0x01) {
+           cmd->SCp.this_residual++;
+           printk("IMM: adjusted buffer for 16 bit transfer\n");
+       }
+       /* Phase 5 - Pre-Data transfer stage */
+    case 5:
+       /* Spin lock for BUSY */
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       /* Require negotiation for read requests */
+       x = (r_str(ppb) & 0xb8);
+       tmp->rd = (x & 0x10) ? 1 : 0;
+       tmp->dp = (x & 0x20) ? 0 : 1;
+
+       if ((tmp->dp) && (tmp->rd))
+           if (imm_negotiate(tmp))
+               return 0;
+       cmd->SCp.phase++;
+
+       /* Phase 6 - Data transfer stage */
+    case 6:
+       /* Spin lock for BUSY */
+       w_ctr(ppb, 0x0c);
+       if (!(r_str(ppb) & 0x80))
+           return 1;
+
+       if (tmp->dp) {
+           retv = imm_completion(cmd);
+           if (retv == -1)
+               return 0;
+           if (retv == 0)
+               return 1;
+       }
+       cmd->SCp.phase++;
+
+       /* Phase 7 - Post data transfer stage */
+    case 7:
+       if ((tmp->dp) && (tmp->rd)) {
+           if ((tmp->mode == IMM_NIBBLE) || (tmp->mode == IMM_PS2)) {
+               w_ctr(ppb, 0x4);
+               w_ctr(ppb, 0xc);
+               w_ctr(ppb, 0xe);
+               w_ctr(ppb, 0x4);
+           }
+       }
+       cmd->SCp.phase++;
+
+       /* Phase 8 - Read status/message */
+    case 8:
+       /* Check for data overrun */
+       if (imm_wait(host_no) != (unsigned char) 0xb8) {
+           imm_fail(host_no, DID_ERROR);
+           return 0;
+       }
+       if (imm_negotiate(tmp))
+           return 0;
+       if (imm_in(host_no, &l, 1)) {   /* read status byte */
+           /* Check for optional message byte */
+           if (imm_wait(host_no) == (unsigned char) 0xb8)
+               imm_in(host_no, &h, 1);
+           cmd->result = (DID_OK << 16) + (l & STATUS_MASK);
+       }
+       if ((tmp->mode == IMM_NIBBLE) || (tmp->mode == IMM_PS2)) {
+           w_ctr(ppb, 0x4);
+           w_ctr(ppb, 0xc);
+           w_ctr(ppb, 0xe);
+           w_ctr(ppb, 0x4);
+       }
+       return 0;               /* Finished */
+       break;
+
+    default:
+       printk("imm: Invalid scsi phase\n");
+    }
+    return 0;
+}
+
+int imm_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
+{
+    int host_no = cmd->host->unique_id;
+
+    if (imm_hosts[host_no].cur_cmd) {
+       printk("IMM: bug in imm_queuecommand\n");
+       return 0;
+    }
+    imm_hosts[host_no].failed = 0;
+    imm_hosts[host_no].jstart = jiffies;
+    imm_hosts[host_no].cur_cmd = cmd;
+    cmd->scsi_done = done;
+    cmd->result = DID_ERROR << 16;     /* default return code */
+    cmd->SCp.phase = 0;                /* bus free */
+
+    imm_pb_claim(host_no);
+
+    imm_hosts[host_no].imm_tq.data = imm_hosts + host_no;
+    imm_hosts[host_no].imm_tq.sync = 0;
+    queue_task(&imm_hosts[host_no].imm_tq, &tq_immediate);
+    mark_bh(IMMEDIATE_BH);
+
+    return 0;
+}
+
+/*
+ * Aimmrently the the disk->capacity attribute is off by 1 sector 
+ * for all disk drives.  We add the one here, but it should really
+ * be done in sd.c.  Even if it gets fixed there, this will still
+ * work.
+ */
+int imm_biosparam(Disk * disk, kdev_t dev, int ip[])
+{
+    ip[0] = 0x40;
+    ip[1] = 0x20;
+    ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+    if (ip[2] > 1024) {
+       ip[0] = 0xff;
+       ip[1] = 0x3f;
+       ip[2] = (disk->capacity + 1) / (ip[0] * ip[1]);
+       if (ip[2] > 1023)
+           ip[2] = 1023;
+    }
+    return 0;
+}
+
+int imm_abort(Scsi_Cmnd * cmd)
+{
+    /*
+     * There is no method for aborting commands since Iomega
+     * have tied the SCSI_MESSAGE line high in the interface
+     */
+
+    switch (cmd->SCp.phase) {
+    case 0:                    /* Do not have access to parport */
+    case 1:                    /* Have not connected to interface */
+       cmd->result = DID_ABORT;
+       cmd->done(cmd);
+       return SCSI_ABORT_SUCCESS;
+       break;
+    default:                   /* SCSI command sent, can not abort */
+       return SCSI_ABORT_BUSY;
+       break;
+    }
+}
+
+void imm_reset_pulse(unsigned int base)
+{
+    w_ctr(base, 0x04);
+    w_dtr(base, 0x40);
+    udelay(1);
+    w_ctr(base, 0x0c);
+    w_ctr(base, 0x0d);
+    udelay(50);
+    w_ctr(base, 0x0c);
+    w_ctr(base, 0x04);
+}
+
+int imm_reset(Scsi_Cmnd * cmd, unsigned int x)
+{
+    int host_no = cmd->host->unique_id;
+
+    /*
+     * PHASE1:
+     * Bring the interface crashing down on whatever is running
+     * hopefully this will kill the request.
+     * Bring back up the interface, reset the drive (and anything
+     * attached for that manner)
+     */
+    if (cmd)
+       if (cmd->SCp.phase)
+           imm_disconnect(cmd->host->unique_id);
+
+    imm_connect(host_no, CONNECT_NORMAL);
+    imm_reset_pulse(IMM_BASE(host_no));
+    udelay(1000);              /* delay for devices to settle down */
+    imm_disconnect(host_no);
+    udelay(1000);              /* Additional delay to allow devices to settle down */
+
+    /*
+     * PHASE2:
+     * Sanity check for the sake of mid-level driver
+     */
+    if (!cmd) {
+       printk("imm bus reset called for invalid command.\n");
+       return SCSI_RESET_NOT_RUNNING;
+    }
+    /*
+     * PHASE3:
+     * Flag the current command as having died due to reset
+     */
+    imm_connect(host_no, CONNECT_NORMAL);
+    imm_fail(host_no, DID_RESET);
+
+    /* Since the command was already on the timer queue imm_interrupt
+     * will be called shortly.
+     */
+    return SCSI_RESET_PENDING;
+}
+
+static int device_check(int host_no)
+{
+    /* This routine looks for a device and then attempts to use EPP
+       to send a command. If all goes as planned then EPP is available. */
+
+    static char cmd[6] =
+    {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
+    int loop, old_mode, status, k, ppb = IMM_BASE(host_no);
+    unsigned char l;
+
+    old_mode = imm_hosts[host_no].mode;
+    for (loop = 0; loop < 8; loop++) {
+        /* Attempt to use EPP for Test Unit Ready */
+        if ((ppb & 0x0007) == 0x0000)
+            imm_hosts[host_no].mode = IMM_EPP_32;
+
+      second_pass:
+        imm_connect(host_no, CONNECT_EPP_MAYBE);
+        /* Select SCSI device */
+        if (!imm_select(host_no, loop)) {
+            imm_disconnect(host_no);
+            continue;
+        }
+        printk("imm: Found device at ID %i, Attempting to use %s\n", loop,
+               IMM_MODE_STRING[imm_hosts[host_no].mode]);
+
+        /* Send SCSI command */
+        status = 1;
+        w_ctr(ppb, 0x0c);
+        for (l = 0; (l < 3) && (status); l++)
+            status = imm_out(host_no, &cmd[l<<1], 2);
+
+        if (!status) {
+            imm_disconnect(host_no);
+            imm_connect(host_no, CONNECT_EPP_MAYBE);
+            w_dtr(ppb, 0x40);
+            w_ctr(ppb, 0x08);
+            udelay(30);
+            w_ctr(ppb, 0x0c);
+            udelay(1000);
+            imm_disconnect(host_no);
+            udelay(1000);
+            if (imm_hosts[host_no].mode == IMM_EPP_32) {
+                imm_hosts[host_no].mode = old_mode;
+                goto second_pass;
+            }
+            printk("imm: Unable to establish communication, aborting driver load.\n");
+            return 1;
+        }
+        w_ctr(ppb, 0x0c);
+
+        k = 1000000;            /* 1 Second */
+        do {
+            l = r_str(ppb);
+            k--;
+            udelay(1);
+        } while (!(l & 0x80) && (k));
+
+        l &= 0xb8;
+
+        if (l != 0xb8) {
+            imm_disconnect(host_no);
+            imm_connect(host_no, CONNECT_EPP_MAYBE);
+           imm_reset_pulse(IMM_BASE(host_no));
+            udelay(1000);
+            imm_disconnect(host_no);
+            udelay(1000);
+            if (imm_hosts[host_no].mode == IMM_EPP_32) {
+                imm_hosts[host_no].mode = old_mode;
+                goto second_pass;
+            }
+            printk("imm: Unable to establish communication, aborting driver load.\n");
+            return 1;
+        }
+        imm_disconnect(host_no);
+        printk("imm: Communication established with ID %i using %s\n", loop,
+               IMM_MODE_STRING[imm_hosts[host_no].mode]);
+        imm_connect(host_no, CONNECT_EPP_MAYBE);
+       imm_reset_pulse(IMM_BASE(host_no));
+        udelay(1000);
+        imm_disconnect(host_no);
+        udelay(1000);
+        return 0;
+    }
+    printk("imm: No devices found, aborting driver load.\n");
+    return 1;
+}
+
diff --git a/drivers/scsi/imm.h b/drivers/scsi/imm.h
new file mode 100644 (file)
index 0000000..2818603
--- /dev/null
@@ -0,0 +1,166 @@
+/*  Driver for the Iomega MatchMaker parallel port SCSI HBA embedded in 
+ * the Iomega ZIP Plus drive
+ * 
+ * (c) 1998     David Campbell    campbell@torque.net
+ *
+ * Please note that I live in Perth, Western Australia. GMT+0800
+ */
+
+#ifndef _IMM_H
+#define _IMM_H
+
+#define   IMM_VERSION   "2.00"
+
+/* 
+ * 10 Apr 1998 (Good Friday) - Received EN144302 by email from Iomega.
+ * Scarry thing is the level of support from one of their managers.
+ * The onus is now on us (the developers) to shut up and start coding.
+ *                                             11Apr98 [ 0.10 ]
+ *
+ * --- SNIP ---
+ *
+ * It manages to find the drive which is a good start. Writing data during
+ * data phase is known to be broken (due to requirements of two byte writes).
+ * Removing "Phase" debug messages.
+ *
+ * PS: Took four hours of coding after I bought a drive.
+ *     ANZAC Day (Aus "War Veterans Holiday")  25Apr98 [ 0.14 ]
+ *
+ * Ten minutes later after a few fixes.... (LITERALLY!!!)
+ * Have mounted disk, copied file, dismounted disk, remount disk, diff file
+ *                    -----  It actually works!!! -----
+ *                                             25Apr98 [ 0.15 ]
+ *
+ * Twenty minutes of mucking around, rearanged the IEEE negotiate mechanism.
+ * Now have byte mode working (only EPP and ECP to go now... :=)
+ *                                             26Apr98 [ 0.16 ]
+ *
+ * Thirty minutes of further coding results in EPP working on my machine.
+ *                                             27Apr98 [ 0.17 ]
+ *
+ * Due to work commitments and inability to get a "true" ECP mode functioning
+ * I have decided to code the parport support into imm.
+ *                                             09Jun98 [ 0.18 ]
+ *
+ * Driver is now out of beta testing.
+ * Support for parport has been added.
+ * Now distributed with the ppa driver.
+ *                                             12Jun98 [ 2.00 ]
+ *
+ * Err.. It appears that imm-2.00 was broken....
+ *                                             18Jun98 [ 2.01 ]
+ *
+ * Patch applied to sync this against the Linux 2.1.x kernel code
+ * Included qboot_zip.sh
+ *                                             21Jun98 [ 2.02 ]
+ */
+/* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
+
+#ifdef IMM_CODE
+#include  <linux/stddef.h>
+#include  <linux/module.h>
+#include  <linux/kernel.h>
+#include  <linux/tqueue.h>
+#include  <linux/ioport.h>
+#include  <linux/delay.h>
+#include  <linux/proc_fs.h>
+#include  <linux/stat.h>
+#include  <linux/blk.h>
+#include  <linux/sched.h>
+#include  <linux/interrupt.h>
+
+#include  <asm/io.h>
+#include  "sd.h"
+#include  "hosts.h"
+/* batteries not included :-) */
+
+/*
+ * modes in which the driver can operate 
+ */
+#define   IMM_AUTODETECT        0      /* Autodetect mode                */
+#define   IMM_NIBBLE            1      /* work in standard 4 bit mode    */
+#define   IMM_PS2               2      /* PS/2 byte mode         */
+#define   IMM_EPP_8             3      /* EPP mode, 8 bit                */
+#define   IMM_EPP_16            4      /* EPP mode, 16 bit               */
+#define   IMM_EPP_32            5      /* EPP mode, 32 bit               */
+#define   IMM_UNKNOWN           6      /* Just in case...                */
+
+static char *IMM_MODE_STRING[] =
+{
+    "Autodetect",
+    "SPP",
+    "PS/2",
+    "EPP 8 bit",
+    "EPP 16 bit",
+    "EPP 32 bit",
+    "Unknown"};
+
+/* This is a global option */
+int imm_sg = SG_ALL;           /* enable/disable scatter-gather. */
+
+/* other options */
+#define IMM_CAN_QUEUE   1      /* use "queueing" interface */
+#define IMM_BURST_SIZE 512     /* data burst size */
+#define IMM_SELECT_TMO  500    /* 500 how long to wait for target ? */
+#define IMM_SPIN_TMO    5000   /* 50000 imm_wait loop limiter */
+#define IMM_DEBUG      0       /* debuging option */
+#define IN_EPP_MODE(x) (x == IMM_EPP_8 || x == IMM_EPP_16 || x == IMM_EPP_32)
+
+/* args to imm_connect */
+#define CONNECT_EPP_MAYBE 1
+#define CONNECT_NORMAL  0
+
+#define inb_x inb
+#define r_dtr(x)        (unsigned char)inb_x((x))
+#define r_str(x)        (unsigned char)inb_x((x)+1)
+#define r_ctr(x)        (unsigned char)inb_x((x)+2)
+#define r_epp(x)        (unsigned char)inb_x((x)+4)
+#define r_fifo(x)       (unsigned char)inb_x((x)+0x400)
+#define r_ecr(x)        (unsigned char)inb_x((x)+0x402)
+
+#define outb_x outb
+#define w_dtr(x,y)      outb_x(y, (x))
+#define w_str(x,y)      outb_x(y, (x)+1)
+#define w_ctr(x,y)      outb_x(y, (x)+2)
+#define w_epp(x,y)      outb_x(y, (x)+4)
+#define w_fifo(x,y)     outb_x(y, (x)+0x400)
+#define w_ecr(x,y)      outb_x(y, (x)+0x402)
+
+static int imm_engine(imm_struct *, Scsi_Cmnd *);
+static int imm_in(int, char *, int);
+static int imm_init(int);
+static void imm_interrupt(void *);
+static int imm_out(int, char *, int);
+
+struct proc_dir_entry proc_scsi_imm =
+{PROC_SCSI_PPA, 3, "imm", S_IFDIR | S_IRUGO | S_IXUGO, 2};
+#else
+extern struct proc_dir_entry proc_scsi_imm;
+#define imm_release 0
+#endif
+
+int imm_detect(Scsi_Host_Template *);
+const char *imm_info(struct Scsi_Host *);
+int imm_command(Scsi_Cmnd *);
+int imm_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
+int imm_abort(Scsi_Cmnd *);
+int imm_reset(Scsi_Cmnd *, unsigned int);
+int imm_proc_info(char *, char **, off_t, int, int, int);
+int imm_biosparam(Disk *, kdev_t, int *);
+
+#define IMM {  proc_dir:               &proc_scsi_imm,                 \
+               proc_info:              imm_proc_info,                  \
+               name:                   "Iomega ZIP Plus drive",        \
+               detect:                 imm_detect,                     \
+               release:                imm_release,                    \
+               command:                imm_command,                    \
+               queuecommand:           imm_queuecommand,               \
+               abort:                  imm_abort,                      \
+               reset:                  imm_reset,                      \
+               bios_param:             imm_biosparam,                  \
+               this_id:                7,                              \
+               sg_tablesize:           SG_ALL,                         \
+               cmd_per_lun:            1,                              \
+               use_clustering:         ENABLE_CLUSTERING               \
+}
+#endif                         /* _IMM_H */
index 854f9e539e10fc4bc63569508e348af0af86450f..8ca70d46a91ae608aaa83e3c64c051b62d46b02b 100644 (file)
@@ -22,6 +22,7 @@
 #include "sd.h"
 #include "hosts.h"
 int ppa_release(struct Scsi_Host *);
+static void ppa_reset_pulse(unsigned int base);
 
 typedef struct {
     struct pardevice *dev;     /* Parport device entry         */
@@ -35,16 +36,16 @@ typedef struct {
     unsigned int p_busy:1;     /* Parport sharing busy flag    */
 } ppa_struct;
 
-#define PPA_EMPTY \
-{NULL,         /* dev */       \
--1,            /* base */      \
-PPA_AUTODETECT,        /* mode */      \
--1,            /* host */      \
-NULL,          /* cur_cmd */   \
-{0, 0, ppa_interrupt, NULL},   \
-0,             /* jstart */    \
-0,             /* failed */    \
-0              /* p_busy */    \
+#define PPA_EMPTY      \
+{      dev:            NULL,           \
+       base:           -1,             \
+       mode:           PPA_AUTODETECT, \
+       host:           -1,             \
+       cur_cmd:        NULL,           \
+       ppa_tq:         {0, 0, ppa_interrupt, NULL},    \
+       jstart:         0,              \
+       failed:         0,              \
+       p_busy:         0               \
 }
 
 #include  "ppa.h"
@@ -139,7 +140,8 @@ int ppa_detect(Scsi_Host_Template * host)
         */
        if (ppa_pb_claim(i))
            while (ppa_hosts[i].p_busy)
-               schedule(); /* Whe can safe schedule() here */
+               schedule();     /* We are safe to schedule here */
+
        ppb = PPA_BASE(i) = ppa_hosts[i].dev->port->base;
        w_ctr(ppb, 0x0c);
        modes = ppa_hosts[i].dev->port->modes;
@@ -557,7 +559,7 @@ static inline int ppa_epp_out(unsigned short epp_p, unsigned short str_p, const
     int i;
     for (i = len; i; i--) {
        outb(*buffer++, epp_p);
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 2
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
        if (inb(str_p) & 0x01)
            return 0;
 #endif
@@ -588,14 +590,12 @@ static int ppa_out(int host_no, char *buffer, int len)
     case PPA_EPP_8:
        epp_reset(ppb);
        w_ctr(ppb, 0x4);
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 1
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
        r = ppa_epp_out(ppb + 4, ppb + 1, buffer, len);
 #else
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC == 0
        if (!(((long) buffer | len) & 0x03))
            outsl(ppb + 4, buffer, len >> 2);
        else
-#endif
            outsb(ppb + 4, buffer, len);
        w_ctr(ppb, 0xc);
        r = !(r_str(ppb) & 0x01);
@@ -616,7 +616,7 @@ static inline int ppa_epp_in(int epp_p, int str_p, char *buffer, int len)
     int i;
     for (i = len; i; i--) {
        *buffer++ = inb(epp_p);
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 2
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
        if (inb(str_p) & 0x01)
            return 0;
 #endif
@@ -655,14 +655,12 @@ static int ppa_in(int host_no, char *buffer, int len)
     case PPA_EPP_8:
        epp_reset(ppb);
        w_ctr(ppb, 0x24);
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC > 1
+#ifdef CONFIG_SCSI_PPA_HAVE_PEDANTIC
        r = ppa_epp_in(ppb + 4, ppb + 1, buffer, len);
 #else
-#if CONFIG_SCSI_PPA_HAVE_PEDANTIC == 0
        if (!(((long) buffer | len) & 0x03))
            insl(ppb + 4, buffer, len >> 2);
        else
-#endif
            insb(ppb + 4, buffer, len);
        w_ctr(ppb, 0x2c);
        r = !(r_str(ppb) & 0x01);
@@ -773,7 +771,7 @@ static int ppa_init(int host_no)
 #if defined(CONFIG_PARPORT) || defined(CONFIG_PARPORT_MODULE)
     if (ppa_pb_claim(host_no))
        while (ppa_hosts[host_no].p_busy)
-           schedule(); /* Whe can safe schedule() here */
+           schedule();         /* We can safe schedule here */
 #endif
 
     ppa_disconnect(host_no);
@@ -789,16 +787,11 @@ static int ppa_init(int host_no)
     if ((r_str(ppb) & 0x08) == 0x00)
        retv--;
 
-    /* This is a SCSI BUS reset signal */
-    if (!retv) {
-       w_dtr(ppb, 0x40);
-       w_ctr(ppb, 0x08);
-       udelay(30);
-       w_ctr(ppb, 0x0c);
-       mdelay(1);              /* Allow devices to settle down */
-    }
+    if (!retv)
+       ppa_reset_pulse(ppb);
+    udelay(1000);              /* Allow devices to settle down */
     ppa_disconnect(host_no);
-    mdelay(1);         /* Another delay to allow devices to settle */
+    udelay(1000);              /* Another delay to allow devices to settle */
 
     if (!retv)
        retv = device_check(host_no);
@@ -989,6 +982,7 @@ static void ppa_interrupt(void *data)
        ppa_disconnect(cmd->host->unique_id);
     if (cmd->SCp.phase > 0)
        ppa_pb_release(cmd->host->unique_id);
+
     tmp->cur_cmd = 0;
     cmd->scsi_done(cmd);
     return;
@@ -1017,7 +1011,7 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
            ppa_fail(host_no, DID_BUS_BUSY);
            return 0;
        }
-       return 1; /* wait that ppa_wakeup claims parport */
+       return 1;               /* wait until ppa_wakeup claims parport */
     case 1:                    /* Phase 1 - Connected */
        {                       /* Perform a sanity check for cable unplugged */
            int retv = 2;       /* Failed */
@@ -1032,7 +1026,7 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
            if ((r_str(ppb) & 0x08) == 0x00)
                retv--;
 
-           if (retv) {
+           if (retv)
                if ((jiffies - tmp->jstart) > (1 * HZ)) {
                    printk("ppa: Parallel port cable is unplugged!!\n");
                    ppa_fail(host_no, DID_BUS_BUSY);
@@ -1041,7 +1035,6 @@ static int ppa_engine(ppa_struct * tmp, Scsi_Cmnd * cmd)
                    ppa_disconnect(host_no);
                    return 1;   /* Try again in a jiffy */
                }
-           }
            cmd->SCp.phase++;
        }
 
@@ -1136,7 +1129,7 @@ int ppa_queuecommand(Scsi_Cmnd * cmd, void (*done) (Scsi_Cmnd *))
 }
 
 /*
- * Apparently the disk->capacity attribute is off by 1 sector 
+ * Apparently the the disk->capacity attribute is off by 1 sector 
  * for all disk drives.  We add the one here, but it should really
  * be done in sd.c.  Even if it gets fixed there, this will still
  * work.
@@ -1158,6 +1151,7 @@ int ppa_biosparam(Disk * disk, kdev_t dev, int ip[])
 
 int ppa_abort(Scsi_Cmnd * cmd)
 {
+    int host_no = cmd->host->unique_id;
     /*
      * There is no method for aborting commands since Iomega
      * have tied the SCSI_MESSAGE line high in the interface
@@ -1166,60 +1160,37 @@ int ppa_abort(Scsi_Cmnd * cmd)
     switch (cmd->SCp.phase) {
     case 0:                    /* Do not have access to parport */
     case 1:                    /* Have not connected to interface */
-       cmd->result = DID_ABORT;
-       cmd->done(cmd);
-       return SCSI_ABORT_SUCCESS;
+       ppa_hosts[host_no].cur_cmd = NULL;      /* Forget the problem */
+       return SUCCESS;
        break;
     default:                   /* SCSI command sent, can not abort */
-       return SCSI_ABORT_BUSY;
+       return FAILED;
        break;
     }
 }
 
-int ppa_reset(Scsi_Cmnd * cmd, unsigned int x)
+static void ppa_reset_pulse(unsigned int base)
+{
+    w_dtr(base, 0x40);
+    w_ctr(base, 0x8);
+    udelay(30);
+    w_ctr(base, 0xc);
+}
+
+int ppa_reset(Scsi_Cmnd * cmd)
 {
     int host_no = cmd->host->unique_id;
-    int ppb = PPA_BASE(host_no);
 
-    /*
-     * PHASE1:
-     * Bring the interface crashing down on whatever is running
-     * hopefully this will kill the request.
-     * Bring back up the interface, reset the drive (and anything
-     * attached for that manner)
-     */
-    if (cmd)
-       if (cmd->SCp.phase)
-           ppa_disconnect(cmd->host->unique_id);
+    if (cmd->SCp.phase)
+       ppa_disconnect(host_no);
+    ppa_hosts[host_no].cur_cmd = NULL; /* Forget the problem */
 
     ppa_connect(host_no, CONNECT_NORMAL);
-    w_dtr(ppb, 0x40);
-    w_ctr(ppb, 0x8);
-    udelay(30);
-    w_ctr(ppb, 0xc);
-    mdelay(1);         /* delay for devices to settle down */
+    ppa_reset_pulse(PPA_BASE(host_no));
+    udelay(1000);              /* device settle delay */
     ppa_disconnect(host_no);
-    mdelay(1);         /* Additional delay to allow devices to settle down */
-
-    /*
-     * PHASE2:
-     * Sanity check for the sake of mid-level driver
-     */
-    if (!cmd) {
-       printk("ppa bus reset called for invalid command.\n");
-       return SCSI_RESET_NOT_RUNNING;
-    }
-    /*
-     * PHASE3:
-     * Flag the current command as having died due to reset
-     */
-    ppa_connect(host_no, CONNECT_NORMAL);
-    ppa_fail(host_no, DID_RESET);
-
-    /* Since the command was already on the timer queue ppa_interrupt
-     * will be called shortly.
-     */
-    return SCSI_RESET_PENDING;
+    udelay(1000);              /* device settle delay */
+    return SUCCESS;
 }
 
 static int device_check(int host_no)
@@ -1261,9 +1232,9 @@ static int device_check(int host_no)
            w_ctr(ppb, 0x08);
            udelay(30);
            w_ctr(ppb, 0x0c);
-           mdelay(1);
+           udelay(1000);
            ppa_disconnect(host_no);
-           mdelay(1);
+           udelay(1000);
            if (ppa_hosts[host_no].mode == PPA_EPP_32) {
                ppa_hosts[host_no].mode = old_mode;
                goto second_pass;
@@ -1284,13 +1255,10 @@ static int device_check(int host_no)
        if (l != 0xf0) {
            ppa_disconnect(host_no);
            ppa_connect(host_no, CONNECT_EPP_MAYBE);
-           w_dtr(ppb, 0x40);
-           w_ctr(ppb, 0x08);
-           udelay(30);
-           w_ctr(ppb, 0x0c);
-           mdelay(1);
+           ppa_reset_pulse(ppb);
+           udelay(1000);
            ppa_disconnect(host_no);
-           mdelay(1);
+           udelay(1000);
            if (ppa_hosts[host_no].mode == PPA_EPP_32) {
                ppa_hosts[host_no].mode = old_mode;
                goto second_pass;
@@ -1301,6 +1269,11 @@ static int device_check(int host_no)
        ppa_disconnect(host_no);
        printk("ppa: Communication established with ID %i using %s\n", loop,
               PPA_MODE_STRING[ppa_hosts[host_no].mode]);
+       ppa_connect(host_no, CONNECT_EPP_MAYBE);
+       ppa_reset_pulse(ppb);
+       udelay(1000);
+       ppa_disconnect(host_no);
+       udelay(1000);
        return 0;
     }
     printk("ppa: No devices found, aborting driver load.\n");
index 41f03585548d087d10ae5a1b1f99d858cfc786e9..c58dd39b2abd6d376164876f7404aa33f7560124 100644 (file)
 #ifndef _PPA_H
 #define _PPA_H
 
-#define   PPA_VERSION   "1.39a"
-
-/* Use the following to enable certain chipset support
- * Default is PEDANTIC = 3
- */
-#include <linux/config.h> /* for CONFIG_SCSI_PPA_HAVE_PEDANTIC */
-#ifndef CONFIG_SCSI_PPA_HAVE_PEDANTIC
-#define CONFIG_SCSI_PPA_HAVE_PEDANTIC  3
-#endif
+#define   PPA_VERSION   "2.01"
 
 /* 
  * this driver has been hacked by Matteo Frigo (athena@theory.lcs.mit.edu)
  *
  * [ Stuff removed ]
  *
- * Compiled against 2.1.53.
- *     Rebuilt ppa_abort() function, should handle unplugged cable.
- *                                                     [1.35s]
- *
- * PPA now auto probes for EPP on base address which are aligned on
- * 8 byte boundaries (0x278 & 0x378) using the attached devices.
- * This hopefully avoids the nasty problem of trying to detect EPP.
- *     Tested on 2.1.53                                [1.36]
+ * Corrected ppa.h for 2.1.x kernels (>=2.1.85)
+ * Modified "Nat Semi Kludge" for extended chipsets
+ *                                                     [1.41]
  *
- * The id_probe utility no longer performs read/write tests.
- * Additional code included for checking the Intel ECP bug
- * (Bit 0 of STR stuck low which fools the EPP detection routine)
- *                                                     [1.37]
+ * Fixed id_probe for EPP 1.9 chipsets (misdetected as EPP 1.7)
+ *                                                     [1.42]
  *
- * Oops! Got the bit sign mixed up for the Intel bug check.
- * Found that an additional delay is required during SCSI resets
- * to allow devices to settle down.
- *                                                     [1.38]
+ * Development solely for 2.1.x kernels from now on!
+ *                                                     [2.00]
  *
- * Fixed all problems in the parport sharing scheme. Now ppa can be safe
- * used with lp or other parport devices on the same parallel port.
- *             1997 by Andrea Arcangeli
- *                                                     [1.39]
+ * Hack and slash at the init code (EPP device check routine)
+ * Added INSANE option.
+ *                                                     [2.01]
  *
- * Little fix in ppa engine to ensure that ppa don' t release parport
- * or disconnect in wrong cases.
- *             1997 by Andrea Arcangeli
- *                                                     [1.39a]
+ * Patch applied to sync against the 2.1.x kernel code
+ * Included qboot_zip.sh
+ *                                                     [2.02]
  */
 /* ------ END OF USER CONFIGURABLE PARAMETERS ----- */
 
@@ -117,6 +98,23 @@ int ppa_sg = SG_ALL;                /* enable/disable scatter-gather. */
 #define CONNECT_EPP_MAYBE 1
 #define CONNECT_NORMAL  0
 
+/* INSANE code */
+#define PPA_INSANE 0
+#if PPA_INSANE > 0
+#define r_dtr(x)        (unsigned char)inb_p((x))
+#define r_str(x)        (unsigned char)inb_p((x)+1)
+#define r_ctr(x)        (unsigned char)inb_p((x)+2)
+#define r_epp(x)        (unsigned char)inb_p((x)+4)
+#define r_fifo(x)       (unsigned char)inb_p((x)+0x400)
+#define r_ecr(x)        (unsigned char)inb_p((x)+0x402)
+
+#define w_dtr(x,y)      outb_p(y, (x))
+#define w_str(x,y)      outb_p(y, (x)+1)
+#define w_ctr(x,y)      outb_p(y, (x)+2)
+#define w_epp(x,y)      outb_p(y, (x)+4)
+#define w_fifo(x,y)     outb_p(y, (x)+0x400)
+#define w_ecr(x,y)      outb_p(y, (x)+0x402)
+#else /* PPA_INSANE */
 #define r_dtr(x)        (unsigned char)inb((x))
 #define r_str(x)        (unsigned char)inb((x)+1)
 #define r_ctr(x)        (unsigned char)inb((x)+2)
@@ -130,6 +128,7 @@ int ppa_sg = SG_ALL;                /* enable/disable scatter-gather. */
 #define w_epp(x,y)      outb(y, (x)+4)
 #define w_fifo(x,y)     outb(y, (x)+0x400)
 #define w_ecr(x,y)      outb(y, (x)+0x402)
+#endif /* PPA_INSANE */
 
 static int ppa_engine(ppa_struct *, Scsi_Cmnd *);
 static int ppa_in(int, char *, int);
@@ -149,23 +148,25 @@ const char *ppa_info(struct Scsi_Host *);
 int ppa_command(Scsi_Cmnd *);
 int ppa_queuecommand(Scsi_Cmnd *, void (*done) (Scsi_Cmnd *));
 int ppa_abort(Scsi_Cmnd *);
-int ppa_reset(Scsi_Cmnd *, unsigned int);
+int ppa_reset(Scsi_Cmnd *);
 int ppa_proc_info(char *, char **, off_t, int, int, int);
 int ppa_biosparam(Disk *, kdev_t, int *);
 
-#define PPA {  proc_dir:               &proc_scsi_ppa,                 \
-               proc_info:              ppa_proc_info,                  \
-               name:                   "Iomega parport ZIP drive",     \
-               detect:                 ppa_detect,                     \
-               release:                ppa_release,                    \
-               command:                ppa_command,                    \
-               queuecommand:           ppa_queuecommand,               \
-               abort:                  ppa_abort,                      \
-               reset:                  ppa_reset,                      \
-               bios_param:             ppa_biosparam,                  \
-               this_id:                -1,                             \
-               sg_tablesize:           SG_ALL,                         \
-               cmd_per_lun:            1,                              \
-               use_clustering:         ENABLE_CLUSTERING               \
+#define PPA {  proc_dir:                       &proc_scsi_ppa,         \
+               proc_info:                      ppa_proc_info,          \
+               name:                           "Iomega parport ZIP drive",\
+               detect:                         ppa_detect,             \
+               release:                        ppa_release,            \
+               command:                        ppa_command,            \
+               queuecommand:                   ppa_queuecommand,       \
+               eh_abort_handler:               ppa_abort,              \
+               eh_device_reset_handler:        NULL,                   \
+               eh_bus_reset_handler:           ppa_reset,              \
+               eh_host_reset_handler:          ppa_reset,              \
+               bios_param:                     ppa_biosparam,          \
+               this_id:                        -1,                     \
+               sg_tablesize:                   SG_ALL,                 \
+               cmd_per_lun:                    1,                      \
+               use_clustering:                 ENABLE_CLUSTERING       \
 }
 #endif                         /* _PPA_H */
index da56b84efc6a20c4647d1e1d1eeaba0290ce42f9..5c45e1e7348ef4aa6e5711810d65feb8aacd335f 100644 (file)
@@ -90,14 +90,6 @@ static const char RCSid[] = "$Header: /vger/u4/cvs/linux/drivers/scsi/scsi.c,v 1
 # error You lose.
 #endif
 
-#define MAX_SCSI_DEVICE_CODE 10
-
-#ifdef DEBUG
-    #define SCSI_TIMEOUT (5*HZ)
-#else
-    #define SCSI_TIMEOUT (2*HZ)
-#endif
-
 #define MIN_RESET_DELAY (2*HZ)
 
 /* Do not call reset on error if we just did a reset within 15 sec. */
index 7824dff31f58f99b566cc64ed9033ad0c536a0fa..045ec15da7df5104c76bebaba751a06c438b4326 100644 (file)
 #define MAX_SCSI_DEVICE_CODE 10
 extern const char *const scsi_device_types[MAX_SCSI_DEVICE_CODE];
 
+#ifdef DEBUG
+    #define SCSI_TIMEOUT (5*HZ)
+#else
+    #define SCSI_TIMEOUT (2*HZ)
+#endif
+
 /*
  *  Use these to separate status msg and our bytes
  *
index b23a61f74153c1b5a0df26e599f0773747360aa8..b43addc1b923f48ad51ce456542104624ee1197a 100644 (file)
@@ -17,37 +17,53 @@ fi
 
 dep_tristate 'Support for Turtle Beach MultiSound Classic, Tahiti, Monterey' CONFIG_SOUND_MSNDCLAS $CONFIG_SOUND
 if [ "$CONFIG_SOUND_MSNDCLAS" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "m" ]; then
-   string '  Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin"
-   string '  Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin"
+   if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
+     comment 'Compiled-in MSND Classic support requires firmware during compilation.'
+     define_bool CONFIG_MSNDCLAS_HAVE_BOOT y
+     string '  Full pathname of MSNDINIT.BIN firmware file' CONFIG_MSNDCLAS_INIT_FILE "/etc/sound/msndinit.bin"
+     string '  Full pathname of MSNDPERM.BIN firmware file' CONFIG_MSNDCLAS_PERM_FILE "/etc/sound/msndperm.bin"
+   else
+     define_bool CONFIG_MSNDCLAS_HAVE_BOOT n
+   fi
 fi
 if [ "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
    int 'MSND Classic IRQ 5,7,9,10,11,12' CONFIG_MSNDCLAS_IRQ 5
-   hex 'MSND Classic Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000
+   hex 'MSND Classic memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDCLAS_MEM D0000
    hex 'MSND Classic I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDCLAS_IO 290
 fi
 
 dep_tristate 'Support for Turtle Beach MultiSound Pinnacle, Fiji' CONFIG_SOUND_MSNDPIN $CONFIG_SOUND
 if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDPIN" = "m" ]; then
-   string '  Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin"
-   string '  Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin"
+   if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then
+     comment 'Compiled-in MSND Pinnacle support requires firmware during compilation.'
+     string '  Full pathname of PNDSPINI.BIN firmware file' CONFIG_MSNDPIN_INIT_FILE "/etc/sound/pndspini.bin"
+     string '  Full pathname of PNDSPERM.BIN firmware file' CONFIG_MSNDPIN_PERM_FILE "/etc/sound/pndsperm.bin"
+     define_bool CONFIG_MSNDPIN_HAVE_BOOT y
+   else
+     define_bool CONFIG_MSNDPIN_HAVE_BOOT n
+   fi
 fi
 if [ "$CONFIG_SOUND_MSNDPIN" = "y" ]; then
    int 'MSND Pinnacle IRQ 5,7,9,10,11,12' CONFIG_MSNDPIN_IRQ 5
-   hex 'MSND Pinnacle Memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000
+   hex 'MSND Pinnacle memory B0000,C8000,D0000,D8000,E0000,E8000' CONFIG_MSNDPIN_MEM D0000
    hex 'MSND Pinnacle I/O 210,220,230,240,250,260,290,3E0' CONFIG_MSNDPIN_IO 290
+   bool 'MSND Pinnacle has S/PDIF I/O' CONFIG_MSNDPIN_DIGITAL
    bool 'MSND Pinnacle Non-PnP Mode' CONFIG_MSNDPIN_NONPNP
    if [ "$CONFIG_MSNDPIN_NONPNP" = "y" ]; then
      comment 'MSND Pinnacle DSP section will be configured to above parameters.'
-     hex 'MSDN Pinnacle Config Port 250,260,270' CONFIG_MSNDPIN_CFG 250
+     hex 'MSDN Pinnacle config port 250,260,270' CONFIG_MSNDPIN_CFG 250
      comment 'Pinnacle-specific Device Configuration (0 disables)'
-     hex 'MSDN Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0
-     int 'MSDN Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0
-     hex 'MSDN Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0
-     hex 'MSDN Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0
-     int 'MSDN Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0
-     hex 'MSDN Pinnacle Joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0
+     hex 'MSND Pinnacle MPU I/O (e.g. 330)' CONFIG_MSNDPIN_MPU_IO 0
+     int 'MSND Pinnacle MPU IRQ (e.g. 9)' CONFIG_MSNDPIN_MPU_IRQ 0
+     hex 'MSND Pinnacle IDE I/O 0 (e.g. 170)' CONFIG_MSNDPIN_IDE_IO0 0
+     hex 'MSND Pinnacle IDE I/O 1 (e.g. 376)' CONFIG_MSNDPIN_IDE_IO1 0
+     int 'MSND Pinnacle IDE IRQ (e.g. 15)' CONFIG_MSNDPIN_IDE_IRQ 0
+     hex 'MSDN Pinnacle joystick I/O (e.g. 200)' CONFIG_MSNDPIN_JOYSTICK_IO 0
    fi
 fi
+if [ "$CONFIG_SOUND_MSNDPIN" = "y" -o "$CONFIG_SOUND_MSNDCLAS" = "y" ]; then
+   int 'MSND buffer size (kB)' CONFIG_MSND_FIFOSIZE 128
+fi
 
 dep_tristate 'OSS sound modules' CONFIG_SOUND_OSS $CONFIG_SOUND
 
index f072b7fad39111dd865aa3a01403775b61781b69..5ca95dd5f804a5669b2df23c49458ddb875e311d 100644 (file)
@@ -235,6 +235,50 @@ endif
 
 
 
+# Turtle Beach MultiSound
+
+ifeq ($(CONFIG_MSNDCLAS_HAVE_BOOT),y)
+    msnd_classic.o: msndperm.c msndinit.c
+
+    msndperm.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_PERM_FILE)) bin2hex
+       ./bin2hex msndperm < $(CONFIG_MSNDCLAS_PERM_FILE) > $@
+       @ ( \
+           echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_PERM_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_PERM_FILE)))'; \
+           echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+           echo 'endif' \
+       ) > .$@.boot
+
+    msndinit.c: $(patsubst "%", %, $(CONFIG_MSNDCLAS_INIT_FILE)) bin2hex
+       ./bin2hex msndinit < $(CONFIG_MSNDCLAS_INIT_FILE) > $@
+       @ ( \
+           echo 'ifeq ($(strip $(CONFIG_MSNDCLAS_HAVE_BOOT) $(CONFIG_MSNDCLAS_INIT_FILE)),$$(strip $$(CONFIG_MSNDCLAS_HAVE_BOOT) $$(CONFIG_MSNDCLAS_INIT_FILE)))'; \
+           echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+           echo 'endif' \
+       ) > .$@.boot
+endif
+
+ifeq ($(CONFIG_MSNDPIN_HAVE_BOOT),y)
+    msnd_pinnacle.o: pndsperm.c pndspini.c
+
+    pndsperm.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_PERM_FILE)) bin2hex
+       ./bin2hex pndsperm < $(CONFIG_MSNDPIN_PERM_FILE) > $@
+       @ ( \
+           echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_PERM_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_PERM_FILE)))'; \
+           echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+           echo 'endif' \
+       ) > .$@.boot
+
+    pndspini.c: $(patsubst "%", %, $(CONFIG_MSNDPIN_INIT_FILE)) bin2hex
+       ./bin2hex pndspini < $(CONFIG_MSNDPIN_INIT_FILE) > $@
+       @ ( \
+           echo 'ifeq ($(strip $(CONFIG_MSNDPIN_HAVE_BOOT) $(CONFIG_MSNDPIN_INIT_FILE)),$$(strip $$(CONFIG_MSNDPIN_HAVE_BOOT) $$(CONFIG_MSNDPIN_INIT_FILE)))'; \
+           echo 'FILES_BOOT_UP_TO_DATE += $@'; \
+           echo 'endif' \
+       ) > .$@.boot
+endif
+
+
+
 # PSS (ECHO-ADI2111)
 
 pss.o: pss_boot.h
index 34148d990877a3fd04cba098432cf211e6af55f9..684456c590e45345aff54f85b3b00e07b4cde270 100644 (file)
@@ -2401,7 +2401,6 @@ void attach_ms_sound(struct address_info *hw_config)
 
 void unload_ms_sound(struct address_info *hw_config)
 {
-       int mixer = audio_devs[hw_config->slots[0]]->mixer_dev;
        ad1848_unload(hw_config->io_base + 4,
                      hw_config->irq,
                      hw_config->dma,
index 99e15cb225144d8e1d71f97872f7782ddc9b9fcc..6ffa1d19d85ee47420af63fd9ad9341ad1af0a53 100644 (file)
@@ -534,6 +534,7 @@ int sound_alloc_audiodev(void)
 
 int sound_alloc_mididev(void)
 {
+#ifdef CONFIG_MIDI
        int i = register_sound_midi(&oss_sound_fops);
        if(i==-1)
                return i;
@@ -541,6 +542,9 @@ int sound_alloc_mididev(void)
        if(i>=num_midis)
                num_midis = i + 1;
        return i;
+#else
+       return (-1);
+#endif
 }
 
 int sound_alloc_synthdev(void)
index 607955d23bdc7e47358eaf169d2b5234a734b669..e1af44cef39953f1a134c4293e7fd5d92d9e2624 100644 (file)
@@ -849,7 +849,7 @@ unload_mad16_mpu(struct address_info *hw_config)
 #if defined(CONFIG_MIDI) && defined(CONFIG_MAD16_OLDCARD)
        if (board_type < C929)  /* Early chip. No MPU support. Just SB MIDI */
        {
-               sb_dsp_unload(hw_config);
+               sb_dsp_unload(hw_config, 0);
                return;
        }
 #endif
index ad7ceaa489c4eed9bc885f1a8ad7a9709f85af3a..a3f73ededff387dd2607ea8c9c83df4ee0c66427 100644 (file)
@@ -20,7 +20,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd.c,v 1.9 1998/09/04 18:41:27 andrewtv Exp $
+ * $Id: msnd.c,v 1.16 1998/09/08 04:05:56 andrewtv Exp $
  *
  ********************************************************************/
 
@@ -46,6 +46,7 @@
 #  include <asm/uaccess.h>
 #  include <asm/spinlock.h>
 #endif
+#include <asm/irq.h>
 #include "msnd.h"
 
 #define LOGNAME                        "msnd"
@@ -224,7 +225,7 @@ int msnd_fifo_read(msnd_fifo *f, char *buf, size_t len, int user)
 int msnd_wait_TXDE(multisound_dev_t *dev)
 {
        register unsigned int io = dev->io;
-       register int timeout = 100;
+       register int timeout = 1000;
     
        while(timeout-- > 0)
                if (inb(io + HP_ISR) & HPISR_TXDE)
@@ -236,7 +237,7 @@ int msnd_wait_TXDE(multisound_dev_t *dev)
 int msnd_wait_HC0(multisound_dev_t *dev)
 {
        register unsigned int io = dev->io;
-       register int timeout = 100;
+       register int timeout = 1000;
 
        while(timeout-- > 0)
                if (!(inb(io + HP_CVR) & HPCVR_HC))
@@ -248,17 +249,16 @@ int msnd_wait_HC0(multisound_dev_t *dev)
 int msnd_send_dsp_cmd(multisound_dev_t *dev, BYTE cmd)
 {
        unsigned long flags;
-       
+
        spin_lock_irqsave(&dev->lock, flags);
        if (msnd_wait_HC0(dev) == 0) {
-
                outb(cmd, dev->io + HP_CVR);
                spin_unlock_irqrestore(&dev->lock, flags);
                return 0;
        }
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       printk(KERN_WARNING LOGNAME ": Send DSP command timeout\n");
+       printk(KERN_DEBUG LOGNAME ": Send DSP command timeout\n");
        
        return -EIO;
 }
@@ -269,14 +269,13 @@ int msnd_send_word(multisound_dev_t *dev, unsigned char high,
        register unsigned int io = dev->io;
 
        if (msnd_wait_TXDE(dev) == 0) {
-               
                outb(high, io + HP_TXH);
                outb(mid, io + HP_TXM);
                outb(low, io + HP_TXL);
                return 0;
        }
 
-       printk(KERN_WARNING LOGNAME ": Send host word timeout\n");
+       printk(KERN_DEBUG LOGNAME ": Send host word timeout\n");
 
        return -EIO;
 }
@@ -286,7 +285,6 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
        int i;
 
        if (len % 3 != 0) {
-               
                printk(KERN_WARNING LOGNAME ": Upload host data not multiple of 3!\n");         
                return -EINVAL;
        }
@@ -303,31 +301,27 @@ int msnd_upload_host(multisound_dev_t *dev, char *bin, int len)
 
 int msnd_enable_irq(multisound_dev_t *dev)
 {
-       printk(KERN_DEBUG LOGNAME ": enable_irq: count %d\n", dev->irq_ref);
+       unsigned long flags;
 
-       if (dev->irq_ref++ != 0)
+       if (dev->irq_ref++)
                return 0;
 
        printk(KERN_DEBUG LOGNAME ": Enabling IRQ\n");
-
+       
+       spin_lock_irqsave(&dev->lock, flags);
        if (msnd_wait_TXDE(dev) == 0) {
-
-               unsigned long flags;
-               
-               spin_lock_irqsave(&dev->lock, flags);
-               
                outb(inb(dev->io + HP_ICR) | HPICR_TREQ, dev->io + HP_ICR);
-
                if (dev->type == msndClassic)
                        outb(dev->irqid, dev->io + HP_IRQM);
-
                outb(inb(dev->io + HP_ICR) & ~HPICR_TREQ, dev->io + HP_ICR);
                outb(inb(dev->io + HP_ICR) | HPICR_RREQ, dev->io + HP_ICR);
-
+               enable_irq(dev->irq);
                spin_unlock_irqrestore(&dev->lock, flags);
-
                return 0;
        }
+       spin_unlock_irqrestore(&dev->lock, flags);
+
+       printk(KERN_DEBUG LOGNAME ": Enable IRQ failed\n");
 
        return -EIO;
 }
@@ -336,29 +330,28 @@ int msnd_disable_irq(multisound_dev_t *dev)
 {
        unsigned long flags;
 
-       printk(KERN_DEBUG LOGNAME ": disable_irq: count %d\n", dev->irq_ref);
-
        if (--dev->irq_ref > 0)
                return 0;
 
-       if (dev->irq_ref < 0) {
-               printk(KERN_WARNING LOGNAME ": IRQ ref count is %d\n", dev->irq_ref);
-/*             dev->irq_ref = 0; */
-       }
+       if (dev->irq_ref < 0)
+               printk(KERN_DEBUG LOGNAME ": IRQ ref count is %d\n", dev->irq_ref);
 
        printk(KERN_DEBUG LOGNAME ": Disabling IRQ\n");
-       
-       udelay(50);
 
        spin_lock_irqsave(&dev->lock, flags);
-       outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
-       
-       if (dev->type == msndClassic)
-               outb(HPIRQ_NONE, dev->io + HP_IRQM);
-
+       if (msnd_wait_TXDE(dev) == 0) {
+               outb(inb(dev->io + HP_ICR) & ~HPICR_RREQ, dev->io + HP_ICR);
+               if (dev->type == msndClassic)
+                       outb(HPIRQ_NONE, dev->io + HP_IRQM);
+               disable_irq(dev->irq);
+               spin_unlock_irqrestore(&dev->lock, flags);
+               return 0;
+       }
        spin_unlock_irqrestore(&dev->lock, flags);
 
-       return 0;
+       printk(KERN_DEBUG LOGNAME ": Disable IRQ failed\n");
+
+       return -EIO;
 }
 
 #ifndef LINUX20
index 804cff425c45edec321096fb0a8f8043f1bf5f73..871a3a9652e36c610acf5e2b68278b50338af647 100644 (file)
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd.h,v 1.18 1998/09/04 18:43:40 andrewtv Exp $
+ * $Id: msnd.h,v 1.31 1998/09/10 14:02:58 andrewtv Exp $
  *
  ********************************************************************/
 #ifndef __MSND_H
 #define __MSND_H
 
-#define VERSION                        "0.7.13"
+#define VERSION                        "0.8.2"
 
 #define DEFSAMPLERATE          DSP_DEFAULT_SPEED
 #define DEFSAMPLESIZE          AFMT_U8
 #define DEFCHANNELS            1
 
-#define DEFFIFOSIZE            64
+#define DEFFIFOSIZE            128
 
 #define SNDCARD_MSND           38
 
 
 #define PCTODSP_OFFSET(w)      (USHORT)((w)/2)
 #define PCTODSP_BASED(w)       (USHORT)(((w)/2) + DSP_BASE_ADDR)
+#define DSPTOPC_BASED(w)       (((w) - DSP_BASE_ADDR) * 2)
 
 #ifdef SLOWIO
 #  undef outb
@@ -207,14 +208,10 @@ typedef struct multisound_dev {
        int memid, irqid;
        int irq, irq_ref;
        unsigned char info;
-       char *base;
-#ifndef LINUX20
-       spinlock_t lock;
-#endif
+       volatile BYTE *base;
 
        /* Motorola 56k DSP SMA */
        volatile BYTE *SMA;
-       volatile BYTE *CurDAQD, *CurDARQD;
        volatile BYTE *DAPQ, *DARQ, *MODQ, *MIDQ, *DSPQ;
        volatile WORD *pwDSPQData, *pwMIDQData, *pwMODQData;
 
@@ -222,27 +219,32 @@ typedef struct multisound_dev {
        enum { msndClassic, msndPinnacle } type;
        mode_t mode;
        unsigned long flags;
-#define F_BANKONE                      0
-#define F_INTERRUPT                    1
-#define F_WRITING                      2
-#define F_WRITEBLOCK                   3
-#define F_READING                      4
-#define F_READBLOCK                    5
-#define F_AUDIO_INUSE                  6
-#define F_EXT_MIDI_INUSE               7
-#define F_INT_MIDI_INUSE               8
-#define F_WRITEFLUSH                   9
-#define F_HAVEDIGITAL                  10
+#define F_RESETTING                    0
+#define F_HAVEDIGITAL                  1
+#define F_AUDIO_WRITE_INUSE            2
+#define F_WRITING                      3
+#define F_WRITEBLOCK                   4
+#define F_WRITEFLUSH                   5
+#define F_AUDIO_READ_INUSE             6
+#define F_READING                      7
+#define F_READBLOCK                    8
+#define F_EXT_MIDI_INUSE               9
+#define F_INT_MIDI_INUSE               10
        struct wait_queue *writeblock, *readblock;
        struct wait_queue *writeflush;
+#ifndef LINUX20
+       spinlock_t lock;
+#endif
+       int nresets;
        unsigned long recsrc;
        int left_levels[16];
        int right_levels[16];
        int mixer_mod_count;
        int calibrate_signal;
-       int sample_size;
-       int sample_rate;
-       int channels;
+       int play_sample_size, play_sample_rate, play_channels;
+       int play_ndelay;
+       int rec_sample_size, rec_sample_rate, rec_channels;
+       int rec_ndelay;
        BYTE bCurrentMidiPatch;
        void (*inc_ref)(void);
        void (*dec_ref)(void);
@@ -250,7 +252,7 @@ typedef struct multisound_dev {
        /* Digital audio FIFOs */
        msnd_fifo DAPF, DARF;
        int fifosize;
-       int lastbank;
+       int last_playbank, last_recbank;
 
        /* MIDI in callback */
        void (*midi_in_interrupt)(struct multisound_dev *);
index bdc28ffd087eeaa9209f83aa0f5cee979898780d..25898f8e0744e1cf3efb337273d2217a8fb8c2ff 100644 (file)
@@ -24,7 +24,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  * 
- * $Id: msnd_classic.h,v 1.7 1998/09/03 06:39:47 andrewtv Exp $
+ * $Id: msnd_classic.h,v 1.9 1998/09/10 04:11:18 andrewtv Exp $
  *
  ********************************************************************/
 #ifndef __MSND_CLASSIC_H
index bebb5d49c7c18d9aedd7fcbd2f9d4ed0557ab918..03e6a177e0d944774b1c8ee8857abeafa8975e43 100644 (file)
@@ -29,7 +29,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd_pinnacle.c,v 1.17 1998/09/04 18:41:27 andrewtv Exp $
+ * $Id: msnd_pinnacle.c,v 1.63 1998/09/10 18:37:19 andrewtv Exp $
  *
  ********************************************************************/
 
@@ -45,6 +45,7 @@
 #ifndef LINUX20
 #  include <linux/init.h>
 #endif
+#include <asm/irq.h>
 #include "sound_config.h"
 #include "sound_firmware.h"
 #ifdef MSND_CLASSIC
 #endif
 #include "msnd.h"
 #ifdef MSND_CLASSIC
+#  ifdef CONFIG_MSNDCLAS_HAVE_BOOT
+#    define HAVE_DSPCODEH
+#  endif
 #  include "msnd_classic.h"
 #  define LOGNAME                      "msnd_classic"
 #else
+#  ifdef CONFIG_MSNDPIN_HAVE_BOOT
+#    define HAVE_DSPCODEH
+#  endif
 #  include "msnd_pinnacle.h"
 #  define LOGNAME                      "msnd_pinnacle"
 #endif
 
+#define get_play_delay_jiffies(size)   ((size) * HZ *                  \
+                                        dev.play_sample_size / 8 /     \
+                                        dev.play_sample_rate /         \
+                                        dev.play_channels)
+
+#define get_rec_delay_jiffies(size)    ((size) * HZ *                  \
+                                        dev.rec_sample_size / 8 /      \
+                                        dev.rec_sample_rate /          \
+                                        dev.rec_channels)
+
 static multisound_dev_t                        dev;
 
 #ifndef HAVE_DSPCODEH
@@ -66,71 +83,86 @@ static char                         *dspini, *permini;
 static int                             sizeof_dspini, sizeof_permini;
 #endif
 
+static int                             dsp_full_reset(void);
+static void                            dsp_write_flush(void);
+
+static __inline__ int chk_send_dsp_cmd(multisound_dev_t *dev, register BYTE cmd)
+{
+       if (msnd_send_dsp_cmd(dev, cmd) == 0)
+               return 0;
+       dsp_full_reset();
+       return msnd_send_dsp_cmd(dev, cmd);
+}
+
 static void reset_play_queue(void)
 {
        int n;
        LPDAQD lpDAQ;
 
-       msnd_fifo_make_empty(&dev.DAPF);
-       writew(0, dev.DAPQ + JQS_wHead);
-       writew(PCTODSP_OFFSET(2 * DAPQ_STRUCT_SIZE), dev.DAPQ + JQS_wTail);
-       dev.CurDAQD = (LPDAQD)(dev.base + 1 * DAPQ_DATA_BUFF);
-       outb(HPBLKSEL_0, dev.io + HP_BLKS);
-       memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+       dev.last_playbank = -1;
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wHead);
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DAPQ + JQS_wTail);
 
-       for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) {
+       for (n = 0, lpDAQ = dev.base + DAPQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
                writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
-               writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize);
+               writew(0, lpDAQ + DAQDS_wSize);
                writew(1, lpDAQ + DAQDS_wFormat);
-               writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
-               writew(dev.channels, lpDAQ + DAQDS_wChannels);
-               writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
+               writew(dev.play_sample_size, lpDAQ + DAQDS_wSampleSize);
+               writew(dev.play_channels, lpDAQ + DAQDS_wChannels);
+               writew(dev.play_sample_rate, lpDAQ + DAQDS_wSampleRate);
                writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               writew(n + 1, lpDAQ + DAQDS_wFlags);
+               writew(n, lpDAQ + DAQDS_wFlags);
        }
-       dev.lastbank = -1;
 }
 
 static void reset_record_queue(void)
 {
        int n;
        LPDAQD lpDAQ;
+       unsigned long flags;
 
-       msnd_fifo_make_empty(&dev.DARF);
-       writew(0, dev.DARQ + JQS_wHead);
-       writew(PCTODSP_OFFSET(2 * DARQ_STRUCT_SIZE), dev.DARQ + JQS_wTail);
-       dev.CurDARQD = (LPDAQD)(dev.base + 1 * DARQ_DATA_BUFF);
+       dev.last_recbank = 2;
+       writew(PCTODSP_OFFSET(0 * DAQDS__size), dev.DARQ + JQS_wHead);
+       writew(PCTODSP_OFFSET(dev.last_recbank * DAQDS__size), dev.DARQ + JQS_wTail);
+
+       /* Critical section: bank 1 access */
+       spin_lock_irqsave(&dev.lock, flags);
        outb(HPBLKSEL_1, dev.io + HP_BLKS);
        memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       spin_unlock_irqrestore(&dev.lock, flags);
 
-       for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) {
+       for (n = 0, lpDAQ = dev.base + DARQ_DATA_BUFF; n < 3; ++n, lpDAQ += DAQDS__size) {
                writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
                writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
                writew(1, lpDAQ + DAQDS_wFormat);
-               writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
-               writew(dev.channels, lpDAQ + DAQDS_wChannels);
-               writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
+               writew(dev.rec_sample_size, lpDAQ + DAQDS_wSampleSize);
+               writew(dev.rec_channels, lpDAQ + DAQDS_wChannels);
+               writew(dev.rec_sample_rate, lpDAQ + DAQDS_wSampleRate);
                writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               writew(n + 1, lpDAQ + DAQDS_wFlags);
+               writew(n, lpDAQ + DAQDS_wFlags);
        }
 }
 
 static void reset_queues(void)
 {
-       writew(0, dev.DSPQ + JQS_wHead);
-       writew(0, dev.DSPQ + JQS_wTail);
-       reset_play_queue();
-       reset_record_queue();
+       if (dev.mode & FMODE_WRITE) {
+               msnd_fifo_make_empty(&dev.DAPF);
+               reset_play_queue();
+       }
+       if (dev.mode & FMODE_READ) {
+               msnd_fifo_make_empty(&dev.DARF);
+               reset_record_queue();
+       }
 }
 
-static int dsp_set_format(int val)
+static int dsp_set_format(struct file *file, int val)
 {
        int data, i;
        LPDAQD lpDAQ, lpDARQ;
 
-       lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
-       lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+       lpDAQ = dev.base + DAPQ_DATA_BUFF;
+       lpDARQ = dev.base + DARQ_DATA_BUFF;
 
        switch (val) {
        case AFMT_U8:
@@ -143,28 +175,43 @@ static int dsp_set_format(int val)
        }
 
        for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
-               writew(data, lpDAQ + DAQDS_wSampleSize);
-               writew(data, lpDARQ + DAQDS_wSampleSize);
+               if (file->f_mode & FMODE_WRITE)
+                       writew(data, lpDAQ + DAQDS_wSampleSize);
+               if (file->f_mode & FMODE_READ)
+                       writew(data, lpDARQ + DAQDS_wSampleSize);
        }
-               
-       dev.sample_size = data;
+       if (file->f_mode & FMODE_WRITE)
+               dev.play_sample_size = data;
+       if (file->f_mode & FMODE_READ)
+               dev.rec_sample_size = data;
 
        return data;
 }
 
-static int dsp_ioctl(unsigned int cmd, unsigned long arg)
+static int dsp_get_frag_size(void)
+{
+       int size;
+       size = dev.fifosize / 4;
+       if (size > 32 * 1024)
+               size = 32 * 1024;
+       return size;
+}
+
+static int dsp_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
 {
        int val, i, data, tmp;
        LPDAQD lpDAQ, lpDARQ;
+        audio_buf_info abinfo;
+       unsigned long flags;
 
-       lpDAQ = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
-       lpDARQ = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
+       lpDAQ = dev.base + DAPQ_DATA_BUFF;
+       lpDARQ = dev.base + DARQ_DATA_BUFF;
 
        switch (cmd) {
        case SNDCTL_DSP_SUBDIVIDE:
        case SNDCTL_DSP_SETFRAGMENT:
        case SNDCTL_DSP_SETDUPLEX:
+       case SNDCTL_DSP_POST:
                return 0;
 
        case SNDCTL_DSP_GETIPTR:
@@ -173,14 +220,39 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg)
        case SNDCTL_DSP_MAPOUTBUF:
                return -EINVAL;
 
-       case SNDCTL_DSP_SYNC:
+       case SNDCTL_DSP_GETOSPACE:
+               if (!(file->f_mode & FMODE_WRITE))
+                       return -EINVAL;
+               spin_lock_irqsave(&dev.lock, flags);
+               abinfo.fragsize = dsp_get_frag_size();
+                abinfo.bytes = dev.DAPF.n - dev.DAPF.len;
+                abinfo.fragstotal = dev.DAPF.n / abinfo.fragsize;
+                abinfo.fragments = abinfo.bytes / abinfo.fragsize;
+               spin_unlock_irqrestore(&dev.lock, flags);
+               return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
+       case SNDCTL_DSP_GETISPACE:
+               if (!(file->f_mode & FMODE_READ))
+                       return -EINVAL;
+               spin_lock_irqsave(&dev.lock, flags);
+               abinfo.fragsize = dsp_get_frag_size();
+                abinfo.bytes = dev.DARF.n - dev.DARF.len;
+                abinfo.fragstotal = dev.DARF.n / abinfo.fragsize;
+                abinfo.fragments = abinfo.bytes / abinfo.fragsize;
+               spin_unlock_irqrestore(&dev.lock, flags);
+               return copy_to_user((void *)arg, &abinfo, sizeof(abinfo)) ? -EFAULT : 0;
+
        case SNDCTL_DSP_RESET:
-               reset_play_queue();
-               reset_record_queue();
+               dev.nresets = 0;
+               reset_queues();
+               return 0;
+
+       case SNDCTL_DSP_SYNC:
+               dsp_write_flush();
                return 0;
                
        case SNDCTL_DSP_GETBLKSIZE:
-               tmp = dev.fifosize / 4;
+               tmp = dsp_get_frag_size();
                if (put_user(tmp, (int *)arg))
                         return -EFAULT;
                return 0;
@@ -195,14 +267,24 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg)
                if (get_user(val, (int *)arg))
                        return -EFAULT;
 
-               data = (val == AFMT_QUERY) ? dev.sample_size : dsp_set_format(val);
+               if (file->f_mode & FMODE_WRITE)
+                       data = val == AFMT_QUERY
+                               ? dev.play_sample_size
+                               : dsp_set_format(file, val);
+               else
+                       data = val == AFMT_QUERY
+                               ? dev.rec_sample_size
+                               : dsp_set_format(file, val);
 
                if (put_user(data, (int *)arg))
                        return -EFAULT;
                return 0;
 
        case SNDCTL_DSP_NONBLOCK:
-               dev.mode |= O_NONBLOCK;
+               if (file->f_mode & FMODE_WRITE)
+                       dev.play_ndelay = 1;
+               if (file->f_mode & FMODE_READ)
+                       dev.rec_ndelay = 1;
                return 0;
 
        case SNDCTL_DSP_GETCAPS:
@@ -224,65 +306,58 @@ static int dsp_ioctl(unsigned int cmd, unsigned long arg)
                data = val;
 
                for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-                       
-                       writew(data, lpDAQ + DAQDS_wSampleRate);
-                       writew(data, lpDARQ + DAQDS_wSampleRate);
+                       if (file->f_mode & FMODE_WRITE)
+                               writew(data, lpDAQ + DAQDS_wSampleRate);
+                       if (file->f_mode & FMODE_READ)
+                               writew(data, lpDARQ + DAQDS_wSampleRate);
                }
-               
-               dev.sample_rate = data;
+               if (file->f_mode & FMODE_WRITE)
+                       dev.play_sample_rate = data;
+               if (file->f_mode & FMODE_READ)
+                       dev.rec_sample_rate = data;
 
                if (put_user(data, (int *)arg))
                        return -EFAULT;
                return 0;
 
        case SNDCTL_DSP_CHANNELS:
-               if (get_user(val, (int *)arg))
-                       return -EFAULT;
-                       
-               switch (val) {
-               case 1:
-               case 2:
-                       data = val;
-                       break;
-               default:
-                       val = data = 2;
-                       break;
-               }
-                                                                       
-               for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
-                       writew(data, lpDAQ + DAQDS_wChannels);
-                       writew(data, lpDARQ + DAQDS_wChannels);
-               }
-
-               dev.channels = data;
-
-               if (put_user(val, (int *)arg))
-                       return -EFAULT;
-               return 0;
-
        case SNDCTL_DSP_STEREO:
                if (get_user(val, (int *)arg))
                        return -EFAULT;
-                       
-               switch (val) {
-               case 0:
-                       data = 1;
-                       break;
-               default:
-                       val = 1;
-               case 1:
-                       data = 2;
-                       break;
+
+               if (cmd == SNDCTL_DSP_CHANNELS) {
+                       switch (val) {
+                       case 1:
+                       case 2:
+                               data = val;
+                               break;
+                       default:
+                               val = data = 2;
+                               break;
+                       }
+               } else {
+                       switch (val) {
+                       case 0:
+                               data = 1;
+                               break;
+                       default:
+                               val = 1;
+                       case 1:
+                               data = 2;
+                               break;
+                       }
                }
                                                                        
                for (i = 0; i < 3; ++i, lpDAQ += DAQDS__size, lpDARQ += DAQDS__size) {
-
-                       writew(data, lpDAQ + DAQDS_wChannels);
-                       writew(data, lpDARQ + DAQDS_wChannels);
+                       if (file->f_mode & FMODE_WRITE)
+                               writew(data, lpDAQ + DAQDS_wChannels);
+                       if (file->f_mode & FMODE_READ)
+                               writew(data, lpDARQ + DAQDS_wChannels);
                }
-
-               dev.channels = data;
+               if (file->f_mode & FMODE_WRITE)
+                       dev.play_channels = data;
+               if (file->f_mode & FMODE_READ)
+                       dev.rec_channels = data;
 
                if (put_user(val, (int *)arg))
                        return -EFAULT;
@@ -320,6 +395,12 @@ static int mixer_get(int d)
        writew(dev.right_levels[a] * readw(dev.SMA + SMA_wCurrMastVolRight) / 0xffff / s,       \
               dev.SMA + SMA_##b##Right);
 
+#define update_pot(d,s,ar)                                             \
+       writeb(dev.left_levels[d] >> 8, dev.SMA + SMA_##s##Left);       \
+       writeb(dev.right_levels[d] >> 8, dev.SMA + SMA_##s##Right);     \
+       if (msnd_send_word(&dev, 0, 0, ar) == 0)                        \
+               chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+
 static int mixer_set(int d, int value)
 {
        int left = value & 0x000000ff;
@@ -350,7 +431,7 @@ static int mixer_set(int d, int value)
                writeb(bLeft, dev.SMA + SMA_bInPotPosLeft);
                writeb(bRight, dev.SMA + SMA_bInPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_IN_SET_POTS) == 0)
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 
 #ifndef MSND_CLASSIC
@@ -358,7 +439,7 @@ static int mixer_set(int d, int value)
                writeb(bLeft, dev.SMA + SMA_bMicPotPosLeft);
                writeb(bRight, dev.SMA + SMA_bMicPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_MIC_SET_POTS) == 0)
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 #endif
 
@@ -366,7 +447,7 @@ static int mixer_set(int d, int value)
                writeb(bLeft, dev.SMA + SMA_bAuxPotPosLeft);
                writeb(bRight, dev.SMA + SMA_bAuxPotPosRight);
                if (msnd_send_word(&dev, 0, 0, HDEXAR_AUX_SET_POTS) == 0)
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
                break;
 
                /* digital controls */
@@ -389,6 +470,20 @@ static int mixer_set(int d, int value)
        return mixer_get(d);
 }
 
+static void mixer_setup(void)
+{
+       update_pot(SOUND_MIXER_LINE, bInPotPos, HDEXAR_IN_SET_POTS);
+#ifndef MSND_CLASSIC
+       update_pot(SOUND_MIXER_MIC, bMicPotPos, HDEXAR_MIC_SET_POTS);
+#endif
+       update_pot(SOUND_MIXER_LINE1, bAuxPotPos, HDEXAR_AUX_SET_POTS);
+       update_vol(SOUND_MIXER_PCM, wCurrPlayVol, 1);
+       update_vol(SOUND_MIXER_IMIX, wCurrInVol, 1);
+#ifndef MSND_CLASSIC
+       update_vol(SOUND_MIXER_SYNTH, wCurrMHdrVol, 1);
+#endif
+}
+
 static unsigned long set_recsrc(unsigned long recsrc)
 {
        if (dev.recsrc == recsrc)
@@ -403,17 +498,15 @@ static unsigned long set_recsrc(unsigned long recsrc)
 #ifndef MSND_CLASSIC
        if (dev.recsrc & SOUND_MASK_LINE) {
                if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
        }
        else if (dev.recsrc & SOUND_MASK_SYNTH) {
                if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_SYNTH_IN) == 0)
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
        }
        else if ((dev.recsrc & SOUND_MASK_DIGITAL1) && test_bit(F_HAVEDIGITAL, &dev.flags)) {
-               if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0) {
-                       udelay(50);
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
-               }
+               if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_DAT_IN) == 0)
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
        }
        else {
 #ifdef HAVE_NORECSRC
@@ -422,7 +515,7 @@ static unsigned long set_recsrc(unsigned long recsrc)
 #else
                dev.recsrc = SOUND_MASK_LINE;
                if (msnd_send_word(&dev, 0, 0, HDEXAR_SET_ANA_IN) == 0)
-                       msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ);
+                       chk_send_dsp_cmd(&dev, HDEX_AUX_REQ);
 #endif
        }
 #endif /* MSND_CLASSIC */
@@ -430,6 +523,12 @@ static unsigned long set_recsrc(unsigned long recsrc)
        return dev.recsrc;
 }
 
+static unsigned long force_recsrc(unsigned long recsrc)
+{
+       dev.recsrc = 0;
+       return set_recsrc(recsrc);
+}
+
 #define set_mixer_info()                                                       \
                strncpy(info.id, "MSNDMIXER", sizeof(info.id));                 \
                strncpy(info.name, "MultiSound Mixer", sizeof(info.name));
@@ -447,10 +546,6 @@ static int mixer_ioctl(unsigned int cmd, unsigned long arg)
                set_mixer_info();
                return copy_to_user((void *)arg, &info, sizeof(info));
        }
-       else if (cmd == OSS_GETVERSION) {
-               int sound_version = SOUND_VERSION;
-               return put_user(sound_version, (int *)arg);
-       }
        else if (((cmd >> 8) & 0xff) == 'M') {
                int val = 0;
                
@@ -521,77 +616,139 @@ static int dev_ioctl(struct inode *inode, struct file *file, unsigned int cmd, u
 {
        int minor = MINOR(inode->i_rdev);
 
+       if (cmd == OSS_GETVERSION) {
+               int sound_version = SOUND_VERSION;
+               return put_user(sound_version, (int *)arg);
+       }
+
        if (minor == dev.dsp_minor)
-               return dsp_ioctl(cmd, arg);
+               return dsp_ioctl(file, cmd, arg);
        else if (minor == dev.mixer_minor)
                return mixer_ioctl(cmd, arg);
 
        return -EINVAL;
 }
 
-static void dsp_halt(void)
+static void dsp_write_flush(void)
 {
-       mdelay(1);
-#ifdef LINUX20
-       if (test_bit(F_READING, &dev.flags)) {
-               clear_bit(F_READING, &dev.flags);
-#else
-       if (test_and_clear_bit(F_READING, &dev.flags)) {
-#endif
-               msnd_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
-               msnd_disable_irq(&dev);
-
-       }
-       mdelay(1);
-#ifdef LINUX20
-       if (test_bit(F_WRITING, &dev.flags)) {
-               clear_bit(F_WRITING, &dev.flags);
-#else
-       if (test_and_clear_bit(F_WRITING, &dev.flags)) {
-#endif
-               set_bit(F_WRITEFLUSH, &dev.flags);
-               interruptible_sleep_on(&dev.writeflush);
+       if (!(dev.mode & FMODE_WRITE) || !test_bit(F_WRITING, &dev.flags))
+               return;
+       set_bit(F_WRITEFLUSH, &dev.flags);
+       current->timeout = jiffies + get_play_delay_jiffies(dev.DAPF.len) + HZ / 8;
+       interruptible_sleep_on(&dev.writeflush);
+       clear_bit(F_WRITEFLUSH, &dev.flags);
+       if (!signal_pending(current)) {
                current->state = TASK_INTERRUPTIBLE;
-               current->timeout = 
-                       jiffies + DAP_BUFF_SIZE / 2 * HZ /
-                       dev.sample_rate / dev.channels;
+               current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE);
                schedule();
                current->timeout = 0;
-               msnd_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
-               msnd_disable_irq(&dev);
-               memset_io(dev.base, 0, DAP_BUFF_SIZE * 3);
+       } else
+               current->timeout = 0;
+       clear_bit(F_WRITING, &dev.flags);
+}
 
+static void dsp_halt(struct file *file)
+{
+       if ((file ? file->f_mode : dev.mode) & FMODE_READ) {
+               clear_bit(F_READING, &dev.flags);
+               chk_send_dsp_cmd(&dev, HDEX_RECORD_STOP);
+               msnd_disable_irq(&dev);
+               if (file) {
+                       printk(KERN_DEBUG LOGNAME ": Stopping read for %p\n", file);
+                       dev.mode &= ~FMODE_READ;
+               }
+               clear_bit(F_AUDIO_READ_INUSE, &dev.flags);
+       }
+       if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) {
+               if (test_bit(F_WRITING, &dev.flags)) {
+                       dsp_write_flush();
+                       chk_send_dsp_cmd(&dev, HDEX_PLAY_STOP);
+               }
+               msnd_disable_irq(&dev);
+               if (file) {
+                       printk(KERN_DEBUG LOGNAME ": Stopping write for %p\n", file);
+                       dev.mode &= ~FMODE_WRITE;
+               }
+               clear_bit(F_AUDIO_WRITE_INUSE, &dev.flags);
        }
-       mdelay(1);
-       reset_queues();
 }
 
-static int dsp_open(struct file *file)
+static int dsp_release(struct file *file)
 {
-       dev.mode = file->f_mode;
-       set_bit(F_AUDIO_INUSE, &dev.flags);
-       reset_queues();
+       dsp_halt(file);
        return 0;
 }
 
-static int dsp_close(void)
+static int dsp_open(struct file *file)
 {
-       dsp_halt();
-       clear_bit(F_AUDIO_INUSE, &dev.flags);
+       if ((file ? file->f_mode : dev.mode) & FMODE_WRITE) {
+               set_bit(F_AUDIO_WRITE_INUSE, &dev.flags);
+               clear_bit(F_WRITING, &dev.flags);
+               msnd_fifo_make_empty(&dev.DAPF);
+               reset_play_queue();
+               if (file) {
+                       printk(KERN_DEBUG LOGNAME ": Starting write for %p\n", file);
+                       dev.mode |= FMODE_WRITE;
+               }
+               msnd_enable_irq(&dev);
+       }
+       if ((file ? file->f_mode : dev.mode) & FMODE_READ) {
+               set_bit(F_AUDIO_READ_INUSE, &dev.flags);
+               clear_bit(F_READING, &dev.flags);
+               msnd_fifo_make_empty(&dev.DARF);
+               reset_record_queue();
+               if (file) {
+                       printk(KERN_DEBUG LOGNAME ": Starting read for %p\n", file);
+                       dev.mode |= FMODE_READ;
+               }
+               msnd_enable_irq(&dev);
+       }
        return 0;
 }
 
+static void set_default_play_audio_parameters(void)
+{
+       dev.play_sample_size = DEFSAMPLESIZE;
+       dev.play_sample_rate = DEFSAMPLERATE;
+       dev.play_channels = DEFCHANNELS;
+}
+
+static void set_default_rec_audio_parameters(void)
+{
+       dev.rec_sample_size = DEFSAMPLESIZE;
+       dev.rec_sample_rate = DEFSAMPLERATE;
+       dev.rec_channels = DEFCHANNELS;
+}
+
+static void set_default_audio_parameters(void)
+{
+       set_default_play_audio_parameters();
+       set_default_rec_audio_parameters();
+}
+
 static int dev_open(struct inode *inode, struct file *file)
 {
        int minor = MINOR(inode->i_rdev);
        int err = 0;
 
        if (minor == dev.dsp_minor) {
-
-               if (test_bit(F_AUDIO_INUSE, &dev.flags))
+               if ((file->f_mode & FMODE_WRITE &&
+                    test_bit(F_AUDIO_WRITE_INUSE, &dev.flags)) ||
+                   (file->f_mode & FMODE_READ &&
+                    test_bit(F_AUDIO_READ_INUSE, &dev.flags)))
                        return -EBUSY;
 
-               err = dsp_open(file);
+               if ((err = dsp_open(file)) >= 0) {
+                       dev.nresets = 0;
+                       if (file->f_mode & FMODE_WRITE) {
+                               set_default_play_audio_parameters();
+                               dev.play_ndelay = (file->f_mode & O_NDELAY) ? 1 : 0;
+                       }
+                       if (file->f_mode & FMODE_READ) {
+                               set_default_rec_audio_parameters();
+                               dev.rec_ndelay = (file->f_mode & O_NDELAY) ? 1 : 0;
+                       }
+               }
        }
        else if (minor == dev.mixer_minor) {
                /* nothing */
@@ -605,9 +762,9 @@ static int dev_open(struct inode *inode, struct file *file)
 }
 
 #ifdef LINUX20
-static void dev_close(struct inode *inode, struct file *file)
+static void dev_release(struct inode *inode, struct file *file)
 #else
-static int dev_close(struct inode *inode, struct file *file)
+static int dev_release(struct inode *inode, struct file *file)
 #endif
 {
        int minor = MINOR(inode->i_rdev);
@@ -619,7 +776,7 @@ static int dev_close(struct inode *inode, struct file *file)
 #ifndef LINUX20
                err = 
 #endif
-                       dsp_close();
+                       dsp_release(file);
        }
        else if (minor == dev.mixer_minor) {
                /* nothing */
@@ -637,62 +794,137 @@ static int dev_close(struct inode *inode, struct file *file)
 #endif
 }
 
-static int DAPF_to_bank(int bank)
+static __inline__ int pack_DARQ_to_DARF(register int bank)
 {
-       return msnd_fifo_read(&dev.DAPF, dev.base + bank * DAP_BUFF_SIZE, DAP_BUFF_SIZE, 0);
+       register int size, n, timeout = 3;
+       register WORD wTmp;
+       LPDAQD DAQD;
+
+       /* Increment the tail and check for queue wrap */
+       wTmp = readw(dev.DARQ + JQS_wTail) + PCTODSP_OFFSET(DAQDS__size);
+       if (wTmp > readw(dev.DARQ + JQS_wSize))
+               wTmp = 0;
+       while (wTmp == readw(dev.DARQ + JQS_wHead) && timeout--)
+               udelay(1);
+       writew(wTmp, dev.DARQ + JQS_wTail);
+
+       /* Get our digital audio queue struct */
+       DAQD = bank * DAQDS__size + dev.base + DARQ_DATA_BUFF;
+
+       /* Get length of data */
+       size = readw(DAQD + DAQDS_wSize);
+
+       /* Read data from the head (unprotected bank 1 access okay
+           since this is only called inside an interrupt) */
+       outb(HPBLKSEL_1, dev.io + HP_BLKS);
+       if ((n = msnd_fifo_write(
+               &dev.DARF,
+               (char *)(dev.base + bank * DAR_BUFF_SIZE),
+               size, 0)) < 0) {
+               outb(HPBLKSEL_0, dev.io + HP_BLKS);
+               return n;
+       }
+       outb(HPBLKSEL_0, dev.io + HP_BLKS);
+
+       return 1;
 }
 
-static int bank_to_DARF(int bank)
+static __inline__ int pack_DAPF_to_DAPQ(register int start)
 {
-       return msnd_fifo_write(&dev.DARF, dev.base + bank * DAR_BUFF_SIZE, DAR_BUFF_SIZE, 0);
+       register WORD DAPQ_tail;
+       register int protect = start, nbanks = 0;
+       LPDAQD DAQD;
+
+       DAPQ_tail = readw(dev.DAPQ + JQS_wTail);
+       while (DAPQ_tail != readw(dev.DAPQ + JQS_wHead) || start) {
+               register int bank_num = DAPQ_tail / PCTODSP_OFFSET(DAQDS__size);
+               register int n;
+               unsigned long flags;
+               
+               /* Write the data to the new tail */
+               if (protect) {
+                       /* Critical section: protect fifo in non-interrupt */
+                       spin_lock_irqsave(&dev.lock, flags);
+                       if ((n = msnd_fifo_read(
+                               &dev.DAPF,
+                               (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
+                               DAP_BUFF_SIZE, 0)) < 0) {
+                               spin_unlock_irqrestore(&dev.lock, flags);
+                               return n;
+                       }
+                       spin_unlock_irqrestore(&dev.lock, flags);
+               } else {
+                       if ((n = msnd_fifo_read(
+                               &dev.DAPF,
+                               (char *)(dev.base + bank_num * DAP_BUFF_SIZE),
+                               DAP_BUFF_SIZE, 0)) < 0) {
+                               return n;
+                       }
+               }
+               if (!n)
+                       break;
+
+               if (start)
+                       start = 0;
+
+               /* Get our digital audio queue struct */
+               DAQD = bank_num * DAQDS__size + dev.base + DAPQ_DATA_BUFF;
+
+               /* Write size of this bank */
+               writew(n, DAQD + DAQDS_wSize);
+               ++nbanks;
+
+               /* Then advance the tail */
+               DAPQ_tail = (++bank_num % 3) * PCTODSP_OFFSET(DAQDS__size);
+               writew(DAPQ_tail, dev.DAPQ + JQS_wTail);
+               
+               /* Tell the DSP to play the bank */
+               msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
+       }
+       
+       return nbanks;
 }
 
 static int dsp_read(char *buf, size_t len)
 {
-       int err = 0;
        int count = len;
 
        while (count > 0) {
-               
                int n;
+               unsigned long flags;
 
+               /* Critical section: protect fifo in non-interrupt */
+               spin_lock_irqsave(&dev.lock, flags);
                if ((n = msnd_fifo_read(&dev.DARF, buf, count, 1)) < 0) {
-
                        printk(KERN_WARNING LOGNAME ": FIFO read error\n");
+                       spin_unlock_irqrestore(&dev.lock, flags);
                        return n;
                }
-
+               spin_unlock_irqrestore(&dev.lock, flags);
                buf += n;
                count -= n;
 
-#ifdef LINUX20         
-               if (!test_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
-                       set_bit(F_READING, &dev.flags);
-#else
-               if (!test_and_set_bit(F_READING, &dev.flags) && (dev.mode & FMODE_READ)) {
-#endif
-                       reset_record_queue();
-                       msnd_enable_irq(&dev);
-                       msnd_send_dsp_cmd(&dev, HDEX_RECORD_START);
-
+               if (!test_bit(F_READING, &dev.flags) && dev.mode & FMODE_READ) {
+                       dev.last_recbank = -1;
+                       if (chk_send_dsp_cmd(&dev, HDEX_RECORD_START) == 0)
+                               set_bit(F_READING, &dev.flags);
                }
 
-               if (dev.mode & O_NONBLOCK)
+               if (dev.rec_ndelay)
                        return count == len ? -EAGAIN : len - count;
 
                if (count > 0) {
-
                        set_bit(F_READBLOCK, &dev.flags);
+                       current->timeout = jiffies + get_rec_delay_jiffies(DAR_BUFF_SIZE);
                        interruptible_sleep_on(&dev.readblock);
+                       if (current->timeout == 0)
+                               clear_bit(F_READING, &dev.flags);
+                       else
+                               current->timeout = 0;
                        clear_bit(F_READBLOCK, &dev.flags);
-
                        if (signal_pending(current))
-                               err = -EINTR;
-
+                               return -EINTR;
                }
-
-               if (err != 0)
-                       return err;
        }
 
        return len - count;
@@ -700,50 +932,41 @@ static int dsp_read(char *buf, size_t len)
 
 static int dsp_write(const char *buf, size_t len)
 {
-       int err = 0;
        int count = len;
 
        while (count > 0) {
-
                int n;
+               unsigned long flags;
 
+               /* Critical section: protect fifo in non-interrupt */
+               spin_lock_irqsave(&dev.lock, flags);
                if ((n = msnd_fifo_write(&dev.DAPF, buf, count, 1)) < 0) {
-
                        printk(KERN_WARNING LOGNAME ": FIFO write error\n");
+                       spin_unlock_irqrestore(&dev.lock, flags);
                        return n;
                }
-
+               spin_unlock_irqrestore(&dev.lock, flags);
                buf += n;
                count -= n;
 
-#ifdef LINUX20
                if (!test_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
-                       set_bit(F_WRITING, &dev.flags);
-#else
-               if (!test_and_set_bit(F_WRITING, &dev.flags) && (dev.mode & FMODE_WRITE)) {
-#endif
-                       reset_play_queue();
-                       msnd_enable_irq(&dev);
-                       msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
-
+                       dev.last_playbank = -1;
+                       if (pack_DAPF_to_DAPQ(1) > 0)
+                               set_bit(F_WRITING, &dev.flags);
                }
 
-               if (dev.mode & O_NONBLOCK)
+               if (dev.play_ndelay)
                        return count == len ? -EAGAIN : len - count;
 
                if (count > 0) {
-                       
                        set_bit(F_WRITEBLOCK, &dev.flags);
+                       current->timeout = jiffies + get_play_delay_jiffies(DAP_BUFF_SIZE);
                        interruptible_sleep_on(&dev.writeblock);
+                       current->timeout = 0;
                        clear_bit(F_WRITEBLOCK, &dev.flags);
-
                        if (signal_pending(current))
-                               err = -EINTR;
-
+                               return -EINTR;
                }
-
-               if (err != 0)
-                       return err;
        }
        
        return len - count;
@@ -758,12 +981,9 @@ static ssize_t dev_read(struct file *file, char *buf, size_t count, loff_t *off)
 {
        int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 #endif
-
-       if (minor == dev.dsp_minor) {
-
+       if (minor == dev.dsp_minor)
                return dsp_read(buf, count);
-
-       } else
+       else
                return -EINVAL;
 }
 
@@ -776,44 +996,22 @@ static ssize_t dev_write(struct file *file, const char *buf, size_t count, loff_
 {
        int minor = MINOR(file->f_dentry->d_inode->i_rdev);
 #endif
-
-       if (minor == dev.dsp_minor) {
-
+       if (minor == dev.dsp_minor)
                return dsp_write(buf, count);
-
-       } else
+       else
                return -EINVAL;
 }
 
-static void eval_dsp_msg(WORD wMessage)
+static __inline__ void eval_dsp_msg(register WORD wMessage)
 {
-       WORD wTmp;
-
        switch (HIBYTE(wMessage)) {
        case HIMT_PLAY_DONE:
-               if (dev.lastbank == LOBYTE(wMessage))
+               if (dev.last_playbank == LOBYTE(wMessage) || !test_bit(F_WRITING, &dev.flags))
                        break;
-               
-               dev.lastbank = LOBYTE(wMessage);
-
-               writew(DAP_BUFF_SIZE, dev.CurDAQD + DAQDS_wSize);
+               dev.last_playbank = LOBYTE(wMessage);
 
-               wTmp = readw(dev.DAPQ + JQS_wTail) + PCTODSP_OFFSET(DAPQ_STRUCT_SIZE);
-               if (wTmp > readw(dev.DAPQ + JQS_wSize))
-                       writew(0, dev.DAPQ + JQS_wTail);
-               else
-                       writew(wTmp, dev.DAPQ + JQS_wTail);
-
-               if ((dev.CurDAQD += DAQDS__size) > (LPDAQD)(dev.base + DAPQ_DATA_BUFF + 2 * DAPQ_STRUCT_SIZE))
-                       dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
-
-               if (dev.lastbank < 3) {
-                       if (DAPF_to_bank(dev.lastbank) > 0) {
-                               mdelay(1);
-                               msnd_send_dsp_cmd(&dev, HDEX_PLAY_START);
-                       } 
-                       else if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
-                               clear_bit(F_WRITING, &dev.flags);
+               if (pack_DAPF_to_DAPQ(0) <= 0) {
+                       if (!test_bit(F_WRITEBLOCK, &dev.flags)) {
 #ifdef LINUX20
                                if (test_bit(F_WRITEFLUSH, &dev.flags)) {
                                        clear_bit(F_WRITEFLUSH, &dev.flags);
@@ -824,6 +1022,7 @@ static void eval_dsp_msg(WORD wMessage)
                                        wake_up_interruptible(&dev.writeflush);
 #endif
                        }
+                       clear_bit(F_WRITING, &dev.flags);
                }
 
                if (test_bit(F_WRITEBLOCK, &dev.flags))
@@ -831,21 +1030,11 @@ static void eval_dsp_msg(WORD wMessage)
                break;
 
        case HIMT_RECORD_DONE:
-               wTmp = readw(dev.DARQ + JQS_wTail) + DARQ_STRUCT_SIZE / 2;
-
-               if (wTmp > readw(dev.DARQ + JQS_wSize))
-                       wTmp = 0;
-
-               while (wTmp == readw(dev.DARQ + JQS_wHead));
+               if (dev.last_recbank == LOBYTE(wMessage))
+                       break;
+               dev.last_recbank = LOBYTE(wMessage);
 
-               writew(wTmp, dev.DARQ + JQS_wTail);
-
-               outb(HPBLKSEL_1, dev.io + HP_BLKS);
-               if (bank_to_DARF(LOBYTE(wMessage)) == 0 && !test_bit(F_READBLOCK, &dev.flags)) {
-                       memset_io(dev.base, 0, DAR_BUFF_SIZE * 3);
-                       clear_bit(F_READING, &dev.flags);
-               }
-               outb(HPBLKSEL_0, dev.io + HP_BLKS);
+               pack_DARQ_to_DARF(dev.last_recbank);
 
                if (test_bit(F_READBLOCK, &dev.flags))
                        wake_up_interruptible(&dev.readblock);
@@ -857,17 +1046,17 @@ static void eval_dsp_msg(WORD wMessage)
                case HIDSP_PLAY_UNDER:
 #endif
                case HIDSP_INT_PLAY_UNDER:
-/*                     printk(KERN_INFO LOGNAME ": Write underflow\n"); */
-                       reset_play_queue();
+/*                     printk(KERN_DEBUG LOGNAME ": Play underflow\n"); */
+                       clear_bit(F_WRITING, &dev.flags);
                        break;
 
                case HIDSP_INT_RECORD_OVER:
-/*                     printk(KERN_INFO LOGNAME ": Read overflow\n"); */
-                       reset_record_queue();
+/*                     printk(KERN_DEBUG LOGNAME ": Record overflow\n"); */
+                       clear_bit(F_READING, &dev.flags);
                        break;
 
                default:
-                       printk(KERN_DEBUG LOGNAME ": DSP message %u\n", LOBYTE(wMessage));
+/*                     printk(KERN_DEBUG LOGNAME ": DSP message %d 0x%02x\n", LOBYTE(wMessage), LOBYTE(wMessage)); */
                        break;
                }
                break;
@@ -877,85 +1066,66 @@ static void eval_dsp_msg(WORD wMessage)
                        (*dev.midi_in_interrupt)(&dev);
                break;
 
-       case HIMT_MIDI_OUT:
-               printk(KERN_DEBUG LOGNAME ": MIDI out event\n");
-               break;
-
        default:
-               printk(KERN_DEBUG LOGNAME ": HIMT message %u\n", HIBYTE(wMessage));
+/*             printk(KERN_DEBUG LOGNAME ": HIMT message %d 0x%02x\n", HIBYTE(wMessage), HIBYTE(wMessage)); */
                break;
        }
 }
 
 static void intr(int irq, void *dev_id, struct pt_regs *regs)
 {
-       if (test_bit(F_INTERRUPT, &dev.flags))
-               return;
-
-       set_bit(F_INTERRUPT, &dev.flags);
-       
-       if (test_bit(F_BANKONE, &dev.flags))
-               outb(HPBLKSEL_0, dev.io + HP_BLKS);
-
+       /* Send ack to DSP */
        inb(dev.io + HP_RXL);
+
+       /* Evaluate queued DSP messages */
        while (readw(dev.DSPQ + JQS_wTail) != readw(dev.DSPQ + JQS_wHead)) {
-               WORD wTmp;
+               register WORD wTmp;
 
-               eval_dsp_msg(*(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead)));
-               
-               wTmp = readw(dev.DSPQ + JQS_wHead) + 1;
-               if (wTmp > readw(dev.DSPQ + JQS_wSize))
+               eval_dsp_msg(readw(dev.pwDSPQData + readw(dev.DSPQ + JQS_wHead)));
+
+               if ((wTmp = readw(dev.DSPQ + JQS_wHead) + 1) > readw(dev.DSPQ + JQS_wSize))
                        writew(0, dev.DSPQ + JQS_wHead);
                else
                        writew(wTmp, dev.DSPQ + JQS_wHead);
        }
-
-       if (test_bit(F_BANKONE, &dev.flags))
-               outb(HPBLKSEL_1, dev.io + HP_BLKS);
-
-       clear_bit(F_INTERRUPT, &dev.flags);
 }
 
 static struct file_operations dev_fileops = {
-       NULL,
-       dev_read,
-       dev_write,
-       NULL,
-       NULL,
-       dev_ioctl,
-       NULL,
-       dev_open,
+       NULL,           /* llseek */
+       dev_read,       /* read */
+       dev_write,      /* write */
+       NULL,           /* readdir */
+       NULL,           /* poll */
+       dev_ioctl,      /* ioctl */
+       NULL,           /* mmap */
+       dev_open,       /* open */
+       NULL,           /* flush */
+       dev_release,    /* release */
+       NULL,           /* fsync */
+       NULL,           /* fasync */
+       NULL,           /* check_media_change */
+       NULL,           /* revalidate */
 #ifndef LINUX20
-#  if LINUX_VERSION_CODE >= 0x020100 + 118
-       NULL,
-#  endif /* >= 2.1.118 */
+       NULL,           /* lock */
 #endif
-       dev_close,
 };
 
-__initfunc(static int reset_dsp(void))
+static int reset_dsp(void)
 {
        int timeout = 100;
                
        outb(HPDSPRESET_ON, dev.io + HP_DSPR);
-       
        mdelay(1);
-
+#ifndef MSND_CLASSIC
        dev.info = inb(dev.io + HP_INFO);
-
+#endif
        outb(HPDSPRESET_OFF, dev.io + HP_DSPR);
-
        mdelay(1);
-
        while (timeout-- > 0) {
-
                if (inb(dev.io + HP_CVR) == HP_CVR_DEF)
                        return 0;
-               
                mdelay(1);
        }
-
        printk(KERN_ERR LOGNAME ": Cannot reset DSP\n");
 
        return -EIO;
@@ -973,7 +1143,6 @@ __initfunc(static int probe_multisound(void))
                printk(KERN_ERR LOGNAME ": I/O port conflict\n");
                return -ENODEV;
        }
-
        request_region(dev.io, dev.numio, "probing");
 
        if (reset_dsp() < 0) {
@@ -1024,127 +1193,82 @@ __initfunc(static int probe_multisound(void))
        return 0;
 }
 
-__initfunc(static int init_sma(void))
+static void msnd_init_queue(volatile BYTE *base, int start, int size)
 {
-       int n;
-       LPDAQD lpDAQ;
+       writew(PCTODSP_BASED(start), base + JQS_wStart);
+       writew(PCTODSP_OFFSET(size) - 1, base + JQS_wSize);
+       writew(0, base + JQS_wHead);
+       writew(0, base + JQS_wTail);
+}
+
+static int init_sma(void)
+{
+       static int initted;
+       WORD mastVolLeft, mastVolRight;
+       unsigned long flags;
 
 #ifdef MSND_CLASSIC
        outb(dev.memid, dev.io + HP_MEMM);
 #endif
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       if (initted) {
+               mastVolLeft = readw(dev.SMA + SMA_wCurrMastVolLeft);
+               mastVolRight = readw(dev.SMA + SMA_wCurrMastVolRight);
+       } else
+               mastVolLeft = mastVolRight = 0;
        memset_io(dev.base, 0, 0x8000);
-       
+
+       /* Critical section: bank 1 access */
+       spin_lock_irqsave(&dev.lock, flags);
        outb(HPBLKSEL_1, dev.io + HP_BLKS);
        memset_io(dev.base, 0, 0x8000);
-       
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
+       spin_unlock_irqrestore(&dev.lock, flags);
 
-       dev.DAPQ = (BYTE *)(dev.base + DAPQ_OFFSET);
-       dev.DARQ = (BYTE *)(dev.base + DARQ_OFFSET);
-       dev.MODQ = (BYTE *)(dev.base + MODQ_OFFSET);
-       dev.MIDQ = (BYTE *)(dev.base + MIDQ_OFFSET);
-       dev.DSPQ = (BYTE *)(dev.base + DSPQ_OFFSET);
-       dev.SMA = (BYTE *)(dev.base + SMA_STRUCT_START);
-
-       dev.CurDAQD = (LPDAQD)(dev.base + DAPQ_DATA_BUFF);
-       dev.CurDARQD = (LPDAQD)(dev.base + DARQ_DATA_BUFF);
-
-       dev.sample_size = DEFSAMPLESIZE;
-       dev.sample_rate = DEFSAMPLERATE;
-       dev.channels = DEFCHANNELS;
-
-       for (n = 0, lpDAQ = dev.CurDAQD; n < 3; ++n, lpDAQ += DAQDS__size) {
-               
-               writew(PCTODSP_BASED((DWORD)(DAP_BUFF_SIZE * n)), lpDAQ + DAQDS_wStart);
-               writew(DAP_BUFF_SIZE, lpDAQ + DAQDS_wSize);
-               writew(1, lpDAQ + DAQDS_wFormat);
-               writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
-               writew(dev.channels, lpDAQ + DAQDS_wChannels);
-               writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
-               writew(HIMT_PLAY_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               writew(n + 1, lpDAQ + DAQDS_wFlags);
-       }
-
-       for (n = 0, lpDAQ = dev.CurDARQD; n < 3; ++n, lpDAQ += DAQDS__size) {
-
-               writew(PCTODSP_BASED((DWORD)(DAR_BUFF_SIZE * n)) + 0x4000, lpDAQ + DAQDS_wStart);
-               writew(DAR_BUFF_SIZE, lpDAQ + DAQDS_wSize);
-               writew(1, lpDAQ + DAQDS_wFormat);
-               writew(dev.sample_size, lpDAQ + DAQDS_wSampleSize);
-               writew(dev.channels, lpDAQ + DAQDS_wChannels);
-               writew(dev.sample_rate, lpDAQ + DAQDS_wSampleRate);
-               writew(HIMT_RECORD_DONE * 0x100 + n, lpDAQ + DAQDS_wIntMsg);
-               writew(n + 1, lpDAQ + DAQDS_wFlags);
-
-       }       
+       dev.pwDSPQData = (volatile WORD *)(dev.base + DSPQ_DATA_BUFF);
+       dev.pwMODQData = (volatile WORD *)(dev.base + MODQ_DATA_BUFF);
+       dev.pwMIDQData = (volatile WORD *)(dev.base + MIDQ_DATA_BUFF);
 
-       dev.pwDSPQData = (WORD *)(dev.base + DSPQ_DATA_BUFF);
-       dev.pwMODQData = (WORD *)(dev.base + MODQ_DATA_BUFF);
-       dev.pwMIDQData = (WORD *)(dev.base + MIDQ_DATA_BUFF);
+       /* Motorola 56k shared memory base */
+       dev.SMA = dev.base + SMA_STRUCT_START;
 
-       writew(PCTODSP_BASED(MIDQ_DATA_BUFF), dev.MIDQ + JQS_wStart);
-       writew(PCTODSP_OFFSET(MIDQ_BUFF_SIZE) - 1, dev.MIDQ + JQS_wSize);
-       writew(0, dev.MIDQ + JQS_wHead);
-       writew(0, dev.MIDQ + JQS_wTail);
+       /* Digital audio play queue */
+       dev.DAPQ = dev.base + DAPQ_OFFSET;
+       msnd_init_queue(dev.DAPQ, DAPQ_DATA_BUFF, DAPQ_BUFF_SIZE);
 
-       writew(PCTODSP_BASED(MODQ_DATA_BUFF), dev.MODQ + JQS_wStart);
-       writew(PCTODSP_OFFSET(MODQ_BUFF_SIZE) - 1, dev.MODQ + JQS_wSize);
-       writew(0, dev.MODQ + JQS_wHead);
-       writew(0, dev.MODQ + JQS_wTail);
+       /* Digital audio record queue */
+       dev.DARQ = dev.base + DARQ_OFFSET;
+       msnd_init_queue(dev.DARQ, DARQ_DATA_BUFF, DARQ_BUFF_SIZE);
 
-       writew(PCTODSP_BASED(DAPQ_DATA_BUFF), dev.DAPQ + JQS_wStart);
-       writew(PCTODSP_OFFSET(DAPQ_BUFF_SIZE) - 1, dev.DAPQ + JQS_wSize);
-       writew(0, dev.DAPQ + JQS_wHead);
-       writew(0, dev.DAPQ + JQS_wTail);
+       /* MIDI out queue */
+       dev.MODQ = dev.base + MODQ_OFFSET;
+       msnd_init_queue(dev.MODQ, MODQ_DATA_BUFF, MODQ_BUFF_SIZE);
 
-       writew(PCTODSP_BASED(DARQ_DATA_BUFF), dev.DARQ + JQS_wStart);
-       writew(PCTODSP_OFFSET(DARQ_BUFF_SIZE) - 1, dev.DARQ + JQS_wSize);
-       writew(0, dev.DARQ + JQS_wHead);
-       writew(0, dev.DARQ + JQS_wTail);
+       /* MIDI in queue */
+       dev.MIDQ = dev.base + MIDQ_OFFSET;
+       msnd_init_queue(dev.MIDQ, MIDQ_DATA_BUFF, MIDQ_BUFF_SIZE);
 
-       writew(PCTODSP_BASED(DSPQ_DATA_BUFF), dev.DSPQ + JQS_wStart);
-       writew(PCTODSP_OFFSET(DSPQ_BUFF_SIZE) - 1, dev.DSPQ + JQS_wSize);
-       writew(0, dev.DSPQ + JQS_wHead);
-       writew(0, dev.DSPQ + JQS_wTail);
-
-       writew(0, dev.SMA + SMA_wCurrPlayBytes);
-       writew(0, dev.SMA + SMA_wCurrRecordBytes);
-
-       writew(0, dev.SMA + SMA_wCurrPlayVolLeft);
-       writew(0, dev.SMA + SMA_wCurrPlayVolRight);
-
-       writew(0, dev.SMA + SMA_wCurrInVolLeft);
-       writew(0, dev.SMA + SMA_wCurrInVolRight);
-
-       writew(0, dev.SMA + SMA_wCurrMastVolLeft);
-       writew(0, dev.SMA + SMA_wCurrMastVolRight);
+       /* DSP -> host message queue */
+       dev.DSPQ = dev.base + DSPQ_OFFSET;
+       msnd_init_queue(dev.DSPQ, DSPQ_DATA_BUFF, DSPQ_BUFF_SIZE);
 
+       /* Setup some DSP values */
+#ifndef MSND_CLASSIC
+       writew(1, dev.SMA + SMA_wCurrPlayFormat);
+       writew(dev.play_sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
+       writew(dev.play_channels, dev.SMA + SMA_wCurrPlayChannels);
+       writew(dev.play_sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
+#endif
+       writew(dev.play_sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+       writew(mastVolLeft, dev.SMA + SMA_wCurrMastVolLeft);
+       writew(mastVolRight, dev.SMA + SMA_wCurrMastVolRight);
 #ifndef MSND_CLASSIC
        writel(0x00010000, dev.SMA + SMA_dwCurrPlayPitch);
        writel(0x00000001, dev.SMA + SMA_dwCurrPlayRate);
 #endif
-
-       writew(0x0000, dev.SMA + SMA_wCurrDSPStatusFlags);
-       writew(0x0000, dev.SMA + SMA_wCurrHostStatusFlags);
-
        writew(0x303, dev.SMA + SMA_wCurrInputTagBits);
-       writew(0, dev.SMA + SMA_wCurrLeftPeak);
-       writew(0, dev.SMA + SMA_wCurrRightPeak);
 
-       writeb(0, dev.SMA + SMA_bInPotPosRight);
-       writeb(0, dev.SMA + SMA_bInPotPosLeft);
-
-       writeb(0, dev.SMA + SMA_bAuxPotPosRight);
-       writeb(0, dev.SMA + SMA_bAuxPotPosLeft);
-
-#ifndef MSND_CLASSIC
-       writew(1, dev.SMA + SMA_wCurrPlayFormat);
-       writew(dev.sample_size, dev.SMA + SMA_wCurrPlaySampleSize);
-       writew(dev.channels, dev.SMA + SMA_wCurrPlayChannels);
-       writew(dev.sample_rate, dev.SMA + SMA_wCurrPlaySampleRate);
-#endif
-       writew(dev.sample_rate, dev.SMA + SMA_wCalFreqAtoD);
+       initted = 1;
 
        return 0;
 }
@@ -1164,7 +1288,7 @@ __initfunc(static int calibrate_adc(WORD srate))
        writew(srate, dev.SMA + SMA_wCalFreqAtoD);
 
        if (msnd_send_word(&dev, 0, 0, HDEXAR_CAL_A_TO_D) == 0 &&
-           msnd_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
+           chk_send_dsp_cmd(&dev, HDEX_AUX_REQ) == 0) {
                current->state = TASK_INTERRUPTIBLE;
                current->timeout = jiffies + HZ / 3;
                schedule();
@@ -1172,13 +1296,12 @@ __initfunc(static int calibrate_adc(WORD srate))
                printk("successful\n");
                return 0;
        }
-
        printk("failed\n");
 
        return -EIO;
 }
 
-__initfunc(static int upload_dsp_code(void))
+static int upload_dsp_code(void)
 {
        outb(HPBLKSEL_0, dev.io + HP_BLKS);
 
@@ -1214,7 +1337,7 @@ __initfunc(static int upload_dsp_code(void))
 }
 
 #ifdef MSND_CLASSIC
-__initfunc(static void reset_proteus(void))
+static void reset_proteus(void)
 {
        outb(HPPRORESET_ON, dev.io + HP_PROR);
        mdelay(TIME_PRO_RESET);
@@ -1223,7 +1346,7 @@ __initfunc(static void reset_proteus(void))
 }
 #endif
 
-__initfunc(static int initialize(void))
+static int initialize(void)
 {
        int err, timeout;
 
@@ -1233,7 +1356,6 @@ __initfunc(static int initialize(void))
 
        reset_proteus();
 #endif
-
        if ((err = init_sma()) < 0) {
                printk(KERN_WARNING LOGNAME ": Cannot initialize SMA\n");
                return err;
@@ -1250,36 +1372,52 @@ __initfunc(static int initialize(void))
                printk(KERN_INFO LOGNAME ": DSP upload successful\n");
 
        timeout = 200;
-
        while (readw(dev.base)) {
                mdelay(1);
-               if (--timeout < 0)
+               if (!timeout--) {
+                       printk(KERN_DEBUG LOGNAME ": DSP reset timeout\n");
                        return -EIO;
+               }
        }
 
+       mixer_setup();
+
        return 0;
 }
 
+static int dsp_full_reset(void)
+{
+       int rv;
+
+       if (test_bit(F_RESETTING, &dev.flags) || ++dev.nresets > 10)
+               return 0;
+
+       printk(KERN_INFO LOGNAME ": Resetting DSP\n");
+       set_bit(F_RESETTING, &dev.flags);
+       dsp_halt(NULL);                 /* Unconditionally halt */
+       if ((rv = initialize()))
+               printk(KERN_WARNING LOGNAME ": DSP reset failed\n");
+       force_recsrc(dev.recsrc);
+       dsp_open(NULL);
+       clear_bit(F_RESETTING, &dev.flags);
+
+       return rv;
+}
+
 __initfunc(static int attach_multisound(void))
 {
        int err;
 
-       printk(KERN_DEBUG LOGNAME ": Intializing DSP\n");
-
-       if ((err = request_irq(dev.irq, intr, SA_SHIRQ, dev.name, &dev)) < 0) {
+       if ((err = request_irq(dev.irq, intr, 0, dev.name, &dev)) < 0) {
                printk(KERN_ERR LOGNAME ": Couldn't grab IRQ %d\n", dev.irq);
                return err;
-       
        }
-
        request_region(dev.io, dev.numio, dev.name);
 
-        if ((err = initialize()) < 0) {
-               printk(KERN_WARNING LOGNAME ": Initialization failure\n");
+        if ((err = dsp_full_reset()) < 0) {
                release_region(dev.io, dev.numio);
                free_irq(dev.irq, &dev);
                return err;
-
        }
 
        if ((err = msnd_register(&dev)) < 0) {
@@ -1307,15 +1445,17 @@ __initfunc(static int attach_multisound(void))
        }
        printk(KERN_INFO LOGNAME ": Using DSP minor %d, mixer minor %d\n", dev.dsp_minor, dev.mixer_minor);
 
-       calibrate_adc(dev.sample_rate);
+       disable_irq(dev.irq);
+       calibrate_adc(dev.play_sample_rate);
 #ifndef MSND_CLASSIC
        printk(KERN_INFO LOGNAME ": Setting initial recording source to Line In\n");
-       set_recsrc(SOUND_MASK_LINE);
+       force_recsrc(SOUND_MASK_LINE);
 #endif
        
        return 0;
 }
 
+#ifdef MODULE
 static void unload_multisound(void)
 {
        release_region(dev.io, dev.numio);
@@ -1324,6 +1464,7 @@ static void unload_multisound(void)
        unregister_sound_dsp(dev.dsp_minor);
        msnd_unregister(&dev);
 }
+#endif
 
 static void mod_inc_ref(void)
 {
@@ -1558,7 +1699,7 @@ static int mem __initdata =               CONFIG_MSNDPIN_MEM;
 #endif
 static int cfg __initdata =            CONFIG_MSNDPIN_CFG;
 /* If not a module, we don't need to bother with reset=1 */
-static int reset __initdata;
+static int reset;
 
 /* Extra Peripheral Configuration (Default: Disable) */
 #ifndef CONFIG_MSNDPIN_MPU_IO
@@ -1626,10 +1767,8 @@ __initfunc(int msnd_pinnacle_init(void))
        printk(KERN_INFO LOGNAME ": Turtle Beach " LONGNAME " Linux Driver Version "
               VERSION ", Copyright (C) 1998 Andrew Veliath\n");
        
-       if (io == -1 || irq == -1 || mem == -1) {
-
+       if (io == -1 || irq == -1 || mem == -1)
                printk(KERN_WARNING LOGNAME ": io, irq and mem must be set\n");
-       }
 
        if (io == -1 ||
            !(io == 0x290 ||
@@ -1640,7 +1779,6 @@ __initfunc(int msnd_pinnacle_init(void))
              io == 0x220 ||
              io == 0x210 ||
              io == 0x3e0)) {
-
                printk(KERN_ERR LOGNAME ": \"io\" - DSP I/O base must be set to 0x210, 0x220, 0x230, 0x240, 0x250, 0x260, 0x290, or 0x3E0\n");
                return -EINVAL;
        }
@@ -1652,7 +1790,6 @@ __initfunc(int msnd_pinnacle_init(void))
              irq == 10 ||
              irq == 11 ||
              irq == 12)) {
-               
                printk(KERN_ERR LOGNAME ": \"irq\" - must be set to 5, 7, 9, 10, 11 or 12\n");
                return -EINVAL;
        }
@@ -1664,7 +1801,6 @@ __initfunc(int msnd_pinnacle_init(void))
              mem == 0xd8000 ||
              mem == 0xe0000 ||
              mem == 0xe8000)) {
-               
                printk(KERN_ERR LOGNAME ": \"mem\" - must be set to "
                       "0xb0000, 0xc8000, 0xd0000, 0xd8000, 0xe0000 or 0xe8000\n");
                return -EINVAL;
@@ -1734,9 +1870,10 @@ __initfunc(int msnd_pinnacle_init(void))
        if (fifosize < 16)
                fifosize = 16;
 
-       if (fifosize > 768)
-               fifosize = 768;
+       if (fifosize > 1024)
+               fifosize = 1024;
 
+       set_default_audio_parameters();
 #ifdef MSND_CLASSIC
        dev.type = msndClassic;
 #else
@@ -1771,34 +1908,28 @@ __initfunc(int msnd_pinnacle_init(void))
        printk(KERN_INFO LOGNAME ": Using %u byte digital audio FIFOs (x2)\n", dev.fifosize);
 
        if ((err = msnd_fifo_alloc(&dev.DAPF, dev.fifosize)) < 0) {
-               
                printk(KERN_ERR LOGNAME ": Couldn't allocate write FIFO\n");
                return err;
        }
 
        if ((err = msnd_fifo_alloc(&dev.DARF, dev.fifosize)) < 0) {
-               
                printk(KERN_ERR LOGNAME ": Couldn't allocate read FIFO\n");
                msnd_fifo_free(&dev.DAPF);
                return err;
        }
 
        if ((err = probe_multisound()) < 0) {
-
                printk(KERN_ERR LOGNAME ": Probe failed\n");
                msnd_fifo_free(&dev.DAPF);
                msnd_fifo_free(&dev.DARF);
                return err;
-
        }
        
        if ((err = attach_multisound()) < 0) {
-
                printk(KERN_ERR LOGNAME ": Attach failed\n");
                msnd_fifo_free(&dev.DAPF);
                msnd_fifo_free(&dev.DARF);
                return err;
-
        }
 
        return 0;
@@ -1813,6 +1944,5 @@ void cleanup_module(void)
 
        msnd_fifo_free(&dev.DAPF);
        msnd_fifo_free(&dev.DARF);
-
 }
 #endif
index 0ae9a1026627a2010b558b4c2e13fb94a7a54a3c..2f572af2c723d78c0ae1ea96bf113bdf5c968df8 100644 (file)
@@ -24,7 +24,7 @@
  * along with this program; if not, write to the Free Software
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
- * $Id: msnd_pinnacle.h,v 1.8 1998/09/03 06:39:47 andrewtv Exp $
+ * $Id: msnd_pinnacle.h,v 1.10 1998/09/10 04:11:18 andrewtv Exp $
  *
  ********************************************************************/
 #ifndef __MSND_PINNACLE_H
index fd6e0b6f5f7dbf3491cfb08b38b10436c8afef14..701be528918e2b38a577a35677f4f8c8d1aab1ee 100644 (file)
@@ -796,7 +796,7 @@ static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int l
                        data = (unsigned short *)mbuf->data;
                        save_flags(flags);
                        cli();
-                       for (i = 0; i < mbuf->len; i++) {
+                       for (i = 0; i < sizeof(mbuf->data)/sizeof(unsigned short); i++) {
                                mbuf->len = i;  /* feed back number of WORDs read */
                                if (!pss_get_dspword(devc, data++)) {
                                        if (i == 0)
index 19f8ee825836190c57ce9089086386f16cb538a0..f3d99cff41b5d1f4e381f5193d227196c82a99ac 100644 (file)
@@ -122,7 +122,7 @@ void sb_setmixer (sb_devc *devc, unsigned int port, unsigned int value);
 unsigned int sb_getmixer (sb_devc *devc, unsigned int port);
 int sb_dsp_detect (struct address_info *hw_config);
 int sb_dsp_init (struct address_info *hw_config);
-void sb_dsp_unload(struct address_info *hw_config);
+void sb_dsp_unload(struct address_info *hw_config, int sbmpu);
 int sb_mixer_init(sb_devc *devc);
 void sb_mixer_set_stereo (sb_devc *devc, int mode);
 void smw_mixer_init(sb_devc *devc);
index 2fc88cb24e08935d5dc3fa03ac84ee438a7ea87d..7977f3ed970a6de0d3689dfcb811cd4ee235675f 100644 (file)
@@ -22,6 +22,8 @@
 #include "sb_mixer.h"
 #include "sb.h"
 
+static int sbmpu = 0;
+
 void attach_sb_card(struct address_info *hw_config)
 {
 #if defined(CONFIG_AUDIO) || defined(CONFIG_MIDI)
@@ -43,7 +45,7 @@ int probe_sb(struct address_info *hw_config)
 void unload_sb(struct address_info *hw_config)
 {
        if(hw_config->slots[0]!=-1)
-               sb_dsp_unload(hw_config);
+               sb_dsp_unload(hw_config, sbmpu);
 }
 
 int sb_be_quiet=0;
@@ -82,8 +84,6 @@ MODULE_PARM(trix, "i");
 MODULE_PARM(pas2, "i");
 MODULE_PARM(sm_games, "i");
 
-static int sbmpu = 0;
-
 void *smw_free = NULL;
 
 int init_module(void)
@@ -113,8 +113,6 @@ int init_module(void)
                config_mpu.io_base = mpu_io;
                if (mpu_io && probe_sbmpu(&config_mpu))
                        sbmpu = 1;
-#endif
-#ifdef CONFIG_MIDI
                if (sbmpu)
                        attach_sbmpu(&config_mpu);
 #endif
index 04b3d785414b6d41e9511c24e113380be6826400..f1a24cc109c25fe20286e4e30e90fba371a7f4e8 100644 (file)
@@ -932,7 +932,10 @@ void sb_dsp_disable_recording(int io_base)
 {
 }
 
-void sb_dsp_unload(struct address_info *hw_config)
+/* if (sbmpu) below we allow mpu401 to manage the midi devs
+   otherwise we have to unload them. (Andrzej Krzysztofowicz) */
+   
+void sb_dsp_unload(struct address_info *hw_config, int sbmpu)
 {
        sb_devc *devc;
 
@@ -951,10 +954,13 @@ void sb_dsp_unload(struct address_info *hw_config)
                if (!(devc->caps & SB_NO_AUDIO && devc->caps & SB_NO_MIDI) && devc->irq > 0)
                {
                        free_irq(devc->irq, devc);
-                       sound_unload_mixerdev(devc->my_mixerdev);
+                       if (devc->my_mixerdev)
+                               sound_unload_mixerdev(devc->my_mixerdev);
                        /* We don't have to do this bit any more the UART401 is its own
                                master  -- Krzysztof Halasa */
-                       /* sound_unload_mididev(devc->my_mididev); */
+                       /* But we have to do it, if UART401 is not detected */
+                       if (!sbmpu && devc->my_mididev)
+                               sound_unload_mididev(devc->my_mididev);
                        sound_unload_audiodev(devc->my_dev);
                }
                kfree(devc);
@@ -1301,10 +1307,8 @@ int probe_sbmpu(struct address_info *hw_config)
                        }
                        hw_config->name = "Sound Blaster 16";
                        hw_config->irq = -devc->irq;
-#if defined(CONFIG_MIDI) && defined(CONFIG_UART401)
                        if (devc->minor > 12)           /* What is Vibra's version??? */
                                sb16_set_mpu_port(devc, hw_config);
-#endif
                        break;
 
                case MDL_ESS:
index 970ec4a0bc85252ad7d62c059ed39de245f8717d..31a299a96b402cb5a1cc7d38559c4876cd403844 100644 (file)
@@ -182,8 +182,6 @@ void sb_dsp_midi_init(sb_devc * devc)
                printk(KERN_ERR "sb_midi: too many MIDI devices detected\n");
                return;
        }
-       std_midi_synth.midi_dev = dev;
-       devc->my_mididev = dev;
        std_midi_synth.midi_dev = devc->my_mididev = dev;
        midi_devs[dev] = (struct midi_operations *)kmalloc(sizeof(struct midi_operations), GFP_KERNEL);
        if (midi_devs[dev] == NULL)
index 7c4af3d0313a2e98850b3e49e20a60ccc8482c07..693433b1bd3a3ab162d1e032c357277833165cd4 100644 (file)
@@ -337,7 +337,10 @@ static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
                                  
                        case SOUND_MIXER_STEREODEVS:
                                ret = devc->supported_devices;
-                               if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
+                               /* The ESS seems to have stereo mic controls */
+                               if (devc->model == MDL_ESS)
+                                       ret &= ~(SOUND_MASK_SPEAKER|SOUND_MASK_IMIX);
+                               else if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
                                        ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
                                break;
                                  
index 5143335122073fe767d22faf73c1a3a3ce85bce2..3220de1297ab3606338c1576efd066de74aae9e5 100644 (file)
@@ -1540,12 +1540,12 @@ int sequencer_ioctl(int dev, struct file *file, unsigned int cmd, caddr_t arg)
                        return 0;
 
                case SNDCTL_MIDI_INFO:
-                       if (get_user(dev, (int *)(&(((struct synth_info *)arg)->device))))
+                       if (get_user(dev, (int *)(&(((struct midi_info *)arg)->device))))
                                return -EFAULT;
                        if (dev < 0 || dev >= max_mididev)
                                return -ENXIO;
                        midi_devs[dev]->info.device = dev;
-                       return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct synth_info))?-EFAULT:0;
+                       return copy_to_user(arg, &midi_devs[dev]->info, sizeof(struct midi_info))?-EFAULT:0;
 
                case SNDCTL_SEQ_THRESHOLD:
                        if (get_user(val, (int *)arg))
index 1ed1b8d7855ab9e2e49e6438cf5ffb32b2eab291..97113a838b719fc44d73a247e4626602f3eb1ad8 100644 (file)
@@ -39,6 +39,8 @@ static int mpu_initialized = 0;
 
 static int *trix_osp = NULL;
 
+static int mpu = 0;
+
 static unsigned char trix_read(int addr)
 {
        outb(((unsigned char) addr), 0x390);    /* MT-0002-PC ASIC address */
@@ -445,7 +447,7 @@ void unload_trix_mpu(struct address_info *hw_config)
 void unload_trix_sb(struct address_info *hw_config)
 {
 #ifdef CONFIG_SBDSP
-       sb_dsp_unload(hw_config);
+       sb_dsp_unload(hw_config, mpu);
 #endif
 }
 
@@ -479,7 +481,6 @@ struct address_info config;
 struct address_info sb_config;
 struct address_info mpu_config;
 
-static int      mpu = 0;
 static int      sb = 0;
 
 static int      fw_load;
index 3740dd263ce2d92ca7ee7e29ec5d4f0e1e214e18..e1b092a7e031a5814948017d59f6332f31517ac2 100644 (file)
@@ -49,7 +49,7 @@
  * aspects of configuring a WaveFront soundcard, particularly the
  * effects processor.
  *
- * $Id: wavfront.c,v 0.4 1998/07/22 02:12:11 pbd Exp $
+ * $Id: wavfront.c,v 0.5 1998/07/22 16:16:41 pbd Exp $
  *
  * This program is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
@@ -667,16 +667,16 @@ wavefront_cmd (wf_config *hw, int cmd,
 /***********************************************************************
 WaveFront: data munging   
 
-Things here are weird.  All data written to the board cannot 
-have its most significant bit set.  Any data item with values 
+Things here are wierd. All data written to the board cannot 
+have its most significant bit set. Any data item with values 
 potentially > 0x7F (127) must be split across multiple bytes.
 
 Sometimes, we need to munge numeric values that are represented on
-the x86 side as 8- to 32-bit values.  Sometimes, we need to munge data
-that is represented on the x86 side as an array of bytes.  The most
+the x86 side as 8-32 bit values. Sometimes, we need to munge data
+that is represented on the x86 side as an array of bytes. The most
 efficient approach to handling both cases seems to be to use 2
-different functions for munging and 2 for de-munging.  This avoids
-weird casting and worrying about bit-level offsets.
+different functions for munging and 2 for de-munging. This avoids
+wierd casting and worrying about bit-level offsets.
 
 **********************************************************************/
 
@@ -1198,14 +1198,14 @@ wavefront_send_sample (wf_config      *hw,
        shptr = munge_int32 (*((UINT32 *) &header->hdr.s.sampleEndOffset),
                             shptr, 4);
        
-       /* This one is truly weird.  What kind of weirdo decided that in
-          a system dominated by 16- and 32-bit integers, they would use
-          just 12 bits ?
+       /* This one is truly wierd. What kind of wierdo decided that in
+          a system dominated by 16 and 32 bit integers, they would use
+          just 12 bits ?
        */
        
        shptr = munge_int32 (header->hdr.s.FrequencyBias, shptr, 3);
        
-       /* Why is this nybblified, when the MSB is *always* zero? 
+       /* Why is this nybblified, when the MSB is *always* zero 
           Anyway, we can't take address of bitfield, so make a
           good-faith guess at where it starts.
        */
@@ -2278,6 +2278,12 @@ wavefront_hw_reset (wf_config *hw)
        int bits;
        int hwv[2];
 
+       /* Check IRQ is legal */
+
+       if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) {
+               return 1;
+       }
+
        if (request_irq (hw->irq, wavefrontintr,
                         0, "WaveFront", (void *) hw) < 0) {
                printk (KERN_WARNING "WaveFront: IRQ %d not available!\n",
@@ -2325,10 +2331,6 @@ wavefront_hw_reset (wf_config *hw)
           plus external 9-pin MIDI interface selected
        */
 
-       if ((bits = wavefront_interrupt_bits (hw->irq)) < 0) {
-               return 1;
-       }
-
        outb (0x80 | 0x40 | bits, hw->data_port);       
   
        /* CONTROL REGISTER
@@ -2350,7 +2352,6 @@ wavefront_hw_reset (wf_config *hw)
           wait till it gets back to use. After a cold boot, this can
           take some time.
           
-          
           I think this is because its only after a cold boot that the
           onboard ROM does its memory check, which can take "up to 4
           seconds" according to the WaveFront SDK. So, since sleeping
@@ -2797,51 +2798,50 @@ wavefront_do_reset (wf_config *hw, int atboot)
        if (hw->israw || wf_raw) {
                if (wavefront_download_firmware (hw, ospath)) {
                        goto gone_bad;
-                       return 1;
                }
-       }
 
-       if (fx_raw) {
-               wffx_init (hw);
-       }
-
-       /* If we loaded the OS, we now have to wait for it to be ready
-          to roll. We can't guarantee that interrupts are enabled,
-          because we might be reloading the module without forcing a
-          reset/reload of the firmware.
-          
-          Rather than busy-wait, lets just turn interrupts on.
-       */
-
-       outb (0x80|0x40|0x10|0x1, hw->control_port);
+               /* Wait for the OS to get running. The protocol for
+                  this is non-obvious, and was determined by
+                  using port-IO tracing in DOSemu and some
+                  experimentation here.
+                  
+                  Rather than busy-wait, use interrupts creatively.
+               */
 
-       wavefront_should_cause_interrupt (hw, WFC_NOOP,
+               wavefront_should_cause_interrupt (hw, WFC_NOOP,
                                          hw->data_port, (10*HZ));
-       
-       if (!hw->irq_ok) {
-               printk (KERN_WARNING "WaveFront: no post-OS interrupt.\n");
-               goto gone_bad;
-       }
-
-       /* Now, do it again ! */
+               
+               if (!hw->irq_ok) {
+                       printk (KERN_WARNING
+                               "WaveFront: no post-OS interrupt.\n");
+                       goto gone_bad;
+               }
+               
+               /* Now, do it again ! */
+               
+               wavefront_should_cause_interrupt (hw, WFC_NOOP,
+                                                 hw->data_port, (10*HZ));
+               
+               if (!hw->irq_ok) {
+                       printk (KERN_WARNING
+                               "WaveFront: no post-OS interrupt(2).\n");
+                       goto gone_bad;
+               }
 
-       wavefront_should_cause_interrupt (hw, WFC_NOOP,
-                                         hw->data_port, (10*HZ));
-       
-       if (!hw->irq_ok) {
-               printk (KERN_WARNING "WaveFront: no post-OS interrupt(2).\n");
-               goto gone_bad;
+               /* OK, no (RX/TX) interrupts any more, but leave mute
+                  on. Master interrupts get enabled when we're done here.
+               */
+               
+               outb (0x80, hw->control_port); 
+               
+               /* No need for the IRQ anymore */
+               
+               free_irq (hw->irq, hw);
        }
-       
-       /* OK, no (RX/TX) interrupts any more, but leave mute
-          on. Master interrupts get enabled when we're done here.
-       */
-
-       outb (0x80, hw->control_port); 
-
-       /* No need for the IRQ anymore */
 
-       free_irq (hw->irq, hw);
+       if (/*XXX has_fx_device() && */ fx_raw) {
+               wffx_init (hw);
+       }
 
        /* SETUPSND.EXE asks for sample memory config here, but since i
           have no idea how to interpret the result, we'll forget
@@ -3109,14 +3109,14 @@ wffx_ioctl (struct wf_config *hw, wavefront_fx_info *r)
 
 /* YSS225 initialization.
 
-   This code was developed using DOSEmu.  The Turtle Beach SETUPSND
-   utility was run with I/O tracing in DOSEmu enabled, and a reconstruction
+   This code was developed using DOSEMU. The Turtle Beach SETUPSND
+   utility was run with I/O tracing in DOSEMU enabled, and a reconstruction
    of the port I/O done, using the Yamaha faxback document as a guide
-   to add more logic to the code.  It's really pretty weird.
+   to add more logic to the code. Its really pretty wierd.
 
    There was an alternative approach of just dumping the whole I/O
    sequence as a series of port/value pairs and a simple loop
-   that output it.  However, I hope that eventually I'll get more
+   that output it. However, I hope that eventually I'll get more
    control over what this code does, and so I tried to stick with
    a somewhat "algorithmic" approach.
 */
@@ -3592,7 +3592,7 @@ int init_module (void)
 
 {
        printk ("Turtle Beach WaveFront Driver\n"
-               "Copyright (C) by Hannu Savolainen, "
+               "Copyright (C) by Hannu Solvainen, "
                "Paul Barton-Davis 1993-1998.\n");
 
        if (io == -1 || irq == -1) {
index 976eec39056fa266b3606f680313d727662c5b53..5664f22e31cfab408a9e665e1b5cb0722f3ca8b2 100644 (file)
@@ -379,6 +379,8 @@ static unsigned long load_aout_interp(struct exec * interp_ex,
        retval = read_exec(interpreter_dentry, offset, addr, text_data, 0);
        if (retval < 0)
                goto out;
+       flush_icache_range((unsigned long)addr,
+                          (unsigned long)addr + text_data);
 
        do_mmap(NULL, ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1),
                interp_ex->a_bss,
index 04215ad40e9cb9761e6e3775bb5a336f9121bb12..2c8a3cf8257e4a2ea2f371f416cb29fc83c66b88 100644 (file)
@@ -160,6 +160,9 @@ static int devpts_root_lookup(struct inode * dir, struct dentry * dentry)
                        entry += (*p++ - '0');
                }
        }
+
+       if (entry > sbi->max_ptys)
+               return -ENOENT;
        
        dentry->d_inode = sbi->inodes[entry];
        if ( dentry->d_inode )
index 25194e9a399b4e8a2d4624c48517e09f7b1acfcf..748b9e9336e2e09446e335b20246a21aa772811f 100644 (file)
@@ -221,13 +221,13 @@ static int parse_options(char *options,int *fat, int *blksize, int *debug,
                        if (value) ret = 0;
                        else opts->sys_immutable = 1;
                }
-               else if (!strcmp(this_char,"codepage")) {
+               else if (!strcmp(this_char,"codepage") && value) {
                        opts->codepage = simple_strtoul(value,&value,0);
                        if (*value) ret = 0;
                        else printk ("MSDOS FS: Using codepage %d\n",
                                        opts->codepage);
                }
-               else if (!strcmp(this_char,"iocharset")) {
+               else if (!strcmp(this_char,"iocharset") && value) {
                        p = value;
                        while (*value && *value != ',') value++;
                        len = value - p;
index 423f86e67510ee6c5beff9d84a1b040addbf1288..9bcf33dae6d6077fc5c689e15f7dfbc8985201e5 100644 (file)
@@ -1,3 +1,17 @@
+1998-09-11  a sun  <asun@purgatorius.zoology.washington.edu>
+
+       * mdb.c: altered mdb struct to reflect hfs plus usage.
+
+1998-08-27  a sun  <asun@purgatorius.zoology.washington.edu>
+
+       * file.c, file_hdr.c, file_cap.c: dealt with the remaining
+       copy_to/from_user() error cases.
+
+1998-08-26  a sun  <asun@purgatorius.zoology.washington.edu>
+
+       * super.c (hfs_read_super): fixed to deal with cdroms. why doesn't
+       the cdrom layer call the partition table code?
+
 Wed Jan 21 14:04:26 1998  a sun  <asun@zoology.washington.edu>
 
        * inode.c, sysdep.c
index 6157afb4730a501dc2220de7b8242f6314ca8f4f..0fe16a7386a8a3131861373b0dcabf40fb84d109 100644 (file)
@@ -267,15 +267,19 @@ static inline void xlate_to_user(char *buf, const char *data, int count)
  *
  * Like copy_from_user() while translating NL->CR;
  */
-static inline void xlate_from_user(char *data, const char *buf, int count)
+static inline int xlate_from_user(char *data, const char *buf, int count)
 {
-       count -= copy_from_user(data, buf, count);
+       int i;
+
+       i = copy_from_user(data, buf, count);
+       count -= i;
        while (count--) {
                if (*data == '\n') {
                        *data = '\r';
                }
                ++data;
        }
+       return i;
 }
 
 /*================ Global functions ================*/
@@ -404,6 +408,13 @@ hfs_s32 hfs_do_read(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
                                xlate_to_user(buf, p, chars);
                        } else {
                                chars -= copy_to_user(buf, p, chars);
+                               if (!chars) {
+                                       brelse(*bhe);
+                                       count = 0;
+                                       if (!read)
+                                               read = -EFAULT;
+                                       break;
+                               }
                        }
                        brelse(*bhe);
                        count -= chars;
@@ -477,10 +488,13 @@ hfs_s32 hfs_do_write(struct inode *inode, struct hfs_fork * fork, hfs_u32 pos,
                        }
                }
                p = (pos % HFS_SECTOR_SIZE) + bh->b_data;
-               if (convert) {
-                       xlate_from_user(p, buf, c);
-               } else {
-                       c -= copy_from_user(p, buf, c);
+               c -= convert ? xlate_from_user(p, buf, c) :
+                       copy_from_user(p, buf, c);
+               if (!c) {
+                       brelse(bh);
+                       if (!written)
+                               written = -EFAULT;
+                       break;
                }
                update_vm_cache(inode,pos,p,c);
                pos += c;
index 4fbd1f0908ed1e69b5c65c518c715c493de7a651..554624d25203f2769f5e47b5fba62e33dcfe606d 100644 (file)
@@ -236,7 +236,7 @@ static hfs_rwret_t cap_info_write(struct file *filp, const char *buf,
                end = pos + mem_count;
 
                cap_build_meta(&meta, entry);
-               copy_from_user(((char *)&meta) + pos, buf, mem_count);
+               mem_count -= copy_from_user(((char *)&meta) + pos, buf, mem_count);
 
                /* Update finder attributes if changed */
                if (OVERLAPS(pos, end, struct hfs_cap_info, fi_fndr)) {
index b12a4606b3d5d8210a274f520a0447dadaa228ca..13035e05632bcfa84b2f527d38190b3c82c30438 100644 (file)
@@ -610,7 +610,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
                        left = count;
                }
 
-               copy_from_user(((char *)&meta) + pos, buf, left);
+               left -= copy_from_user(((char *)&meta) + pos, buf, left);
                layout->magic   = hfs_get_nl(meta.magic);
                layout->version = hfs_get_nl(meta.version);
                layout->entries = hfs_get_hs(meta.entries);
@@ -642,7 +642,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
                        left = count;
                }
 
-               copy_from_user(((char *)&meta) + pos, buf, left);
+               left -= copy_from_user(((char *)&meta) + pos, buf, left);
                init_layout(layout, meta.descrs);
 
                count -= left;
@@ -782,7 +782,7 @@ static hfs_rwret_t hdr_write(struct file *filp, const char *buf,
 
                /* transfer the data from user space */
                if (p) {
-                       copy_from_user(p + offset, buf, left);
+                       left -= copy_from_user(p + offset, buf, left);
                } else if (fork) {
                        left = hfs_do_write(inode, fork, offset, buf, left);
                }
index 45ad05022c7af02207a16271ea8793197bc512bc..7f66e4ee617c18f5b6e9473ceebff6edd7b9e215 100644 (file)
@@ -29,6 +29,8 @@
  * the HFS equivalent of a superblock.
  *
  * Reference: _Inside Macintosh: Files_ pages 2-59 through 2-62
+ *
+ * modified for HFS Extended
  */
 struct raw_mdb {
        hfs_word_t      drSigWord;      /* Signature word indicating fs type */
@@ -60,9 +62,11 @@ struct raw_mdb {
        hfs_lword_t     drFilCnt;       /* number of files in the fs */
        hfs_lword_t     drDirCnt;       /* number of directories in the fs */
        hfs_byte_t      drFndrInfo[32]; /* data used by the Finder */
-       hfs_word_t      drVCSize;       /* MacOS caching parameter */
-       hfs_word_t      drVCBMSize;     /* MacOS caching parameter */
-       hfs_word_t      drCtlCSize;     /* MacOS caching parameter */
+       hfs_word_t      drEmbedSigWord; /* embedded volume signature */
+       hfs_lword_t     drEmbedExtent;  /* starting block number (xdrStABN) 
+                                          and number of allocation blocks 
+                                          (xdrNumABlks) occupied by embedded
+                                          volume */
        hfs_lword_t     drXTFlSize;     /* bytes in the extents B-tree */
        hfs_byte_t      drXTExtRec[12]; /* extents B-tree's first 3 extents */
        hfs_lword_t     drCTFlSize;     /* bytes in the catalog B-tree */
index d59340f1095fa625ce77c1b0e16a82933099e0ba..5891b493e997141a214e22727ff1dbc91aafe5c5 100644 (file)
@@ -201,8 +201,8 @@ isofs_find_entry(struct inode *dir, struct dentry *dentry, unsigned long *ino)
                 * Skip hidden or associated files unless unhide is set 
                 */
                match = 0;
-               if(   !(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
-                  || dir->i_sb->u.isofs_sb.s_unhide == 'y' )
+               if ((!(de->flags[-dir->i_sb->u.isofs_sb.s_high_sierra] & 5)
+                   || dir->i_sb->u.isofs_sb.s_unhide == 'y') && dlen)
                {
                        match = (isofs_cmp(dentry,dpnt,dlen) == 0);
                }
index 87c62e4c9cd356ec0797f62b48bdf24ea9f99ed4..d4b5c5bb0ebdeafa11cb95e4af559765c9d501a7 100644 (file)
@@ -149,10 +149,10 @@ static int msdos_format_name(char conv,const char *name,int len,
 static int msdos_find(struct inode *dir,const char *name,int len,
     struct buffer_head **bh,struct msdos_dir_entry **de,int *ino)
 {
-       char msdos_name[MSDOS_NAME];
        int res;
        char dotsOK;
        char scantype;
+       char msdos_name[MSDOS_NAME];
 
        dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
        res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
@@ -225,7 +225,9 @@ static struct dentry_operations msdos_dentry_operations = {
        NULL,           /* d_revalidate */
        msdos_hash,
        msdos_cmp,
-       NULL            /* d_delete */
+       NULL,           /* d_delete */
+       NULL,
+       NULL
 };
 
 struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
@@ -253,49 +255,45 @@ out_fail:
 int msdos_lookup(struct inode *dir,struct dentry *dentry)
 {
        struct super_block *sb = dir->i_sb;
-       int ino,res;
+       struct inode *inode = NULL;
        struct msdos_dir_entry *de;
        struct buffer_head *bh;
-       struct inode *inode;
+       int ino,res;
        
        PRINTK (("msdos_lookup\n"));
 
        dentry->d_op = &msdos_dentry_operations;
 
-       if(!dir) { /* N.B. This test is bogus -- should never happen */
-               d_add(dentry, NULL);
-               return 0;
-       }
-
-       if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,&bh,&de,&ino)) < 0) {
-               if(res == -ENOENT) {
-                       d_add(dentry, NULL);
-                       res = 0;
-               }
-               return res;
-       }
-       PRINTK (("msdos_lookup 4\n"));
+       res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
+                       &de, &ino);
+       if (res == -ENOENT)
+               goto add;
+       if (res < 0)
+               goto out;
        if (bh)
                fat_brelse(sb, bh);
-       PRINTK (("msdos_lookup 4.5\n"));
-       if (!(inode = iget(dir->i_sb,ino)))
-               return -EACCES;
-       PRINTK (("msdos_lookup 5\n"));
+
+       /* try to get the inode */
+       res = -EACCES;
+       inode = iget(dir->i_sb, ino);
+       if (!inode)
+               goto out;
        if (!inode->i_sb ||
-           (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
-               /* crossed a mount point into a non-msdos fs */
-               d_add(dentry, inode);
-               return 0;
+          (inode->i_sb->s_magic != MSDOS_SUPER_MAGIC)) {
+               printk(KERN_WARNING "msdos_lookup: foreign inode??\n");
        }
-       if (MSDOS_I(inode)->i_busy) { /* mkdir in progress */
+       /* mkdir in progress? */
+       if (MSDOS_I(inode)->i_busy) {
+               printk(KERN_WARNING "msdos_lookup: %s/%s busy\n",
+                       dentry->d_parent->d_name.name, dentry->d_name.name);
                iput(inode);
-               d_add(dentry, NULL); /* N.B. Do we really want a negative? */
-               return 0;
+               goto out;
        }
-       PRINTK (("msdos_lookup 6\n"));
+       res = 0;
+add:
        d_add(dentry, inode);
-       PRINTK (("msdos_lookup 7\n"));
-       return 0;
+out:
+       return res;
 }
 
 
@@ -308,9 +306,6 @@ static int msdos_create_entry(struct inode *dir, const char *name,
        struct msdos_dir_entry *de;
        int res,ino;
 
-       if(!dir)
-               return -ENOENT;
-
        *result = NULL;
        if ((res = fat_scan(dir,NULL,&bh,&de,&ino,SCAN_ANY)) < 0) {
                if (res != -ENOENT) return res;
@@ -350,14 +345,14 @@ int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct inode *inode;
-       char msdos_name[MSDOS_NAME];
        int ino,res,is_hid;
+       char msdos_name[MSDOS_NAME];
 
-       if (!dir) return -ENOENT;
-       if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
-                                    dentry->d_name.name,dentry->d_name.len,
-                                    msdos_name,0,
-                                    MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0)
+       res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
+                               dentry->d_name.name,dentry->d_name.len,
+                               msdos_name,0,
+                               MSDOS_SB(sb)->options.dotsOK);
+       if (res < 0)
                return res;
        is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
        fat_lock_creation();
@@ -434,8 +429,8 @@ static int msdos_empty(struct inode *dir)
 /***** Remove a directory */
 int msdos_rmdir(struct inode *dir, struct dentry *dentry)
 {
-       struct inode *inode = dentry->d_inode;
        struct super_block *sb = dir->i_sb;
+       struct inode *inode = dentry->d_inode;
        int res,ino;
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
@@ -493,13 +488,14 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
        struct buffer_head *bh;
        struct msdos_dir_entry *de;
        struct inode *inode,*dot;
-       char msdos_name[MSDOS_NAME];
        int ino,res,is_hid;
+       char msdos_name[MSDOS_NAME];
 
-       if ((res = msdos_format_name(MSDOS_SB(dir->i_sb)->options.name_check,
-                                    dentry->d_name.name,dentry->d_name.len,
-                                    msdos_name,0,
-                                    MSDOS_SB(dir->i_sb)->options.dotsOK)) < 0)
+       res = msdos_format_name(MSDOS_SB(sb)->options.name_check,
+                               dentry->d_name.name,dentry->d_name.len,
+                               msdos_name,0,
+                               MSDOS_SB(sb)->options.dotsOK);
+       if (res < 0)
                return res;
        is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
        fat_lock_creation();
@@ -537,6 +533,7 @@ int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
        iput(dot);
        d_instantiate(dentry, inode);
        return 0;
+
 mkdir_error:
        if (msdos_rmdir(dir,dentry) < 0)
                fat_fs_panic(dir->i_sb,"rmdir in mkdir failed");
@@ -546,10 +543,7 @@ out_unlock:
 }
 
 /***** Unlink a file */
-static int msdos_unlinkx(
-       struct inode *dir,
-       struct dentry *dentry,
-       int nospc)      /* Flag special file ? */
+static int msdos_unlinkx( struct inode *dir, struct dentry *dentry, int nospc)
 {
        struct super_block *sb = dir->i_sb;
        struct inode *inode = dentry->d_inode;
@@ -558,22 +552,25 @@ static int msdos_unlinkx(
        struct msdos_dir_entry *de;
 
        bh = NULL;
-       if ((res = msdos_find(dir,dentry->d_name.name,dentry->d_name.len,
-                             &bh,&de,&ino)) < 0)
+       res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
+                       &bh, &de, &ino);
+       if (res < 0)
                goto unlink_done;
        res = -EPERM;
        if (!S_ISREG(inode->i_mode) && nospc)
                goto unlink_done;
        if (IS_IMMUTABLE(inode))
                goto unlink_done;
+       /* N.B. check for busy files? */
+
        inode->i_nlink = 0;
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
        MSDOS_I(inode)->i_busy = 1;
        mark_inode_dirty(inode);
        mark_inode_dirty(dir);
+       d_delete(dentry);       /* This also frees the inode */
        de->name[0] = DELETED_FLAG;
        fat_mark_buffer_dirty(sb, bh, 1);
-       d_delete(dentry);       /* This also frees the inode */
        res = 0;
 unlink_done:
        fat_brelse(sb, bh);
@@ -592,28 +589,40 @@ int msdos_unlink_umsdos(struct inode *dir,struct dentry *dentry)
        return msdos_unlinkx (dir,dentry,0);
 }
 
+#define MSDOS_CHECK_BUSY 1
+
 /***** Rename within a directory */
-static int rename_same_dir(struct inode *old_dir,char *old_name,
+static int msdos_rename_same(struct inode *old_dir,char *old_name,
     struct dentry *old_dentry,
     struct inode *new_dir,char *new_name,struct dentry *new_dentry,
     struct buffer_head *old_bh,
-    struct msdos_dir_entry *old_de,int old_ino,int is_hid)
+    struct msdos_dir_entry *old_de, int old_ino, int is_hid)
 {
        struct super_block *sb = old_dir->i_sb;
        struct buffer_head *new_bh;
        struct msdos_dir_entry *new_de;
        struct inode *new_inode,*old_inode;
-       int new_ino,exists,error;
+       int new_ino, exists, error;
+
+       if (!strncmp(old_name, new_name, MSDOS_NAME))
+               goto set_hid;
+       error = -ENOENT;
+       if (*(unsigned char *) old_de->name == DELETED_FLAG)
+               goto out;
 
-       if (!strncmp(old_name,new_name,MSDOS_NAME)) goto set_hid;
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
-       if (*(unsigned char *) old_de->name == DELETED_FLAG) {
-               if (exists)
-                       fat_brelse(sb, new_bh);
-               return -ENOENT;
-       }
        if (exists) {
+               error = -EIO;
                new_inode = new_dentry->d_inode;
+               /* Make sure it really exists ... */
+               if (!new_inode) {
+                       printk(KERN_ERR
+                               "msdos_rename_same: %s/%s inode NULL, ino=%d\n",
+                               new_dentry->d_parent->d_name.name,
+                               new_dentry->d_name.name, new_ino);
+                       d_drop(new_dentry);
+                       goto out_error;
+               }
                error = S_ISDIR(new_inode->i_mode)
                        ? (old_de->attr & ATTR_DIR)
                                ? msdos_empty(new_inode)
@@ -621,11 +630,26 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
                        : (old_de->attr & ATTR_DIR)
                                ? -EPERM
                                : 0;
-               if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
-               if (error) {
-                       fat_brelse(sb, new_bh);
-                       return error;
+               if (error)
+                       goto out_error;
+               error = -EPERM;
+               if ((old_de->attr & ATTR_SYS))
+                       goto out_error;
+
+#ifdef MSDOS_CHECK_BUSY
+               /* check for a busy dentry */
+               error = -EBUSY;
+               if (new_dentry->d_count > 1) {
+                       shrink_dcache_parent(new_dentry);
+                       if (new_dentry->d_count > 1) {
+printk("msdos_rename_same: %s/%s busy, count=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
+new_dentry->d_count);
+                               goto out_error;
+                       }
                }
+#endif
+
                if (S_ISDIR(new_inode->i_mode)) {
                        new_dir->i_nlink--;
                        mark_inode_dirty(new_dir);
@@ -633,11 +657,16 @@ static int rename_same_dir(struct inode *old_dir,char *old_name,
                new_inode->i_nlink = 0;
                MSDOS_I(new_inode)->i_busy = 1;
                mark_inode_dirty(new_inode);
+#ifdef MSDOS_CHECK_BUSY
+               /* d_delete the dentry, as we killed its inode */
+               d_delete(new_dentry);
+#endif
+
                new_de->name[0] = DELETED_FLAG;
                fat_mark_buffer_dirty(sb, new_bh, 1);
                fat_brelse(sb, new_bh);
        }
-       memcpy(old_de->name,new_name,MSDOS_NAME);
+       memcpy(old_de->name, new_name, MSDOS_NAME);
        /* Update the dcache */
        d_move(old_dentry, new_dentry);
 set_hid:
@@ -650,51 +679,63 @@ set_hid:
        MSDOS_I(old_inode)->i_attrs = is_hid
                ? (MSDOS_I(old_inode)->i_attrs |  ATTR_HIDDEN)
                : (MSDOS_I(old_inode)->i_attrs &~ ATTR_HIDDEN);
-       return 0;
+       error = 0;
+out:
+       return error;
+
+out_error:
+       fat_brelse(sb, new_bh);
+       goto out;
 }
 
 /***** Rename across directories - a nonphysical move */
-static int rename_diff_dir(struct inode *old_dir,char *old_name,
+static int msdos_rename_diff(struct inode *old_dir, char *old_name,
     struct dentry *old_dentry,
-    struct inode *new_dir,char *new_name,struct dentry *new_dentry,
+    struct inode *new_dir,char *new_name, struct dentry *new_dentry,
     struct buffer_head *old_bh,
-    struct msdos_dir_entry *old_de,int old_ino,int is_hid)
+    struct msdos_dir_entry *old_de, int old_ino, int is_hid)
 {
        struct super_block *sb = old_dir->i_sb;
        struct buffer_head *new_bh,*free_bh,*dotdot_bh;
        struct msdos_dir_entry *new_de,*free_de,*dotdot_de;
        struct inode *old_inode,*new_inode,*free_inode,*dotdot_inode;
-       struct dentry *walk;
        int new_ino,free_ino,dotdot_ino;
-       int error,exists;
+       int error, exists;
 
-       if (old_dir->i_dev != new_dir->i_dev) return -EINVAL;
-       if (old_ino == new_dir->i_ino) return -EINVAL;
-       walk = new_dentry;
+       error = -EINVAL;
+       if (old_ino == new_dir->i_ino)
+               goto out;
        /* prevent moving directory below itself */
-       for (;;) {
-               if (walk == old_dentry) return -EINVAL;
-               if (walk == walk->d_parent) break;
-               walk = walk->d_parent;
-       }
+       if (is_subdir(new_dentry, old_dentry))
+               goto out;
+
+       error = -ENOENT;
+       if (*(unsigned char *) old_de->name == DELETED_FLAG)
+               goto out;
+
        /* find free spot */
-       while ((error = fat_scan(new_dir,NULL,&free_bh,&free_de,&free_ino,
-           SCAN_ANY)) < 0) {
-               if (error != -ENOENT) return error;
+       while ((error = fat_scan(new_dir, NULL, &free_bh, &free_de, &free_ino,
+                                       SCAN_ANY)) < 0) {
+               if (error != -ENOENT)
+                       goto out;
                error = fat_add_cluster(new_dir);
-               if (error) return error;
+               if (error)
+                       goto out;
        }
+
        exists = fat_scan(new_dir,new_name,&new_bh,&new_de,&new_ino,SCAN_ANY) >= 0;
-       old_inode = old_dentry->d_inode;
-       if (*(unsigned char *) old_de->name == DELETED_FLAG) {
-               fat_brelse(sb, free_bh);
-               if (exists)
-                       fat_brelse(sb, new_bh);
-               return -ENOENT;
-       }
-       new_inode = NULL; /* to make GCC happy */
        if (exists) {  /* Trash the old file! */
+               error = -EIO;
                new_inode = new_dentry->d_inode;
+               /* Make sure it really exists ... */
+               if (!new_inode) {
+                       printk(KERN_ERR
+                               "msdos_rename_diff: %s/%s inode NULL, ino=%d\n",
+                               new_dentry->d_parent->d_name.name,
+                               new_dentry->d_name.name, new_ino);
+                       d_drop(new_dentry);
+                       goto out_new;
+               }
                error = S_ISDIR(new_inode->i_mode)
                        ? (old_de->attr & ATTR_DIR)
                                ? msdos_empty(new_inode)
@@ -702,39 +743,87 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
                        : (old_de->attr & ATTR_DIR)
                                ? -EPERM
                                : 0;
-               if (!error && (old_de->attr & ATTR_SYS)) error = -EPERM;
-               if (error) {
-                       fat_brelse(sb, new_bh);
-                       return error;
+               if (error)
+                       goto out_new;
+               error = -EPERM;
+               if ((old_de->attr & ATTR_SYS))
+                       goto out_new;
+
+#ifdef MSDOS_CHECK_BUSY
+               /* check for a busy dentry */
+               error = -EBUSY;
+               if (new_dentry->d_count > 1) {
+                       shrink_dcache_parent(new_dentry);
+                       if (new_dentry->d_count > 1) {
+printk("msdos_rename_diff: target %s/%s busy, count=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
+new_dentry->d_count);
+                               goto out_new;
+                       }
+               }
+#endif
+               if (S_ISDIR(new_inode->i_mode)) {
+                       new_dir->i_nlink--;
+                       mark_inode_dirty(new_dir);
                }
                new_inode->i_nlink = 0;
                MSDOS_I(new_inode)->i_busy = 1;
                mark_inode_dirty(new_inode);
+#ifdef MSDOS_CHECK_BUSY
+               /* d_delete the dentry, as we killed its inode */
+               d_delete(new_dentry);
+#endif
                new_de->name[0] = DELETED_FLAG;
                fat_mark_buffer_dirty(sb, new_bh, 1);
+               fat_brelse(sb, new_bh);
        }
-       memcpy(free_de,old_de,sizeof(struct msdos_dir_entry));
-       memcpy(free_de->name,new_name,MSDOS_NAME);
+
+       old_inode = old_dentry->d_inode;
+       /* Get the dotdot inode if we'll need it ... */
+       dotdot_bh = NULL;
+       dotdot_inode = NULL;
+       if (S_ISDIR(old_inode->i_mode)) {
+               error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
+                               &dotdot_de, &dotdot_ino, SCAN_ANY);
+               if (error < 0)
+                       goto rename_done;
+               error = -EIO;
+               dotdot_inode = iget(sb, dotdot_ino);
+               if (!dotdot_inode)
+                       goto out_dotdot;
+       }
+
+       /* get an inode for the new name */
+       memcpy(free_de, old_de, sizeof(struct msdos_dir_entry));
+       memcpy(free_de->name, new_name, MSDOS_NAME);
        free_de->attr = is_hid
                ? (free_de->attr|ATTR_HIDDEN)
                : (free_de->attr&~ATTR_HIDDEN);
-       if (!(free_inode = iget(new_dir->i_sb,free_ino))) {
-               free_de->name[0] = DELETED_FLAG;
-               /*
-                * Don't mark free_bh as dirty. Both states 
-                * are supposed to be equivalent.
-                */
-               fat_brelse(sb, free_bh);
-               if (exists)
-                       fat_brelse(sb, new_bh);
-               return -EIO;
-       }
-       if (exists && S_ISDIR(new_inode->i_mode)) {
-               new_dir->i_nlink--;
-               mark_inode_dirty(new_dir);
-       }
+
+       error = -EIO;
+       free_inode = iget(sb, free_ino);
+       if (!free_inode)
+               goto out_iput;
        msdos_read_inode(free_inode);
 
+       /*
+        * Make sure the old dentry isn't busy,
+        * as we need to change inodes ...
+        */
+       if (old_dentry->d_count > 1) {
+               shrink_dcache_parent(old_dentry);
+               if (old_dentry->d_count > 1) {
+printk("msdos_rename_diff: source %s/%s busy, count=%d\n",
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+old_dentry->d_count);
+                       goto out_iput;
+               }
+       }
+
+       /* keep the inode for a bit ... */
+       old_inode->i_count++;
+       d_delete(old_dentry);
+
        free_inode->i_mode   = old_inode->i_mode;
        free_inode->i_size   = old_inode->i_size;
        free_inode->i_blocks = old_inode->i_blocks;
@@ -747,29 +836,20 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
        MSDOS_I(free_inode)->i_logstart = MSDOS_I(old_inode)->i_logstart;
        MSDOS_I(free_inode)->i_attrs = MSDOS_I(old_inode)->i_attrs;
 
-       /* Detach d_alias from old inode and attach to new inode */
-       list_del(&old_dentry->d_alias);
+       /*
+        * Install the new inode ...
+        */
        d_instantiate(old_dentry, free_inode);
-       iput(old_inode);
 
        fat_cache_inval_inode(old_inode);
        mark_inode_dirty(old_inode);
        old_de->name[0] = DELETED_FLAG;
        fat_mark_buffer_dirty(sb, old_bh, 1);
        fat_mark_buffer_dirty(sb, free_bh, 1);
+       iput(old_inode);
 
-       if (exists) {
-               /* free_inode is put after putting new_inode and old_inode */
-               fat_brelse(sb, new_bh);
-       }
-       if (S_ISDIR(old_inode->i_mode)) {
-               if ((error = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
-                   &dotdot_de,&dotdot_ino,SCAN_ANY)) < 0) goto rename_done;
-               if (!(dotdot_inode = iget(old_inode->i_sb,dotdot_ino))) {
-                       fat_brelse(sb, dotdot_bh);
-                       error = -EIO;
-                       goto rename_done;
-               }
+       /* a directory? */
+       if (dotdot_bh) {
                MSDOS_I(dotdot_inode)->i_start = MSDOS_I(new_dir)->i_start;
                MSDOS_I(dotdot_inode)->i_logstart = MSDOS_I(new_dir)->i_logstart;
                dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
@@ -787,9 +867,26 @@ static int rename_diff_dir(struct inode *old_dir,char *old_name,
        /* Update the dcache */
        d_move(old_dentry, new_dentry);
        error = 0;
+
 rename_done:
        fat_brelse(sb, free_bh);
+out:
        return error;
+
+out_iput:
+       free_de->name[0] = DELETED_FLAG;
+       /*
+        * Don't mark free_bh as dirty. Both states 
+        * are supposed to be equivalent.
+        */
+       iput(free_inode); /* may be NULL */
+       iput(dotdot_inode);
+out_dotdot:
+       fat_brelse(sb, dotdot_bh);
+       goto rename_done;
+out_new:
+       fat_brelse(sb, new_bh);
+       goto rename_done;
 }
 
 /***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
@@ -797,36 +894,45 @@ int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
                 struct inode *new_dir,struct dentry *new_dentry)
 {
        struct super_block *sb = old_dir->i_sb;
-       char old_msdos_name[MSDOS_NAME],new_msdos_name[MSDOS_NAME];
        struct buffer_head *old_bh;
        struct msdos_dir_entry *old_de;
-       int old_ino,error;
+       int old_ino, error;
        int is_hid,old_hid; /* if new file and old file are hidden */
-
-       if ((error = msdos_format_name(MSDOS_SB(old_dir->i_sb)->options.name_check,
-                                      old_dentry->d_name.name,
-                                      old_dentry->d_name.len,old_msdos_name,1,
-                                      MSDOS_SB(old_dir->i_sb)->options.dotsOK))
-           < 0) goto rename_done;
-       if ((error = msdos_format_name(MSDOS_SB(new_dir->i_sb)->options.name_check,
-                                      new_dentry->d_name.name,
-                                      new_dentry->d_name.len,new_msdos_name,0,
-                                      MSDOS_SB(new_dir->i_sb)->options.dotsOK))
-           < 0) goto rename_done;
-       is_hid = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
+       char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
+
+       error = -EINVAL;
+       if (sb != new_dir->i_sb)
+               goto rename_done;
+       error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
+                               old_dentry->d_name.name, old_dentry->d_name.len,
+                               old_msdos_name, 1,MSDOS_SB(sb)->options.dotsOK);
+       if (error < 0)
+               goto rename_done;
+       error = msdos_format_name(MSDOS_SB(sb)->options.name_check,
+                               new_dentry->d_name.name, new_dentry->d_name.len,
+                               new_msdos_name, 0,MSDOS_SB(sb)->options.dotsOK);
+       if (error < 0)
+               goto rename_done;
+
+       is_hid  = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
        old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
-       if ((error = fat_scan(old_dir,old_msdos_name,&old_bh,&old_de,
-           &old_ino,old_hid?SCAN_HID:SCAN_NOTHID)) < 0) goto rename_done;
+       error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de,
+                       &old_ino, old_hid?SCAN_HID:SCAN_NOTHID);
+       if (error < 0)
+               goto rename_done;
+
        fat_lock_creation();
        if (old_dir == new_dir)
-               error = rename_same_dir(old_dir,old_msdos_name,old_dentry,
-                   new_dir,new_msdos_name,new_dentry,
-                   old_bh,old_de,old_ino,is_hid);
-       else error = rename_diff_dir(old_dir,old_msdos_name,old_dentry,
-                    new_dir,new_msdos_name,new_dentry,
-                    old_bh,old_de,old_ino,is_hid);
+               error = msdos_rename_same(old_dir, old_msdos_name, old_dentry,
+                                       new_dir, new_msdos_name, new_dentry,
+                                       old_bh, old_de, (ino_t)old_ino, is_hid);
+       else
+               error = msdos_rename_diff(old_dir, old_msdos_name, old_dentry,
+                                       new_dir, new_msdos_name, new_dentry,
+                                       old_bh, old_de, (ino_t)old_ino, is_hid);
        fat_unlock_creation();
        fat_brelse(sb, old_bh);
+
 rename_done:
        return error;
 }
index 4b28aec2e6fb138838c27d39bf4d879cdefacffb..f61e49e57266203a658d7dfd67f8aefd95950f51 100644 (file)
@@ -844,7 +844,7 @@ static int get_stat(int pid, char * buffer)
 
        return sprintf(buffer,"%d (%s) %c %d %d %d %d %d %lu %lu \
 %lu %lu %lu %lu %lu %ld %ld %ld %ld %ld %ld %lu %lu %ld %lu %lu %lu %lu %lu \
-%lu %lu %lu %lu %lu %lu %lu %lu\n",
+%lu %lu %lu %lu %lu %lu %lu %lu %d\n",
                pid,
                tsk->comm,
                state,
@@ -885,7 +885,8 @@ static int get_stat(int pid, char * buffer)
                sigcatch    .sig[0] & 0x7fffffffUL,
                wchan,
                tsk->nswap,
-               tsk->cnswap);
+               tsk->cnswap,
+               tsk->exit_signal);
 }
                
 static inline void statm_pte_range(pmd_t * pmd, unsigned long address, unsigned long size,
@@ -1224,6 +1225,11 @@ static long get_root_array(char * page, int type, char **start,
                case PROC_PCI:
                        return get_pci_list(page);
 #endif
+
+#ifdef CONFIG_NUBUS
+               case PROC_NUBUS:
+                       return get_nubus_list(page);
+#endif                 
                        
                case PROC_CPUINFO:
                        return get_cpuinfo(page);
index 5fa82929ba0d9aa4809ebef306e05a34fe78b933..375ff6f75a7d29fe79cb4e5c19a61bef109add4f 100644 (file)
@@ -52,8 +52,8 @@ void sysv_free_block(struct super_block * sb, unsigned int block)
         * into this block being freed:
         */
        if (*sb->sv_sb_flc_count == sb->sv_flc_size) {
-               unsigned short * flc_count;
-               unsigned long * flc_blocks;
+               u16 * flc_count;
+               u32 * flc_blocks;
 
                bh = sv_getblk(sb, sb->s_dev, block);
                if (!bh) {
@@ -154,8 +154,8 @@ int sysv_new_block(struct super_block * sb)
                return 0;
        }
        if (*sb->sv_sb_flc_count == 0) { /* the last block continues the free list */
-               unsigned short * flc_count;
-               unsigned long * flc_blocks;
+               u16 * flc_count;
+               u32 * flc_blocks;
 
                if (!(bh = sv_bread(sb, sb->s_dev, block))) {
                        printk("sysv_new_block: cannot read free-list block\n");
@@ -247,8 +247,8 @@ unsigned long sysv_count_free_blocks(struct super_block * sb)
                }
                /* block = sb->sv_sb_flc_blocks[0], the last block continues the free list */
                while (1) {
-                       unsigned short * flc_count;
-                       unsigned long * flc_blocks;
+                       u16 * flc_count;
+                       u32 * flc_blocks;
 
                        if (block < sb->sv_firstdatazone || block >= sb->sv_nzones) {
                                printk("sysv_count_free_blocks: new block %d is not in data zone\n",block);
index 96b0649a4b01580e6f1d70c9d218a0bef20a5374..ddffd7de26ba12da27baa29333d1436e84c035b4 100644 (file)
 /* Sync one block. The block number is
  * from_coh_ulong(*blockp) if convert=1, *blockp if convert=0.
  */
-static int sync_block (struct inode * inode, unsigned long * blockp, int convert, int wait)
+static int sync_block (struct inode * inode, u32 *blockp, int convert, int wait)
 {
        struct buffer_head * bh;
-       unsigned long tmp, block;
+       u32 tmp, block;
        struct super_block * sb;
 
        block = tmp = *blockp;
@@ -59,11 +59,11 @@ static int sync_block (struct inode * inode, unsigned long * blockp, int convert
 }
 
 /* Sync one block full of indirect pointers and read it because we'll need it. */
-static int sync_iblock (struct inode * inode, unsigned long * iblockp, int convert,
+static int sync_iblock (struct inode * inode, u32 * iblockp, int convert,
                        struct buffer_head * *bh, int wait)
 {
        int rc;
-       unsigned long tmp, block;
+       u32 tmp, block;
 
        *bh = NULL;
        block = tmp = *iblockp;
@@ -101,7 +101,7 @@ static int sync_direct(struct inode *inode, int wait)
        return err;
 }
 
-static int sync_indirect(struct inode *inode, unsigned long *iblockp, int convert, int wait)
+static int sync_indirect(struct inode *inode, u32 *iblockp, int convert, int wait)
 {
        int i;
        struct buffer_head * ind_bh;
@@ -115,7 +115,7 @@ static int sync_indirect(struct inode *inode, unsigned long *iblockp, int conver
        sb = inode->i_sb;
        for (i = 0; i < sb->sv_ind_per_block; i++) {
                rc = sync_block (inode,
-                                ((unsigned long *) ind_bh->b_data) + i, sb->sv_convert,
+                                ((u32 *) ind_bh->b_data) + i, sb->sv_convert,
                                 wait);
                if (rc > 0)
                        break;
@@ -126,7 +126,7 @@ static int sync_indirect(struct inode *inode, unsigned long *iblockp, int conver
        return err;
 }
 
-static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int convert,
+static int sync_dindirect(struct inode *inode, u32 *diblockp, int convert,
                          int wait)
 {
        int i;
@@ -141,7 +141,7 @@ static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int conv
        sb = inode->i_sb;
        for (i = 0; i < sb->sv_ind_per_block; i++) {
                rc = sync_indirect (inode,
-                                   ((unsigned long *) dind_bh->b_data) + i, sb->sv_convert,
+                                   ((u32 *) dind_bh->b_data) + i, sb->sv_convert,
                                    wait);
                if (rc > 0)
                        break;
@@ -152,7 +152,7 @@ static int sync_dindirect(struct inode *inode, unsigned long *diblockp, int conv
        return err;
 }
 
-static int sync_tindirect(struct inode *inode, unsigned long *tiblockp, int convert,
+static int sync_tindirect(struct inode *inode, u32 *tiblockp, int convert,
                          int wait)
 {
        int i;
@@ -167,7 +167,7 @@ static int sync_tindirect(struct inode *inode, unsigned long *tiblockp, int conv
        sb = inode->i_sb;
        for (i = 0; i < sb->sv_ind_per_block; i++) {
                rc = sync_dindirect (inode,
-                                    ((unsigned long *) tind_bh->b_data) + i, sb->sv_convert,
+                                    ((u32 *) tind_bh->b_data) + i, sb->sv_convert,
                                     wait);
                if (rc > 0)
                        break;
index 583b94c256b6fac411eece48afba861cf9534149..f2cf52087475ae122ed30fc47874ae6d5dccb7e0 100644 (file)
@@ -30,7 +30,7 @@
 #include <linux/string.h>
 #include <linux/locks.h>
 #include <linux/init.h>
-
+#include <asm/byteorder.h>
 #include <asm/uaccess.h>
 
 #if 0
@@ -532,7 +532,7 @@ void sysv_write_super (struct super_block *sb)
 
 void sysv_put_super(struct super_block *sb)
 {
-       /* we can assume sysv_write_super() has already been called, and
+       /* we can assume sysv_write_super() has already been called,
           and that the superblock is locked */
        brelse(sb->sv_bh1);
        if (sb->sv_bh1 != sb->sv_bh2) brelse(sb->sv_bh2);
@@ -648,8 +648,8 @@ int sysv_bmap(struct inode * inode,int block_nr)
 static struct buffer_head * inode_getblk(struct inode * inode, int nr, int create)
 {
        struct super_block *sb;
-       unsigned long tmp;
-       unsigned long *p;
+       u32 tmp;
+       u32 *p;
        struct buffer_head * result;
 
        sb = inode->i_sb;
@@ -684,7 +684,7 @@ static struct buffer_head * block_getblk(struct inode * inode,
        struct buffer_head * bh, int nr, int create)
 {
        struct super_block *sb;
-       unsigned long tmp, block;
+       u32 tmp, block;
        sysv_zone_t *p;
        struct buffer_head * result;
 
@@ -782,26 +782,43 @@ struct buffer_head * sysv_file_bread(struct inode * inode, int block, int create
        return NULL;
 }
 
+#ifdef __BIG_ENDIAN
+
+static inline unsigned long read3byte (unsigned char * p)
+{
+       return (p[2] | (p[1]<<8) | (p[0]<<16));
+}
+
+static inline void write3byte (unsigned char *p , unsigned long val)
+{
+       p[2]=val&0xFF;
+       p[1]=(val>>8)&0xFF;
+       p[0]=(val>>16)&0xFF;
+}
+
+#else
 
-static inline unsigned long read3byte (char * p)
+static inline unsigned long read3byte (unsigned char * p)
 {
        return (unsigned long)(*(unsigned short *)p)
             | (unsigned long)(*(unsigned char *)(p+2)) << 16;
 }
 
-static inline void write3byte (char * p, unsigned long val)
+static inline void write3byte (unsigned char * p, unsigned long val)
 {
        *(unsigned short *)p = (unsigned short) val;
        *(unsigned char *)(p+2) = val >> 16;
 }
 
-static inline unsigned long coh_read3byte (char * p)
+#endif
+
+static inline unsigned long coh_read3byte (unsigned char * p)
 {
        return (unsigned long)(*(unsigned char *)p) << 16
             | (unsigned long)(*(unsigned short *)(p+1));
 }
 
-static inline void coh_write3byte (char * p, unsigned long val)
+static inline void coh_write3byte (unsigned char * p, unsigned long val)
 {
        *(unsigned char *)p = val >> 16;
        *(unsigned short *)(p+1) = (unsigned short) val;
index 7c919caff637be3a49f5281f9bfaaa6dd93c25ba..c318648a99bf1380436a7332daa356d55f096fae 100644 (file)
@@ -41,8 +41,8 @@ static int trunc_direct(struct inode * inode)
 {
        struct super_block * sb;
        unsigned int i;
-       unsigned long * p;
-       unsigned long block;
+       u32 * p;
+       u32 block;
        struct buffer_head * bh;
        int retry = 0;
 
@@ -71,7 +71,7 @@ repeat:
        return retry;
 }
 
-static int trunc_indirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
+static int trunc_indirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt)
 {
        unsigned long indtmp, indblock;
        struct super_block * sb;
@@ -140,14 +140,14 @@ done:
        return retry;
 }
 
-static int trunc_dindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
+static int trunc_dindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt)
 {
-       unsigned long indtmp, indblock;
+       u32 indtmp, indblock;
        struct super_block * sb;
        struct buffer_head * indbh;
        unsigned int i;
        sysv_zone_t * ind;
-       unsigned long tmp, block;
+       u32 tmp, block;
        int retry = 0;
 
        indblock = indtmp = *p;
@@ -197,14 +197,14 @@ done:
        return retry;
 }
 
-static int trunc_tindirect(struct inode * inode, unsigned long offset, unsigned long * p, int convert, unsigned char * dirt)
+static int trunc_tindirect(struct inode * inode, unsigned long offset, sysv_zone_t * p, int convert, unsigned char * dirt)
 {
-       unsigned long indtmp, indblock;
+       u32 indtmp, indblock;
        struct super_block * sb;
        struct buffer_head * indbh;
        unsigned int i;
        sysv_zone_t * ind;
-       unsigned long tmp, block;
+       u32 tmp, block;
        int retry = 0;
 
        indblock = indtmp = *p;
index 5a7bcd8540667084ef220d30d30a6ff64aed0620..11c8040821a52926f31d01a34661cb8297f25f1f 100644 (file)
 #define UMSDOS_SPECIAL_DIRFPOS 3
 extern struct inode *pseudo_root;
 
+/* #define UMSDOS_DEBUG_VERBOSE 1 */
 
+/*
+ * Dentry operations routines
+ */
+
+/* nothing for now ... */
+static int umsdos_dentry_validate(struct dentry *dentry)
+{
+       return 1;
+}
+
+/* for now, drop everything to force lookups ... */
+static void umsdos_dentry_dput(struct dentry *dentry)
+{
+       struct inode *inode = dentry->d_inode;
+       if (inode) {
+               d_drop(dentry);
+       }
+}
+
+static struct dentry_operations umsdos_dentry_operations =
+{
+       umsdos_dentry_validate, /* d_validate(struct dentry *) */
+       NULL,                   /* d_hash */
+       NULL,                   /* d_compare */
+       umsdos_dentry_dput,     /* d_delete(struct dentry *) */
+       NULL,
+       NULL,
+};
 
 /*
  * This needs to have the parent dentry passed to it.
@@ -109,9 +138,9 @@ static int umsdos_dir_once (        void *buf,
  * Return a negative value from linux/errno.h.
  * Return > 0 if success (the number of bytes written by filldir).
  * 
- * This function is used by the normal readdir VFS entry point and by
- * some function who try to find out info on a file from a pure MSDOS
- * inode. See umsdos_locate_ancestor() below.
+ * This function is used by the normal readdir VFS entry point,
+ * and in order to get the directory entry from a file's dentry.
+ * See umsdos_dentry_to_entry() below.
  */
  
 static int umsdos_readdir_x (struct inode *dir, struct file *filp,
@@ -175,8 +204,10 @@ Printk (("umsdos_readdir_x: what UMSDOS_SPECIAL_DIRFPOS /mn/?\n"));
        if (IS_ERR(demd))
                goto out_end;
        ret = 0;
-       if (!demd->d_inode)
+       if (!demd->d_inode) {
+printk("no EMD file??\n");
                goto out_dput;
+       }
 
        /* set up our private filp ... */
        fill_new_filp(&new_filp, demd);
@@ -189,33 +220,56 @@ Printk (("f_pos %Ld i_size %ld\n", new_filp.f_pos, demd->d_inode->i_size));
        ret = 0;
        while (new_filp.f_pos < demd->d_inode->i_size) {
                off_t cur_f_pos = new_filp.f_pos;
-               struct umsdos_info info;
                struct dentry *dret;
+               struct inode *inode;
                struct umsdos_dirent entry;
+               struct umsdos_info info;
 
                ret = -EIO;
                if (umsdos_emd_dir_readentry (&new_filp, &entry) != 0)
                        break;
-
                if (entry.name_len == 0)
-                       goto remove_name;
+                       continue;
 
                umsdos_parse (entry.name, entry.name_len, &info);
                info.f_pos = cur_f_pos;
                umsdos_manglename (&info);
+               /*
+                * Do a real lookup on the short name.
+                */
                dret = umsdos_lookup_dentry(filp->f_dentry, info.fake.fname,
-                                                info.fake.len);
+                                                info.fake.len, 1);
                ret = PTR_ERR(dret);
                if (IS_ERR(dret))
                        break;
+               /*
+                * If the file wasn't found, remove it from the EMD.
+                */
+               if (!dret->d_inode)
+                       goto remove_name;
 
-Printk (("Looking for inode of %s/%s, flags=%x\n",
-dret->d_parent->d_name.name, info.fake.fname, entry.flags));
+Printk (("Found %s/%s, ino=%ld, flags=%x\n",
+dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
+entry.flags));
+               /* check whether to resolve a hard-link */
                if ((entry.flags & UMSDOS_HLINK) && follow_hlink) {
                        dret = umsdos_solve_hlink (dret);
                        ret = PTR_ERR(dret);
                        if (IS_ERR(dret))
                                break;
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_readdir_x: link is %s/%s, ino=%ld\n",
+dret->d_parent->d_name.name, dret->d_name.name,
+(dret->d_inode ? dret->d_inode->i_ino : 0));
+#endif
+               }
+
+               /* save the inode ptr and number, then free the dentry */
+               inode = dret->d_inode;
+               if (!inode) {
+printk("umsdos_readdir_x: %s/%s negative after link\n",
+dret->d_parent->d_name.name, dret->d_name.name);
+                       goto clean_up;
                }
                                        
                /* #Specification:  pseudo root / reading real root
@@ -225,20 +279,21 @@ dret->d_parent->d_name.name, info.fake.fname, entry.flags));
                 * infinite recursion (/DOS/linux/DOS/linux/...) while
                 * walking the file system.
                 */
-               if (dret->d_inode != pseudo_root &&
+               if (inode != pseudo_root &&
                    (internal_read || !(entry.flags & UMSDOS_HIDDEN))) {
-                       Printk ((KERN_DEBUG "filldir now\n"));
                        if (filldir (dirbuf, entry.name, entry.name_len,
-                                cur_f_pos, dret->d_inode->i_ino) < 0) {
+                                cur_f_pos, inode->i_ino) < 0) {
                                new_filp.f_pos = cur_f_pos;
                        }
-Printk (("Found %s/%s(%ld)\n",
-dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino));
+Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
+dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));
                        if (u_entry != NULL)
                                *u_entry = entry;
                        dput(dret);
+                       ret = 0;
                        break;
                }
+       clean_up:
                dput(dret);
                continue;
 
@@ -248,11 +303,17 @@ dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino));
                 * in the MS-DOS directory any more, the entry is
                 * removed from the EMD file silently.
                 */
-               Printk (("'Silently' removing EMD for file\n"));
-               ret = umsdos_delentry(filp->f_dentry, &info, 1);
+#ifdef UMSDOS_PARANOIA
+printk("umsdos_readdir_x: %s/%s out of sync, erased\n",
+filp->f_dentry->d_name.name, info.entry.name);
+#endif
+               ret = umsdos_delentry(filp->f_dentry, &info, 
+                                       S_ISDIR(info.entry.mode));
                if (ret)
-                       break;
-               continue;
+                       printk(KERN_WARNING 
+                               "umsdos_readdir_x: delentry %s, err=%d\n",
+                               info.entry.name, ret);
+               goto clean_up;
        }
        /*
         * If the fillbuf has failed, f_pos is back to 0.
@@ -296,8 +357,6 @@ static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
                struct umsdos_dirent entry;
 
                bufk.count = 0;
-               PRINTK (("UMSDOS_readdir: calling _x (%p,%p,%p,%d,%p,%d,%p)\n",
-                       dir, filp, &bufk, 0, &entry, 1, umsdos_dir_once));
                ret = umsdos_readdir_x (dir, filp, &bufk, 0, &entry, 1, 
                                        umsdos_dir_once);
                if (bufk.count == 0)
@@ -509,8 +568,8 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                err = umsdos_readdir_x (parent->d_inode, &filp, &bufk, 1, 
                                entry, 0, umsdos_filldir_k);
                if (err < 0) { 
-                       printk ("UMSDOS: can't locate inode %ld in EMD??\n",
-                               inode->i_ino);
+                       printk ("umsdos_dentry_to_entry: ino=%ld, err=%d\n",
+                               inode->i_ino, err);
                        break;
                }
                if (bufk.ino == inode->i_ino) {
@@ -523,73 +582,6 @@ out:
        return ret;
 }
 
-/*
- * Deprecated. Try to get rid of this soon!
- */
-int umsdos_inode2entry (struct inode *dir, struct inode *inode,
-                              struct umsdos_dirent *entry)
-{
-       int ret = -ENOENT;
-       struct inode *emddir;
-       struct dentry *i2e;
-       struct file filp;
-       struct UMSDOS_DIR_SEARCH bufsrch;
-       struct UMSDOS_DIRENT_K bufk;
-
-       if (pseudo_root && inode == pseudo_root) {
-               /*
-                * Quick way to find the name.
-                * Also umsdos_readdir_x won't show /linux anyway
-                */
-               memcpy (entry->name, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN + 1);
-               entry->name_len = UMSDOS_PSDROOT_LEN;
-               ret = 0;
-               goto out;
-       }
-
-       emddir = umsdos_emd_dir_lookup (dir, 0);
-       if (emddir == NULL) {
-               /* This is a DOS directory. */
-               i2e = creat_dentry ("@i2e.nul@", 9, dir, NULL);
-               fill_new_filp (&filp, i2e);
-               filp.f_reada = 1;
-               filp.f_pos = 0;
-               bufsrch.entry = entry;
-               bufsrch.search_ino = inode->i_ino;
-               fat_readdir (&filp, &bufsrch, umsdos_dir_search);
-               if (bufsrch.found) {
-                       ret = 0;
-                       inode->u.umsdos_i.i_dir_owner = dir->i_ino;
-                       inode->u.umsdos_i.i_emd_owner = 0;
-                       umsdos_setup_dir_inode (inode);
-               }
-               goto out;
-       }
-
-       /* skip . and .. see umsdos_readdir_x() */
-
-       i2e = creat_dentry ("@i2e.nn@", 8, dir, NULL);
-       fill_new_filp (&filp, i2e);
-       filp.f_reada = 1;
-       filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
-       while (1) {
-               if (umsdos_readdir_x (dir, &filp, &bufk, 1, 
-                               entry, 0, umsdos_filldir_k) < 0) {
-                       printk ("UMSDOS: can't locate inode %ld in EMD??\n",
-                               inode->i_ino);
-                       break;
-               }
-               if (bufk.ino == inode->i_ino) {
-                       ret = 0;
-                       umsdos_lookup_patch (dir, inode, entry, bufk.f_pos);
-                       break;
-               }
-       }
-       iput (emddir);
-out:
-       return ret;
-}
-
 
 /*
  * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
@@ -638,6 +630,11 @@ int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
        int ret = -ENOENT;
        struct umsdos_info info;
 
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_lookup_x: looking for %s/%s\n", 
+dentry->d_parent->d_name.name, dentry->d_name.name);
+#endif
+
        umsdos_startlookup (dir);
        /* this shouldn't happen ... */
        if (len == 1 && name[0] == '.') {
@@ -664,38 +661,53 @@ int umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
        }
 
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
-       if (ret)
+       if (ret) {
+printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n", 
+dentry->d_parent->d_name.name, dentry->d_name.name, ret);
                goto out;
+       }
+
        ret = umsdos_findentry (dentry->d_parent, &info, 0);
+       if (ret) {
+if (ret != -ENOENT)
+printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n", 
+dentry->d_parent->d_name.name, dentry->d_name.name, ret);
+               goto out;
+       }
 Printk (("lookup %.*s pos %lu ret %d len %d ", 
 info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
-       if (ret)
-               goto out;
-
 
+       /* do a real lookup to get the short name ... */
        dret = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname,
-                                       info.fake.len);
+                                       info.fake.len, 1);
        ret = PTR_ERR(dret);
        if (IS_ERR(dret))
                goto out;
        if (!dret->d_inode)
                goto out_remove;
-
        umsdos_lookup_patch_new(dret, &info.entry, info.f_pos);
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_lookup_x: found %s/%s, ino=%ld\n", 
+dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
+#endif
 
        /* Check for a hard link */
        if (info.entry.flags & UMSDOS_HLINK) {
-Printk (("checking hard link %s/%s, ino=%ld, flags=%x\n", 
-dret->d_parent->d_name.name, dret->d_name.name,
-dret->d_inode->i_ino, info.entry.flags));
                dret = umsdos_solve_hlink (dret);
                ret = PTR_ERR(dret);
                if (IS_ERR(dret))
                        goto out;
        }
-       /* N.B. can dentry be negative after resolving hlinks? */
 
-       if (pseudo_root && dret->d_inode == pseudo_root && !nopseudo) {
+       ret = -ENOENT;
+       inode = dret->d_inode;
+       if (!inode) {
+printk("umsdos_lookup_x: %s/%s negative after link\n", 
+dret->d_parent->d_name.name, dret->d_name.name);
+               goto out_dput;
+       }
+
+       if (inode == pseudo_root && !nopseudo) {
                /* #Specification: pseudo root / dir lookup
                 * For the same reason as readdir, a lookup in /DOS for
                 * the pseudo root directory (linux) will fail.
@@ -705,23 +717,22 @@ dret->d_inode->i_ino, info.entry.flags));
                 * which are recorded independently of the pseudo-root
                 * mode.
                 */
-               Printk (("umsdos_lookup_x: untested Pseudo_root\n"));
-               ret = -ENOENT;
+printk(KERN_WARNING "umsdos_lookup_x: untested, inode == Pseudo_root\n");
                goto out_dput;
-       } else {
-               /* We've found it OK.  Now put inode in dentry. */
-               inode = dret->d_inode;
        }
 
        /*
-        * Hash the dentry with the inode.
+        * We've found it OK.  Now hash the dentry with the inode.
         */
 out_add:
        inode->i_count++;
        d_add (dentry, inode);
+       dentry->d_op = &umsdos_dentry_operations;
        ret = 0;
 
 out_dput:
+       if (dret != dentry)
+               d_drop(dret);
        dput(dret);
 out:
        umsdos_endlookup (dir);
@@ -729,10 +740,10 @@ out:
 
 out_remove:
        printk(KERN_WARNING "UMSDOS:  entry %s/%s out of sync, erased\n",
-               dentry->d_name.name, info.fake.fname);
+               dentry->d_parent->d_name.name, dentry->d_name.name);
        umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
        ret = -ENOENT;
-       goto out;
+       goto out_dput;
 }
 
 
@@ -756,6 +767,7 @@ int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
                Printk ((KERN_DEBUG 
                        "UMSDOS_lookup: converting -ENOENT to negative\n"));
                d_add (dentry, NULL);
+               dentry->d_op = &umsdos_dentry_operations;
                ret = 0;
        }
        return ret;
@@ -768,7 +780,8 @@ int UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
  * We need to use this instead of lookup_dentry, as the 
  * directory semaphore lock is already held.
  */
-struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len)
+struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
+                                       int real)
 {
        struct dentry *result, *dentry;
        int error;
@@ -783,7 +796,9 @@ struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len)
                dentry = d_alloc(parent, &qstr);
                if (dentry) {
                        result = dentry;
-                       error = umsdos_real_lookup(parent->d_inode, result);
+                       error = real ?
+                               UMSDOS_rlookup(parent->d_inode, result) :
+                               UMSDOS_lookup(parent->d_inode, result);
                        if (error)
                                goto out_fail;
                }
@@ -797,6 +812,21 @@ out_fail:
        goto out;
 }
 
+/*
+ * Return a path relative to our root.
+ */
+char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
+{
+       struct dentry * old_root = current->fs->root;
+       char * path;
+
+       /* N.B. not safe -- fix this soon! */
+       current->fs->root = dentry->d_sb->s_root;
+       path = d_path(dentry, buffer, len);
+       current->fs->root = old_root;
+       return path;
+}
+       
 
 /*
  * gets dentry which points to pseudo-hardlink
@@ -812,96 +842,99 @@ struct dentry *umsdos_solve_hlink (struct dentry *hlink)
 {
        /* root is our root for resolving pseudo-hardlink */
        struct dentry *base = hlink->d_sb->s_root;
-       struct dentry *final, *dir, *dentry_dst;
+       struct dentry *dentry_dst;
        char *path, *pt;
-       unsigned long len;
-       int ret = -EIO;
+       int len;
        struct file filp;
 
-       check_dentry_path (hlink, "HLINK BEGIN hlink");
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_solve_hlink: following %s/%s\n", 
+hlink->d_parent->d_name.name, hlink->d_name.name);
+#endif
 
-       final = ERR_PTR (-ENOMEM);
+       dentry_dst = ERR_PTR (-ENOMEM);
        path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
        if (path == NULL)
                goto out;
 
        fill_new_filp (&filp, hlink);
        filp.f_flags = O_RDONLY;
-       filp.f_pos = 0;
 
-       Printk (("hlink2inode "));
        len = umsdos_file_read_kmem (&filp, path, hlink->d_inode->i_size);
        if (len != hlink->d_inode->i_size)
                goto out_noread;
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk ("umsdos_solve_hlink: %s/%s is path %s\n",
+hlink->d_parent->d_name.name, hlink->d_name.name, path);
+#endif
 
        /* start at root dentry */
-       dir = dget(base);
-       path[hlink->d_inode->i_size] = '\0';
-       pt = path;
+       dentry_dst = dget(base);
+       path[len] = '\0';
+       pt = path + 1; /* skip leading '/' */
        while (1) {
+               struct dentry *dir = dentry_dst, *demd;
                char *start = pt;
-               int len;
+               int real;
 
                while (*pt != '\0' && *pt != '/') pt++;
                len = (int) (pt - start);
                if (*pt == '/') *pt++ = '\0';
 
-               dentry_dst = umsdos_lookup_dentry(dir, start, len);
+               real = (dir->d_inode->u.umsdos_i.i_emd_dir == 0);
+               /*
+                * Hack alert! inode->u.umsdos_i.i_emd_dir isn't reliable,
+                * so just check whether there's an EMD file ...
+                */
+               real = 1;
+               demd = umsdos_get_emd_dentry(dir);
+               if (!IS_ERR(demd)) {
+                       if (demd->d_inode)
+                               real = 0;
+                       dput(demd);
+               }
+
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk ("umsdos_solve_hlink: dir %s/%s, name=%s, emd_dir=%ld, real=%d\n",
+dir->d_parent->d_name.name, dir->d_name.name, start,
+dir->d_inode->u.umsdos_i.i_emd_dir, real);
+#endif
+               dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
+               if (real)
+                       d_drop(dir);
+               dput (dir);
                if (IS_ERR(dentry_dst))
                        break;
-               if (dir->d_inode->u.umsdos_i.i_emd_dir == 0) {
-                       /* This is a DOS directory */
-                       ret = umsdos_rlookup_x (dir->d_inode, dentry_dst, 1);
-               } else {
-                       ret = umsdos_lookup_x (dir->d_inode, dentry_dst, 1);
-               }
-               Printk (("  returned %d\n", ret));
-               dput (dir);     /* dir no longer needed */
-               dir = dentry_dst;
-
-               Printk (("h2n lookup :%s: -> %d ", start, ret));
-               final = ERR_PTR (ret);
-               if (ret != 0) {
-                       /* path component not found! */
+               /* not found? stop search ... */
+               if (!dentry_dst->d_inode) {
                        break;
                }
-               if (*pt == '\0') {      /* we're finished! */
-                       final = umsdos_lookup_dentry(hlink->d_parent,
-                                               (char *) hlink->d_name.name,
-                                               hlink->d_name.len);
+               if (*pt == '\0')        /* we're finished! */
                        break;
-               }
        } /* end while */
-       /*
-        * See whether we found the path ...
-        */
-       if (!IS_ERR(final)) {
-               if (!final->d_inode) {
-                       d_instantiate(final, dir->d_inode);
-                       /* we need inode to survive. */
-                       dir->d_inode->i_count++;        
-               } else {
-                       printk ("umsdos_solve_hlink: %s/%s already exists\n",
-                               final->d_parent->d_name.name,
-                               final->d_name.name);
-               }
-printk ("umsdos_solve_hlink: ret = %d, %s/%s -> %s/%s\n",
-ret, hlink->d_parent->d_name.name, hlink->d_name.name,
-final->d_parent->d_name.name, final->d_name.name);
-       }
-       dput(dir);
+
+       if (IS_ERR(dentry_dst))
+               printk ("umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst));
+#ifdef UMSDOS_DEBUG_VERBOSE
+       else if (!dentry_dst->d_inode)
+               printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n",
+                       dentry_dst->d_parent->d_name.name,
+                       dentry_dst->d_name.name);
+       else
+               printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
+                       dentry_dst->d_parent->d_name.name,
+                       dentry_dst->d_name.name, dentry_dst->d_inode->i_ino);
+#endif
 
 out_free:
        kfree (path);
 
 out:
        dput(hlink);    /* original hlink no longer needed */
-       check_dentry_path (hlink, "HLINK FIN hlink");
-       check_dentry_path (final, "HLINK RET final");
-       return final;
+       return dentry_dst;
 
 out_noread:
-       printk("umsdos_solve_hlink: failed reading pseudolink!\n");
+       printk(KERN_WARNING "umsdos_solve_hlink: failed reading pseudolink!\n");
        goto out_free;
 }      
 
@@ -943,5 +976,4 @@ struct inode_operations umsdos_dir_inode_operations =
        NULL,                   /* smap */
        NULL,                   /* updatepage */
        NULL,                   /* revalidate */
-
 };
index 2f56b040445c2629d5ffc88e72a3134d67a5213a..21c20360693d7011e8e3d47d41ab6d8c26cbd8ff 100644 (file)
@@ -30,46 +30,12 @@ ssize_t umsdos_file_read_kmem (     struct file *filp,
                                char *buf,
                                size_t count)
 {
-       int ret;
-
+       ssize_t ret;
        mm_segment_t old_fs = get_fs ();
 
        set_fs (KERNEL_DS);
-
-       PRINTK ((KERN_DEBUG "umsdos_file_read_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d\n", filp, buf, count));
-       PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-       PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
-       PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-       PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary));
-       PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-       PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
-       PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
-       PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
-
        MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
-
        ret = fat_file_read (filp, buf, count, &filp->f_pos);
-       PRINTK ((KERN_DEBUG "fat_file_read returned with %d!\n", ret));
-
-       PRINTK ((KERN_DEBUG "  (ret) inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-       PRINTK ((KERN_DEBUG "  (ret) f_pos=%Lu\n", filp->f_pos));
-       PRINTK ((KERN_DEBUG "  (ret) name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-       PRINTK ((KERN_DEBUG "  (ret) i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary));
-       PRINTK ((KERN_DEBUG "  (ret) f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-       PRINTK ((KERN_DEBUG "  (ret) f_owner=%d\n", filp->f_owner.uid));
-       PRINTK ((KERN_DEBUG "  (ret) f_version=%ld\n", filp->f_version));
-       PRINTK ((KERN_DEBUG "  (ret) f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
-
-#if 0
-       {
-               struct umsdos_dirent *mydirent = buf;
-
-               Printk ((KERN_DEBUG "  (DDD) uid=%d\n", mydirent->uid));
-               Printk ((KERN_DEBUG "  (DDD) gid=%d\n", mydirent->gid));
-               Printk ((KERN_DEBUG "  (DDD) name=>%.20s<\n", mydirent->name));
-       }
-#endif
-
        set_fs (old_fs);
        return ret;
 }
@@ -90,28 +56,22 @@ ssize_t umsdos_file_write_kmem_real (struct file * filp,
 
        set_fs (KERNEL_DS);
 
-       PRINTK ((KERN_DEBUG "umsdos_file_write_kmem /mn/: Checkin: filp=%p, buf=%p, size=%d\n", filp, buf, count));
-       PRINTK ((KERN_DEBUG "  struct dentry=%p\n", filp->f_dentry));
-       PRINTK ((KERN_DEBUG "  struct inode=%p\n", filp->f_dentry->d_inode));
-       PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp->f_dentry->d_inode->i_ino, filp->f_dentry->d_inode->i_size));
-       PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp->f_pos));
-       PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp->f_dentry->d_name.len, filp->f_dentry->d_name.name));
-       PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I (filp->f_dentry->d_inode)->i_binary));
-       PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp->f_count, filp->f_flags));
-       PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp->f_owner.uid));
-       PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp->f_version));
-       PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp->f_reada, filp->f_ramax, filp->f_raend, filp->f_ralen, filp->f_rawin));
-
        /* note: i_binary=2 is for CVF-FAT. We put it here, instead of
-        * umsdos_file_write_kmem, since it is also wise not to compress symlinks
-        * (in the unlikely event that they are > 512 bytes and can be compressed 
-        * FIXME: should we set it when reading symlinks too? */
+        * umsdos_file_write_kmem, since it is also wise not to compress
+        * symlinks (in the unlikely event that they are > 512 bytes and
+        * can be compressed.
+        * FIXME: should we set it when reading symlinks too?
+        */
 
        MSDOS_I (filp->f_dentry->d_inode)->i_binary = 2;
 
        ret = fat_file_write (filp, buf, count, &filp->f_pos);
-       Printk ((KERN_DEBUG "fat_file_write returned with %ld!\n", (long int) ret));
-
+#ifdef UMSDOS_PARANOIA
+       if (ret != count) {
+               printk(KERN_WARNING "umsdos_file_write: count=%u, ret=%u\n",
+                       count, ret);
+       }
+#endif
        set_fs (old_fs);
        return ret;
 }
@@ -125,9 +85,8 @@ ssize_t umsdos_file_write_kmem (struct file *filp,
                                const char *buf,
                                size_t count)
 {
-       int ret;
+       ssize_t ret;
 
-       Printk ((KERN_DEBUG " STARTED WRITE_KMEM /mn/\n"));
        ret = umsdos_file_write_kmem_real (filp, buf, count);
        return ret;
 }
@@ -166,7 +125,6 @@ ssize_t umsdos_emd_dir_write (      struct file *filp,
 Printk (("umsdos_emd_dir_write /mn/: calling write_kmem with %p, %p, %d, %Ld\n",
 filp, buf, count, filp->f_pos));
        written = umsdos_file_write_kmem (filp, buf, count);
-       Printk (("umsdos_emd_dir_write /mn/: write_kmem returned\n"));
 
 #ifdef __BIG_ENDIAN
        d->nlink = le16_to_cpu (d->nlink);
@@ -179,13 +137,13 @@ filp, buf, count, filp->f_pos));
        d->mode = le16_to_cpu (d->mode);
 #endif
 
-#if UMS_DEBUG
+#ifdef UMSDOS_PARANOIA
 if (written != count)
 printk(KERN_ERR "umsdos_emd_dir_write: ERROR: written (%d) != count (%d)\n",
 written, count);
 #endif
 
-       return written != count ? -EIO : 0;
+       return (written != count) ? -EIO : 0;
 }
 
 
@@ -199,9 +157,7 @@ written, count);
 
 ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count)
 {
-       long int ret = 0;
-       int sizeread;
-
+       ssize_t sizeread, ret = 0;
 
 #ifdef __BIG_ENDIAN
        struct umsdos_dirent *d = (struct umsdos_dirent *) buf;
@@ -211,8 +167,9 @@ ssize_t umsdos_emd_dir_read (struct file *filp, char *buf, size_t count)
        filp->f_flags = 0;
        sizeread = umsdos_file_read_kmem (filp, buf, count);
        if (sizeread != count) {
-printk ("UMSDOS:  problem with EMD file:  can't read pos = %Ld (%d != %d)\n",
-filp->f_pos, sizeread, count);
+               printk (KERN_WARNING 
+                       "UMSDOS: EMD problem, pos=%Ld, count=%d, read=%d\n",
+                       filp->f_pos, count, sizeread);
                ret = -EIO;
        }
 #ifdef __BIG_ENDIAN
@@ -226,7 +183,6 @@ filp->f_pos, sizeread, count);
        d->mode = le16_to_cpu (d->mode);
 #endif
        return ret;
-
 }
 
 
@@ -237,8 +193,8 @@ struct dentry *umsdos_get_emd_dentry(struct dentry *parent)
 {
        struct dentry *demd;
 
-       demd = umsdos_lookup_dentry (parent, UMSDOS_EMD_FILE, 
-                                       UMSDOS_EMD_NAMELEN);
+       demd = umsdos_lookup_dentry(parent, UMSDOS_EMD_FILE, 
+                                       UMSDOS_EMD_NAMELEN, 1);
        return demd;
 }
 
@@ -260,7 +216,7 @@ int umsdos_have_emd(struct dentry *dir)
 
 /*
  * Create the EMD file for a directory if it doesn't
- * already exist. Returns 0 or and error code.
+ * already exist. Returns 0 or an error code.
  */
 int umsdos_make_emd(struct dentry *parent)
 {
@@ -272,22 +228,23 @@ int umsdos_make_emd(struct dentry *parent)
                goto out;
 
        /* already created? */
+       err = 0;
        inode = demd->d_inode;
-       if (inode) {
-               parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino;
-               err = 0;
-               goto out_dput;
-       }
+       if (inode)
+               goto out_set;
 
-printk("umsdos_make_emd: creating %s/%s\n",
-parent->d_name.name, demd->d_name.name);
+Printk(("umsdos_make_emd: creating %s/%s\n",
+parent->d_name.name, demd->d_name.name));
 
        err = msdos_create(parent->d_inode, demd, S_IFREG | 0777);
        if (err) {
-               printk (KERN_WARNING "UMSDOS: Can't create EMD file\n");
+               printk (KERN_WARNING
+                       "UMSDOS: Can't create EMD file %s/%s\n",
+                       parent->d_name.name, demd->d_name.name);
                goto out_dput;
        }
        inode = demd->d_inode;
+out_set:
        parent->d_inode->u.umsdos_i.i_emd_dir = inode->i_ino;
        /* Disable UMSDOS_notify_change() for EMD file */
        inode->u.umsdos_i.i_emd_owner = 0xffffffff;
@@ -338,7 +295,7 @@ printk("UMSDOS: flaky i_dentry hack failed\n");
        dlook = creat_dentry (UMSDOS_EMD_FILE, UMSDOS_EMD_NAMELEN, NULL, d_dir);
        if (!dlook)
                goto out;
-       rv = umsdos_real_lookup (dir, dlook);
+       rv = msdos_lookup (dir, dlook);
                
        PRINTK ((KERN_DEBUG "-returned %d\n", rv));
        Printk ((KERN_INFO "emd_dir_lookup "));
@@ -450,7 +407,7 @@ parent->d_parent->d_name.name, parent->d_name.name);
 
        if (free_entry) {
                /* #Specification: EMD file / empty entries
-                * Unused entry in the EMD file are identified
+                * Unused entries in the EMD file are identified
                 * by the name_len field equal to 0. However to
                 * help future extension (or bug correction :-( ),
                 * empty entries are filled with 0.
@@ -662,6 +619,8 @@ demd->d_parent->d_name.name, demd->d_name.name, emd_dir));
                        }
                }
        }
+Printk(("umsdos_find: ready to mangle %s, len=%d, pos=%ld\n",
+entry->name, entry->name_len, (long)info->f_pos));
        umsdos_manglename (info);
 
 out_dput:
index 5277c95481b0ffc7511fd7c9510404cd2904df3b..339d828011f2043a26bd62473b04a6a42070ba9c 100644 (file)
@@ -32,15 +32,12 @@ static ssize_t UMSDOS_file_read (
        struct dentry *dentry = filp->f_dentry;
        struct inode *inode = dentry->d_inode;
 
-       /* We have to set the access time because msdos don't care */
-       /* FIXME */
        int ret = fat_file_read (filp, buf, count, ppos);
 
+       /* We have to set the access time because msdos don't care */
        if (!IS_RDONLY (inode)) {
                inode->i_atime = CURRENT_TIME;
-               /* FIXME 
-                * inode->i_dirt = 1;
-                */
+               mark_inode_dirty(inode);
        }
        return ret;
 }
@@ -65,10 +62,11 @@ static ssize_t UMSDOS_file_write (
 static void UMSDOS_truncate (struct inode *inode)
 {
        Printk (("UMSDOS_truncate\n"));
-       fat_truncate (inode);
-       inode->i_ctime = inode->i_mtime = CURRENT_TIME;
-
-       /*FIXME inode->i_dirt = 1; */
+       if (!IS_RDONLY (inode)) {
+               fat_truncate (inode);
+               inode->i_ctime = inode->i_mtime = CURRENT_TIME;
+               mark_inode_dirty(inode);
+       }
 }
 
 /* Function for normal file system (512 bytes hardware sector size) */
index ca20bb8c30d063619ea487add22ddb89c78630c1..c15a243695f588fb23c3d87ffdd00aa22bd5b0b4 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/umsdos_fs.h>
 #include <linux/list.h>
 
+extern struct dentry_operations umsdos_dentry_operations;
 extern struct inode_operations umsdos_rdir_inode_operations;
 
 
@@ -59,7 +60,7 @@ struct dentry *geti_dentry (struct inode *inode)
 void fill_new_filp (struct file *filp, struct dentry *dentry)
 {
        if (!dentry)
-               printk("fill_new_filp: NULL dentry!\n");
+               printk(KERN_ERR "fill_new_filp: NULL dentry!\n");
 
        memset (filp, 0, sizeof (struct file));
        filp->f_reada = 1;
@@ -133,7 +134,7 @@ void UMSDOS_put_inode (struct inode *inode)
                 ,inode->u.umsdos_i.i_emd_owner, inode->u.umsdos_i.pos
                 ,inode->u.umsdos_i.i_emd_dir, inode->i_count));
 
-       if (inode && pseudo_root && inode == pseudo_root) {
+       if (inode == pseudo_root) {
                printk (KERN_ERR "Umsdos: Oops releasing pseudo_root."
                        " Notify jacques@solucorp.qc.ca\n");
        }
@@ -150,23 +151,6 @@ void UMSDOS_put_super (struct super_block *sb)
 }
 
 
-/*
- * Call msdos_lookup, but set back the original msdos function table.
- * Return 0 if OK, or a negative error code if not.
- * Dentry will hold inode of the file, if successful
- */
-int umsdos_real_lookup (struct inode *dir, struct dentry *dentry)
-{
-       int ret;
-
-       PRINTK ((KERN_DEBUG "umsdos_real_lookup: looking for %s/%s /",
-               dentry->d_parent->d_name.name, dentry->d_name.name));
-       ret = msdos_lookup (dir, dentry);
-       PRINTK (("/ returned %d\n", ret));
-
-       return ret;
-}
-
 /*
  * Complete the setup of an directory dentry.
  * First, it completes the function pointers, then
@@ -230,6 +214,34 @@ void umsdos_setup_dir_inode (struct inode *inode)
 /*
  * Add some info into an inode so it can find its owner quickly
  */
+void umsdos_set_dirinfo_new (struct dentry *dentry, off_t f_pos)
+{
+       struct inode *inode = dentry->d_inode;
+       struct inode *dir = dentry->d_parent->d_inode;
+       struct dentry *demd;
+
+       inode->u.umsdos_i.i_dir_owner = dir->i_ino;
+       inode->u.umsdos_i.i_emd_owner = 0;
+       inode->u.umsdos_i.pos = f_pos;
+
+       /* now check the EMD file */
+       demd = umsdos_get_emd_dentry(dentry->d_parent);
+       if (IS_ERR(demd)) {
+               goto out;
+       }
+       if (demd->d_inode) {
+               inode->u.umsdos_i.i_emd_owner = demd->d_inode->i_ino;
+       }
+       dput (demd);
+out:
+       return;
+}
+
+
+/*
+ * Add some info into an inode so it can find its owner quickly
+ * Note: Deprecated; use above function if possible.
+ */
 void umsdos_set_dirinfo (struct inode *inode, struct inode *dir, off_t f_pos)
 {
        struct inode *emd_owner = umsdos_emd_dir_lookup (dir, 1);
@@ -405,15 +417,14 @@ void UMSDOS_read_inode (struct inode *inode)
 }
 
 
-/* #Specification: notify_change / i_nlink > 0
- * notify change is only done for inode with nlink > 0. An inode
- * with nlink == 0 is no longer associated with any entry in
- * the EMD file, so there is nothing to update.
- */
-static int internal_notify_change (struct inode *inode, struct iattr *attr)
+int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
 {
+       struct inode *inode = dentry->d_inode;
        unsigned long i_emd_owner = inode->u.umsdos_i.i_emd_owner;
+       struct dentry *demd;
        int ret;
+       struct file filp;
+       struct umsdos_dirent entry;
 
        Printk ((KERN_DEBUG "UMSDOS_notify_change: entering\n"));
 
@@ -425,62 +436,61 @@ static int internal_notify_change (struct inode *inode, struct iattr *attr)
 
        if (inode->i_ino == UMSDOS_ROOT_INO)
                goto out_nolink;
+       if (i_emd_owner != 0)
+               goto out_nolink;
 
-       if (i_emd_owner != 0xffffffff && i_emd_owner != 0) {
-               /* This inode is not a EMD file nor an inode used internally
-                * by MSDOS, so we can update its status.
-                * See emd.c
-                */
-               struct inode *emd_owner;
-               struct file filp;
-               struct umsdos_dirent entry;
-               struct dentry *emd_dentry;
-
-               Printk (("notify change %p ", inode));
-               ret = -EPERM;
-               emd_owner = iget (inode->i_sb, i_emd_owner);
-               if (!emd_owner) {
-                       printk ("UMSDOS: emd_owner = NULL ???");
-                       goto out_nolink;
-               }
-               emd_dentry = geti_dentry (emd_owner); /* FIXME? */
-               fill_new_filp (&filp, emd_dentry);
+       /* get the EMD file dentry */
+       demd = umsdos_get_emd_dentry(dentry->d_parent);
+       ret = PTR_ERR(demd);
+       if (IS_ERR(demd))
+               goto out_nolink;
+       ret = -EPERM;
+       if (!demd->d_inode)
+               goto out_dput;
+
+       ret = 0;
+       if (inode == demd->d_inode)
+               goto out_dput;
+       /* This inode is not a EMD file nor an inode used internally
+        * by MSDOS, so we can update its status.
+        * See emd.c
+        */
 
+       Printk (("notify change %p ", inode));
+       fill_new_filp (&filp, demd);
+       filp.f_pos = inode->u.umsdos_i.pos;
+
+       Printk (("pos = %Lu ", filp.f_pos));
+       /* Read only the start of the entry since we don't touch the name */
+       ret = umsdos_emd_dir_read (&filp, (char *) &entry, UMSDOS_REC_SIZE);
+       if (!ret) {
+               if (attr->ia_valid & ATTR_UID)
+                       entry.uid = attr->ia_uid;
+               if (attr->ia_valid & ATTR_GID)
+                       entry.gid = attr->ia_gid;
+               if (attr->ia_valid & ATTR_MODE)
+                       entry.mode = attr->ia_mode;
+               if (attr->ia_valid & ATTR_ATIME)
+                       entry.atime = attr->ia_atime;
+               if (attr->ia_valid & ATTR_MTIME)
+                       entry.mtime = attr->ia_mtime;
+               if (attr->ia_valid & ATTR_CTIME)
+                       entry.ctime = attr->ia_ctime;
+
+               entry.nlink = inode->i_nlink;
                filp.f_pos = inode->u.umsdos_i.pos;
-               filp.f_reada = 0;
-               Printk (("pos = %Lu ", filp.f_pos));
-               /* Read only the start of the entry since we don't touch */
-               /* the name */
-               ret = umsdos_emd_dir_read (&filp, (char *) &entry, 
-                                               UMSDOS_REC_SIZE);
-               if (!ret) {
-                       if (attr->ia_valid & ATTR_UID)
-                               entry.uid = attr->ia_uid;
-                       if (attr->ia_valid & ATTR_GID)
-                               entry.gid = attr->ia_gid;
-                       if (attr->ia_valid & ATTR_MODE)
-                               entry.mode = attr->ia_mode;
-                       if (attr->ia_valid & ATTR_ATIME)
-                               entry.atime = attr->ia_atime;
-                       if (attr->ia_valid & ATTR_MTIME)
-                               entry.mtime = attr->ia_mtime;
-                       if (attr->ia_valid & ATTR_CTIME)
-                               entry.ctime = attr->ia_ctime;
-
-                       entry.nlink = inode->i_nlink;
-                       filp.f_pos = inode->u.umsdos_i.pos;
-                       ret = umsdos_emd_dir_write (&filp, (char *) &entry,
-                                                        UMSDOS_REC_SIZE);
-
-                       Printk (("notify pos %lu ret %d nlink %d ",
-                               inode->u.umsdos_i.pos, ret, entry.nlink));
-                       /* #Specification: notify_change / msdos fs
-                        * notify_change operation are done only on the
-                        * EMD file. The msdos fs is not even called.
-                        */
-               }
-               iput(emd_owner);
+               ret = umsdos_emd_dir_write (&filp, (char *) &entry,
+                                                UMSDOS_REC_SIZE);
+
+               Printk (("notify pos %lu ret %d nlink %d ",
+                       inode->u.umsdos_i.pos, ret, entry.nlink));
+               /* #Specification: notify_change / msdos fs
+                * notify_change operation are done only on the
+                * EMD file. The msdos fs is not even called.
+                */
        }
+out_dput:
+       dput(demd);
 out_nolink:
        if (ret == 0)
                inode_setattr (inode, attr);
@@ -489,11 +499,6 @@ out:
 }
 
 
-int UMSDOS_notify_change (struct dentry *dentry, struct iattr *attr)
-{
-       return internal_notify_change (dentry->d_inode, attr);
-}
-
 /*
  * Update the disk with the inode content
  */
@@ -558,9 +563,8 @@ struct super_block *UMSDOS_read_super (struct super_block *sb, void *data,
        sb->s_op = &umsdos_sops;
        MSDOS_SB(sb)->options.dotsOK = 0;       /* disable hidden==dotfile */
 
-       /* FIXME:?? clear d_op on root so it will not be inherited */
-       sb->s_root->d_op = NULL;
-
+       /* install our dentry operations ... */
+       sb->s_root->d_op = &umsdos_dentry_operations;
        pseudo = sb->s_root->d_inode;
        umsdos_setup_dir(sb->s_root);
 
@@ -599,7 +603,7 @@ void pseudo_root_stuff(void)
        sbin = creat_dentry ("sbin", 4, NULL, root);
 
        Printk ((KERN_DEBUG "Mounting root\n"));
-       if (umsdos_real_lookup (pseudo, root) == 0
+       if (msdos_lookup (pseudo, root) == 0
            && (root->d_inode != NULL)
            && S_ISDIR (root->d_inode->i_mode)) {
 
@@ -609,7 +613,7 @@ Printk ((KERN_DEBUG "/%s is there\n", UMSDOS_PSDROOT_NAME));
                etc = creat_dentry ("etc", 3, NULL, root);
 
 
-               if (umsdos_real_lookup (pseudo, etc) == 0
+               if (msdos_lookup (pseudo, etc) == 0
                    && S_ISDIR (etc->d_inode->i_mode)) {
 
 Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME));
@@ -617,9 +621,9 @@ Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME));
                        init = creat_dentry ("init", 4, NULL, etc);
                        etc_rc = creat_dentry ("rc", 2, NULL, etc);
 
-                       if ((umsdos_real_lookup (pseudo, init) == 0
+                       if ((msdos_lookup (pseudo, init) == 0
                             && S_ISREG (init->d_inode->i_mode))
-                           || (umsdos_real_lookup (pseudo, etc_rc) == 0
+                           || (msdos_lookup (pseudo, etc_rc) == 0
                         && S_ISREG (etc_rc->d_inode->i_mode))) {
                                pseudo_ok = 1;
                        }
@@ -629,12 +633,12 @@ Printk ((KERN_DEBUG "/%s/etc is there\n", UMSDOS_PSDROOT_NAME));
                        /* iput(rc); */
                }
                if (!pseudo_ok
-               /* && umsdos_real_lookup (pseudo, "sbin", 4, sbin)==0 */
-                   && umsdos_real_lookup (pseudo, sbin) == 0
+               /* && msdos_lookup (pseudo, "sbin", 4, sbin)==0 */
+                   && msdos_lookup (pseudo, sbin) == 0
                    && S_ISDIR (sbin->d_inode->i_mode)) {
 
 Printk ((KERN_DEBUG "/%s/sbin is there\n", UMSDOS_PSDROOT_NAME));
-                       if (umsdos_real_lookup (pseudo, init) == 0
+                       if (msdos_lookup (pseudo, init) == 0
                            && S_ISREG (init->d_inode->i_mode)) {
                                pseudo_ok = 1;
                        }
index 84e1f503424e2baf88a6ae9c386bf20535d4763c..22f8f0645b9b9c72e493cb4ecf43e2bca1865a93 100644 (file)
@@ -262,13 +262,13 @@ int UMSDOS_ioctl_dir(struct inode *dir, struct file *filp, unsigned int cmd,
                 */
                old_dentry = umsdos_lookup_dentry (dentry, 
                                                data.dos_dirent.d_name,
-                                               data.dos_dirent.d_reclen);
+                                               data.dos_dirent.d_reclen ,1);
                ret = PTR_ERR(old_dentry);
                if (IS_ERR(old_dentry))
                        goto out;
                new_dentry = umsdos_lookup_dentry (dentry,
                                                data.umsdos_dirent.name,
-                                               data.umsdos_dirent.name_len);
+                                               data.umsdos_dirent.name_len, 1);
                ret = PTR_ERR(new_dentry);
                if (!IS_ERR(new_dentry)) {
 printk("umsdos_ioctl: renaming %s/%s to %s/%s\n",
@@ -314,7 +314,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
                 * Return 0 if success.
                 */
                temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
-                                                   data.dos_dirent.d_reclen);
+                                               data.dos_dirent.d_reclen, 1);
                ret = PTR_ERR(temp);
                if (IS_ERR(temp))
                        goto out;
@@ -336,7 +336,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
                 * Return 0 if success.
                 */
                temp = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
-                                                   data.dos_dirent.d_reclen);
+                                           data.dos_dirent.d_reclen, 1);
                ret = PTR_ERR(temp);
                if (IS_ERR(temp))
                        goto out;
@@ -362,7 +362,7 @@ new_dentry->d_parent->d_name.name, new_dentry->d_name.name);
                struct inode *inode;
 
                dret = umsdos_lookup_dentry(dentry, data.dos_dirent.d_name,
-                                                   data.dos_dirent.d_reclen);
+                                           data.dos_dirent.d_reclen, 1);
                ret = PTR_ERR(dret);
                if (IS_ERR(dret))
                        goto out;
index b365fbf04600e199f45738d8d17c8144cbf7b519..2ec793db79b65fd5471c7d8e75f5e3542640fd68 100644 (file)
@@ -224,8 +224,8 @@ static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
  * 
  * Return the status of the operation. 0 mean success.
  *
- * #Specification: create / file exist in DOS
- * Here is a situation. Trying to create a file with
+ * #Specification: create / file exists in DOS
+ * Here is a situation: we are trying to create a file with
  * UMSDOS. The file is unknown to UMSDOS but already
  * exists in the DOS directory.
  * 
@@ -254,19 +254,9 @@ static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
        int ret;
        struct umsdos_info info;
 
-if (dentry->d_inode)
-printk("umsdos_create_any: %s/%s not negative!\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-
-Printk (("umsdos_create_any /mn/: create %.*s in dir=%lu - nevercreat=/",
-(int) dentry->d_name.len, dentry->d_name.name, dir->i_ino));
-
-       check_dentry_path (dentry, "umsdos_create_any");
        ret = umsdos_nevercreat (dir, dentry, -EEXIST);
-       if (ret) {
-Printk (("%d/\n", ret));
+       if (ret)
                goto out;
-       }
 
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
        if (ret)
@@ -286,7 +276,7 @@ Printk (("%d/\n", ret));
 
        /* create short name dentry */
        fake = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len);
+                                       info.fake.len, 1);
        ret = PTR_ERR(fake);
        if (IS_ERR(fake))
                goto out_unlock;
@@ -300,39 +290,26 @@ Printk (("%d/\n", ret));
        if (ret)
                goto out_remove;
 
-       inode = fake->d_inode;
-       umsdos_lookup_patch_new(fake, &info.entry, info.f_pos);
-
-Printk (("inode %p[%lu], count=%d ", inode, inode->i_ino, inode->i_count));
-Printk (("Creation OK: [dir %lu] %.*s pid=%d pos %ld\n",
-dir->i_ino, info.fake.len, info.fake.fname, current->pid, info.f_pos));
-
-       check_dentry_path (dentry, "umsdos_create_any: BEG dentry");
-       check_dentry_path (fake, "umsdos_create_any: BEG fake");
-
        /*
         * Note! The long and short name might be the same,
         * so check first before doing the instantiate ...
         */
        if (dentry != fake) {
+               inode = fake->d_inode;
                /* long name also gets inode info */
                inode->i_count++;
                d_instantiate (dentry, inode);
        }
-
-       check_dentry_path (dentry, "umsdos_create_any: END dentry");
-       check_dentry_path (fake, "umsdos_create_any: END fake");
+       umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos);
        goto out_dput;
 
 out_remove:
-if (ret == -EEXIST)
-printk("UMSDOS: out of sync, error [%ld], deleting %.*s %d %d pos %ld\n",
-dir->i_ino ,info.fake.len, info.fake.fname, -ret, current->pid, info.f_pos);
-       umsdos_delentry (dentry->d_parent, &info, 0);
+       if (ret == -EEXIST)
+               printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
+                       dentry->d_parent->d_name.name, info.fake.fname);
+       umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
 
 out_dput:
-Printk (("umsdos_create %.*s ret = %d pos %ld\n",
-info.fake.len, info.fake.fname, ret, info.f_pos));
        /* N.B. any value in keeping short name dentries? */
        if (dentry != fake)
                d_drop(fake);
@@ -382,27 +359,21 @@ static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
                            struct inode *new_dir, struct dentry *new_dentry,
                            int flags)
 {
-       int old_ret, new_ret;
-       struct dentry *old, *new, *dret;
-       struct inode *oldid = NULL;
-       int ret = -EPERM;
+       struct dentry *old, *new, *new_target = NULL;
+       int err, ret = -EPERM;
        struct umsdos_info old_info;
        struct umsdos_info new_info;
 
-       old_ret = umsdos_parse (old_dentry->d_name.name,
+       err = umsdos_parse (old_dentry->d_name.name,
                                old_dentry->d_name.len, &old_info);
-       if (old_ret)
+       if (err)
                goto out;
-       new_ret = umsdos_parse (new_dentry->d_name.name,
+       err = umsdos_parse (new_dentry->d_name.name,
                                new_dentry->d_name.len, &new_info);
-       if (new_ret)
+       if (err)
                goto out;
 
-       check_dentry_path (old_dentry, "umsdos_rename_f OLD");
-       check_dentry_path (new_dentry, "umsdos_rename_f OLD");
-
        chkstk ();
-Printk (("umsdos_rename %d %d ", old_ret, new_ret));
        umsdos_lockcreate2 (old_dir, new_dir);
        chkstk ();
 
@@ -415,16 +386,16 @@ Printk (("ret %d ", ret));
 
        /* check sticky bit on old_dir */
        ret = -EPERM;
-       if (is_sticky(old_dir, old_info.entry.uid)) {
-               Printk (("sticky set on old "));
+       if (is_sticky(old_dir, old_info.entry.uid))
                goto out_unlock;
-       }
 
-       /* Does new_name already exist? */
-       new_ret = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
-       /* if destination file exists, are we allowed to replace it ? */
-       if (new_ret == 0 && is_sticky(new_dir, new_info.entry.uid)) {
-               Printk (("sticky set on new "));
+       /*
+        * Check whether the new_name already exists, and
+        * if so whether we're allowed to replace it.
+        */
+       err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
+       if (err == 0 && is_sticky(new_dir, new_info.entry.uid)) {
+Printk (("sticky set on new "));
                goto out_unlock;
        }
 
@@ -433,37 +404,50 @@ Printk (("ret %d ", ret));
        ret = umsdos_newentry (new_dentry->d_parent, &new_info);
        chkstk ();
        if (ret) {
-Printk (("ret %d %d ", ret, new_info.fake.len));
+               printk("umsdos_rename_f: new name failed, ret=%d\n", ret);
                goto out_unlock;
        }
 
-       dret = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname, 
-                                       old_info.fake.len);
-       ret = PTR_ERR(dret);
-       if (IS_ERR(dret))
+       old = umsdos_lookup_dentry(old_dentry->d_parent, old_info.fake.fname, 
+                                       old_info.fake.len, 1);
+       ret = PTR_ERR(old);
+       if (IS_ERR(old))
                goto out_unlock;
-#if 0
-       /* This is the same as dret */
-       oldid = dret->d_inode;
-       old = creat_dentry (old_info.fake.fname, old_info.fake.len,
-                               oldid, old_dentry->d_parent);
-#endif
-       old = dret;
+       /* short and long name dentries match? */
+       if (old == old_dentry)
+               dput(old);
+
        new = umsdos_lookup_dentry(new_dentry->d_parent, new_info.fake.fname, 
-                                       new_info.fake.len);
+                                       new_info.fake.len, 1);
        ret = PTR_ERR(new);
        if (IS_ERR(new))
                goto out_dput;
+       /*
+        * Note! If the short and long name dentries match,
+        * the target name will be destroyed by the msdos
+        * rename. So we make a copy in case it's needed.
+        */
+       if (new == new_dentry) {
+               dput(new);
+               /* make a copy of the target dentry */
+               ret = -ENOMEM;
+               new_target = d_alloc(new_dentry->d_parent,
+                                       &new_dentry->d_name);
+               if (!new_target)
+                       goto out_dput;
+       }
 
        Printk (("msdos_rename "));
-       check_dentry_path (old, "umsdos_rename_f OLD2");
-       check_dentry_path (new, "umsdos_rename_f NEW2");
        ret = msdos_rename (old_dir, old, new_dir, new);
        chkstk ();
-printk("after m_rename ret %d ", ret);
-       /* dput(old); */
-       dput(new);
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_rename_f: now %s/%s, ret=%d\n", 
+old->d_parent->d_name.name, old->d_name.name, ret);
+#endif
+       if (new != new_dentry)
+               dput(new);
 
+       /* If the rename failed, remove the new EMD entry */
        if (ret != 0) {
                umsdos_delentry (new_dentry->d_parent, &new_info,
                                 S_ISDIR (new_info.entry.mode));
@@ -471,35 +455,47 @@ printk("after m_rename ret %d ", ret);
                goto out_dput;
        }
 
+       /* Rename successful ... remove old name from EMD */
        ret = umsdos_delentry (old_dentry->d_parent, &old_info,
                                 S_ISDIR (old_info.entry.mode));
        chkstk ();
+
+       /* dput() the dentry if we haven't already */
+out_dput:
+       if (old_dentry != old)
+               dput(old);
        if (ret)
-               goto out_dput;
-#if 0
+               goto out_unlock;
+       /*
+        * Check whether to update the dcache ... if both 
+        * old and new dentries match, it's already correct.
+        */
+       if (new_dentry != new) {
+               d_move(old_dentry, new_dentry);
+       } else if (old_dentry != old) {
+               /* new dentry was destroyed ... */
+               d_drop(new_dentry);
+               d_add(new_target, NULL);
+               d_move(old_dentry, new_target);
+       }
+
        /*
         * Update f_pos so notify_change will succeed
         * if the file was already in use.
         */
-       umsdos_set_dirinfo (new_dentry->d_inode, new_dir, new_info.f_pos);
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_rename_f: %s/%s dirinfo, old=%d, new=%d\n", 
+old_dentry->d_parent->d_name.name, old_dentry->d_name.name,
+old_info.f_pos, new_info.f_pos);
 #endif
-       if (old_dentry == dret) {
-printk("umsdos_rename_f: old dentries match -- skipping d_move\n");
-               goto out_dput;
-       }
-       d_move (old_dentry, new_dentry);
-
-out_dput:
-       dput(dret);
+       umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
 
 out_unlock:
-       Printk ((KERN_DEBUG "umsdos_rename_f: unlocking dirs...\n"));
+       dput(new_target);
        umsdos_unlockcreate (old_dir);
        umsdos_unlockcreate (new_dir);
 
 out:
-       check_dentry_path (old_dentry, "umsdos_rename_f OLD3");
-       check_dentry_path (new_dentry, "umsdos_rename_f NEW3");
        Printk ((" _ret=%d\n", ret));
        return ret;
 }
@@ -509,11 +505,11 @@ out:
  * Return a negative error code or 0 if OK.
  */
 /* #Specification: symbolic links / strategy
- * A symbolic link is simply a file which hold a path. It is
+ * A symbolic link is simply a file which holds a path. It is
  * implemented as a normal MSDOS file (not very space efficient :-()
  * 
- * I see 2 different way to do it. One is to place the link data
- * in unused entry of the EMD file. The other is to have a separate
+ * I see two different ways to do this: One is to place the link data
+ * in unused entries of the EMD file; the other is to have a separate
  * file dedicated to hold all symbolic links data.
  * 
  * Let's go for simplicity...
@@ -525,37 +521,33 @@ static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
        int ret, len;
        struct file filp;
 
+Printk(("umsdos_symlink: %s/%s to %s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, symname));
+
        ret = umsdos_create_any (dir, dentry, mode, 0, flags);
        if (ret) {
-Printk (("umsdos_symlink ret %d ", ret));
+printk("umsdos_symlink: create failed, ret=%d\n", ret);
                goto out;
        }
 
-       len = strlen (symname);
-
        fill_new_filp (&filp, dentry);
-       filp.f_pos = 0;
-
-       /* Make the inode acceptable to MSDOS FIXME */
-Printk ((KERN_WARNING "   symname=%s ; dentry name=%.*s (ino=%lu)\n",
-symname, (int) dentry->d_name.len, dentry->d_name.name, dentry->d_inode->i_ino));
+       len = strlen (symname);
        ret = umsdos_file_write_kmem_real (&filp, symname, len);
-       
        if (ret >= 0) {
                if (ret != len) {
                        ret = -EIO;
-                       printk ("UMSDOS: "
-                            "Can't write symbolic link data\n");
+                       printk (KERN_WARNING
+                               "UMSDOS: Can't write symbolic link data\n");
                } else {
                        ret = 0;
                }
        }
        if (ret != 0) {
+printk("umsdos_symlink: write failed, unlinking\n");
                UMSDOS_unlink (dir, dentry);
        }
 
 out:
-       Printk (("\n"));
        return ret;
 }
 
@@ -583,6 +575,12 @@ int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
        int ret;
        struct umsdos_dirent entry;
 
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_link: new %s%s -> %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, 
+olddentry->d_parent->d_name.name, olddentry->d_name.name);
+#endif
        ret = -EPERM;
        if (S_ISDIR (oldinode->i_mode))
                goto out;
@@ -599,45 +597,78 @@ int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
        olddir = olddentry->d_parent->d_inode;
        umsdos_lockcreate2 (dir, olddir);
 
-       /* get the entry for the old name */
+       /* get the directory entry for the old name */
        ret = umsdos_dentry_to_entry(olddentry, &entry);
        if (ret)
                goto out_unlock;
-Printk (("umsdos_link :%.*s: ino %lu flags %d ",
-entry.name_len, entry.name ,oldinode->i_ino, entry.flags));
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_link: have old entry %s, ino=%lu, flags=%x\n",
+entry.name, oldinode->i_ino, entry.flags);
+#endif
 
        if (!(entry.flags & UMSDOS_HIDDEN)) {
                struct umsdos_info info;
 
+               /* get a hidden link name */
                ret = umsdos_newhidden (olddentry->d_parent, &info);
                if (ret)
                        goto out_unlock;
+Printk(("umsdos_link: made hidden %s\n", info.entry.name));
+
+               /*
+                * Make a dentry and rename the original file ...
+                */
+               temp = umsdos_lookup_dentry(dentry->d_parent, info.entry.name,
+                                               info.entry.name_len, 0); 
+               if (IS_ERR(temp))
+                       goto out_unlock;
 
-               ret = umsdos_rename_f (olddentry->d_inode, olddentry, 
-                                       dir, dentry, UMSDOS_HIDDEN);
+               /* rename the link to the hidden location ... */
+               ret = umsdos_rename_f (olddir, olddentry, dir, temp,
+                                       UMSDOS_HIDDEN);
+               dput(temp);
                if (ret)
                        goto out_unlock;
-               path = d_path(olddentry, (char *) buffer, PAGE_SIZE);
+#ifdef UMSDOS_DEBUG_VERBOSE
+printk("umsdos_link: renamed to %s%s\n",
+olddentry->d_parent->d_name.name, olddentry->d_name.name);
+#endif
+
+               /*
+                * Capture the path to the hidden link.
+                */
+               path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
                if (!path)
                        goto out_unlock;
+Printk(("umsdos_link: hidden link path=%s\n", path));
+
+               /*
+                * Recreate a dentry for the original name and symlink it.
+                * Note: this counts as the "original" reference, so we 
+                * don't increment i_nlink for this one.
+                */ 
                temp = umsdos_lookup_dentry(olddentry->d_parent, entry.name,
-                                               entry.name_len); 
+                                               entry.name_len, 0); 
                if (IS_ERR(temp))
                        goto out_unlock;
                ret = umsdos_symlink_x (olddir, temp, path, 
                                        S_IFREG | 0777, UMSDOS_HLINK);
-               if (ret == 0) {
-                       ret = umsdos_symlink_x (dir, dentry, path,
-                                       S_IFREG | 0777, UMSDOS_HLINK);
-               }
                dput(temp);
+               if (ret)
+                       goto out_unlock;
+
+               /* This symlink increments i_nlink (see below.) */
+               ret = umsdos_symlink_x (dir, dentry, path,
+                                       S_IFREG | 0777, UMSDOS_HLINK);
                goto out_unlock;
        }
-       path = d_path(olddentry, (char *) buffer, PAGE_SIZE);
-       if (path) {
-               ret = umsdos_symlink_x (dir, dentry, path, 
+
+       path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
+       if (!path)
+               goto out_unlock;
+Printk(("umsdos_link: already hidden, path=%s\n", path));
+       ret = umsdos_symlink_x (dir, dentry, path, 
                                S_IFREG | 0777, UMSDOS_HLINK);
-       }
 
 out_unlock:
        umsdos_unlockcreate (olddir);
@@ -648,6 +679,8 @@ out:
                struct iattr newattrs;
 
                oldinode->i_nlink++;
+printk("UMSDOS_link: linked %s/%s, nlink=%d\n",
+olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_nlink);
                newattrs.ia_valid = 0;
                ret = UMSDOS_notify_change (olddentry, &newattrs);
        }
@@ -665,12 +698,7 @@ out:
  */
 int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
 {
-       int ret;
-       Printk ((KERN_ERR "UMSDOS_create: entering\n"));
-       check_dentry_path (dentry, "UMSDOS_create START");
-       ret = umsdos_create_any (dir, dentry, mode, 0, 0);
-       check_dentry_path (dentry, "UMSDOS_create END");
-       return ret;
+       return umsdos_create_any (dir, dentry, mode, 0, 0);
 }
 
 
@@ -699,10 +727,8 @@ int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
                goto out;
 
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
-       if (ret) {
-Printk (("umsdos_mkdir %d\n", ret));
+       if (ret)
                goto out;
-       }
 
        umsdos_lockcreate (dir);
        info.entry.mode = mode | S_IFDIR;
@@ -713,14 +739,12 @@ Printk (("umsdos_mkdir %d\n", ret));
        info.entry.flags = 0;
        info.entry.nlink = 1;
        ret = umsdos_newentry (dentry->d_parent, &info);
-       if (ret) {
-Printk (("newentry %d ", ret));
+       if (ret)
                goto out_unlock;
-       }
 
        /* lookup the short name dentry */
        temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len);
+                                       info.fake.len, 1);
        ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out_unlock;
@@ -737,36 +761,27 @@ dentry->d_parent->d_name.name, info.fake.fname);
        if (ret)
                goto out_remove;
 
-       inode = temp->d_inode;
-       umsdos_lookup_patch_new(temp, &info.entry, info.f_pos);
-
        /*
         * Note! The long and short name might be the same,
         * so check first before doing the instantiate ...
         */
        if (dentry != temp) {
-               if (!dentry->d_inode) {
-                       inode->i_count++;
-                       d_instantiate(dentry, inode);
-               } else {
-                       printk("umsdos_mkdir: not negative??\n");
-               }
-       } else {
-               printk("umsdos_mkdir: dentries match, skipping inst\n");
+if (dentry->d_inode)
+printk("umsdos_mkdir: dentry not negative!\n");
+               inode = temp->d_inode;
+               inode->i_count++;
+               d_instantiate(dentry, inode);
        }
-
-       /* create the EMD file */
-       err = umsdos_make_emd(dentry);
+       umsdos_lookup_patch_new(dentry, &info.entry, info.f_pos);
 
        /* 
-        * set up the dir so it is promoted to EMD,
-        * with the EMD file invisible inside it.
+        * Create the EMD file, and set up the dir so it is
+        * promoted to EMD with the EMD file invisible.
+        *
+        * N.B. error return if EMD fails?
         */
-       umsdos_setup_dir(temp);
-       goto out_dput;
-
-out_remove:
-       umsdos_delentry (dentry->d_parent, &info, 1);
+       err = umsdos_make_emd(dentry);
+       umsdos_setup_dir(dentry);
 
 out_dput:
        /* kill off the short name dentry */ 
@@ -776,9 +791,14 @@ out_dput:
 
 out_unlock:
        umsdos_unlockcreate (dir);
-       Printk (("umsdos_mkdir %d\n", ret));
 out:
+       Printk (("umsdos_mkdir %d\n", ret));
        return ret;
+
+       /* an error occurred ... remove EMD entry. */
+out_remove:
+       umsdos_delentry (dentry->d_parent, &info, 1);
+       goto out_dput;
 }
 
 /*
@@ -801,11 +821,7 @@ out:
 int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
                 int mode, int rdev)
 {
-       int ret;
-       check_dentry_path (dentry, "UMSDOS_mknod START");
-       ret = umsdos_create_any (dir, dentry, mode, rdev, 0);
-       check_dentry_path (dentry, "UMSDOS_mknod END");
-       return ret;
+       return umsdos_create_any (dir, dentry, mode, rdev, 0);
 }
 
 /*
@@ -821,13 +837,6 @@ int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
        if (ret)
                goto out;
 
-#if 0  /* no need for lookup ... we have a dentry ... */
-       ret = umsdos_lookup_x (dir, dentry, 0);
-       Printk (("rmdir lookup %d ", ret));
-       if (ret != 0)
-               goto out;
-#endif
-
        umsdos_lockcreate (dir);
        ret = -EBUSY;
        if (dentry->d_count > 1) {
@@ -839,6 +848,14 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                }
        }
 
+       /* check the sticky bit */
+       ret = -EPERM;
+       if (is_sticky(dir, dentry->d_inode->i_uid)) {
+printk("umsdos_rmdir: %s/%s is sticky\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+               goto out_unlock;
+       }
+
        /* check whether the EMD is empty */
        empty = umsdos_isempty (dentry);
        ret = -ENOTEMPTY;
@@ -848,24 +865,21 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
        /* Have to remove the EMD file? */
        if (empty == 1) {
                struct dentry *demd;
-               /* check sticky bit */
-               ret = -EPERM;
-               if (is_sticky(dir, dentry->d_inode->i_uid)) {
-printk("umsdos_rmdir: %s/%s is sticky\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-                       goto out_unlock;
-               }
+
+Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
 
                ret = -ENOTEMPTY;
                /* see if there's an EMD file ... */
                demd = umsdos_get_emd_dentry(dentry);
                if (IS_ERR(demd))
                        goto out_unlock;
-printk("umsdos_rmdir: got EMD dentry %s/%s, inode=%p\n",
-demd->d_parent->d_name.name, demd->d_name.name, demd->d_inode);
 
                err = msdos_unlink (dentry->d_inode, demd);
-Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
+#ifdef UMSDOS_PARANOIA
+if (err)
+printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
+demd->d_parent->d_name.name, demd->d_name.name, err);
+#endif
                dput(demd);
                if (err)
                        goto out_unlock;
@@ -875,7 +889,7 @@ Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
        /* Call findentry to complete the mangling */
        umsdos_findentry (dentry->d_parent, &info, 2);
        temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len);
+                                       info.fake.len, 1);
        ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out_unlock;
@@ -884,8 +898,8 @@ Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
         */
        if (temp == dentry) {
                dput(temp);
-printk("umsdos_rmdir: %s/%s, short matches long\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
+Printk(("umsdos_rmdir: %s/%s, short matches long\n",
+dentry->d_parent->d_name.name, dentry->d_name.name));
        }
 
        /*
@@ -897,16 +911,18 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
 
        /* OK so far ... remove the name from the EMD */
        ret = umsdos_delentry (dentry->d_parent, &info, 1);
+#ifdef UMSDOS_PARANOIA
+if (ret)
+printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
+#endif
 
-out_dput:
        /* dput() temp if we didn't do it above */
+out_dput:
        if (temp != dentry) {
                d_drop(temp);
                dput(temp);
                if (!ret)
                        d_delete (dentry);
-printk("umsdos_rmdir: %s/%s, short=%s dput\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname);
        }
 
 out_unlock:
@@ -922,8 +938,8 @@ out:
  * Remove a file from the directory.
  *
  * #Specification: hard link / deleting a link
- * When we delete a file, and this file is a link
- * we must subtract 1 to the nlink field of the
+ * When we delete a file and this file is a link,
+ * we must subtract 1 from the nlink field of the
  * hidden link.
  * 
  * If the count goes to 0, we delete this hidden
@@ -931,12 +947,12 @@ out:
  */
 int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
 {
-       struct dentry *temp;
+       struct dentry *temp, *link = NULL;
        struct inode *inode;
        int ret;
        struct umsdos_info info;
 
-Printk (("UMSDOS_unlink: entering %s/%s\n",
+Printk(("UMSDOS_unlink: entering %s/%s\n",
 dentry->d_parent->d_name.name, dentry->d_name.name));
 
        ret = umsdos_nevercreat (dir, dentry, -EPERM);
@@ -950,11 +966,13 @@ dentry->d_parent->d_name.name, dentry->d_name.name));
        umsdos_lockcreate (dir);
        ret = umsdos_findentry (dentry->d_parent, &info, 1);
        if (ret) {
-printk("UMSDOS_unlink: findentry returned %d\n", ret);
+printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, ret);
                goto out_unlock;
        }
 
 Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
+
        ret = -EPERM;
        /* check sticky bit */
        if (is_sticky(dir, info.entry.uid)) {
@@ -963,65 +981,55 @@ dentry->d_parent->d_name.name, dentry->d_name.name);
                goto out_unlock;
        }
 
-       ret = 0;
+       /*
+        * Note! If this is a hardlink and the names are aliased,
+        * the short-name lookup will return the hardlink dentry.
+        * In order to get the correct (real) inode, we just drop
+        * the original dentry.
+        */ 
        if (info.entry.flags & UMSDOS_HLINK) {
-printk("UMSDOS_unlink: hard link %s/%s, fake=%s\n",
+               d_drop(dentry);
+#ifdef UMSDOS_PARANOIA
+printk("UMSDOS_unlink: hard link %s/%s, fake=%s, dropping\n",
 dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname);
-               /*
-                * First, get the inode of the hidden link
-                * using the standard lookup function.
-                */
-
-               ret = umsdos_lookup_x (dir, dentry, 0);
-               inode = dentry->d_inode;
-               if (ret)
-                       goto out_unlock;
-
-               Printk (("unlink nlink = %d ", inode->i_nlink));
-               inode->i_nlink--;
-               if (inode->i_nlink == 0) {
-                       struct umsdos_dirent entry;
-
-                       ret = umsdos_dentry_to_entry (dentry, &entry);
-                       if (ret == 0) {
-                               ret = UMSDOS_unlink (dentry->d_parent->d_inode,
-                                                       dentry);
-                       }
-               } else {
-                       struct iattr newattrs;
-                       newattrs.ia_valid = 0;
-                       ret = UMSDOS_notify_change (dentry, &newattrs);
-               }
+#endif
        }
-       if (ret)
-               goto out_unlock;
 
        /* get the short name dentry */
        temp = umsdos_lookup_dentry(dentry->d_parent, info.fake.fname, 
-                                       info.fake.len);
+                                       info.fake.len, 1);
+       ret = PTR_ERR(temp);
        if (IS_ERR(temp))
                goto out_unlock;
 
        /*
-        * If the short name matches the long,
-        * dput() it now so it's not busy.
+        * Resolve hardlinks now, but defer processing until later.
         */
-       if (temp == dentry) {
-printk("UMSDOS_unlink: %s/%s, short matches long\n",
-dentry->d_parent->d_name.name, dentry->d_name.name);
-               dput(temp);
+       if (info.entry.flags & UMSDOS_HLINK) {
+               link = umsdos_solve_hlink(dget(temp));
        }
 
+       /*
+        * If the short and long names are aliased,
+        * dput() it now so the dentry isn't busy.
+        */
+       if (temp == dentry)
+               dput(temp);
+
+       /* Delete the EMD entry */
        ret = umsdos_delentry (dentry->d_parent, &info, 0);
-       if (ret && ret != -ENOENT)
+       if (ret && ret != -ENOENT) {
+               printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
+                       info.entry.name, ret);
                goto out_dput;
+       }
 
-printk("UMSDOS: Before msdos_unlink %.*s ",
-info.fake.len, info.fake.fname);
        ret = msdos_unlink_umsdos (dir, temp);
-
-Printk (("msdos_unlink %.*s %o ret %d ",
-info.fake.len, info.fake.fname ,info.entry.mode, ret));
+#ifdef UMSDOS_PARANOIA
+if (ret)
+printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
+temp->d_parent->d_name.name, temp->d_name.name, ret);
+#endif
 
        /* dput() temp if we didn't do it above */
 out_dput:
@@ -1030,12 +1038,56 @@ out_dput:
                dput(temp);
                if (!ret)
                        d_delete (dentry);
-printk("umsdos_unlink: %s/%s, short=%s dput\n",
-dentry->d_parent->d_name.name, dentry->d_name.name, info.fake.fname);
        }
 
 out_unlock:
        umsdos_unlockcreate (dir);
+
+       /*
+        * Now check for deferred handling of a hardlink.
+        */
+       if (!link)
+               goto out;
+
+       if (IS_ERR(link)) {
+printk("umsdos_unlink: failed to resolve %s/%s\n",
+dentry->d_parent->d_name.name, dentry->d_name.name);
+               if (!ret)
+                       ret = PTR_ERR(link);
+               goto out;
+       }
+
+Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
+link->d_parent->d_name.name, link->d_name.name, ret));
+
+       /* already have an error? */
+       if (ret)
+               goto out_cleanup;
+
+       /* make sure the link exists ... */
+       inode = link->d_inode;
+       if (!inode) {
+               printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
+               goto out_cleanup;
+       }
+
+       /*
+        * If this was the last linked references, delete it now.
+        */
+       if (inode->i_nlink <= 1) {
+               ret = UMSDOS_unlink (link->d_parent->d_inode, link);
+printk("umsdos_unlink: nlink -> 0, unlinked, ret=%d\n", ret);
+       } else {
+               struct iattr newattrs;
+               inode->i_nlink--;
+               newattrs.ia_valid = 0;
+               ret = UMSDOS_notify_change (link, &newattrs);
+       }
+
+out_cleanup:
+       d_drop(link);
+       dput(link);
+
 out:
        Printk (("umsdos_unlink %d\n", ret));
        return ret;
@@ -1059,14 +1111,10 @@ int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
                goto out;
 
        /* This is not terribly efficient but should work. */
-       ret = UMSDOS_unlink (new_dir, new_dentry);
-       chkstk ();
-       Printk (("rename unlink ret %d -- ", ret));
-       if (ret == -EISDIR) {
+       if (S_ISDIR(new_dentry->d_inode->i_mode))
                ret = UMSDOS_rmdir (new_dir, new_dentry);
-               chkstk ();
-               Printk (("rename rmdir ret %d -- ", ret));
-       }
+       else
+               ret = UMSDOS_unlink (new_dir, new_dentry);
        if (ret)
                goto out;
 
index 39605218d7b567e5cc55f718012465fa07101d8c..7101655e3b2bbff70c49ba58054fd06caf45a25d 100644 (file)
@@ -20,6 +20,7 @@
 
 
 extern struct inode *pseudo_root;
+extern struct dentry_operations umsdos_dentry_operations;
 
 struct RDIR_FILLDIR {
        void *dirbuf;
@@ -96,7 +97,7 @@ printk (KERN_WARNING "umsdos_rlookup_x: we are at pseudo-root thingy?\n");
                goto out;
        }
 
-       ret = umsdos_real_lookup (dir, dentry);
+       ret = msdos_lookup (dir, dentry);
        inode = dentry->d_inode;
        if ((ret == 0) && inode) {
                if (inode == pseudo_root && !nopseudo) {
@@ -119,6 +120,8 @@ inode->i_ino));
                }
        }
 out:
+       /* always install our dentry ops ... */
+       dentry->d_op = &umsdos_dentry_operations;
        PRINTK ((KERN_DEBUG "umsdos_rlookup_x: returning %d\n", ret));
        return ret;
 }
@@ -170,28 +173,19 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
 
        ret = msdos_rmdir (dir, dentry);
        if (ret != -ENOTEMPTY)
-               goto out_check;
-
-#if 0  /* why do this? we have the dentry ... */
-       ret = UMSDOS_rlookup (dir, dentry);
-       PRINTK (("rrmdir lookup %d ", ret));
-       if (ret)
                goto out_unlock;
-       ret = -ENOTEMPTY;
-#endif
 
        empty = umsdos_isempty (dentry);
        if (empty == 1) {
-               struct dentry *temp;
+               struct dentry *demd;
                /* We have to remove the EMD file. */
-               temp = umsdos_lookup_dentry(dentry, UMSDOS_EMD_FILE, 
-                                               UMSDOS_EMD_NAMELEN);
-               ret = PTR_ERR(temp);
-               if (!IS_ERR(temp)) {
+               demd = umsdos_get_emd_dentry(dentry);
+               ret = PTR_ERR(demd);
+               if (!IS_ERR(demd)) {
                        ret = 0;
-                       if (temp->d_inode)
-                               ret = msdos_unlink (dentry->d_inode, temp);
-                       dput(temp);
+                       if (demd->d_inode)
+                               ret = msdos_unlink (dentry->d_inode, demd);
+                       dput(demd);
                }
                if (ret)
                        goto out_unlock;
@@ -199,15 +193,9 @@ static int UMSDOS_rrmdir ( struct inode *dir, struct dentry *dentry)
        /* now retry the original ... */
        ret = msdos_rmdir (dir, dentry);
 
-out_check:
-       /* Check whether we succeeded ... */
-       if (!ret)
-               d_delete(dentry);
-
 out_unlock:
        umsdos_unlockcreate (dir);
 out:
-       check_inode (dir);
        return ret;
 }
 
index 7b88a78e425b52d3692fd3a5c1785d25d10f1c4d..0f7d68c0aef6107d724913b467f4c3ec11c9161b 100644 (file)
  * same target at the same time. Again, I am not sure it
  * is a problem at all.
  */
+
 /* #Specification: hard link / strategy
  * Hard links are difficult to implement on top of an MS-DOS FAT file
  * system. Unlike Unix file systems, there are no inodes. A directory
  * The entry -LINK1 will be hidden. It will hold a link count.
  * When all link are erased, the hidden file is erased too.
  */
+
 /* #Specification: weakness / hard link
  * The strategy for hard link introduces a side effect that
  * may or may not be acceptable. Here is the sequence
index dc639a7a442052f0ba06b43d9f66c7ef9b9896f0..cc739cfa51189025359a8236b9ddfcd41dcae8d5 100644 (file)
@@ -32,52 +32,26 @@ int umsdos_readlink_x (          struct dentry *dentry,
                             char *buffer,
                             int bufsiz)
 {
-       int ret;
+       size_t size = dentry->d_inode->i_size;
        loff_t loffs = 0;
+       ssize_t ret;
        struct file filp;
 
-       ret = dentry->d_inode->i_size;
-
-       if (!(dentry->d_inode)) {
-               return -EBADF;
-       }
+Printk((KERN_DEBUG "UMSDOS_read: %s/%s, size=%u\n",
+dentry->d_parent->d_name.name, dentry->d_name.name, size));
 
        fill_new_filp (&filp, dentry);
-
        filp.f_reada = 0;
        filp.f_flags = O_RDONLY;
-       filp.f_op = &umsdos_symlink_operations;         /* /mn/ - we have to fill it with dummy values so we won't segfault */
-
-       if (ret > bufsiz)
-               ret = bufsiz;
-
-       PRINTK ((KERN_DEBUG "umsdos_readlink_x /mn/: Checkin: filp=%p, buffer=%p, size=%d, offs=%Lu\n", &filp, buffer, ret, loffs));
-       PRINTK ((KERN_DEBUG "  f_op=%p\n", filp.f_op));
-       PRINTK ((KERN_DEBUG "  inode=%lu, i_size=%lu\n", filp.f_dentry->d_inode->i_ino, filp.f_dentry->d_inode->i_size));
-       PRINTK ((KERN_DEBUG "  f_pos=%Lu\n", filp.f_pos));
-       PRINTK ((KERN_DEBUG "  name=%.*s\n", (int) filp.f_dentry->d_name.len, filp.f_dentry->d_name.name));
-       PRINTK ((KERN_DEBUG "  i_binary(sb)=%d\n", MSDOS_I (filp.f_dentry->d_inode)->i_binary));
-       PRINTK ((KERN_DEBUG "  f_count=%d, f_flags=%d\n", filp.f_count, filp.f_flags));
-       PRINTK ((KERN_DEBUG "  f_owner=%d\n", filp.f_owner.uid));
-       PRINTK ((KERN_DEBUG "  f_version=%ld\n", filp.f_version));
-       PRINTK ((KERN_DEBUG "  f_reada=%ld, f_ramax=%ld, f_raend=%ld, f_ralen=%ld, f_rawin=%ld\n", filp.f_reada, filp.f_ramax, filp.f_raend, filp.f_ralen, filp.f_rawin));
+       filp.f_op    = &umsdos_symlink_operations;
 
+       if (size > bufsiz)
+               size = bufsiz;
 
-       PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: running fat_file_read (%p, %p, %d, %Lu)\n", &filp, buffer, ret, loffs));
-       if (fat_file_read (&filp, buffer, (size_t) ret, &loffs) != ret) {
+       ret = fat_file_read (&filp, buffer, size, &loffs);
+       if (ret != size) {
                ret = -EIO;
        }
-#if 0
-       {
-               struct umsdos_dirent *mydirent = buffer;
-
-               PRINTK ((KERN_DEBUG "  (DDD) uid=%d\n", mydirent->uid));
-               PRINTK ((KERN_DEBUG "  (DDD) gid=%d\n", mydirent->gid));
-               PRINTK ((KERN_DEBUG "  (DDD) name=>%.20s<\n", mydirent->name));
-       }
-#endif
-
-       PRINTK ((KERN_DEBUG "umsdos_readlink_x: FIXME /mn/: fat_file_read returned offs=%Lu ret=%d\n", loffs, ret));
        return ret;
 }
 
@@ -85,48 +59,38 @@ int umsdos_readlink_x (          struct dentry *dentry,
 
 static int UMSDOS_readlink (struct dentry *dentry, char *buffer, int buflen)
 {
-       int ret;
-
-       PRINTK ((KERN_DEBUG "UMSDOS_readlink: calling umsdos_readlink_x for %.*s\n", (int) dentry->d_name.len, dentry->d_name.name));
-
-       ret = umsdos_readlink_x (dentry, buffer, buflen);
-       PRINTK ((KERN_DEBUG "readlink %d bufsiz %d\n", ret, buflen));
-       /* dput(dentry); / * FIXME /mn/? It seems it is unneeded. d_count is not changed by umsdos_readlink_x */
-
-       Printk ((KERN_WARNING "UMSDOS_readlink /mn/: FIXME! skipped dput(dentry). returning %d\n", ret));
-       return ret;
-
+       return umsdos_readlink_x (dentry, buffer, buflen);
 }
 
 /* this one mostly stolen from romfs :) */
-static struct dentry *UMSDOS_followlink (struct dentry *dentry, struct dentry *base)
+static struct dentry *UMSDOS_followlink (struct dentry *dentry, 
+                                       struct dentry *base)
 {
        struct inode *inode = dentry->d_inode;
-       char *symname = NULL;
+       char *symname;
        int len, cnt;
        mm_segment_t old_fs = get_fs ();
 
-       Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: (%.*s/%.*s)\n", (int) dentry->d_parent->d_name.len, dentry->d_parent->d_name.name, (int) dentry->d_name.len, dentry->d_name.name));
+Printk((KERN_DEBUG "UMSDOS_followlink /mn/: (%s/%s)\n",
+dentry->d_parent->d_name.name, dentry->d_name.name));
 
        len = inode->i_size;
 
        if (!(symname = kmalloc (len + 1, GFP_KERNEL))) {
-               dentry = ERR_PTR (-EAGAIN);     /* correct? */
+               dentry = ERR_PTR (-ENOMEM);
                goto outnobuf;
        }
+
        set_fs (KERNEL_DS);     /* we read into kernel space this time */
-       PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: Here goes umsdos_readlink_x %p, %p, %d\n", dentry, symname, len));
        cnt = umsdos_readlink_x (dentry, symname, len);
-       PRINTK ((KERN_DEBUG "UMSDOS_followlink /mn/: back from umsdos_readlink_x %p, %p, %d!\n", dentry, symname, len));
        set_fs (old_fs);
-       Printk ((KERN_DEBUG "UMSDOS_followlink /mn/: link name is %.*s with len %d\n", cnt, symname, cnt));
 
        if (len != cnt) {
                dentry = ERR_PTR (-EIO);
                goto out;
-       } else
-               symname[len] = 0;
+       }
 
+       symname[len] = 0;
        dentry = lookup_dentry (symname, base, 1);
        kfree (symname);
 
@@ -139,7 +103,7 @@ static struct dentry *UMSDOS_followlink (struct dentry *dentry, struct dentry *b
        return dentry;
 }
 
-
+/* needed to patch the file structure */
 static struct file_operations umsdos_symlink_operations =
 {
        NULL,                   /* lseek - default */
@@ -158,7 +122,7 @@ static struct file_operations umsdos_symlink_operations =
 
 struct inode_operations umsdos_symlink_inode_operations =
 {
-       NULL,                   /* default file operations */
+       NULL,                   /* default file operations (none) */
        NULL,                   /* create */
        NULL,                   /* lookup */
        NULL,                   /* link */
@@ -169,14 +133,14 @@ struct inode_operations umsdos_symlink_inode_operations =
        NULL,                   /* mknod */
        NULL,                   /* rename */
        UMSDOS_readlink,        /* readlink */
-       UMSDOS_followlink,      /* followlink *//* /mn/ is this REALLY needed ? I recall seeing it working w/o it... */
-       generic_readpage,       /* readpage *//* in original NULL. changed to generic_readpage. FIXME? /mn/ */
+       UMSDOS_followlink,      /* followlink */
+       generic_readpage,       /* readpage */
        NULL,                   /* writepage */
-       fat_bmap,               /* bmap *//* in original NULL. changed to fat_bmap. FIXME? /mn/ */
+       fat_bmap,               /* bmap */
        NULL,                   /* truncate */
        NULL,                   /* permission */
        NULL,                   /* smap */
        NULL,                   /* updatepage */
        NULL                    /* revalidate */
-
 };
+
diff --git a/include/asm-i386/desc.h b/include/asm-i386/desc.h
new file mode 100644 (file)
index 0000000..e91580e
--- /dev/null
@@ -0,0 +1,61 @@
+#ifndef __ARCH_DESC_H
+#define __ARCH_DESC_H
+
+struct desc_struct {
+       unsigned long a,b;
+};
+
+extern struct desc_struct gdt_table[];
+extern struct desc_struct *idt, *gdt;
+
+struct Xgt_desc_struct {
+       unsigned short size;
+       unsigned long address __attribute__((packed));
+};
+
+#define idt_descr (*(struct Xgt_desc_struct *)((char *)&idt - 2))
+#define gdt_descr (*(struct Xgt_desc_struct *)((char *)&gdt - 2))
+
+/*
+ * Entry into gdt where to find first TSS. GDT layout:
+ *   0 - null
+ *   1 - not used
+ *   2 - kernel code segment
+ *   3 - kernel data segment
+ *   4 - user code segment
+ *   5 - user data segment
+ *   6 - not used
+ *   7 - not used
+ *   8 - APM BIOS support
+ *   9 - APM BIOS support
+ *  10 - APM BIOS support
+ *  11 - APM BIOS support
+ *  12 - TSS #0
+ *  13 - LDT #0
+ *  14 - TSS #1
+ *  15 - LDT #1
+ */
+#define FIRST_TSS_ENTRY 12
+#define FIRST_LDT_ENTRY (FIRST_TSS_ENTRY+1)
+#define _TSS(n) ((((unsigned long) n)<<4)+(FIRST_TSS_ENTRY<<3))
+#define _LDT(n) ((((unsigned long) n)<<4)+(FIRST_LDT_ENTRY<<3))
+#define load_TR(n) __asm__ __volatile__("ltr %%ax": /* no output */ :"a" (_TSS(n)))
+#define load_ldt(n) __asm__ __volatile__("lldt %%ax": /* no output */ :"a" (_LDT(n)))
+#define store_TR(n) \
+__asm__("str %%ax\n\t" \
+       "subl %2,%%eax\n\t" \
+       "shrl $4,%%eax" \
+       :"=a" (n) \
+       :"0" (0),"i" (FIRST_TSS_ENTRY<<3))
+
+extern void set_intr_gate(unsigned int irq, void * addr);
+extern void set_ldt_desc(unsigned int n, void *addr, unsigned int size);
+extern void set_tss_desc(unsigned int n, void *addr);
+
+/*
+ * This is the ldt that every process will get unless we need
+ * something other than this.
+ */
+extern struct desc_struct default_ldt;
+
+#endif
index 75f6cc7046629185a8910705bff54cc35d44b947..41bd00856b821e789809fdedbde34b32a9e318cb 100644 (file)
@@ -1,6 +1,8 @@
 #ifndef _LINUX_LOOP_H
 #define _LINUX_LOOP_H
 
+#include <linux/kdev_t.h>
+
 /*
  * include/linux/loop.h
  *
@@ -28,27 +30,41 @@ struct loop_device {
                                    char *raw_buf, char *loop_buf, int size);
        char            lo_name[LO_NAME_SIZE];
        char            lo_encrypt_key[LO_KEY_SIZE];
-#ifdef DES_AVAILABLE
-       des_key_schedule lo_des_key;
-       unsigned long   lo_des_init[2];
-#endif
-#ifdef IDEA_AVAILABLE
-        idea_key        lo_idea_en_key;
-        idea_key        lo_idea_de_key;
-#endif
+       __u32           lo_init[2];
+       uid_t           lo_key_owner;   /* Who set the key */
+       int             (*ioctl)(struct loop_device *, int cmd, 
+                                unsigned long arg); 
+
        struct file *   lo_backing_file;
+       void            *key_data; 
+       char            key_reserved[48]; /* for use by the filter modules */
 };
 
 typedef        int (* transfer_proc_t)(struct loop_device *, int cmd,
                                char *raw_buf, char *loop_buf, int size);
 
+#endif /* __KERNEL__ */
+
 /*
  * Loop flags
  */
 #define LO_FLAGS_DO_BMAP       0x00000001
 #define LO_FLAGS_READ_ONLY     0x00000002
 
-#endif /* __KERNEL__ */
+/* 
+ * Note that this structure gets the wrong offsets when directly used
+ * from a glibc program, because glibc has a 32bit dev_t.
+ * Prevent people from shooting in their own foot.  
+ */
+#if __GLIBC__ >= 2 && !defined(dev_t)
+#error "Wrong dev_t in loop.h"
+#endif 
+
+/*
+ *     This uses kdev_t because glibc currently has no appropiate
+ *     conversion version for the loop ioctls. 
+ *     The situation is very unpleasant        
+ */
 
 struct loop_info {
        int             lo_number;      /* ioctl r/o */
@@ -66,15 +82,31 @@ struct loop_info {
 };
 
 /*
- * Loop encryption types --- LO_CRYPT_IDEA isn't supported yet
+ * Loop filter types
  */
 
 #define LO_CRYPT_NONE  0
 #define LO_CRYPT_XOR   1
 #define LO_CRYPT_DES   2
-#define LO_CRYPT_IDEA  3
-#define MAX_LO_CRYPT   4
+#define LO_CRYPT_DUMMY     9
+#define LO_CRYPT_SKIPJACK 10
+#define MAX_LO_CRYPT   20
 
+#ifdef __KERNEL__
+/* Support for loadable transfer modules */
+struct loop_func_table {
+       int number;     /* filter type */ 
+       int (*transfer)(struct loop_device *lo, int cmd, 
+                       char *raw_buf, char *loop_buf, int size);
+       int (*init)(struct loop_device *, struct loop_info *); 
+       int (*release)(struct loop_device *);  
+       int (*ioctl)(struct loop_device *, int cmd, unsigned long arg);
+}; 
+
+int  loop_register_transfer(struct loop_func_table *funcs);
+int loop_unregister_transfer(int number); 
+
+#endif
 /*
  * IOCTL commands --- we will commandeer 0x4C ('L')
  */
index 1e912ae53eddcf972b2f244e0fe18218c6cf636e..ef7649b1e254a8bac00a9fd2a713dc2163c2d95a 100644 (file)
@@ -23,6 +23,7 @@ enum root_directory_inos {
        PROC_CPUINFO,
        PROC_PCI,
        PROC_MCA,
+       PROC_NUBUS,
        PROC_SELF,      /* will change inode # */
        PROC_NET,
         PROC_SCSI,
index 00d40adcac62a0e66f44c9ba9d0f3494778aba32..76dab1072bd6af986a6154e01f12a4d82a2bbf00 100644 (file)
    as { byte2, byte3, byte0, byte1 }. We need conversions.
 */
 
-typedef unsigned long coh_ulong;
+typedef u32 coh_ulong;
 
-static inline coh_ulong to_coh_ulong (unsigned long x)
+static inline coh_ulong to_coh_ulong (u32 x)
 {
        return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
 }
 
-static inline unsigned long from_coh_ulong (coh_ulong x)
+static inline u32 from_coh_ulong (coh_ulong x)
 {
        return ((x & 0xffff) << 16) | ((x & 0xffff0000) >> 16);
 }
 
 /* inode numbers are 16 bit */
 
-typedef unsigned short sysv_ino_t;
+typedef u16 sysv_ino_t;
 
 /* Block numbers are 24 bit, sometimes stored in 32 bit.
    On Coherent FS, they are always stored in PDP-11 manner: the least
    significant 16 bits come last.
 */
 
-typedef unsigned long sysv_zone_t;
+typedef u32 sysv_zone_t;
 
 /* Among the blocks ... */
 /* Xenix FS, Coherent FS: block 0 is the boot block, block 1 the super-block.
@@ -75,36 +75,36 @@ typedef unsigned long sysv_zone_t;
 #define XENIX_NICINOD  100     /* number of inode cache entries */
 #define XENIX_NICFREE  100     /* number of free block list chunk entries */
 struct xenix_super_block {
-       unsigned short s_isize; /* index of first data zone */
-       unsigned long  s_fsize __packed2__; /* total number of zones of this fs */
+       u16             s_isize; /* index of first data zone */
+       u32             s_fsize __packed2__; /* total number of zones of this fs */
        /* the start of the free block list: */
-       unsigned short s_nfree; /* number of free blocks in s_free, <= XENIX_NICFREE */
-       unsigned long  s_free[XENIX_NICFREE]; /* first free block list chunk */
+       u16             s_nfree;        /* number of free blocks in s_free, <= XENIX_NICFREE */
+       u32             s_free[XENIX_NICFREE]; /* first free block list chunk */
        /* the cache of free inodes: */
-       unsigned short s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */
-       sysv_ino_t     s_inode[XENIX_NICINOD]; /* some free inodes */
+       u16             s_ninode; /* number of free inodes in s_inode, <= XENIX_NICINOD */
+       sysv_ino_t      s_inode[XENIX_NICINOD]; /* some free inodes */
        /* locks, not used by Linux: */
-       char           s_flock; /* lock during free block list manipulation */
-       char           s_ilock; /* lock during inode cache manipulation */
-       char           s_fmod;  /* super-block modified flag */
-       char           s_ronly; /* flag whether fs is mounted read-only */
-       unsigned long  s_time __packed2__; /* time of last super block update */
-       unsigned long  s_tfree __packed2__; /* total number of free zones */
-       unsigned short s_tinode;        /* total number of free inodes */
-       short          s_dinfo[4];      /* device information ?? */
-       char           s_fname[6];      /* file system volume name */
-       char           s_fpack[6];      /* file system pack name */
-       char           s_clean;         /* set to 0x46 when filesystem is properly unmounted */
-       char           s_fill[371];
-       long           s_magic;         /* version of file system */
-       long           s_type;          /* type of file system: 1 for 512 byte blocks
+       char            s_flock;        /* lock during free block list manipulation */
+       char            s_ilock;        /* lock during inode cache manipulation */
+       char            s_fmod;         /* super-block modified flag */
+       char            s_ronly;        /* flag whether fs is mounted read-only */
+       u32             s_time __packed2__; /* time of last super block update */
+       u32             s_tfree __packed2__; /* total number of free zones */
+       u16             s_tinode;       /* total number of free inodes */
+       s16             s_dinfo[4];     /* device information ?? */
+       char            s_fname[6];     /* file system volume name */
+       char            s_fpack[6];     /* file system pack name */
+       char            s_clean;        /* set to 0x46 when filesystem is properly unmounted */
+       char            s_fill[371];
+       s32             s_magic;        /* version of file system */
+       s32             s_type;         /* type of file system: 1 for 512 byte blocks
                                                                2 for 1024 byte blocks */
 };
 
 /* Xenix free list block on disk */
 struct xenix_freelist_chunk {
-       unsigned short fl_nfree;        /* number of free blocks in fl_free, <= XENIX_NICFREE] */
-       unsigned long  fl_free[XENIX_NICFREE] __packed2__;
+       u16     fl_nfree;       /* number of free blocks in fl_free, <= XENIX_NICFREE] */
+       u32     fl_free[XENIX_NICFREE] __packed2__;
 };
 
 /* SystemV FS comes in two variants:
@@ -116,116 +116,120 @@ struct xenix_freelist_chunk {
 
 /* SystemV4 super-block data on disk */
 struct sysv4_super_block {
-       unsigned short s_isize; /* index of first data zone */
-       unsigned long  s_fsize; /* total number of zones of this fs */
+       u16     s_isize;        /* index of first data zone */
+       u16     s_pad0;
+       u32     s_fsize;        /* total number of zones of this fs */
        /* the start of the free block list: */
-       unsigned short s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */
-       unsigned long  s_free[SYSV_NICFREE]; /* first free block list chunk */
+       u16     s_nfree;        /* number of free blocks in s_free, <= SYSV_NICFREE */
+       u16     s_pad1;
+       u32     s_free[SYSV_NICFREE]; /* first free block list chunk */
        /* the cache of free inodes: */
-       unsigned short s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */
+       u16     s_ninode;       /* number of free inodes in s_inode, <= SYSV_NICINOD */
+       u16     s_pad2;
        sysv_ino_t     s_inode[SYSV_NICINOD]; /* some free inodes */
        /* locks, not used by Linux: */
-       char           s_flock; /* lock during free block list manipulation */
-       char           s_ilock; /* lock during inode cache manipulation */
-       char           s_fmod;  /* super-block modified flag */
-       char           s_ronly; /* flag whether fs is mounted read-only */
-       unsigned long  s_time;  /* time of last super block update */
-       short          s_dinfo[4];      /* device information ?? */
-       unsigned long  s_tfree; /* total number of free zones */
-       unsigned short s_tinode;        /* total number of free inodes */
-       char           s_fname[6];      /* file system volume name */
-       char           s_fpack[6];      /* file system pack name */
-       long           s_fill[12];
-       long           s_state;         /* file system state: 0x7c269d38-s_time means clean */
-       long           s_magic;         /* version of file system */
-       long           s_type;          /* type of file system: 1 for 512 byte blocks
+       char    s_flock;        /* lock during free block list manipulation */
+       char    s_ilock;        /* lock during inode cache manipulation */
+       char    s_fmod;         /* super-block modified flag */
+       char    s_ronly;        /* flag whether fs is mounted read-only */
+       u32     s_time;         /* time of last super block update */
+       s16     s_dinfo[4];     /* device information ?? */
+       u32     s_tfree;        /* total number of free zones */
+       u16     s_tinode;       /* total number of free inodes */
+       u16     s_pad3;
+       char    s_fname[6];     /* file system volume name */
+       char    s_fpack[6];     /* file system pack name */
+       s32     s_fill[12];
+       s32     s_state;        /* file system state: 0x7c269d38-s_time means clean */
+       s32     s_magic;        /* version of file system */
+       s32     s_type;         /* type of file system: 1 for 512 byte blocks
                                                                2 for 1024 byte blocks */
 };
 
 /* SystemV4 free list block on disk */
 struct sysv4_freelist_chunk {
-       unsigned short fl_nfree;        /* number of free blocks in fl_free, <= SYSV_NICFREE] */
-       unsigned long  fl_free[SYSV_NICFREE];
+       u16 fl_nfree;   /* number of free blocks in fl_free, <= SYSV_NICFREE] */
+       u32  fl_free[SYSV_NICFREE];
 };
 
 /* SystemV2 super-block data on disk */
 struct sysv2_super_block {
-       unsigned short s_isize; /* index of first data zone */
-       unsigned long  s_fsize __packed2__; /* total number of zones of this fs */
+       u16     s_isize;                /* index of first data zone */
+       u32     s_fsize __packed2__;    /* total number of zones of this fs */
        /* the start of the free block list: */
-       unsigned short s_nfree; /* number of free blocks in s_free, <= SYSV_NICFREE */
-       unsigned long  s_free[SYSV_NICFREE]; /* first free block list chunk */
+       u16     s_nfree;                /* number of free blocks in s_free, <= SYSV_NICFREE */
+       u32     s_free[SYSV_NICFREE];   /* first free block list chunk */
        /* the cache of free inodes: */
-       unsigned short s_ninode; /* number of free inodes in s_inode, <= SYSV_NICINOD */
+       u16     s_ninode;               /* number of free inodes in s_inode, <= SYSV_NICINOD */
        sysv_ino_t     s_inode[SYSV_NICINOD]; /* some free inodes */
        /* locks, not used by Linux: */
-       char           s_flock; /* lock during free block list manipulation */
-       char           s_ilock; /* lock during inode cache manipulation */
-       char           s_fmod;  /* super-block modified flag */
-       char           s_ronly; /* flag whether fs is mounted read-only */
-       unsigned long  s_time __packed2__; /* time of last super block update */
-       short          s_dinfo[4];      /* device information ?? */
-       unsigned long  s_tfree __packed2__; /* total number of free zones */
-       unsigned short s_tinode;        /* total number of free inodes */
-       char           s_fname[6];      /* file system volume name */
-       char           s_fpack[6];      /* file system pack name */
-       long           s_fill[14];
-       long           s_state;         /* file system state: 0xcb096f43 means clean */
-       long           s_magic;         /* version of file system */
-       long           s_type;          /* type of file system: 1 for 512 byte blocks
+       char    s_flock;                /* lock during free block list manipulation */
+       char    s_ilock;                /* lock during inode cache manipulation */
+       char    s_fmod;                 /* super-block modified flag */
+       char    s_ronly;                /* flag whether fs is mounted read-only */
+       u32     s_time __packed2__;     /* time of last super block update */
+       s16     s_dinfo[4];             /* device information ?? */
+       u32     s_tfree __packed2__;    /* total number of free zones */
+       u16     s_tinode;               /* total number of free inodes */
+       char    s_fname[6];             /* file system volume name */
+       char    s_fpack[6];             /* file system pack name */
+       s32     s_fill[14];
+       s32     s_state;                /* file system state: 0xcb096f43 means clean */
+       s32     s_magic;                /* version of file system */
+       s32     s_type;                 /* type of file system: 1 for 512 byte blocks
                                                                2 for 1024 byte blocks */
 };
 
 /* SystemV2 free list block on disk */
 struct sysv2_freelist_chunk {
-       unsigned short fl_nfree;        /* number of free blocks in fl_free, <= SYSV_NICFREE] */
-       unsigned long  fl_free[SYSV_NICFREE] __packed2__;
+       u16     fl_nfree;       /* number of free blocks in fl_free, <= SYSV_NICFREE] */
+       u32     fl_free[SYSV_NICFREE] __packed2__;
 };
 
 /* Coherent super-block data on disk */
 #define COH_NICINOD    100     /* number of inode cache entries */
 #define COH_NICFREE    64      /* number of free block list chunk entries */
 struct coh_super_block {
-       unsigned short s_isize; /* index of first data zone */
-       coh_ulong      s_fsize __packed2__; /* total number of zones of this fs */
+       u16             s_isize;        /* index of first data zone */
+       coh_ulong       s_fsize __packed2__; /* total number of zones of this fs */
        /* the start of the free block list: */
-       unsigned short s_nfree; /* number of free blocks in s_free, <= COH_NICFREE */
-       coh_ulong      s_free[COH_NICFREE] __packed2__; /* first free block list chunk */
+       u16 s_nfree;    /* number of free blocks in s_free, <= COH_NICFREE */
+       coh_ulong       s_free[COH_NICFREE] __packed2__; /* first free block list chunk */
        /* the cache of free inodes: */
-       unsigned short s_ninode; /* number of free inodes in s_inode, <= COH_NICINOD */
-       sysv_ino_t     s_inode[COH_NICINOD]; /* some free inodes */
+       u16             s_ninode;       /* number of free inodes in s_inode, <= COH_NICINOD */
+       sysv_ino_t      s_inode[COH_NICINOD]; /* some free inodes */
        /* locks, not used by Linux: */
-       char           s_flock; /* lock during free block list manipulation */
-       char           s_ilock; /* lock during inode cache manipulation */
-       char           s_fmod;  /* super-block modified flag */
-       char           s_ronly; /* flag whether fs is mounted read-only */
-       coh_ulong      s_time __packed2__; /* time of last super block update */
-       coh_ulong      s_tfree __packed2__; /* total number of free zones */
-       unsigned short s_tinode;        /* total number of free inodes */
-       unsigned short s_interleave_m;  /* interleave factor */
-       unsigned short s_interleave_n;
-       char           s_fname[6];      /* file system volume name */
-       char           s_fpack[6];      /* file system pack name */
-       unsigned long  s_unique;        /* zero, not used */
+       char            s_flock;        /* lock during free block list manipulation */
+       char            s_ilock;        /* lock during inode cache manipulation */
+       char            s_fmod;         /* super-block modified flag */
+       char            s_ronly;        /* flag whether fs is mounted read-only */
+       coh_ulong       s_time __packed2__; /* time of last super block update */
+       coh_ulong       s_tfree __packed2__; /* total number of free zones */
+       u16             s_tinode;       /* total number of free inodes */
+       u16             s_interleave_m; /* interleave factor */
+       u16             s_interleave_n;
+       char            s_fname[6];     /* file system volume name */
+       char            s_fpack[6];     /* file system pack name */
+       u32             s_unique;       /* zero, not used */
 };
 
 /* Coherent free list block on disk */
 struct coh_freelist_chunk {
-       unsigned short fl_nfree;        /* number of free blocks in fl_free, <= COH_NICFREE] */
-       unsigned long  fl_free[COH_NICFREE] __packed2__;
+       u16 fl_nfree;   /* number of free blocks in fl_free, <= COH_NICFREE] */
+       u32  fl_free[COH_NICFREE] __packed2__;
 };
 
 
 /* SystemV/Coherent inode data on disk */
 
 struct sysv_inode {
-       unsigned short i_mode;
-       unsigned short i_nlink;
-       unsigned short i_uid;
-       unsigned short i_gid;
-       unsigned long  i_size;
+       u16 i_mode;
+       u16 i_nlink;
+       u16 i_uid;
+       u16 i_gid;
+       u32 i_size;
        union { /* directories, regular files, ... */
-               char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks,
+               unsigned char i_addb[3*(10+1+1+1)+1]; /* zone numbers: max. 10 data blocks,
                                              * then 1 indirection block,
                                              * then 1 double indirection block,
                                              * then 1 triple indirection block.
@@ -236,14 +240,14 @@ struct sysv_inode {
                /* named pipes on Coherent */
                struct {
                        char p_addp[30];
-                       short p_pnc;
-                       short p_prx;
-                       short p_pwx;
+                       s16 p_pnc;
+                       s16 p_prx;
+                       s16 p_pwx;
                } i_p;
        } i_a;
-       unsigned long i_atime;  /* time of last access */
-       unsigned long i_mtime;  /* time of last modification */
-       unsigned long i_ctime;  /* time of creation */
+       u32 i_atime;    /* time of last access */
+       u32 i_mtime;    /* time of last modification */
+       u32 i_ctime;    /* time of creation */
 };
 
 /* The admissible values for i_mode are listed in <linux/stat.h> :
@@ -301,7 +305,7 @@ extern inline unsigned short to_coh_imode(mode_t mode)
 /* The number of inodes per block is
    sb->sv_inodes_per_block = block_size / sizeof(struct sysv_inode) */
 /* The number of indirect pointers per block is
-   sb->sv_ind_per_block = block_size / sizeof(unsigned long) */
+   sb->sv_ind_per_block = block_size / sizeof(u32) */
 
 
 /* SystemV/Coherent directory entry on disk */
index 56a63f1ef9a38cbfd9adb1cc2f110a6a11ccfd67..990b3543fdcd2f285cb3e8b8a6e6ec0712b6f305 100644 (file)
@@ -5,11 +5,11 @@
  * SystemV/Coherent FS inode data in memory
  */
 struct sysv_inode_info {
-       unsigned long i_data[10+1+1+1]; /* zone numbers: max. 10 data blocks,
-                                        * then 1 indirection block,
-                                        * then 1 double indirection block,
-                                        * then 1 triple indirection block.
-                                        */
+       u32 i_data[10+1+1+1];   /* zone numbers: max. 10 data blocks,
+                                * then 1 indirection block,
+                                * then 1 double indirection block,
+                                * then 1 triple indirection block.
+                                */
 };
 
 #endif
index 99a7c125d981e0ef12d168200d0aadd73904cada..df886f651c02d06d6b0a34028bf2bbf88d4f9ad8 100644 (file)
@@ -50,21 +50,21 @@ struct sysv_sb_info {
           different superblock layout. */
        char *         s_sbd1;          /* entire superblock data, for part 1 */
        char *         s_sbd2;          /* entire superblock data, for part 2 */
-       unsigned short *s_sb_fic_count; /* pointer to s_sbd->s_ninode */
-        unsigned short *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
-       unsigned short *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
-       unsigned short *s_sb_flc_count; /* pointer to s_sbd->s_nfree */
-       unsigned long  *s_sb_flc_blocks; /* pointer to s_sbd->s_free */
-       unsigned long  *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */
-       unsigned long  *s_sb_time;      /* pointer to s_sbd->s_time */
-       unsigned long  *s_sb_state;     /* pointer to s_sbd->s_state, only FSTYPE_SYSV */
+       u16            *s_sb_fic_count; /* pointer to s_sbd->s_ninode */
+        u16            *s_sb_fic_inodes; /* pointer to s_sbd->s_inode */
+       u16            *s_sb_total_free_inodes; /* pointer to s_sbd->s_tinode */
+       u16            *s_sb_flc_count; /* pointer to s_sbd->s_nfree */
+       u32            *s_sb_flc_blocks; /* pointer to s_sbd->s_free */
+       u32            *s_sb_total_free_blocks;/* pointer to s_sbd->s_tfree */
+       u32            *s_sb_time;      /* pointer to s_sbd->s_time */
+       u32            *s_sb_state;     /* pointer to s_sbd->s_state, only FSTYPE_SYSV */
        /* We keep those superblock entities that don't change here;
           this saves us an indirection and perhaps a conversion. */
-       unsigned long  s_firstinodezone; /* index of first inode zone */
-       unsigned long  s_firstdatazone; /* same as s_sbd->s_isize */
-       unsigned long  s_ninodes;       /* total number of inodes */
-       unsigned long  s_ndatazones;    /* total number of data zones */
-       unsigned long  s_nzones;        /* same as s_sbd->s_fsize */
+       u32            s_firstinodezone; /* index of first inode zone */
+       u32            s_firstdatazone; /* same as s_sbd->s_isize */
+       u32            s_ninodes;       /* total number of inodes */
+       u32            s_ndatazones;    /* total number of data zones */
+       u32            s_nzones;        /* same as s_sbd->s_fsize */
 };
 /* The fields s_ind_per_block_2_1, s_toobig_block are currently unused. */
 
index 44a6eec2b34d0b5f29e4c8d28c0e095ede9954ea..ed049fca2ca4ebae295f9750e6fb153c82b7626f 100644 (file)
@@ -11,6 +11,7 @@ int  dummy_dir_read ( struct file *filp,
         char *buf,
         size_t size,
         loff_t *count);
+char * umsdos_d_path(struct dentry *, char *, int);
 void umsdos_lookup_patch_new(struct dentry *, struct umsdos_dirent *, off_t);
 void umsdos_lookup_patch (struct inode *dir,
         struct inode *inode,
@@ -27,7 +28,7 @@ int umsdos_lookup_x (
                            struct dentry *dentry,
                            int nopseudo);
 int UMSDOS_lookup(struct inode *, struct dentry *);
-struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int);
+struct dentry *umsdos_lookup_dentry(struct dentry *, char *, int, int);
 
 struct dentry *umsdos_solve_hlink (struct dentry *hlink);
 
@@ -80,15 +81,11 @@ int UMSDOS_statfs (struct super_block *, struct statfs *, int);
 struct super_block *UMSDOS_read_super (struct super_block *, void *, int);
 void UMSDOS_put_super (struct super_block *);
 
-struct dentry *compat_umsdos_real_lookup (struct dentry *d_dir,
-        const char *name,
-        int len);
 int umsdos_real_lookup(struct inode *, struct dentry *);        
 void umsdos_setup_dir(struct dentry *);
 void umsdos_setup_dir_inode (struct inode *inode);
-void umsdos_set_dirinfo (struct inode *inode,
-        struct inode *dir,
-        off_t f_pos);
+void umsdos_set_dirinfo_new(struct dentry *, off_t);
+void umsdos_set_dirinfo (struct inode *, struct inode *, off_t);
 int umsdos_isinit (struct inode *inode);
 void umsdos_patch_dentry_inode (struct dentry *, off_t);
 void umsdos_patch_inode (struct inode *, struct inode *, off_t);
index e089d607ef5f26244a9e76a3ec56dad751bf22bf..043d4c9e2bd594f92bf3d67884c994280c291f6a 100644 (file)
@@ -48,6 +48,7 @@ extern void video_unregister_device(struct video_device *);
 #define VID_TYPE_SCALES                128     /* Scalable */
 #define VID_TYPE_MONOCHROME    256     /* Monochrome only */
 #define VID_TYPE_SUBCAPTURE    512     /* Can capture subareas of the image */
+#define VID_TYPE_OUTPUT                1024    /* Can output video data */
 
 struct video_capability
 {
index 736fc2747d5b68d9f6c3fce4647227667e2d47f0..f5f4052d665b9722c8bf661d9f37401facc59ad8 100644 (file)
@@ -150,10 +150,6 @@ typedef unsigned char UCHAR8;
 #define WF_MIDI_VIRTUAL_IS_EXTERNAL 0x2
 #define WF_MIDI_IN_TO_SYNTH_DISABLED 0x4
 
-/* See wavefront.c for details */
-
-#define WAVEFRONT_MAX_DEVICES 1 /* How many WaveFront cards we can handle */
-
 /* slot indexes for struct address_info: makes code a little more mnemonic */
 
 #define WF_SYNTH_SLOT         0
@@ -502,11 +498,11 @@ typedef union wf_any {
     wavefront_drum d;
 } wavefront_any;
 
-/* Hannu Savolainen hoped that his "patch_info" struct in soundcard.h
-   might work for other wavetable-based patch-loading situations.
-   Alas, his fears were correct.  The WaveFront doesn't even come with
-   just "patches", but several different kinds of structures that
-   control the process of generating sound.
+/* Hannu Solvainen hoped that his "patch_info" struct in soundcard.h
+   might work for other wave-table based patch loading situations.
+   Alas, his fears were correct. The WaveFront doesn't even come with
+   just "patches", but several different kind of structures that
+   control the sound generation process.
  */
 
 typedef struct wf_patch_info {
@@ -662,7 +658,7 @@ typedef struct wf_fx_info {
 
 /* Allow direct user-space control over FX memory/coefficient data.
    In theory this could be used to download the FX microprogram,
-   but it would be a little slower, and involve some weird code.
+   but it would be a little slower, and involve some wierd code.
  */
 
 #define WFFX_MEMSET              69
index 6f6b281ea5825376ac9da8f9dba40453bedead33..72ecd910df3cae2fa83c6a218e2f3ff443895251 100644 (file)
@@ -239,7 +239,11 @@ static inline void __exit_sighand(struct task_struct *tsk)
        struct signal_struct * sig = tsk->sig;
 
        if (sig) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&tsk->sigmask_lock, flags);
                tsk->sig = NULL;
+               spin_unlock_irqrestore(&tsk->sigmask_lock, flags);
                if (atomic_dec_and_test(&sig->count))
                        kfree(sig);
        }
index 9f4014ae9ce3f3e99fda8df5e73ddc84fb009af1..1b3fb7fc94a00a84a419bf00bf5927824d157345 100644 (file)
@@ -146,6 +146,7 @@ EXPORT_SYMBOL(d_move);
 EXPORT_SYMBOL(d_instantiate);
 EXPORT_SYMBOL(d_alloc);
 EXPORT_SYMBOL(d_lookup);
+EXPORT_SYMBOL(d_path);
 EXPORT_SYMBOL(__mark_inode_dirty);
 EXPORT_SYMBOL(get_empty_filp);
 EXPORT_SYMBOL(init_private_file);
index 7469c0d0824306b663f6ca47cd9b9d6d69db4522..130e6371a285f005ac9256f6a6c085ab5902ee15 100644 (file)
@@ -213,10 +213,50 @@ printk(" %d -> %d\n", signal_pending(current), sig);
        return sig;
 }
 
+/*
+ * Determine whether a signal should be posted or not.
+ *
+ * Signals with SIG_IGN can be ignored, except for the
+ * special case of a SIGCHLD. 
+ *
+ * Some signals with SIG_DFL default to a non-action.
+ */
+static int ignored_signal(int sig, struct task_struct *t)
+{
+       struct signal_struct *signals;
+       struct k_sigaction *ka;
+
+       /* Don't ignore traced or blocked signals */
+       if ((t->flags & PF_PTRACED) || sigismember(&t->blocked, sig))
+               return 0;
+       
+       signals = t->sig;
+       if (!signals)
+               return 1;
+
+       ka = &signals->action[sig-1];
+       switch ((unsigned long) ka->sa.sa_handler) {
+       case (unsigned long) SIG_DFL:
+               if (sig == SIGCONT ||
+                   sig == SIGWINCH ||
+                   sig == SIGCHLD ||
+                   sig == SIGURG)
+                       break;
+               return 0;
+
+       case (unsigned long) SIG_IGN:
+               if (sig != SIGCHLD)
+                       break;
+       /* fallthrough */
+       default:
+               return 0;
+       }
+       return 1;
+}
+
 int
 send_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 {
-       struct k_sigaction *ka;
        unsigned long flags;
        int ret;
 
@@ -227,13 +267,6 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
        ret = -EINVAL;
        if (sig < 0 || sig > _NSIG)
                goto out_nolock;
-
-       /* If t->sig is gone, we must be trying to kill the task.  So
-          pretend that it doesn't exist anymore.  */
-       ret = -ESRCH;
-       if (t->sig == NULL)
-               goto out_nolock;
-
        /* The somewhat baroque permissions check... */
        ret = -EPERM;
        if ((!info || ((unsigned long)info != 1 && SI_FROMUSER(info)))
@@ -249,9 +282,7 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
        if (!sig)
                goto out_nolock;
 
-       ka = &t->sig->action[sig-1];
        spin_lock_irqsave(&t->sigmask_lock, flags);
-
        switch (sig) {
        case SIGKILL: case SIGCONT:
                /* Wake up the process if stopped.  */
@@ -277,16 +308,8 @@ printk("SIG queue (%s:%d): %d ", t->comm, t->pid, sig);
           handled immediately (ie non-blocked and untraced) and
           that is ignored (either explicitly or by default).  */
 
-       if (!(t->flags & PF_PTRACED) && !sigismember(&t->blocked, sig)
-           /* Don't bother with ignored sigs (SIGCHLD is special) */
-           && ((ka->sa.sa_handler == SIG_IGN && sig != SIGCHLD)
-               /* Some signals are ignored by default.. (but SIGCONT
-                  already did its deed) */
-               || (ka->sa.sa_handler == SIG_DFL
-                   && (sig == SIGCONT || sig == SIGCHLD
-                       || sig == SIGWINCH || sig == SIGURG)))) {
+       if (ignored_signal(sig, t))
                goto out;
-       }
 
        if (sig < SIGRTMIN) {
                /* Non-real-time signals are not queued.  */
@@ -372,12 +395,18 @@ printk(" %d -> %d\n", signal_pending(t), ret);
 int
 force_sig_info(int sig, struct siginfo *info, struct task_struct *t)
 {
-       if (t->sig == NULL)
+       unsigned long int flags;
+
+       spin_lock_irqsave(&t->sigmask_lock, flags);
+       if (t->sig == NULL) {
+               spin_unlock_irqrestore(&t->sigmask_lock, flags);
                return -ESRCH;
+       }
 
        if (t->sig->action[sig-1].sa.sa_handler == SIG_IGN)
                t->sig->action[sig-1].sa.sa_handler = SIG_DFL;
        sigdelset(&t->blocked, sig);
+       spin_unlock_irqrestore(&t->sigmask_lock, flags);
 
        return send_sig_info(sig, info, t);
 }
index fb70baa3030c2f5d166a56158ceaba51534e0fdb..b666c0191a9cbf2cc5aa061b5d4d5b1d2f43f73f 100644 (file)
@@ -634,7 +634,7 @@ unsigned long put_dirty_page(struct task_struct * tsk, unsigned long page, unsig
  * and potentially makes it more efficient.
  */
 static void do_wp_page(struct task_struct * tsk, struct vm_area_struct * vma,
-       unsigned long address, int write_access, pte_t *page_table)
+       unsigned long address, pte_t *page_table)
 {
        pte_t pte;
        unsigned long old_page, new_page;
@@ -914,7 +914,7 @@ static inline void handle_pte_fault(struct task_struct *tsk,
                flush_tlb_page(vma, address);
                return;
        }
-       do_wp_page(tsk, vma, address, write_access, pte);
+       do_wp_page(tsk, vma, address, pte);
 }
 
 /*
index b64570308213c4087b2f6c0d4628521071c9771e..43e0e1705899de0b08d987b9e13cd6a42832f023 100644 (file)
@@ -18,8 +18,8 @@ if [ "$CONFIG_INET" = "y" ]; then
   source net/ipv4/Config.in
   if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
 #   Sorry, but IPv6 as module is still invalid.
-#   tristate 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6
-    bool 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6
+    tristate 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6
+#   bool 'The IPv6 protocol (EXPERIMENTAL)' CONFIG_IPV6
     if [ "$CONFIG_IPV6" != "n" ]; then
            source net/ipv6/Config.in
     fi
index cd84989a602db5dbe6c104c12b80485601d28d6c..77cb218d30fb92ade98aa2881c108501d16eb630 100644 (file)
@@ -1290,10 +1290,12 @@ static int ax25_getname(struct socket *sock, struct sockaddr *uaddr, int *uaddr_
                fsa.fsa_ax25.sax25_call   = sk->protinfo.ax25->dest_addr;
                fsa.fsa_ax25.sax25_ndigis = 0;
 
-               ndigi = sk->protinfo.ax25->digipeat->ndigi;
-               fsa.fsa_ax25.sax25_ndigis = ndigi;
-               for (i = 0; i < ndigi; i++)
-                       fsa.fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i];
+               if (sk->protinfo.ax25->digipeat != NULL) {
+                       ndigi = sk->protinfo.ax25->digipeat->ndigi;
+                       fsa.fsa_ax25.sax25_ndigis = ndigi;
+                       for (i = 0; i < ndigi; i++)
+                               fsa.fsa_digipeater[i] = sk->protinfo.ax25->digipeat->calls[i];
+               }
        } else {
                fsa.fsa_ax25.sax25_family = AF_AX25;
                fsa.fsa_ax25.sax25_call   = sk->protinfo.ax25->source_addr;
index fb13b5e16ec42f324cc91e8192f5151f2f9fe3ed..7ee9f8744fe432cc0b24150a21ba3ebc209560a2 100644 (file)
@@ -192,7 +192,7 @@ static inline void skb_headerinit(void *p, kmem_cache_t *cache,
        skb->ip_summed = 0;
        skb->security = 0;      /* By default packets are insecure */
        skb->dst = NULL;
-#ifdef CONFIG_IP_FIREWALL_CHAINS
+#ifdef CONFIG_IP_FIREWALL
         skb->fwmark = 0;
 #endif
        memset(skb->cb, 0, sizeof(skb->cb));
index 6a3ae17bf58902ee5c34d62a0ef6b2e32a82193d..d27720cdce233080e6467c13c0662e48dd2ad532 100644 (file)
@@ -292,7 +292,7 @@ static void tcp_sacktag_write_queue(struct sock *sk, struct tcp_sack_block *sp,
                        /* The retransmission queue is always in order, so
                         * we can short-circuit the walk early.
                         */
-                       if(after(TCP_SKB_CB(skb)->end_seq, end_seq))
+                       if(!before(start_seq, TCP_SKB_CB(skb)->end_seq))
                                break;
 
                        /* We play conservative, we don't allow SACKS to partially
@@ -471,8 +471,8 @@ static void tcp_fast_retrans(struct sock *sk, u32 ack, int not_dup)
                  * to one half the current congestion window, but no less 
                  * than two segments. Retransmit the missing segment.
                  */
-                tp->dup_acks++;
                if (tp->high_seq == 0 || after(ack, tp->high_seq)) {
+                       tp->dup_acks++;
                        if ((tp->fackets_out > 3) || (tp->dup_acks == 3)) {
                                 tp->snd_ssthresh = max(tp->snd_cwnd >> (TCP_CWND_SHIFT + 1), 2);
                                 tp->snd_cwnd = (tp->snd_ssthresh + 3) << TCP_CWND_SHIFT;
@@ -1711,10 +1711,6 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
         */
 
        if (flg == tp->pred_flags && TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
-               if (!tcp_sequence(tp, TCP_SKB_CB(skb)->seq, TCP_SKB_CB(skb)->end_seq)) {
-                       tcp_send_ack(sk);
-                       goto discard;
-               }
                if (len <= th->doff*4) {
                        /* Bulk data transfer: sender */
                        if (len == th->doff*4) {
@@ -1729,8 +1725,13 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
                        }
                } else if (TCP_SKB_CB(skb)->ack_seq == tp->snd_una) {
                        /* Bulk data transfer: receiver */
-                       if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf)
+                       if (atomic_read(&sk->rmem_alloc) > sk->rcvbuf) {
+                               /* We must send an ACK for zero window probes. */
+                               if (!before(TCP_SKB_CB(skb)->seq,
+                                               tp->rcv_wup + tp->rcv_wnd))
+                                       tcp_send_ack(sk);
                                goto discard;
+                       }
                        
                        __skb_pull(skb,th->doff*4);
 
index eab552c365d93e0623c036c2474ad82a07100fa2..e6c9033ead245942f5f5bb0c17646dcf98ed1abc 100644 (file)
@@ -500,6 +500,7 @@ void udp_err(struct sk_buff *skb, unsigned char *dp, int len)
        }
        
        switch (type) {
+       case ICMP_TIME_EXCEEDED:
        case ICMP_SOURCE_QUENCH:
                return;
        case ICMP_PARAMETERPROB:
index a9ee64925ceec25ff73d92f45c2d4b280f4e9fe9..04a9e4b8b03c5c7deedf2d118c1ea3d2c719a35f 100644 (file)
 #include <asm/uaccess.h>
 #include <asm/system.h>
 
+static int unloadable = 0; /* XX: Turn to one when all is ok within the
+                             module for allowing unload */
+
+#if defined(MODULE) && LINUX_VERSION_CODE > 0x20115
+MODULE_AUTHOR("Cast of dozens");
+MODULE_DESCRIPTION("IPv6 protocol stack for Linux");
+MODULE_PARM(unloadable, "i");
+#endif
+
 extern struct proto_ops inet6_stream_ops;
 extern struct proto_ops inet6_dgram_ops;
 
@@ -463,6 +472,7 @@ static struct proc_dir_entry proc_net_snmp6 = {
 #ifdef MODULE
 int ipv6_unload(void)
 {
+       if (!unloadable) return 1;
        /* We keep internally 3 raw sockets */
        return __this_module.usecount - 3;
 }
index f987d942513a0f3b213d08b3f6f38a711fddbc22..1af56347290240e04733659bfd8bf54cef1da0e3 100644 (file)
@@ -305,6 +305,7 @@ EXPORT_SYMBOL(tcp_transmit_skb);
 EXPORT_SYMBOL(tcp_connect);
 EXPORT_SYMBOL(tcp_make_synack);
 EXPORT_SYMBOL(tcp_tw_death_row_slot);
+EXPORT_SYMBOL(tcp_sync_mss);
 EXPORT_SYMBOL(net_statistics); 
 
 EXPORT_SYMBOL(xrlim_allow);
index e97d339b3ed02ae8f7b7ffa5ea2da3c73641181b..dd6d593355ddcbc05037f1f3418df1407956e547 100644 (file)
@@ -677,7 +677,7 @@ error:
 /*
  * Send out data on TCP socket.
  * FIXME: Make the sendto call non-blocking in order not to hang
- * a daemon on a dead client. Requires write queue maintenance.
+ * a daemon on a dead client. Requires write queue maintenance.
  */
 static int
 svc_tcp_sendto(struct svc_rqst *rqstp)