]> git.neil.brown.name Git - history.git/commitdiff
Import 2.1.77 2.1.77
authorLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:19 +0000 (15:14 -0500)
committerLinus Torvalds <torvalds@linuxfoundation.org>
Fri, 23 Nov 2007 20:14:19 +0000 (15:14 -0500)
135 files changed:
CREDITS
Documentation/00-INDEX
Documentation/Configure.help
Documentation/cdrom/00-INDEX
Documentation/cdrom/bpcd [deleted file]
Documentation/cdrom/cdrom-standard.tex
Documentation/ez.txt [deleted file]
Documentation/modules.txt
Documentation/networking/filter.txt
Documentation/paride.txt [new file with mode: 0644]
MAINTAINERS
Makefile
arch/alpha/kernel/osf_sys.c
arch/i386/boot/setup.S
arch/i386/defconfig
arch/i386/kernel/ptrace.c
arch/i386/kernel/signal.c
arch/i386/kernel/smp.c
arch/i386/mm/init.c
drivers/block/Config.in
drivers/block/Makefile
drivers/block/ez.c [deleted file]
drivers/block/genhd.c
drivers/block/ide-dma.c
drivers/block/ide-pci.c
drivers/block/ide-proc.c
drivers/block/ide.h
drivers/block/ide_modes.h
drivers/block/ll_rw_blk.c
drivers/block/paride/Config.in [new file with mode: 0644]
drivers/block/paride/Makefile [new file with mode: 0644]
drivers/block/paride/aten.c [new file with mode: 0644]
drivers/block/paride/bpck.c [new file with mode: 0644]
drivers/block/paride/comm.c [new file with mode: 0644]
drivers/block/paride/dstr.c [new file with mode: 0644]
drivers/block/paride/epat.c [new file with mode: 0644]
drivers/block/paride/epia.c [new file with mode: 0644]
drivers/block/paride/frpw.c [new file with mode: 0644]
drivers/block/paride/kbic.c [new file with mode: 0644]
drivers/block/paride/on20.c [new file with mode: 0644]
drivers/block/paride/on26.c [new file with mode: 0644]
drivers/block/paride/paride.c [new file with mode: 0644]
drivers/block/paride/paride.h [new file with mode: 0644]
drivers/block/paride/pcd.c [new file with mode: 0644]
drivers/block/paride/pd.c [new file with mode: 0644]
drivers/block/paride/pf.c [new file with mode: 0644]
drivers/block/paride/pseudo.h [new file with mode: 0644]
drivers/block/paride/setup.h [new file with mode: 0644]
drivers/block/trm290.c
drivers/cdrom/Config.in
drivers/cdrom/Makefile
drivers/cdrom/bpcd.c [deleted file]
drivers/cdrom/cdrom.c
drivers/cdrom/cm206.c
drivers/char/Config.in
drivers/char/bttv.c
drivers/char/bw-qcam.c [new file with mode: 0644]
drivers/char/bw-qcam.h [new file with mode: 0644]
drivers/char/pms.c
drivers/char/tty_io.c
drivers/char/vc_screen.c
drivers/char/wdt.c
drivers/isdn/isdn_net.c
drivers/isdn/isdn_tty.c
drivers/net/Config.in
drivers/net/eepro100.c
drivers/net/hamradio/baycom_par.c
drivers/scsi/Makefile
drivers/scsi/hosts.h
drivers/scsi/scsi_syms.c
drivers/sound/Config.in
drivers/sound/Makefile
drivers/sound/ad1848.c
drivers/sound/audio.c
drivers/sound/dmabuf.c
drivers/sound/gus_midi.c
drivers/sound/gus_wave.c
drivers/sound/ics2101.c
drivers/sound/midi_synth.c
drivers/sound/midibuf.c
drivers/sound/mpu401.c
drivers/sound/opl3.c
drivers/sound/pas2_midi.c
drivers/sound/pas2_mixer.c
drivers/sound/pas2_pcm.c
drivers/sound/pss.c
drivers/sound/sb_audio.c
drivers/sound/sb_card.c
drivers/sound/sb_midi.c
drivers/sound/sb_mixer.c
drivers/sound/sequencer.c
drivers/sound/softoss.c
drivers/sound/sound_calls.h
drivers/sound/sound_switch.c [deleted file]
drivers/sound/sound_syms.c
drivers/sound/sound_timer.c
drivers/sound/soundcard.c
drivers/sound/soundmodule.h
drivers/sound/sscape.c
drivers/sound/sys_timer.c
drivers/sound/uart401.c
drivers/sound/uart6850.c
drivers/sound/v_midi.c
fs/exec.c
fs/nfs/dir.c
fs/nls/Config.in
fs/ntfs/Makefile
fs/ntfs/dir.c
fs/ntfs/fs.c
fs/ntfs/inode.c
fs/ntfs/support.c
fs/ntfs/support.h
fs/proc/array.c
fs/vfat/namei.c
include/asm-i386/processor.h
include/asm-i386/uaccess.h
include/linux/baycom.h
include/linux/cdrom.h
include/linux/genhd.h
include/linux/hdlcdrv.h
include/linux/if.h
include/linux/proc_fs.h
include/linux/sched.h
include/linux/sockios.h
include/linux/soundmodem.h
include/net/sock.h
init/main.c
kernel/sched.c
mm/page_alloc.c
net/core/dev.c
net/core/filter.c
net/ipv4/Config.in
net/ipv4/tcp_ipv4.c
scripts/Menuconfig
scripts/lxdialog/lxdialog.c

diff --git a/CREDITS b/CREDITS
index acafbbaa6c8cde3d9be5bfd8955ca98df0c88cab..38ae4206292a02671194bfe754051136408b0a9c 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -572,10 +572,12 @@ S: USA
 
 N: Grant Guenther
 E: grant@torque.net
-D: drivers for parallel port devices: ppa, ez, bpcd
-D: original architect of the parallel-port sharing scheme. 
-S: 906-1001 Bay St.
-S: Toronto, Ontario, M5S 3A6 
+W: http://www.torque.net/linux-pp.html
+D: original author of ppa driver for parallel port ZIP drive
+D: original architect of the parallel-port sharing scheme 
+D: PARIDE subsystem: drivers for parallel port IDE & ATAPI devices
+S: 44 St. Joseph St., Suite 506
+S: Toronto, Ontario, M4Y 2W4
 S: Canada
 
 N: Richard Günther
index a1d31366091a53dadc96c684106854c12fa76e2c..d4727eae0231fa186ff7144b4e2245cdad442228 100644 (file)
@@ -32,8 +32,6 @@ digiepca.txt
        - info on Digi Intl. {PC,PCI,EISA}Xx and Xem series cards.
 exception.txt
        - how linux v2.1 handles exceptions without verify_area etc.
-ez.txt
-       - documentation for the SyQuest parallel port EZ drive support.
 filesystems/
        - directory with info on the various filesystems that Linux supports.
 ftape.txt
@@ -70,6 +68,8 @@ nfsroot.txt
        - short guide on setting up a diskless box with NFS root filesystem
 oops-tracing.txt
        - how to decode those nasty internal kernel error dump messages.
+paride.txt
+       - information about the parallel port IDE subsystem.
 parport.txt
        - how to use the parallel-port driver.
 ramdisk.txt
index e12f0286a1281b88c91e08ed3465b44c4e93e17f..f0ede54497a8ebd313961e602c23ba457b669d32 100644 (file)
@@ -18,6 +18,9 @@
 # is a work-in-progress effort of the Italian translation team,
 # currently only for the 2.0 version of this file, maintained 
 # by rubini@linux.it.
+#   - http://www.cs.net.pl/~cezar/Kernel is the beginning of a Polish
+# translation of the 2.0 version of this file, maintained by Cezar
+# Cichocki (cezar@cs.net.pl).
 #
 # Information about what a kernel is, what it does, how to patch and
 # compile it and much more is contained in the Kernel-HOWTO, available
@@ -112,7 +115,7 @@ CONFIG_BLK_DEV_FD
   running kernel whenever you want). The module will be called
   floppy.o. If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
-  
+
 RAM disk support
 CONFIG_BLK_DEV_RAM
   Saying Y here will allow you to use a portion of your RAM memory as
@@ -150,12 +153,18 @@ CONFIG_BLK_DEV_LOOP
 
 Network Block Device support
 CONFIG_BLK_DEV_NBD
-  Saying Y here will allow computer to serve as client for network
-  block device - it will be able to use block devices exported by
-  servers (mount filesystems on them etc.). It also allows you to run
-  a block-device in userland (making server and client physicaly the same
-  computer, communicating using loopback). Normal users say N
-  here. Read Documentation/nbd.txt.
+  Saying Y here will allow your computer to serve as a client for
+  network 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 a special file such as /dev/nd0. It also allows you to run
+  a block-device in userland (making server and client physically the
+  same computer, communicating using loopback). 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
+  nbd.o. Normal users say N here. Read Documentation/nbd.txt.
 
 Enhanced IDE/MFM/RLL disk/cdrom/tape/floppy support
 CONFIG_BLK_DEV_IDE
@@ -163,11 +172,11 @@ CONFIG_BLK_DEV_IDE
   interfaces, each being able to serve a "master" and a "slave"
   device, for a combination of up to eight IDE disk/cdrom/tape/floppy
   drives.  Useful information about large (>540MB) IDE disks,
-  soundcard IDE ports, module support, and other topics, is all
+  soundcard IDE ports, module support, and other topics, is 
   contained in Documentation/ide.txt.  If you have one or more IDE
   drives, say Y here.  If your system has no IDE drives, or if memory
   requirements are really tight, you could say N here, and select the
-  Old harddisk driver instead to save about 13kB of memory in the
+  "Old harddisk driver" instead to save about 13kB of memory in the
   kernel.  To fine-tune IDE drive/interface parameters for improved
   performance, look for the hdparm package at
   sunsite.unc.edu:/pub/Linux/kernel/patches/diskdrives/
@@ -248,18 +257,18 @@ 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,
-  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 through
-  the SCSI emulation). At boot time, the FLOPPY drive will be
-  identified along with other IDE devices, as "hdb" or "hdc", or
-  something similar. If you want to compile the 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 ide-floppy.o.
-  
+  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,
+  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 through the SCSI
+  emulation). At boot time, the FLOPPY drive will be identified along
+  with other IDE devices, as "hdb" or "hdc", or something similar. If
+  you want to compile the 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 ide-floppy.o.
+
 SCSI emulation support
 CONFIG_BLK_DEV_IDESCSI
   This will provide SCSI host adapter emulation for IDE ATAPI devices,
@@ -316,14 +325,25 @@ CONFIG_BLK_DEV_IDEPCI
 Generic PCI bus-master DMA support
 CONFIG_BLK_DEV_IDEDMA
   If your PCI IDE controller is capable of bus-master DMA
-  (Direct Memory Access) transfers (most newer systems),
-  then you will want to enable this option to reduce CPU overhead.
+  (Direct Memory Access) transfers (most newer systems are),
+  then you will want to say Y here to reduce CPU overhead.
   With this option, Linux will automatically enable DMA transfers
   in most cases, noting this with "DMA" appended to the drive
   identification info.  You can also 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 sunsite.unc.edu/pub/Linux/system/hardware/
+   It is safe to say Y to this question.
+
+  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 enable this option to allow use of 
+  bus-mastering DMA data transfers. Read the comments at the
+  beginning of drivers/block/idedma.c and Documentation/ide.txt.
+  You can get the latest version of the hdparm utility via 
+  ftp (user: anonymous) from
+  sunsite.unc.edu/pub/Linux/kernel/patches/diskdrives/; it is
+  used to tune your harddisk. 
   It is safe to say Y to this question.
 
 Other IDE chipset support
@@ -341,8 +361,9 @@ CONFIG_BLK_DEV_4DRIVES
   Certain older chipsets, including the Tekram 690CD, use a
   single set of I/O ports at 0x1f0 to control up to four drives,
   instead of the customary two drives per port.  Support for this
-  is enabled at runtime using the "ide0=four" kernel boot parameter.
-  
+  can be enabled at runtime using the "ide0=four" kernel boot
+  parameter if you say Y here.
+
 DTC-2278 support
 CONFIG_BLK_DEV_DTC2278
   This driver is enabled at runtime using the "ide0=dtc2278" kernel
@@ -368,17 +389,15 @@ CONFIG_BLK_DEV_PDC4030
   "ide0=dc4030" kernel boot parameter.  See the Documentation/ide.txt
   and drivers/block/pdc4030.c files for more info.
 
-Tekram TRM290 support (EXPERIMENTAL)
 CONFIG_BLK_DEV_TRM290
   This driver adds support for bus master DMA transfers
   using the Tekram TRM290 PCI IDE chip.  Volunteers are
   needed for further tweaking and development.
   Please read the comments at the top of drivers/block/trm290.c.
 
-OPTi 82C621 support (EXPERIMENTAL)
+OPTi 82C621 enhanced support (EXPERIMENTAL)
 CONFIG_BLK_DEV_OPTI621
-  This driver allows use of hdparm to change the PIO timings
-  for drives attached to an OPTi MIDE controller.
+  This is a driver for the OPTi 82C621 EIDE controller.
   Please read the comments at the top of drivers/block/opti621.c.
 
 NS87415 support (EXPERIMENTAL)
@@ -417,22 +436,166 @@ CONFIG_BLK_DEV_XD
   Documentation/modules.txt. The module will be called xd.o. It's
   pretty unlikely that you have one of these: say N.
 
-SyQuest EZ parallel port disk support
-CONFIG_BLK_DEV_EZ
-  If you have a parallel port version of SyQuest's EZ135 or EZ230
-  removable media devices you can use this driver.  Answer Y to build
-  the driver into the kernel, or M if you would like to build it as a
-  loadable module. The module will be called ez.o.  Read the file
-  linux/Documentation/ez.txt.  It is possible to use several devices
-  with a single common parallel port (e.g. printer and EZ135); it is
-  safe to compile both drivers into the kernel.
+Parallel port IDE device support
+CONFIG_PARIDE
+  There are many external CD-ROM and disk devices that connect
+  through your computer's parallel port.  Most of them are actually
+  IDE devices using a parallel port IDE adapter.  This option enables
+  the PARIDE subsystem which contains drivers for many of these
+  external drives.  Read linux/Documentation/paride.txt for more
+  information.  If you have enabled the parallel port support general
+  configuration option, you may share a single port between your
+  printer and other parallel port devices.  Answer Y to build PARIDE 
+  support into your kernel, or M if you would like to build it as a 
+  loadable module.  If your parallel port support is in a loadable 
+  module, you must build PARIDE as a module.  If you built PARIDE
+  support into your kernel, you may still build the individual 
+  protocol modules and high-level drivers as loadable modules.  To
+  use the PARIDE support, you must have this module as well as at
+  least one protocol module and one high-level driver.  If you build
+  this support as a module, it will be called paride.o.
+
+Parallel port IDE disks
+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 
+  parallel port IDE driver, otherwise you should answer M to build 
+  it as a loadable module.  The module will be called pd.o.  You 
+  must also have at least one parallel port protocol driver in your 
+  system.  Among the devices supported by this driver are the SyQuest 
+  EZ-135, EZ-230 and SparQ drives, the Avatar Shark and the backpack
+  hardrives from MicroSolutions.
+
+Parallel port ATAPI CD-ROMs
+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
+  parallel port ATAPI CD-ROM driver, otherwise you should answer M
+  to build it as a loadable module.  The module will be called pcd.o.
+  You must also have at least one parallel port protocol driver in
+  your system.  Among the devices supported by this driver are the
+  MicroSolutions backpack CD-ROM drives and the Freecom Power CD.
+
+Parallel port ATAPI disks
+CONFIG_PARIDE_PF 
+  This option enable 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
+  parallel port ATAPI disk driver, otherwise you should answer M
+  to build it as a loadable module.  The module will be called pf.o.
+  You must also have at least one parallel port protocol driver in
+  your system.  Among the devices supported by this driver are the
+  MicroSolutions backpack PD/CD drive and the Imation Superdisk
+  LS-120 drive.
+
+ATEN EH-100 protocol
+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 
+  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 aten.o.  You must also 
+  have a high-level driver for the type of device that you want to 
+  support.
+
+MicroSolutions backpack protocol
+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
+  driver, otherwise you should answer M to build it as a loadable
+  module.  The module will be called bpck.o.  You must also have
+  a high-level driver for the type of device that you want to support.
+
+DataStor Commuter protocol
+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
+  driver, otherwise you should answer M to build it as a loadable
+  module.  The module will be called comm.o.  You must also have
+  a high-level driver for the type of device that you want to support.
+
+DataStor EP-2000 protocol
+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
+  driver, otherwise you should answer M to build it as a loadable
+  module.  The module will be called dstr.o.  You must also have
+  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.
+
+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.
+
+FreeCom power protocol
+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 
+  should answer M to build it as a loadable module.  The module will be 
+  called frpw.o.  You must also have a high-level driver for the type 
+  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.
+
+OnSpec 90c20 protocol
+CONFIG_PARIDE_ON20 
+  This option enables support for the (obsolete) 90c20 parallel port 
+  IDE protocol from OnSpec (often marketted under the ValuStore brand
+  name).  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 on20.o.  You must also have a high-level driver for the 
+  type of device that you want to support.
+
+OnSpec 90c26 protocol
+CONFIG_PARIDE_ON26 
+  This option enables support for the 90c26 parallel port IDE protocol 
+  from OnSpec Electronics (often marketted under the ValuStore brand
+  name).  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 on26.o.  You must also have a high-level driver for the 
+  type of device that you want to support.
 
 Multiple devices driver support
 CONFIG_BLK_DEV_MD
   This driver lets you combine several harddisk partitions into one
   logical block device. Information about how and why to use it and the
   necessary tools are available over ftp (user: anonymous) from
-  sweet-smoke.ufr-info-p7.ibp.fr/pub/public/Linux in the md package
+  sweet-smoke.ufr-info-p7.ibp.fr/pub/Linux in the md package
   and the md-FAQ. Please read drivers/block/README.md. If unsure, say
   N.
 
@@ -463,13 +626,18 @@ CONFIG_MD_MIRRORING
   A RAID-1 set consists of several disk drives which are exact copies
   of each other. In the event of a mirror failure, the RAID driver
   will continue to use the operational mirrors in the set, providing
-  an error free MD device to the higher levels of the kernel. In
-  a set with N drives, the available space is the capacity of a single
-  drive, and the set protects against a failure of (N - 1) drives.
-  raidtools, a set of user-space tools which create and maintain
-  RAID1/4/5 sets, is available at:
+  an error free MD (multiple device) to the higher levels of the
+  kernel. In a set with N drives, the available space is the capacity
+  of a single drive, and the set protects against a failure of (N - 1)
+  drives.  raidtools, a set of user-space tools which create and
+  maintain RAID1/4/5 sets, is available at:
   ftp://ftp.kernel.org/pub/linux/daemons/raid
   http://luthien.nuclecu.unam.mx/~miguel/raid
+  If you want to use such a RAID-1 set say Y. This code is also
+  available as a module called raid1.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. If unsure, say Y.
 
 RAID-4/RAID-5 mode
 CONFIG_MD_RAID5
@@ -478,12 +646,17 @@ CONFIG_MD_RAID5
   of a single drive. For a given sector (row) number, (N - 1) drives
   contain data sectors, and one drive contains the parity protection.
   For a RAID-4 set, the parity blocks are present on a single drive,
-  while a RAID-5 set distributes the parity accross the drives in one
+  while a RAID-5 set distributes the parity across the drives in one
   of the available parity distribution methods.
   raidtools, a set of user-space tools which create and maintain
   RAID1/4/5 sets, is available at:
   ftp://ftp.kernel.org/pub/linux/daemons/raid
   http://luthien.nuclecu.unam.mx/~miguel/raid
+  If you want to use such a RAID-5 set, say Y. This code is also
+  available as a module called raid5.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. If unsure, say Y.
 
 Support for Deskstation RPC44 
 CONFIG_DESKSTATION_RPC44
@@ -561,30 +734,7 @@ CONFIG_NET
   kernel, you should consider updating your networking tools too
   because changes in the kernel and the tools often go hand in hand;
   see http://www.inka.de/sites/lina/linux/NetTools/index_en.html for
-  details.
-
-Packet socket
-CONFIG_PACKET
-  Packet protocol is used by applications directly communicating
-  to network devices f.e. tcpdump. You want them to work, choose Y.
-  If you run kerneld, you might want to choose M.
-
-Kernel/User netlink socket
-CONFIG_NETLINK
-  This protocol family is used for bi-directional communication
-  between kernel and user level daemons. This option is unlikely to
-  be useful for common workstation, but if you configure router or
-  firewall, do not hesitate: press Y.
-
-Routing messages
-CONFIG_RTNETLINK
-  One of netlink protocols used by kernel routing engine.
-  You will need it to use advanced routing features.
-
-Netlink device emulation
-CONFIG_NETLINK_DEV
-  It is backward compatibility option, choose Y for now.
-  This option will be removed soon.
+  details. 
 
 Network aliasing
 CONFIG_NET_ALIAS
@@ -603,7 +753,7 @@ CONFIG_NET_ALIAS
 
 Socket filtering
 CONFIG_FILTER
-  The Linux Socket Filter is a deviation of the Berkely Packet Filter.
+  The Linux Socket Filter is derived from the Berkeley Packet Filter.
   Through Socket Filtering you can have the kernel decide whether the
   data is good and to continue processing it. Linux Socket Filtering 
   works on all socket types except TCP for now. See the text file
@@ -642,7 +792,7 @@ CONFIG_SYN_COOKIES
   to continue to connect, even when your machine is under attack.
   There is no need for the legitimate users to change their TCP/IP
   software; SYN cookies work transparently to them.  For technical
-  information about syn cookies, check out
+  information about SYN cookies, check out
   ftp://koobera.math.uic.edu/pub/docs/syncookies-archive.
   If you say Y here, note that SYN cookies aren't enabled by default:
   you need to add the command
@@ -781,11 +931,12 @@ CONFIG_PCI
 
 PCI BIOS support
 CONFIG_PCI_BIOS
-  If you have enabled PCI bus support above, you probably want to allow
-  Linux to use your PCI BIOS to detect the PCI devices and determine
-  their configuration. Note: some old PCI motherboards have BIOS bugs
-  and may crash if this switch is enabled -- for such motherboards,
-  you should disable PCI BIOS support and use direct PCI access instead.
+  If you have enabled PCI bus support above, you probably want to
+  allow Linux to use your PCI BIOS to detect the PCI devices and
+  determine their configuration. Note: some old PCI motherboards have
+  BIOS bugs and may crash if this switch is enabled -- for such
+  motherboards, you should say N here and say Y to "PCI direct access
+  support" instead.
   Except for some special cases (embedded systems with no BIOS), you
   probably should say Y here.
 
@@ -801,9 +952,9 @@ CONFIG_PCI_DIRECT
 PCI bridge optimization (experimental)
 CONFIG_PCI_OPTIMIZE
   This can improve access times for some hardware devices if you have
-  a really broken BIOS and your computer uses a PCI bus system. Set to Y
-  if you think it might help, but try turning it off if you experience
-  any problems with the PCI bus.
+  a really broken BIOS and your computer uses a PCI bus system. Set to
+  Y if you think it might help, but try turning it off if you
+  experience any problems with the PCI bus. N is the safe answer.
 
 MCA support
 CONFIG_MCA
@@ -856,7 +1007,7 @@ CONFIG_BINFMT_ELF
   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
   programs like lynx or netscape).  If you find that after upgrading
-  to Linux kernel 1.3 and saying Y here, you still can't run any ELF
+  from Linux kernel 1.2 and saying Y here, you still can't run any ELF
   binaries (they just crash), then you'll have to install the newest
   ELF runtime libraries, including ld.so (check the file
   Documentation/Changes for location and latest version). If you want
@@ -886,18 +1037,45 @@ CONFIG_BINFMT_AOUT
   because some crucial programs on your system might still be in A.OUT
   format.
 
-Kernel support for JAVA binaries
+Kernel support for JAVA binaries (obsolete)
 CONFIG_BINFMT_JAVA
-  This option is obsolete. Use binfmt_misc instead. It is more 
-  flexible. 
+  JAVA(tm) is an object oriented programming language developed by
+  SUN; JAVA programs are compiled into "JAVA bytecode" binaries which
+  can then be interpreted by run time systems on many different
+  operating systems.  These JAVA binaries are becoming a universal
+  executable format. If you want to execute JAVA binaries, read the
+  Java on Linux HOWTO, available via ftp (user: anonymous) at
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. You will then need to install
+  the run time system contained in the Java Developers Kit (JDK) as
+  described in the HOWTO. This is completely independent of the Linux
+  kernel and you do NOT need to say Y here for this to work.
+  Saying Y here allows you to execute a JAVA bytecode binary just like
+  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
+  "<!--applet-->". If you want to use this, say Y here and read
+  Documentation/java.txt. If you disable this option it will reduce
+  your kernel by about 4kB. This is not much and by itself does not
+  warrant removing support. However its removal is a good idea if you
+  do not have the JDK installed. You may answer M for module support
+  and later load the module when you install the JDK or find an
+  interesting Java program that you can't live without. The module
+  will be called binfmt_java.o. 
+  The complete functionality of this Java support is also provided by
+  the more general option "Kernel support for MISC binaries",
+  below. This option is therefore considered obsolete and you probably
+  want to say N here and Y to "Kernel support for MISC binaries" if
+  you're interested in Java.
 
 Kernel support for Linux/Intel ELF binaries
 CONFIG_BINFMT_EM86
   Say Y here if you want to be able to execute Linux/Intel ELF
-  binaries just like native Alpha binaries on your machine. For this
-  to work, you need to have the emulator /usr/bin/em86 in place.  You
-  may answer M to compile the emulation support as a module and later
-  load the module when you want to use a Linux/Intel binary. The
+  binaries just like native Alpha binaries on your Alpha machine. For
+  this to work, you need to have the emulator /usr/bin/em86 in place.
+  You may answer M to compile the emulation support as a module and
+  later load the module when you want to use a Linux/Intel binary. The
   module will be called binfmt_em86.o.  If unsure, say Y.
 
 Kernel support for MISC binaries
@@ -919,6 +1097,15 @@ CONFIG_BINFMT_MISC
   you have use for it.  
   If you don't know what to answer at this point, say Y.
 
+Solaris binary emulation
+CONFIG_SOLARIS_EMUL
+  This is experimental code which will enable you to run (many)
+  Solaris binaries on your Sparc Linux machine.  This code 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 solaris.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
+
 Processor family
 CONFIG_M386
   This is the processor type of your CPU. This information is used for
@@ -928,7 +1115,11 @@ CONFIG_M386
   then the kernel will run on all of these CPUs: 486 and Pentium
   (=586) and Pentium Pro (=686). In rare cases, it can make sense to
   specify "Pentium" even if running on a 486: the kernel will be
-  smaller but slower. If you don't know what to do, say "386".
+  smaller but slower. 
+  If you have a multiple processor machine and want Linux to use all
+  the processors in parallel, set the SMP variable in the toplevel
+  kernel Makefile.
+  If you don't know what to do, say "386".
 
 Video mode selection support
 CONFIG_VIDEO_SELECT
@@ -950,23 +1141,34 @@ CONFIG_PARPORT
   If you want to use devices connected to your parallel port (the
   connector at the computers with 25 holes), e.g. printer, Zip drive,
   PLIP link etc., then you need to enable this option; please read
-  Documentation/parport.txt and drivers/misc/BUGS-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
-  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 use by this driver at module load time, read
-  Documentation/networking/net-modules.txt.
+  Documentation/parport.txt and drivers/misc/BUGS-parport.  For
+  extensive information about drivers for many devices attaching to
+  the parallel port see http://www.torque.net/linux-pp.html on the WWW
+  (To browse the WWW, you need to have access to a machine on the
+  Internet that has a programs like lynx or netscape). 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 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 use by this driver at
+  module load time, read Documentation/networking/net-modules.txt.
 
 PC-style hardware 
 CONFIG_PARPORT_PC
   You should enable this option if you have a PC-style parallel
   port. All IBM PC compatible computers and some Alphas have PC-style
-  parallel ports.  This driver is also available as a module which
-  will be called parport_pc.o.
+  parallel ports.  This code is also available as a module. If you
+  want to it 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_pc.o.
+
+Sun Ultra/AX-style hardware 
+CONFIG_PARPORT_AX
+  Say Y here if you need support for the parallel port hardware on Sun
+  Ultra/AX machines.  This code is also available as a module (say M),
+  called parport_ax.o.  If in doubt, saying N is the safe plan.
 
 Compile the kernel into the ELF object format 
 CONFIG_ELF_KERNEL
@@ -996,9 +1198,9 @@ CONFIG_PNP
 
 Auto-probe for parallel devices
 CONFIG_PNP_PARPORT
-  Some IEEE-1284 conformant parallel-port devices can identify themselves
-  when requested.  If this option is enabled the kernel will probe to see
-  what devices are connected at boot time.
+  Some IEEE-1284 conformant parallel-port devices can identify
+  themselves when requested.  Say Y to enable this feature, or M to
+  compile it as a module (parport_ieee1284.o).  If in doubt, say N.
 
 Plug and Play subsystem (EXPERIMENTAL)
 CONFIG_PNP_DRV
@@ -1031,7 +1233,7 @@ CONFIG_PNP_ISA
   Plug and Play ISA devices. This includes full support for PnP ISA,
   including the I/O range check feature.
 
-PnP ISA backwards-compatiblity support
+PnP ISA backwards-compatibility support
 CONFIG_PNP_ISA_COMPAT
   This option will enable partial backwards compatibility with drivers
   written using older versions (up to the last 0.2.x) of the PnP driver
@@ -1044,18 +1246,18 @@ CONFIG_PNP_LEGACY
   These cards used somewhat proprietary mechanisms for configuring
   IRQs, DMAs, IO addresses, and memory ranges. These devices (mainly
   network cards, but also some sound card) can be configured as any
-  other PnP device can by enabling this option, if appropriate drivers
+  other PnP device can by saying Y here, if appropriate drivers
   for these devices are available.
 
 PnP sysctl support (RECOMMENDED)
 CONFIG_PNP_SYSCTL
   This option enables support for the user-mode interface to the
-  kernel-mode PnP systems. It requires that you enable CONFIG_SYSCTL.
-  The only reason you might want to switch this off is if you aren't
-  going to use user-mode utilities to configure PnP, and you want to
-  save a couple of kilobytes of kernel space. Answer Y unless you know
-  what you are doing. User-mode utilities and a library for accessing
-  this interface may be found at
+  kernel-mode PnP systems. It requires that you said Y to "Sysctl
+  support" above.  The only reason you might want to switch this off
+  is if you aren't going to use user-mode utilities to configure PnP,
+  and you want to save a couple of kilobytes of kernel space. Answer Y
+  unless you know what you are doing. User-mode utilities and a
+  library for accessing this interface may be found at
   http://www.lpsg.demon.co.uk/pnp-linux.html.
 
 PnP auto-configures all devices on startup
@@ -1082,10 +1284,10 @@ CONFIG_MODVERSIONS
   kernel. Saying Y here makes it possible, and safe, to use the
   same modules even after compiling a new kernel; this requires the
   program modprobe. All the software needed for module support is in
-  the modules package (check the file Documentation/Changes for
+  the modutils package (check the file Documentation/Changes for
   location and latest version).  NOTE: if you say Y here but don't
   have the program genksyms (which is also contained in the above
-  mentioned modules package), then the building of your kernel will
+  mentioned modutils package), then the building of your kernel will
   fail.  If you are going to use modules that are generated from
   non-kernel sources, you would benefit from this option. Otherwise
   it's not that important. So, N ought to be a safe bet.
@@ -1100,7 +1302,7 @@ CONFIG_KERNELD
   "kerneld" will also automatically unload all unused modules, so you
   don't have to use "rmmod" either.  kerneld will also provide support
   for different user-level beeper and screen blanker programs later
-  on.  The "kerneld" daemon is included in the modules package (check
+  on.  The "kerneld" daemon is included in the modutils package (check
   Documentation/Changes for latest version and location). You will
   probably want to read the kerneld mini-HOWTO, available via ftp
   (user: anonymous) from
@@ -1150,17 +1352,80 @@ CONFIG_IP_MULTICAST
   you need to have access to a machine on the Internet that has a
   program like lynx or netscape). Information about the multicast
   capabilities of the various network cards is contained in
-  drivers/net/README.multicast. For most people, it's safe to say N.
+  Documentation/networking/multicast.txt. For most people, it's safe
+  to say N.
+
+IP: advanced router
+CONFIG_IP_ADVANCED_ROUTER
+  If you intend to run your Linux box mostly as a router, i.e. as a
+  computer that forwards and redistributes network packets, say Y; you
+  will then be presented with several options that allow more precise
+  control about the routing process.
+  The answer to this question won't directly affect the kernel: saying
+  N will just cause this configure script to skip all the questions
+  about advanced routing.
+  Note that your box can only act as a router if you say Y to "/proc
+  filesystem support" below and if you enable IP forwarding in your
+  kernel; you can do this from within a boot-time script like so:
+    echo "1" > /proc/sys/net/ipv4/ip_forwarding
+  after the /proc filesystem has been mounted.  
+  If unsure, say N here.
+
+IP: policy routing
+CONFIG_IP_MULTIPLE_TABLES
+  Normally, a router decides what to do with a received packet based
+  solely on the packet's final destination address. If you say Y here,
+  routing can also take into account the originating address and the
+  network device from which the packet reached us.
+
+IP: equal cost multipath
+CONFIG_IP_ROUTE_MULTIPATH
+  Normally, the routing tables specify a single action to be taken in
+  a deterministic manner for a given packet. If you say Y here
+  however, it becomes possible to attach several actions to a packet
+  pattern, in effect specifying several alternative paths to travel
+  for those packets. The router considers all these paths to be of
+  equal "cost" and chooses one of them in a non-deterministic fashion
+  if a matching packet arrives.
+
+IP: use TOS value as routing key
+CONFIG_IP_ROUTE_TOS
+  The header of every IP packet carries a TOS (Type of Service) value
+  with which the packet requests a certain treatment, e.g. low latency
+  (for interactive traffic), high throughput, or high
+  reliability. Normally, these values are ignored, but if you say Y
+  here, you will be able to specify different routes for packets with
+  different TOS values.
+
+IP: verbose route monitoring
+CONFIG_IP_ROUTE_VERBOSE
+  If you say Y here, which is recommended, then the kernel will print
+  verbose messages regarding the routing, for example warnings about
+  received packets which look strange and could be evidence of an
+  attack or a misconfigured system somewhere. The information is
+  handled by the klogd demon which is responsible for kernel messages
+  ("man klogd").
+
+IP: large routing tables
+CONFIG_IP_ROUTE_LARGE_TABLES
+  If you have routing zones that grow to more than about 64 entries,
+  you may want to say Y here to speed up the routing process.
+
+IP: fast network address translation
+CONFIG_IP_ROUTE_NAT
+  If you say Y here, your router will be able to modify source and
+  destination addresses of packets that pass through it.
 
 IP: optimize as router not host
 CONFIG_IP_ROUTER
   Some Linux network drivers use a technique called copy and checksum
-  to optimize host performance. For a machine which is forwarding most
-  packets to another host this is however a loss. This parameter turns
-  off copy and checksum from devices. It may make other changes in the
-  future.
+  to optimize host performance. For a machine which acts a router most
+  of the time and is forwarding most packets to another host this is
+  however a loss. If you say Y here, copy and checksum will be
+  switched off. In the future, it may make other changes which
+  optimize for router operation.
   Note that your box can only act as a router if you say Y to "/proc
-  filesystem support" below and you enable IP forwarding in your
+  filesystem support" below and if you enable IP forwarding in your
   kernel; you can do this from within a boot-time script like so:
     echo "1" > /proc/sys/net/ipv4/ip_forwarding
   after the /proc filesystem has been mounted.  If unsure, say N here.
@@ -1179,21 +1444,22 @@ CONFIG_IP_FIREWALL
   support" below and IP forwarding is enabled in your kernel; do this
   from within a boot-time script like so: 
     echo "1" > /proc/sys/net/ipv4/ip_forwarding
-  after the /proc filesystem has been mounted.  You need to say Y to
-  "IP firewalling" in order to be able to use IP masquerading
-  (i.e. local computers can chat with an outside host, but that
-  outside host is made to think that it is talking to the firewall box
-  -- makes the local network completely invisible and avoids the need
-  to allocate valid IP host addresses for the machines on the local
-  net) and IP packet accounting (keeping track of what is using all
-  your network bandwidth) and IP transparent proxying (makes the
-  computers on the local 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). If unsure, say N.
+  after the /proc filesystem has been mounted.  
+  You need to say Y to "IP firewalling" in order to be able to use IP
+  masquerading (masquerading means that local computers can chat with
+  an outside host, but that outside host is made to think that it is
+  talking to the firewall box -- makes the local network completely
+  invisible and avoids the need to allocate valid IP host addresses
+  for the machines on the local net) and IP packet accounting (keeping
+  track of what is using all your network bandwidth) and IP
+  transparent proxying (makes the computers on the local 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). If
+  unsure, say N.
 
 IP: firewall packet netlink device
 CONFIG_IP_FIREWALL_NETLINK
-  If you say Y here and when packets hit your Linux firewall and are
+  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
@@ -1219,8 +1485,8 @@ CONFIG_IP_PNP
   of the routing table during kernel boot, based on either information
   supplied at the kernel command line or by BOOTP or RARP protocols.
   You need to say Y only for diskless machines requiring network access
-  to boot (see CONFIG_ROOT_NFS for more information about root volume
-  mounted via NFS), because all other machines configure the network in
+  to boot (in which case you want to say Y to "Root file system on
+  NFS" as well), because all other machines configure the network in
   their startup scripts.
 
 BOOTP support
@@ -1265,18 +1531,22 @@ CONFIG_NET_IPIP
 
 IP: GRE tunnels over IP
 CONFIG_NET_IPGRE
-  Another kind of tunneling protocol - "Generic Routing Encapsulation".
-  It allows to tunnel any networking protocol over existing IPv4
-  infrastructure. At the moment only IPv4 and IPv6 are supported.
-  It is useful, if another endpoint is Cisco router: it likes
-  GRE much more than IPIP and, particularly, allows multicasts
-  redistribution over GRE tunnels.
+  Tunneling means encapsulating data of one protocol type within
+  another protocol and sending it over a channel that understands the
+  encapsulating protocol. This particular tunneling driver implements
+  GRE (Generic Routing Encapsulation) and at this time allows
+  encapsulating of IPv4 or IPv6 over existing IPv4
+  infrastructure. This driver is useful if the other endpoint is a
+  Cisco router: Cisco likes GRE much better than the other Linux
+  tunneling driver ("IP: tunneling" above). In addition, GRE allows
+  multicast redistribution through the tunnel.
 
 IP: broadcast GRE over IP
 CONFIG_NET_IPGRE_BROADCAST
-  One application of GRE/IP, allowing to construct broadcast LAN,
-  looking like ethernet network, distributed over the Internet.
-  It requires, that your domain supported multicast routing.
+  One application of GRE/IP is to construct a broadcast WAN (Wide Area
+  Network), which looks like a normal1 ethernet LAN (Local Area
+  Network), but can be distributed all over the Internet. If you want
+  to do that, say Y here and to "IP: multicast routing" below.
 
 IP: firewall packet logging
 CONFIG_IP_FIREWALL_VERBOSE
@@ -1312,7 +1582,7 @@ CONFIG_IP_MASQUERADE
   Linux box to the Internet using SLiRP [SLiRP is a SLIP/PPP emulator
   that works if you have a regular dial up shell account on some UNIX
   computer; get it via ftp (user: anonymous) from
-  ftp://sunsite.unc.edu/pub/Linux/system/Network/serial/].)  Details
+  ftp://sunsite.unc.edu/pub/Linux/system/network/serial/].)  Details
   on how to set things up are contained in the IP Masquerading FAQ,
   available at http://www.indyramp.com/masq/. If you say Y here, then
   the modules ip_masq_ftp.o (for ftp transfers through the firewall),
@@ -1324,23 +1594,27 @@ CONFIG_IP_MASQUERADE
 
 IP: ICMP masquerading
 CONFIG_IP_MASQUERADE_ICMP
-  The basic masquerade code described for CONFIG_IP_MASQUERADE only
+  The basic masquerade code described for "IP: masquerading" above only
   handles TCP or UDP packets (and ICMP errors for existing 
   connections).  This option adds additional support for masquerading
   ICMP packets, such as ping or the probes used by the Windows 95
   tracert program.
-  If you want this, say Y.
+  If you want this, say Y. 
 
 IP: ipautofw masquerade support
 CONFIG_IP_MASQUERADE_IPAUTOFW (Experimental)
-  ipautofw is a program by Richard Lynch allowing additional
-  support for masquerading protocols which do not (as yet)
-  have additional protocol helpers.  
-  Information and source for ipautofw is available from
+  ipautofw is a program by Richard Lynch allowing additional support
+  for masquerading protocols which do not (as yet) have their own
+  additional protocol helpers.  Information and source for ipautofw is
+  available via ftp (user: anonymous) from
   ftp://ftp.netis.com/pub/members/rlynch/
   The ipautofw code is still under development and so is currently
   marked EXPERIMENTAL.
-  If you want this, say Y.
+  If you want this, say Y. This code 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 ip_masq_autofw.o. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 IP: ipportfw masquerade support
 CONFIG_IP_MASQUERADE_IPPORTFW
@@ -1348,10 +1622,16 @@ CONFIG_IP_MASQUERADE_IPPORTFW
   to allow some forwarding of packets from outside to inside a
   firewall on given ports. Information and source for ipportfw is
   available from
-  http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html
+  http://www.monmouth.demon.co.uk/ipsubs/portforwarding.html (to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape).
   The portfw code is still under development and so is currently
   marked EXPERIMENTAL.
-  If you want this, say Y.
+  If you want this, say Y. This code 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 ip_masq_portfw.o. If
+  you want to compile it as a module, say M here and read
+  Documentation/modules.txt.
 
 IP: always defragment 
 CONFIG_IP_ALWAYS_DEFRAG
@@ -1397,23 +1677,26 @@ CONFIG_IP_MROUTE
   audio and video broadcasts. In order to do that, you would most
   likely run the program mrouted. Information about the multicast
   capabilities of the various network cards is contained in
-  drivers/net/README.multicast. If you haven't heard about it, you
-  don't need it.
+  Documentation/networking/multicast.txt. If you haven't heard about
+  it, you don't need it.
 
 IP: PIM-SM version 1 support
 CONFIG_IP_PIMSM_V1
-  Kernel side support for Sparse Mode PIM version 1. This multicast
-  routing protocol is used widely due to Cisco supports it.
-  You need special software to use it (pimd-v1). Press N, if
-  you do not want to use PIM-SM v1. Note, that Dense Mode PIM
-  need not this option.
+  Kernel side support for Sparse Mode PIM (Protocol Independent
+  Multicast) version 1. This multicast routing protocol is used widely
+  because Cisco supports it.  You need special software to use it
+  (pimd-v1). Please see http://netweb.usc.edu/pim/ for more
+  information about PIM (to browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or
+  netscape). Say Y if you want to use PIM-SM v1. Note that you can say
+  N here if you just want to use Dense Mode PIM.
 
 IP: PIM-SM version 2 support
 CONFIG_IP_PIMSM_V2
-  Kernel side support for Sparse Mode PIM version 2. You need
-  experimental routing daemon supporting it (pimd or gated-5).
-  This protocol is not used widely, so that press Y, if you
-  do not want play with it.
+  Kernel side support for Sparse Mode PIM version 2. In order to use
+  this, you need an experimental routing daemon supporting it (pimd or
+  gated-5).  This routing protocol is not used widely, so say N unless
+  you want to play with it.
 
 PC/TCP compatibility mode
 CONFIG_INET_PCTCP
@@ -1435,16 +1718,18 @@ CONFIG_INET_RARP
   rarp ("man rarp") on your box. If you actually want to use a
   diskless Sun 3 machine as an Xterminal to Linux, say Y here and
   fetch Linux-Xkernel from
-  ftp://sunsite.unc.edu/pub/Linux/system/Network/boot.net/.  Superior
+  ftp://sunsite.unc.edu/pub/Linux/system/network/boot.net/.  Superior
   solutions to the problem of booting and configuring machines over a
   net connection are given by the protocol BOOTP and its successor
   DHCP. See the DHCP FAQ
-  http://web.syr.edu/~jmwobus/comfaqs/dhcp.faq.html for details.  If
-  you want to compile RARP 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 rarp.o.  If you don't understand a word of the above, say N
-  and rest in peace.
+  http://web.syr.edu/~jmwobus/comfaqs/dhcp.faq.html for details (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
+  RARP 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 rarp.o.
+  If you don't understand a word of the above, say N and rest in
+  peace.
 
 Assume subnets are local
 CONFIG_INET_SNARL
@@ -1517,10 +1802,16 @@ CONFIG_SKB_LARGE
 
 Unix domain sockets
 CONFIG_UNIX
-  Y if you want Unix domain sockets.  Unless you are working on an
-  embedded system or somthing, you probably want to say Y.  If you try
-  building this as a module and you are running kerneld, you need to make
-  sure and add 'alias net-pf-1 unix' to your /etc/conf.module file.
+  This includes Unix domain sockets, the standard Unix mechanism for
+  establishing and accessing network connections.  Unless you are
+  working on an embedded system or something, you probably want to say
+  Y.  The socket 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 unix.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt. If you
+  try building this as a module and you are running kerneld, be sure
+  to add 'alias net-pf-1 unix' to your /etc/conf.module file.  If
+  unsure, say Y.
 
 The IPv6 protocol
 CONFIG_IPV6
@@ -1528,31 +1819,35 @@ CONFIG_IPV6
   Protocol IP version 6 (also called IPng "IP next
   generation"). Features of this new protocol include: expanded
   address space, authentication and privacy, and seamless
-  interoperability with the current version of IP. For general
-  information about IPv6, see
-  http://playground.sun.com/pub/ipng/html/ipng-main.html; for specific
-  information about IPv6 under Linux read the HOWTO at
-  http://www.terra.net/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. 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.
+  interoperability with the current version of IP (IP version 4). For
+  general information about IPv6, see
+  http://playground.sun.com/pub/ipng/html/ipng-main.html (to browse
+  the WWW, you need to have access to a machine on the Internet that
+  has a program like lynx or netscape); for specific information about
+  IPv6 under Linux read the HOWTO at http://www.terra.net/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. 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.
 
 IPv6: enable EUI-64 token format
 CONFIG_IPV6_EUI64
-  6bone is moving to new aggregatable address format and new link local
-  address assignment (EUI-64). Say Y, if your site already upgraded, or
-  started upgrade.
+  6bone, the network of computers using the IPv6 protocol, is moving
+  to a new aggregatable address format and a new link local address
+  assignment (EUI-64). Say Y, if your site has upgraded already, or
+  has started to upgrade.
 
 IPv6: disable provider based addresses
 CONFIG_IPV6_NO_PB
-  Linux tries to operate correctly, when site is moved to EUI-64
-  only partially. Unfortunately, these two formats ("provider based"
-  and "aggregatable") are incompatible. Say Y, if your site finished
-  upgrade, and/or you encountered some problems caused by presense of
-  two link-local addresses on an interface.
+  Linux tries to operate correctly when your site is moved to EUI-64
+  only partially. Unfortunately, the two address formats (old:
+  "provider based" and new: "aggregatable") are incompatible. Say Y,
+  if your site finished the upgrade to EUI-64, and/or you encountered
+  some problems caused by the presence of two link-local addresses on
+  an interface.
 
 The IPX protocol
 CONFIG_IPX
@@ -1560,13 +1855,13 @@ CONFIG_IPX
   used for local networks of Windows machines. You need it if you want
   to access Novell Netware file or print servers using the Linux
   Novell client ncpfs (available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/system/Filesystems/) or from within the
+  sunsite.unc.edu:/pub/Linux/system/filesystems/) or from within the
   Linux DOS emulator dosemu (read the DOSEMU-HOWTO, available in
   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. To
   turn your Linux box into a fully featured Netware file server and
   IPX router, say Y here and fetch either lwared from
-  sunsite.unc.edu:/pub/Linux/system/Network/daemons/ or mars_nwe from
+  sunsite.unc.edu:/pub/Linux/system/network/daemons/ or mars_nwe from
   ftp.gwdg.de:/pub/linux/misc/ncpfs. For more information, read the
   IPX-HOWTO in sunsite.unc.edu:/pub/Linux/docs/howto. The IPX driver
   would enlarge your kernel by about 5 kB. This driver is also
@@ -1624,39 +1919,49 @@ CONFIG_ATALK
   machine on the Internet that has a program like lynx or
   netscape). EtherTalk is the name used for appletalk over ethernet
   and the cheaper and slower LocalTalk is appletalk over a proprietary
-  apple network using serial links. Ethertalk and Localtalk is fully 
+  apple network using serial links. Ethertalk and Localtalk are fully 
   supported by Linux. The NET-2-HOWTO, available via ftp (user: anonymous)
   in sunsite.unc.edu:/pub/Linux/docs/HOWTO contains valuable information
   as well. 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 will be called appletalk.o. If you want to compile
+  want). The module is called appletalk.o. If you want to compile
   it as a module, say M here and read Documentation/modules.txt. I
   hear that the GNU boycott of Apple is over, so even politically
   correct people are allowed to say Y here.
 
 Appletalk-IP driver support
 CONFIG_IPDDP
-  Appletalk-IP is a method Macintosh users use IP services. This driver
-  allows you to either send your IP traffic over an Appletalk network to
-  an Appletalk-IP router, or you can have your machine act as an Appletalk-IP
-  router and route Appletalk-IP traffic for your Macintosh users. Both
-  modes require seperate user-space support software, please see each
-  individual options help to get the correct URL of the software.
-
-Appletalk-IP Encapsulation support
-CONFIG_IPDDP_ENCAP
   This allows IP networking for users who only have Appletalk
-  networking available.  This feature is experimental. Please see
-  http://www.maths.unm.edu/~bradford/ltpc.html for support software.
+  networking available.  This feature is experimental. With this
+  driver, you can either encapsulate IP inside Appletalk (e.g. if your
+  Linux box is stuck on an appletalk only network) or decapsulate
+  (e.g. if you want your Linux box to act as a internet gateway for a
+  zoo of appletalk connected Macs). You decide which one of the two
+  you want in the following two questions; you can say Y to only one
+  of them. Please see Documentation/networking/ipddp.txt for more
+  information.  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 ipddp.o. If you want to
+  compile it as a module, say M here and read
+  Documentation/modules.txt.
 
-Appletalk-IP Decapsulation support
+IP to Appletalk-IP Encapsulation support
+CONFIG_IPDDP_ENCAP
+  If you say Y here, the kernel will be able to encapsulate IP packets
+  inside Appletalk frames; this is useful if your Linux box is stuck
+  on an appletalk network (which hopefully contains a decapsulator
+  somewhere). Please see Documentation/networking/ipddp.txt for more
+  information. If you say Y here, you cannot say Y to "Appletalk-IP to
+  IP Decapsulation support", below.
+
+Appletalk-IP to IP Decapsulation support
 CONFIG_IPDDP_DECAP
-  This allows you to provide IP services to your Appletalk users.
-  It does not matter what interface the Macs are comming into your
-  Linux box on, be it Localtalk, Ethertalk, PPPtalk, etc. The only
-  dependent variable is if the Appletalk layer supports the protocol
-  you need. User space software is required to run this driver, you
-  can pick it up at http://spacs1.spacs.k12.wi.us/~jschlst/MacGate.html
+  If you say Y here, the kernel will be able to decapsulate
+  Appletalk-IP frames to IP packets; this is useful if you want your
+  Linux box to act as an Internet gateway for an appletalk
+  network. Please see Documentation/networking/ipddp.txt for more
+  information. If you say Y here, you cannot say Y to "IP to
+  Appletalk-IP Encapsulation support", above.
 
 Apple/Farallon LocalTalk PC card support
 CONFIG_LTPC
@@ -1665,8 +1970,7 @@ CONFIG_LTPC
   If you are in doubt, this card is the one with the 65C02 chip on it.
   You also need version 1.3.3 or later of the netatalk package.
   This driver is experimental, which means that it may not work.
-  See README.ltpc in the drivers/net directory, and the web site
-  http://www.math.unm.edu/~bradford/ltpc.html
+  See the file Documentation/networking/ltpc.txt.
 
 COPS LocalTalk PC card support
 CONFIG_COPS
@@ -1675,9 +1979,7 @@ CONFIG_COPS
   package.  This driver is experimental, which means that it may not
   work.  This driver will only work if you choose "Appletalk DDP"
   networking support, above.
-  Please read the file Documentation/networking/README.cops.  See the
-  web site http://www.math.unm.edu/~bradford/ltpc.html for localtalk
-  IP tools.
+  Please read the file Documentation/networking/cops.txt. 
 
 Dayna firmware support
 CONFIG_COPS_DAYNA
@@ -1690,6 +1992,17 @@ CONFIG_COPS_TANGENT
   Support COPS compatible cards with Tangent style firmware (Tangent
   ATB_II, Novell NL-1000, Daystar Digital LT-200.
 
+Amateur Radio support
+CONFIG_HAMRADIO
+  If you want to connect your Linux computer to an amateur radio, say
+  Y here. You want to read 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) and the HAM-HOWTO
+  and the AX25-HOWTO, both available via ftp (user: anonymous) from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the answer to this
+  question won't directly affect the kernel: saying N will just cause
+  this configure script to skip all the questions about amateur radio.
+
 Amateur Radio AX.25 Level 2
 CONFIG_AX25
   This is the protocol used for computer communication over amateur
@@ -1783,19 +2096,20 @@ CONFIG_ROSE
 CCITT X.25 Packet Layer
 CONFIG_X25
   X.25 is a set of standardized network protocols, similar in scope to
-  frame relay; the one physical line from your box to the entry point
-  to the X.25 network can carry several logical point-to-point
-  connections (called "virtual circuits") to other computers connected
-  to the X.25 network. Governments, banks, and other organizations
-  tend to use it to connect to each other or to form Wide Area
-  Networks. Many countries have public X.25 networks.  X.25 consists
-  of two protocols: the higher level Packet Layer Protocol (PLP) (say
-  Y here if you want that) and the lower level data link layer
-  protocol LAPB (say Y to "LAPB Data Link Driver" below if you want
-  that). You can read more about X.25 at
-  http://www.sangoma.com/x25.html and
-  http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm.
-  Information about X.25 for Linux is contained in the files
+  frame relay; the one physical line from your box to the X.25 network
+  entry point can carry several logical point-to-point connections
+  (called "virtual circuits") to other computers connected to the X.25
+  network. Governments, banks, and other organizations tend to use it
+  to connect to each other or to form Wide Area Networks (WAN's). Many
+  countries have public X.25 networks.  X.25 consists of two
+  protocols: the higher level Packet Layer Protocol (PLP) (say Y here
+  if you want that) and the lower level data link layer protocol LAPB
+  (say Y to "LAPB Data Link Driver" below if you want that). You can
+  read more about X.25 at http://www.sangoma.com/x25.html and
+  http://www.cisco.com/univercd/data/doc/software/11_0/rpcg/cx25.htm
+  (to browse the WWW, you need to have access to a machine on the
+  Internet that has a program like lynx or netscape).  Information
+  about X.25 for Linux is contained in the files
   Documentation/networking/x25.txt and
   Documentation/networking/x25-iface.txt.  One connects to an X.25
   network either with a dedicated network card using the X.21 protocol
@@ -1831,7 +2145,7 @@ CONFIG_LAPB
 CONFIG_LLC
   This is a Logical Link Layer protocol used for X.25 connections over
   ethernet, using ordinary ethernet cards. 
-  
+
 Bridging (EXPERIMENTAL)
 CONFIG_BRIDGE
   If you say Y here, then your Linux box will be able to act as an
@@ -1842,14 +2156,25 @@ CONFIG_BRIDGE
   algorithm. As this is a standard, Linux bridges will interwork
   properly with other third party bridge products. In order to use
   this, you'll need the bridge configuration tools available via ftp
-  (user: anonymous) from shadow.cabi.net. Note that if your box acts
-  as a bridge, it probably contains several ethernet devices, but the
-  kernel is not able to recognize more than one at boot time without
-  help; for details read the Multiple-Ethernet-mini-HOWTO, available
-  via ftp (user: anonymous) in
+  (user: anonymous) from shadow.cabi.net in /pub/Linux. Note that if
+  your box acts as a bridge, it probably contains several ethernet
+  devices, but the kernel is not able to recognize more than one at
+  boot time without help; for details read the
+  Multiple-Ethernet-mini-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. The Bridging code is
   still in test. If unsure, say N.
 
+Packet socket
+CONFIG_PACKET
+  The Packet protocol is used by applications which communicate
+  directly with network devices without an intermediate network
+  protocol implemented in the kernel, e.g. tcpdump. If you want that
+  they work, choose Y. This driver is also available as a module
+  called af_packet.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. If
+  unsure, say Y.
+
 Kernel/User network link driver
 CONFIG_NETLINK
   This driver allows for two-way communication between certain parts
@@ -1861,7 +2186,9 @@ CONFIG_NETLINK
   to "Kernel/User network link driver" further down.  You also need to
   say Y here if you want to use arpd, a daemon that helps keep the
   internal ARP cache (a mapping between IP addresses and hardware
-  addresses on the local network) small. If unsure, say N.
+  addresses on the local network) small. The ethertap device, which
+  lets user space programs read and write raw ethernet frames, also
+  needs the network link driver. If unsure, say Y.
 
 Routing messages
 CONFIG_RTNETLINK
@@ -1870,6 +2197,11 @@ CONFIG_RTNETLINK
   you can read some network related routing information from that
   file. Everything you write to that file will be discarded.
 
+Netlink device emulation
+CONFIG_NETLINK_DEV
+  This is a backward compatibility option, choose Y for now.
+  This option will be removed soon.
+
 SCSI support?
 CONFIG_SCSI
   If you want to use a SCSI harddisk, SCSI tapedrive, SCSI CDROM or
@@ -1902,7 +2234,7 @@ CONFIG_BLK_DEV_SD
   your root filesystem (the one containing the directory /) is located
   on a SCSI disk. In this case, do not compile the driver for your
   SCSI host adapter (below) as a module either.
-  
+
 SCSI tape support
 CONFIG_CHR_DEV_ST
   If you want to use a SCSI tapedrive under Linux, say Y and read the
@@ -1930,8 +2262,7 @@ CONFIG_BLK_DEV_SR_VENDOR
   This enables the usage of vendor specific SCSI commands. This is
   required to support multisession CD's on with old NEC/TOSHIBA
   cdrom drives (and HP Writers). If you have such a drive and get
-  the first session only, try to turn this on. Most drives should
-  work fine without this.
+  the first session only, try to say Y here; everybody else says N.
 
 SCSI generic support
 CONFIG_CHR_DEV_SG
@@ -1972,14 +2303,14 @@ CONFIG_SCSI_LOGGING
   This turns on a logging facility that can be used to debug a number
   of problems.  Normally no logging output will appear, but you can
   enable logging with a shell command like: 
-  'echo "scsi log token [level]" > /proc/scsi/scsi'
-  There are a number of things that can be used for 'token', and this
-  allows you to select the types of information you want, and the level
-  allows you to select the level of verbosity.  If you say 'N' here,
-  it may be harder to track down some types of scsi problems.  If
-  you say 'Y' here your kernel will be somewhat larger, but there
-  should be no noticable performance impact as long as you have logging
-  turned off.
+     echo "scsi log token [level]" > /proc/scsi/scsi
+  There are a number of things that can be used for 'token' (you can
+  find them in the source: drivers/scsi/scsi.c), and this allows you
+  to select the types of information you want, and the level allows
+  you to select the level of verbosity.  If you say 'N' here, it may
+  be harder to track down some types of scsi problems.  If you say 'Y'
+  here your kernel will be somewhat larger, but there should be no
+  noticeable performance impact as long as you have logging turned off.
 
 AdvanSys SCSI support
 CONFIG_SCSI_ADVANSYS
@@ -2015,7 +2346,7 @@ CONFIG_SCSI_AHA1542
   inserted in and removed from the running kernel whenever you want),
   say M here and read Documentation/modules.txt. The module will be
   called aha1542.o.
+
 Adaptec AHA1740 support
 CONFIG_SCSI_AHA1740
   This is support for a SCSI host adapter. It is explained in section
@@ -2057,21 +2388,22 @@ CONFIG_OVERRIDE_CMDS
 
 Maximum number of commands per LUN
 CONFIG_AIC7XXX_CMDS_PER_LUN
-  If tagged queueing is enabled, then you may want to try increasing
-  the number of SCSI commands per LUN to more than 2.  By default, we
-  limit the commands per LUN to 2 with or without tagged queueing
-  enabled.  If tagged queueing is disabled, the sequencer in the host
-  adapter will keep the 2nd command in the input queue until the first
-  one completes - so it is OK to have more than 1 command queued.  If
-  tagged queueing is enabled, then the sequencer will attempt to send
-  the 2nd command block to the device while the first command block is
-  executing and the device is disconnected.  For adapters limited to 4
-  command blocks (SCB's), you may want to actually decrease the
-  commands per LUN to 1, if you often have more than 2 devices active
-  at the same time.  This will ensure that there will always be a free
-  SCB for up to 4 devices active at the same time.  When SCB paging is
-  enabled, set the commands per LUN to 8 or higher (see "SCB paging
-  support" below).  If unsure, go with the default for now.
+  By default, we limit the commands per LUN to 2 with or without
+  tagged queueing enabled.  If tagged queueing is enabled, the
+  sequencer in the host adapter will attempt to send the 2nd command
+  block to the device while the first command block is still executing
+  and the device is disconnected. If the devices don't complain, you
+  can thus try to increase the number of SCSI commands per LUN to more
+  than 2 in this case. If tagged queueing is disabled, the sequencer
+  in the host adapter will keep the 2nd command in its input queue
+  until the first one completes - so it is OK to have more than 1
+  command queued. However, for host adapters limited to 4 command
+  blocks (SCB's), you may want to actually decrease the commands per
+  LUN to 1, if you often have more than 2 devices active at the same
+  time.  This will ensure that there will always be a free SCB for up
+  to 4 devices active at the same time. When SCB paging is enabled,
+  set the commands per LUN to 8 or higher (see "SCB paging support"
+  below).  If unsure, go with the default for now.
 
 Enable SCB paging
 CONFIG_AIC7XXX_PAGE_ENABLE
@@ -2171,7 +2503,7 @@ CONFIG_SCSI_U14_34F
   want). The module will be called u14-34f.o. If you want to compile
   it as a module, say M here and read Documentation/modules.txt.
 
-enable linked commands
+enable elevator sorting
 CONFIG_SCSI_U14_34F_LINKED_COMMANDS
   This is a feature of SCSI-2 which improves performance: the host
   adapter can send a whole list of commands to a device in one
@@ -2209,7 +2541,7 @@ CONFIG_SCSI_GENERIC_NCR5380
   kernel whenever you want). The module will be called g_NCR5380.o. If
   you want to compile it as a module, say M here and read
   Documentation/modules.txt.
+
 Enable NCR53c400 extensions
 CONFIG_SCSI_GENERIC_NCR53C400
   This enables certain optimizations for the NCR53c400 scsi cards. You
@@ -2249,7 +2581,7 @@ CONFIG_SCSI_NCR53C7xx_FAST
   This will enable 10MHz FAST-SCSI transfers with your host
   adapter. Some systems have problems with that speed, so it's safest
   to say N here.
+
 allow DISCONNECT
 CONFIG_SCSI_NCR53C7xx_DISCONNECT
   This enables the disconnect/reconnect feature of the NCR SCSI
@@ -2394,6 +2726,12 @@ CONFIG_SCSI_IBMMCA
   say M here and read Documentation/modules.txt. The module will be
   called ibmmca.o.
 
+reset SCSI-devices while booting
+CONFIG_SCSI_IBMMCA_DEV_RESET
+  If you say Y here, each connected SCSI device will get a reset
+  command at boot time. This can be necessary for some special SCSI
+  devices. If unsure, say N.
+
 Always IN2000 SCSI support
 CONFIG_SCSI_IN2000
   This is support for an ISA bus SCSI host adapter. You'll find more
@@ -2416,6 +2754,36 @@ CONFIG_SCSI_PAS16
   pas16.o. If you want to compile it as a module, say M here and read
   Documentation/modules.txt.
 
+PCI2000 support
+CONFIG_SCSI_PCI2000
+  This is support for the PCI2000I EIDE interface card which acts as a
+  SCSI host adapter. Please read the SCSI-HOWTO, available via ftp
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. This
+  driver is also available as a module called pci2000.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.
+
+PCI2220i support
+CONFIG_SCSI_PCI2220I
+  This is support for the PCI2220i EIDE interface card which acts as a
+  SCSI host adapter. Please read the SCSI-HOWTO, available via ftp
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. This
+  driver is also available as a module called pci2220i.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.
+
+PSI240i support
+CONFIG_SCSI_PSI240I
+  This is support for the PSI240i EIDE interface card which acts as a
+  SCSI host adapter. Please read the SCSI-HOWTO, available via ftp
+  (user: anonymous) at sunsite.unc.edu:/pub/Linux/docs/HOWTO. This
+  driver is also available as a module called psi240i.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.
+
 Qlogic FAS SCSI support
 CONFIG_SCSI_QLOGIC_FAS
   This driver works only with the ISA, VLB, and PCMCIA versions of the
@@ -2484,15 +2852,15 @@ CONFIG_SCSI_ULTRASTOR
   Documentation/modules.txt. The module will be called ultrastor.o.
   Note that there is also another driver for the same hardware:
   "UltraStor 14F/34F support", above.
+
 7000FASST SCSI support
 CONFIG_SCSI_7000FASST
-  This driver supports the Western Digital 7000 SCSI host adapter.
-  Some information is in the source: drivers/scsi/wd7000.c.  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 will be called wd7000.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  This driver supports the Western Digital 7000 SCSI host adapter
+  family.  Some information is in the source: drivers/scsi/wd7000.c.
+  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 will be called wd7000.o. If you want to compile it
+  as a module, say M here and read Documentation/modules.txt.
 
 EATA ISA/EISA/PCI (DPT and generic EATA/DMA-compliant boards) support
 CONFIG_SCSI_EATA
@@ -2517,7 +2885,7 @@ CONFIG_SCSI_EATA_TAGGED_QUEUE
   previous commands haven't finished yet. Some SCSI devices don't
   implement this properly, so the save answer is N.
 
-enable linked commands
+enable elevator sorting
 CONFIG_SCSI_EATA_LINKED_COMMANDS
   This is a feature of SCSI-2 which improves performance: the host
   adapter can send a whole list of commands to a device in one
@@ -2542,25 +2910,12 @@ CONFIG_SCSI_NCR53C406A
   and read Documentation/modules.txt. The module will be called
   NCR53c406.o.
 
-Tekram DC390W/U/F (T) SCSI support
-CONFIG_SCSI_DC390W
-  This driver supports the Tekram DC390W/U/F (T) PCI SCSI host
-  adapters with the NCR/Symbios 53c825/875 chips. Say Y here if you
-  have one of those. If however you have a DC390 (T) adaptor with the
-  Am53C974A chip, use the DC390(T) driver "Tekram DC390(T) (AMD
-  PCscsi) SCSI support", 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 ???.o.
-  
 Tekram DC390(T) (AMD PCscsi) SCSI support
 CONFIG_SCSI_DC390T
   This driver supports the Tekram DC390(T) PCI SCSI host adapter with
   the Am53C974A chip, and perhaps other cards using the same chip.
-  This driver does _not_ support the DC390W/U/F adaptor with the 
-  NCR/Symbios chips; use "Tekram DC390W/U/F (T) SCSI support" for that
-  one.
+  This driver does _not_ support the DC390W/U/F adaptor with the
+  NCR/Symbios chips; use "NCR53C8XX SCSI support" for that one.
   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
@@ -2622,7 +2977,7 @@ CONFIG_SCSI_DEBUG
   is that many hard to reproduce problems can be tested in a controlled
   environment where there is reduced risk of losing important data.
   This is primarily of use to people trying to debug the middle and upper
-  layers of the scsi subsystem.
+  layers of the scsi subsystem. If unsure, say N.
 
 Network device support?
 CONFIG_NETDEVICES
@@ -2634,20 +2989,21 @@ CONFIG_NETDEVICES
   shell account or a BBS, even using term (term is a program which
   gives you almost full Internet connectivity if you have a regular
   dial up shell account on some Internet connected Unix computer. Read
-  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html).  You'll
-  have to say Y if your computer contains a network card that you want
-  to use under linux (make sure you know its name because you will be
-  asked for it and read the Ethernet-HOWTO; also, if you plan to use
-  more than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you want to use
-  SLIP (Serial Line Internet Protocol is the protocol used to send
-  Internet traffic over telephone lines or nullmodem cables) or CSLIP
-  (compressed SLIP) or PPP (Point to Point Protocol, a better and
-  newer replacement for SLIP) or PLIP (Parallel Line Internet Protocol
-  is mainly used to create a mini network by connecting the parallel
-  ports of two local machines) or AX.25/KISS (protocol for sending
-  internet traffic over radio links).  Make sure to read the
+  http://www.bart.nl/~patrickr/term-howto/Term-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)).  You'll have to say Y if your
+  computer contains a network card that you want to use under linux
+  (make sure you know its name because you will be asked for it and
+  read the Ethernet-HOWTO; also, if you plan to use more than one
+  network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini) or if you
+  want to use SLIP (Serial Line Internet Protocol is the protocol used
+  to send Internet traffic over telephone lines or nullmodem cables)
+  or CSLIP (compressed SLIP) or PPP (Point to Point Protocol, a better
+  and newer replacement for SLIP) or PLIP (Parallel Line Internet
+  Protocol is mainly used to create a mini network by connecting the
+  parallel ports of two local machines) or AX.25/KISS (protocol for
+  sending internet traffic over radio links).  Make sure to read the
   NET-2-HOWTO.  Eventually, you will have to read Olaf Kirch's
   excellent book "Network Administrator's Guide", to be found in
   sunsite.unc.edu:/pub/Linux/docs/LDP.  If unsure, say Y.
@@ -2669,7 +3025,7 @@ CONFIG_DUMMY
   want to use more than one dummy device at a time, you need to
   compile this driver as a module. Instead of 'dummy', the devices
   will then be called 'dummy0', 'dummy1' etc.
-  
+
 SLIP (serial line) support
 CONFIG_SLIP
   Say Y if you intend to use SLIP or CSLIP (compressed SLIP) to
@@ -2681,7 +3037,7 @@ CONFIG_SLIP
   nullmodems). Normally, your access provider has to support SLIP in
   order for you to be able to use it, but there is now a SLIP emulator
   called SLiRP around (available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/system/Network/serial/) which allows you
+  sunsite.unc.edu:/pub/Linux/system/network/serial/) which allows you
   to use SLIP over a regular dial up shell connection. If you plan to
   use SLiRP, make sure to say Y to CSLIP, below. The NET-2-HOWTO,
   available via ftp (user: anonymous) in
@@ -2690,14 +3046,16 @@ CONFIG_SLIP
   term (term is a program which gives you almost full Internet
   connectivity if you have a regular dial up shell account on some
   Internet connected Unix computer. Read
-  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html). SLIP
-  support will enlarge your kernel by about 4kB. If unsure, say N.  If
-  you want to compile this as a module ( = code which can be inserted
-  in and removed from the running kernel whenever you want), say M
-  here and read Documentation/modules.txt as well as
+  http://www.bart.nl/~patrickr/term-howto/Term-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)). SLIP support will enlarge
+  your kernel by about 4kB. If unsure, say N.  If you want to compile
+  this as a module ( = code which can be inserted in and removed from
+  the running kernel whenever you want), say M here and read
+  Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. The module will be called
   slip.o.
-  
+
 CSLIP compressed headers
 CONFIG_SLIP_COMPRESSED
   This protocol is faster than SLIP because it uses compression on the
@@ -2705,7 +3063,7 @@ CONFIG_SLIP_COMPRESSED
   on both ends. Ask your access provider if you are not sure and say
   Y, just in case. You will still be able to use plain SLIP. If you
   plan to use SLiRP, the SLIP emulator (available via ftp (user:
-  anonymous) from sunsite.unc.edu:/pub/Linux/system/Network/serial/)
+  anonymous) from sunsite.unc.edu:/pub/Linux/system/network/serial/)
   which allows you to use SLIP over a regular dial up shell
   connection, you definitely want to say Y here. The NET-2-HOWTO,
   available via ftp (user: anonymous) in
@@ -2728,27 +3086,15 @@ CONFIG_SLIP_MODE_SLIP6
   end of the link as well. It's good enough, for example, to run IP
   over the async ports of a Camtec JNT Pad. If unsure, say N.
 
-Radio network interfaces
+Wireless LAN (non-hamradio)
 CONFIG_NET_RADIO
-  Radio based interfaces for Linux. This includes amateur radio
-  (AX.25), support for wireless ethernet and other systems. Note that
-  the answer to this question won't directly affect the kernel: saying
-  N will just cause this configure script to skip all the questions
-  about radio interfaces. Some user-level drivers for scarab devices
-  which don't require special kernel support are available via ftp
-  (user: anonymous) from shadow.cabi.net. 
-  If unsure, say N.
-
-AX.25 network interfaces
-CONFIG_NET_HAM
-  Say Y here if you want support for a device that connects your Linux
-  box to your amateur radio (HAM). AX.25 is the protocol used for
-  digital traffic over amateur radio connections. You might want to
-  read the HAM-HOWTO and the AX25-HOWTO, both available via ftp (user:
-  anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
-  answer to this question won't directly affect the kernel: saying N
-  will just cause this configure script to skip all the questions
-  about amateur radio interfaces.
+  Support for wireless LAN's and everything having to do with radio,
+  but not with amateur radio. Note that the answer to this question
+  won't directly affect the kernel: saying N will just cause this
+  configure script to skip all the questions about radio
+  interfaces. Some user-level drivers for scarab devices which don't
+  require special kernel support are available via ftp (user:
+  anonymous) from shadow.cabi.net in /pub/Linux.
 
 PPP (point-to-point) support
 CONFIG_PPP
@@ -2758,7 +3104,7 @@ CONFIG_PPP
   otherwise you can't use it (not quite true any more: the free
   program SLiRP can emulate a PPP line if you just have a regular dial
   up shell account on some UNIX computer; get it via ftp (user:
-  anonymous) from sunsite.unc.edu:/pub/Linux/system/Network/serial/).
+  anonymous) from sunsite.unc.edu:/pub/Linux/system/network/serial/).
   To use PPP, you need an additional program called pppd as described
   in Documentation/networking/ppp.txt and in the PPP-HOWTO, available
   from sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you upgrade from an
@@ -2767,20 +3113,22 @@ CONFIG_PPP
   program which gives you almost full Internet connectivity if you
   have a regular dial up shell account on some Internet connected UNIX
   computer. Read
-  http://www.bart.nl/~patrickr/term-howto/Term-HOWTO.html). The PPP
-  option enlarges your kernel by about 16kB. This driver is also
-  available as a module ( = code which can be inserted in and removed
-  from the running kernel whenever you want). If you said Y to
-  "Version information on all symbols" above, then you cannot compile
-  the PPP driver into the kernel; you can then only compile it as a
-  module. The module will be called ppp.o. If you want to compile it
-  as a module, say M here and read Documentation/modules.txt as well
-  as Documentation/networking/net-modules.txt. Note that, no matter
-  what you do, the BSD compression code (used to compress the IP
-  packets sent over the serial line; has to be supported at the other
-  end as well) will always be compiled as a module; it is called
-  bsd_comp.o and will show up in the directory modules once you have
-  said "make modules". If unsure, say N.
+  http://www.bart.nl/~patrickr/term-howto/Term-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)). The PPP option enlarges your
+  kernel by about 16kB. This driver is also available as a module ( =
+  code which can be inserted in and removed from the running kernel
+  whenever you want). If you said Y to "Version information on all
+  symbols" above, then you cannot compile the PPP driver into the
+  kernel; you can then only compile it as a module. The module will be
+  called ppp.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. Note that, no matter what
+  you do, the BSD compression code (used to compress the IP packets
+  sent over the serial line; has to be supported at the other end as
+  well) will always be compiled as a module; it is called bsd_comp.o
+  and will show up in the directory modules once you have said "make
+  modules". If unsure, say N.
 
 Shortwave radio modem driver
 CONFIG_HFMODEM
@@ -2806,7 +3154,9 @@ STRIP (Metricom Starmode radio IP)
 CONFIG_STRIP
   Say Y if you have a Metricom radio and intend to use Starmode Radio
   IP.  STRIP is a radio protocol developed for the MosquitoNet project
-  (http://mosquitonet.stanford.edu/) to send Internet traffic using
+  (On the WWW at http://mosquitonet.stanford.edu/; to browse the WWW,
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape) to send Internet traffic using
   Metricom radios.  Metricom radios are small, battery powered,
   100kbit/sec packet radio transceivers, about the size and weight of
   a cellular telephone.  (You may also have heard them called
@@ -2821,6 +3171,26 @@ CONFIG_STRIP
   the running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called strip.o.
 
+Radio support
+CONFIG_MISC_RADIO
+  If you have a radio card (which enables your computer to receive
+  regular radio broadcasts), then you will want to say "y" here and
+  make a character device file (usually /dev/radio) with major number
+  10 and minor 152 using mknod ("man mknod").  And then, don't forget
+  to pick up some useful tools to use said device (you _might_ find
+  something at ftp.lmh.ox.ac.uk: /users/weejock/linux/, but I haven't
+  written anything too useful yet...)
+
+AIMSlab RadioTrack card
+CONFIG_RADIO_RTRACK
+  Choose Y here if you have one of these, and then fill in the port
+  address below.
+
+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.
+
 LAPB over Ethernet driver
 CONFIG_LAPBETHER
   This is a driver for a pseudo device (typically called /dev/lapb0)
@@ -2857,36 +3227,52 @@ CONFIG_SCC
   running kernel whenever you want), say M here and read
   Documentation/modules.txt. The module will be called scc.o.
 
+additional delay for PA0HZP OptoSCC compatible boards
+CONFIG_SCC_DELAY
+
+support for TRX that feedback the tx signal to rx
+CONFIG_SCC_TRXECHO
+###
+### Don't know what's going on here.
+###
+
 High-speed (DMA) SCC driver for AX.25
 CONFIG_DMASCC
-  This is a driver for high-speed SCC boards, i.e. those supporting
-  DMA on one port. Currently, only Ottawa PI/PI2 boards (see
-  http://hydra.carleton.ca/info/pi2.html) and Gracilis PackeTwin
-  boards (see http://www.paccomm.com/) are supported and detected
-  automatically. Multiple boards are operated simultaneously. If
-  you compile this driver as a module, it will be called dmascc.o.
-  If you don't give any parameter to the driver, all possible I/O
-  addresses are probed. This could irritate other devices that are
-  currently not in use. You may specify the list of addresses to be
-  probed by "dmascc=addr1,addr2,..." (when compiled into the kernel
-  image) or "io=addr1,addr2,..." (when loaded as a module).
-  The network interfaces will be called dmascc0 and dmascc1 for the
-  board detected first, dmascc2 and dmascc3 for the second one, and
-  so on. Before you configure each interface with ifconfig, you MUST
-  set certain parameters, such as channel access timing, clock mode,
-  and DMA channel. This is accomplished with a small utility program
-  called dmascc_cfg, which is part of the ax25-utils package.
-  Alternatively, you may download the utility from
+  This is a driver for high-speed SCC boards (used to connect your
+  computer to your amateur radio and send internet traffic over the
+  radio), i.e. those supporting DMA on one port. Currently, only
+  Ottawa PI/PI2 boards (see http://hydra.carleton.ca/info/pi2.html)
+  and Gracilis PackeTwin boards (see http://www.paccomm.com/; to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape) are supported and detected
+  automatically. If you have one of these cards, you can say Y here
+  and should read the HAM-HOWTO, available via ftp (user: anonymous)
+  in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  This driver operates multiple boards simultaneously. If you compile
+  this driver as a module, it will be called dmascc.o.  If you don't
+  give any parameter to the driver, all possible I/O addresses are
+  probed. This could irritate other devices that are currently not in
+  use. You may specify the list of addresses to be probed by
+  "dmascc=addr1,addr2,..." (when compiled into the kernel image) or
+  "io=addr1,addr2,..." (when loaded as a module).  The network
+  interfaces will be called dmascc0 and dmascc1 for the board detected
+  first, dmascc2 and dmascc3 for the second one, and so on. Before you
+  configure each interface with ifconfig, you MUST set certain
+  parameters, such as channel access timing, clock mode, and DMA
+  channel. This is accomplished with a small utility program called
+  dmascc_cfg, which is part of the ax25-utils package.  Alternatively,
+  you may download the utility from
   http://www.oevsv.at/~oe1kib/Linux.html.
 
 BAYCOM picpar and par96 driver for AX.25
 CONFIG_BAYCOM_PAR
-  This is a driver for Baycom style simple amateur radio
-  modems that connect to a parallel interface. The driver 
-  supports the picpar and par96 designs. To configure the
-  driver, use the sethdlc utility available in the standard
-  ax25 utilities package. For information on the modems, see
-  http://www.baycom.de and Documentation/networking/baycom.txt. If you
+  This is a driver for Baycom style simple amateur radio modems that
+  connect to a parallel interface. The driver supports the picpar and
+  par96 designs. To configure the driver, use the sethdlc utility
+  available in the standard ax25 utilities package. For information on
+  the modems, see http://www.baycom.de (to browse the WWW, you need to
+  have access to a machine on the Internet that has a program like
+  lynx or netscape) and Documentation/networking/baycom.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),
   say M here and read Documentation/modules.txt. This is
@@ -2895,45 +3281,51 @@ CONFIG_BAYCOM_PAR
 BAYCOM ser12 full duplex driver for AX.25
 CONFIG_BAYCOM_SER_FDX
   This is one of two drivers for Baycom style simple amateur radio
-  modems that connect to a serial interface. The driver supports
-  the ser12 design in full duplex mode. In addition, it allows the
+  modems that connect to a serial interface. The driver supports the
+  ser12 design in full duplex mode. In addition, it allows the
   baudrate to be set between 300 and 4800 baud (however not all modems
-  support all baudrates). This is the preferred driver. baycom_ser_hdx.o
-  is the old driver and still provided in case this driver does not work
-  with your serial interface chip. To configure the driver, use the
-  sethdlc utility available in the standard ax25 utilities package. 
-  For information on the modems, see http://www.baycom.de and
-  Documentation/networking/baycom.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),
-  say M here and read Documentation/modules.txt. This is
-  recommended. The module will be called baycom_ser_fdx.o.
+  support all baudrates). This is the preferred driver. The next
+  driver, "BAYCOM ser12 half duplex driver for AX.25" is the old
+  driver and still provided in case this driver does not work with
+  your serial interface chip. To configure the driver, use the sethdlc
+  utility available in the standard ax25 utilities package.  For
+  information on the modems, see http://www.baycom.de (to browse the
+  WWW, you need to have access to a machine on the Internet that has a
+  program like lynx or netscape) and
+  Documentation/networking/baycom.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), say M here and read
+  Documentation/modules.txt. This is recommended. The module will be
+  called baycom_ser_fdx.o.
 
 BAYCOM ser12 half duplex driver for AX.25
 CONFIG_BAYCOM_SER_HDX
   This is one of two drivers for Baycom style simple amateur radio
-  modems that connect to a serial interface. The driver supports
-  the ser12 design in full duplex mode. This is the old driver. 
-  It is still provided in case your serial interface chip does
-  not work with the full duplex driver. This driver is depreciated.
-  To configure the driver, use the sethdlc utility available
-  in the standard ax25 utilities package. For information
-  on the modems, see http://www.baycom.de and
-  Documentation/networking/baycom.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),
-  say M here and read Documentation/modules.txt. This is
-  recommended. The module will be called baycom_ser_hdx.o.
+  modems that connect to a serial interface. The driver supports the
+  ser12 design in full duplex mode. This is the old driver.  It is
+  still provided in case your serial interface chip does not work with
+  the full duplex driver. This driver is depreciated.  To configure
+  the driver, use the sethdlc utility available in the standard ax25
+  utilities package. For information on the modems, see
+  http://www.baycom.de (to browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or netscape)
+  and Documentation/networking/baycom.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), say M here and read
+  Documentation/modules.txt. This is recommended. The module will be
+  called baycom_ser_hdx.o.
 
 Soundcard modem driver for AX.25
 CONFIG_SOUNDMODEM
   This experimental driver allows a standard SoundBlaster or
   WindowsSoundSystem compatible soundcard to be used as a packet radio
-  modem, to send digital traffic over amateur radio. To configure the
-  driver, use the sethdlc, smdiag and smmixer utilities available in
-  the standard ax25 utilities package. For information on how to key
-  the transmitter, see
-  http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html and
+  modem (NOT as a telephone modem!), to send digital traffic over
+  amateur radio. To configure the driver, use the sethdlc, smdiag and
+  smmixer utilities available in the standard ax25 utilities
+  package. For information on how to key the transmitter, see
+  http://www.ife.ee.ethz.ch/~sailer/pcf/ptt_circ/ptt.html (to browse
+  the WWW, you need to have access to a machine on the Internet that
+  has a program like lynx or netscape) and
   Documentation/networking/soundmodem.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), say M here and read
@@ -3015,26 +3407,6 @@ CONFIG_SOUNDMODEM_FSK9600
   can only use one protocol at a time, depending on what the other end
   can understand).
 
-Shortwave radio modem driver
-CONFIG_HFMODEM
-  This experimental driver is used by a package (to be released)
-  that implements the shortwave radio protocols RTTY, Sitor (Amtor),
-  Pactor 1 and GTOR using a standard PC soundcard. If unsure,
-  say N.
-
-Shortwave radio modem driver support for SoundBlaster and compatible cards
-CONFIG_HFMODEM_SBC
-  This option enables the hfmodem driver to use SoundBlaster and
-  compatible cards. It requires a 16bit capable card, i.e.
-  SB16 or better, or ESS1688 or newer.
-
-Shortwave radio modem driver support for WSS and Crystal cards
-CONFIG_HFMODEM_WSS
-  This option enables the hfmodem driver to use WindowsSoundSystem
-  compatible cards. These cards feature a codec chip from either
-  Analog Devices (such as AD1848, AD1845, AD1812) or Crystal
-  Semiconductors (such as CS4248, CS423x).
-
 Serial port KISS driver for AX.25
 CONFIG_MKISS
   KISS is the protocol used to send IP traffic over AX.25 radio
@@ -3049,28 +3421,31 @@ CONFIG_MKISS
 
 PLIP (parallel port) support
 CONFIG_PLIP
-  PLIP (Parallel Line Internet Protocol) is used to create a mini
-  network consisting of two (or, rarely, more) local machines. The
-  parallel ports (the connectors at the computers with 25 holes) are
-  connected using "null printer" or "Turbo Laplink" cables which can
-  transmit 4 bits at a time or using special PLIP cables, to be used
-  on bidirectional parallel ports only, which can transmit 8 bits at a
-  time (you can find the wiring of these cables in
-  drivers/net/README?.plip). The cables can be up to 15m long. This
-  works also if one of the machines runs DOS/Windows and has some PLIP
-  software installed, e.g. the Crynwr PLIP packet driver
-  (http://sunsite.cnam.fr/packages/Telnet/PC/msdos/misc/pktdrvr.txt)
-  and winsock or NCSA's telnet.  If you want to use this, say Y and
-  read the PLIP mini-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini as well as the
-  NET-2-HOWTO in sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the
-  PLIP protocol was changed and this PLIP driver won't work together
-  with the PLIP support in Linux versions 1.0.x.  This option enlarges
-  your kernel by about 8kB. If you want to compile this as a module (
-  = code which can be inserted in and removed from the running kernel
-  whenever you want), say M here and read Documentation/modules.txt as
-  well as Documentation/networking/net-modules.txt. The module will be
-  called plip.o.
+  PLIP (Parallel Line Internet Protocol) is used to create a
+  reasonably fast mini network consisting of two (or, rarely, more)
+  local machines. The PLIP driver has two modes, mode 0 and mode
+  1. The parallel ports (the connectors at the computers with 25
+  holes) are connected with "null printer" or "Turbo Laplink" cables
+  which can transmit 4 bits at a time (mode 0) or with special PLIP
+  cables, to be used on bidirectional parallel ports only, which can
+  transmit 8 bits at a time (mode 1); you can find the wiring of these
+  cables in Documentation/networking/PLIP.txt. The cables can be up to
+  15m long. Mode 0 works also if one of the machines runs DOS/Windows
+  and has some PLIP software installed, e.g. the Crynwr PLIP packet
+  driver (http://www.kanren.net/pktdrvr-info.html; to browse the WWW,
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape) and winsock or NCSA's telnet.  If you
+  want to use PLIP, say Y and read the PLIP mini-HOWTO, available via
+  ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini
+  as well as the NET-2-HOWTO in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that the PLIP protocol
+  was changed and this PLIP driver won't work together with the PLIP
+  support in Linux versions 1.0.x.  This option enlarges your kernel
+  by about 8kB. If you want to compile this as a module (= code which
+  can be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. The module will be called
+  plip.o. If unsure, say Y or M, in case you buy a laptop later.
 
 EQL (serial line load balancing) support
 CONFIG_EQUALIZER
@@ -3081,11 +3456,32 @@ CONFIG_EQUALIZER
   like one double speed connection using this driver. Naturally, this
   has to be supported at the other end as well, either with a similar
   EQL Linux driver or with a Livingston Portmaster 2e. Say Y if you
-  want this and read drivers/net/README.eql. 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 will be
-  called eql.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt.
+  want this and read Documentation/networking/eql.txt. 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 will
+  be called eql.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt. If unsure, say N.
+
+Ethertap network tap
+CONFIG_ETHERTAP
+  If you say Y here (and have said Y to "Kernel/User network link
+  driver", above) and create a character special file /dev/tap0 with
+  major number 36 and minor number 16 using mknod ("man mknod"), you
+  will be able to have a user space program read and write raw
+  ethernet frames from/to that special file. tap0 can be configured
+  with ifconfig and route like any other ethernet device but it is not
+  connected to any physical LAN; everything written by the user to
+  /dev/tap0 is treated by the kernel as if it had come in from a LAN
+  to the device tap0; everything the kernel wants to send out over the
+  device tap0 can instead be read by the user from /dev/tap0: the user
+  mode program replaces the LAN that would be attached to an ordinary
+  ethernet device.  Please read the file
+  Documentation/networking/ethertap.txt for more information.  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 will be called ethertap.o. If you want to compile it as a
+  module, say M here and read Documentation/modules.txt. If you don't
+  know what to use this for, you don't need it.
 
 Frame Relay (DLCI) support
 CONFIG_DLCI
@@ -3096,16 +3492,15 @@ CONFIG_DLCI
   network, usually at the phone company) can carry several logical
   point-to-point connections to other computers connected to the frame
   relay network. For a general explanation of the protocol, check out
-  http://frame-relay.indiana.edu/4000/4000index.html on the WWW. (To
-  browse the WWW, you need to have access to a machine on the Internet
-  that has a program like lynx or netscape.) To use frame relay, you
-  need supporting hardware (FRAD) and certain programs from the
-  net-tools package as explained in
-  Documentation/networking/framerelay.txt. This driver is also
+  http://www.frforum.com/ on the WWW. (To browse the WWW, you need to
+  have access to a machine on the Internet that has a program like
+  lynx or netscape.) To use frame relay, you need supporting hardware
+  (FRAD) and certain programs from the net-tools package as explained
+  in Documentation/networking/framerelay.txt. 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 will be
-  called dlci.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt.
+  called dlci.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt.
 
 Max open DLCI
 CONFIG_DLCI_COUNT
@@ -3133,13 +3528,13 @@ CONFIG_SDLA
 
 WAN Router
 CONFIG_WAN_ROUTER
-      Wide Area Networks (WANs), such as X.25, frame relay and leased
+  Wide Area Networks (WANs), such as X.25, frame relay and leased
   lines, are used to interconnect Local Area Networks (LANs) over vast
   distances with data transfer rates significantly higher than those
   achievable with commonly used asynchronous modem connections.
   Usually, a quite expensive external device called `WAN router' is
   needed to connect to a WAN.
-      As an alternative, WAN routing can be built into the Linux
+  As an alternative, WAN routing can be built into the Linux
   kernel.  With relatively inexpensive WAN interface cards available
   on the market, a perfectly usable router can be built for less than
   half the price of an external router.  If you have one of those
@@ -3148,38 +3543,147 @@ CONFIG_WAN_ROUTER
   need a wan-tools package available via FTP (user: anonymous) from
   ftp.sangoma.com.  Read Documentation/networking/wan-router.txt for
   more information.
-      WAN routing is always built as a module ( = code which can be
+  WAN routing is always built as a module ( = code which can be
   inserted in and removed from the running kernel whenever you want).
   The module is called wanrouter.o.  For general information about 
   modules read Documentation/modules.txt.
 
+CPU is too slow to handle full bandwidth
+CONFIG_CPU_IS_SLOW
+###
+### How to know when the CPU is too slow?
+###
+
+QoS and/or fair queueing
+CONFIG_NET_SCHED
+  When the kernel has several packets to send out over the network
+  devices, it has to make a decision which one to send first. This is
+  especially important if some of the network devices are real time
+  devices that need a certain minimum data flow rate.  There are
+  several different algorithms how to do this "fairly"; they are
+  called packet schedulers. You can attach different schedulers to
+  different network devices. If you want to stick to the default
+  scheduling algorithm, say N here. If you want to experiment with a
+  couple of different algorithms, say Y. The available schedulers are
+  listed in the following questions; you can say Y to as many as you
+  like.  If unsure, say N now.
+
+CBQ packet scheduler
+CONFIG_NET_SCH_CBQ
+  Say Y here if you want to use the Class-Based Queueing (CBQ) packet
+  scheduling algorithm for some of your network devices. This
+  algorithm classifies the waiting packets into a tree-like hierarchy
+  of classes; the leaves of this tree are in turn scheduled by
+  separate algorithms (called "disciplines" in this context) which you
+  can choose below from among the "auxiliary disciplines".  See the top
+  of net/sched/sch_cbq.c for references about the CBQ algorithm.
+  This code is also available as a
+  module called sch_cbq.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.
+
+CSZ packet scheduler
+CONFIG_NET_SCH_CSZ
+  Say Y here if you want to use the Clark-Shenker-Zhang (CSZ) packet
+  scheduling algorithm for some of your network devices. At the
+  moment, this is the only algorithm that can guarantee service for
+  real-time applications (see the top of net/sched/sch_csz.c for
+  details and references about the algorithm). This code is also
+  available as a module called sch_csz.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.
+
+RED queueing discipline
+CONFIG_NET_SCH_RED
+  Say Y here if you want to use the Random Early Detection (RED)
+  packet scheduling algorithm for some of your network devices (see
+  the top of net/sched/sch_red.c for details and references about the
+  algorithm). This code is also available as a module called sch_red.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.
+
+SFQ queueing discipline
+CONFIG_NET_SCH_SFQ
+  Say Y here if you want to use the Stochastic Fairness Queueing (SFQ)
+  packet scheduling algorithm for some of your network devices or as a
+  leaf discipline for the CBQ scheduling algorithm (see the top of
+  net/sched/sch_sfq.c for details and references about the SFQ
+  algorithm). This code is also available as a module called sch_sfq.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.
+
+auxiliary TBF queue
+CONFIG_NET_SCH_TBF
+  Say Y here if you want to use the Simple Token Bucket Filter (TBF)
+  packet scheduling algorithm for some of your network devices or as a
+  leaf discipline for the CBQ scheduling algorithm (see the top of
+  net/sched/sch_tbf.c for a description of the TBF algorithm). This code
+  is also available as a module called sch_tbf.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.
+
+auxiliary FIFO queue
+CONFIG_NET_SCH_PFIFO
+  Say Y here if you want to use a simple FIFO (first in - first out)
+  packet "scheduler" for some of your network devices or as a leaf
+  discipline for the CBQ scheduling algorithm. This code is also
+  available as a module called sch_fifo.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.
+
+auxiliary PRIO queue
+CONFIG_NET_SCH_PRIO
+  Say Y here if you want to use an n-band priority queue packet
+  "scheduler" for some of your network devices or as a leaf discipline
+  for the CBQ scheduling algorithm. This code is also available as a
+  module called sch_prio.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.
+###
+### what user level programs are needed to administrate these packet 
+### schedulers?
+###
+
 WAN Drivers
 CONFIG_WAN_DRIVERS
-      Say 'Y' to this option if you are planning to use your Linux box
-  as a WAN 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 WAN drivers currently available.  For more information, read
-  Documentation/networking/wan-router.txt.
+  Say Y to this option if you are planning to use your Linux 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 WAN drivers currently available.
+  For more information, read
+  Documentation/networking/wan-router.txt. Note that the answer to
+  this question won't directly affect the kernel: saying N will just
+  cause this configure script to skip all the questions about WAN
+  drivers. If unsure, say N.
 
 Sangoma WANPIPE(tm) multiprotocol cards
 CONFIG_VENDOR_SANGOMA
-      WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com)
-  is a family of intelligent multiprotocol WAN adapters with data
-  transfer rates up to T1 (1.544 Mbps).  They are also known as
-  Synchronous Data Link Adapters (SDLA) and designated S502E(A), S503
-  or S508. These cards support the X.25, Frame Relay, and PPP
-  protocols. If you have one or more of these cards, say 'Y' to this
-  option.  The next questions will ask you about the protocols you
-  want the driver to support. The driver will be compiled as a module
-  ( = code which can be inserted in and removed from the running
-  kernel whenever you want).  The module will be called wanpipe.o.
-  For general information about modules read
+  WANPIPE from Sangoma Technologies Inc. (http://www.sangoma.com; to
+  browse the WWW, you need to have access to a machine on the Internet
+  that has a program like lynx or netscape) is a family of intelligent
+  multiprotocol WAN adapters with data transfer rates up to T1 (1.544
+  Mbps).  They are also known as Synchronous Data Link Adapters (SDLA)
+  and designated S502E(A), S503 or S508. These cards support the X.25,
+  Frame Relay, and PPP protocols. If you have one or more of these
+  cards, say Y to this option and read
+  Documentation/networking/wanpipe.txt.  The next questions will ask
+  you about the protocols you want the driver to support. The driver
+  will be compiled as a module ( = code which can be inserted in and
+  removed from the running kernel whenever you want).  The module will
+  be called wanpipe.o.  For general information about modules read
   Documentation/modules.txt.
 
 Maximum number of cards
 CONFIG_WANPIPE_CARDS
-      Enter number of WANPIPE adapters installed in your machine.  The
+  Enter number of WANPIPE adapters installed in your machine.  The
   driver can support up to 8 cards.  You may enter more than you
   actually have if you plan to add more cards in the future without
   re-compiling the driver, but remember that in this case you'll waste
@@ -3187,22 +3691,26 @@ CONFIG_WANPIPE_CARDS
 
 WANPIPE X.25 support
 CONFIG_WANPIPE_X25
-      Say 'Y' to this option, if you are planning to connect a WANPIPE
-  card to an X.25 network.  If you say 'N', the X.25 support will not
-  be included in the driver (saves about 16K of kernel memory).
+  Say Y to this option, if you are planning to connect a WANPIPE card
+  to an X.25 network. You should then also have said Y to "CCITT X.25
+  Packet Layer" and "LAPB Data Link Driver", above. If you say N, the
+  X.25 support will not be included in the driver (saves about 16K of
+  kernel memory).
 
 WANPIPE Frame Relay support
 CONFIG_WANPIPE_FR
-      Say 'Y' to this option, if you are planning to connect a WANPIPE
-  card to a frame relay network.  If you say 'N', the frame relay
+  Say Y to this option, if you are planning to connect a WANPIPE card
+  to a frame relay network. You should then also have said Y to "Frame
+  Relay (DLCI) support", above. If you say N, the frame relay
   support will not be included in the driver (saves about 16K of
   kernel memory).
 
 WANPIPE PPP support
 CONFIG_WANPIPE_PPP
-      Say 'Y' to this option, if you are planning to connect a WANPIPE
-  card to a leased line using Point-to-Point protocol (PPP).  If you
-  say 'N', the PPP support will not be included in the driver (saves
+  Say Y to this option, if you are planning to connect a WANPIPE card
+  to a leased line using Point-to-Point protocol (PPP). You should
+  then also have said Y to "PPP (point-to-point) support", above. If
+  you say N, the PPP support will not be included in the driver (saves
   about 16K of kernel memory).
 
 Sun LANCE Ethernet support
@@ -3246,10 +3754,7 @@ CONFIG_NET_VENDOR_SMC
   the answer to this question doesn't directly affect the kernel:
   saying N will just cause this configure script to skip all the
   questions about Western Digital cards. If you say Y, you will be
-  asked for your specific card in the following questions. If you plan
-  to use more than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  asked for your specific card in the following questions.
 
 WD80*3 support
 CONFIG_WD80x3
@@ -3287,24 +3792,80 @@ CONFIG_SMC9194
   This is support for the SMC9xxx based Ethernet cards.  Choose this
   option if you have a DELL laptop with the docking station, or
   another SMC9192/9194 based chipset.  Say Y if you want it compiled
-  into the kernel, and read the the file drivers/net/README.smc9 and
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  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 will be
-  called smc9194.o. If you want to compile it as a module, say M here
-  and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more
-  than one network card under linux, read the
+  into the kernel, and read the the file
+  Documentation/networking/smc9.txt and the Ethernet-HOWTO, available
+  via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.
+  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 will be called smc9194.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt. If you plan to use
+  more than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
-AMD LANCE and PCnet (AT1500 and NE2100) support
-CONFIG_LANCE
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Some LinkSys cards are of
-  this type. If you plan to use more than one network card under
+Racal-Interlan (Micom) NI cards
+CONFIG_NET_VENDOR_RACAL
+  If you have a network (ethernet) card belonging to this class, such
+  as the NI5010, NI5210 or NI6210, say Y and read the Ethernet-HOWTO,
+  available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
+  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. Note that
+  the answer to this question doesn't directly affect the kernel:
+  saying N will just cause this configure script to skip all the
+  questions about NI cards. If you say Y, you will be asked for your
+  specific card in the following questions.
+
+NI5010 support
+CONFIG_NI5010
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Note that this is still
+  experimental code. 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 will be called
+  ni5010.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt as well as
+xIO  Documentation/networking/net-modules.txt. If you plan to use more
+  than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
+NI5210 support
+CONFIG_NI52
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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 will be called
+  ni52.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. If you plan to use more
+  than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
+NI6510 support
+CONFIG_NI65
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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 will be called
+  ni65.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt. If you plan to use more
+  than one network card under linux, read the
+  Multiple-Ethernet-mini-HOWTO, available from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
+AMD LANCE and PCnet (AT1500 and NE2100) support
+CONFIG_LANCE
+  If you have a network (ethernet) card of this type, say Y and read
+  the Ethernet-HOWTO, available via ftp (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO. Some LinkSys cards are of
+  this type. If you plan to use more than one network card under
   linux, read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
@@ -3444,7 +4005,7 @@ CONFIG_ARCNET
   (arguably) beautiful poetry in Documentation/networking/arcnet.txt.
   You need both this driver, and the driver for the particular ARCnet
   chipset of your card. If you don't know, then it's probably a 
-  COM90xx type card, so say Y (or M) to ARCnet COM90xx chipset support
+  COM90xx type card, so say Y (or M) to "ARCnet COM90xx chipset support"
   below.
   You might also want to have a look at the Ethernet-HOWTO, available
   via ftp (user: anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO
@@ -3457,7 +4018,7 @@ CONFIG_ARCNET
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-  
+
 Enable arc0e (ARCnet "ether-encap" packet format)
 CONFIG_ARCNET_ETH
   This allows you to use "ethernet encapsulation" with your ARCnet
@@ -3483,30 +4044,50 @@ CONFIG_ARCNET_1051
   documentation in Documentation/networking/arcnet.txt for more
   information about using arc0e and arc0s.
 
-ARCnet COM90xx chipset support
+ARCnet COM90xx (normal) chipset driver
 CONFIG_ARCNET_COM90xx
-  This is the chipset driver for the standard COM90xx cards. If you always
-  used the old arcnet driver without knowing what type of card you had, 
-  this is probably the one for you.
+  This is the chipset driver for the standard COM90xx cards. If you
+  have always used the old arcnet driver without knowing what type of
+  card you had, this is probably the one for you. 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 will be
+  called com90xx.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
 
-ARCnet COM90xx IO mapped mode chipset support
-CONFIG_ARCNET_COM90xxIO
-  This is the chipset driver for the COM90xx cards, using them in IO-mapped
-  mode instead of memory-mapped mode. This is slower than the normal driver.
-  Only use it if your card doesn't support shared memory.
+ARCnet COM90xx (IO mapped) chipset driver
+CONFIG_ARCNET_COM90x
+  This is the chipset driver for the COM90xx cards, using them in
+  IO-mapped mode instead of memory-mapped mode. This is slower than
+  the normal driver.  Only use it if your card doesn't support shared
+  memory. 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 will be called com90io.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt.
 
-ARCnet RIM I chipset support
+ARCnet COM90xx (RIM I) chipset driver
 CONFIG_ARCNET_RIM_I
-  This is yet another chipset driver for the COM90xx cards, but this time
-  only using memory-mapped mode, and no IO ports at all. This driver is
-  completely untested, so if you have one of these cards, please mail 
-  dwmw2@cam.ac.uk, especially if it works!
+  This is yet another chipset driver for the COM90xx cards, but this
+  time only using memory-mapped mode, and no IO ports at all. This
+  driver is completely untested, so if you have one of these cards,
+  please mail dwmw2@cam.ac.uk, especially if it works!
+  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 will be called arc-rimi.o. If you want to compile
+  it as a module, say M here and read Documentation/modules.txt as
+  well as Documentation/networking/net-modules.txt.
 
-ARCnet COM20020 chipset support
+ARCnet COM20020 chipset driver
 CONFIG_ARCNET_COM20020
-  This is the driver for the new COM20020 chipset. It supports such things
-  as promiscuous mode, so packet sniffing is possible, and extra diagnostic
-  information.
+  This is the driver for the new COM20020 chipset. It supports such
+  things as promiscuous mode, so packet sniffing is possible, and
+  extra diagnostic information. 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 will be called
+  com20020.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt as well as
+  Documentation/networking/net-modules.txt.
 
 Cabletron E21xx support
 CONFIG_E2100
@@ -3553,12 +4134,13 @@ CONFIG_DEPCA
 EtherWorks 3 support
 CONFIG_EWRK3
   This driver supports the DE203, DE204 and DE205 network (ethernet)
-  cards. If this is for you, say Y and read drivers/net/README.ewrk3
-  in the kernel source as well as the Ethernet-HOWTO, available via
-  ftp (user: anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO.
-  If you want to compile this as a module ( = code which can be
-  inserted in and removed from the running kernel whenever you want),
-  say M here and read Documentation/modules.txt as well as
+  cards. If this is for you, say Y and read
+  Documentation/networking/ewrk3.txt in the kernel source as well as
+  the Ethernet-HOWTO, available via ftp (user: anonymous) from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you want to compile this
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. The module will be called
   ewrk3.o. If you plan to use more than one network card under linux,
   read the Multiple-Ethernet-mini-HOWTO, available from
@@ -3633,40 +4215,6 @@ CONFIG_EEXPRESS
   linux, read the Multiple-Ethernet-mini-HOWTO, available from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
 
-NI5010 support
-CONFIG_NI5010
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you plan to use more than
-  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
-  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-  Note that this is still experimental code. If you use this driver,
-  please contact the authors to join the development team.
-
-NI5210 support
-CONFIG_NI52
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. 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 will be called
-  ni52.o. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. If you plan to use more than
-  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
-  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-
-NI6510 support
-CONFIG_NI65
-  If you have a network (ethernet) card of this type, say Y and read
-  the Ethernet-HOWTO, available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO. If you want to compile it as
-  a module, say M here and read Documentation/modules.txt as well as
-  Documentation/networking/net-modules.txt. The module will be called
-  ni65.o. If you plan to use more than one network card under linux,
-  read the Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
-
 AT&T WaveLAN & DEC RoamAbout DS support
 CONFIG_WAVELAN
   The Lucent Wavelan (formerly NCR and AT&T ; or DEC RoamAbout DS) is
@@ -3678,8 +4226,9 @@ CONFIG_WAVELAN
   If you want to use a card of this type under Linux, say Y and read
   the Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO. Some more specific
-  information is contained in drivers/net/README.wavelan. You will
-  also need the wireless tools package available from
+  information is contained in
+  Documentation/networking/wavelan.txt. You will also need the
+  wireless tools package available from
   ftp://ftp.inka.de/pub/comp/Linux/networking/NetTools/contrib/.
   This driver is also available as a module ( = code which can be
   inserted in and removed from the running kernel whenever you
@@ -3759,18 +4308,18 @@ CONFIG_NET_EISA
   This is another class of network cards which attach directly to the
   bus. If you have one of those, say Y and read the Ethernet-HOWTO,
   available via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO; if you are unsure, say
-  Y. Note that the answer to this question doesn't directly affect the
-  kernel: saying N will just cause this configure script to skip all
-  the questions about this class of network cards. If you say Y, you
-  will be asked for your specific card in the following questions.  If
-  you plan to use more than one network card under linux, read the
-  Multiple-Ethernet-mini-HOWTO, available from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you plan to use more than
+  one network card under linux, read the Multiple-Ethernet-mini-HOWTO,
+  available from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. If you
+  are unsure, say Y. Note that the answer to this question doesn't
+  directly affect the kernel: saying N will just cause this configure
+  script to skip all the questions about this class of network
+  cards. If you say Y, you will be asked for your specific card in the
+  following questions.
 
 AMD PCnet32 (VLB and PCI) support
 CONFIG_PCNET32
-  if you have a PCnet32 or PCnetPCI based network (ethernet) card, say
+  If you have a PCnet32 or PCnetPCI based network (ethernet) card, say
   Y here and read the Ethernet-HOWTO, available via ftp (user:
   anonymous) in sunsite.unc.edu:/pub/Linux/docs/HOWTO.  If you plan to
   use more than one network card under linux, read the
@@ -3825,11 +4374,11 @@ CONFIG_DE4X5
   models. If you have a network card of this type, say Y and read the
   Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  More specific information is
-  contained in drivers/net/README.de4x5. 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 will be called
-  de4x5.o. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt as well as
+  contained in Documentation/networking/de4x5.txt. 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 will be
+  called de4x5.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
@@ -3860,11 +4409,11 @@ CONFIG_DGRS
   models. If you have a network card of this type, say Y and read the
   Ethernet-HOWTO, available via ftp (user: anonymous) in
   sunsite.unc.edu:/pub/Linux/docs/HOWTO.  More specific information is
-  contained in drivers/net/README.dgrs. 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 will be called
-  dgrs.o. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt as well as
+  contained in Documentation/networking/dgrs.txt. 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 will be
+  called dgrs.o. If you want to compile it as a module, say M here and
+  read Documentation/modules.txt as well as
   Documentation/networking/net-modules.txt. If you plan to use more
   than one network card under linux, read the
   Multiple-Ethernet-mini-HOWTO, available from
@@ -3948,8 +4497,8 @@ CONFIG_ATP
 D-Link DE600 pocket adapter support
 CONFIG_DE600
   This is a network (ethernet) device which attaches to your parallel
-  port. Read drivers/net/README.DLINK as well as the Ethernet-HOWTO,
-  available via ftp (user: anonymous) from
+  port. Read Documentation/networking/DLINK.txt as well as the
+  Ethernet-HOWTO, available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. It is
   possible to have several devices share a single parallel port and it
   is safe to compile the corresponding drivers into the kernel. If you
@@ -3963,8 +4512,8 @@ CONFIG_DE600
 D-Link DE620 pocket adapter support
 CONFIG_DE620
   This is a network (ethernet) device which attaches to your parallel
-  port. Read drivers/net/README.DLINK as well as the Ethernet-HOWTO,
-  available via ftp (user: anonymous) from
+  port. Read Documentation/networking/DLINK.txt as well as the
+  Ethernet-HOWTO, available via ftp (user: anonymous) from
   sunsite.unc.edu:/pub/Linux/docs/HOWTO if you want to use this. It is
   possible to have several devices share a single parallel port and it
   is safe to compile the corresponding drivers into the kernel. If you
@@ -3974,7 +4523,7 @@ CONFIG_DE620
   will be called de620.o. If you plan to use more than one network
   card under linux, read the Multiple-Ethernet-mini-HOWTO, available
   from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+
 Token Ring driver support
 CONFIG_TR
   Token Ring is IBM's way of communication on a local network; the
@@ -4031,9 +4580,9 @@ CONFIG_CD_NO_IDESCSI
   For each of these drivers, a file Documentation/cdrom/<driver_name>
   exists. Especially in cases where you do not know exactly which kind
   of drive you have you should read there.
-  Most of these drivers use a file drivers/cdrom/<driver_name>.h where
-  you can define your interface parameters and switch some internal
-  goodies.
+  Most of these drivers use a file drivers/cdrom/<driver_name>.h
+  where you can define your interface parameters and switch some
+  internal goodies.
   All these CDROM drivers are also usable as a module (= code which can
   be inserted in and removed from the running kernel whenever you want).
   If you want to compile them as module, say M instead of Y and read
@@ -4049,7 +4598,7 @@ CONFIG_CDU31A
   will not be auto detected by the kernel at boot time; you have to
   provide the interface address as an option to the kernel at boot
   time as described in Documentation/cdrom/cdu31a or fill in your
-  parameters into linux/drivers/cdrom/cdu31a.c. Try "man bootparam" or
+  parameters into drivers/cdrom/cdu31a.c. Try "man bootparam" or
   see the documentation of your boot loader (lilo or loadlin) about
   how to pass options to the kernel. The lilo procedure is also
   explained in the SCSI-HOWTO. If you say Y here, you should also say
@@ -4072,7 +4621,7 @@ CONFIG_MCD
   (PhotoCDs).  There is a new driver (next question) which can do
   this. If you want that one, say N here.
   If the driver doesn't work out of the box, you might want to have a
-  look at linux/drivers/cdrom/mcd.h.  If you say Y here, you should
+  look at drivers/cdrom/mcd.h.  If you say Y here, you should
   also say Y to "ISO9660 cdrom filesystem support" below, because
   that's the filesystem used on CDROMs. Please also read the file
   Documentation/cdrom/mcd. This driver is also available as a module (
@@ -4116,7 +4665,7 @@ CONFIG_SBPCD
   are not sure, but can consume some time during the boot process if
   none of the supported drives gets found.
   Once your drive got found, you should enter the reported parameters 
-  into linux/drivers/cdrom/sbpcd.h and set "DISTRIBUTION 0" there.
+  into drivers/cdrom/sbpcd.h and set "DISTRIBUTION 0" there.
   This driver can support up to four CDROM interface cards, and each
   card can support up to four CDROM drives; if you say Y here, you
   will be asked how many controllers you have. If compiled as a
@@ -4135,7 +4684,7 @@ CONFIG_SBPCD2
   Say Y here only if you have two CDROM controller boards of this type
   (usually only if you have more than four drives). You should enter
   the parameters for the second, third and fourth interface card into
-  linux/drivers/cdrom/sbpcd.h before compiling the new kernel. Read
+  linux/include/linux/sbpcd.h before compiling the new kernel. Read
   the file Documentation/cdrom/sbpcd.
 
 Aztech/Orchid/Okano/Wearnes/TXC/CyDROM  CDROM support
@@ -4167,29 +4716,14 @@ Goldstar R420 CDROM support
 CONFIG_GSCD
   If this is your CDROM drive, say Y here.  As described in
   linux/Documentation/cdrom/gscd, you might have to change a setting
-  in the file linux/drivers/cdrom/gscd.h before compiling the kernel. 
-  Please read the file Documentation/cdrom/gscd. If you say Y here, 
-  you should also say Y to "ISO9660 cdrom filesystem support" below,
-  because that's the filesystem used on CDROMs. 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 will be
-  called gscd.o. If you want to compile it as a module, say M here and
-  read Documentation/modules.txt.
-
-MicroSolutions backpack CDROM support
-CONFIG_BPCD
-  MicroSolutions backpack CDROM is an external drive that connects to
-  the parallel port.  This driver supports model 164550 (and perhaps
-  other models).  Say Y if you have one of these, and read the file
-  Documentation/cdrom/bpcd. If you say Y here, you should also say Y
-  to "ISO9660 cdrom filesystem support" below, because that's the
-  filesystem used on CDROMs. It is possible for several devices to
-  share a parallel port and it is safe to compile the corresponding
-  drivers all into 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 will be called
-  bpcd.o. If you want to compile it as a module, say M here and read
-  Documentation/modules.txt.
+  in the file linux/drivers/cdrom/gscd.h before compiling the
+  kernel. Please read the file Documentation/cdrom/gscd. If you say Y
+  here, you should also say Y to "ISO9660 cdrom filesystem support"
+  below, because that's the filesystem used on CDROMs. 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 will
+  be called gscd.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Philips/LMS CM206 CDROM support
 CONFIG_CM206
@@ -4263,10 +4797,10 @@ CONFIG_QUOTA
   If you say Y here, you will be able to set per user limits for disk
   usage (also called diskquotas). Currently, it works only for the
   ext2 filesystem. You need additional software in order to use quota
-  support; it is available via ftp (user: anonymous) from
-  ftp.funet.fi/pub/Linux/kernel/src/subsystems/quota/. Probably the
-  quota support is only useful for multi user systems. If unsure, say
-  N.
+  support; for details, read the Quota mini-HOWTO, available via ftp
+  (user: anonymous) in
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini. Probably the quota
+  support is only useful for multi user systems. If unsure, say N.
 
 Online mirror support
 CONFIG_OMIRR
@@ -4461,6 +4995,33 @@ CONFIG_EXT2_FS
   compiled as a module, and so this could be dangerous. Most everyone
   wants to say Y here.
 
+ISO9660 cdrom filesystem support
+CONFIG_ISO9660_FS
+  This is the standard filesystem used on CDROMs. It was previously
+  known as "High Sierra Filesystem" and is called "hsfs" on other Unix
+  systems. The so-called Rock-Ridge extensions which allow for long
+  Unix filenames and symbolic links are also supported by this
+  driver. If you have a CDROM drive and want to do more with it than
+  just listen to audio CDs and watch its LEDs, say Y (and read
+  Documentation/filesystems/isofs.txt and the CDROM-HOWTO, available
+  via ftp (user: anonymous) from
+  sunsite.unc.edu:/pub/Linux/docs/HOWTO), thereby enlarging your
+  kernel by about 27 kB; otherwise say N.  If you want to compile this
+  as a module ( = code which can be inserted in and removed from the
+  running kernel whenever you want), say M here and read
+  Documentation/modules.txt. The module will be called isofs.o.
+
+Microsoft Joliet cdrom extensions
+CONFIG_JOLIET
+  Joliet is a Microsoft extension for the ISO9660 CDROM filesystem
+  which allows for long filenames in unicode format (unicode is the
+  new 16 bit character code, successor to ASCII, which encodes the
+  characters of almost all languages of the world; see
+  http://www.unicode.org for more information; to browse the WWW, you
+  need to have access to a machine on the Internet that has a program
+  like lynx or netscape). Say Y here if you want to be able to read
+  Joliet CDROMs under Linux.
+
 fat fs support
 CONFIG_FAT_FS
   If you want to use one of the FAT-based filesystems (the MS-DOS,
@@ -4485,7 +5046,7 @@ CONFIG_MSDOS_FS
   Linux, you can either use the DOS emulator DOSEMU, described in the
   DOSEMU-HOWTO, available via ftp (user: anonymous) at
   sunsite.unc.edu:/pub/Linux/docs/HOWTO, or try dmsdosfs in
-  sunsite.unc.edu:/pub/Linux/system/Filesystems/dosfs. If you intend
+  sunsite.unc.edu:/pub/Linux/system/filesystems/dosfs. If you intend
   to use dosemu with a non-compressed MSDOS partition, say Y here) and
   MSDOS floppies. This means that file access becomes transparent,
   i.e. the MSDOS files look and behave just like all other Unix files.
@@ -4541,154 +5102,6 @@ CONFIG_UMSDOS_FS
   umsdos.o. Note that the filesystem of your root partition cannot be
   a module, so this could be dangerous. If unsure, say N.
 
-nls: Native language codepages and Unicode support
-CONFIG_NLS
-  This is required by the FAT filesystems and by the ISO9660 filesystem
-  when it is compiled with Joliet support.  Joliet is a Microsoft
-  extension for CDROMs that supports Unicode.  This allows translation
-  between different character sets. When dealing with the FAT based
-  filesystems, there are two character sets that are important. The
-  first is the codepage.  Codepages are character sets that are used by
-  DOS to allow filenames to have native language characters when
-  character sets were limited to 256 characters. The codepage is the
-  character set that is used to store native language characters on
-  disk.  The two most common codepages are 437 in the United States and
-  850 in much of Europe. The second important character set is the
-  input/output character set. This is the character set that is
-  displayed on the screen. In the United States, this will almost always
-  be the ISO 8859-1 character set. This is the default. Linux will only
-  do a translation of the FAT filenames, not the contents of the files.
-
-nls iso8859-1
-CONFIG_NLS_ISO8859_1
-  ISO8859-1 is the Latin 1 character set, and it covers most West
-  European languages such as Albanian, Catalan, Danish, Dutch, English,
-  Faeroese, Finnish, French, German, Galician, Irish, Icelandic, Italian,
-  Norwegian, Portuguese, Spanish, Swedish, and Valencian.
-
-nls iso8859-2
-CONFIG_NLS_ISO8859_2
-  ISO8859-2 is the Latin 2 character set, and it works for most
-  Latin-written Slavic and Central European languages: Czech, German,
-  Hungarian, Polish, Rumanian, Croatian, Slovak, Slovene.
-
-nls iso8859-3
-CONFIG_NLS_ISO8859_3
-  ISO8859-3 is the Latin 3 character set, and it s popular with authors
-  of Esperanto, Galician, Maltese, and Turkish.
-
-nls iso8859-4
-CONFIG_NLS_ISO8859_4
-  ISO8859-4 is the Latin 4 character set, and it introduces letters
-  for Estonian, Latvian, and Lithuanian. It is an incomplete predecessor of
-  Latin 6.
-
-nls iso8859-5
-CONFIG_NLS_ISO8859_5
-  ISO8859-5 is a Cyrillic character set, and you can type Bulgarian,
-  Byelorussian, Macedonian, Russian, Serbian, and Ukrainian.
-  Note that the charset KOI8-R is preferred in Russia.
-
-nls iso8859-6
-CONFIG_NLS_ISO8859_6
-  ISO8859-6 is the Arabic character set.
-
-nls iso8859-7
-CONFIG_NLS_ISO8859_7
-  ISO8859-7 is the Modern Greek character set.
-
-nls iso8859-8
-CONFIG_NLS_ISO8859_8
-  ISO8859-8 is the Hebrew character set.
-
-nls iso8859-9
-CONFIG_NLS_ISO8859_9
-  ISO8859-9 is the Latin 5 character set, and it replaces the rarely
-  needed Icelandic letters in Latin 1 with the Turkish ones. Useful in
-  Turkey.
-
-nls iso8859-10
-CONFIG_NLS_ISO8859_10
-  ISO8859-10 is the Latin 6 character set, and it adds the last Inuit
-  (Greenlandic) and Sami (Lappish) letters that were missing in Latin 4 to
-  cover the entire Nordic area. 
-
-nls koi8-r
-CONFIG_NLS_KOI8_R
-  This is the preferred Russian character set.
-
-nls codepage 437
-CONFIG_NLS_CODEPAGE_437
-  This is the DOS codepage that is used in the United States and parts of
-  Canada.
-
-nls codepage 737
-CONFIG_NLS_CODEPAGE_737
-  This is the codepage used by DOS for Greek.
-
-nls codepage 775
-CONFIG_NLS_CODEPAGE_775
-  This is the codepage used by DOS for the Baltic Rim Languages.
-
-nls codepage 850
-CONFIG_NLS_CODEPAGE_850
-  This is the DOS codepage that is used in 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
-  codepage 437.
-
-nls codepage 852
-CONFIG_NLS_CODEPAGE_852
-  This is the Latin 2 codepage used by DOS for much of Central and
-  Eastern Europe.  It has all the required characters for these languages:
-  Albanian, Croatian, Czech, English, Finnish, Hungarian, Irish, German,
-  Polish, Romanian, Serbian (Latin transcription), Slovak, Slovenian, and
-  Sorbian.
-
-nls codepage 855
-CONFIG_NLS_CODEPAGE_855
-  This is the DOS codepage that is used for Cyrillic.
-
-nls codepage 857
-CONFIG_NLS_CODEPAGE_857
-  This is the DOS codepage that is used for Turkish.
-
-nls codepage 860
-CONFIG_NLS_CODEPAGE_860
-  This is the DOS codepage that is used for Portuguese.
-
-nls codepage 861
-CONFIG_NLS_CODEPAGE_861
-  This is the DOS codepage that is used for Icelandic.
-
-nls codepage 862
-CONFIG_NLS_CODEPAGE_862
-  This is the DOS codepage that is used for Hebrew.
-
-nls codepage 863
-CONFIG_NLS_CODEPAGE_863
-  This is the DOS codepage that is used for Canadian French.
-
-nls codepage 864
-CONFIG_NLS_CODEPAGE_864
-  This is the DOS codepage that is used for Arabic.
-
-nls codepage 865
-CONFIG_NLS_CODEPAGE_865
-  This is the DOS codepage that is used in the Nordic European countries.
-
-nls codepage 866
-CONFIG_NLS_CODEPAGE_866
-  This is the DOS codepage that is used for Cyrillic/Russian.
-
-nls codepage 869
-CONFIG_NLS_CODEPAGE_869
-  This is the DOS codepage that is used for Greek.
-
-nls codepage 874
-CONFIG_NLS_CODEPAGE_874
-  This is the DOS codepage that is used for Thai.
-
 /proc filesystem support
 CONFIG_PROC_FS
   This is a virtual filesystem providing information about the status
@@ -4697,16 +5110,17 @@ CONFIG_PROC_FS
   them. Also, you cannot read the files with less: you need to use
   more or cat. The filesystem is explained in the Kernel Hacker's
   Guide at http://www.redhat.com:8080/HyperNews/get/khg.html on the
-  Web, and also on the proc(8) manpage ("man 8 proc").  This option
-  will enlarge your kernel by about 18 kB. 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 - often a source of
-  trouble if two devices are mistakenly configured to use the same
-  IRQ). Several programs depend on this, so everyone should say Y
-  here.
-  
+  WWW (to browse the WWW, you need to have access to a machine on the
+  Internet that has a program like lynx or netscape), and also on the
+  proc(8) manpage ("man 8 proc").  This option will enlarge your
+  kernel by about 18 kB. 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 - often a source of trouble if two
+  devices are mistakenly configured to use the same IRQ). Several
+  programs depend on this, so everyone should say Y here.
+
 NFS filesystem support
 CONFIG_NFS_FS
   If you are connected to some other (usually local) Unix computer
@@ -4730,7 +5144,7 @@ CONFIG_NFS_FS
   Documentation/modules.txt. If you configure a diskless machine which
   will mount its root filesystem over nfs (in order to do that, check
   out the netboot package, available via ftp (user: anonymous) from
-  sunsite.unc.edu in /pub/Linux/system/Linux-boot/, extract with "tar
+  sunsite.unc.edu in /pub/Linux/system/boot/ethernet/, extract with "tar
   xzvf filename", and say Y to "Root file system on NFS" below), then
   you cannot compile this driver as a module. If you don't know what
   all this is about, say N.
@@ -4759,20 +5173,28 @@ CONFIG_NFSD
   module, say M here and read Documentation/modules.txt. If unsure,
   say N.
 
-ISO9660 cdrom filesystem support
-CONFIG_ISO9660_FS
-  This is the standard filesystem used on CDROMs. It was previously
-  known as "High Sierra Filesystem" and is called "hsfs" on other Unix
-  systems. The so-called Rock-Ridge extensions which allow for long
-  Unix filenames are also supported by this driver. If you have a
-  CDROM drive and want to do more with it than just listen to audio
-  CDs and watch its LEDs, say Y (and read the CDROM-HOWTO, available
-  via ftp (user: anonymous) from
-  sunsite.unc.edu:/pub/Linux/docs/HOWTO), thereby enlarging your
-  kernel by about 27 kB; otherwise say N.  If you want to compile this
-  as a module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. The module will be called isofs.o.
+BOOTP support
+CONFIG_RNFS_BOOTP
+  If you want your Linux box to mount its whole root filesystem from
+  some other computer over the net via NFS and you want the IP address
+  of your computer to be discovered automatically at boot time using
+  the BOOTP protocol (a special protocol designed for doing this job),
+  say Y here. In case the boot ROM of your network card was designed
+  for booting Linux and does BOOTP itself, providing all necessary
+  information on the kernel command line, you can say N here.  If
+  unsure, say Y. Note that in case you want to use BOOTP, a BOOTP
+  server must be operating on your network. Read
+  Documentation/nfsroot.txt for details.
+
+RARP support
+CONFIG_RNFS_RARP
+  If you want your Linux box to mount its whole root filesystem from
+  some other computer over the net via NFS and you want the IP address
+  of your computer to be discovered automatically at boot time using
+  the RARP protocol (an older protocol which is being obsoleted by
+  BOOTP and DHCP), say Y here. Note that in case you want to use RARP,
+  a RARP server must be operating on your network. Read
+  Documentation/nfsroot.txt for details.
 
 OS/2 HPFS filesystem support (read only)
 CONFIG_HPFS_FS
@@ -4793,15 +5215,21 @@ CONFIG_NTFS_FS
   NTFS is the file system of Microsoft Windows NT. Say Y if you want
   to access partitions using this file system. The Linux NTFS driver
   supports most of the mount options of the VFAT driver, see
-  Documentation/filesystems/ntfs.txt. There is an experimental
-  write support available; use at your own risk.
+  Documentation/filesystems/ntfs.txt. Saying Y here will give you
+  read-only access to NTFS partitions. This code 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 ntfs.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 NTFS read-write support (experimental)
 CONFIG_NTFS_RW
-  The read-write support in NTFS is far from being complete and well
-  tested. If you enable this, be prepared to recover the NTFS volume
-  from tape.
-  
+  If you say Y here, you will (hopefully) be able to write to NTFS
+  file systems as well as to read from them.  The read-write support
+  in NTFS is far from being complete and is not well tested. If you
+  enable this, be prepared to recover the NTFS volume from tape. If
+  unsure, say N.
+
 System V and Coherent filesystem support
 CONFIG_SYSV_FS
   SCO, Xenix and Coherent are commercial Unix systems for intel
@@ -4819,15 +5247,15 @@ CONFIG_SYSV_FS
   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").  Note
-  also that this option has nothing whatsoever to do with the option
-  "System V IPC". Read about the System V filesystem in
-  Documentation/filesystems/sysv-fs.txt. This option will enlarge your
-  kernel by about 34 kB. 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 sysv.o. If you
-  haven't heard about all of this before, it's safe to say N.
+  operating systems) is given by the tar program ("man tar" or
+  preferably "info tar").  Note also that this option has nothing
+  whatsoever to do with the option "System V IPC". Read about the
+  System V filesystem in Documentation/filesystems/sysv-fs.txt. This
+  option will enlarge your kernel by about 34 kB. 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 sysv.o. If
+  you haven't heard about all of this before, it's safe to say N.
 
 Kernel automounter support (experimental)
 CONFIG_AUTOFS_FS
@@ -4848,42 +5276,54 @@ BSD UFS filesystem support (read only)
 CONFIG_UFS_FS
   BSD and derivate versions of Unix (such as SunOS, FreeBSD, NetBSD
   and NeXTstep) use a filesystem called UFS. Some System V Unixes can
-  create and mount partitions and diskettes using this filesystem as
-  well. Saying Y here allows you to mount these partitions and
-  diskettes read-only. If you only intend to mount files from some
-  other Unix over the network using NFS, you don't need the UFS
-  filesystem support (but you need nfs filesystem support
+  create and mount harddisk partitions and diskettes using this
+  filesystem as well. Saying Y here allows you to mount these
+  partitions and diskettes read-only. If you only intend to mount
+  files from some other Unix over the network using NFS, you don't
+  need the UFS filesystem support (but you need nfs filesystem support
   obviously). Note that this option is generally not needed for
   floppies, since a good portable way to transport files and
   directories between unixes (and even other operating systems) is
-  given by the tar program ("man tar"). When accessing NeXTstep files,
-  you may need to convert them from the NeXT character set to the
-  Latin1 character set; use GNU recode for this purpose.  Say Y to
-  build UFS support into your kernel. If you want to compile this as a
-  module ( = code which can be inserted in and removed from the
-  running kernel whenever you want), say M here and read
-  Documentation/modules.txt. The module will be called ufs.o. If you
-  haven't heard about all of this before, it's safe to say N.
+  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
+  for this purpose.  Say Y to build UFS read support into your
+  kernel. If you want to compile this as a module ( = code which can
+  be inserted in and removed from the running kernel whenever you
+  want), say M here and read Documentation/modules.txt. 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
-  FreeBSD uses its own partition scheme on your PC. It requires only
-  one entry in the primary partition table of your disk and manages it
-  similarly to DOS extended partitions, putting in its first sector a
-  new partition table in disklabel format. Saying Y here allows you to
-  read these disklabels and further mount FreeBSD partitions on your
-  Linux box if you also have configured BSD ufs filesystem support. If
-  you don't know what all this is about, say N.
+  FreeBSD uses its own harddisk partition scheme on your PC. It
+  requires only one entry in the primary partition table of your disk
+  and manages it similarly to DOS extended partitions, putting in its
+  first sector a new partition table in disklabel format. Saying Y
+  here allows you to read these disklabels and further mount FreeBSD
+  partitions read-only from within Linux if you have also said Y to
+  "BSD ufs filesystem support", above. If you don't know what all this
+  is about, say N.
 
 SMD disklabel (Sun partition tables) support
 CONFIG_SMD_DISKLABEL
-  Like most systems, SunOS uses its own partition table format,
-  incompatible with all others. Saying Y here allows you to read these
-  partition tables and further mount SunOS disks on your Linux box if
-  you also have configured BSD ufs filesystem support. This is mainly
-  used to carry data from a Sparc under SunOS to your Linux box via a
-  removable medium like magneto-optical or ZIP drives. If you don't
-  know what all this is about, say N.
+  Like most systems, SunOS uses its own harddisk partition table
+  format, incompatible with all others. Saying Y here allows you to
+  read these partition tables and further mount SunOS disks read-only
+  from within Linux if you have also said Y to "BSD ufs filesystem
+  support", above. This is mainly used to carry data from a Sparc
+  under SunOS to your Linux box via a removable medium like
+  magneto-optical or ZIP drives; note however that 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"). If you don't know what all this is about,
+  say N.
+
+Macintosh partition map support
+CONFIG_MAC_PARTITION
+  Say Y here if you want your Linux system to be able to read
+  the partition tables of Macintosh hard drives, and thus use
+  partitions on those drives.
 
 SMB filesystem support (to mount WfW shares etc..)
 CONFIG_SMB_FS
@@ -4899,7 +5339,7 @@ CONFIG_SMB_FS
   available to Windows clients (which need to have a TCP/IP stack),
   you don't need to say Y here; you can use the program samba
   (available via ftp (user: anonymous) in
-  sunsite.unc.edu:/pub/Linux/system/Network/samba) for that. General
+  sunsite.unc.edu:/pub/Linux/system/network/samba) for that. General
   information about how to connect Linux, Windows machines and Macs is
   on the WWW at http://eats.com/linux_mac_win.html (to browse the WWW,
   you need to have access to a machine on the Internet that has a
@@ -4911,15 +5351,22 @@ CONFIG_SMB_FS
 
 Coda filesystem support
 CONFIG_CODA_FS
-  CODA is an advanced network filesystem.  It has support for disconnected
-  operation for laptops, read/write server replication, persistent client
-  caches and write back caching. 
-  By choosing this option you are compiling kernel support for Coda clients
-  into the Linux kernel.  You will need user level code as well, both for 
-  the client and server. Server's are currently user level, i.e. need
-  no kernel support. For further information see
-  http://www.coda.cs.cmu.edu or contact Peter Braam <braam@cs.cmu.edu>. 
-
+  CODA is an advanced network filesystem.  It has support for
+  disconnected operation for laptops, read/write server replication,
+  persistent client caches and write back caching.
+  By saying Y here you are compiling kernel support for Coda clients
+  into the Linux kernel.  You will need user level code as well, both
+  for the client and server. Servers are currently user level,
+  i.e. need no kernel support. For technical information, read
+  Documentation/filesystems/coda.txt. 
+  If you want to compile the coda client 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 coda.o. 
+  For further information see http://www.coda.cs.cmu.edu (to browse
+  the WWW, you need to have access to a machine on the Internet that
+  has a program like lynx or netscape) or contact Peter Braam
+  <braam@cs.cmu.edu>.
 
 SMB Win95 bug work-around
 CONFIG_SMB_WIN95
@@ -4946,20 +5393,21 @@ Amiga FFS filesystem support
 CONFIG_AFFS_FS
   The Fast File System (FFS) is the common filesystem used on
   harddisks by Amiga(tm) Systems since AmigaOS Version 1.3
-  (34.20). With this driver you can also mount diskfiles used by the
-  Un*X Amiga Emulator by Bernd Schmidt
-  (http://www-users.informatik.rwth-aachen.de/~crux/uae.html).  If you
-  want to do the latter, you will also need to say Y to "Loop device
-  support", above. Say Y if you want to be able to read and write
-  files from and to an Amiga FFS partition on your harddrive. Amiga
-  floppies however cannot be read with this driver due to an
-  incompatibility of the floppy controller used in an Amiga and the
-  standard floppy controller in PCs and workstations. Read
-  Documentation/filesystems/affs.txt and fs/affs/Changes. This
-  filesystem 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 affs.o. If you want to compile it as a module,
-  say M here and read Documentation/modules.txt.  If unsure, say N.
+  (34.20). With this driver you can also mount diskfiles used by Bernd
+  Schmidt's Un*X Amiga Emulator (http://www.freiburg.linux.de/~uae/;
+  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
+  do the latter, you will also need to say Y to "Loop device support",
+  above. Say Y if you want to be able to read and write files from and
+  to an Amiga FFS partition on your harddrive. Amiga floppies however
+  cannot be read with this driver due to an incompatibility of the
+  floppy controller used in an Amiga and the standard floppy
+  controller in PCs and workstations. Read
+  Documentation/filesystems/affs.txt and fs/affs/Changes. This filesystem 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
+  affs.o. If you want to compile it as a module, say M here and read
+  Documentation/modules.txt.  If unsure, say N.
 
 ROM filesystem support
 CONFIG_ROMFS_FS
@@ -4973,23 +5421,323 @@ CONFIG_ROMFS_FS
   and read Documentation/modules.txt.  If you don't know whether you
   need it, then you don't need it: say N.
 
+nls: Native language codepages and Unicode support
+CONFIG_NLS
+  This is required by the FAT and NTFS filesystems and by the ISO9660
+  filesystem when it is compiled with Joliet support.  Joliet is a
+  Microsoft extension for CDROMs that supports Unicode.  This allows
+  translation between different character sets. When dealing with the
+  FAT based filesystems, there are two character sets that are
+  important. The first is the codepage.  Codepages are character sets
+  that are used by DOS to allow filenames to have native language
+  characters when character sets were limited to 256 characters. The
+  codepage is the character set that is used to store native language
+  characters on disk.  The two most common codepages are 437 in the
+  United States and 850 in much of Europe. The second important
+  character set is the input/output character set. This is the
+  character set that is displayed on the screen. In the United States,
+  this will almost always be the ISO 8859-1 character set. This is the
+  default. Linux will only do a translation of the FAT filenames, not
+  the contents of the files.
+
+nls codepage 437
+CONFIG_NLS_CODEPAGE_437
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 in
+  the United States and parts of Canada. This is recommended.
+
+nls codepage 737
+CONFIG_NLS_CODEPAGE_737
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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
+  Greek. If unsure, say N.
+
+nls codepage 775
+CONFIG_NLS_CODEPAGE_775
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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
+  for the Baltic Rim Languages. If unsure, say N.
+
+nls codepage 850
+CONFIG_NLS_CODEPAGE_850
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored
+  in so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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
+  countries here]. It has some characters useful to many European
+  languages that are not part of the US codepage 437. If unsure, say
+  Y.
+
+nls codepage 852
+CONFIG_NLS_CODEPAGE_852
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 Latin 2 codepage used by DOS
+  for much of Central and Eastern Europe.  It has all the required
+  characters for these languages: Albanian, Croatian, Czech, English,
+  Finnish, Hungarian, Irish, German, Polish, Romanian, Serbian (Latin
+  transcription), Slovak, Slovenian, and Sorbian.
+
+nls codepage 855
+CONFIG_NLS_CODEPAGE_855
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Cyrillic.
+
+nls codepage 857
+CONFIG_NLS_CODEPAGE_857
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Turkish.
+
+nls codepage 860
+CONFIG_NLS_CODEPAGE_860
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Portuguese.
+
+nls codepage 861
+CONFIG_NLS_CODEPAGE_861
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Icelandic.
+
+nls codepage 862
+CONFIG_NLS_CODEPAGE_862
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Hebrew.
+
+nls codepage 863
+CONFIG_NLS_CODEPAGE_863
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Canadian
+  French.
+
+nls codepage 864
+CONFIG_NLS_CODEPAGE_864
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Arabic.
+
+nls codepage 865
+CONFIG_NLS_CODEPAGE_865
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for the Nordic
+  European countries.
+
+nls codepage 866
+CONFIG_NLS_CODEPAGE_866
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for
+  Cyrillic/Russian.
+
+nls codepage 869
+CONFIG_NLS_CODEPAGE_869
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Greek.
+###
+### Why do we have two codepages for Greek and Cyrillic?
+###
+
+nls codepage 874
+CONFIG_NLS_CODEPAGE_874
+  The Microsoft fat filesystem family can deal with filenames in
+  native language character sets. These character sets are stored in
+  so-called DOS codepages. You need to include the appropriate
+  codepage if you want to be able to read/write these filenames on
+  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 for Thai.
+
+nls iso8859-1
+CONFIG_NLS_ISO8859_1
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 1 character
+  set, which covers most West European languages such as Albanian,
+  Catalan, Danish, Dutch, English, Faeroese, Finnish, French, German,
+  Galician, Irish, Icelandic, Italian, Norwegian, Portuguese, Spanish,
+  Swedish, and Valencian. It is also the default for the US. If
+  unsure, say Y.
+
+nls iso8859-2
+CONFIG_NLS_ISO8859_2
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the the Latin 2 character
+  set, which works for most Latin-written Slavic and Central European
+  languages: Czech, German, Hungarian, Polish, Rumanian, Croatian,
+  Slovak, Slovene.
+
+nls iso8859-3
+CONFIG_NLS_ISO8859_3
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 3 character
+  set, which is popular with authors of Esperanto, Galician, Maltese,
+  and Turkish.
+
+nls iso8859-4
+CONFIG_NLS_ISO8859_4
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 4 character
+  set which introduces letters for Estonian, Latvian, and
+  Lithuanian. It is an incomplete predecessor of Latin 6.
+
+nls iso8859-5
+CONFIG_NLS_ISO8859_5
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-5, a Cyrillic
+  character set with which you can type Bulgarian, Byelorussian,
+  Macedonian, Russian, Serbian, and Ukrainian.  Note that the charset
+  KOI8-R is preferred in Russia.
+
+nls iso8859-6
+CONFIG_NLS_ISO8859_6
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-6, the Arabic
+  character set.
+
+nls iso8859-7
+CONFIG_NLS_ISO8859_7
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-7, the Modern
+  Greek character set.
+
+nls iso8859-8
+CONFIG_NLS_ISO8859_8
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for ISO8859-8, the Hebrew
+  character set.
+
+nls iso8859-9
+CONFIG_NLS_ISO8859_9
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 5 character
+  set, and it replaces the rarely needed Icelandic letters in Latin 1
+  with the Turkish ones. Useful in Turkey.
+
+nls iso8859-10
+CONFIG_NLS_ISO8859_10
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the Latin 6 character
+  set, which adds the last Inuit (Greenlandic) and Sami (Lappish)
+  letters that were missing in Latin 4 to cover the entire Nordic
+  area.
+
+nls koi8-r
+CONFIG_NLS_KOI8_R
+  If you want to display filenames with native language characters
+  from the Microsoft fat filesystem family or from JOLIET CDROMs
+  correctly on the screen, you need to include the appropriate
+  input/output character sets. Say Y here for the preferred Russian
+  character set.
+
 Virtual terminal
 CONFIG_VT
-  This includes support for a terminal device using display and
+  This includes support for a terminal device with display and
   keyboard devices. Only people using embedded systems want to say N
-  here; most everybody says Y.
+  here; most everybody else says Y. If unsure, say Y, or else you
+  won't be able to do much with your new shiny Linux system :-)
 
-Console on virtual terminal
+Support for console on virtual terminal
 CONFIG_VT_CONSOLE
-  If you enable this option, by default all kernel messages will be sent
-  to the device /dev/tty0 which corresponds to the virtual terminal you
+  If you say Y here, by default all kernel messages will be sent to
+  the device /dev/tty0 which corresponds to the virtual terminal you
   have visible on your display. You should say Y here unless you only
-  want to have the kernel messages output on a serial port.
+  want to have the kernel messages output on a serial port (in which
+  case you probably want to say Y to "Console on serial port", below).
 
 Software generated cursor
 CONFIG_SOFTCURSOR
-  If you enable this option, you'll be able to do lots of nice things
-  with your cursor -- for example to turn it into a non-blinking one.
+  If you say Y here, you'll be able to do lots of nice things with the
+  cursors of your virtual consoles -- for example to turn them into
+  non-blinking block cursors which are more visible on laptop screens.
   See Documentation/VGA-softcursor.txt for more information.
 
 Standard/generic serial support
@@ -5011,14 +5759,14 @@ CONFIG_SERIAL
   that they can use serial mice, modems and similar devices connecting
   to the standard serial ports.
 
-Console on serial port
+Support for console on serial port
 CONFIG_SERIAL_CONSOLE
-  If you enable this option, it is possible to use a serial port as the
-  console. By default still the virtual console will be used at the
-  system console but you can alter that using a kernel command line
-  option. If you don't have a VGA card installed the kernel will
-  automatically use /dev/ttyS0 as system console if this option is
-  enabled.
+  If you say Y here, it is possible to use a serial port as the
+  console. By default still the currently visible virtual console will
+  be used as the system console but you can alter that using a kernel
+  command line option. If you don't have a VGA card installed and you
+  say Y here, the kernel will automatically use /dev/ttyS0 as system
+  console.
 
 Comtrol Rocketport support
 CONFIG_ROCKETPORT
@@ -5070,27 +5818,29 @@ CONFIG_SPECIALIX
   connect more than two modems to your linux box, for instance in
   order to become a BBS. If you have a card like that, say Y here and
   read the file Documentation/specialix.txt. Also it's possible to say
-  M here and compile this driver as kernel loadable module.
+  M here and compile this driver as kernel loadable module which will
+  be called specialix.o.
 
 Specialix DTR/RTS pin is RTS
 CONFIG_SPECIALIX_RTSCTS
-  The Specialix card can only support either RTS or DTR. When this
-  option is off, the driver will use the pin as "DTR" when the tty is
-  in software handshake mode. When this option is on or hardware 
-  handshake is on, it will always be RTS. Read the file 
-  Documentation/specialix.txt for more information. 
+  The Specialix card can only support either RTS or DTR. When you say
+  N here, the driver will use the pin as "DTR" when the tty is in
+  software handshake mode. When you say Y here or hardware handshake
+  is on, it will always be RTS. Read the file
+  Documentation/specialix.txt for more information.
 
 Cyclades async mux support
 CONFIG_CYCLADES
   This is a driver for a card that gives you many serial ports. You
   would need something like this to connect more than two modems to
-  your linux box, for instance in order to become a BBS. 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
-  cyclades.o. If you haven't heard about it, it's safe to say N. (As
-  of 1.3.9x kernels, this driver's minor numbers start at 0 instead of
-  32.)
+  your linux box, for instance in order to become a BBS. For
+  information about the Cyclades-Z card, read
+  drivers/char/README.cycladesZ. 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 cyclades.o. If
+  you haven't heard about it, it's safe to say N. (As of 1.3.9x
+  kernels, this driver's minor numbers start at 0 instead of 32.)
 
 Stallion multiport serial support 
 CONFIG_STALDRV
@@ -5100,7 +5850,7 @@ CONFIG_STALDRV
   asked for your specific card model in the next questions. Make sure
   to read drivers/char/README.stallion in this case. If you have never
   heard about all this, it's safe to say N.
+
 Stallion EasyIO or EC8/32 support 
 CONFIG_STALLION
   If you have an EasyIO or EasyConnection 8/32 multiport Stallion
@@ -5260,12 +6010,13 @@ CONFIG_82C710_MOUSE
 PC110 digitizer pad support
 CONFIG_PC110_PAD
   This drives the digitizer pad on the IBM PC110 palmtop (see
-  http://toy.cabi.net). It can turn the digitizer pad into a PS/2
-  mouse emulation with tap gestures or into an absolute pad.  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
-  pc110pad.o.
+  http://toy.cabi.net; to browse the WWW, you need to have access to a
+  machine on the Internet that has a program like lynx or
+  netscape). It can turn the digitizer pad into a PS/2 mouse emulation
+  with tap gestures or into an absolute pad.  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 pc110pad.o.
 
 Microsoft busmouse support
 CONFIG_MS_BUSMOUSE
@@ -5321,97 +6072,90 @@ CONFIG_QIC02_DYNCONF
 
 Floppy tape drive (QIC-80/40/3010/3020/TR-1/TR-2/TR-3) support
 CONFIG_FTAPE
-    If you have a tape drive that is connected to your floppy
-  controller, say `Y' here. Some tape drives (like the Seagate "Tape
+  If you have a tape drive that is connected to your floppy
+  controller, say Y here. Some tape drives (like the Seagate "Tape
   Store 3200" or the Iomega "Ditto 3200" or the Exabyte "Eagle TR-3")
   come with a "high speed" controller of their own. These drives (and
-  their companion controllers) are also supported.
-    If you have a special controller (such as the CMS FC-10, FC-20,
+  their companion controllers) are also supported if you say Y here.
+  If you have a special controller (such as the CMS FC-10, FC-20,
   Mountain Mach-II, or any controller that is based on the Intel 82078
   FDC like the high speed controllers by Seagate and Exabyte and
   Iomega's "Ditto Dash") you must configure it by selecting the
-  appropriate entries from the "Floppy tape controllers" sub-menu and
-  possibly modify the default values for the IRQ and DMA channel and
-  the IO base in ftape's configuration menu. If you want to use your
-  floppy tape drive on a PCI-bus based system, please read the file
-  `./drivers/char/ftape/README.PCI'.
-    The ftape kernel driver is also available as a runtime loadable
+  appropriate entries from the "Floppy tape controllers" sub-menu
+  below and possibly modify the default values for the IRQ and DMA
+  channel and the IO base in ftape's configuration menu. If you want
+  to use your floppy tape drive on a PCI-bus based system, please read
+  the file drivers/char/ftape/README.PCI.
+  The ftape kernel driver is also available as a runtime loadable
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want). If you want to compile it as a
-  module, say `M' here and read `./Documentation/modules.txt'.
-    Note that the `Ftape-HOWTO' is out of date (sorry), but there is a
-  web page with more recent documentation at
-  `http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/'. This page
+  module, say M here and read Documentation/modules.txt. The module
+  will be called ftape.o.
+  Note that the Ftape-HOWTO is out of date (sorry) and documents the
+  older version 2.08 of this software but still contains useful
+  information. There is a web page with more recent documentation at
+  http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ . This page
   always contains the latest release of the ftape driver and useful
   information (backup software, ftape related patches and
-  documentation, FAQ). The Ftape-HOWTO still contains useful
-  information, though, but documents the older 2.08 version of ftape,
-  whereas this version of ftape is 3.04.
-    Note that the file system interface has changed quite a lot
-  compared to previous versions of ftape. Please read
-  `./Documentation/ftape.txt'
+  documentation, FAQ). (To browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or netscape.)
+  Note that the file system interface has changed quite a bit compared
+  to previous versions of ftape. Please read Documentation/ftape.txt.
 
 The file system interface for ftape
 CONFIG_ZFTAPE
-    Normally, you want to say `Y' or `M'. DON'T say `N' here or you
+  Normally, you want to say Y or M. DON'T say N here or you
   WON'T BE ABLE TO USE YOUR FLOPPY TAPE DRIVE.
-    The ftape module itself no longer contains the routines necessary
+  The ftape module itself no longer contains the routines necessary
   to interface with the kernel VFS layer (i.e. to actually write data
   to and read data from the tape drive). Instead the file system
   interface (i.e. the hardware independent part of the driver) has
   been moved to a separate module.
-    If you say `M' zftape will be compiled as as a runtime loadable
+  If you say M zftape will be compiled as a runtime loadable
   module ( = code which can be inserted in and removed from the
   running kernel whenever you want). In this case you should read
-  `./Documentation/modules.txt'.
-    There will also be another module called `zft-compressor.o' which
-  contains code to support user transparent on-the-fly compression
-  based on Ross William's lzrw3 algorithm. `zft-compressor.o' will be
-  compiled as a runtime loadable module only. If you have enabled
+  Documentation/modules.txt. The module will be called zftape.o.
+  Regardless of whether you say Y or M here, an additional runtime
+  loadable module called `zft-compressor.o' which contains code to
+  support user transparent on-the-fly compression based on Ross
+  William's lzrw3 algorithm will be produced. If you have enabled
   auto-loading of kernel modules via `kerneld' (i.e. have said `Y' to
   CONFIG_KERNELD) then `zft-compressor.o' will be loaded automatically
   by zftape when needed.
-    Despite of its name zftape does NOT use compression by
-  default. The file `./Documentation/ftape.txt' contains a short
-  description of the most important changes in the file system
-  interface compared to previous versions of ftape. The ftape home
-  page `http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/'
-  contains further information. IMPORTANT NOTE: zftape can read
-  archives created by previous versions of ftape and provide file mark
-  support (i.e. fast skipping between tape archives) but previous
-  version of ftape will lack file mark support when reading archives
-  produced by zftape.
-
-Builtin on-the-fly compression for zftape, based on lzrw3
-CONFIG_ZFT_COMPRESSOR
-    This module implements builtin on-the-fly compression for ftape's
-  file system interface zftape. `zft-compressor.o' is compiled as a
-  runtime loadable module only and will be loaded by zftape on demand
-  if support for auto-loading of modules via `kerneld' has been
-  enabled (CONFIG_KERNELD).
+  Despite of its name zftape does NOT use compression by default. The
+  file Documentation/ftape.txt contains a short description of the
+  most important changes in the file system interface compared to
+  previous versions of ftape. The ftape home page
+  http://www-math.math.rwth-aachen.de/~LBFM/claus/ftape/ contains
+  further information (to browse the WWW, you need to have access to a
+  machine on the Internet that has a program like lynx or netscape).
+  IMPORTANT NOTE: zftape can read archives created by previous
+  versions of ftape and provide file mark support (i.e. fast skipping
+  between tape archives) but previous version of ftape will lack file
+  mark support when reading archives produced by zftape.
 
 Default block size for zftape
 CONFIG_ZFT_DFLT_BLK_SZ
-    If unsure leave this at its default value, i.e. 10240.  Note that
+  If unsure leave this at its default value, i.e. 10240.  Note that
   you specify only the default block size here. The block size can be
   changed at run time using the MTSETBLK tape operation with the
   MTIOCTOP ioctl (i.e. with "mt -f /dev/qft0 setblk #BLKSZ" from the
   shell command line).
-    The probably most striking difference between zftape and previous
+  The probably most striking difference between zftape and previous
   versions of ftape is the fact that all data must be written or read
   in multiples of a fixed block size. The block size defaults to
   10240 which is what GNU tar uses. The values for the block size
   should be either 1 or multiples of 1024 up to a maximum value of
   63488 (i.e. 62k). If you specify `1' then zftape's builtin
   compression will be disabled.
-    Reasonable values are `10240' (GNU tar's default block size),
+  Reasonable values are `10240' (GNU tar's default block size),
   `5120' (afio's default block size), `32768' (default block size some
   backup programs assume for SCSI tape drives) or `1' (no restriction
   on block size, but disables builtin compression).
 
 Number of DMA buffers
 CONFIG_FT_NR_BUFFERS
-    Please leave this at `3"' unless you REALLY know what you are
+  Please leave this at `3' unless you REALLY know what you are
   doing. It is not necessary to change this value. Values below 3 make
   the proper use of ftape impossible, values greater than 3 are waste
   of memory. You can change the amount of DMA memory used by ftape at
@@ -5421,7 +6165,7 @@ CONFIG_FT_NR_BUFFERS
 
 Procfs entry for ftape
 CONFIG_FT_PROC_FS
-    Optional. Saying `Y' will result in creation of a file
+  Optional. Saying `Y' will result in creation of a file
   `/proc/ftape' under the proc file system. This files can be viewed
   with your favorite pager (i.e. use "more /proc/ftape/history" or
   "less /proc/ftape/history" or simply "cat /proc/ftape/history"). The
@@ -5431,21 +6175,21 @@ CONFIG_FT_PROC_FS
   kernel driver. Saying `Y' will enlarge the size of the ftape driver
   by approximately 2k.
   WARNING: When compiling ftape as a module (i.e. saying `M' to
-  `CONFIG_FTAPE') it is dangerous to use ftape's proc file system
+  "Floppy tape drive") it is dangerous to use ftape's proc file system
   interface. Accessing `/proc/ftape' while the module is unloaded will
   result in a kernel Oops. This cannot be fixed from inside ftape.
 
 Controlling the amount of debugging output of ftape
 CONFIG_FT_NORMAL_DEBUG
-    This option controls the amount of debugging output the ftape driver
+  This option controls the amount of debugging output the ftape driver
   is ABLE to produce; it does not increase or diminish the debugging
   level itself. If unsure, leave this at its default setting,
   i.e. choose "Normal".
-    Ftape can print lots of debugging messages to the system console
+  Ftape can print lots of debugging messages to the system console
   resp. kernel log files. Reducing the amount of possible debugging
   output reduces the size of the kernel module by some kb, so it might
   be a good idea to use "None" for emergency boot floppies.
-    If you want to save memory then the following strategy is
+  If you want to save memory then the following strategy is
   recommended: leave this option at its default setting "Normal" until
   you know that the driver works as expected, afterwards reconfigure
   the kernel, this time specifying "Reduced" or "None" and recompile
@@ -5453,12 +6197,12 @@ CONFIG_FT_NORMAL_DEBUG
   debugging output does not increase the amount of debugging output
   printed to the console but only makes it possible to produce
   "Excessive" debugging output.
-    Please read `./Documentation/ftape.txt' for a short description
+  Please read Documentation/ftape.txt for a short description
   how to control the amount of debugging output.
 
 The floppy drive controller for ftape
 CONFIG_FT_STD_FDC
-    Only change this setting if you have a special controller. If you
+  Only change this setting if you have a special controller. If you
   didn't plug any add-on card into your computer system but just
   plugged the floppy tape cable into the already existing floppy drive
   controller then you don't want to change the default setting,
@@ -5473,115 +6217,115 @@ CONFIG_FT_STD_FDC
   `2'. This is necessary for any controller card that is based on
   Intel's 82078 FDC such as Seagate's, Exabyte's and Iomega's "high
   speed" controllers.
-    If you choose something other than "Standard" then please make
+  If you choose something other than "Standard" then please make
   sure that the settings for the IO base address and the IRQ and DMA
   channel in the configuration menus below are correct. Use the manual
   of your tape drive to determine the correct settings!
-    If you are already successfully using your tape drive with another
+  If you are already successfully using your tape drive with another
   operating system then you definitely should use the same settings
   for the IO base, the IRQ and DMA channel that have proven to work
   with that other OS.
-    Note that this menu lets you specify only the default setting for
+  Note that this menu lets you specify only the default setting for
   the hardware setup. The hardware configuration can be changed at
   boot time (when ftape is compiled into the kernel, i.e. if you
-  have said `Y' to `CONFIG_FTAPE') or module load time (i.e. if you
-  have said `M' to `CONFIG_FTAPE').
-    Please read also the file `./Documentation/ftape.txt' which
+  have said Y to "Floppy tape drive") or module load time (i.e. if you
+  have said M to "Floppy tape drive").
+  Please read also the file Documentation/ftape.txt which
   contains a short description of the parameters that can be set at
   boot or load time. If you want to use your floppy tape drive on a
   PCI-bus based system, please read the file
-  `./drivers/char/ftape/README.PCI'.
+  drivers/char/ftape/README.PCI.
 
 IO base of the floppy disk controller used with Ftape
 CONFIG_FT_FDC_BASE
-    You don't need to specify a value if the following default
+  You don't need to specify a value if the following default
   settings for the base IO address are correct:
   <<< MACH-2     : 0x1E0 >>>
   <<< FC-10/FC-20: 0x180 >>>
   <<< Secondary  : 0x370 >>>
   Secondary refers to a secondary FDC controller like the "high speed"
   controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
-    Please make sure that the setting for the IO base address
+  Please make sure that the setting for the IO base address
   specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
   CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
   successfully using the tape drive with another operating system then
   you definitely should use the same settings for the IO base that has
   proven to work with that other OS.
-    Note that this menu lets you specify only the default setting for
+  Note that this menu lets you specify only the default setting for
   the IO base. The hardware configuration can be changed at boot time
-  (when ftape is compiled into the kernel, i.e. if you specify `Y' to
-  `CONFIG_FTAPE') or module load time (i.e. if you have say `M' to
-  `CONFIG_FTAPE').
-    Please read also the file `./Documentation/ftape.txt' which
-  contains a short description of the parameters that can be set at
-  boot or load time.
-  
+  (when ftape is compiled into the kernel, i.e. if you specified Y to
+  "Floppy tape drive") or module load time (i.e. if you have said M to
+  "Floppy tape drive").
+  Please read also the file Documentation/ftape.txt which contains a
+  short description of the parameters that can be set at boot or load
+  time.
+
 IRQ channel for the floppy disk controller used with Ftape
 CONFIG_FT_FDC_IRQ
-    You don't need to specify a value if the following default
+  You don't need to specify a value if the following default
   settings for the interrupt channel are correct:
   <<< MACH-2     : 6 >>>
   <<< FC-10/FC-20: 9 >>>
   <<< Secondary  : 6 >>>
   Secondary refers to secondary a FDC controller like the "high speed"
   controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
-    Please make sure that the setting for the IO base address
+  Please make sure that the setting for the IO base address
   specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
   CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
   successfully using the tape drive with another operating system then
   you definitely should use the same settings for the IO base that has
   proven to work with that other OS.
-    Note that this menu lets you specify only the default setting for
+  Note that this menu lets you specify only the default setting for
   the IRQ channel. The hardware configuration can be changed at boot
-  time (when ftape is compiled into the kernel, i.e. if you specify
-  `Y' to `CONFIG_FTAPE') or module load time (i.e. if you have say `M'
-  to `CONFIG_FTAPE').
-    Please read also the file `./Documentation/ftape.txt' which
-  contains a short description of the parameters that can be set at
-  boot or load time.
-  
+  time (when ftape is compiled into the kernel, i.e. if you specified
+  Y to "Floppy tape drive") or module load time (i.e. if you have said M
+  to "Floppy tape drive").
+  Please read also the file Documentation/ftape.txt which contains a
+  short description of the parameters that can be set at boot or load
+  time.
+
 DMA channel for the floppy disk controller used with Ftape
 CONFIG_FT_FDC_DMA
-    You don't need to specify a value if the following default
+  You don't need to specify a value if the following default
   settings for the DMA channel are correct:
   <<< MACH-2     : 2 >>>
   <<< FC-10/FC-20: 3 >>>
   <<< Secondary  : 2 >>>
   Secondary refers to a secondary FDC controller like the "high speed"
   controllers delivered by Seagate or Exabyte or Iomega's Ditto Dash.
-    Please make sure that the setting for the IO base address
+  Please make sure that the setting for the IO base address
   specified here is correct. USE THE MANUAL OF YOUR TAPE DRIVE OR
   CONTROLLER CARD TO DETERMINE THE CORRECT SETTING. If you are already
   successfully using the tape drive with another operating system then
   you definitely should use the same settings for the IO base that has
   proven to work with that other OS.
-    Note that this menu lets you specify only the default setting for
+  Note that this menu lets you specify only the default setting for
   the DMA channel. The hardware configuration can be changed at boot
-  time (when ftape is compiled into the kernel, i.e. if you specify
-  `Y' to `CONFIG_FTAPE') or module load time (i.e. if you have say `M'
-  to `CONFIG_FTAPE').
-    Please read also the file `./Documentation/ftape.txt' which
-  contains a short description of the parameters that can be set at
-  boot or load time.
+  time (when ftape is compiled into the kernel, i.e. if you specified
+  Y to "Floppy tape drive") or module load time (i.e. if you have said M
+  to "Floppy tape drive").
+  Please read also the file Documentation/ftape.txt which contains a
+  short description of the parameters that can be set at boot or load
+  time.
 
 FDC FIFO Threshold before requesting DMA service
 CONFIG_FT_FDC_THR
-    Set the FIFO threshold of the FDC. If this is higher the DMA
+  Set the FIFO threshold of the FDC. If this is higher the DMA
   controller may serve the FCD after a higher latency time. If this is
   lower, less DMA transfers occur leading to less bus contention.
-    You may try to tune this if ftape annoys you with "reduced data
+  You may try to tune this if ftape annoys you with "reduced data
   rate because of excessive overrun errors" messages. However, this
   doesn't seem to have too much an effect.
   If unsure, don't touch the initial value, i.e. leave it at "8".
 
 FDC maximum data rate
 CONFIG_FT_FDC_MAX_RATE
-    With some mother board/FDC combinations ftape will not be able to
+  With some mother board/FDC combinations ftape will not be able to
   run your FDC/tape drive combination at the highest available
   speed. If this is the case you'll encounter "reduced data rate
   because of excessive overrun errors" messages and lots of retries
   before ftape finally decides to reduce the data rate.
-    In this case it might be desirable to tell ftape beforehand that
+  In this case it might be desirable to tell ftape beforehand that
   it need not try to run the tape drive at the highest available
   speed. If unsure, leave this disabled, i.e. leave it at 2000
   bits/sec.
@@ -5605,20 +6349,22 @@ CONFIG_APM
   USER RESUME operation, the /proc/apm device will provide battery
   status information, and user-space programs will receive
   notification of APM "events" (e.g., battery status
-  change). Supporting software can be gotten via ftp (user: anonymous)
-  from tsx-11.mit.edu/pub/linux/packages/laptops/apm/. This driver
-  does not spin down disk drives (see hdparm(8) for that); and it
-  doesn't turn off VESA-compliant "green" monitors.  This driver does
-  not support the TI 4000M TravelMate and the ACER 486/DX4/75 because
-  they don't have compliant BIOSes.  Many "green" desktop machines
-  also don't have compliant BIOSes, and this driver will cause those
-  machines to panic during the boot phase (typically, these machines
-  are using a data segment of 0040, which is reserved for the Linux
-  kernel). Generally, if you don't have a battery in your machine,
-  there isn't much point in using this driver and you should say N.
-  If you get random kernel OOPSes or reboots that don't seem to be
-  related to anything, try disabling/enabling this option. Some other
-  things to try when experiencing seemingly random, "weird" problems:
+  change). Supporting software is available; for more information,
+  read the Battery Powered Linux mini-HOWTO available via ftp (user:
+  anonymous) from sunsite.unc.edu:/pub/Linux/docs/HOWTO/mini.
+  This driver does not spin down disk drives (see hdparm(8) for that);
+  and it doesn't turn off VESA-compliant "green" monitors.  This
+  driver does not support the TI 4000M TravelMate and the ACER
+  486/DX4/75 because they don't have compliant BIOSes.  Many "green"
+  desktop machines also don't have compliant BIOSes, and this driver
+  will cause those machines to panic during the boot phase (typically,
+  these machines are using a data segment of 0040, which is reserved
+  for the Linux kernel). Generally, if you don't have a battery in
+  your machine, there isn't much point in using this driver and you
+  should say N.  If you get random kernel OOPSes or reboots that don't
+  seem to be related to anything, try disabling/enabling this
+  option. Some other things to try when experiencing seemingly random,
+  "weird" problems:
    1) passing the "no-hlt" option to the kernel 
    2) passing the "no-387" option to the kernel 
    3) passing the "floppy=nodma" option to the kernel
@@ -5674,8 +6420,13 @@ CONFIG_APM_DISPLAY_BLANK
 
 Power off on shutdown 
 CONFIG_APM_POWER_OFF
-  This option will power off the computer after the Linux kernel is halted
-  (e.g., with the halt(8) command).  As with the other APM options, this
+  Enable the ability to power off the computer after the Linux kernel
+  is halted.  You will need software (e.g., a suitable version of the
+  halt(8) command) to cause the computer to power down.  Recent
+  versions of the sysvinit package available from
+  ftp://sunsite.unc.edu/pub/Linux/system/daemons/init/ (user:
+  anonymous) contain support for this ("halt -p" shuts down Linux and
+  powers off the computer).  As with the other APM options, this
   option may not work reliably with some APM BIOS implementations.
 
 Watchdog Timer Support 
@@ -5766,7 +6517,7 @@ CONFIG_ACQUIRE_WDT
   inserted in and removed from the running kernel whenever you want).
   The module is called pscwdt.o. If you want to compile it as a module,
   say M here and read Documentation/modules.txt.  Most people will say N.
-  
+
 Enhanced Real Time Clock Support
 CONFIG_RTC
   If you say Y here and create a character special file /dev/rtc with
@@ -5782,6 +6533,13 @@ CONFIG_RTC
   have a use for such a device (such as periodic data sampling), then
   say Y here, and go read the file Documentation/rtc.txt for details.
 
+Tadpole ANA H8 Support
+CONFIG_H8
+  The Hitachi H8/337 is a microcontroller used to deal with the power
+  and thermal environment. If you say Y here, you will be able to
+  communicate with it via via a character special device. If unsure,
+  say N.
+
 /dev/nvram support
 CONFIG_NVRAM
   If you say Y here and create a character special file /dev/nvram
@@ -5802,18 +6560,17 @@ CONFIG_NVRAM
 
 PC joystick support
 CONFIG_JOYSTICK
-  If you have a PC compatible analog or digital joystick, you can
-  say Y here. If you then create a character special file under /dev
-  with major number 15 and minor number 0 or 1 (for the two joystick
-  ports) using mknod ("man mknod"), you can read the status of the
-  buttons and the x and y coordinates from that file. More
-  information, an example program and a calibration program are
-  contained in the joystick package which is available at:
-  ftp://sunsite.unc.edu/pub/Linux/kernel/patches/console
-  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 will be called joystick.o. If you want to compile it as a
-  module, say M here and read Documentation/modules.txt.
+  If you have a PC compatible analog or digital joystick, you can say
+  Y here. If you then create a character special file under /dev with
+  major number 15 and minor number 0 or 1 (for the two joystick ports)
+  using mknod ("man mknod"), you can read the status of the buttons
+  and the x and y coordinates from that file. Please read the file
+  Documentation/joystick.txt which contains more information and the
+  location of the joystick package that you'll need.  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 will
+  be called joystick.o. If you want to compile it as a module, say M
+  here and read Documentation/modules.txt.
 
 ARC console time
 CONFIG_RTC_ARC
@@ -5864,6 +6621,9 @@ CONFIG_ADLIB
   these cards may cause trouble (I don't currently know of any such
   cards, however).
 
+Loopback MIDI device support
+CONFIG_VMIDI
+
 Gravis Ultrasound support
 CONFIG_GUS
   Say Y here for any type of Gravis Ultrasound card, including
@@ -5937,14 +6697,15 @@ CONFIG_TRIX
   Answer Y if you have the AudioTriX Pro sound card manufactured
   by MediaTrix.
 
-Support for MAD16 and/or Mozart based cards
+Support for OPTi MAD16 and/or Mozart based cards
 CONFIG_MAD16
-  Answer Y if your card has a Mozart (OAK OTI-601) or MAD16
-  (OPTi 82C928 or 82C929) audio interface chip. These chips are
-  currently 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).
+  Answer Y if your card has a Mozart (OAK OTI-601) or MAD16 (OPTi
+  82C928 or 82C929 or 82C931) audio interface chip. For the 82C931,
+  please read drivers/sound/README.C931. These chips are currently
+  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).
 
 Support for Crystal CS4232 based (PnP) cards
 CONFIG_CS4232
@@ -5980,7 +6741,7 @@ CONFIG_SUN_AUDIO
 SB32/AWE support
 CONFIG_AWE32_SYNTH
   Say Y here if you have a SB32 or SB AWE soundcard. See
-  linux/drivers/sound/lowlevel/README.awe for more info.
+  drivers/sound/lowlevel/README.awe for more info.
 
 Additional low level drivers
 CONFIG_LOWLEVEL_SOUND
@@ -6002,23 +6763,23 @@ CONFIG_ACI_MIXER
 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 an SBPro or a Microsoft Sound System card, so you should
-  have said Y to either "SoundBlaster (SB, SBPro, SB16, clones)
+  can emulate either an SBPro or a Microsoft Sound System card, so you
+  should have said Y to either "SoundBlaster (SB, SBPro, SB16, clones)
   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
+  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.
+  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.
 
 SC-6600 based audio cards (new Audio Excel DSP 16)
 CONFIG_SC6600
-  The SC6600 is the new version of DSP mounted on the Audio Excel DSP 16
-  cards. Find in the manual the FCC ID of your audio card and answer Y if
-  you have an SC6600 DSP.
+  The SC6600 is the new version of DSP mounted on the Audio Excel DSP
+  16 cards. Find in the manual the FCC ID of your audio card and
+  answer Y if you have an SC6600 DSP.
 
 Audio Excel DSP 16 (MSS emulation)
 CONFIG_AEDSP16_MSS
@@ -6040,9 +6801,10 @@ CONFIG_PROFILE
   read it, you need the readprofile package from sunsite.unc.edu. Its
   manpage gives information regarding the format of profiling data. To
   become a kernel hacker, you can start with the Kernel Hacker's Guide
-  at http://www.redhat.com:8080/HyperNews/get/khg.html. Mere mortals
-  say N.
+  at http://www.redhat.com:8080/HyperNews/get/khg.html (to browse the
+  WWW, you need to have access to a machine on the Internet that has a
+  program like lynx or netscape). Mere mortals say N.
+
 Profile shift count
 CONFIG_PROFILE_SHIFT
   This is used to adjust the granularity with which the addresses of
@@ -6079,12 +6841,13 @@ CONFIG_ISDN
   emulator. Network devices support autodial, channel-bundling,
   callback and caller-authentication without having a daemon
   running. A reduced T.70 protocol is supported with tty's suitable
-  for German BTX. On D-Channel, the protocols EDSS1 and 1TR6 are
-  supported. See Documentation/isdn/README for more information.  If
-  you want to compile the ISDN 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 isdn.o.  If unsure, say N.
+  for German BTX. On D-Channel, the protocols EDSS1 (Euro-ISDN) and
+  1TR6 (German style) are supported. See Documentation/isdn/README for
+  more information.  If you want to compile the ISDN code 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 isdn.o.  If
+  unsure, say N.
 
 Support synchronous PPP
 CONFIG_ISDN_PPP
@@ -6199,7 +6962,7 @@ HiSax Support for US/NI-1
 CONFIG_HISAX_NI1
   You should choose the D-channel protocol your local
   telephone service provider uses here by saying Y or N.
-  
+
 HiSax Support for German 1TR6
 CONFIG_HISAX_1TR6
   You should choose the D-channel protocol your local
@@ -6226,21 +6989,25 @@ CONFIG_ISDN_DRV_SC
   can be inserted in and removed from the running kernel whenever you
   want, details in Documentation/modules.txt); the module will be
   called sc.o.  See Documentation/isdn/README.sc and
-  http://www.spellcast.com for more information.
+  http://www.spellcast.com for more information (to browse the WWW,
+  you need to have access to a machine on the Internet that has a
+  program like lynx or netscape).
 
 AVM-B1 with CAPI2.0 support
 CONFIG_ISDN_DRV_AVMB1
   This enables support for the AVM B1 ISDN networking cards. In
   addition, a CAPI (Common ISDN Application Programming Interface, a
   standard making it easy for programs to access ISDN hardware, see
-  http://www.capi.org/) interface for this card is provided. In order
-  to use this card, additional firmware is necessary, which has to be
-  downloaded into the card using a utility which is distributed
-  separately. Please read the file Documentation/isdn/README.avmb1.
-  This code 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 avmb1.o. If you want to compile it
-  as a module, say M here and read Documentation/modules.txt.
+  http://www.capi.org/; to browse the WWW, you need to have access to
+  a machine on the Internet that has a program like lynx or netscape)
+  interface for this card is provided. In order to use this card,
+  additional firmware is necessary, which has to be downloaded into
+  the card using a utility which is distributed separately. Please
+  read the file Documentation/isdn/README.avmb1.  This code 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 avmb1.o. If you want to compile it as a module, say M here
+  and read Documentation/modules.txt.
 
 Verbose reason code reporting (kernel size +=7K)
 CONFIG_ISDN_DRV_AVMB1_VERBOSE_REASON
@@ -6252,8 +7019,9 @@ Support for AP1000 multicomputer
 CONFIG_AP1000
   This enables support for a sparc based parallel multi-computer
   called AP1000+. For details on our efforts to port Linux to this
-  machine see http://cap.anu.edu.au/cap/projects/linux or mail to
-  hackers@cafe.anu.edu.au
+  machine see http://cap.anu.edu.au/cap/projects/linux (to browse the
+  WWW, you need to have access to a machine on the Internet that has a
+  program like lynx or netscape) or mail to hackers@cafe.anu.edu.au
 
 Sparc ESP SCSI support
 CONFIG_SCSI_SUNESP
@@ -6269,6 +7037,14 @@ CONFIG_SUN_OPENPROMIO
   removed from the running kernel whenever you want), say M and read
   Documentation/modules.txt. If unsure, say Y.
 
+Mostek real time clock support
+CONFIG_SUN_MOSTEK_RTC
+
+Siemens SAB82532 serial support
+CONFIG_SAB82532
+###
+### Please someone fill these in.
+###
 
 # m68k-specific kernel options
 # Documented by Chris Lawrence <quango@themall.net> et al.
@@ -6507,8 +7283,8 @@ CONFIG_BLZ1230_SCSI
 
 Fastlane SCSI support
 CONFIG_FASTLANE_SCSI
-  If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use one
-  in the near future, say Y to this question.  Otherwise, say N.
+  If you have the Phase5 Fastlane Z3 SCSI controller, or plan to use
+  one in the near future, say Y to this question.  Otherwise, say N.
 
 Atari native SCSI support
 CONFIG_ATARI_SCSI
@@ -6629,32 +7405,13 @@ CONFIG_ATARI_SCC
   whenever you want). If you want to compile it as a module, say M
   here and read Documentation/modules.txt.
 
-Radio support
-CONFIG_MISC_RADIO
-  If you have a radio card (you will probably know if you do!), then
-  you will want to say "y" here and make a character device file 
-  (usually /dev/radio) with major number 10 and minor 152 using mknod
-  ("man mknod").  And then, don't forget to pick up some useful tools
-  to use said device (you _might_ find something at ftp.lmh.ox.ac.uk:
-  /users/weejock/linux/radio/, but I haven't written anything too
-  useful yet...)
-
-AIMSlab RadioTrack card
-CONFIG_RADIO_RTRACK
-  Choose "y" here if you have one of these, and then fill in the port
-  address below.
-
-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.
-
 Atari SCC serial DMA support
 CONFIG_ATARI_SCC_DMA
-  This enables DMA support for receiving data on channel A of the SCC. If
-  you have a TT you may say Y here and read drivers/char/atari_SCC.README.
-  All other users should say N here, because only the TT has SCC-DMA, even
-  if your machine keeps claiming so at boot time.
+  This enables DMA support for receiving data on channel A of the
+  SCC. If you have a TT you may say Y here and read
+  drivers/char/atari_SCC.README.  All other users should say N here,
+  because only the TT has SCC-DMA, even if your machine keeps claiming
+  so at boot time.
 
 Atari MIDI serial support
 CONFIG_ATARI_MIDI
@@ -6760,7 +7517,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.
+  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
@@ -6778,7 +7538,11 @@ CONFIG_SCSI_MAC53C94
   On Power Macintoshes (and clones) with two SCSI buses, the external
   SCSI bus is usually controlled by a 53C94 SCSI bus adaptor.  Older
   machines which only have one SCSI bus, such as the 7200, also use
-  the 53C94.  Say Y to include support for the 53C94.
+  the 53C94.  Say Y to include support for the 53C94.  This driver is
+  also available as a module called mac53c94.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.
 
 MACE (Power Mac ethernet) support
 CONFIG_MACE
@@ -6788,14 +7552,37 @@ CONFIG_MACE
 
 Video For Linux
 CONFIG_VIDEO_DEV
-  Support for audio/video capture and overlay devices. The exact capabilities
-  of each device vary. User tools for this are available from
-  ftp://ftp.uk.linux.org/pub/linux/video4linux
+  Support for audio/video capture and overlay devices. The exact
+  capabilities of each device vary. User tools for this are available
+  from ftp://ftp.uk.linux.org/pub/linux/video4linux.  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 here and read
+  Documentation/modules.txt.
 
 BT848 Video For Linux
 CONFIG_VIDEO_BT848
-  Support for BT848 based frame grabber/overlay boards. This includes the 
-  Miro, Hauppauge and STB boards.
+  Support for BT848 based frame grabber/overlay boards. This includes
+  the Miro, Hauppauge and STB boards. This driver is
+  also available as a module called bttv.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.
+
+Quickcam BW Video For Linux
+CONFIG_VIDEO_BWQCAM
+  Say Y have if you have such a thing. This driver is also available
+  as a module called bw-qcam.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.
+
+Mediavision Pro Movie Studio Video For Linux
+CONFIG_VIDEO_PMS
+  Say Y if you have such a thing. This driver is also available as a
+  module called pms.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.
 
 # need an empty line after last entry, for sed script in Configure.
 
@@ -6924,18 +7711,36 @@ CONFIG_VIDEO_BT848
 # LocalWords:  zorro CAPI AVMB capi avmb VP SYN syncookies EM em pc Ethertalk
 # LocalWords:  Dayna DL Daynatalk LT PhoneNET ATB Daystar queueing CMDS SCBs ls
 # LocalWords:  SCB STATS Thinnet ThunderLAN TLAN Netelligent NetFlex tlan james
-# LocalWords:  caldera Preload dcache Preloading slowdowns schoebel uni
-# LocalWords:  stuttgart rdist TRANS hostnames mango jukeboxes ESS
+# LocalWords:  caldera Preload dcache Preloading slowdowns schoebel uni NBD nbd
+# LocalWords:  stuttgart rdist TRANS hostnames mango jukeboxes ESS userland PD
 # 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 SCB's RX
 # LocalWords:  dataless kerneltype SYSNAME Netbeui Comtrol Rocketport palmtop
 # LocalWords:  nvram SYSRQ SysRq PrintScreen sysrq NVRAMs NvRAM Shortwave RTTY
 # LocalWords:  HFMODEM shortwave Sitor Amtor Pactor GTOR hfmodem hayes TX TMOUT
-# LocalWords:  QIC TR CONFIG FTAPE Iomega CMS FC FDC Exabyte Iomega's DFLT
-# LocalWords:  tapedrive THR FCD IRQ DMA SZ PCI ftape README txt HOWTO
-# LocalWords:  http www rwth aachen LBFM claus FAQ mt ZFTAPE VFS
-# LocalWords:  zftape zft William's lzrw kerneld BLK zftape's tar's
-# LocalWords:  afio's MTSETBLK MTIOCTOP dev qft setblk BLKSZ NR
-# LocalWords:  setdrvbuffer kb NUMBUFFERS Procfs PROC FS proc resp STD
-# LocalWords:  Alt LocalWords
+# LocalWords:  IDEPCI IDEDMA idedma PDC pdc TRM trm raidtools luthien nuclecu
+# LocalWords:  unam mx miguel koobera uic EMUL solaris pp ieee lpsg co DMAs TOS
+# LocalWords:  BLDCONFIG preloading jumperless BOOTINIT modutils multipath GRE
+# LocalWords:  misconfigured autoconfiguration IPGRE ICMP tracert ipautofw PIM
+# LocalWords:  netis rlynch autofw ipportfw monmouth ipsubs portforwarding pimd
+# LocalWords:  portfw PIMSM netweb usc pim pf EUI aggregatable PB decapsulate
+# LocalWords:  ipddp Decapsulation DECAP bool HAMRADIO WAN's tcpdump af CD's tx
+# LocalWords:  ethertap multisession PPC MMIO GDT GDTH ICP gdth hamradio LAN's
+# LocalWords:  lmh weejock AIMSlab RadioTrack RTRACK HZP OptoSCC TRX rx TRXECHO
+# LocalWords:  DMASCC paccomm dmascc addr cfg oevsv oe kib picpar FDX baudrate
+# LocalWords:  baudrates fdx HDX hdx PSK kanren frforum QoS SCHED CBQ SCH sched
+# LocalWords:  sch cbq CSZ Shenker Zhang csz SFQ sfq TBF tbf PFIFO fifo PRIO RW
+# LocalWords:  prio Micom xIO dwmw rimi OMIRR omirr omirrd unicode ntfs cmu
+# LocalWords:  Braam braam Schmidt's freiburg nls codepages codepage Romanian
+# LocalWords:  Slovak Slovenian Sorbian Nordic iso Catalan Faeroese Galician SZ
+# LocalWords:  Valencian Slovene Esperanto Estonian Latvian Byelorussian KOI mt
+# LocalWords:  charset Inuit Greenlandic Sami Lappish koi SOFTCURSOR softcursor
+# LocalWords:  Specialix specialix DTR RTS RTSCTS cycladesZ Exabyte ftape's
+# LocalWords:  Iomega's LBFM claus ZFTAPE VFS zftape zft William's lzrw DFLT kb
+# LocalWords:  MTSETBLK MTIOCTOP qft setblk zftape's tar's afio's setdrvbuffer
+# LocalWords:  Procfs Exabyte's THR FCD sysvinit init PSC pscwdt VMIDI Euro SAB
+# LocalWords:  Mostek Fastlane PowerMac PReP PMAC PowerPC Macintoshes Starmax
+# LocalWords:  PowerStack Starmaxes MCOMMON DEVICETREE ATY IMS IMSTT videodev
+# LocalWords:  BT Hauppauge STB bttv Quickcam BW BWQCAM bw qcam Mediavision PMS
+# LocalWords:  pms
index fee4a7e6630335669f5d0a8397e206fd7bb554ca..c8b428bf19171724cf081fed3731a249ec1e8771 100644 (file)
@@ -2,8 +2,6 @@
        - this file (info on CD-ROMs and Linux)
 aztcd
        - info on Aztech/Orchid/Okano/Wearnes/Conrad/CyCDROM driver.
-bpcd
-       - info on MicroSolutions backpack CDROM 
 
 cdrom-standard.tex
        - LaTeX document on standardizing the CD-ROM programming interface.
diff --git a/Documentation/cdrom/bpcd b/Documentation/cdrom/bpcd
deleted file mode 100644 (file)
index 877d7fe..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-linux/Documentation/cdrom/bpcd (c) 1996  Grant R. Guenther <grant@torque.net>
-
-This file documents the bpcd driver for the MicroSolutions backpack CDrom,
-an external parallel port device.  
-
-There are apparently two versions of the backpack protocol.  This 
-driver knows about the version 2 protocol - as is used in the 4x 
-and 6x products.  There is no support for the sound hardware that
-is included in some models.  It should not be difficult to add 
-support for the ATAPI audio play functions and the corresponding 
-ioctls.
-
-The driver was developed by reverse engineering the protocol
-and testing it on the backpack model 164550.  This model
-is actually a stock ATAPI drive packaged with a custom 
-ASIC that implements the IDE over parallel protocol.
-I tested with a backpack that happened to contain a Goldstar
-drive, but I've seen reports of Sony and Mitsumi drives as well.
-
-Before attempting to use the driver, you will need to
-create a new device special file.  The following commands will
-do that for you:
-
-               mknod /dev/bpcd b 41 0
-               chown root:disk /dev/bpcd
-               chmod 660 /dev/bpcd
-
-Afterward, you can mount a disk in the usual way:
-
-               mount -t iso9660 /dev/bpcd /cdrom
-
-(assuming you have made a directory /cdrom to use as a mount point).
-
-The driver will attempt to detect which parallel port your
-backpack is connected to.  If this fails for any reason, you
-can override it by specifying a port on the LILO command line
-(for built in drivers) or the insmod command (for drivers built
-as modules).   If your drive is on the port at 0x3bc, you would
-use one of these commands:
-
-               LILO:      bpcd=0x3bc
-
-               insmod:    insmod bpcd bp_base=0x3bc
-
-The driver can detect if the parallel port supports 8-bit
-transfers.  If so, it will use them.  You can force it to use
-4-bit (nybble) mode by setting the variable bp_nybble to 1 on
-an insmod command, or using the following LILO parameters:
-
-               bpcd=0x3bc,1
-
-(you must specify the correct port address if you use this method.)
-
-There is currently no support for EPP or ECP modes.  Also,
-as far as I can tell, the MicroSolutions protocol does not
-support interrupts in the 4-bit and 8-bit modes.
-
-MicroSolutions' protocol allows for several drives to be
-chained together off the same parallel port.  Currently, this
-driver will recognise only one of them.  If you do have more
-than one drive, it will choose the one with the lowest id number,
-where the id number is the last two digits of the product's
-serial number.
-
-It is not currently possible to connect a printer to the chained
-port on the BackPack and expect Linux to use both devices at once.
-If you need to use this driver together with a printer on the
-same port, build both the bpcd and lp drivers as modules.
-
-Keep an eye on http://www.torque.net/bpcd.html for news and
-other information about the driver.  If you have any problems
-with this driver, please send me, grant@torque.net, some mail 
-directly before posting into the newsgroups or mailing lists.
-
index 6f1af1c18261cb3f8328118adc24c592b412e311..1db560b158a03ccf82f7792954cbdcb464619e10 100644 (file)
@@ -1,5 +1,5 @@
 \documentclass{article}
-\def\version{$Id: cdrom-standard.tex,v 1.8 1997/11/19 21:58:33 david Exp $}
+\def\version{$Id: cdrom-standard.tex,v 1.9 1997/12/28 15:42:49 david Exp $}
 \newcommand{\newsection}[1]{\newpage\section{#1}}
 
 \evensidemargin=0pt
@@ -388,46 +388,6 @@ CDS_DISC_OK& a disc is loaded and everything is fine\cr
 }
 $$
 
-\subsection{$Disc_status$}
-\label{disc status}
-
-As a complement to $drive_status()$, this function can provide {\emph
-{some}} information about the current disc that is inserted in the
-drive. This function is now implemented internally in the \UCD, so the
-low-level drivers do not need to implement this functionality anymore.
-
-The history of development of the CD's use as a carrier medium for
-various digital information has lead to many different disc types. This
-$ioctl$ makes the false assumption that CDs have {\emph {only one}} type
-of data on them. While this is often the case, it is also very common
-for CDs to have some tracks with data, and some tracks with audio.
-Because this is an existing interface, rather than fixing this interface
-by changing the assumptions it was made under, thereby breaking all user
-applications that use this function, the \UCD\ implements this $ioctl$
-as follows: If the CD in question has audio tracks on it, and it has
-absolutly no CD-I, XA, or data tracks on it, it will be reported as
-$CDS_AUDIO$. Failing that, if the CD in question has any CD-I tracks
-on it, it will be reported as $CDS_XA_2_2$. Failing that, if the CD in
-question has any XA tracks on it, it will be reported as $CDS_XA_2_1$.
-Finally, if the CD in question has any data tracks on it, it will be
-reported as a data CD ($CDS_DATA_1$). 
-
-This function can return:
-$$
-\halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
-CDS_NO_INFO& no information available\cr
-CDS_NO_DISC& no disc is inserted, or tray is opened\cr
-CDS_AUDIO& Audio disc (2352 audio bytes/frame)\cr
-CDS_DATA_1& data disc, mode 1 (2048 user bytes/frame)\cr
-CDS_DATA_2& data disc, mode 2 (2336 user bytes/frame)\cr
-CDS_XA_2_1& mixed data (XA), mode 2, form 1 (2048 user bytes)\cr
-CDS_XA_2_2& mixed data (XA), mode 2, form 1 (2324  user bytes)\cr
-}
-$$
-As far as I know, data \cdrom s are always of type $CDS_DATA_1$. For
-some information concerning frame layout of the various disc types, see
-a recent version of \cdromh. 
-
 \subsection{$Int\ media_changed(struct\ cdrom_device_info * cdi, int\ disc_nr)$}
 
 This function is very similar to the original function in $struct\ 
@@ -940,8 +900,46 @@ the current flags.
   given. The special value $CDSL_CURRENT$ requests that information
   about the currently selected slot is returned.
 \item[CDROM_DISC_STATUS] Returns the type of the disc currently in the
-  drive by a call to $disc_status()$. Return values are as defined in
-  section~\ref{disc status}.
+  drive.  It should be viewed as a complement to $CDROM_DRIVE_STATUS$.
+  This $ioctl$ can provide \emph {some} information about the current
+  disc that is inserted in the drive.  This functionality used to be
+  implemented in the low level drivers, but is now carried out
+  entirely in \UCD.
+  
+  The history of development of the CD's use as a carrier medium for
+  various digital information has lead to many different disc types.
+  This $ioctl$ is useful only in the case that CDs have \emph {only
+    one} type of data on them.  While this is often the case, it is
+  also very common for CDs to have some tracks with data, and some
+  tracks with audio.  Because this is an existing interface, rather
+  than fixing this interface by changing the assumptions it was made
+  under, thereby breaking all user applications that use this
+  function, the \UCD\ implements this $ioctl$ as follows: If the CD in
+  question has audio tracks on it, and it has absolutly no CD-I, XA,
+  or data tracks on it, it will be reported as $CDS_AUDIO$.  If it has
+  both audio and data tracks, it will return $CDS_MIXED$.  If there
+  are no audio tracks on the disc, and if the CD in question has any
+  CD-I tracks on it, it will be reported as $CDS_XA_2_2$.  Failing
+  that, if the CD in question has any XA tracks on it, it will be
+  reported as $CDS_XA_2_1$.  Finally, if the CD in question has any
+  data tracks on it, it will be reported as a data CD ($CDS_DATA_1$).
+
+  This $ioctl$ can return:
+  $$
+  \halign{$#$\ \hfil&$/*$ \rm# $*/$\hfil\cr
+    CDS_NO_INFO& no information available\cr
+    CDS_NO_DISC& no disc is inserted, or tray is opened\cr
+    CDS_AUDIO& Audio disc (2352 audio bytes/frame)\cr
+    CDS_DATA_1& data disc, mode 1 (2048 user bytes/frame)\cr
+    CDS_DATA_2& data disc, mode 2 (2336 user bytes/frame)\cr
+    CDS_XA_2_1& mixed data (XA), mode 2, form 1 (2048 user bytes)\cr
+    CDS_XA_2_2& mixed data (XA), mode 2, form 1 (2324  user bytes)\cr
+    CDS_MIXED& mixed audio/data disc\cr
+    }
+  $$
+  For some information concerning frame layout of the various disc
+  types, see a recent version of \cdromh.
+
 \item[CDROM_CHANGER_NSLOTS] Returns the number of slots in a
   juke-box. 
 \end{description}
@@ -1021,4 +1019,3 @@ the first place.
 $ \version\ $
 \eject
 \end{document}
-
diff --git a/Documentation/ez.txt b/Documentation/ez.txt
deleted file mode 100644 (file)
index 9fb314e..0000000
+++ /dev/null
@@ -1,85 +0,0 @@
-linux/Documentation/ez.txt (c) 1996  Grant R. Guenther <grant@torque.net>
-
-This file documents the ez driver for the parallel port versions of 
-SyQuest's EZ135 and EZ230 removable media disk drives.  
-        
-Special thanks go to Pedro Soria-Rodriguez for his help testing 
-the EZFlyer 230 support.
-
-The drive is actually SyQuest's IDE product with a ShuttleTech 
-IDE <-> parallel converter chip built in.
-
-Before attempting to access the new driver, you will need to
-create some device special files.  The following commands will
-do that for you:
-
-                mknod /dev/eza  b 40 0
-                mknod /dev/eza1 b 40 1
-                mknod /dev/eza2 b 40 2
-                mknod /dev/eza3 b 40 3
-                mknod /dev/eza4 b 40 4
-                chown root:disk /dev/ez*
-                chmod 660 /dev/ez*
-
-You can make devices for more partitions (up to 15) if you need to.
-
-You can alter certain driver parameters on the LILO or LOADLIN 
-command line.  The general syntax is
-
-               ez=base[,irq]
-
-where base is the base address of the parallel port you want to use 
-and irq is the interrupt number for that port.   By default, the 
-driver uses the ports at 0x378 and irq 7.  You can disable the 
-interrupt by specifying it as 0.  For example, to run the driver 
-on port 0x3bc without an interrupt, you would append the following 
-to the LILO command line:
-
-               ez=0x3bc,0
-
-If you have configured the driver as a loadable module, you can 
-adjust these parameters on the insmod command line using the 
-variables ez_base and ez_irq.  For example:
-
-                insmod ez ez_base=0x3bc
-
-The driver can detect if the parallel port supports 8-bit
-transfers.  If so, it will use them.
-
-The driver can be used with or without interrupts.  If an IRQ
-is specified the driver will use it - if it can. If the irq 
-number is set to 0, an alternative, polling-based, strategy 
-will be used.  Polling consumes more CPU time, but may be more 
-stable on some systems.
-
-If you experience timeout errors while using this driver - and
-you have enabled interrupts - try disabling the interrupt.  I
-have heard reports of some parallel ports having exceptionally
-unreliable interrupts.  This could happen on misconfigured 
-systems in which an inactive sound card shares the same IRQ with 
-the parallel port. (Remember that most people do not use the
-parallel port interrupt for printing.)
-
-It would be advantageous to use multiple mode transfers,
-but ShuttleTech's driver does not appear to use them, so I'm not
-sure that the converter can handle it.
-
-It is not currently possible to connect a printer to the chained
-port on an EZ drive and expect Linux to use both devices at once.
-If you need to do this, build both the ez and lp drivers as modules
-and load one or the other as required.
-
-When the EZ230 powers on, the "standby timer" is set to about 6
-minutes:  if the drive is idle for that length of time, it will
-put itself into a low power standby mode.  It takes a couple of
-seconds for the drive to come out of standby mode.  So, if you
-load this driver while it is in standby mode, you will notice
-a "freeze" of a second or two as the driver waits for the EZ230
-to come back to life.  Once loaded, this driver disables the
-standby timer (until you next power up the EZ230 ...)
-
-Keep an eye on http://www.torque.net/ez135.html for news and
-other information about the driver.  If you have any problems
-with this driver, please send me, grant@torque.net, some mail 
-directly before posting into the newsgroups or mailing lists.
-
index ace34450c78495980f152610fd577f781dfacdbd..b637da0a40a723d8dff2d6660129a355b56ea5fe 100644 (file)
@@ -60,7 +60,6 @@ Here is a sample of the available modules included in the kernel sources:
                aztcd:     Aztech,Orchid,Okano,Wearnes
                cm206:     Philips/LMS CM206
                gscd:      Goldstar GCDR-420
-               bpcd:      MicroSolutions backpack CDrom
                mcd, mcdx: Mitsumi LU005, FX001
                optcd:     Optics Storage Dolphin 8000AT
                sjcd:      Sanyo CDR-H94A
index 9e2d73169129e2849470d30534a63ad44f0cc350..60deb1771bd3f7702b7e70ee61c34ac55206a01b 100644 (file)
@@ -4,14 +4,14 @@ Written by: Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
 Introduction
 ============
 
-       Linux Socket Filtering is a deviation of the Berkely
+       Linux Socket Filtering is derived from the Berkeley
 Packet Filter. There are some distinct differences between
 the BSD and Linux Kernel Filtering.
 
 Linux Socket Filtering (LSF) allows a user-space program to
 attach a filter onto any socket and allow or disallow certain
 types of data to come through the socket. LSF follows exactly
-the same filter code structure as the BSD Berkely Packet Filter
+the same filter code structure as the BSD Berkeley Packet Filter
 (BPF), so refering to the BSD bpf.4 manpage is very helpful in
 creating filters.
 
@@ -39,4 +39,4 @@ setsockopt(sockfd, SOL_SOCKET, SO_ATTACH_FILTER, &Filter, sizeof(Filter));
 setsockopt(sockfd, SOL_SOCKET, SO_DETACH_FILTER, &value, sizeof(value));
 
 See the BSD bpf.4 manpage and the BSD Packet Filter paper written by
-Steven McCanne and Van Jacobson of Lawrence Berkely Laboratory.
+Steven McCanne and Van Jacobson of Lawrence Berkeley Laboratory.
diff --git a/Documentation/paride.txt b/Documentation/paride.txt
new file mode 100644 (file)
index 0000000..1a6b464
--- /dev/null
@@ -0,0 +1,338 @@
+
+               Linux and parallel port IDE devices
+
+PARIDE v1.0   (c) 1997  Grant Guenther <grant@torque.net>
+
+1. Introduction
+
+Owing to the simplicity and near universality of the parallel port interface
+to personal computers, many external devices such as portable hard-disk,
+CD-ROM, LS-120 and tape drives use the parallel port to connect to their
+host computer.  While some devices (notably scanners) use ad-hoc methods
+to pass commands and data through the parallel port interface, most 
+external devices are actually identical to an internal model, but with
+a parallel-port adapter chip added in.  Some of the original parallel port
+adapters were little more than mechanisms for mulitplexing a SCSI bus.
+(The Iomega PPA-3 adapter used in the ZIP drives is an example of this
+approach).  Most current designs, however, take a different approach.
+The adapter chip reproduces a small ISA or IDE bus in the external device
+and the communication protocol provides operations for reading and writing
+device registers, as well as data block transfer functions.  Sometimes,
+the device being addressed via the parallel cable is a standard SCSI
+controller like an NCR 5380.  The "ditto" family of external tape
+drives use the ISA replicator to interface a floppy disk controller,
+which is then connected to a floppy-tape mechanism.  The vast majority
+of external parallel port devices, however, are now based on standard
+IDE type devices, which require no intermediate controller.  If one
+were to open up a parallel port CD-ROM drive, for instance, one would
+find a standard ATAPI CD-ROM drive, a power supply, and a single adapter
+that interconnected a standard PC parallel port cable and a standard
+IDE cable.  It is usually possible to exchange the CD-ROM device with
+any other device using the IDE interface. 
+
+The document describes the support in Linux for parallel port IDE
+devices.  It does not cover parallel port SCSI devices, "ditto" tape
+drives or scanners.  Many different devices are supported by the 
+parallel port IDE subsystem, including:
+
+       MicroSolutions backpack CD-ROM
+       MicroSolutions backpack PD/CD
+       MicroSolutions backpack hard-drives
+       SyQuest EZ-135, EZ-230 & SparQ drives
+       Avatar Shark
+       Imation Superdisk LS-120
+       FreeCom Power CD
+       Hewlett-Packard 5GB tape drive
+
+as well as most of the clone and no-name products on the market.
+
+To support such a wide range of devices, PARIDE, the parallel port IDE
+subsystem, is actually structured in three parts.   There is a base
+paride module which provides a registry and some common methods for
+accessing the parallel ports.  The second component is a set of 
+high-level drivers for each of the different type of supported device: 
+
+       pd      IDE disk
+       pcd     ATAPI CD-ROM
+       pf      ATAPI disk
+       pt      ATAPI tape      (not yet available)
+
+(Support for ATAPI CD-R and CD-RW drives is not yet in development,
+but this may change.)
+
+The high-level drivers function according to the relevant standards.
+The third component of PARIDE is a set of low-level protocol drivers
+for each of the parallel port IDE adapter chips.  Thanks to the interest
+and encouragement of Linux users from many parts of the world, 
+support is available for almost all known adapter protocols:
+
+        aten    ATEN EH-100                            (HK)
+        bpck    Microsolutions backpack                (US)
+        comm    DataStor (old-type) "commuter" adapter (TW)
+        dstr    DataStor EP-2000                       (TW)
+        epat    Shuttle EPAT                           (UK)
+        epia    Shuttle EPIA                           (UK)
+        frpw    Freecom Power                          (DE)
+        kbic    KingByte KBIC-951A and KBIC-971A       (TW)
+        on20    OnSpec 90c20                           (US)
+        on26    OnSpec 90c26                           (US)
+
+(A driver for some modes of the Noveca RAP// protocol is also under 
+development).  
+
+
+2. Using the PARIDE subsystem
+
+While configuring the Linux kernel, you may choose either to build
+the PARIDE drivers into your kernel, or to build them as modules.
+
+In either case, you will need to select "Parallel port IDE device support"
+as well as at least one of the high-level drivers and at least one
+of the parallel port communication protocols.  If you do not know
+what kind of parallel port adapter is used in your drive, you could
+begin by checking the file names and any text files on your DOS 
+installation floppy.  Alternatively, you can look at the markings on
+the adapter chip itself.  That's usually sufficient to identify the
+correct device.  
+
+You can actually select all the protocol modules, and allow the PARIDE
+subsystem to try them all for you.
+
+For the "brand-name" products listed above, here are the protocol
+and high-level drivers that you would use:
+
+       Manufacturer            Model           Driver  Protocol
+       
+       MicroSolutions          CD-ROM          pcd     bpck
+       MicroSolutions          PD drive        pf      bpck
+       MicroSolutions          hard-drive      pd      bpck
+       SyQuest                 EZ, SparQ       pd      epat
+       Imation                 Superdisk       pf      epat
+       Avatar                  Shark           pd      epat
+       FreeCom                 CD-ROM          pcd     frpw
+       Hewlett-Packard         5GB Tape        pt      epat
+
+2.1  Configuring built-in drivers
+
+We recommend that you get to know how the drivers work and how to
+configure them as loadable modules, before attempting to compile a
+kernel with the drivers built-in.
+
+If you built all of your PARIDE support directly into your kernel,
+and you have just a single parallel port IDE device, your kernel should
+locate it automatically for you.  If you have more than one device,
+you may need to give some command line options to your bootloader
+(eg: LILO), how to do that is beyond the scope of this document.
+
+The high-level drivers accept a number of command line parameters, all
+of which are documented in the source files in linux/drivers/block/paride.
+By default, each driver will automatically try all parallel ports it
+can find, and all protocol types that have been installed, until it finds
+a parallel port IDE adapter.  Once it finds one, the probe stops.  So,
+if you have more than one device, you will need to tell the drivers
+how to identify them.  This requires specifying the port address, the
+protocol identification number and, for some devices, the drive's
+chain ID.  While your system is booting, a number of messages are
+displayed on the console.  Like all such messages, they can be
+reviewed with the 'dmesg' command.  Among those messages will be
+some lines like:
+
+       paride: bpck registered as protocol 0
+       paride: epat registered as protocol 1
+
+The numbers will always be the same until you build a new kernel with
+different protocol selections.  You should note these numbers as you
+will need them to identify the devices.
+
+If you happen to be using a MicroSolutions backpack device, you will
+also need to know the unit ID number for each drive.  This is usually
+the last two digits of the drive's serial number (but read MicroSolution's
+documentation about this).
+
+As an example, lets assume that you have a MicroSolutions PD/CD drive
+with unit ID number 36 connected to the parallel port at 0x378, a SyQuest 
+EZ-135 connected to the chained port on the PD/CD drive and also an 
+Imation Superdisk connected to port 0x278.  You could give the following 
+options on your boot command:
+
+       pd.drive0=0x378,1 pf.drive0=0x278,1 pf.drive1=0x378,0,36
+
+In the last option, pf.drive1 configures device /dev/pf1, the 0x378
+is the parallel port base address, the 0 is the protocol registration
+number and 36 is the chain ID.
+
+Please note:  while PARIDE will work both with and without the 
+PARPORT parallel port sharing system that is included by the
+"Parallel port support" option, PARPORT must be included and enabled
+if you want to use chains of devices on the same parallel port.
+
+2.2  Loading and configuring PARIDE as modules
+
+It is much faster and simpler to get to understand the PARIDE drivers
+if you use them as loadable kernel modules.   
+
+Note 1:  using these drivers with the "kerneld" automatic module loading
+system is not recommended, and is not documented here.  
+
+Note 2:  if you build PARPORT support as a loadable module, PARIDE must
+also be built as loadable modules, and PARPORT must be loaded before the
+PARIDE modules.
+
+To use PARIDE, you must begin by 
+
+       insmod paride
+
+this loads a base module which provides a registry for the protocols,
+among other tasks.
+
+Then, load as many of the protocol modules as you think you might need.
+As you load each module, it will register the protocols that it supports,
+and print a log message to your kernel log file and your console. For 
+example:
+
+       # insmod epat
+       paride: epat registered as protocol 0
+       # insmod kbic
+       paride: k951 registered as protocol 1
+        paride: k971 registered as protocol 2
+
+Finally, you can load high-level drivers for each kind of device that
+you have connected.  By default, each driver will autoprobe for a single 
+device, but you can support up to four similar devices by giving their
+individual co-ordinates when you load the driver.
+
+For example, if you had two no-name CD-ROM drives both using the
+KingByte KBIC-951A adapter, one on port 0x378 and the other on 0x3bc
+you could give the following command:
+
+       # insmod pcd drive0=0x378,1 drive1=0x3bc,1
+
+For most adapters, giving a port address and protocol number is sufficient,
+but check the source files in linux/drivers/block/paride for more 
+information.  (Hopefully someone will write some man pages one day !).
+
+As another example, here's what happens when PARPORT is installed, and
+a SyQuest EZ-135 is attached to port 0x378:
+
+       # insmod paride
+       paride: version 1.0 installed
+       # insmod epat
+       paride: epat registered as protocol 0
+       # insmod pd
+       pd: pd version 1.0, major 45, cluster 64, nice 0
+       pda: Sharing parport1 at 0x378
+       pda: epat 1.0, Shuttle EPAT chip c3 at 0x378, mode 5 (EPP-32), delay 1
+       pda: SyQuest EZ135A, 262144 blocks [128M], (512/16/32), removable media
+        pda: pda1
+
+Note that the last line is the output from the generic partition table
+scanner - in this case it reports that it has found a disk with one partition.
+
+2.3  Using a PARIDE device
+
+Once the drivers have been loaded, you can access PARIDE devices in the
+same way as their traditional counterparts.  You will probably need to
+create the device "special files".  Here is a simple script that you can
+cut to a file and execute:
+
+#!/bin/bash
+#
+# mkd -- a script to create the device special files for the PARIDE subsystem
+#
+function mkdev {
+  mknod $1 $2 $3 $4 ; chmod 0660 $1 ; chown root:disk $1
+}
+#
+function pd {
+  D=$( printf \\$( printf "x%03x" $[ $1 + 97 ] ) )
+  mkdev pd$D b 45 $[ $1 * 16 ]
+  for P in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
+  do mkdev pd$D$P b 45 $[ $1 * 16 + $P ]
+  done
+}
+#
+cd /dev
+#
+for u in 0 1 2 3 ; do pd $u ; done
+for u in 0 1 2 3 ; do mkdev pcd$u b 46 $u ; done 
+for u in 0 1 2 3 ; do mkdev pf$u  b 47 $u ; done 
+for u in 0 1 2 3 ; do mkdev pt$u  c 96 $u ; done 
+for u in 0 1 2 3 ; do mkdev npt$u c 96 $[ $u + 128 ] ; done 
+#
+# end of mkd
+
+With the device files and drivers in place, you can access PARIDE devices
+like any other Linux device.   For example, to mount a CD-ROM in pcd0, use:
+
+       mount /dev/pcd0 /cdrom
+
+If you have a fresh Avatar Shark cartridge, and the drive is pda, you
+might do something like:
+
+       fdisk /dev/pda          -- make a new partition table with
+                                  partition 1 of type 83
+
+       mke2fs /dev/pda1        -- to build the file system
+
+       mkdir /shark            -- make a place to mount the disk
+
+       mount /dev/pda1 /shark
+
+Devices like the Imation superdisk work in the same way, except that
+they do not have a partition table.  For example to make a 120MB
+floppy that you could share with a DOS system:
+
+       mkdosfs /dev/pf0
+       mount /dev/pf0 /mnt
+
+
+3. Troubleshooting
+
+While a lot of testing has gone into these drivers to make them work
+as smoothly as possible, problems will arise.  If you do have problems,
+please check all the obvious things first:  does the drive work in
+DOS with the manufacturer's drivers ?  If that doesn't yield any useful
+clues, then please make sure that only one drive is hooked to your system,
+and that either (a) PARPORT is enabled or (b) no other device driver
+is using your parallel port (check in /proc/ioports).  Then, load the
+appropriate drivers (you can load several protocol modules if you want)
+as in:
+
+       # insmod paride
+       # insmod epat
+       # insmod bpck
+       # insmod kbic
+       ...
+       # insmod pd verbose=1
+
+(using the correct driver for the type of device you have, of course).
+The verbose=1 parameter will cause the drivers to log a trace of their
+activity as they attempt to locate your drive.
+
+Use 'dmesg' to capture a log of all the PARIDE messages (any messages
+beginning with paride:, a protocol module's name or a driver's name) and
+include that with your bug report.  You can submit a bug report in one
+of two ways.  Either send it directly to the author of the PARIDE suite,
+by e-mail to grant@torque.net, or join the linux-parport mailing list
+and post your report there.
+
+You can join the linux-parport mailing list by sending a mail message
+to 
+               linux-parport-request@torque.net
+
+with the single word 
+
+               subscribe
+
+in the body of the mail message (not in the subject line).   Please be
+sure that your mail program is correctly set up when you do this,  as
+the list manager is a robot that will subscribe you using the reply
+address in your mail headers.  REMOVE any anti-spam gimmicks you may
+have in your mail headers, when sending mail to the list server.
+
+You might also find some useful information on the linux-parport
+web pages (although they are not always up to date) at
+
+       http://www.torque.net/linux-pp.html
+
+
index 9dc4686e6276517754e90474b6f670c86194db5e..ecb8612f45691219e8b819e5a93f617e139d097d 100644 (file)
@@ -511,6 +511,13 @@ W: http://www.cyberelk.demon.co.uk/parport.html
 W:     http://www.cage.curtin.edu.au/~campbell/parbus/
 S:     Maintained
 
+PARIDE DRIVERS FOR PARALLEL PORT IDE DEVICES
+P:     Grant Guenther
+M:     grant@torque.net
+L:     linux-parport@torque.net
+W:     http://www.torque.net/linux-pp.html
+S:     Maintained
+
 PNP SUPPORT
 P:     Tom Lees
 M:     tom@lpsg.demon.co.uk
index 784b71c1fbdd1c1d1ffcb7b85dd5272115cc18bf..52af638e4e6547b05922655289ce06d8e8a0a482 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,6 +1,6 @@
 VERSION = 2
 PATCHLEVEL = 1
-SUBLEVEL = 76
+SUBLEVEL = 77
 
 ARCH := $(shell uname -m | sed -e s/i.86/i386/ -e s/sun4u/sparc64/)
 
@@ -157,6 +157,10 @@ ifdef CONFIG_PNP
 DRIVERS := $(DRIVERS) drivers/pnp/pnp.a
 endif
 
+ifeq ($(CONFIG_PARIDE),y)
+DRIVERS := $(DRIVERS) drivers/block/paride/paride.a
+endif
+
 ifdef CONFIG_HAMRADIO
 DRIVERS := $(DRIVERS) drivers/net/hamradio/hamradio.a
 endif
@@ -346,10 +350,10 @@ clean:    archclean
 
 mrproper: clean
        rm -f include/linux/autoconf.h include/linux/version.h
-       rm -f drivers/net/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h
-       rm -f drivers/net/soundmodem/sm_tbl_{hapn4800,psk4800}.h
-       rm -f drivers/net/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h
-       rm -f drivers/net/soundmodem/gentbl
+       rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk1200,afsk2666,fsk9600}.h
+       rm -f drivers/net/hamradio/soundmodem/sm_tbl_{hapn4800,psk4800}.h
+       rm -f drivers/net/hamradio/soundmodem/sm_tbl_{afsk2400_7,afsk2400_8}.h
+       rm -f drivers/net/hamradio/soundmodem/gentbl
        rm -f drivers/char/hfmodem/gentbl drivers/char/hfmodem/tables.h
        rm -f drivers/sound/*_boot.h drivers/sound/.*.boot
        rm -f .version .config* config.in config.old
index e64b6d5e1eadd7aa6d78fe005737f7f45b8d53f7..be985d2b78b9fcf206bbe9e10041ed48af751f79 100644 (file)
@@ -966,7 +966,7 @@ static inline long get_it32(struct itimerval *o, struct itimerval32 *i)
 
 static inline long put_it32(struct itimerval32 *o, struct itimerval *i)
 {
-       return (!access_ok(VERIFY_WRITE, i, sizeof(*i)) ||
+       return (!access_ok(VERIFY_WRITE, o, sizeof(*o)) ||
                (__put_user(i->it_interval.tv_sec, &o->it_interval.tv_sec) |
                 __put_user(i->it_interval.tv_usec, &o->it_interval.tv_usec) |
                 __put_user(i->it_value.tv_sec, &o->it_value.tv_sec) |
@@ -1241,7 +1241,7 @@ asmlinkage int osf_wait4(pid_t pid, int *ustatus, int options,
  * seems to be a timeval pointer, and I suspect the second
  * one is the time remaining.. Ho humm.. No documentation.
  */
-asmlinkage int osf_usleep_thread(struct timeval *sleep, struct timeval *remain)
+asmlinkage int osf_usleep_thread(struct timeval32 *sleep, struct timeval32 *remain)
 {
        struct timeval tmp;
        unsigned long ticks;
index 11310bd494b01a58a08ebba58096f642a8848239..0384031a8da40a18a7f9108092ac402e1a152472 100644 (file)
@@ -274,6 +274,8 @@ loader_ok:
 
 oldstylemem:
        pop     ebx
+#else
+       mov     dword ptr [0x1e0], #0
 #endif
        mov     ah,#0x88
        int     0x15
index f5de6e1a44937abcab6ba1f7944834f8ca2914fd..d21db83e17c8a06d705d2189651fdf6147131cb0 100644 (file)
@@ -73,7 +73,8 @@ CONFIG_BLK_DEV_IDEDMA=y
 # CONFIG_BLK_DEV_MD is not set
 # CONFIG_BLK_DEV_RAM is not set
 # CONFIG_BLK_DEV_XD is not set
-# CONFIG_BLK_DEV_EZ is not set
+CONFIG_PARIDE_PARPORT=y
+# CONFIG_PARIDE is not set
 # CONFIG_BLK_DEV_HD is not set
 
 #
@@ -240,10 +241,6 @@ CONFIG_LOCKD=y
 CONFIG_AUTOFS_FS=y
 # CONFIG_UFS_FS is not set
 # CONFIG_MAC_PARTITION is not set
-
-#
-# Native Language Support
-#
 # CONFIG_NLS is not set
 
 #
@@ -269,6 +266,7 @@ CONFIG_82C710_MOUSE=y
 # CONFIG_RTC is not set
 # CONFIG_VIDEO_DEV is not set
 # CONFIG_VIDEO_BT848 is not set
+# CONFIG_VIDEO_BWQCAM is not set
 # CONFIG_VIDEO_PMS is not set
 # CONFIG_NVRAM is not set
 # CONFIG_JOYSTICK is not set
index e08d7510022047ed09db0b395f1d2bd8bb4fd87a..4623f9100ae284a86fe3a9f59bd5c25206cd182b 100644 (file)
@@ -611,7 +611,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                          child->tss.i387.hard.twd = 0xffffffff;
                        }
 #ifdef CONFIG_MATH_EMULATION
-                       if ( hard_math ) {
+                       if ( boot_cpu_data.hard_math ) {
 #endif
                          if (last_task_used_math == child) {
                            clts();
@@ -639,7 +639,7 @@ asmlinkage int sys_ptrace(long request, long pid, long addr, long data)
                          }
                        child->used_math = 1;
 #ifdef CONFIG_MATH_EMULATION
-                       if ( hard_math ) {
+                       if ( boot_cpu_data.hard_math ) {
 #endif
                          if (last_task_used_math == child) {
                            /* Discard the state of the FPU */
index 3c321a83e10b5ef92fe75c7504f06aac423d6cc4..2ed384eeeb2cd94f612556169b6df4c723765df1 100644 (file)
@@ -416,7 +416,7 @@ static void setup_frame(int sig, struct k_sigaction *ka,
        {
                unsigned long seg = __USER_DS;
                __asm__("mov %w0,%%fs ; mov %w0,%%gs": "=r"(seg) : "0"(seg));
-               set_fs(MAKE_MM_SEG(seg));
+               set_fs(USER_DS);
                regs->xds = seg;
                regs->xes = seg;
                regs->xss = seg;
@@ -488,7 +488,7 @@ static void setup_rt_frame(int sig, struct k_sigaction *ka, siginfo_t *info,
        {
                unsigned long seg = __USER_DS;
                __asm__("mov %w0,%%fs ; mov %w0,%%gs": "=r"(seg) : "0"(seg));
-               set_fs(MAKE_MM_SEG(seg));
+               set_fs(USER_DS);
                regs->xds = seg;
                regs->xes = seg;
                regs->xss = seg;
index b4c5062d59ed57183fc0a66381e91a169d55c631..038492cad95168ede2d1c63706351be116a26a5e 100644 (file)
@@ -25,6 +25,7 @@
  *             Alan Cox        :       Dumb bug: 'B' step PPro's are fine
  *             Ingo Molnar     :       Added APIC timers, based on code
  *                                     from Jose Renau
+ *             Alan Cox        :       Added EBDA scanning
  */
 
 #include <linux/kernel.h>
@@ -924,7 +925,7 @@ __initfunc(void smp_boot_cpus(void))
        if (!max_cpus)
        {
                smp_found_config = 0;
-               printk("SMP mode deactivated, forcing use of dummy APIC emulation.\n");
+               printk(KERN_INFO "SMP mode deactivated, forcing use of dummy APIC emulation.\n");
        }
 
        /*
@@ -1063,7 +1064,7 @@ __initfunc(void smp_boot_cpus(void))
                        if(cpu_present_map&(1<<i))
                                bogosum+=cpu_data[i].loops_per_sec;
                }
-               printk("Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
+               printk(KERN_INFO "Total of %d processors activated (%lu.%02lu BogoMIPS).\n",
                        cpucount+1,
                        (bogosum+2500)/500000,
                        ((bogosum+2500)/5000)%100);
index b8f4742e937c2c27bb5cf27e52c0c944654783f4..fc7ad28ea500c154035e79a09729a0b6ee62bfe6 100644 (file)
@@ -178,14 +178,21 @@ __initfunc(unsigned long paging_init(unsigned long start_mem, unsigned long end_
                 *      the error...
                 */
                if (!smp_scan_config(639*0x400,0x400))  /* Scan the top 1K of base RAM */
-                       smp_scan_config(0xF0000,0x10000);       /* Scan the 64K of bios */
+               {
+                       if(!smp_scan_config(0xF0000,0x10000))   /* Scan the 64K of bios */
+                       {
+                               /*
+                                *      If it is an SMP machine we should know now, unless the configuration
+                                *      is in an EISA/MCA bus machine with an extended bios data area. 
+                                */
+                
+                               address = *(unsigned short *)phys_to_virt(0x40E); /* EBDA */
+                               address<<=4;    /* Real mode segments to physical */
+                               smp_scan_config(address, 0x1000);       /* Scan the EBDA */
+                       }
+               }
        }
-       /*
-        *      If it is an SMP machine we should know now, unless the configuration
-        *      is in an EISA/MCA bus machine with an extended bios data area. I don't
-        *      have such a machine so someone else can fill in the check of the EBDA
-        *      here.
-        */
+                       
 /*     smp_alloc_memory(8192); */
 #endif
        start_mem = PAGE_ALIGN(start_mem);
index b76e9af08e49b7f3956f888c93ef480a17d855ea..0597ea3d677c8e05ac416ef5b236d4f219047da4 100644 (file)
@@ -27,9 +27,11 @@ else
       if [ "$CONFIG_BLK_DEV_IDEPCI" = "y" ]; then
         bool '     Generic PCI bus-master DMA support' CONFIG_BLK_DEV_IDEDMA
         if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-          bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
           bool '     OPTi 82C621 chipset enhanced support (EXPERIMENTAL)' CONFIG_BLK_DEV_OPTI621
-          bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
+          if [ "$CONFIG_BLK_DEV_IDEDMA" = "y" ]; then
+            bool '     Tekram TRM290 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_TRM290
+            bool '     NS87415 chipset support (EXPERIMENTAL)' CONFIG_BLK_DEV_NS87415
+          fi
         fi
       fi
     fi
@@ -68,7 +70,16 @@ if [ "$CONFIG_BLK_DEV_RAM" = "y" ]; then
   bool '   Initial RAM disk (initrd) support' CONFIG_BLK_DEV_INITRD
 fi
 tristate 'XT harddisk support' CONFIG_BLK_DEV_XD
-tristate 'SyQuest EZ parallel port disk support' CONFIG_BLK_DEV_EZ
+
+if [ "$CONFIG_PARPORT" = "y" -o "$CONFIG_PARPORT" = "n" ] ; then
+   define_bool CONFIG_PARIDE_PARPORT y
+else
+   define_bool CONFIG_PARIDE_PARPORT m
+fi
+dep_tristate 'Parallel port IDE device support' CONFIG_PARIDE $CONFIG_PARIDE_PARPORT
+if [ "$CONFIG_PARIDE" != "n" ]; then
+  source drivers/block/paride/Config.in
+fi
 
 if [ "$CONFIG_BLK_DEV_HD_IDE" = "y" -o "$CONFIG_BLK_DEV_HD_ONLY" = "y" ]; then
   define_bool CONFIG_BLK_DEV_HD y
index f992a98a5bbf64a5ca0ba72892c86c86e5ba0957..22f5daebd55608b1cc9f962052905f3595bf5038 100644 (file)
 # In the future, some of these should be built conditionally.
 #
 
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS) paride
+
 
 L_TARGET := block.a
 L_OBJS   := ll_rw_blk.o genhd.o
@@ -191,14 +195,6 @@ else
   endif
 endif
 
-ifeq ($(CONFIG_BLK_DEV_EZ),y)
-L_OBJS += ez.o
-else
-  ifeq ($(CONFIG_BLK_DEV_EZ),m)
-  M_OBJS += ez.o
-  endif
-endif
-
 ifeq ($(CONFIG_BLK_DEV_MD),y)
 LX_OBJS += md.o
 
@@ -244,4 +240,13 @@ else
   endif
 endif
 
+ifeq ($(CONFIG_PARIDE),y)
+SUB_DIRS       += paride
+MOD_SUB_DIRS   += paride
+else
+  ifeq ($(CONFIG_PARIDE),m)
+  MOD_SUB_DIRS += paride
+  endif
+endif
+
 include $(TOPDIR)/Rules.make
diff --git a/drivers/block/ez.c b/drivers/block/ez.c
deleted file mode 100644 (file)
index 6c2960a..0000000
+++ /dev/null
@@ -1,1022 +0,0 @@
-/* 
-       ez.c    (c) 1996  Grant R. Guenther <grant@torque.net>
-                         Under the terms of the GNU public license.
-
-       This is a driver for the parallel port versions of SyQuest's 
-        EZ135 and EZ230 removable media disk drives.  
-        
-        Special thanks go to Pedro Soria-Rodriguez for his help testing 
-       the EZFlyer 230 support.
-
-       The drive is actually SyQuest's IDE product with a
-        ShuttleTech IDE <-> parallel converter chip built in.
-
-       To compile the driver, ensure that /usr/include/linux and
-        /usr/include/asm are links to the correct include files for 
-        the target system. Then compile the driver with 
-
-               cc -D__KERNEL__ -DMODULE -O2 -c ez.c
-
-        If you are using MODVERSIONS, add the following to the cc command:
-
-               -DMODVERSIONS -I /usr/include/linux/modversions.h
-
-       You must then load it with insmod.
-
-       Before attempting to access the new driver, you will need to
-        create some device special files.  The following commands will
-       do that for you:
-
-               mknod /dev/eza  b 40 0
-               mknod /dev/eza1 b 40 1
-               mknod /dev/eza2 b 40 2
-               mknod /dev/eza3 b 40 3
-               mknod /dev/eza4 b 40 4
-               chown root:disk /dev/ez*
-               chmod 660 /dev/ez*
-
-       You can make devices for more partitions (up to 15) if you need to.
-
-       You can alter the port used by the driver in two ways:  either
-        change the definition of EZ_BASE or modify the ez_base variable
-        on the insmod command line, for example:
-
-               insmod ez ez_base=0x3bc
-
-       The driver can detect if the parallel port supports 8-bit
-        transfers.  If so, it will use them.  You can force it to use
-        4-bit (nybble) mode by setting the variable ez_nybble to 1.
-
-       The driver can be used with or without interrupts.  If an IRQ
-        is specified in the variable ez_irq, the driver will use it.
-        If ez_irq is set to 0, an alternative, polling-based, strategy 
-       will be used.
-
-       If you experience timeout errors while using this driver - and
-        you have enabled interrupts - try disabling the interrupt.  I
-        have heard reports of some parallel ports having exceptionally
-        unreliable interrupts.  This could happen on misconfigured 
-        systems in which an inactive sound card shares the same IRQ with 
-        the parallel port. (Remember that most people do not use the
-        parallel port interrupt for printing.)
-
-       It would be advantageous to use multiple mode transfers,
-        but ShuttleTech's driver does not appear to use them, so I'm not
-        sure that the converter can handle it.
-
-       It is not currently possible to connect a printer to the chained
-        port on the EZ135p and expect Linux to use both devices at once.
-
-       When the EZ230 powers on, the "standby timer" is set to about 6
-        minutes:  if the drive is idle for that length of time, it will
-        put itself into a low power standby mode.  It takes a couple of
-        seconds for the drive to come out of standby mode.  So, if you
-        load this driver while it is in standby mode, you will notice
-        a "freeze" of a second or two as the driver waits for the EZ230
-        to come back to life.  Once loaded, this driver disables the
-        standby timer (until you next power up the EZ230 ...)
-
-       Keep an eye on http://www.torque.net/ez135.html for news and
-        other information about the driver.  If you have any problems
-        with this driver, please send me, grant@torque.net, some mail 
-        directly before posting into the newsgroups or mailing lists.
-
-*/
-
-#define        EZ_VERSION      "0.11"
-
-#define        EZ_BASE         0x378
-#define EZ_IRQ         7
-#define EZ_REP         4
-
-#include <linux/module.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/tqueue.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/genhd.h>
-#include <linux/hdreg.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#define EZ_BITS           4                    /* compatible with SCSI version */
-#define EZ_MAJOR   40                  /* as assigned by hpa */
-
-#define MAJOR_NR EZ_MAJOR
-
-/* set up defines for blk.h,  why don't all drivers do it this way ? */
-
-#define DEVICE_NAME "ez"
-#define DEVICE_REQUEST do_ez_request
-#define DEVICE_NR(device) (MINOR(device)>>EZ_BITS)
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-
-#include <linux/blk.h>
-
-#define EZ_PARTNS  (1<<EZ_BITS)
-
-#define EZ_LOG_HEADS   64              
-#define EZ_LOG_SECTS   32              /* SCSI compatible logical geometry */
-
-#define EZ_SIGOFF      54
-#define EZ_SIG         "ySuQse tZE"
-#define EZ_SIGLEN      10
-#define EZ_ID_LEN      14
-
-#define EZ_TMO         250             /* interrupt timeout in jiffies */
-
-#define EZ_SPIN_DEL     50             /* spin delay in micro-seconds  */
-
-#define EZ_SPIN                (10000/EZ_SPIN_DEL)*EZ_TMO  
-#define EZ_ISPIN       (10000/EZ_SPIN_DEL)*20
-#define EZ_DELAY        udelay(EZ_SPIN_DEL)
-
-#define STAT_ERR       0x00001
-#define STAT_INDEX     0x00002
-#define STAT_ECC       0x00004
-#define STAT_DRQ       0x00008
-#define STAT_SEEK      0x00010
-#define STAT_WRERR     0x00020
-#define STAT_READY     0x00040
-#define STAT_BUSY      0x00080
-
-#define ERR_AMNF       0x00100
-#define ERR_TK0NF      0x00200
-#define ERR_ABRT       0x00400
-#define ERR_MCR                0x00800
-#define ERR_IDNF       0x01000
-#define ERR_MC         0x02000
-#define ERR_UNC                0x04000
-#define ERR_TMO                0x10000
-
-#define IDE_READ       0x20
-#define IDE_WRITE      0x30
-#define IDE_STANDBY     0x96
-#define IDE_DOORLOCK   0xde
-#define IDE_DOORUNLOCK  0xdf
-#define IDE_ACKCHANGE   0xdb
-#define IDE_IDENTIFY    0xec
-
-int ez_init(void);
-void ez_setup(char * str, int * ints);
-#ifdef MODULE
-void cleanup_module( void );
-#endif
-static void ez_geninit(struct gendisk *ignored);
-static int ez_open(struct inode *inode, struct file *file);
-static void do_ez_request(void);
-static int ez_ioctl(struct inode *inode,struct file *file,
-                    unsigned int cmd, unsigned long arg);
-static int ez_release (struct inode *inode, struct file *file);
-static int ez_revalidate(kdev_t dev);
-static int ez_check_media(kdev_t dev);
-static void ez_get_capacity( void );
-static int ez_detect(void);
-static void do_ez_read(void);
-static void do_ez_write(void);
-static void ez_media_check(void);
-static void ez_doorlock(int func);
-static void ez_interrupt( int irq, void * dev_id, struct pt_regs * regs);
-static void ez_pseudo( void *data);
-static void ez_timer_int( unsigned long data);
-static void do_ez_read_drq( void );
-static void do_ez_write_done( void );
-
-static struct hd_struct ez[EZ_PARTNS];
-static int ez_sizes[EZ_PARTNS];
-static int ez_blocksizes[EZ_PARTNS];
-
-static int     ez_base = EZ_BASE;
-static int      ez_irq = EZ_IRQ;
-static int     ez_rep = EZ_REP;
-static int     ez_nybble = 0;          /* force 4-bit mode ? */
-
-static int ez_valid = 0;               /* OK to open */
-static int ez_access = 0;              /* count of active opens ... */
-static int ez_changed = 0;             /* Did we see new media on open ? */
-static int ez_capacity = 512*16*32;     /* Size of this volume in sectors */
-static int ez_heads = 16;              /* physical geometry */
-static int ez_sectors = 32;
-static int ez_mode = 1;                        /* 4- or 8-bit mode */
-static int ez_loops = 0;               /* counter for pseudo-interrupts */
-static int ez_timeout = 0;             /* did the interrupt time out ? */
-static int ez_int_seen = 0;            /* have we ever seen an interrupt ? */
-static int ez_busy = 0;                        /* request being processed ? */
-static int ez_block;                   /* address of next requested block */
-static int ez_count;                   /* number of blocks still to do */
-static char * ez_buf;                  /* buffer for request in progress */
-static char ez_scratch[512];           /* scratch block buffer */
-static void (*ez_continuation)(void);  /* i/o completion handler */
-
-char   *ez_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR",
-                        "READY","BUSY","AMNF","TK0NF","ABRT","MCR",
-                        "IDNF","MC","UNC","???","TMO"};
-
-static struct tq_struct ez_tq = {0,0,ez_pseudo,NULL};
-static struct timer_list ez_timer = {0,0,0,0,ez_timer_int};
-static struct wait_queue *ez_wait_open = NULL;
-
-/* kernel glue structures */
-
-static struct gendisk ez_gendisk = {
-       MAJOR_NR,       /* Major number */
-       "ez",           /* Major name */
-       EZ_BITS,        /* Bits to shift to get real from partition */
-       EZ_PARTNS,      /* Number of partitions per real */
-       1,              /* maximum number of real */
-       ez_geninit,     /* init function */
-       ez,             /* hd struct */
-       ez_sizes,       /* block sizes */
-       0,              /* number */
-        NULL,          /* internal */
-       NULL            /* next */
-};
-
-static struct file_operations ez_fops = {
-       NULL,                   /* lseek - default */
-       block_read,             /* read - general block-dev read */
-       block_write,            /* write - general block-dev write */
-       NULL,                   /* readdir - bad */
-       NULL,                   /* select */
-       ez_ioctl,               /* ioctl */
-       NULL,                   /* mmap */
-       ez_open,                /* open */
-       ez_release,             /* release */
-       block_fsync,            /* fsync */
-       NULL,                   /* fasync */
-       ez_check_media,         /* media change ? */
-       ez_revalidate           /* revalidate new media */
-};
-
-__initfunc(int ez_init (void)) /* preliminary initialisation */
-
-{      
-       if (register_blkdev(MAJOR_NR,"ez",&ez_fops)) {
-               printk("ez_init: unable to get major number %d\n",MAJOR_NR);
-               return -1;
-       }
-       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-       read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
-       ez_gendisk.next = gendisk_head;
-       gendisk_head = &ez_gendisk;
-
-       return 0;
-}
-
-__initfunc(static void ez_geninit (struct gendisk *ignored))    /* real init */
-
-{      int i;
-
-       ez_gendisk.nr_real = 0;
-       
-       if (ez_detect()) {
-               ez_busy = 0;
-               ez_valid = 1;
-               ez_gendisk.nr_real = 1;
-               ez[0].nr_sects = ez_capacity;
-               for(i=0;i<EZ_PARTNS;i++) ez_blocksizes[i] = 1024;
-               blksize_size[MAJOR_NR] = ez_blocksizes;
-       } 
-#ifdef MODULE
-         else cleanup_module();
-#endif
-}
-
-static int ez_open (struct inode *inode, struct file *file)
-
-{      int dev = DEVICE_NR(inode->i_rdev);
-
-       if (dev >= ez_gendisk.nr_real) return -ENODEV;
-
-       MOD_INC_USE_COUNT;
-
-       while (!ez_valid) sleep_on(&ez_wait_open);
-       ez_access++;
-       ez_media_check();
-       ez_doorlock(IDE_DOORLOCK);
-       return 0;
-}
-
-static void do_ez_request (void)
-
-{       int    dev;
-
-       if (ez_busy) return;
-repeat:
-       if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
-       INIT_REQUEST;
-
-       dev = MINOR(CURRENT->rq_dev);
-       ez_block = CURRENT->sector;
-       ez_count = CURRENT->nr_sectors;
-
-       if ((dev >= EZ_PARTNS) || ((ez_block+ez_count) > ez[dev].nr_sects)) {
-               end_request(0);
-               goto repeat;
-       }
-
-       ez_block += ez[dev].start_sect;
-       ez_buf = CURRENT->buffer;
-
-       if (CURRENT->cmd == READ) do_ez_read();
-       else if (CURRENT->cmd == WRITE) do_ez_write();
-       else {  end_request(0);
-               goto repeat;
-       }
-}
-
-static int ez_ioctl(struct inode *inode,struct file *file,
-                   unsigned int cmd, unsigned long arg)
-
-{      struct hd_geometry *geo = (struct hd_geometry *) arg;
-       int dev, err;
-
-       if ((!inode) || (!inode->i_rdev)) return -EINVAL;
-       dev = MINOR(inode->i_rdev);
-       if (dev >= EZ_PARTNS) return -EINVAL;
-
-       switch (cmd) {
-           case HDIO_GETGEO:
-               if (!geo) return -EINVAL;
-               err = verify_area(VERIFY_WRITE,geo,sizeof(*geo));
-               if (err) return err;
-               put_user(ez_capacity/(EZ_LOG_HEADS*EZ_LOG_SECTS),
-                        (short *) &geo->cylinders);
-               put_user(EZ_LOG_HEADS, (char *) &geo->heads);
-               put_user(EZ_LOG_SECTS, (char *) &geo->sectors);
-               put_user(ez[dev].start_sect,(long *)&geo->start);
-               return 0;
-           case BLKRASET:
-               if(!suser()) return -EACCES;
-               if(!(inode->i_rdev)) return -EINVAL;
-               if(arg > 0xff) return -EINVAL;
-               read_ahead[MAJOR(inode->i_rdev)] = arg;
-               return 0;
-            case BLKRAGET:
-               if (!arg) return -EINVAL;
-               err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
-               if (err) return (err);
-               put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
-               return (0);
-           case BLKGETSIZE:
-               if (!arg) return -EINVAL;
-               err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
-               if (err) return (err);
-               put_user(ez[dev].nr_sects,(long *) arg);
-               return (0);
-           case BLKFLSBUF:
-               if(!suser())  return -EACCES;
-               if(!(inode->i_rdev)) return -EINVAL;
-               fsync_dev(inode->i_rdev);
-               invalidate_buffers(inode->i_rdev);
-               return 0;
-           case BLKRRPART:
-               return ez_revalidate(inode->i_rdev);
-           RO_IOCTLS(inode->i_rdev,arg);
-           default:
-               return -EINVAL;
-       }
-}
-
-static int ez_release (struct inode *inode, struct file *file)
-
-{      kdev_t devp;
-
-       devp = inode->i_rdev;
-       if (DEVICE_NR(devp) == 0)  {
-               fsync_dev(devp);
-               invalidate_inodes(devp);
-               invalidate_buffers(devp);
-               ez_access--;
-               if (!ez_access) ez_doorlock(IDE_DOORUNLOCK);
-               MOD_DEC_USE_COUNT;
-       }
-       return 0;
-}
-
-static int ez_check_media( kdev_t dev)
-
-{       int    t;
-
-       t = ez_changed;
-       ez_changed = 0;
-       return t;
-}
-
-static int ez_revalidate(kdev_t dev)
-
-{      int p;
-       long flags;
-       kdev_t devp;
-
-       save_flags(flags);
-       cli(); 
-       if (ez_access > 1) {
-               restore_flags(flags);
-               return -EBUSY;
-       }
-       ez_valid = 0;
-       restore_flags(flags);   
-
-       for (p=(EZ_PARTNS-1);p>=0;p--) {
-               devp = MKDEV(MAJOR_NR, p);
-               fsync_dev(devp);
-               invalidate_inodes(devp);
-               invalidate_buffers(devp);
-               ez[p].start_sect = 0;
-               ez[p].nr_sects = 0;
-       }
-
-       ez_get_capacity();
-       ez[0].nr_sects = ez_capacity;
-       resetup_one_dev(&ez_gendisk,0);
-
-       ez_valid = 1;
-       wake_up(&ez_wait_open);
-
-       return 0;
-}
-
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-void   cleanup_module(void);
-
-int    init_module(void)
-
-{      int     err;
-       long    flags;
-
-       save_flags(flags);
-       cli();
-
-       err = ez_init();
-       if (err) {
-           restore_flags(flags);
-           return err;
-       }
-       ez_geninit(&ez_gendisk);
-
-       if (!ez_gendisk.nr_real) {
-               restore_flags(flags);
-               return -1;
-       }
-
-       ez_valid = 0;
-       resetup_one_dev(&ez_gendisk,0);
-       ez_valid = 1;
-
-       restore_flags(flags);
-       return 0;
-}
-
-void   cleanup_module(void)
-
-{      struct gendisk **gdp;
-       long flags;
-
-       save_flags(flags);
-       cli();
-
-       unregister_blkdev(MAJOR_NR,"ez");
-
-       for(gdp=&gendisk_head;*gdp;gdp=&((*gdp)->next))
-               if (*gdp == &ez_gendisk) break;
-       if (*gdp) *gdp = (*gdp)->next;
-
-       if (ez_gendisk.nr_real) {
-               release_region(ez_base,3);
-               if (ez_irq) free_irq(ez_irq,NULL);
-       }
-
-       restore_flags(flags);
-}
-
-#else 
-
-/* ez_setup:  process lilo command parameters ...
-
-   syntax:     ez=base[,irq[,rep[,nybble]]]
-*/
-
-__initfunc(void ez_setup(char *str, int *ints))
-
-{       if (ints[0] > 0) ez_base = ints[1];
-        if (ints[0] > 1) ez_irq = ints[2];
-        if (ints[0] > 2) ez_rep = ints[3];
-        if (ints[0] > 3) ez_nybble = ints[4];
-} 
-
-#endif
-
-/* Now the actual hardware interface to the EZ135p */
-
-static void    out_p( short port, char byte)
-
-{       int i;
-
-       for(i=0;i<ez_rep;i++) outb(byte,ez_base+port);
-}
-
-static int     in_p( short port)
-
-{       int i;
-       char c;
-
-       c=inb(ez_base+port);
-       for(i=1;i<ez_rep;i++) c=inb(ez_base+port);
-       return c & 0xff;
-}
-
-#define w0(byte)  out_p(0,byte)
-#define w2(byte)  out_p(2,byte)
-#define r0()      (in_p(0) & 0xff)
-#define r1()      (in_p(1) & 0xff)
-
-/*  register access functions */
-
-static int read_regr( char regr )
-
-{      int h, l;
-
-       if (ez_mode == 1) {     /* nybble mode */
-           w0(regr);
-           w2(1); w2(3);
-           l = r1() >> 4;
-           w2(4);
-           h = r1() & 0xf0;
-           return h + l;
-       } else {                /* byte mode */
-           w0(regr+0x20);
-           w2(1); w2(0x25);
-           h = r0();
-           w2(4);
-           return h;
-       }
-}      
-
-static void write_regr( char regr, char val )
-
-{      w0(regr);
-       w2(1);
-       w0(val);
-       w2(4);
-}
-
-/* connect / disconnect code */
-
-static void prefix( char byte )
-
-{      w2(4); w0(0x22); w0(0xaa); w0(0x55); w0(0); 
-       w0(0xff); w0(0x87); w0(0x78); w0(byte);
-        w2(5); w2(4); w0(0xff); 
-}
-
-static void connect ( void  )
-
-{      prefix(0x40); prefix(0x50); prefix(0xe0);
-        w0(0); w2(1); w2(4);
-       read_regr(0xd);
-       write_regr(0x6d,0xe8);
-       write_regr(0x6c,0x1c);
-       write_regr(0x72,0x10);
-       write_regr(0x6a,0x38);
-       write_regr(0x68,0x10);
-       read_regr(0x12);
-       write_regr(0x72,0x10);
-       read_regr(0xd);
-       write_regr(0x6d,0xaa);
-       write_regr(0x6d,0xaa);
-}
-
-static void disconnect ( void )
-
-{      read_regr(0xd);
-       write_regr(0x6d,0xa8);
-       prefix(0x30);
-} 
-
-/* basic i/o */
-
-static void read_block( char * buf )
-
-/* the nybble mode read has a curious optimisation in it: there are actually
-   five bits available on each read.  The extra bit is used to signal that
-   the next nybble is identical ...  I wonder how much research went into
-   designing this use of the extra bit ?
-*/
-
-{      int     j, k, n0, n1, n2, n3;
-
-       read_regr(0xd); write_regr(0x6d,0xe9);
-
-       j = 0;
-       if (ez_mode == 1) {             /* nybble mode */
-
-           w0(7); w2(1); w2(3); w0(0xff);
-           for(k=0;k<256;k++) {
-               w2(6); n0 = r1();
-               if (n0 & 8) n1 = n0; else { w2(4); n1 = r1(); }
-               w2(7); n2 = r1();
-               if (n2 & 8) n3 = n2; else { w2(5); n3 = r1(); }
-               buf[j++] = (n0 >> 4) + (n1 & 0xf0);
-               buf[j++] = (n2 >> 4) + (n3 & 0xf0);
-           }
-
-       } else {                        /* byte mode */
-
-           w0(0x27); w2(1); w2(0x25); w0(0);
-           for(k=0;k<256;k++) {
-               w2(0x24); buf[j++] = r0();
-                       w2(0x25); buf[j++] = r0();
-           }
-           w2(0x26); w2(0x27); w0(0); w2(0x25); w2(4);
-
-       }
-}
-
-static void write_block( char * buf )
-
-{      int     j;
-
-       read_regr(0xd); write_regr(0x6d,0xe9);
-
-       w0(0x67); w2(1); w2(5);
-       for(j=0;j<256;j++) {
-               w0(buf[2*j]); w2(4);
-               w0(buf[2*j+1]); w2(5);
-       }
-       w2(7); w2(4);
-}
-
-/*  ide command interface */
-
-void   ez_print_error( char * msg, int status )
-
-{      char    *e, *p;
-        int    i;
-
-       e = ez_scratch;
-       for(i=0;i<18;i++) if (status & (1<<i)) {
-               p = ez_errs[i];
-               while ((*e++=*p++));
-               *(e-1) = ' ';
-       }
-       if (status) e--;
-       *e = 0;
-       printk("ez: %s: status = 0x%x (%s)\n",msg,status,ez_scratch);
-}
-
-static int wait_for( int w, char * msg )    /* polled wait */
-
-{      int     k, r, e;
-
-       k=0;
-       while(k < EZ_SPIN) { 
-           r = read_regr(0x1f);
-            k++;
-           if (ez_timeout) break;
-           if (((r & w) == w) && !(r & STAT_BUSY)) break;
-           EZ_DELAY;
-       }
-       e = (read_regr(0x19)<<8) + r;
-       if ((k >= EZ_SPIN) || ez_timeout) e |= (ERR_TMO|STAT_ERR);
-       if ((e & STAT_ERR) & (msg != NULL)) ez_print_error(msg,e);
-       return e;
-}
-
-static void send_command( int n, int s, int h, int c0, int c1, int func )
-
-{
-       read_regr(0xd); write_regr(0x6d,0xa9);
-
-       write_regr(0x76,0);             
-       write_regr(0x79,0);     /* the IDE task file */
-       write_regr(0x7a,n);
-       write_regr(0x7b,s);
-       write_regr(0x7c,c0);
-       write_regr(0x7d,c1);
-       write_regr(0x7e,0xa0+h);
-       write_regr(0x7f,func);
-
-       udelay(1);
-}
-
-static void ez_ide_command( int func, int block )
-
-{      int c1, c0, h, s;
-
-       s  = ( block % ez_sectors) + 1;
-       h  = ( block / ez_sectors) % ez_heads;
-       c0 = ( block / (ez_sectors*ez_heads)) % 256;
-       c1 = ( block / (ez_sectors*ez_heads*256));
-
-       send_command(1,s,h,c0,c1,func);
-}
-
-static void ez_gate_intr( int flag )
-
-{      if (flag) write_regr(0x6d,0x39);  /* gate interrupt line to bus */
-       if (flag && ez_irq) w2(0x14);     /* enable IRQ */
-       if (!flag) w2(4);                 /* disable IRQ */
-}
-
-static int check_int( void )   /* is the interrupt bit set  ?  */
-
-{      return (r1() & 0x40);
-}
-
-static void ez_doorlock( int func )
-
-{      connect();
-       if (wait_for(STAT_READY,"Lock") & STAT_ERR) {
-               disconnect();
-               return;
-       }
-       ez_ide_command(func,0);
-       wait_for(STAT_READY,"Lock done");
-       disconnect();
-}
-
-/* ez_media_check: check for and acknowledge the MC flag */
-
-__initfunc(static void ez_media_check( void ))
-
-{      int r;
-
-       ez_changed = 0;
-       connect();
-       r = wait_for(STAT_READY,"Media check ready");
-       if (!(r & STAT_ERR)) {
-               ez_ide_command(IDE_READ,0);  /* try to read block 0 */
-               r = wait_for(STAT_DRQ,"Media check");
-               if (!(r & STAT_ERR)) read_block(ez_scratch);
-       } else ez_changed = 1;   /* say changed if other error */
-       if (r & ERR_MC) {
-               ez_changed = 1;
-               ez_ide_command(IDE_ACKCHANGE,0);
-               wait_for(STAT_READY,"Ack. media change");
-       }
-       disconnect();
-}
-
-__initfunc(static int ez_identify( void ))
-
-
-{      int     k, r;
-
-       connect();
-       wait_for(0,NULL);  /* wait until not busy, quietly */
-       ez_ide_command(IDE_IDENTIFY,0);
-
-       if (ez_irq) {                   /* check that the interrupt works */
-               ez_gate_intr(1);
-               k = 0;
-               while ((k++ < EZ_ISPIN) && !ez_int_seen) EZ_DELAY;
-               ez_gate_intr(0);
-               r = read_regr(0x1f);
-               if ((!ez_int_seen) || !(r & STAT_DRQ)) {
-                       free_irq(ez_irq,NULL);
-                       ez_irq = 0;
-               }
-       }
-
-        if (wait_for(STAT_DRQ,NULL) & STAT_ERR) {
-               disconnect();
-               return 0;
-       }
-       read_block(ez_scratch);
-       disconnect();
-       return 1;
-}
-
-#define  word_val(n)   (ez_scratch[2*n]+256*ez_scratch[2*n+1])
-
-__initfunc(static void ez_get_capacity( void ))
-
-{      int     ez_cylinders;
-
-       connect();
-       wait_for(0,NULL);
-       ez_ide_command(IDE_IDENTIFY,0);
-       if (wait_for(STAT_DRQ,"Get capacity") & STAT_ERR) {
-               disconnect();
-               return;
-       }
-       read_block(ez_scratch);
-       disconnect();
-       ez_sectors = word_val(6);
-       ez_heads = word_val(3);
-       ez_cylinders  = word_val(1);
-       ez_capacity = ez_sectors*ez_heads*ez_cylinders;
-       printk("ez: Capacity = %d, (%d/%d/%d)\n",ez_capacity,ez_cylinders,
-               ez_heads,ez_sectors);
-}
-
-__initfunc(static void ez_standby_off( void ))
-
-{      connect();
-       wait_for(0,NULL);
-       send_command(0,0,0,0,0,IDE_STANDBY);
-       wait_for(0,NULL);
-       disconnect();
-}
-
-__initfunc(static int ez_port_check( void ))   /* check for 8-bit port */
-
-{      int     r;
-
-        w2(0); 
-       w0(0x55); if (r0() != 0x55) return 0;
-       w0(0xaa); if (r0() != 0xaa) return 0;
-       w2(0x20); w0(0x55); r = r0(); w0(0xaa);
-       if (r0() == r) return 2;
-       if (r0() == 0xaa) return 1;
-       return 0;
-}
-
-__initfunc(static int ez_detect( void ))
-
-{      int j, k;
-       char sig[EZ_SIGLEN] = EZ_SIG;
-       char id[EZ_ID_LEN+1];
-       long    flags;
-
-       if (check_region(ez_base,3)) {
-               printk("ez: Ports at 0x%x are not available\n",ez_base);
-               return 0;
-       }
-
-       ez_mode = ez_port_check();
-       if (!ez_mode) {
-               printk("ez: No parallel port at 0x%x\n",ez_base);
-               return 0;
-       }
-
-       if (ez_irq && request_irq(ez_irq,ez_interrupt,0,"ez",NULL)) ez_irq = 0;
-
-       if (ez_nybble) ez_mode = 1;
-           
-       request_region(ez_base,3,"ez");
-
-       save_flags(flags);
-       sti();
-
-       k = 0;
-       if (ez_identify()) {
-               k = 1;
-               for(j=0;j<EZ_SIGLEN;j++) 
-                  k &= (ez_scratch[j+EZ_SIGOFF] == sig[j]);
-       }
-       if (k) { 
-           for(j=0;j<EZ_ID_LEN;j++) id[j^1] = ez_scratch[j+EZ_SIGOFF];
-           id[EZ_ID_LEN] = 0;
-           if (!ez_irq) printk("ez %s: %s at 0x%x, %d-bit mode.\n",
-                               EZ_VERSION,id,ez_base,4*ez_mode);
-           else printk("ez %s: %s at 0x%x, IRQ %d, %d-bit mode.\n",
-                        EZ_VERSION,id,ez_base,ez_irq,4*ez_mode);
-           ez_standby_off();
-           ez_media_check();
-           ez_get_capacity();
-           restore_flags(flags);
-           return 1;
-       }
-       restore_flags(flags);
-       release_region(ez_base,3);
-       if (ez_irq) free_irq(ez_irq,NULL);
-       printk("ez: Drive not detected\n");
-       return 0;
-}
-
-/* interrupt management */
-
-static void ez_set_intr( void (*continuation)(void) )
-
-{      ez_continuation = continuation;
-       ez_loops = 1;  ez_timeout = 0;
-       ez_gate_intr(1);
-       if (ez_irq) {
-               ez_timer.expires = jiffies + EZ_TMO;
-               add_timer(&ez_timer);
-       } else queue_task(&ez_tq,&tq_scheduler);        
-}
-
-static void ez_pseudo( void *data )
-
-{      void (*con)(void);
-
-       ez_timeout = (ez_loops >= EZ_TMO);
-       if (check_int() || ez_timeout) {
-               con = ez_continuation;
-               ez_continuation = NULL;
-               if (con) con();
-       } else {        
-               ez_loops++;
-               queue_task(&ez_tq,&tq_scheduler);
-       }
-}
-
-static void ez_timer_int( unsigned long data)
-
-{      void  (*con)(void);
-
-       con = ez_continuation;
-       if (!con) return;
-       ez_continuation = NULL;
-       ez_gate_intr(0);
-       ez_timeout = 1;
-       con();
-}
-
-static void ez_interrupt( int irq, void * dev_id, struct pt_regs * regs)
-
-{      void  (*con)(void);
-
-       ez_int_seen = 1;
-       con = ez_continuation;
-       if (!con) return;
-       ez_gate_intr(0);
-       del_timer(&ez_timer);
-       ez_continuation = NULL;
-       con();
-}
-
-/* The i/o request engine */
-
-#define EZ_DONE(s) { disconnect(); end_request(s); ez_busy = 0;\
-                    cli(); do_ez_request(); return; }
-
-static void do_ez_read( void )
-
-{      ez_busy = 1;
-       if (!ez_count) {
-               ez_busy = 0;
-               return;
-       }
-       sti();
-       connect();
-       if (wait_for(STAT_READY,"do_ez_read") & STAT_ERR) EZ_DONE(0);
-       ez_ide_command(IDE_READ,ez_block);
-       ez_set_intr(do_ez_read_drq);
-}
-
-static void do_ez_read_drq( void )
-
-{      sti();
-       if (wait_for(STAT_DRQ,"do_ez_read_drq") & STAT_ERR) EZ_DONE(0);
-       read_block(ez_buf);
-       ez_count--;
-       if (ez_count) {
-               ez_buf += 512;
-               ez_block++;
-               disconnect();
-               do_ez_read();
-               return;
-       }
-       EZ_DONE(1);
-}
-
-static void do_ez_write( void )
-
-{      ez_busy = 1;
-       if (!ez_count) {
-               ez_busy = 0;
-               return;
-       }
-       sti();
-       connect();
-       if (wait_for(STAT_READY,"do_ez_write") & STAT_ERR) 
-          EZ_DONE(0);
-       ez_ide_command(IDE_WRITE,ez_block);
-       if (wait_for(STAT_DRQ,"do_ez_write_drq") & STAT_ERR) 
-          EZ_DONE(0);
-       write_block(ez_buf);
-       ez_set_intr(do_ez_write_done);
-}
-
-static void do_ez_write_done( void )
-
-{      sti();
-       if (wait_for(STAT_READY,"do_ez_write_done") & STAT_ERR) EZ_DONE(0);
-       ez_count--;
-       if (ez_count) {
-               ez_buf += 512;
-               ez_block++;
-               disconnect();
-               do_ez_write();
-               return;
-       }
-       EZ_DONE(1);
-}
-
-/* end of ez.c */
index 2dab2564fa7005e409bee6f6b0eee2aa244e6442..bbe73e3300eefe28aab560947fe42945403b25b9 100644 (file)
@@ -2,7 +2,7 @@
  *  Code extracted from
  *  linux/kernel/hd.c
  *
- *  Copyright (C) 1991, 1992  Linus Torvalds
+ *  Copyright (C) 1991-1998  Linus Torvalds
  *
  *
  *  Thanks to Branko Lankester, lankeste@fwi.uva.nl, who found a bug
@@ -105,6 +105,7 @@ static void add_partition (struct gendisk *hd, int minor, int start, int size)
 static inline int is_extended_partition(struct partition *p)
 {
        return (SYS_IND(p) == DOS_EXTENDED_PARTITION ||
+               SYS_IND(p) == WIN98_EXTENDED_PARTITION ||
                SYS_IND(p) == LINUX_EXTENDED_PARTITION);
 }
 
index bba7355803361ff39a7c802ab11b16cf1c08fe12..246d87c07ff8fafb97816974024b6b82d4d98feb 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/ide-dma.c      Version 4.07  December 5, 1997
+ *  linux/drivers/block/ide-dma.c      Version 4.08  December 31, 1997
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
@@ -171,8 +171,8 @@ int ide_build_dmatable (ide_drive_t *drive)
                }
                /*
                 * Fill in the dma table, without crossing any 64kB boundaries.
-                * The hardware requires 16-bit alignment of all blocks
-                * (trm290 requires 32-bit alignment).
+                * Most hardware requires 16-bit alignment of all blocks,
+                * but the trm290 requires 32-bit alignment.
                 */
                if ((addr & 3)) {
                        printk("%s: misaligned DMA buffer\n", drive->name);
@@ -247,7 +247,7 @@ static int config_drive_for_dma (ide_drive_t *drive)
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
 {
        ide_hwif_t *hwif = HWIF(drive);
-       unsigned int dma_base = hwif->dma_base;
+       unsigned long dma_base = hwif->dma_base;
        unsigned int count, reading = 0;
 
        switch (func) {
@@ -288,12 +288,12 @@ int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive)
        }
 }
 
-void ide_setup_dma (ide_hwif_t *hwif, unsigned int dma_base, unsigned int num_ports) /* __init */
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dma_base, unsigned int num_ports) /* __init */
 {
        static unsigned long dmatable = 0;
        static unsigned leftover = 0;
 
-       printk("    %s: BM-DMA at 0x%04x-0x%04x", hwif->name, dma_base, dma_base + num_ports - 1);
+       printk("    %s: BM-DMA at 0x%04lx-0x%04lx", hwif->name, dma_base, dma_base + num_ports - 1);
        if (check_region(dma_base, num_ports)) {
                printk(" -- ERROR, PORT ADDRESSES ALREADY IN USE\n");
                return;
@@ -356,25 +356,26 @@ __initfunc(static long read_pcicfg_dword (byte fn, unsigned short reg))
 /*
  * Fetch the DMA Bus-Master-I/O-Base-Address (BMIBA) from PCI space:
  */
-unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) /* __init */
+unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) /* __init */
 {
-       unsigned int new, dma_base = 0;
+       unsigned long new, dma_base = 0;
        byte bus = hwif->pci_bus, fn = hwif->pci_fn;
 
        if (hwif->mate && hwif->mate->dma_base) {
                dma_base = hwif->mate->dma_base - (hwif->channel ? 0 : 8);
-       } else if (pcibios_read_config_dword(bus, fn, 0x20, &dma_base)) {
+       } else if (pcibios_read_config_dword(bus, fn, 0x20, (unsigned int *)&dma_base)) {
                printk("%s: failed to read dma_base\n", name);
                dma_base = 0;
        } else if ((dma_base &= ~0xf) == 0 || dma_base == ~0xf) {
-               printk("%s: dma_base is invalid (0x%04x, BIOS problem)\n", name, dma_base);
+               printk("%s: dma_base is invalid (0x%04lx, BIOS problem)\n", name, dma_base);
                new = ide_find_free_region(16 + extra);
                hwif->no_autodma = 1;   /* default DMA off if we had to configure it here */
                if (new) {
-                       printk("%s: setting dma_base to 0x%04x\n", name, new);
+                       printk("%s: setting dma_base to 0x%04lx\n", name, new);
                        new |= 1;
                        (void) pcibios_write_config_dword(bus, fn, 0x20, new);
-                       (void) pcibios_read_config_dword(bus, fn, 0x20, &dma_base);
+                       dma_base = 0;
+                       (void) pcibios_read_config_dword(bus, fn, 0x20, (unsigned int *)&dma_base);
                        if (dma_base != new) {
                                if (bus == 0) {
                                        printk("%s: operation failed, bypassing BIOS to try again\n", name);
index adcf99525b3453aea44fdc27699465147f5d1f5d..d8fa6edf53ae024dea287aaf354abe0f16ab03f7 100644 (file)
@@ -1,13 +1,13 @@
 /*
- *  linux/drivers/block/ide-pci.c      Version 1.00  December 8, 1997
+ *  linux/drivers/block/ide-pci.c      Version 1.02  December 29, 1997
  *
  *  Copyright (c) 1995-1998  Mark Lord
  *  May be copied or modified under the terms of the GNU General Public License
  */
 
 /*
- * This modules provides support for automatic detection and
- * configuration of all PCI IDE interfaces present in a system.  
+ *  This module provides support for automatic detection and
+ *  configuration of all PCI IDE interfaces present in a system.  
  */
 
 #include <linux/config.h>
@@ -41,6 +41,7 @@
 #define DEVID_NS87410  ((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87410})
 #define DEVID_NS87415  ((ide_pci_devid_t){PCI_VENDOR_ID_NS,      PCI_DEVICE_ID_NS_87415})
 #define DEVID_HT6565   ((ide_pci_devid_t){PCI_VENDOR_ID_HOLTEK,  PCI_DEVICE_ID_HOLTEK_6565})
+#define DEVID_AEC6210  ((ide_pci_devid_t){0x1191,                0x0005})
 
 #define IDE_IGNORE     ((void *)-1)
 
@@ -102,6 +103,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
        {DEVID_OPTI621X,"OPTI621X",     INIT_OPTI621,   {{0x45,0x80,0x00}, {0x40,0x08,0x00}} },
        {DEVID_TRM290,  "TRM290",       INIT_TRM290,    {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
        {DEVID_NS87415, "NS87415",      INIT_NS87415,   {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
+       {DEVID_AEC6210, "AEC6210",      NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}} },
        {IDE_PCI_DEVID_NULL, "PCI_IDE", NULL,           {{0x00,0x00,0x00}, {0x00,0x00,0x00}} }};
 
 /*
@@ -111,7 +113,7 @@ static ide_pci_device_t ide_pci_chipsets[] __initdata = {
  * by the BIOS, to avoid conflicts later in the init cycle,
  * but we don't.       FIXME
  */
-unsigned int ide_find_free_region (unsigned short size) /* __init */
+unsigned long ide_find_free_region (unsigned short size) /* __init */
 {
        static unsigned short base = 0x5800;    /* it works for me */
        unsigned short i;
@@ -228,10 +230,11 @@ __initfunc(static int ide_setup_pci_baseregs (byte bus, byte fn, const char *nam
 __initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int ccode, ide_pci_device_t *d))
 {
        unsigned int port, at_least_one_hwif_enabled = 0, no_autodma = 0;
-       unsigned short pcicmd = 0;
+       unsigned short pcicmd = 0, tried_config = 0;
        byte tmp = 0, progif = 0, pciirq = 0;
        ide_hwif_t *hwif, *mate = NULL;
 
+check_if_enabled:
        if (pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
         || pcibios_read_config_byte(bus, fn, 0x09, &progif)
         || pcibios_read_config_byte(bus, fn, 0x3c, &pciirq))
@@ -247,21 +250,32 @@ __initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int cco
                 * Maybe the user deliberately *disabled* the device,
                 * but we'll eventually ignore it again if no drives respond.
                 */
-               if (ide_setup_pci_baseregs(bus, fn, d->name)
-                || pcibios_write_config_word(bus, fn, 0x04, pcicmd|1)
-                || pcibios_read_config_word(bus, fn, 0x04, &pcicmd)
-                || !(pcicmd & 1))
+               if (tried_config++
+                || ide_setup_pci_baseregs(bus, fn, d->name)
+                || pcibios_write_config_word(bus, fn, 0x04, pcicmd|1))
                {
                        printk("%s: device disabled (BIOS)\n", d->name);
                        return;
                }
                no_autodma = 1; /* default DMA off if we had to configure it here */
-               printk("%s: device enabled (Linux)\n", d->name);
+               goto check_if_enabled;
        }
-       if (!pciirq || pciirq >= NR_IRQS) {     /* is pciirq invalid? */
-               if (pciirq || (progif & 0x5))   /* don't complain if using "legacy" mode */
-                       printk("%s: BIOS returned %d for IRQ (ignored)\n", d->name, pciirq);
-               pciirq = 0;     /* probe for it instead */
+       if (tried_config)
+               printk("%s: device enabled (Linux)\n", d->name);
+       /*
+        * Can we trust the reported IRQ?
+        */
+       if ((ccode >> 16) != PCI_CLASS_STORAGE_IDE || (progif & 5) != 5) {
+               printk("%s: not 100%% native mode: will probe irqs later\n", d->name);
+               pciirq = 0;
+       } else if (tried_config) {
+               printk("%s: will probe irqs later\n", d->name);
+               pciirq = 0;
+       } else if (!pciirq || pciirq >= NR_IRQS) {
+               printk("%s: bad irq from BIOS (%d): will probe later\n", d->name, pciirq);
+               pciirq = 0;
+       } else {
+               printk("%s: 100%% native mode on irq %d\n", d->name, pciirq);
        }
        /*
         * Set up the IDE ports
@@ -286,7 +300,8 @@ __initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int cco
                hwif->pci_fn = fn;
                hwif->pci_devid = d->devid;
                hwif->channel = port;
-               hwif->irq = pciirq;
+               if (!hwif->irq)
+                       hwif->irq = pciirq;
                if (mate) {
                        hwif->mate = mate;
                        mate->mate = hwif;
@@ -296,7 +311,7 @@ __initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int cco
 #ifdef CONFIG_BLK_DEV_IDEDMA
                if (IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246) || ((ccode >> 16) == PCI_CLASS_STORAGE_IDE && (ccode & 0x8000))) {
                        unsigned int extra = (!mate && IDE_PCI_DEVID_EQ(d->devid, DEVID_PDC20246)) ? 16 : 0;
-                       unsigned int dma_base = ide_get_or_set_dma_base(hwif, extra, d->name);
+                       unsigned long dma_base = ide_get_or_set_dma_base(hwif, extra, d->name);
                        if (dma_base && !(pcicmd & 4)) {
                                /*
                                 * Set up BM-DMA capability (PnP BIOS should have done this)
@@ -311,7 +326,7 @@ __initfunc(static void ide_setup_pci_device (byte bus, byte fn, unsigned int cco
                        if (dma_base)
                                ide_setup_dma(hwif, dma_base, 8);
                        else
-                               printk("%s: %s Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, ccode=0x%04x, dma_base=0x%04x\n",
+                               printk("%s: %s Bus-Master DMA disabled (BIOS), pcicmd=0x%04x, ccode=0x%04x, dma_base=0x%04lx\n",
                                 hwif->name, d->name, pcicmd, ccode, dma_base);
                }
 #endif /* CONFIG_BLK_DEV_IDEDMA */
@@ -352,10 +367,10 @@ static inline void ide_scan_pci_device (unsigned int bus, unsigned int fn)
                        continue;       /* OPTI Viper-M uses same devid for functions 0 and 1 */
                else if (!IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL) || (ccode >> 16) == PCI_CLASS_STORAGE_IDE) {
                        if (IDE_PCI_DEVID_EQ(d->devid, IDE_PCI_DEVID_NULL))
-                               printk("%s: unknown IDE device on PCI bus %d function %d, VID=%04x, DID=%04x\n",
+                               printk("%s: unknown IDE controller on PCI bus %d function %d, VID=%04x, DID=%04x\n",
                                        d->name, bus, fn, devid.vid, devid.did);
                        else
-                               printk("%s: PCI bus %d function %d\n", d->name, bus, fn);
+                               printk("%s: IDE controller on PCI bus %d function %d\n", d->name, bus, fn);
                        ide_setup_pci_device(bus, fn, ccode, d);
                }
        } while (hedt == 0x80 && (++fn & 7));
@@ -379,4 +394,3 @@ void ide_scan_pcibus (void) /* __init */
                }
        }
 }
-
index 859581bf389293076a6f77a0e7b6e7a97c4d3623..ea377e447400e357dd44a5569a8071de5b586b68 100644 (file)
@@ -1,5 +1,5 @@
 /*
- *  linux/drivers/block/proc_ide.c     Version 1.01    December 12, 1997
+ *  linux/drivers/block/ide-proc.c     Version 1.02    December 31, 1997
  *
  *  Copyright (C) 1997-1998    Mark Lord
  */
  * This should provide better utilities, and less kernel bloat.
  *
  * The entire pci config space for a PCI interface chipset can be
- * retrieved by just reading it.  e.g.    "cat /proc/ide3/pci"
+ * retrieved by just reading it.  e.g.    "cat /proc/ide3/config"
  *
- * To modify registers, do something like:
- *   echo "40:88" >/proc/ide/ide3/pci
+ * To modify registers *safely*, do something like:
+ *   echo "P40:88" >/proc/ide/ide3/config
  * That expression writes 0x88 to pci config register 0x40
  * on the chip which controls ide3.  Multiple tuples can be issued,
  * and the writes will be completed as an atomic set:
- *   echo "40:88 41:35 42:00 43:00" >/proc/ide/ide3/pci
- * All numbers must be pairs of ascii hex digits.
+ *   echo "P40:88 P41:35 P42:00 P43:00" >/proc/ide/ide3/config
+ *
+ * All numbers must be specified using pairs of ascii hex digits.
+ * It is important to note that these writes will be performed
+ * after waiting for the IDE controller (both interfaces)
+ * to be completely idle, to ensure no corruption of I/O in progress.
+ *
+ * Non-PCI registers can also be written, using "R" in place of "P"
+ * in the above examples.  The size of the port transfer is determined
+ * by the number of pairs of hex digits given for the data.  If a two
+ * digit value is given, the write will be a byte operation; if four
+ * digits are used, the write will be performed as a 16-bit operation;
+ * and if eight digits are specified, a 32-bit "dword" write will be
+ * performed.  Odd numbers of digits are not permitted.
+ *
+ * If there is an error *anywhere* in the string of registers/data
+ * then *none* of the writes will be performed.
  *
  * Also useful, "cat /proc/ide0/hda/identify" will issue an IDENTIFY
  * (or PACKET_IDENTIFY) command to /dev/hda, and then dump out the
@@ -44,6 +59,7 @@
 #include <linux/pci.h>
 #include <linux/bios32.h>
 #include <linux/ctype.h>
+#include <asm/io.h>
 #include "ide.h"
 
 #ifndef MIN
@@ -64,13 +80,14 @@ static int ide_getxdigit(char c)
        return digit;
 }
 
-
-static int xx_xx_parse_error (const char *start, unsigned long maxlen)
+static int xx_xx_parse_error (const char *data, unsigned long len, const char *msg)
 {
-       char errbuf[7];
-       int i, len = MIN(6, maxlen);
+       char errbuf[16];
+       int i;
+       if (len >= sizeof(errbuf))
+               len = sizeof(errbuf) - 1;
        for (i = 0; i < len; ++i) {
-               char c = start[i];
+               char c = data[i];
                if (!c || c == '\n')
                        c = '\0';
                else if (iscntrl(c))
@@ -78,17 +95,17 @@ static int xx_xx_parse_error (const char *start, unsigned long maxlen)
                errbuf[i] = c;
        }
        errbuf[i] = '\0';
-       printk("proc_ide: error: expected 'xx:xx', but got '%s'\n", errbuf);
+       printk("proc_ide: error: %s: '%s'\n", msg, errbuf);
        return -EINVAL;
 }
 
-static int proc_ide_write_pci
+static int proc_ide_write_config
        (struct file *file, const char *buffer, unsigned long count, void *data)
 {
        ide_hwif_t      *hwif = (ide_hwif_t *)data;
        int             for_real = 0;
-       unsigned long   n, flags;
-       const char      *start;
+       unsigned long   startn = 0, n, flags;
+       const char      *start = NULL, *msg = NULL;
 
        if (!suser())
                return -EACCES;
@@ -105,56 +122,109 @@ static int proc_ide_write_pci
         */
        save_flags(flags);
        do {
-               const char *p = buffer;
-               n = count;
+               const char *p;
                if (for_real) {
                        unsigned long timeout = jiffies + (3 * HZ);
+                       ide_hwgroup_t *mygroup = (ide_hwgroup_t *)(hwif->hwgroup);
+                       ide_hwgroup_t *mategroup = NULL;
+                       if (hwif->mate && hwif->mate->hwgroup)
+                               mategroup = (ide_hwgroup_t *)(hwif->mate->hwgroup);
                        cli();  /* ensure all PCI writes are done together */
-                       while (((ide_hwgroup_t *)(hwif->hwgroup))->active || (hwif->mate && ((ide_hwgroup_t *)(hwif->mate->hwgroup))->active)) {
-                               sti();
+                       while (mygroup->active || (mategroup && mategroup->active)) {
+                               restore_flags(flags);
                                if (0 < (signed long)(jiffies - timeout)) {
                                        printk("/proc/ide/%s/pci: channel(s) busy, cannot write\n", hwif->name);
-                                       restore_flags(flags);
                                        return -EBUSY;
                                }
                                cli();
                        }
                }
-               while (n) {
-                       int d1, d2, rc;
-                       byte reg, val;
+               p = buffer;
+               n = count;
+               while (n > 0) {
+                       int d, digits;
+                       unsigned int reg = 0, val = 0, is_pci;
                        start = p;
-#if 0
-                       printk("loop(%d): n=%ld, input=%.5s\n", for_real, n, p);
-#endif
-                       if (n < 5)
-                               goto parse_error;
-                       if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+                       startn = n--;
+                       switch (*p++) {
+                               case 'R':       is_pci = 0;
+                                               break;
+                               case 'P':       is_pci = 1;
+                                               break;
+                               default:        msg = "expected 'R' or 'P'";
+                                               goto parse_error;
+                       }
+                       digits = 0;
+                       while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
+                               reg = (reg << 4) | d;
+                               --n;
+                               ++p;
+                               ++digits;
+                       }
+                       if (!digits || (digits > 4) || (is_pci && reg > 0xff)) {
+                               msg = "bad/missing register number";
                                goto parse_error;
-                       reg = (d1 << 4) | d2;
-                       if (*p++ != ':')
+                       }
+                       if (--n < 0 || *p++ != ':') {
+                               msg = "missing ':'";
                                goto parse_error;
-                       if (0 > (d1 = ide_getxdigit(*p++)) || 0 > (d2 = ide_getxdigit(*p++)))
+                       }
+                       digits = 0;
+                       while (n > 0 && (d = ide_getxdigit(*p)) >= 0) {
+                               val = (val << 4) | d;
+                               --n;
+                               ++p;
+                               ++digits;
+                       }
+                       if (digits != 2 && digits != 4 && digits != 8) {
+                               msg = "bad data, 2/4/8 digits required";
                                goto parse_error;
-                       val = (d1 << 4) | d2;
-                       if (n > 5 && !isspace(*p))
+                       }
+                       if (n > 0 && !isspace(*p)) {
+                               msg = "expected whitespace after data";
                                goto parse_error;
-                       n -= 5;
-                       while (n && isspace(*p)) {
+                       }
+                       while (n > 0 && isspace(*p)) {
                                --n;
                                ++p;
                        }
+                       if (is_pci && (reg & ((digits >> 1) - 1))) {
+                               msg = "misaligned access";
+                               goto parse_error;
+                       }
                        if (for_real) {
 #if 0
-                               printk("proc_ide_write_pci: reg=0x%02x, val=0x%02x\n", reg, val);
+                               printk("proc_ide_write_config: type=%c, reg=0x%x, val=0x%x, digits=%d\n", is_pci ? 'PCI' : 'non-PCI', reg, val, digits);
 #endif
-                               rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
-                               if (rc) {
-                                       restore_flags(flags);
-                                       printk("proc_ide_write_pci: error writing bus %d fn %d reg 0x%02x value 0x%02x\n",
-                                               hwif->pci_bus, hwif->pci_fn, reg, val);
-                                       printk("proc_ide_write_pci: %s\n", pcibios_strerror(rc));
-                                       return -EIO;
+                               if (is_pci) {
+                                       int rc = 0;
+                                       switch (digits) {
+                                               case 2: msg = "byte";
+                                                       rc = pcibios_write_config_byte(hwif->pci_bus, hwif->pci_fn, reg, val);
+                                                       break;
+                                               case 4: msg = "word";
+                                                       rc = pcibios_write_config_word(hwif->pci_bus, hwif->pci_fn, reg, val);
+                                                       break;
+                                               case 8: msg = "dword";
+                                                       rc = pcibios_write_config_dword(hwif->pci_bus, hwif->pci_fn, reg, val);
+                                                       break;
+                                       }
+                                       if (rc) {
+                                               restore_flags(flags);
+                                               printk("proc_ide_write_config: error writing %s at bus %d fn %d reg 0x%x value 0x%x\n",
+                                                       msg, hwif->pci_bus, hwif->pci_fn, reg, val);
+                                               printk("proc_ide_write_config: %s\n", pcibios_strerror(rc));
+                                               return -EIO;
+                                       }
+                               } else {        /* not pci */
+                                       switch (digits) {
+                                               case 2: outb(val, reg);
+                                                       break;
+                                               case 4: outw(val, reg);
+                                                       break;
+                                               case 8: outl(val, reg);
+                                                       break;
+                                       }
                                }
                        }
                }
@@ -163,25 +233,26 @@ static int proc_ide_write_pci
        return count;
 parse_error:
        restore_flags(flags);
-       return xx_xx_parse_error(start, n);
+       printk("parse error\n");
+       return xx_xx_parse_error(start, startn, msg);
 }
 
-static int proc_ide_read_pci
+static int proc_ide_read_config
        (char *page, char **start, off_t off, int count, int *eof, void *data)
 {
        ide_hwif_t      *hwif = (ide_hwif_t *)data;
        char            *out = page;
        int             len, reg = 0;
 
-       out += sprintf(out, "Bus %d Function %d Vendor %04x Device %04x Channel %d\n",
+       out += sprintf(out, "pci bus %d function %d vendor %04x device %04x channel %d\n",
                hwif->pci_bus, hwif->pci_fn, hwif->pci_devid.vid, hwif->pci_devid.did, hwif->channel);
        do {
                byte val;
                int rc = pcibios_read_config_byte(hwif->pci_bus, hwif->pci_fn, reg, &val);
                if (rc) {
-                       printk("proc_ide_read_pci: error reading bus %d fn %d reg 0x%02x\n",
+                       printk("proc_ide_read_config: error reading bus %d fn %d reg 0x%02x\n",
                                hwif->pci_bus, hwif->pci_fn, reg);
-                       printk("proc_ide_read_pci: %s\n", pcibios_strerror(rc));
+                       printk("proc_ide_read_config: %s\n", pcibios_strerror(rc));
                        return -EIO;
                        out += sprintf(out, "??%c", (++reg & 0xf) ? ' ' : '\n');
                } else
@@ -455,11 +526,11 @@ static void create_proc_ide_interfaces (struct proc_dir_entry *parent)
                if (!hwif_ent) return;
 #ifdef CONFIG_PCI
                if (!IDE_PCI_DEVID_EQ(hwif->pci_devid, IDE_PCI_DEVID_NULL)) {
-                       ent = create_proc_entry("pci", 0, hwif_ent);
+                       ent = create_proc_entry("config", 0, hwif_ent);
                        if (!ent) return;
                        ent->data = hwif;
-                       ent->read_proc  = proc_ide_read_pci;
-                       ent->write_proc = proc_ide_write_pci;;
+                       ent->read_proc  = proc_ide_read_config;
+                       ent->write_proc = proc_ide_write_config;;
 
                        ent = create_proc_entry("model", 0, hwif_ent);
                        if (!ent) return;
index 5ea5dd2ac66fc0b18a8069321b3a1fdb47908f13..fde3f5b3e5a0a1185d47930e2e9b87d878fa06cc 100644 (file)
@@ -321,9 +321,9 @@ typedef struct hwif_s {
        ide_dmaproc_t   *dmaproc;       /* dma read/write/abort routine */
        unsigned long   *dmatable;      /* dma physical region descriptor table */
        struct hwif_s   *mate;          /* other hwif from same PCI chip */
-       unsigned int    dma_base;       /* base addr for dma ports */
-       unsigned int    config_data;    /* for use by chipset-specific code */
-       unsigned int    select_data;    /* for use by chipset-specific code */
+       unsigned long   dma_base;       /* base addr for dma ports */
+       unsigned long   config_data;    /* for use by chipset-specific code */
+       unsigned long   select_data;    /* for use by chipset-specific code */
        struct proc_dir_entry *proc;    /* /proc/ide/ directory entry */
        int             irq;            /* our irq number */
        byte            major;          /* our major number */
@@ -365,7 +365,7 @@ typedef struct hwgroup_s {
  * /proc/ide interface
  */
 typedef struct {
-       char *name;
+       const char *name;
        read_proc_t *read_proc;
        write_proc_t *write_proc;
 } ide_proc_entry_t;
@@ -656,15 +656,15 @@ int ide_register_subdriver (ide_drive_t *drive, ide_driver_t *driver, int versio
 int ide_unregister_subdriver (ide_drive_t *drive);
 
 #ifdef CONFIG_BLK_DEV_IDEPCI
-unsigned int ide_find_free_region (unsigned short size) __init;
+unsigned long ide_find_free_region (unsigned short size) __init;
 void ide_scan_pcibus (void) __init;
 #endif
 #ifdef CONFIG_BLK_DEV_IDEDMA
 int ide_build_dmatable (ide_drive_t *drive);
 void ide_dma_intr  (ide_drive_t *drive);
 int ide_dmaproc (ide_dma_action_t func, ide_drive_t *drive);
-void ide_setup_dma (ide_hwif_t *hwif, unsigned int dmabase, unsigned int num_ports) __init;
-unsigned int ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
+void ide_setup_dma (ide_hwif_t *hwif, unsigned long dmabase, unsigned int num_ports) __init;
+unsigned long ide_get_or_set_dma_base (ide_hwif_t *hwif, int extra, const char *name) __init;
 #endif
 
 #ifdef CONFIG_BLK_DEV_IDE
index 589fbfaa7d38f862ecb7df7219bea2e3dfef48b4..21679622c02bcc7513a1202384c229863cbeef30 100644 (file)
@@ -15,7 +15,7 @@
  * breaking the fragile cmd640.c support.
  */
 
-#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS)
+#if defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621)
 
 /*
  * Standard (generic) timings for PIO modes, from ATA2 specification.
@@ -222,5 +222,5 @@ byte ide_get_best_pio_mode (ide_drive_t *drive, byte mode_wanted, byte max_mode,
 }
 
 #endif /* _IDE_C */
-#endif /* defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) */
+#endif /* defined(CONFIG_BLK_DEV_CMD640) || defined(CONFIG_IDE_CHIPSETS) || defined(CONFIG_BLK_DEV_OPTI621) */
 #endif /* _IDE_MODES_H */
index c852db6ff096fa99329cc6570a2fd079389a68f9..afd3324eae01c6aade6fd2606e1ccac07a9b5f49 100644 (file)
@@ -665,12 +665,6 @@ void ll_rw_swap_file(int rw, kdev_t dev, unsigned int *b, int nb, char *buf)
                }
        }
 }
-#ifdef CONFIG_BLK_DEV_EZ
-extern void ez_init( void );
-#endif
-#ifdef CONFIG_BPCD
-extern void bpcd_init( void );
-#endif
 
 __initfunc(int blk_dev_init(void))
 {
@@ -724,8 +718,8 @@ __initfunc(int blk_dev_init(void))
 #ifdef CONFIG_BLK_DEV_XD
        xd_init();
 #endif
-#ifdef CONFIG_BLK_DEV_EZ
-       ez_init();
+#ifdef CONFIG_PARIDE
+       { extern void paride_init(void); paride_init(); };
 #endif
 #ifdef CONFIG_MAC_FLOPPY
        swim3_init();
@@ -761,9 +755,6 @@ __initfunc(int blk_dev_init(void))
 #ifdef CONFIG_GSCD
        gscd_init();
 #endif CONFIG_GSCD
-#ifdef CONFIG_BPCD
-       bpcd_init();
-#endif CONFIG_BPCD
 #ifdef CONFIG_CM206
        cm206_init();
 #endif
diff --git a/drivers/block/paride/Config.in b/drivers/block/paride/Config.in
new file mode 100644 (file)
index 0000000..4748977
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# PARIDE configuration
+#
+comment 'Parallel IDE high-level drivers'
+dep_tristate '  Parallel port IDE disks' CONFIG_PARIDE_PD $CONFIG_PARIDE
+dep_tristate '  Parallel port ATAPI CD-ROMs' CONFIG_PARIDE_PCD $CONFIG_PARIDE
+dep_tristate '  Parallel port ATAPI disks' CONFIG_PARIDE_PF $CONFIG_PARIDE
+comment 'Parallel IDE protocol modules'
+dep_tristate '    ATEN EH-100 protocol' CONFIG_PARIDE_ATEN $CONFIG_PARIDE
+dep_tristate '    MicroSolutions backpack protocol' CONFIG_PARIDE_BPCK $CONFIG_PARIDE
+dep_tristate '    DataStor Commuter protocol' CONFIG_PARIDE_COMM $CONFIG_PARIDE
+dep_tristate '    DataStor EP-2000 protocol' CONFIG_PARIDE_DSTR $CONFIG_PARIDE
+dep_tristate '    Shuttle EPAT/EPEZ protocol' CONFIG_PARIDE_EPAT $CONFIG_PARIDE
+dep_tristate '    Shuttle EPIA protocol' CONFIG_PARIDE_EPIA $CONFIG_PARIDE
+dep_tristate '    FreeCom power protocol' CONFIG_PARIDE_FRPW $CONFIG_PARIDE
+dep_tristate '    KingByte KBIC-951A/971A protocols' CONFIG_PARIDE_KBIC $CONFIG_PARIDE
+dep_tristate '    OnSpec 90c20 protocol' CONFIG_PARIDE_ON20 $CONFIG_PARIDE
+dep_tristate '    OnSpec 90c26 protocol' CONFIG_PARIDE_ON26 $CONFIG_PARIDE
+#
diff --git a/drivers/block/paride/Makefile b/drivers/block/paride/Makefile
new file mode 100644 (file)
index 0000000..a6fa960
--- /dev/null
@@ -0,0 +1,133 @@
+#
+# Makefile for PARIDE
+#
+# Note! Dependencies are done automagically by 'make dep', which also
+# removes any old dependencies. DON'T put your own dependencies here
+# unless it's something special (ie not a .c file).
+#
+# Note 2! The CFLAGS definitions are now inherited from the
+# parent makes..
+
+SUB_DIRS     := 
+MOD_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+L_TARGET := paride.a
+MX_OBJS  :=
+LX_OBJS  := 
+MI_OBJS  :=
+MIX_OBJS :=
+
+ifeq ($(CONFIG_PARIDE),y)
+  LX_OBJS += paride.o
+else
+  ifeq ($(CONFIG_PARIDE),m)
+    MX_OBJS += paride.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_PD),y)
+  LX_OBJS += pd.o
+else
+  ifeq ($(CONFIG_PARIDE_PD),m)
+    MX_OBJS += pd.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_PCD),y)
+  LX_OBJS += pcd.o
+else
+  ifeq ($(CONFIG_PARIDE_PCD),m)
+    MX_OBJS += pcd.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_PF),y)
+  LX_OBJS += pf.o
+else
+  ifeq ($(CONFIG_PARIDE_PF),m)
+    MX_OBJS += pf.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_ATEN),y)
+  LX_OBJS += aten.o
+else
+  ifeq ($(CONFIG_PARIDE_ATEN),m)
+    MX_OBJS += aten.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_BPCK),y)
+  LX_OBJS += bpck.o
+else
+  ifeq ($(CONFIG_PARIDE_BPCK),m)
+    MX_OBJS += bpck.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_COMM),y)
+  LX_OBJS += comm.o
+else
+  ifeq ($(CONFIG_PARIDE_COMM),m)
+    MX_OBJS += comm.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_DSTR),y)
+  LX_OBJS += dstr.o
+else
+  ifeq ($(CONFIG_PARIDE_DSTR),m)
+    MX_OBJS += dstr.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_KBIC),y)
+  LX_OBJS += kbic.o
+else
+  ifeq ($(CONFIG_PARIDE_KBIC),m)
+    MX_OBJS += kbic.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_EPAT),y)
+  LX_OBJS += epat.o
+else
+  ifeq ($(CONFIG_PARIDE_EPAT),m)
+    MX_OBJS += epat.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_EPIA),y)
+  LX_OBJS += epia.o
+else
+  ifeq ($(CONFIG_PARIDE_EPIA),m)
+    MX_OBJS += epia.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_FRPW),y)
+  LX_OBJS += frpw.o
+else
+  ifeq ($(CONFIG_PARIDE_FRPW),m)
+    MX_OBJS += frpw.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_ON20),y)
+  LX_OBJS += on20.o
+else
+  ifeq ($(CONFIG_PARIDE_ON20),m)
+    MX_OBJS += on20.o
+  endif
+endif
+
+ifeq ($(CONFIG_PARIDE_ON26),y)
+  LX_OBJS += on26.o
+else
+  ifeq ($(CONFIG_PARIDE_ON26),m)
+    MX_OBJS += on26.o
+  endif
+endif
+
+include $(TOPDIR)/Rules.make
diff --git a/drivers/block/paride/aten.c b/drivers/block/paride/aten.c
new file mode 100644 (file)
index 0000000..dd11b03
--- /dev/null
@@ -0,0 +1,166 @@
+/* 
+        aten.c        (c) 1997  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+       aten.c is a low-level protocol driver for the ATEN EH-100
+       parallel port adapter.  The EH-100 supports 4-bit and 8-bit
+        modes only.  There is also an EH-132 which supports EPP mode
+        transfers.  The EH-132 is not yet supported.
+
+*/
+
+#define ATEN_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b)                ((((a>>4)&0x0f)|(b&0xf0))^0x88)
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x08, 0x20 };
+
+static void  aten_write_regr( PIA *pi, int cont, int regr, int val)
+
+{      int r;
+
+       r = regr + cont_map[cont] + 0x80;
+
+       w0(r); w2(0xe); w2(6); w0(val); w2(7); w2(6); w2(0xc);
+}
+
+static int aten_read_regr( PIA *pi, int cont, int regr )
+
+{      int  a, b, r;
+
+        r = regr + cont_map[cont] + 0x40;
+
+       switch (pi->mode) {
+
+        case 0: w0(r); w2(0xe); w2(6); 
+               w2(7); w2(6); w2(0);
+               a = r1(); w0(0x10); b = r1(); w2(0xc);
+               return j44(a,b);
+
+        case 1: r |= 0x10;
+               w0(r); w2(0xe); w2(6); w0(0xff); 
+               w2(0x27); w2(0x26); w2(0x20);
+               a = r0();
+               w2(0x26); w2(0xc);
+               return a;
+       }
+       return -1;
+}
+
+static void aten_read_block( PIA *pi, char * buf, int count )
+
+{      int  k, a, b, c, d;
+
+       switch (pi->mode) {
+
+       case 0: w0(0x48); w2(0xe); w2(6);
+               for (k=0;k<count/2;k++) {
+                       w2(7); w2(6); w2(2);
+                       a = r1(); w0(0x58); b = r1();
+                       w2(0); d = r1(); w0(0x48); c = r1();
+                       buf[2*k] = j44(c,d);
+                       buf[2*k+1] = j44(a,b);
+               }
+               w2(0xc);
+               break;
+
+       case 1: w0(0x58); w2(0xe); w2(6);
+               for (k=0;k<count/2;k++) {
+                       w2(0x27); w2(0x26); w2(0x22);
+                       a = r0(); w2(0x20); b = r0();
+                       buf[2*k] = b; buf[2*k+1] = a;
+               }
+               w2(0x26); w2(0xc);
+               break;
+       }
+}
+
+static void aten_write_block( PIA *pi, char * buf, int count )
+
+{      int k;
+
+       w0(0x88); w2(0xe); w2(6);
+       for (k=0;k<count/2;k++) {
+               w0(buf[2*k+1]); w2(0xe); w2(6);
+               w0(buf[2*k]); w2(7); w2(6);
+       }
+       w2(0xc);
+}
+
+static void aten_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+       w2(0xc);        
+}
+
+static void aten_disconnect ( PIA *pi )
+
+{       w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void aten_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[2] = {"4-bit","8-bit"};
+
+        printk("%s: aten %s, ATEN EH-100 at 0x%x, ",
+                pi->device,ATEN_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void aten_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void aten_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol aten = {"aten",0,2,2,1,1,
+                           aten_write_regr,
+                           aten_read_regr,
+                           aten_write_block,
+                           aten_read_block,
+                           aten_connect,
+                           aten_disconnect,
+                           0,
+                           0,
+                           0,
+                           aten_log_adapter,
+                           aten_inc_use, 
+                           aten_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &aten ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &aten );
+}
+
+#endif
+
+/* end of aten.c */
diff --git a/drivers/block/paride/bpck.c b/drivers/block/paride/bpck.c
new file mode 100644 (file)
index 0000000..21caad6
--- /dev/null
@@ -0,0 +1,476 @@
+/* 
+       bpck.c  (c) 1996,1997  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
+
+       bpck.c is a low-level protocol driver for the MicroSolutions 
+       "backpack" parallel port IDE adapter.  
+
+*/
+
+#define        BPCK_VERSION    "1.0" 
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#undef r2
+#undef w2
+
+#define PC                     pi->private
+#define r2()                   (PC=(in_p(2) & 0xff))
+#define w2(byte)               {out_p(2,byte); PC = byte;}
+#define t2(pat)                {PC ^= pat; out_p(2,PC);}
+#define e2()                   {PC &= 0xfe; out_p(2,PC);}
+#define o2()                   {PC |= 1; out_p(2,PC);}
+
+#define j44(l,h)     (((l>>3)&0x7)|((l>>4)&0x8)|((h<<1)&0x70)|(h&0x80))
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+   cont = 2 - use internal bpck register addressing
+*/
+
+static int  cont_map[3] = { 0x40, 0x48, 0 };
+
+static int bpck_read_regr( PIA *pi, int cont, int regr )
+
+{       int r, l, h;
+
+       r = regr + cont_map[cont];
+
+       switch (pi->mode) {
+
+       case 0: w0(r & 0xf); w0(r); t2(2); t2(4);
+               l = r1();
+               t2(4);
+               h = r1();
+               return j44(l,h);
+
+       case 1: w0(r & 0xf); w0(r); t2(2);
+               e2(); t2(0x20);
+               t2(4); h = r0();
+               t2(1); t2(0x20);
+               return h;
+
+       case 2:
+       case 3:
+       case 4: w0(r); w2(9); w2(0); w2(0x20);
+               h = r4();
+               w2(0);
+               return h;
+
+       }
+       return -1;
+}      
+
+static void bpck_write_regr( PIA *pi, int cont, int regr, int val )
+
+{      int     r;
+
+        r = regr + cont_map[cont];
+
+       switch (pi->mode) {
+
+       case 0:
+       case 1: w0(r);
+               t2(2);
+               w0(val);
+               o2(); t2(4); t2(1);
+               break;
+
+       case 2:
+       case 3:
+       case 4: w0(r); w2(9); w2(0);
+               w0(val); w2(1); w2(3); w2(0);
+               break;
+
+       }
+}
+
+/* These macros access the bpck registers in native addressing */
+
+#define WR(r,v)                bpck_write_regr(pi,2,r,v)
+#define RR(r)          (bpck_read_regr(pi,2,r))
+
+static void bpck_write_block( PIA *pi, char * buf, int count )
+
+{      int i;
+
+       switch (pi->mode) {
+
+       case 0: WR(4,0x40);
+               w0(0x40); t2(2); t2(1);
+               for (i=0;i<count;i++) { w0(buf[i]); t2(4); }
+               WR(4,0);
+               break;
+
+       case 1: WR(4,0x50);
+                w0(0x40); t2(2); t2(1);
+                for (i=0;i<count;i++) { w0(buf[i]); t2(4); }
+                WR(4,0x10);
+               break;
+
+       case 2: WR(4,0x48);
+               w0(0x40); w2(9); w2(0); w2(1);
+               for (i=0;i<count;i++) w4(buf[i]);
+               w2(0);
+               WR(4,8);
+               break;
+
+        case 3: WR(4,0x48);
+                w0(0x40); w2(9); w2(0); w2(1);
+                for (i=0;i<count/2;i++) w4w(((u16 *)buf)[i]);
+                w2(0);
+                WR(4,8);
+                break;
+        case 4: WR(4,0x48);
+                w0(0x40); w2(9); w2(0); w2(1);
+                for (i=0;i<count/4;i++) w4l(((u32 *)buf)[i]);
+                w2(0);
+                WR(4,8);
+                break;
+       }
+}
+
+static void bpck_read_block( PIA *pi, char * buf, int count )
+
+{      int i, l, h;
+
+       switch (pi->mode) {
+
+       case 0: WR(4,0x40);
+               w0(0x40); t2(2);
+               for (i=0;i<count;i++) {
+                   t2(4); l = r1();
+                   t2(4); h = r1();
+                   buf[i] = j44(l,h);
+               }
+               WR(4,0);
+               break;
+
+       case 1: WR(4,0x50);
+               w0(0x40); t2(2); t2(0x20);
+               for(i=0;i<count;i++) { t2(4); buf[i] = r0(); }
+               t2(1); t2(0x20);
+               WR(4,0x10);
+               break;
+
+       case 2: WR(4,0x48);
+               w0(0x40); w2(9); w2(0); w2(0x20);
+               for (i=0;i<count;i++) buf[i] = r4();
+               w2(0);
+               WR(4,8);
+               break;
+
+        case 3: WR(4,0x48);
+                w0(0x40); w2(9); w2(0); w2(0x20);
+                for (i=0;i<count/2;i++) ((u16 *)buf)[i] = r4w();
+                w2(0);
+                WR(4,8);
+                break;
+
+        case 4: WR(4,0x48);
+                w0(0x40); w2(9); w2(0); w2(0x20);
+                for (i=0;i<count/4;i++) ((u32 *)buf)[i] = r4l();
+                w2(0);
+                WR(4,8);
+                break;
+
+       }
+}
+
+static int bpck_probe_unit ( PIA *pi )
+
+{      int o1, o0, f7, id;
+       int t, s;
+
+       id = pi->unit;
+       s = 0;
+       w2(4); w2(0xe); r2(); t2(2); 
+       o1 = r1()&0xf8;
+       o0 = r0();
+       w0(255-id); w2(4); w0(id);
+       t2(8); t2(8); t2(8);
+       t2(2); t = r1()&0xf8;
+       f7 = ((id % 8) == 7);
+       if ((f7) || (t != o1)) { t2(2); s = r1()&0xf8; }
+       if ((t == o1) && ((!f7) || (s == o1)))  {
+               w2(0x4c); w0(o0);
+               return 0;       
+       }
+       t2(8); w0(0); t2(2); w2(0x4c); w0(o0);
+       return 1;
+}
+       
+static void bpck_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+       w0(0xff-pi->unit); w2(4); w0(pi->unit);
+       t2(8); t2(8); t2(8); 
+       t2(2); t2(2);
+       
+       switch (pi->mode) {
+
+       case 0: t2(8); WR(4,0);
+               break;
+
+       case 1: t2(8); WR(4,0x10);
+               break;
+
+       case 2:
+        case 3:
+       case 4: w2(0); WR(4,8);
+               break;
+
+       }
+
+       WR(5,8);
+
+       if (pi->devtype == PI_PCD) {
+               WR(0x46,0x10);          /* fiddle with ESS logic ??? */
+               WR(0x4c,0x38);
+               WR(0x4d,0x88);
+               WR(0x46,0xa0);
+               WR(0x41,0);
+               WR(0x4e,8);
+               }
+}
+
+static void bpck_disconnect ( PIA *pi )
+
+{      w0(0); 
+       if (pi->mode >= 2) { w2(9); w2(0); } else t2(2);
+       w2(0x4c); w0(pi->saved_r0);
+} 
+
+static void bpck_force_spp ( PIA *pi )
+
+/* This fakes the EPP protocol to turn off EPP ... */
+
+{       pi->saved_r0 = r0();
+        w0(0xff-pi->unit); w2(4); w0(pi->unit);
+        t2(8); t2(8); t2(8); 
+        t2(2); t2(2);
+
+        w2(0); 
+        w0(4); w2(9); w2(0); 
+        w0(0); w2(1); w2(3); w2(0);     
+        w0(0); w2(9); w2(0);
+        w2(0x4c); w0(pi->saved_r0);
+}
+
+#define TEST_LEN  16
+
+static int bpck_test_proto( PIA *pi, char * scratch, int verbose )
+
+{      int i, e, l, h, om;
+       char buf[TEST_LEN];
+
+       bpck_force_spp(pi);
+
+       switch (pi->mode) {
+
+       case 0: bpck_connect(pi);
+               WR(0x13,0x7f);
+               w0(0x13); t2(2);
+               for(i=0;i<TEST_LEN;i++) {
+                    t2(4); l = r1();
+                    t2(4); h = r1();
+                    buf[i] = j44(l,h);
+               }
+               bpck_disconnect(pi);
+               break;
+
+        case 1: bpck_connect(pi);
+               WR(0x13,0x7f);
+                w0(0x13); t2(2); t2(0x20);
+                for(i=0;i<TEST_LEN;i++) { t2(4); buf[i] = r0(); }
+                t2(1); t2(0x20);
+               bpck_disconnect(pi);
+               break;
+
+       case 2:
+       case 3:
+       case 4: om = pi->mode;
+               pi->mode = 0;
+               bpck_connect(pi);
+               WR(7,3);
+               WR(4,8);
+               bpck_disconnect(pi);
+
+               pi->mode = om;
+               bpck_connect(pi);
+               w0(0x13); w2(9); w2(1); w0(0); w2(3); w2(0); w2(0xe0);
+
+               switch (pi->mode) {
+                 case 2: for (i=0;i<TEST_LEN;i++) buf[i] = r4();
+                         break;
+                 case 3: for (i=0;i<TEST_LEN/2;i++) ((u16 *)buf)[i] = r4w();
+                          break;
+                 case 4: for (i=0;i<TEST_LEN/4;i++) ((u32 *)buf)[i] = r4l();
+                          break;
+               }
+
+               w2(0);
+               WR(7,0);
+               bpck_disconnect(pi);
+
+               break;
+
+       }
+
+       if (verbose) {
+           printk("%s: bpck: 0x%x unit %d mode %d: ",
+                  pi->device,pi->port,pi->unit,pi->mode);
+           for (i=0;i<TEST_LEN;i++) printk("%3d",buf[i]);
+           printk("\n");
+       }
+
+       e = 0;
+       for (i=0;i<TEST_LEN;i++) if (buf[i] != (i+1)) e++;
+       return e;
+}
+
+static void bpck_read_eeprom ( PIA *pi, char * buf )
+
+{       int i,j,k,n,p,v,f, om;
+
+       bpck_force_spp(pi);
+
+       om = pi->mode;
+       pi->mode = 0;
+
+       bpck_connect(pi);
+       
+       n = 0;
+       WR(4,0);
+       for (i=0;i<64;i++) {
+           WR(6,8);  
+           WR(6,0xc);
+           p = 0x100;
+           for (k=0;k<9;k++) {
+               f = (((i + 0x180) & p) != 0) * 2;
+               WR(6,f+0xc); 
+               WR(6,f+0xd); 
+               WR(6,f+0xc);
+               p = (p >> 1);
+           }
+           for (j=0;j<2;j++) {
+               v = 0;
+               for (k=0;k<8;k++) {
+                   WR(6,0xc); 
+                   WR(6,0xd); 
+                   WR(6,0xc); 
+                   f = RR(0);
+                   v = 2*v + (f == 0x84);
+               }
+               buf[2*i+1-j] = v;
+           }
+       }
+       WR(6,8);
+       WR(6,0);
+       WR(5,8);
+
+       bpck_disconnect(pi);
+
+        if (om >= 2) {
+                bpck_connect(pi);
+                WR(7,3);
+                WR(4,8);
+                bpck_disconnect(pi);
+        }
+
+       pi->mode = om;
+}
+
+static int bpck_test_port ( PIA *pi )  /* check for 8-bit port */
+
+{      int     i, r, m;
+
+       w2(0x2c); i = r0(); w0(255-i); r = r0(); w0(i);
+       m = -1;
+       if (r == i) m = 2;
+       if (r == (255-i)) m = 0;
+
+       w2(0xc); i = r0(); w0(255-i); r = r0(); w0(i);
+       if (r != (255-i)) m = -1;
+       
+       if (m == 0) { w2(6); w2(0xc); r = r0(); w0(0xaa); w0(r); w0(0xaa); }
+       if (m == 2) { w2(0x26); w2(0xc); }
+
+       if (m == -1) return 0;
+       return 5;
+}
+
+static void bpck_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{      char    *mode_string[5] = { "4-bit","8-bit","EPP-8",
+                                   "EPP-16","EPP-32" };
+
+#ifdef DUMP_EEPROM
+       int i;
+#endif
+
+       bpck_read_eeprom(pi,scratch);
+
+#ifdef DUMP_EEPROM
+       if (verbose) {
+          for(i=0;i<128;i++)
+               if ((scratch[i] < ' ') || (scratch[i] > '~'))
+                   scratch[i] = '.';
+          printk("%s: bpck EEPROM: %64.64s\n",pi->device,scratch);
+          printk("%s:              %64.64s\n",pi->device,&scratch[64]);
+       }
+#endif
+
+       printk("%s: bpck %s, backpack %8.8s unit %d",
+               pi->device,BPCK_VERSION,&scratch[110],pi->unit);
+       printk(" at 0x%x, mode %d (%s), delay %d\n",pi->port,
+               pi->mode,mode_string[pi->mode],pi->delay);
+}
+
+static void bpck_inc_use( void )
+
+{      MOD_INC_USE_COUNT;
+}
+
+static void bpck_dec_use( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol bpck = { "bpck",0,5,2,4,256,
+                         bpck_write_regr,
+                         bpck_read_regr,
+                         bpck_write_block,
+                         bpck_read_block,
+                         bpck_connect,
+                         bpck_disconnect,
+                         bpck_test_port,
+                         bpck_probe_unit,
+                         bpck_test_proto,
+                         bpck_log_adapter,
+                         bpck_inc_use,
+                         bpck_dec_use
+                       };
+
+#ifdef MODULE
+
+int    init_module(void)
+
+{      return pi_register(&bpck) - 1;
+}
+
+void   cleanup_module(void)
+
+{      pi_unregister(&bpck);
+}
+
+#endif
+
+/* end of bpck.c */
diff --git a/drivers/block/paride/comm.c b/drivers/block/paride/comm.c
new file mode 100644 (file)
index 0000000..794bbb9
--- /dev/null
@@ -0,0 +1,222 @@
+/* 
+        comm.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
+
+       comm.c is a low-level protocol driver for some older models
+       of the DataStor "Commuter" parallel to IDE adapter.  Some of
+       the parallel port devices marketed by Arista currently
+       use this adapter.
+*/
+
+#define COMM_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+/* mode codes:  0  nybble reads, 8-bit writes
+                1  8-bit reads and writes
+                2  8-bit EPP mode
+*/
+
+#define j44(a,b)       (((a>>3)&0x0f)|((b<<1)&0xf0))
+
+#define P1     w2(5);w2(0xd);w2(0xd);w2(5);w2(4);
+#define P2     w2(5);w2(7);w2(7);w2(5);w2(4);
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x08, 0x10 };
+
+static int comm_read_regr( PIA *pi, int cont, int regr )
+
+{       int     l, h, r;
+
+        r = regr + cont_map[cont];
+
+        switch (pi->mode)  {
+
+        case 0: w0(r); P1; w0(0);
+               w2(6); l = r1(); w0(0x80); h = r1(); w2(4);
+                return j44(l,h);
+
+        case 1: w0(r+0x20); P1; 
+               w0(0); w2(0x26); h = r0(); w2(4);
+                return h;
+
+       case 2:
+       case 3:
+        case 4: w3(r+0x20); r1(); 
+               w2(0x24); h = r4(); w2(4);
+                return h;
+
+        }
+        return -1;
+}       
+
+static void comm_write_regr( PIA *pi, int cont, int regr, int val )
+
+{       int  r;
+
+        r = regr + cont_map[cont];
+
+        switch (pi->mode)  {
+
+        case 0:
+        case 1: w0(r); P1; w0(val); P2;
+               break;
+
+       case 2:
+       case 3:
+        case 4: w3(r); r1(); w4(val); 
+                break;
+        }
+}
+
+static void comm_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+        w2(4); w0(0xff); w2(6);
+        w2(4); w0(0xaa); w2(6);
+        w2(4); w0(0x00); w2(6);
+        w2(4); w0(0x87); w2(6);
+        w2(4); w0(0xe0); w2(0xc); w2(0xc); w2(4);
+}
+
+static void comm_disconnect ( PIA *pi )
+
+{       w2(0); w2(0); w2(0); w2(4); 
+       w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void comm_read_block( PIA *pi, char * buf, int count )
+
+{       int     i, l, h;
+
+        switch (pi->mode) {
+        
+        case 0: w0(0x48); P1;
+                for(i=0;i<count;i++) {
+                        w0(0); w2(6); l = r1();
+                        w0(0x80); h = r1(); w2(4);
+                        buf[i] = j44(l,h);
+                }
+                break;
+
+        case 1: w0(0x68); P1; w0(0);
+                for(i=0;i<count;i++) {
+                        w2(0x26); buf[i] = r0(); w2(0x24);
+                }
+               w2(4);
+               break;
+               
+       case 2: w3(0x68); r1(); w2(0x24);
+               for (i=0;i<count;i++) buf[i] = r4();
+               w2(4);
+               break;
+
+        case 3: w3(0x68); r1(); w2(0x24);
+                for (i=0;i<count/2;i++) ((u16 *)buf)[i] = r4w();
+                w2(4);
+                break;
+
+        case 4: w3(0x68); r1(); w2(0x24);
+                for (i=0;i<count/4;i++) ((u32 *)buf)[i] = r4l();
+                w2(4);
+                break;
+               
+       }
+}
+
+/* NB: Watch out for the byte swapped writes ! */
+
+static void comm_write_block( PIA *pi, char * buf, int count )
+
+{       int    k;
+
+        switch (pi->mode) {
+
+        case 0:
+        case 1: w0(0x68); P1;
+               for (k=0;k<count;k++) {
+                        w2(5); w0(buf[k^1]); w2(7);
+                }
+                w2(5); w2(4);
+                break;
+
+        case 2: w3(0x48); r1();
+                for (k=0;k<count;k++) w4(buf[k^1]);
+                break;
+
+        case 3: w3(0x48); r1();
+                for (k=0;k<count/2;k++) w4w(pi_swab16(buf,k));
+                break;
+
+        case 4: w3(0x48); r1();
+                for (k=0;k<count/4;k++) w4l(pi_swab32(buf,k));
+                break;
+
+
+        }
+}
+
+static void comm_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[5] = {"4-bit","8-bit","EPP-8","EPP-16","EPP-32"};
+
+        printk("%s: comm %s, DataStor Commuter at 0x%x, ",
+                pi->device,COMM_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void comm_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void comm_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol comm = {"comm",0,5,2,1,1,
+                           comm_write_regr,
+                           comm_read_regr,
+                           comm_write_block,
+                           comm_read_block,
+                           comm_connect,
+                           comm_disconnect,
+                           0,
+                           0,
+                           0,
+                           comm_log_adapter,
+                           comm_inc_use, 
+                           comm_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &comm ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &comm );
+}
+
+#endif
+
+/* end of comm.c */
diff --git a/drivers/block/paride/dstr.c b/drivers/block/paride/dstr.c
new file mode 100644 (file)
index 0000000..53cedcc
--- /dev/null
@@ -0,0 +1,237 @@
+/* 
+        dstr.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
+
+        dstr.c is a low-level protocol driver for the 
+        DataStor EP2000 parallel to IDE adapter chip.
+
+*/
+
+#define DSTR_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+/* mode codes:  0  nybble reads, 8-bit writes
+                1  8-bit reads and writes
+                2  8-bit EPP mode
+               3  EPP-16
+               4  EPP-32
+*/
+
+#define j44(a,b)  (((a>>3)&0x07)|((~a>>4)&0x08)|((b<<1)&0x70)|((~b)&0x80))
+
+#define P1     w2(5);w2(0xd);w2(5);w2(4);
+#define P2     w2(5);w2(7);w2(5);w2(4);
+#define P3      w2(6);w2(4);w2(6);w2(4);
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x20, 0x40 };
+
+static int dstr_read_regr( PIA *pi, int cont, int regr )
+
+{       int     a, b, r;
+
+        r = regr + cont_map[cont];
+
+       w0(0x81); P1;
+       if (pi->mode) { w0(0x11); } else { w0(1); }
+       P2; w0(r); P1;
+
+        switch (pi->mode)  {
+
+        case 0: w2(6); a = r1(); w2(4); w2(6); b = r1(); w2(4);
+                return j44(a,b);
+
+        case 1: w0(0); w2(0x26); a = r0(); w2(4);
+                return a;
+
+       case 2:
+       case 3:
+        case 4: w2(0x24); a = r4(); w2(4);
+                return a;
+
+        }
+        return -1;
+}       
+
+static void dstr_write_regr(  PIA *pi, int cont, int regr, int val )
+
+{       int  r;
+
+        r = regr + cont_map[cont];
+
+       w0(0x81); P1; 
+       if (pi->mode >= 2) { w0(0x11); } else { w0(1); }
+       P2; w0(r); P1;
+       
+        switch (pi->mode)  {
+
+        case 0:
+        case 1: w0(val); w2(5); w2(7); w2(5); w2(4);
+               break;
+
+       case 2:
+       case 3:
+        case 4: w4(val); 
+                break;
+        }
+}
+
+#define  CCP(x)  w0(0xff);w2(0xc);w2(4);\
+                w0(0xaa);w0(0x55);w0(0);w0(0xff);w0(0x87);w0(0x78);\
+                w0(x);w2(5);w2(4);
+
+static void dstr_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+        w2(4); CCP(0xe0); w0(0xff);
+}
+
+static void dstr_disconnect ( PIA *pi )
+
+{       CCP(0x30);
+        w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void dstr_read_block( PIA *pi, char * buf, int count )
+
+{       int     k, a, b;
+
+        w0(0x81); P1;
+        if (pi->mode) { w0(0x19); } else { w0(9); }
+       P2; w0(0x82); P1; P3; w0(0x20); P1;
+
+        switch (pi->mode) {
+
+        case 0: for (k=0;k<count;k++) {
+                        w2(6); a = r1(); w2(4);
+                        w2(6); b = r1(); w2(4);
+                        buf[k] = j44(a,b);
+                } 
+                break;
+
+        case 1: w0(0);
+                for (k=0;k<count;k++) {
+                        w2(0x26); buf[k] = r0(); w2(0x24);
+                }
+                w2(4);
+                break;
+
+        case 2: w2(0x24); 
+                for (k=0;k<count;k++) buf[k] = r4();
+                w2(4);
+                break;
+
+        case 3: w2(0x24); 
+                for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w();
+                w2(4);
+                break;
+
+        case 4: w2(0x24); 
+                for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l();
+                w2(4);
+                break;
+
+        }
+}
+
+static void dstr_write_block( PIA *pi, char * buf, int count )
+
+{       int    k;
+
+        w0(0x81); P1;
+        if (pi->mode) { w0(0x19); } else { w0(9); }
+        P2; w0(0x82); P1; P3; w0(0x20); P1;
+
+        switch (pi->mode) {
+
+        case 0:
+        case 1: for (k=0;k<count;k++) {
+                        w2(5); w0(buf[k]); w2(7);
+                }
+                w2(5); w2(4);
+                break;
+
+        case 2: w2(0xc5);
+                for (k=0;k<count;k++) w4(buf[k]);
+               w2(0xc4);
+                break;
+
+        case 3: w2(0xc5);
+                for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
+                w2(0xc4);
+                break;
+
+        case 4: w2(0xc5);
+                for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
+                w2(0xc4);
+                break;
+
+        }
+}
+
+
+static void dstr_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[5] = {"4-bit","8-bit","EPP-8",
+                                  "EPP-16","EPP-32"};
+
+        printk("%s: dstr %s, DataStor EP2000 at 0x%x, ",
+                pi->device,DSTR_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void dstr_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void dstr_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol dstr = {"dstr",0,5,2,1,1,
+                           dstr_write_regr,
+                           dstr_read_regr,
+                           dstr_write_block,
+                           dstr_read_block,
+                           dstr_connect,
+                           dstr_disconnect,
+                           0,
+                           0,
+                           0,
+                           dstr_log_adapter,
+                           dstr_inc_use, 
+                           dstr_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &dstr ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &dstr );
+}
+
+#endif
+
+/* end of dstr.c */
diff --git a/drivers/block/paride/epat.c b/drivers/block/paride/epat.c
new file mode 100644 (file)
index 0000000..f6c19c9
--- /dev/null
@@ -0,0 +1,315 @@
+/* 
+        epat.c  (c) 1997  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+       This is the low level protocol driver for the EPAT parallel
+        to IDE adapter from Shuttle Technologies.  This adapter is
+        used in many popular parallel port disk products such as the
+        SyQuest EZ drives, the Avatar Shark and the Imation SuperDisk.
+       
+*/
+
+#define EPAT_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define j44(a,b)               (((a>>4)&0x0f)+(b&0xf0))
+#define j53(a,b)               (((a>>3)&0x1f)+((b<<4)&0xe0))
+
+/* cont =  0   IDE register file
+   cont =  1   IDE control registers
+   cont =  2   internal EPAT registers
+*/
+
+static int cont_map[3] = { 0x18, 0x10, 0 };
+
+static void epat_write_regr( PIA *pi, int cont, int regr, int val)
+
+{      int r;
+
+       r = regr + cont_map[cont];
+
+       switch (pi->mode) {
+
+       case 0:
+       case 1:
+       case 2: w0(0x60+r); w2(1); w0(val); w2(4);
+               break;
+
+       case 3:
+       case 4:
+       case 5: w3(0x40+r); w4(val);
+               break;
+
+       }
+}
+
+static int epat_read_regr( PIA *pi, int cont, int regr )
+
+{      int  a, b, r;
+
+       r = regr + cont_map[cont];
+
+       switch (pi->mode) {
+
+       case 0: w0(r); w2(1); w2(3); 
+               a = r1(); w2(4); b = r1();
+               return j44(a,b);
+
+       case 1: w0(0x40+r); w2(1); w2(4);
+               a = r1(); b = r2(); w0(0xff);
+               return j53(a,b);
+
+       case 2: w0(0x20+r); w2(1); w2(0x25);
+               a = r0(); w2(4);
+               return a;
+
+       case 3:
+       case 4:
+       case 5: w3(r); w2(0x24); a = r4(); w2(4);
+               return a;
+
+       }
+       return -1;      /* never gets here */
+}
+
+static void epat_read_block( PIA *pi, char * buf, int count )
+
+{      int  k, ph, a, b;
+
+       switch (pi->mode) {
+
+       case 0: w0(7); w2(1); w2(3); w0(0xff);
+               ph = 0;
+               for(k=0;k<count;k++) {
+                       if (k == count-1) w0(0xfd);
+                       w2(6+ph); a = r1();
+                       if (a & 8) b = a; 
+                         else { w2(4+ph); b = r1(); }
+                       buf[k] = j44(a,b);
+                       ph =  1 - ph;
+               }
+               w0(0); w2(4);
+               break;
+
+       case 1: w0(0x47); w2(1); w2(5); w0(0xff);
+               ph = 0;
+               for(k=0;k<count;k++) {
+                       if (k == count-1) w0(0xfd); 
+                       w2(4+ph);
+                       a = r1(); b = r2();
+                       buf[k] = j53(a,b);
+                       ph = 1 - ph;
+               }
+               w0(0); w2(4);
+               break;
+
+       case 2: w0(0x27); w2(1); w2(0x25); w0(0);
+               ph = 0;
+               for(k=0;k<count-1;k++) {
+                       w2(0x24+ph);
+                       buf[k] = r0();
+                       ph = 1 - ph;
+               }
+               w2(0x26); w2(0x27); buf[count-1] = r0(); 
+               w2(0x25); w2(4);
+               break;
+
+       case 3: w3(0x80); w2(0x24);
+               for(k=0;k<count-1;k++) buf[k] = r4();
+               w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4();
+               w2(4);
+               break;
+
+       case 4: w3(0x80); w2(0x24);
+               for(k=0;k<(count/2)-1;k++) ((u16 *)buf)[k] = r4w();
+               buf[count-2] = r4();
+               w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4();
+               w2(4);
+               break;
+
+       case 5: w3(0x80); w2(0x24);
+               for(k=0;k<(count/4)-1;k++) ((u32 *)buf)[k] = r4l();
+               for(k=count-4;k<count-1;k++) buf[k] = r4();
+               w2(4); w3(0xa0); w2(0x24); buf[count-1] = r4();
+               w2(4);
+               break;
+
+       }
+}
+
+static void epat_write_block( PIA *pi, char * buf, int count )   
+
+{      int ph, k;
+
+       switch (pi->mode) {
+
+       case 0:
+       case 1:
+       case 2: w0(0x67); w2(1); w2(5);
+               ph = 0;
+               for(k=0;k<count;k++) {
+                       w0(buf[k]);
+                       w2(4+ph);
+                       ph = 1 - ph;
+               }
+               w2(7); w2(4);
+               break;
+
+       case 3: w3(0xc0); 
+               for(k=0;k<count;k++) w4(buf[k]);
+               w2(4);
+               break;
+
+       case 4: w3(0xc0); 
+               for(k=0;k<(count/2);k++) w4w(((u16 *)buf)[k]);
+               w2(4);
+               break;
+
+       case 5: w3(0xc0); 
+               for(k=0;k<(count/4);k++) w4l(((u32 *)buf)[k]);
+               w2(4);
+               break;
+
+       }
+}
+
+/* these macros access the EPAT registers in native addressing */
+
+#define        WR(r,v)         epat_write_regr(pi,2,r,v)
+#define        RR(r)           (epat_read_regr(pi,2,r))
+
+/* and these access the IDE task file */
+
+#define WRi(r,v)         epat_write_regr(pi,0,r,v)
+#define RRi(r)           (epat_read_regr(pi,0,r))
+
+/* FIXME:  the CCP stuff should be fixed to handle multiple EPATs on a chain */
+
+#define CCP(x)         w2(4);w0(0x22);w0(0xaa);w0(0x55);w0(0);w0(0xff);\
+                w0(0x87);w0(0x78);w0(x);w2(4);w2(5);w2(4);w0(0xff);
+
+static void epat_connect ( PIA *pi )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+       CCP(0); CCP(0xe0);
+       w0(0); w2(1); w2(4);
+       if (pi->mode >= 3) {
+               w0(0); w2(1); w2(4); w2(0xc);
+               w0(0x40); w2(6); w2(7); w2(4); w2(0xc); w2(4);
+       }
+       WR(8,0x10); WR(0xc,0x14); WR(0xa,0x38); WR(0x12,0x10);
+}
+
+static void epat_disconnect ( PIA *pi )
+
+{       CCP(0x30);
+        w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static int epat_test_proto( PIA *pi, char * scratch, int verbose )
+
+{       int     k, j, f, cc;
+       int     e[2] = {0,0};
+
+        epat_connect(pi);
+       cc = RR(0xd);
+       epat_disconnect(pi);
+
+       epat_connect(pi);
+       for (j=0;j<2;j++) {
+           WRi(6,0xa0+j*0x10);
+            for (k=0;k<256;k++) {
+                WRi(2,k^0xaa);
+                WRi(3,k^0x55);
+                if (RRi(2) != (k^0xaa)) e[j]++;
+                }
+           }
+        epat_disconnect(pi);
+
+        f = 0;
+        epat_connect(pi);
+        WR(0x13,1); WR(0x13,0); WR(0xa,0x11);
+        epat_read_block(pi,scratch,512);
+       
+        for (k=0;k<256;k++) {
+            if ((scratch[2*k] & 0xff) != k) f++;
+            if ((scratch[2*k+1] & 0xff) != (0xff-k)) f++;
+        }
+        epat_disconnect(pi);
+
+        if (verbose)  {
+            printk("%s: epat: port 0x%x, mode %d, ccr %x, test=(%d,%d,%d)\n",
+                  pi->device,pi->port,pi->mode,cc,e[0],e[1],f);
+       }
+       
+        return (e[0] && e[1]) || f;
+}
+
+static void epat_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{      int     ver;
+        char    *mode_string[6] = 
+                  {"4-bit","5/3","8-bit","EPP-8","EPP-16","EPP-32"};
+
+       epat_connect(pi);
+       WR(0xa,0x38);           /* read the version code */
+        ver = RR(0xb);
+        epat_disconnect(pi);
+
+       printk("%s: epat %s, Shuttle EPAT chip %x at 0x%x, ",
+               pi->device,EPAT_VERSION,ver,pi->port);
+       printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void epat_inc_use ( void )
+
+{      MOD_INC_USE_COUNT;
+}
+
+static void epat_dec_use ( void )
+
+{      MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol epat = {"epat",0,6,3,1,1,
+                          epat_write_regr,
+                          epat_read_regr,
+                          epat_write_block,
+                          epat_read_block,
+                          epat_connect,
+                          epat_disconnect,
+                          0,
+                          0,
+                          epat_test_proto,
+                          epat_log_adapter,
+                          epat_inc_use, 
+                          epat_dec_use 
+                         };
+
+
+#ifdef MODULE
+
+int    init_module(void)
+
+{      return pi_register( &epat) - 1;
+}
+
+void   cleanup_module(void)
+
+{      pi_unregister( &epat);
+}
+
+#endif
+
+/* end of epat.c */
diff --git a/drivers/block/paride/epia.c b/drivers/block/paride/epia.c
new file mode 100644 (file)
index 0000000..73d83fe
--- /dev/null
@@ -0,0 +1,318 @@
+/* 
+        epia.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
+
+        epia.c is a low-level protocol driver for Shuttle Technologies 
+       EPIA parallel to IDE adapter chip.  This device is now obsolete
+       and has been replaced with the EPAT chip, which is supported
+       by epat.c, however, some devices based on EPIA are still
+       available.
+
+*/
+
+#define EPIA_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+/* mode codes:  0  nybble reads on port 1, 8-bit writes
+                1  5/3 reads on ports 1 & 2, 8-bit writes
+                2  8-bit reads and writes
+                3  8-bit EPP mode
+               4  16-bit EPP
+               5  32-bit EPP
+*/
+
+#define j44(a,b)                (((a>>4)&0x0f)+(b&0xf0))
+#define j53(a,b)                (((a>>3)&0x1f)+((b<<4)&0xe0))
+
+/* cont =  0   IDE register file
+   cont =  1   IDE control registers
+*/
+
+static int cont_map[2] = { 0, 0x80 };
+
+static int epia_read_regr( PIA *pi, int cont, int regr )
+
+{       int     a, b, r;
+
+       regr += cont_map[cont];
+
+        switch (pi->mode)  {
+
+        case 0: r = regr^0x39;
+                w0(r); w2(1); w2(3); w0(r);
+                a = r1(); w2(1); b = r1(); w2(4);
+                return j44(a,b);
+
+        case 1: r = regr^0x31;
+                w0(r); w2(1); w0(r&0x37); 
+                w2(3); w2(5); w0(r|0xf0);
+                a = r1(); b = r2(); w2(4);
+                return j53(a,b);
+
+        case 2: r = regr^0x29;
+                w0(r); w2(1); w2(0X21); w2(0x23); 
+                a = r0(); w2(4);
+                return a;
+
+       case 3:
+       case 4:
+        case 5: w3(regr); w2(0x24); a = r4(); w2(4);
+                return a;
+
+        }
+        return -1;
+}       
+
+static void epia_write_regr( PIA *pi, int cont, int regr, int val)
+
+{       int  r;
+
+       regr += cont_map[cont];
+
+        switch (pi->mode)  {
+
+        case 0:
+        case 1:
+        case 2: r = regr^0x19;
+                w0(r); w2(1); w0(val); w2(3); w2(4);
+                break;
+
+       case 3:
+       case 4:
+        case 5: r = regr^0x40;
+                w3(r); w4(val); w2(4);
+                break;
+        }
+}
+
+#define WR(r,v)         epia_write_regr(pi,0,r,v)
+#define RR(r)           (epia_read_regr(pi,0,r))
+
+/* The use of register 0x84 is entirely unclear - it seems to control
+   some EPP counters ...  currently we know about 3 different block
+   sizes:  the standard 512 byte reads and writes, 12 byte writes and 
+   2048 byte reads (the last two being used in the CDrom drivers.
+*/
+
+static void epia_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+
+        w2(4); w0(0xa0); w0(0x50); w0(0xc0); w0(0x30); w0(0xa0); w0(0);
+        w2(1); w2(4);
+        if (pi->mode >= 3) { 
+                w0(0xa); w2(1); w2(4); w0(0x82); w2(4); w2(0xc); w2(4);
+                w2(0x24); w2(0x26); w2(4);
+        }
+        WR(0x86,8);  
+}
+
+static void epia_disconnect ( PIA *pi )
+
+{       WR(0x84,0x10);
+        w0(pi->saved_r0);
+        w2(1); w2(4);
+        w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void epia_read_block( PIA *pi, char * buf, int count )
+
+{       int     k, ph, a, b;
+
+        switch (pi->mode) {
+
+        case 0: w0(0x81); w2(1); w2(3); w0(0xc1);
+                ph = 1;
+                for (k=0;k<count;k++) {
+                        w2(2+ph); a = r1();
+                        w2(4+ph); b = r1();
+                        buf[k] = j44(a,b);
+                        ph = 1 - ph;
+                } 
+                w0(0); w2(4);
+                break;
+
+        case 1: w0(0x91); w2(1); w0(0x10); w2(3); 
+                w0(0x51); w2(5); w0(0xd1); 
+                ph = 1;
+                for (k=0;k<count;k++) {
+                        w2(4+ph);
+                        a = r1(); b = r2();
+                        buf[k] = j53(a,b);
+                        ph = 1 - ph;
+                }
+                w0(0); w2(4);
+                break;
+
+        case 2: w0(0x89); w2(1); w2(0x23); w2(0x21); 
+                ph = 1;
+                for (k=0;k<count;k++) {
+                        w2(0x24+ph);
+                        buf[k] = r0();
+                        ph = 1 - ph;
+                }
+                w2(6); w2(4);
+                break;
+
+        case 3: if (count > 512) WR(0x84,3);
+               w3(0); w2(0x24);
+                for (k=0;k<count;k++) buf[k] = r4();
+                w2(4); WR(0x84,0);
+                break;
+
+        case 4: if (count > 512) WR(0x84,3);
+               w3(0); w2(0x24);
+               for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w();
+                w2(4); WR(0x84,0);
+                break;
+
+        case 5: if (count > 512) WR(0x84,3);
+               w3(0); w2(0x24);
+                for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l();
+                w2(4); WR(0x84,0);
+                break;
+
+        }
+}
+
+static void epia_write_block( PIA *pi, char * buf, int count )
+
+{       int     ph, k, last, d;
+
+        switch (pi->mode) {
+
+        case 0:
+        case 1:
+        case 2: w0(0xa1); w2(1); w2(3); w2(1); w2(5);
+                ph = 0;  last = 0x8000;
+                for (k=0;k<count;k++) {
+                        d = buf[k];
+                        if (d != last) { last = d; w0(d); }
+                        w2(4+ph);
+                        ph = 1 - ph;
+                }
+                w2(7); w2(4);
+                break;
+
+        case 3: if (count < 512) WR(0x84,1);
+               w3(0x40);
+                for (k=0;k<count;k++) w4(buf[k]);
+               if (count < 512) WR(0x84,0);
+                break;
+
+        case 4: if (count < 512) WR(0x84,1);
+               w3(0x40);
+                for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
+               if (count < 512) WR(0x84,0);
+                break;
+
+        case 5: if (count < 512) WR(0x84,1);
+               w3(0x40);
+                for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
+               if (count < 512) WR(0x84,0);
+                break;
+
+        }
+
+}
+
+static int epia_test_proto( PIA *pi, char * scratch, int verbose )
+
+{       int     j, k, f;
+       int     e[2] = {0,0};
+
+        epia_connect(pi);
+        for (j=0;j<2;j++) {
+            WR(6,0xa0+j*0x10);
+            for (k=0;k<256;k++) {
+                WR(2,k^0xaa);
+                WR(3,k^0x55);
+                if (RR(2) != (k^0xaa)) e[j]++;
+                }
+            }
+        epia_disconnect(pi);
+
+        f = 0;
+        epia_connect(pi);
+        WR(0x84,8);
+        epia_read_block(pi,scratch,512);
+        for (k=0;k<256;k++) {
+            if ((scratch[2*k] & 0xff) != ((k+1) & 0xff)) f++;
+            if ((scratch[2*k+1] & 0xff) != ((-2-k) & 0xff)) f++;
+        }
+        WR(0x84,0);
+        epia_disconnect(pi);
+
+        if (verbose)  {
+            printk("%s: epia: port 0x%x, mode %d, test=(%d,%d,%d)\n",
+                   pi->device,pi->port,pi->mode,e[0],e[1],f);
+        }
+        
+        return (e[0] && e[1]) || f;
+
+}
+
+
+static void epia_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[6] = {"4-bit","5/3","8-bit",
+                                  "EPP-8","EPP-16","EPP-32"};
+
+        printk("%s: epia %s, Shuttle EPIA at 0x%x, ",
+                pi->device,EPIA_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void epia_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void epia_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol epia = {"epia",0,6,3,1,1,
+                           epia_write_regr,
+                           epia_read_regr,
+                           epia_write_block,
+                           epia_read_block,
+                           epia_connect,
+                           epia_disconnect,
+                           0,
+                           0,
+                           epia_test_proto,
+                           epia_log_adapter,
+                           epia_inc_use, 
+                           epia_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &epia ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &epia );
+}
+
+#endif
+
+/* end of epia.c */
+
diff --git a/drivers/block/paride/frpw.c b/drivers/block/paride/frpw.c
new file mode 100644 (file)
index 0000000..fe7b145
--- /dev/null
@@ -0,0 +1,256 @@
+/* 
+       frpw.c  (c) 1997  Grant R. Guenther <grant@torque.net>
+                         Under the terms of the GNU public license
+
+       frpw.c is a low-level protocol driver for the Freecom "Power"
+       parallel port IDE adapter.
+       
+*/
+
+#define        FRPW_VERSION    "1.0" 
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define cec4           w2(0xc);w2(0xe);w2(0xe);w2(0xc);w2(4);w2(4);w2(4);
+#define j44(l,h)       (((l>>4)&0x0f)|(h&0xf0))
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x08, 0x10 };
+
+static int frpw_read_regr( PIA *pi, int cont, int regr )
+
+{      int     h,l,r;
+
+       r = regr + cont_map[cont];
+
+       w2(4);
+       w0(r); cec4;
+       w2(6); l = r1();
+       w2(4); h = r1();
+       w2(4); 
+
+       return j44(l,h);
+
+}
+
+static void frpw_write_regr( PIA *pi, int cont, int regr, int val)
+
+{      int r;
+
+        r = regr + cont_map[cont];
+
+       w2(4); w0(r); cec4; 
+       w0(val);
+       w2(5);w2(7);w2(5);w2(4);
+}
+
+static void frpw_read_block_int( PIA *pi, char * buf, int count, int regr )
+
+{       int     h, l, k, ph;
+
+        switch(pi->mode) {
+
+        case 0: w2(4); w0(regr); cec4;
+                for (k=0;k<count;k++) {
+                        w2(6); l = r1();
+                        w2(4); h = r1();
+                        buf[k] = j44(l,h);
+                }
+                w2(4);
+                break;
+
+        case 1: ph = 2;
+                w2(4); w0(regr + 0xc0); cec4;
+                w0(0xff);
+                for (k=0;k<count;k++) {
+                        w2(0xa4 + ph); 
+                        buf[k] = r0();
+                        ph = 2 - ph;
+                } 
+                w2(0xac); w2(0xa4); w2(4);
+                break;
+
+        case 2: w2(4); w0(regr + 0x80); cec4;
+                for (k=0;k<count;k++) buf[k] = r4();
+                w2(0xac); w2(0xa4);
+                w2(4);
+                break;
+
+       case 3: w2(4); w0(regr + 0x80); cec4;
+               for (k=0;k<count-2;k++) buf[k] = r4();
+               w2(0xac); w2(0xa4);
+               buf[count-2] = r4();
+               buf[count-1] = r4();
+               w2(4);
+               break;
+
+        }
+}
+
+static void frpw_read_block( PIA *pi, char * buf, int count)
+
+{      frpw_read_block_int(pi,buf,count,0x08);
+}
+
+static void frpw_write_block( PIA *pi, char * buf, int count )
+{      int     k;
+
+       switch(pi->mode) {
+
+       case 0:
+       case 1:
+       case 2: w2(4); w0(8); cec4; w2(5);
+               for (k=0;k<count;k++) {
+                       w0(buf[k]);
+                       w2(7);w2(5);
+               }
+               w2(4);
+               break;
+
+       case 3: w2(4); w0(0xc8); cec4; w2(5);
+               for (k=0;k<count;k++) w4(buf[k]);
+               w2(4);
+               break;
+       }
+}
+
+static void frpw_connect ( PIA *pi  )
+
+{       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+       w2(4);
+}
+
+static void frpw_disconnect ( PIA *pi )
+
+{       w2(4); w0(0x20); cec4;
+       w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+/* Stub logic to see if PNP string is available - used to distinguish
+   between the Xilinx and ASIC implementations of the Freecom adapter.
+*/
+
+static int frpw_test_pnp ( PIA *pi )
+
+{      int olddelay, a, b;
+
+       olddelay = pi->delay;
+       pi->delay = 10;
+
+       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+       
+       w2(4); w0(4); w2(6); w2(7);
+       a = r1() & 0xff; w2(4); b = r1() & 0xff;
+       w2(0xc); w2(0xe); w2(4);
+
+       pi->delay = olddelay;
+        w0(pi->saved_r0);
+        w2(pi->saved_r2);
+
+       return ((~a&0x40) && (b&0x40));
+} 
+
+/*  We use pi->private to record the chip type:  
+       0 = untested, 2 = Xilinx, 3 = ASIC
+*/  
+
+static int frpw_test_proto( PIA *pi, char * scratch, int verbose )
+
+{       int     k, r;
+
+       if (!pi->private) pi->private = frpw_test_pnp(pi) + 2;
+
+       if ((pi->private == 2) && (pi->mode > 2)) {
+          if (verbose) 
+               printk("%s: frpw: Xilinx does not support mode %d\n",
+                       pi->device, pi->mode);
+          return 1;
+       }
+
+       if ((pi->private == 3) && (pi->mode == 2)) {
+          if (verbose)
+               printk("%s: frpw: ASIC does not support mode 2\n",
+                       pi->device);
+          return 1;
+       }
+
+       frpw_connect(pi);
+        frpw_read_block_int(pi,scratch,512,0x10);
+        r = 0;
+        for (k=0;k<128;k++) if (scratch[k] != k) r++;
+       frpw_disconnect(pi);
+
+        if (verbose)  {
+            printk("%s: frpw: port 0x%x, mode %d, test=%d\n",
+                   pi->device,pi->port,pi->mode,r);
+        }
+
+        return r;
+}
+
+
+static void frpw_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[4] = {"4-bit","8-bit","EPP-X","EPP-A"};
+
+        printk("%s: frpw %s, Freecom (%s) adapter at 0x%x, ", pi->device,
+               FRPW_VERSION,(pi->private == 2)?"Xilinx":"ASIC",pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void frpw_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void frpw_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol frpw = {"frpw",0,4,2,2,1,
+                           frpw_write_regr,
+                           frpw_read_regr,
+                           frpw_write_block,
+                           frpw_read_block,
+                           frpw_connect,
+                           frpw_disconnect,
+                           0,
+                           0,
+                           frpw_test_proto,
+                           frpw_log_adapter,
+                           frpw_inc_use, 
+                           frpw_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &frpw ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &frpw );
+}
+
+#endif
+
+/* end of frpw.c */
diff --git a/drivers/block/paride/kbic.c b/drivers/block/paride/kbic.c
new file mode 100644 (file)
index 0000000..47f5cd2
--- /dev/null
@@ -0,0 +1,305 @@
+/*
+        kbic.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
+
+        This is a low-level driver for the KBIC-951A and KBIC-971A
+        parallel to IDE adapter chips from KingByte Information Systems.
+
+       The chips are almost identical, however, the wakeup code 
+       required for the 971A interferes with the correct operation of
+        the 951A, so this driver registers itself twice, once for
+       each chip.
+
+*/
+
+#define KBIC_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define r12w()                 (delay_p,inw(pi->port+1)&0xffff) 
+
+#define j44(a,b)                ((((a>>4)&0x0f)|(b&0xf0))^0x88)
+#define j53(w)                  (((w>>3)&0x1f)|((w>>4)&0xe0))
+
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int  cont_map[2] = { 0x80, 0x40 };
+
+static int kbic_read_regr( PIA *pi, int cont, int regr )
+
+{       int     a, b, s;
+
+        s = cont_map[cont];
+
+       switch (pi->mode) {
+
+       case 0: w0(regr|0x18|s); w2(4); w2(6); w2(4); w2(1); w0(8);
+               a = r1(); w0(0x28); b = r1(); w2(4);
+               return j44(a,b);
+
+       case 1: w0(regr|0x38|s); w2(4); w2(6); w2(4); w2(5); w0(8);
+               a = r12w(); w2(4);
+               return j53(a);
+
+       case 2: w0(regr|0x08|s); w2(4); w2(6); w2(4); w2(0xa5); w2(0xa1);
+               a = r0(); w2(4);
+                       return a;
+
+       case 3:
+       case 4:
+       case 5: w0(0x20|s); w2(4); w2(6); w2(4); w3(regr);
+               a = r4(); b = r4(); w2(4); w2(0); w2(4);
+               return a;
+
+       }
+       return -1;
+}       
+
+static void  kbic_write_regr( PIA *pi, int cont, int regr, int val)
+
+{       int  s;
+
+        s = cont_map[cont];
+
+        switch (pi->mode) {
+
+       case 0: 
+        case 1:
+       case 2: w0(regr|0x10|s); w2(4); w2(6); w2(4); 
+               w0(val); w2(5); w2(4);
+               break;
+
+       case 3:
+       case 4:
+       case 5: w0(0x20|s); w2(4); w2(6); w2(4); w3(regr);
+               w4(val); w4(val);
+               w2(4); w2(0); w2(4);
+                break;
+
+       }
+}
+
+static void k951_connect ( PIA *pi  )
+
+{      pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+        w2(4); 
+}
+
+static void k951_disconnect ( PIA *pi )
+
+{              w0(pi->saved_r0);
+        w2(pi->saved_r2);
+}
+
+#define        CCP(x)  w2(0xc4);w0(0xaa);w0(0x55);w0(0);w0(0xff);w0(0x87);\
+               w0(0x78);w0(x);w2(0xc5);w2(0xc4);w0(0xff);
+
+static void k971_connect ( PIA *pi  )
+
+{      pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+       CCP(0x20);
+        w2(4); 
+}
+
+static void k971_disconnect ( PIA *pi )
+
+{       CCP(0x30);
+       w0(pi->saved_r0);
+        w2(pi->saved_r2);
+}
+
+/* counts must be congruent to 0 MOD 4, but all known applications
+   have this property.
+*/
+
+static void kbic_read_block( PIA *pi, char * buf, int count )
+
+{       int     k, a, b;
+
+        switch (pi->mode) {
+
+        case 0: w0(0x98); w2(4); w2(6); w2(4);
+                for (k=0;k<count/2;k++) {
+                       w2(1); w0(8);    a = r1();
+                              w0(0x28); b = r1();
+                       buf[2*k]   = j44(a,b);
+                       w2(5);           b = r1();
+                              w0(8);    a = r1();
+                       buf[2*k+1] = j44(a,b);
+                       w2(4);
+                } 
+                break;
+
+        case 1: w0(0xb8); w2(4); w2(6); w2(4); 
+                for (k=0;k<count/4;k++) {
+                        w0(0xb8); 
+                       w2(4); w2(5); 
+                        w0(8);    buf[4*k]   = j53(r12w());
+                       w0(0xb8); buf[4*k+1] = j53(r12w());
+                       w2(4); w2(5);
+                                 buf[4*k+3] = j53(r12w());
+                       w0(8);    buf[4*k+2] = j53(r12w());
+                }
+                w2(4);
+                break;
+
+        case 2: w0(0x88); w2(4); w2(6); w2(4);
+                for (k=0;k<count/2;k++) {
+                        w2(0xa0); w2(0xa1); buf[2*k] = r0();
+                        w2(0xa5); buf[2*k+1] = r0();
+                }
+                w2(4);
+                break;
+
+        case 3: w0(0xa0); w2(4); w2(6); w2(4); w3(0);
+                for (k=0;k<count;k++) buf[k] = r4();
+                w2(4); w2(0); w2(4);
+                break;
+
+       case 4: w0(0xa0); w2(4); w2(6); w2(4); w3(0);
+                for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w();
+                w2(4); w2(0); w2(4);
+                break;
+
+        case 5: w0(0xa0); w2(4); w2(6); w2(4); w3(0);
+                for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l();
+                w2(4); w2(0); w2(4);
+                break;
+
+
+        }
+}
+
+static void kbic_write_block( PIA *pi, char * buf, int count )
+
+{       int     k;
+
+        switch (pi->mode) {
+
+        case 0:
+        case 1:
+        case 2: w0(0x90); w2(4); w2(6); w2(4); 
+               for(k=0;k<count/2;k++) {
+                       w0(buf[2*k+1]); w2(0); w2(4); 
+                       w0(buf[2*k]);   w2(5); w2(4); 
+               }
+               break;
+
+        case 3: w0(0xa0); w2(4); w2(6); w2(4); w3(0);
+               for(k=0;k<count/2;k++) {
+                       w4(buf[2*k+1]); 
+                        w4(buf[2*k]);
+                }
+               w2(4); w2(0); w2(4);
+               break;
+
+       case 4: w0(0xa0); w2(4); w2(6); w2(4); w3(0);
+                for(k=0;k<count/2;k++) w4w(pi_swab16(buf,k));
+                w2(4); w2(0); w2(4);
+                break;
+
+        case 5: w0(0xa0); w2(4); w2(6); w2(4); w3(0);
+                for(k=0;k<count/4;k++) w4l(pi_swab32(buf,k));
+                w2(4); w2(0); w2(4);
+                break;
+
+        }
+
+}
+
+static void kbic_log_adapter( PIA *pi, char * scratch, 
+                             int verbose, char * chip )
+
+{       char    *mode_string[6] = {"4-bit","5/3","8-bit",
+                                  "EPP-8","EPP_16","EPP-32"};
+
+        printk("%s: kbic %s, KingByte %s at 0x%x, ",
+                pi->device,KBIC_VERSION,chip,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void k951_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{      kbic_log_adapter(pi,scratch,verbose,"KBIC-951A");
+}
+
+static void k971_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       kbic_log_adapter(pi,scratch,verbose,"KBIC-971A");
+}
+
+static void kbic_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void kbic_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol k951 = {"k951",0,6,3,1,1,
+                           kbic_write_regr,
+                           kbic_read_regr,
+                           kbic_write_block,
+                           kbic_read_block,
+                           k951_connect,
+                           k951_disconnect,
+                           0,
+                           0,
+                           0,
+                           k951_log_adapter,
+                           kbic_inc_use, 
+                           kbic_dec_use 
+                         };
+
+
+struct pi_protocol k971 = {"k971",0,6,3,1,1,
+                           kbic_write_regr,
+                           kbic_read_regr,
+                           kbic_write_block,
+                           kbic_read_block,
+                           k971_connect,
+                           k971_disconnect,
+                           0,
+                           0,
+                           0,
+                           k971_log_adapter,
+                           kbic_inc_use, 
+                           kbic_dec_use 
+                          };
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       int s5,s7;
+
+       s5 = pi_register(&k951);
+       s7 = pi_register(&k971);
+
+       return (s5 || s7) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &k951 );
+       pi_unregister( &k971 );
+}
+
+#endif
+
+/* end of kbic.c */
diff --git a/drivers/block/paride/on20.c b/drivers/block/paride/on20.c
new file mode 100644 (file)
index 0000000..c9b3fa3
--- /dev/null
@@ -0,0 +1,157 @@
+/* 
+       on20.c  (c) 1996  Grant R. Guenther <grant@torque.net>
+                         Under the terms of the GNU public license.
+
+        on20.c is a low-level protocol driver for the
+        Onspec 90c20 parallel to IDE adapter. 
+*/
+
+#define        ON20_VERSION    "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+#define op(f)  w2(4);w0(f);w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4);
+#define vl(v)  w2(4);w0(v);w2(5);w2(7);w2(5);w2(4);
+
+#define j44(a,b)  (((a>>4)&0x0f)|(b&0xf0))
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int on20_read_regr( PIA *pi, int cont, int regr )
+
+{      int h,l, r ;
+
+        r = (regr<<2) + 1 + cont;
+
+        op(1); vl(r); op(0);
+
+       switch (pi->mode)  {
+
+        case 0:  w2(4); w2(6); l = r1();
+                 w2(4); w2(6); h = r1();
+                 w2(4); w2(6); w2(4); w2(6); w2(4);
+                return j44(l,h);
+
+       case 1:  w2(4); w2(0x26); r = r0(); 
+                 w2(4); w2(0x26); w2(4);
+                return r;
+
+       }
+       return -1;
+}      
+
+static void on20_write_regr( PIA *pi, int cont, int regr, int val )
+
+{      int r;
+
+       r = (regr<<2) + 1 + cont;
+
+       op(1); vl(r); 
+       op(0); vl(val); 
+       op(0); vl(val);
+}
+
+static void on20_connect ( PIA *pi)
+
+{      pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+
+       w2(4);w0(0);w2(0xc);w2(4);w2(6);w2(4);w2(6);w2(4); 
+       if (pi->mode) { op(2); vl(8); op(2); vl(9); }
+              else   { op(2); vl(0); op(2); vl(8); }
+}
+
+static void on20_disconnect ( PIA *pi )
+
+{      w2(4);w0(7);w2(4);w2(0xc);w2(4);
+        w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void on20_read_block( PIA *pi, char * buf, int count )
+
+{      int     k, l, h; 
+
+       op(1); vl(1); op(0);
+
+       for (k=0;k<count;k++) 
+           if (pi->mode) {
+               w2(4); w2(0x26); buf[k] = r0();
+           } else {
+               w2(6); l = r1(); w2(4);
+               w2(6); h = r1(); w2(4);
+               buf[k] = j44(l,h);
+           }
+       w2(4);
+}
+
+static void on20_write_block(  PIA *pi, char * buf, int count )
+
+{      int     k;
+
+       op(1); vl(1); op(0);
+
+       for (k=0;k<count;k++) { w2(5); w0(buf[k]); w2(7); }
+       w2(4);
+}
+
+static void on20_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[2] = {"4-bit","8-bit"};
+
+        printk("%s: on20 %s, OnSpec 90c20 at 0x%x, ",
+                pi->device,ON20_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void on20_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void on20_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol on20 = {"on20",0,2,2,1,1,
+                           on20_write_regr,
+                           on20_read_regr,
+                           on20_write_block,
+                           on20_read_block,
+                           on20_connect,
+                           on20_disconnect,
+                           0,
+                           0,
+                           0,
+                           on20_log_adapter,
+                           on20_inc_use, 
+                           on20_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &on20 ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &on20 );
+}
+
+#endif
+
+/* end of on20.c */
diff --git a/drivers/block/paride/on26.c b/drivers/block/paride/on26.c
new file mode 100644 (file)
index 0000000..21e6e01
--- /dev/null
@@ -0,0 +1,261 @@
+/* 
+        on26.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
+
+        on26.c is a low-level protocol driver for the 
+        OnSpec 90c26 parallel to IDE adapter chip.
+
+*/
+
+#define ON26_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <asm/io.h>
+
+#include "paride.h"
+
+/* mode codes:  0  nybble reads, 8-bit writes
+                1  8-bit reads and writes
+                2  8-bit EPP mode
+               3  EPP-16
+               4  EPP-32
+*/
+
+#define j44(a,b)  (((a>>4)&0x0f)|(b&0xf0))
+
+#define P1     w2(5);w2(0xd);w2(5);w2(0xd);w2(5);w2(4);
+#define P2     w2(5);w2(7);w2(5);w2(4);
+
+/* cont = 0 - access the IDE register file 
+   cont = 1 - access the IDE command set 
+*/
+
+static int on26_read_regr( PIA *pi, int cont, int regr )
+
+{       int     a, b, r;
+
+       r = (regr<<2) + 1 + cont;
+
+        switch (pi->mode)  {
+
+        case 0: w0(1); P1; w0(r); P2; w0(0); P1; 
+               w2(6); a = r1(); w2(4);
+               w2(6); b = r1(); w2(4);
+               w2(6); w2(4); w2(6); w2(4);
+                return j44(a,b);
+
+        case 1: w0(1); P1; w0(r); P2; w0(0); P1;
+               w2(0x26); a = r0(); w2(4); w2(0x26); w2(4);
+                return a;
+
+       case 2:
+       case 3:
+        case 4: w3(1); w3(1); w2(5); w4(r); w2(4);
+               w3(0); w3(0); w2(0x24); a = r4(); w2(4);
+               w2(0x24); r4(); w2(4);
+                return a;
+
+        }
+        return -1;
+}       
+
+static void on26_write_regr( PIA *pi, int cont, int regr, int val )
+
+{       int  r;
+
+        r = (regr<<2) + 1 + cont;
+
+        switch (pi->mode)  {
+
+        case 0:
+        case 1: w0(1); P1; w0(r); P2; w0(0); P1;
+               w0(val); P2; w0(val); P2;
+               break;
+
+       case 2:
+       case 3:
+        case 4: w3(1); w3(1); w2(5); w4(r); w2(4);
+               w3(0); w3(0); 
+               w2(5); w4(val); w2(4);
+               w2(5); w4(val); w2(4);
+                break;
+        }
+}
+
+#define  CCP(x)  w0(0xff);w0(0xaa);w0(0x55);w0(0);w0(0xff);\
+                w0(0x87);w0(0x78);w0(x);w2(4);
+
+static void on26_connect ( PIA *pi )
+
+{       int    x;
+
+       pi->saved_r0 = r0();
+        pi->saved_r2 = r2();
+
+        CCP(0x20);
+       w2(0xcd); w2(0xcc); w0(0xff);
+       x = 8; if (pi->mode) x = 9;
+
+       w0(2); P1; w0(8); P2;
+       w0(2); P1; w0(x); P2;
+}
+
+static void on26_disconnect ( PIA *pi )
+
+{       if (pi->mode >= 2) { w3(4); w3(4); w3(4); w3(4); }
+                     else { w0(4); P1; w0(4); P1; }
+       CCP(0x30);
+        w2(0xcd); w2(0xcc); w0(0xff);
+        w0(pi->saved_r0);
+        w2(pi->saved_r2);
+} 
+
+static void on26_read_block( PIA *pi, char * buf, int count )
+
+{       int     k, a, b;
+
+        switch (pi->mode) {
+
+        case 0: w0(1); P1; w0(1); P2; w0(2); P1; w0(0x18); P2; w0(0); P1;
+               udelay(10);
+               for (k=0;k<count;k++) {
+                        w2(6); a = r1();
+                        w2(4); b = r1();
+                        buf[k] = j44(a,b);
+                }
+               w0(2); P1; w0(8); P2; 
+                break;
+
+        case 1: w0(1); P1; w0(1); P2; w0(2); P1; w0(0x19); P2; w0(0); P1;
+               udelay(10);
+                for (k=0;k<count/2;k++) {
+                        w2(0x26); buf[2*k] = r0(); 
+                       w2(0x24); buf[2*k+1] = r0();
+                }
+                w0(2); P1; w0(9); P2;
+                break;
+
+        case 2: w3(1); w3(1); w2(5); w4(1); w2(4);
+               w3(0); w3(0); w2(0x24);
+               udelay(10);
+                for (k=0;k<count;k++) buf[k] = r4();
+                w2(4);
+                break;
+
+        case 3: w3(1); w3(1); w2(5); w4(1); w2(4);
+                w3(0); w3(0); w2(0x24);
+                udelay(10);
+                for (k=0;k<count/2;k++) ((u16 *)buf)[k] = r4w();
+                w2(4);
+                break;
+
+        case 4: w3(1); w3(1); w2(5); w4(1); w2(4);
+                w3(0); w3(0); w2(0x24);
+                udelay(10);
+                for (k=0;k<count/4;k++) ((u32 *)buf)[k] = r4l();
+                w2(4);
+                break;
+
+        }
+}
+
+static void on26_write_block( PIA *pi, char * buf, int count )
+
+{       int    k;
+
+        switch (pi->mode) {
+
+        case 0: 
+        case 1: w0(1); P1; w0(1); P2; 
+               w0(2); P1; w0(0x18+pi->mode); P2; w0(0); P1;
+               udelay(10);
+               for (k=0;k<count/2;k++) {
+                        w2(5); w0(buf[2*k]); 
+                       w2(7); w0(buf[2*k+1]);
+                }
+                w2(5); w2(4);
+               w0(2); P1; w0(8+pi->mode); P2;
+                break;
+
+        case 2: w3(1); w3(1); w2(5); w4(1); w2(4);
+               w3(0); w3(0); w2(0xc5);
+               udelay(10);
+                for (k=0;k<count;k++) w4(buf[k]);
+               w2(0xc4);
+                break;
+
+        case 3: w3(1); w3(1); w2(5); w4(1); w2(4);
+                w3(0); w3(0); w2(0xc5);
+                udelay(10);
+                for (k=0;k<count/2;k++) w4w(((u16 *)buf)[k]);
+                w2(0xc4);
+                break;
+
+        case 4: w3(1); w3(1); w2(5); w4(1); w2(4);
+                w3(0); w3(0); w2(0xc5);
+                udelay(10);
+                for (k=0;k<count/4;k++) w4l(((u32 *)buf)[k]);
+                w2(0xc4);
+                break;
+
+        }
+
+}
+
+static void on26_log_adapter( PIA *pi, char * scratch, int verbose )
+
+{       char    *mode_string[5] = {"4-bit","8-bit","EPP-8",
+                                  "EPP-16","EPP-32"};
+
+        printk("%s: on26 %s, OnSpec 90c26 at 0x%x, ",
+                pi->device,ON26_VERSION,pi->port);
+        printk("mode %d (%s), delay %d\n",pi->mode,
+               mode_string[pi->mode],pi->delay);
+
+}
+
+static void on26_inc_use ( void )
+
+{       MOD_INC_USE_COUNT;
+}
+
+static void on26_dec_use ( void )
+
+{       MOD_DEC_USE_COUNT;
+}
+
+struct pi_protocol on26 = {"on26",0,5,2,1,1,
+                           on26_write_regr,
+                           on26_read_regr,
+                           on26_write_block,
+                           on26_read_block,
+                           on26_connect,
+                           on26_disconnect,
+                           0,
+                           0,
+                           0,
+                           on26_log_adapter,
+                           on26_inc_use, 
+                           on26_dec_use 
+                          };
+
+
+#ifdef MODULE
+
+int     init_module(void)
+
+{       return pi_register( &on26 ) - 1;
+}
+
+void    cleanup_module(void)
+
+{       pi_unregister( &on26 );
+}
+
+#endif
+
+/* end of on26.c */
+
diff --git a/drivers/block/paride/paride.c b/drivers/block/paride/paride.c
new file mode 100644 (file)
index 0000000..1d5530c
--- /dev/null
@@ -0,0 +1,480 @@
+/* 
+        paride.c  (c) 1997  Grant R. Guenther <grant@torque.net>
+                            Under the terms of the GNU public license.
+
+       This is the base module for the family of device drivers
+        that support parallel port IDE devices.  
+
+*/
+
+#define PI_VERSION      "1.0"
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/types.h>
+#include <linux/kernel.h>
+#include <linux/ioport.h>
+#include <linux/string.h>
+
+#ifdef CONFIG_PARPORT_MODULE
+#define CONFIG_PARPORT
+#endif
+
+#ifdef CONFIG_PARPORT
+#include <linux/parport.h>
+#endif
+
+#include "paride.h"
+
+#define MAX_PROTOS     32
+
+static struct pi_protocol      *protocols[MAX_PROTOS];
+
+
+void pi_write_regr( PIA *pi, int cont, int regr, int val)
+
+{      pi->proto->write_regr(pi,cont,regr,val);
+}
+
+int pi_read_regr( PIA *pi, int cont, int regr)
+
+{      return pi->proto->read_regr(pi,cont,regr);
+}
+
+void pi_write_block( PIA *pi, char * buf, int count)
+
+{      pi->proto->write_block(pi,buf,count);
+}
+
+void pi_read_block( PIA *pi, char * buf, int count)
+
+{       pi->proto->read_block(pi,buf,count);
+}
+
+#ifdef CONFIG_PARPORT
+
+static void pi_wake_up( void *p)
+
+{       PIA  *pi = (PIA *) p;
+       long flags;
+       void (*cont)(void) = NULL;
+
+       save_flags(flags);
+       cli();
+
+       if (pi->claim_cont && !parport_claim(pi->pardev)) {
+               cont = pi->claim_cont;
+               pi->claim_cont = NULL;
+               pi->claimed = 1;
+       }
+
+       restore_flags(flags);   
+       wake_up(&(pi->parq));
+       if (cont) cont();
+}
+
+#endif
+
+void pi_do_claimed( PIA *pi, void(*cont)(void))
+
+#ifdef CONFIG_PARPORT
+
+{      long flags;
+
+       save_flags(flags);
+       cli();
+
+       if (!pi->pardev || !parport_claim(pi->pardev)) {
+               pi->claimed = 1;
+               restore_flags(flags);
+               cont();
+       } else {
+               pi->claim_cont = cont;
+               restore_flags(flags);
+       }
+}
+
+#else
+
+{      cont();
+}
+
+#endif
+
+static void pi_claim( PIA *pi)
+
+{      if (pi->claimed) return;
+       pi->claimed = 1;
+#ifdef CONFIG_PARPORT
+        if (pi->pardev)
+          while (parport_claim((struct pardevice *)(pi->pardev)))
+            sleep_on(&(pi->parq));
+#endif
+}
+
+static void pi_unclaim( PIA *pi)
+
+{      pi->claimed = 0;
+#ifdef CONFIG_PARPORT
+        if (pi->pardev) parport_release((struct pardevice *)(pi->pardev));
+#endif 
+}
+
+void pi_connect( PIA *pi)
+
+{      pi_claim(pi);
+       pi->proto->connect(pi);
+}
+
+void pi_disconnect( PIA *pi)
+
+{      pi->proto->disconnect(pi);
+       pi_unclaim(pi);
+}
+
+static void pi_unregister_parport( PIA *pi)
+
+{
+#ifdef CONFIG_PARPORT
+        if (pi->pardev) {
+           parport_unregister_device((struct pardevice *)(pi->pardev));
+          pi->pardev = NULL;
+       }
+#endif
+}
+
+void pi_release( PIA *pi)
+
+{      pi_unregister_parport(pi);
+       if ((!pi->pardev)&&(pi->reserved)) 
+               release_region(pi->port,pi->reserved);
+       pi->proto->dec_use();
+}
+
+#define WR(r,v)         pi_write_regr(pi,0,r,v)
+#define RR(r)           (pi_read_regr(pi,0,r))
+
+static int pi_test_proto( PIA *pi, char * scratch, int verbose )
+
+{       int     j, k;
+        int     e[2] = {0,0};
+
+       if (pi->proto->test_proto) {
+               pi_claim(pi);
+               j = pi->proto->test_proto(pi,scratch,verbose);
+               pi_unclaim(pi);
+               return j;
+       }
+
+        pi_connect(pi);
+
+        for (j=0;j<2;j++) {
+                WR(6,0xa0+j*0x10);
+                for (k=0;k<256;k++) {
+                        WR(2,k^0xaa);
+                        WR(3,k^0x55);
+                        if (RR(2) != (k^0xaa)) e[j]++;
+                        }
+                }
+
+        pi_disconnect(pi);
+
+        if (verbose)
+                printk("%s: %s: port 0x%x, mode  %d, test=(%d,%d)\n",
+                        pi->device,pi->proto->name,pi->port,
+                       pi->mode,e[0],e[1]);
+
+        return (e[0] && e[1]);  /* not here if both > 0 */
+}
+
+int  pi_register( PIP *pr)
+
+{      int k;
+
+       for (k=0;k<MAX_PROTOS;k++) 
+          if (protocols[k] && !strcmp(pr->name,protocols[k]->name)) {
+               printk("paride: %s protocol already registered\n",pr->name);
+               return 0;
+          }
+       k = 0;
+       while((k<MAX_PROTOS) && (protocols[k])) k++;
+       if (k == MAX_PROTOS) {
+               printk("paride: protocol table full\n");
+               return 0;
+       }
+       MOD_INC_USE_COUNT;
+       protocols[k] = pr;
+       pr->index = k;
+       printk("paride: %s registered as protocol %d\n",pr->name,k);
+       return 1;
+}      
+
+void pi_unregister( PIP *pr)
+
+{      if (!pr) return;
+       if (protocols[pr->index] != pr) {
+               printk("paride: %s not registered\n",pr->name);
+               return;
+       } 
+       protocols[pr->index] = 0;
+       MOD_DEC_USE_COUNT;
+}
+
+static void pi_register_parport( PIA *pi, int verbose)
+
+{
+#ifdef CONFIG_PARPORT
+
+       struct parport  *pp;
+
+       pp = parport_enumerate();
+
+       while((pp)&&(pp->base != pi->port)) pp = pp->next;
+
+       if (!pp) return;
+
+       pi->pardev = (void *) parport_register_device(
+             pp,pi->device,NULL,pi_wake_up,NULL,0,(void *)pi);
+
+       pi->parq = NULL;
+
+       if (verbose) printk("%s: 0x%x is %s\n",pi->device,pi->port,pp->name);
+       
+       pi->parname = pp->name;
+
+#endif
+}
+
+static int pi_probe_mode( PIA *pi, int max, char * scratch, int verbose)
+
+{      int     best, range;
+
+       if (pi->mode != -1) {
+               if (pi->mode >= max) return 0;
+               range = 3;
+               if (pi->mode >= pi->proto->epp_first) range = 8;
+               if ((range == 8) && (pi->port % 8)) return 0;
+               if ((!pi->pardev) && check_region(pi->port,range)) return 0;
+               pi->reserved = range;
+               return (!pi_test_proto(pi,scratch,verbose));
+       }
+       best = -1;
+       for(pi->mode=0;pi->mode<max;pi->mode++) {
+               range = 3;
+               if (pi->mode >= pi->proto->epp_first) range = 8;
+               if ((range == 8) && (pi->port % 8)) break;
+               if ((!pi->pardev) && check_region(pi->port,range)) break;
+               pi->reserved = range;
+               if (!pi_test_proto(pi,scratch,verbose)) best = pi->mode;
+       }
+       pi->mode = best;
+       return (best > -1);
+}
+
+static int pi_probe_unit( PIA *pi, int unit, char * scratch, int verbose)
+
+{      int max,s,e;
+
+       s = unit; e = s+1;
+
+       if (s == -1) { 
+               s = 0; 
+               e = pi->proto->max_units; 
+       }
+
+       pi_register_parport(pi,verbose);
+
+       if ((!pi->pardev) && check_region(pi->port,3)) return 0;
+
+       if (pi->proto->test_port) {
+               pi_claim(pi);
+               max = pi->proto->test_port(pi);
+               pi_unclaim(pi);
+       }
+       else max = pi->proto->max_mode;
+
+       if (pi->proto->probe_unit) {
+          pi_claim(pi);
+          for (pi->unit=s;pi->unit<e;pi->unit++)
+             if (pi->proto->probe_unit(pi)) {
+                pi_unclaim(pi);
+                if (pi_probe_mode(pi,max,scratch,verbose)) return 1;
+                pi_unregister_parport(pi); 
+                return 0;
+                }
+          pi_unclaim(pi);
+          pi_unregister_parport(pi); 
+          return 0;
+          }
+
+       if (!pi_probe_mode(pi,max,scratch,verbose)) {
+          pi_unregister_parport(pi); 
+          return 0;
+       }
+       return 1;
+               
+}
+
+int pi_init(PIA *pi, int autoprobe, int port, int mode, 
+           int unit, int protocol, int delay, char * scratch, 
+           int devtype, int verbose, char *device )
+
+{      int p,k,s,e;
+       int lpts[7] = {0x3bc,0x378,0x278,0x268,0x27c,0x26c,0};
+
+       s = protocol; e = s+1;
+
+       if (autoprobe) {
+               s = 0; 
+               e = MAX_PROTOS;
+       } else if ((s < 0) || (s >= MAX_PROTOS) || (port <= 0) ||
+                   (!protocols[s]) || (unit < 0) || 
+                   (unit >= protocols[s]->max_units)) {
+                       printk("%s: Invalid parameters\n",device);
+                       return 0;
+                       }
+
+       for (p=s;p<e;p++) {
+         if (protocols[p]) {
+               pi->proto = protocols[p];
+               pi->proto->inc_use();
+               if (delay == -1) pi->delay = pi->proto->default_delay;
+                 else pi->delay = delay;
+               pi->devtype = devtype;
+               pi->device = device;
+               pi->private = 0;
+
+               pi->parname = NULL;
+               pi->pardev = NULL;
+               pi->parq = NULL;
+               pi->claimed = 0;
+               pi->claim_cont = NULL;
+               
+               pi->mode = mode;
+               if (port != -1) {
+                       pi->port = port;
+                       if (pi_probe_unit(pi,unit,scratch,verbose)) break;
+                       pi->port = 0;
+               } else { 
+                       k = 0;
+                       while ((pi->port = lpts[k++]))
+                          if (pi_probe_unit(pi,unit,scratch,verbose)) break;
+                       if (pi->port) break;
+               }
+               pi->proto->dec_use();
+         }
+       }
+
+       if (!pi->port) {
+               if (autoprobe) printk("%s: Autoprobe failed\n",device);
+               else printk("%s: Adapter not found\n",device);
+               return 0;
+       }
+
+       if (!pi->pardev)
+          request_region(pi->port,pi->reserved,pi->device);
+
+       if (pi->parname)
+          printk("%s: Sharing %s at 0x%x\n",pi->device,
+                       pi->parname,pi->port);
+
+       pi->proto->log_adapter(pi,scratch,verbose);
+
+       return 1;
+}
+
+#ifdef MODULE
+
+int    init_module(void)
+
+{      int k;
+
+       for (k=0;k<MAX_PROTOS;k++) protocols[k] = 0;
+       printk("paride: version %s installed\n",PI_VERSION);
+       return 0;
+}
+
+void   cleanup_module(void)
+
+{
+}
+
+#else
+
+void   paride_init( void )
+
+{
+
+#ifdef CONFIG_PARIDE_ATEN
+       { extern struct pi_protocol aten;
+         pi_register(&aten);
+       };
+#endif
+#ifdef CONFIG_PARIDE_BPCK
+        { extern struct pi_protocol bpck;
+          pi_register(&bpck);
+        };
+#endif
+#ifdef CONFIG_PARIDE_COMM
+        { extern struct pi_protocol comm;
+          pi_register(&comm);
+        };
+#endif
+#ifdef CONFIG_PARIDE_DSTR
+        { extern struct pi_protocol dstr;
+          pi_register(&dstr);
+        };
+#endif
+#ifdef CONFIG_PARIDE_EPAT
+        { extern struct pi_protocol epat;
+          pi_register(&epat);
+        };
+#endif
+#ifdef CONFIG_PARIDE_EPIA
+        { extern struct pi_protocol epia;
+          pi_register(&epia);
+        };
+#endif
+#ifdef CONFIG_PARIDE_FRPW
+        { extern struct pi_protocol frpw;
+          pi_register(&frpw);
+        };
+#endif
+#ifdef CONFIG_PARIDE_KBIC
+        { extern struct pi_protocol k951;
+          extern struct pi_protocol k971;
+          pi_register(&k951);
+          pi_register(&k971);
+        };
+#endif
+#ifdef CONFIG_PARIDE_ON20
+        { extern struct pi_protocol on20;
+          pi_register(&on20);
+        };
+#endif
+#ifdef CONFIG_PARIDE_ON26
+        { extern struct pi_protocol on26;
+          pi_register(&on26);
+        };
+#endif
+
+#ifdef CONFIG_PARIDE_PD
+       { extern int pd_init(void);
+         pd_init();
+       };
+#endif
+#ifdef CONFIG_PARIDE_PCD
+        { extern int pcd_init(void);
+          pcd_init();
+        };
+#endif
+#ifdef CONFIG_PARIDE_PF
+        { extern int pf_init(void);
+          pf_init();
+        };
+#endif
+}
+
+#endif
+
+/* end of paride.c */
diff --git a/drivers/block/paride/paride.h b/drivers/block/paride/paride.h
new file mode 100644 (file)
index 0000000..04de514
--- /dev/null
@@ -0,0 +1,157 @@
+/* paride.h    (c) 1997  Grant R. Guenther <grant@torque.net>
+                         Under the terms of the GPL.
+
+   This file defines the interface between the high-level parallel
+   IDE device drivers (pd, pf, pcd, pt) and the adapter chips.
+
+*/
+
+#define PARIDE_H_VERSION       "1.0"
+
+/* Some adapters need to know what kind of device they are in
+
+   Values for devtype:
+*/
+
+#define        PI_PD   0       /* IDE disk */
+#define PI_PCD 1       /* ATAPI CDrom */
+#define PI_PF   2      /* ATAPI disk */
+#define PI_PT  3       /* ATAPI tape */
+
+/* The paride module contains no state, instead the drivers allocate
+   a pi_adapter data structure and pass it to paride in every operation.
+
+*/
+
+struct pi_adapter  {
+
+       struct pi_protocol *proto;   /* adapter protocol */
+       int     port;                /* base address of parallel port */
+       int     mode;                /* transfer mode in use */
+       int     delay;               /* adapter delay setting */
+       int     devtype;             /* device type: PI_PD etc. */
+       char    *device;             /* name of driver */
+       int     unit;                /* unit number for chained adapters */
+       int     saved_r0;            /* saved port state */
+       int     saved_r2;            /* saved port state */
+       int     reserved;            /* number of ports reserved */
+       int     private;             /* for protocol module */
+
+       struct wait_queue *parq;     /* semaphore for parport sharing */
+       void    *pardev;             /* pointer to pardevice */
+       char    *parname;            /* parport name */
+       int     claimed;             /* parport has already been claimed */
+       void (*claim_cont)(void);    /* continuation for parport wait */
+};
+
+typedef struct pi_adapter PIA;
+
+/* functions exported by paride to the high level drivers */
+
+extern int pi_init(PIA *pi, 
+       int autoprobe,          /* 1 to autoprobe */
+       int port,               /* base port address */
+       int mode,               /* -1 for autoprobe */
+       int unit,               /* unit number, if supported */
+       int protocol,           /* protocol to use */
+       int delay,              /* -1 to use adapter specific default */
+       char * scratch,         /* address of 512 byte buffer */
+       int devtype,            /* device type: PI_PD, PI_PCD, etc ... */
+       int verbose,            /* log verbose data while probing */
+       char *device            /* name of the driver */
+       );                      /* returns 0 on failure, 1 on success */
+
+extern void pi_release(PIA *pi);
+
+/* registers are addressed as (cont,regr)
+
+               cont: 0 for command register file, 1 for control register(s)
+       regr: 0-7 for register number.
+
+*/
+
+extern void pi_write_regr(PIA *pi, int cont, int regr, int val);
+
+extern int pi_read_regr(PIA *pi, int cont, int regr);
+
+extern void pi_write_block(PIA *pi, char * buf, int count);
+
+extern void pi_read_block(PIA *pi, char * buf, int count);
+
+extern void pi_connect(PIA *pi);
+
+extern void pi_disconnect(PIA *pi);
+
+extern void pi_do_claimed(PIA *pi, void (*cont)(void));
+
+/* macros and functions exported to the protocol modules */
+
+#define delay_p                        (pi->delay?udelay(pi->delay):0)
+#define out_p(offs,byte)       outb(byte,pi->port+offs); delay_p;
+#define in_p(offs)             (delay_p,inb(pi->port+offs))
+
+#define w0(byte)                {out_p(0,byte);}
+#define r0()                    (in_p(0) & 0xff)
+#define w1(byte)                {out_p(1,byte);}
+#define r1()                    (in_p(1) & 0xff)
+#define w2(byte)                {out_p(2,byte);}
+#define r2()                    (in_p(2) & 0xff)
+#define w3(byte)                {out_p(3,byte);}
+#define w4(byte)                {out_p(4,byte);}
+#define r4()                    (in_p(4) & 0xff)
+#define w4w(data)              {outw(data,pi->port+4); delay_p;}
+#define w4l(data)              {outl(data,pi->port+4); delay_p;}
+#define r4w()                  (delay_p,inw(pi->port+4)&0xffff)
+#define r4l()                  (delay_p,inl(pi->port+4)&0xffffffff)
+
+static inline u16 pi_swab16( char *b, int k)
+
+{      union { u16 u; char t[2]; } r;
+
+       r.t[0]=b[2*k+1]; r.t[1]=b[2*k];
+        return r.u;
+}
+
+static inline u32 pi_swab32( char *b, int k)
+
+{      union { u32 u; char f[4]; } r;
+
+       r.f[0]=b[4*k+1]; r.f[1]=b[4*k];
+       r.f[2]=b[4*k+3]; r.f[3]=b[4*k+2];
+        return r.u;
+}
+
+struct pi_protocol {
+
+       char    name[8];        /* name for this protocol */
+       int     index;          /* index into protocol table */
+
+       int     max_mode;       /* max mode number */
+       int     epp_first;      /* modes >= this use 8 ports */
+       
+       int     default_delay;  /* delay parameter if not specified */
+       int     max_units;      /* max chained units probed for */
+
+       void (*write_regr)(PIA *,int,int,int);
+       int  (*read_regr)(PIA *,int,int);
+       void (*write_block)(PIA *,char *,int);
+       void (*read_block)(PIA *,char *,int);
+
+       void (*connect)(PIA *);
+       void (*disconnect)(PIA *);
+       
+       int  (*test_port)(PIA *);
+       int  (*probe_unit)(PIA *);
+       int  (*test_proto)(PIA *,char *,int);
+       void (*log_adapter)(PIA *,char *,int);
+       
+       void (*inc_use)(void);
+       void (*dec_use)(void);
+};
+
+typedef struct pi_protocol PIP;
+
+extern int pi_register( PIP * );
+extern void pi_unregister ( PIP * );
+
+/* end of paride.h */
diff --git a/drivers/block/paride/pcd.c b/drivers/block/paride/pcd.c
new file mode 100644 (file)
index 0000000..177f898
--- /dev/null
@@ -0,0 +1,786 @@
+/* 
+       pcd.c   (c) 1997  Grant R. Guenther <grant@torque.net>
+                         Under the terms of the GNU public license.
+
+       This is high-level driver for parallel port ATAPI CDrom
+        drives based on chips supported by the paride module.
+
+        By default, the driver will autoprobe for a single parallel
+        port ATAPI CDrom drive, but if their individual parameters are
+        specified, the driver can handle up to 4 drives.
+
+        The behaviour of the pcd driver can be altered by setting
+        some parameters from the insmod command line.  The following
+        parameters are adjustable:
+
+            drive0      These four arguments can be arrays of       
+            drive1      1-6 integers as follows:
+            drive2
+            drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<dly>
+
+                        Where,
+
+                <prt>   is the base of the parallel port address for
+                        the corresponding drive.  (required)
+
+                <pro>   is the protocol number for the adapter that
+                        supports this drive.  These numbers are
+                        logged by 'paride' when the protocol modules
+                        are initialised.  (0 if not given)
+
+                <uni>   for those adapters that support chained
+                        devices, this is the unit selector for the
+                        chain of devices on the given port.  It should
+                        be zero for devices that don't support chaining.
+                        (0 if not given)
+
+                <mod>   this can be -1 to choose the best mode, or one
+                        of the mode numbers supported by the adapter.
+                        (-1 if not given)
+
+               <slv>   ATAPI CDroms can be jumpered to master or slave.
+                       Set this to 0 to choose the master drive, 1 to
+                        choose the slave, -1 (the default) to choose the
+                       first drive found.
+
+                <dly>   some parallel ports require the driver to 
+                        go more slowly.  -1 sets a default value that
+                        should work with the chosen protocol.  Otherwise,
+                        set this to a small integer, the larger it is
+                        the slower the port i/o.  In some cases, setting
+                        this to zero will speed up the device. (default -1)
+                        
+            major       You may use this parameter to overide the
+                        default major number (46) that this driver
+                        will use.  Be sure to change the device
+                        name as well.
+
+            name        This parameter is a character string that
+                        contains the name the kernel will use for this
+                        device (in /proc output, for instance).
+                        (default "pcd")
+
+            verbose     This parameter controls the amount of logging
+                        that is done while the driver probes for
+                        devices.  Set it to 0 for a quiet load, or 1 to
+                        see all the progress messages.  (default 0)
+
+            nice        This parameter controls the driver's use of
+                        idle CPU time, at the expense of some speed.
+       If this driver is built into the kernel, you can use kernel
+        the following command line parameters, with the same values
+        as the corresponding module parameters listed above:
+
+           pcd.drive0
+           pcd.drive1
+           pcd.drive2
+           pcd.drive3
+           pcd.nice
+
+        In addition, you can use the parameter pcd.disable to disable
+        the driver entirely.
+
+*/
+
+#define        PCD_VERSION     "1.0"
+#define PCD_MAJOR      46
+#define PCD_NAME       "pcd"
+#define PCD_UNITS      4
+
+/* Here are things one can override from the insmod command.
+   Most are autoprobed by paride unless set here.  Verbose is on
+   by default.
+
+*/
+
+static int      verbose = 0;
+static int      major = PCD_MAJOR;
+static char     *name = PCD_NAME;
+static int      nice = 0;
+static int      disable = 0;
+
+static int drive0[6] = {0,0,0,-1,-1,-1};
+static int drive1[6] = {0,0,0,-1,-1,-1};
+static int drive2[6] = {0,0,0,-1,-1,-1};
+static int drive3[6] = {0,0,0,-1,-1,-1};
+
+static int (*drives[4])[6] = {&drive0,&drive1,&drive2,&drive3};
+static int pcd_drive_count;
+
+#define D_PRT   0
+#define D_PRO   1
+#define D_UNI   2
+#define D_MOD   3
+#define D_SLV   4
+#define D_DLY   5
+
+#define DU              (*drives[unit])
+
+/* end of parameters */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/cdrom.h>
+
+#include <asm/uaccess.h>
+
+#ifndef MODULE
+
+#include "setup.h"
+
+static STT pcd_stt[6] = {{"drive0",6,drive0},
+                         {"drive1",6,drive1},
+                         {"drive2",6,drive2},
+                         {"drive3",6,drive3},
+                        {"disable",1,&disable},
+                         {"nice",1,&nice}};
+
+void pcd_setup( char *str, int *ints)
+
+{       generic_setup(pcd_stt,6,str);
+}
+
+#endif
+
+MODULE_PARM(verbose,"i");
+MODULE_PARM(major,"i");
+MODULE_PARM(name,"s");
+MODULE_PARM(nice,"i");
+MODULE_PARM(drive0,"1-6i");
+MODULE_PARM(drive1,"1-6i");
+MODULE_PARM(drive2,"1-6i");
+MODULE_PARM(drive3,"1-6i");
+
+#include "paride.h"
+
+/* set up defines for blk.h,  why don't all drivers do it this way ? */
+
+#define MAJOR_NR       major
+#define DEVICE_NAME "PCD"
+#define DEVICE_REQUEST do_pcd_request
+#define DEVICE_NR(device) (MINOR(device))
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#include <linux/blk.h>
+
+#include "pseudo.h"
+
+#define PCD_RETRIES         5
+#define PCD_TMO                   800          /* timeout in jiffies */
+#define PCD_DELAY           50          /* spin delay in uS */
+
+#define PCD_SPIN               (10000/PCD_DELAY)*PCD_TMO
+
+#define IDE_ERR                0x01
+#define IDE_DRQ         0x08
+#define IDE_READY       0x40
+#define IDE_BUSY        0x80
+
+int pcd_init(void);
+void cleanup_module( void );
+
+static int     pcd_open(struct inode *inode, struct file *file);
+static void    do_pcd_request(void);
+static void    do_pcd_read(int unit);
+static int     pcd_ioctl(struct inode *inode,struct file *file,
+                         unsigned int cmd, unsigned long arg);
+
+static int pcd_release (struct inode *inode, struct file *file);
+
+static int     pcd_detect(void);
+static void     pcd_lock(int unit);
+static void     pcd_unlock(int unit);
+static void     pcd_eject(int unit);
+static int      pcd_check_media(int unit);
+static void     do_pcd_read_drq(void);
+
+static int pcd_blocksizes[PCD_UNITS];
+
+#define PCD_NAMELEN    8
+
+struct pcd_unit {
+       struct pi_adapter pia;  /* interface to paride layer */
+       struct pi_adapter *pi;
+       int drive;              /* master/slave */
+       int access;             /* count of active opens */
+       int present;            /* does this unit exist ? */
+       char name[PCD_NAMELEN]; /* pcd0, pcd1, etc */
+       };
+
+struct pcd_unit pcd[PCD_UNITS];
+
+/*  'unit' must be defined in all functions - either as a local or a param */
+
+#define PCD pcd[unit]
+#define PI PCD.pi
+
+static char pcd_scratch[64];
+static char pcd_buffer[2048];           /* raw block buffer */
+static int pcd_bufblk = -1;             /* block in buffer, in CD units,
+                                           -1 for nothing there. See also
+                                          pd_unit.
+                                        */
+
+/* the variables below are used mainly in the I/O request engine, which
+   processes only one request at a time.
+*/
+
+static int pcd_unit = -1;              /* unit of current request & bufblk */
+static int pcd_retries;                        /* retries on current request */
+static int pcd_busy = 0;               /* request being processed ? */
+static int pcd_sector;                 /* address of next requested sector */
+static int pcd_count;                  /* number of blocks still to do */
+static char * pcd_buf;                 /* buffer for request in progress */
+
+/* kernel glue structures */
+
+static struct file_operations pcd_fops = {
+       NULL,                   /* lseek - default */
+       block_read,             /* read - general block-dev read */
+       block_write,            /* write - general block-dev write */
+       NULL,                   /* readdir - bad */
+       NULL,                   /* select */
+       pcd_ioctl,              /* ioctl */
+       NULL,                   /* mmap */
+       pcd_open,               /* open */
+       pcd_release,            /* release */
+       block_fsync,            /* fsync */
+       NULL,                   /* fasync */
+       NULL,                   /* media change ? */
+       NULL                    /* revalidate new media */
+};
+
+static void pcd_init_units( void )
+
+{       int     unit, j;
+
+        pcd_drive_count = 0;
+        for (unit=0;unit<PCD_UNITS;unit++) {
+                PCD.pi = & PCD.pia;
+                PCD.access = 0;
+                PCD.present = 0;
+                j = 0;
+                while ((j < PCD_NAMELEN-2) && (PCD.name[j]=name[j])) j++;
+                PCD.name[j++] = '0' + unit;
+                PCD.name[j] = 0;
+                PCD.drive = DU[D_SLV];
+                if (DU[D_PRT]) pcd_drive_count++;
+        }
+}
+
+int pcd_init (void)    /* preliminary initialisation */
+
+{       int    i;
+
+       if (disable) return -1;
+
+       pcd_init_units();
+
+       if (pcd_detect()) return -1;
+
+       if (register_blkdev(MAJOR_NR,name,&pcd_fops)) {
+               printk("pcd: unable to get major number %d\n",MAJOR_NR);
+               return -1;
+       }
+       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+       read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
+
+       for (i=0;i<PCD_UNITS;i++) pcd_blocksizes[i] = 1024;
+        blksize_size[MAJOR_NR] = pcd_blocksizes;
+
+       return 0;
+}
+
+static int pcd_open (struct inode *inode, struct file *file)
+
+{      int unit = DEVICE_NR(inode->i_rdev);
+
+       if  ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
+
+       if (file->f_mode & 2) return -EROFS;  /* wants to write ? */
+
+       MOD_INC_USE_COUNT;
+
+       if (pcd_check_media(unit)) {
+               MOD_DEC_USE_COUNT;
+               return -ENXIO;
+       }
+
+       pcd_lock(unit);
+
+       PCD.access++;
+       return 0;
+}
+
+static void do_pcd_request (void)
+
+{       int unit;
+
+       if (pcd_busy) return;
+        while (1) {
+           if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+           INIT_REQUEST;
+           if (CURRENT->cmd == READ) {
+               unit = MINOR(CURRENT->rq_dev);
+               if (unit != pcd_unit) {
+                       pcd_bufblk = -1;
+                       pcd_unit = unit;
+               }
+               pcd_sector = CURRENT->sector;
+               pcd_count = CURRENT->nr_sectors;
+               pcd_buf = CURRENT->buffer;
+               do_pcd_read(unit);
+               if (pcd_busy) return;
+           } 
+           else end_request(0);
+       }
+}
+
+static int pcd_ioctl(struct inode *inode,struct file *file,
+                   unsigned int cmd, unsigned long arg)
+
+/* we currently support only the EJECT ioctl. */
+
+{      int unit = DEVICE_NR(inode->i_rdev);
+       if  ((unit >= PCD_UNITS) || (!PCD.present)) return -ENODEV;
+
+       switch (cmd) {
+            case CDROMEJECT: if (PCD.access == 1) {
+                               pcd_eject(unit);
+                               return 0;
+                            }
+           default:
+               return -EINVAL;
+       }
+}
+
+static int pcd_release (struct inode *inode, struct file *file)
+
+{      kdev_t  devp;
+       int     unit;
+
+        struct super_block *sb;
+
+       devp = inode->i_rdev;
+       unit = DEVICE_NR(devp);
+
+       if  ((unit >= PCD_UNITS) || (PCD.access <= 0)) 
+                       return -EINVAL;
+       
+       PCD.access--;
+
+       if (!PCD.access) { 
+               fsync_dev(devp);
+
+                sb = get_super(devp);
+                if (sb) invalidate_inodes(sb);
+
+               invalidate_buffers(devp);
+               pcd_unlock(unit);
+
+       }
+
+       MOD_DEC_USE_COUNT;
+
+        return 0;
+
+}
+
+#ifdef MODULE
+
+/* Glue for modules ... */
+
+int    init_module(void)
+
+{      int     err;
+       long    flags;
+
+       save_flags(flags);
+       cli();
+
+       err = pcd_init();
+
+       restore_flags(flags);
+       return err;
+}
+
+void   cleanup_module(void)
+
+{      long flags;
+       int unit;
+
+       save_flags(flags);
+       cli();
+       unregister_blkdev(MAJOR_NR,name);
+       
+        for (unit=0;unit<PCD_UNITS;unit++) 
+           if (PCD.present) pi_release(PI);
+
+       restore_flags(flags);
+}
+
+#endif
+
+#define WR(c,r,v)       pi_write_regr(PI,c,r,v)
+#define RR(c,r)         (pi_read_regr(PI,c,r))
+
+static int pcd_wait( int unit, int go, int stop, char * fun, char * msg )
+
+{      int j, r, e, s, p;
+
+       j = 0;
+       while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(j++<PCD_SPIN))
+               udelay(PCD_DELAY);
+
+       if ((r&(IDE_ERR&stop))||(j>=PCD_SPIN)) {
+          s = RR(0,7);
+          e = RR(0,1);
+          p = RR(0,2);
+                  if (j >= PCD_SPIN) e |= 0x100;
+           if (fun) printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
+                          " loop=%d phase=%d\n",
+                           PCD.name,fun,msg,r,s,e,j,p);
+          return (s<<8)+r;
+       }
+       return 0;
+}
+
+static int pcd_command( int unit, char * cmd, int dlen, char * fun )
+
+{      pi_connect(PI);
+
+        WR(0,6,0xa0 + 0x10*PCD.drive);
+
+       if (pcd_wait(unit,IDE_BUSY|IDE_DRQ,0,fun,"before command")) {
+               pi_disconnect(PI);
+               return -1;
+       }
+
+        WR(0,4,dlen % 256);
+        WR(0,5,dlen / 256);
+        WR(0,7,0xa0);          /* ATAPI packet command */
+
+        if (pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_ERR,fun,"command DRQ")) {
+               pi_disconnect(PI);
+               return -1;
+       }
+
+        if (RR(0,2) != 1) {
+           printk("%s: %s: command phase error\n",PCD.name,fun);
+          pi_disconnect(PI);
+           return -1;
+        }
+
+       pi_write_block(PI,cmd,12);
+
+       return 0;
+}
+
+static int pcd_completion( int unit, char * buf,  char * fun )
+
+{      int r, s, n;
+
+       r = pcd_wait(unit,IDE_BUSY,IDE_DRQ|IDE_READY|IDE_ERR,fun,"completion");
+
+       if ((RR(0,2)&2) && (RR(0,7)&IDE_DRQ)) { 
+               n = (RR(0,4)+256*RR(0,5));
+               pi_read_block(PI,buf,n);
+       }
+
+       s = pcd_wait(unit,IDE_BUSY,IDE_READY|IDE_ERR,fun,"data done");
+
+       pi_disconnect(PI); 
+
+       return (r?r:s);
+}
+
+static void pcd_req_sense( int unit, int quiet )
+
+{      char    rs_cmd[12] = { 0x03,0,0,0,16,0,0,0,0,0,0,0 };
+       char    buf[16];
+       int     r;
+
+       r = pcd_command(unit,rs_cmd,16,"Request sense");
+       udelay(1000);
+       if (!r) pcd_completion(unit,buf,"Request sense");
+
+        if ((!r)&&(!quiet)) 
+               printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
+                      PCD.name,buf[2]&0xf,buf[12],buf[13]);
+}
+
+static int pcd_atapi( int unit, char * cmd, int dlen, char * buf, char * fun )
+
+{      int r;
+
+       r = pcd_command(unit,cmd,dlen,fun);
+       udelay(1000);
+       if (!r) r = pcd_completion(unit,buf,fun);
+       if (r) pcd_req_sense(unit,!fun);
+       
+       return r;
+}
+
+#define DBMSG(msg)     NULL
+
+static void pcd_lock(int unit)
+
+{      char    lo_cmd[12] = { 0x1e,0,0,0,1,0,0,0,0,0,0,0 };
+       char    cl_cmd[12] = { 0x1b,0,0,0,3,0,0,0,0,0,0,0 };
+
+       pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd1")); 
+       pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd2"));
+       pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd3"));
+       pcd_atapi(unit,cl_cmd,0,pcd_scratch,DBMSG("cd4"));
+       pcd_atapi(unit,cl_cmd,0,pcd_scratch,"close door");
+
+        pcd_atapi(unit,lo_cmd,0,pcd_scratch,DBMSG("ld"));
+        pcd_atapi(unit,lo_cmd,0,pcd_scratch,"lock door");
+}
+
+static void pcd_unlock( int unit )
+
+{      char    un_cmd[12] = { 0x1e,0,0,0,0,0,0,0,0,0,0,0 };
+
+       pcd_atapi(unit,un_cmd,0,pcd_scratch,"unlock door");
+}
+
+static void pcd_eject( int unit)
+
+{      char    ej_cmd[12] = { 0x1b,0,0,0,2,0,0,0,0,0,0,0 };
+
+       pcd_unlock(unit);
+       pcd_atapi(unit,ej_cmd,0,pcd_scratch,"eject");
+}
+
+#define PCD_RESET_TMO  30              /* in tenths of a second */
+
+static void pcd_sleep( int cs )
+
+{       current->state = TASK_INTERRUPTIBLE;
+        current->timeout = jiffies + cs;
+        schedule();
+}
+
+static int pcd_reset( int unit )
+
+/* the ATAPI standard actually specifies the contents of all 7 registers
+   after a reset, but the specification is ambiguous concerning the last
+   two bytes, and different drives interpret the standard differently.
+*/
+
+{      int     i, k, flg;
+       int     expect[5] = {1,1,1,0x14,0xeb};
+       long    flags;
+
+       pi_connect(PI);
+       WR(0,6,0xa0 + 0x10*PCD.drive);
+       WR(0,7,8);
+
+       save_flags(flags);
+       sti();
+
+       pcd_sleep(2);           /* delay a bit*/
+
+       k = 0;
+       while ((k++ < PCD_RESET_TMO) && (RR(1,6)&IDE_BUSY))
+               pcd_sleep(10);
+
+       restore_flags(flags);
+
+       flg = 1;
+       for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
+
+       if (verbose) {
+               printk("%s: Reset (%d) signature = ",PCD.name,k);
+               for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
+               if (!flg) printk(" (incorrect)");
+               printk("\n");
+       }
+       
+       pi_disconnect(PI);
+       return flg-1;   
+}
+
+static int pcd_check_media( int unit )
+
+{      char    rc_cmd[12] = { 0x25,0,0,0,0,0,0,0,0,0,0,0};
+
+       pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("cm1"));
+       pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("cm2"));
+       return (pcd_atapi(unit,rc_cmd,8,pcd_scratch,DBMSG("cm3")));
+}
+
+static int pcd_identify( int unit, char * id )
+
+{      int k, s;
+       char   id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
+
+       pcd_bufblk = -1;
+
+        s = pcd_atapi(unit,id_cmd,36,pcd_buffer,"identify");
+
+       if (s) return -1;
+       if ((pcd_buffer[0] & 0x1f) != 5) {
+         if (verbose) printk("%s: %s is not a CDrom\n",
+                       PCD.name,PCD.drive?"Slave":"Master");
+         return -1;
+       }
+       for (k=0;k<16;k++) id[k] = pcd_buffer[16+k]; id[16] = 0;
+       k = 16; while ((k >= 0) && (id[k] <= 0x20)) { id[k] = 0; k--; }
+
+       printk("%s: %s: %s\n",PCD.name,PCD.drive?"Slave":"Master",id);
+
+       return 0;
+}
+
+static int pcd_probe( int unit, int ms, char * id )
+
+/*     returns  0, with id set if drive is detected
+               -1, if drive detection failed
+*/
+
+{      if (ms == -1) {
+            for (PCD.drive=0;PCD.drive<=1;PCD.drive++)
+              if (!pcd_reset(unit) && !pcd_identify(unit,id)) 
+                 return 0;
+       } else {
+           PCD.drive = ms;
+            if (!pcd_reset(unit) && !pcd_identify(unit,id)) 
+               return 0;
+       }
+       return -1;
+}
+
+static int pcd_detect( void )
+
+{      char    id[18];
+       int     k, unit;
+
+       printk("%s: %s version %s, major %d, nice %d\n",
+               name,name,PCD_VERSION,major,nice);
+
+       k = 0;
+       if (pcd_drive_count == 0) {  /* nothing spec'd - so autoprobe for 1 */
+           unit = 0;
+           if (pi_init(PI,1,-1,-1,-1,-1,-1,pcd_buffer,
+                     PI_PCD,verbose,PCD.name)) {
+               if (!pcd_probe(unit,-1,id)) {
+                       PCD.present = 1;
+                       k++;
+               } else pi_release(PI);
+           }
+
+       } else for (unit=0;unit<PCD_UNITS;unit++) if (DU[D_PRT])
+           if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
+                        DU[D_PRO],DU[D_DLY],pcd_buffer,PI_PCD,verbose,
+                        PCD.name)) {
+               if (!pcd_probe(unit,DU[D_SLV],id)) {
+                        PCD.present = 1;
+                        k++;
+                } else pi_release(PI);
+            }
+
+       if (k) return 0;
+       
+       printk("%s: No CDrom drive found\n",name);
+       return -1;
+}
+
+/* I/O request processing */
+
+static int pcd_ready( void )
+
+{      int     unit = pcd_unit;
+
+       return (((RR(1,6)&(IDE_BUSY|IDE_DRQ))==IDE_DRQ)) ;
+}
+
+static void pcd_transfer( void )
+
+{      int     k, o;
+
+       while (pcd_count && (pcd_sector/4 == pcd_bufblk)) {
+               o = (pcd_sector % 4) * 512;
+               for(k=0;k<512;k++) pcd_buf[k] = pcd_buffer[o+k];
+               pcd_count--;
+               pcd_buf += 512;
+               pcd_sector++;
+       }
+}
+
+static void pcd_start( void )
+
+{      int     unit = pcd_unit;
+       int     b, i;
+       char    rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
+
+       pcd_bufblk = pcd_sector / 4;
+        b = pcd_bufblk;
+       for(i=0;i<4;i++) { 
+          rd_cmd[5-i] = b & 0xff;
+          b = b >> 8;
+       }
+
+
+       if (pcd_command(unit,rd_cmd,2048,"read block")) {
+               pcd_bufblk = -1; 
+               pcd_busy = 0;
+               cli();
+               end_request(0);
+               do_pcd_request();
+               return;
+       }
+
+       udelay(1000);
+
+       ps_set_intr(do_pcd_read_drq,pcd_ready,PCD_TMO,nice);
+
+}
+
+static void do_pcd_read( int unit )
+
+{      pcd_busy = 1;
+       pcd_retries = 0;
+       pcd_transfer();
+       if (!pcd_count) {
+               end_request(1);
+               pcd_busy = 0;
+               return;
+       }
+       sti();
+
+       pi_do_claimed(PI,pcd_start);
+}
+
+static void do_pcd_read_drq( void )
+
+{      int     unit = pcd_unit;
+
+       sti();
+
+       if (pcd_completion(unit,pcd_buffer,"read block")) {
+                if (pcd_retries < PCD_RETRIES) {
+                        udelay(1000);
+                        pcd_retries++;
+                       pi_do_claimed(PI,pcd_start);
+                        return;
+                        }
+               cli();
+               pcd_busy = 0;
+               pcd_bufblk = -1;
+               end_request(0);
+               do_pcd_request();
+               return;
+       }
+
+       do_pcd_read(unit);
+       do_pcd_request();
+}
+       
+/* end of pcd.c */
diff --git a/drivers/block/paride/pd.c b/drivers/block/paride/pd.c
new file mode 100644 (file)
index 0000000..e9efbcd
--- /dev/null
@@ -0,0 +1,1062 @@
+/* 
+        pd.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+        This is the high-level driver for parallel port IDE hard
+        drives based on chips supported by the paride module.
+
+       By default, the driver will autoprobe for a single parallel
+       port IDE drive, but if their individual parameters are
+        specified, the driver can handle up to 4 drives.
+
+        The behaviour of the pd driver can be altered by setting
+        some parameters from the insmod command line.  The following
+        parameters are adjustable:
+           drive0      These four arguments can be arrays of       
+           drive1      1-7 integers as follows:
+           drive2
+           drive3      <prt>,<pro>,<uni>,<mod>,<geo>,<sby>,<dly>
+
+                       Where,
+
+               <prt>   is the base of the parallel port address for
+                       the corresponding drive.  (required)
+
+               <pro>   is the protocol number for the adapter that
+                       supports this drive.  These numbers are
+                        logged by 'paride' when the protocol modules
+                       are initialised.  (0 if not given)
+
+               <uni>   for those adapters that support chained
+                       devices, this is the unit selector for the
+                       chain of devices on the given port.  It should
+                       be zero for devices that don't support chaining.
+                       (0 if not given)
+
+               <mod>   this can be -1 to choose the best mode, or one
+                       of the mode numbers supported by the adapter.
+                       (-1 if not given)
+
+               <geo>   this defaults to 0 to indicate that the driver
+                       should use the CHS geometry provided by the drive
+                       itself.  If set to 1, the driver will provide
+                       a logical geometry with 64 heads and 32 sectors
+                       per track, to be consistent with most SCSI
+                       drivers.  (0 if not given)
+
+               <sby>   set this to zero to disable the power saving
+                       standby mode, if needed.  (1 if not given)
+
+               <dly>   some parallel ports require the driver to 
+                       go more slowly.  -1 sets a default value that
+                       should work with the chosen protocol.  Otherwise,
+                       set this to a small integer, the larger it is
+                       the slower the port i/o.  In some cases, setting
+                       this to zero will speed up the device. (default -1)
+                       
+
+            major       You may use this parameter to overide the
+                        default major number (45) that this driver
+                        will use.  Be sure to change the device
+                        name as well.
+
+            name        This parameter is a character string that
+                        contains the name the kernel will use for this
+                        device (in /proc output, for instance).
+                       (default "pd")
+
+           cluster     The driver will attempt to aggregate requests
+                       for adjacent blocks into larger multi-block
+                       clusters.  The maximum cluster size (in 512
+                       byte sectors) is set with this parameter.
+                       (default 64)
+
+           verbose     This parameter controls the amount of logging
+                       that is done while the driver probes for
+                       devices.  Set it to 0 for a quiet load, or to 1
+                       see all the progress messages.  (default 0)
+
+            nice        This parameter controls the driver's use of
+                        idle CPU time, at the expense of some speed.
+
+        If this driver is built into the kernel, you can use kernel
+        the following command line parameters, with the same values
+        as the corresponding module parameters listed above:
+
+            pd.drive0
+            pd.drive1
+            pd.drive2
+            pd.drive3
+            pd.cluster
+            pd.nice
+
+        In addition, you can use the parameter pd.disable to disable
+        the driver entirely.
+*/
+
+#define PD_VERSION      "1.0"
+#define PD_MAJOR       45
+#define PD_NAME                "pd"
+#define PD_UNITS       4
+
+/* Here are things one can override from the insmod command.
+   Most are autoprobed by paride unless set here.  Verbose is on
+   by default.
+
+*/
+
+static int     verbose = 0;
+static int     major = PD_MAJOR;
+static char    *name = PD_NAME;
+static int     cluster = 64;   
+static int      nice = 0;
+static int      disable = 0;
+
+static int drive0[7] = {0,0,0,-1,0,1,-1};
+static int drive1[7] = {0,0,0,-1,0,1,-1};
+static int drive2[7] = {0,0,0,-1,0,1,-1};
+static int drive3[7] = {0,0,0,-1,0,1,-1};
+
+static int (*drives[4])[7] = {&drive0,&drive1,&drive2,&drive3};
+static int pd_drive_count;
+
+#define D_PRT  0
+#define D_PRO   1
+#define D_UNI  2
+#define D_MOD  3
+#define D_GEO  4
+#define D_SBY  5
+#define D_DLY  6
+
+#define        DU              (*drives[unit])
+
+/* end of parameters */
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+
+#include <asm/uaccess.h>
+
+#ifndef MODULE
+
+#include "setup.h"
+
+static STT pd_stt[7] = {{"drive0",7,drive0},
+                       {"drive1",7,drive1},
+                       {"drive2",7,drive2},
+                       {"drive3",7,drive3},
+                       {"disable",1,&disable},
+                       {"cluster",1,&cluster},
+                       {"nice",1,&nice}};
+
+void pd_setup( char *str, int *ints)
+
+{      generic_setup(pd_stt,7,str);
+}
+
+#endif
+
+MODULE_PARM(verbose,"i");
+MODULE_PARM(major,"i");
+MODULE_PARM(name,"s");
+MODULE_PARM(cluster,"i");
+MODULE_PARM(nice,"i");
+MODULE_PARM(drive0,"1-7i");
+MODULE_PARM(drive1,"1-7i");
+MODULE_PARM(drive2,"1-7i");
+MODULE_PARM(drive3,"1-7i");
+
+#include "paride.h"
+
+#define PD_BITS    4
+
+/* set up defines for blk.h,  why don't all drivers do it this way ? */
+
+#define MAJOR_NR   major
+#define DEVICE_NAME "PD"
+#define DEVICE_REQUEST do_pd_request
+#define DEVICE_NR(device) (MINOR(device)>>PD_BITS)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#include <linux/blk.h>
+
+#include "pseudo.h"
+
+#define PD_PARTNS      (1<<PD_BITS)
+#define PD_DEVS                PD_PARTNS*PD_UNITS
+
+/* numbers for "SCSI" geometry */
+
+#define PD_LOG_HEADS    64
+#define PD_LOG_SECTS    32
+
+#define PD_ID_OFF       54
+#define PD_ID_LEN       14
+
+#define PD_MAX_RETRIES  5
+#define PD_TMO          800             /* interrupt timeout in jiffies */
+#define PD_SPIN_DEL     50              /* spin delay in micro-seconds  */
+
+#define PD_SPIN         (10000/PD_SPIN_DEL)*PD_TMO  
+
+#define STAT_ERR        0x00001
+#define STAT_INDEX      0x00002
+#define STAT_ECC        0x00004
+#define STAT_DRQ        0x00008
+#define STAT_SEEK       0x00010
+#define STAT_WRERR      0x00020
+#define STAT_READY      0x00040
+#define STAT_BUSY       0x00080
+
+#define ERR_AMNF        0x00100
+#define ERR_TK0NF       0x00200
+#define ERR_ABRT        0x00400
+#define ERR_MCR         0x00800
+#define ERR_IDNF        0x01000
+#define ERR_MC          0x02000
+#define ERR_UNC         0x04000
+#define ERR_TMO         0x10000
+
+#define IDE_READ               0x20
+#define IDE_WRITE              0x30
+#define IDE_READ_VRFY          0x40
+#define IDE_INIT_DEV_PARMS     0x91
+#define IDE_STANDBY            0x96
+#define IDE_ACKCHANGE          0xdb
+#define IDE_DOORLOCK           0xde
+#define IDE_DOORUNLOCK         0xdf
+#define IDE_IDENTIFY           0xec
+
+int pd_init(void);
+void pd_setup(char * str, int * ints);
+#ifdef MODULE
+void cleanup_module( void );
+#endif
+static void pd_geninit(struct gendisk *ignored);
+static int pd_open(struct inode *inode, struct file *file);
+static void do_pd_request(void);
+static int pd_ioctl(struct inode *inode,struct file *file,
+                    unsigned int cmd, unsigned long arg);
+static int pd_release (struct inode *inode, struct file *file);
+static int pd_revalidate(kdev_t dev);
+static int pd_detect(void);
+static void do_pd_read(void);
+static void do_pd_write(void);
+static void do_pd_read_drq( void );
+static void do_pd_write_done( void );
+
+static int pd_identify (int unit);
+static void pd_media_check(int unit);
+static void pd_doorlock(int unit, int func);
+static int pd_check_media(kdev_t dev);
+
+static struct hd_struct pd_hd[PD_DEVS];
+static int pd_sizes[PD_DEVS];
+static int pd_blocksizes[PD_DEVS];
+
+#define PD_NAMELEN     8
+
+struct pd_unit {
+       struct pi_adapter pia;          /* interface to paride layer */
+       struct pi_adapter *pi;
+       int access;                     /* count of active opens ... */
+       int capacity;                   /* Size of this volume in sectors */
+       int heads;                      /* physical geometry */
+       int sectors;
+       int cylinders;
+       int changed;                    /* Have we seen a disk change ? */
+       int removable;                  /* removable media device  ?  */
+       int standby;
+       int alt_geom;
+       int present;
+       char name[PD_NAMELEN];          /* pda, pdb, etc ... */
+       };
+
+struct pd_unit pd[PD_UNITS];
+
+/*  'unit' must be defined in all functions - either as a local or a param */
+
+#define PD pd[unit]
+#define PI PD.pi
+
+static int pd_valid = 1;               /* serialise partition checks */
+static char pd_scratch[512];            /* scratch block buffer */
+
+/* the variables below are used mainly in the I/O request engine, which
+   processes only one request at a time.
+*/
+
+static int pd_retries = 0;              /* i/o error retry count */
+static int pd_busy = 0;                 /* request being processed ? */
+static int pd_block;                    /* address of next requested block */
+static int pd_count;                    /* number of blocks still to do */
+static int pd_run;                     /* sectors in current cluster */
+static int pd_cmd;                     /* current command READ/WRITE */
+static int pd_unit;                    /* unit of current request */
+static int pd_dev;                     /* minor of current request */
+static int pd_poffs;                   /* partition offset of current minor */
+static char * pd_buf;                   /* buffer for request in progress */
+
+static struct wait_queue *pd_wait_open = NULL;
+
+static char *pd_errs[17] = { "ERR","INDEX","ECC","DRQ","SEEK","WRERR",
+                             "READY","BUSY","AMNF","TK0NF","ABRT","MCR",
+                             "IDNF","MC","UNC","???","TMO"};
+
+/* kernel glue structures */
+
+static struct gendisk pd_gendisk = {
+        PD_MAJOR,       /* Major number */
+        PD_NAME,        /* Major name */
+        PD_BITS,        /* Bits to shift to get real from partition */
+        PD_PARTNS,      /* Number of partitions per real */
+        PD_UNITS,       /* maximum number of real */
+        pd_geninit,     /* init function */
+        pd_hd,          /* hd struct */
+        pd_sizes,       /* block sizes */
+        0,              /* number */
+        NULL,           /* internal */
+        NULL            /* next */
+};
+
+static struct file_operations pd_fops = {
+        NULL,                   /* lseek - default */
+        block_read,             /* read - general block-dev read */
+        block_write,            /* write - general block-dev write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* select */
+        pd_ioctl,               /* ioctl */
+        NULL,                   /* mmap */
+        pd_open,                /* open */
+        pd_release,             /* release */
+        block_fsync,            /* fsync */
+        NULL,                   /* fasync */
+        pd_check_media,         /* media change ? */
+        pd_revalidate           /* revalidate new media */
+};
+
+void pd_init_units( void )
+
+{      int     unit, j;
+
+       pd_drive_count = 0;
+       for (unit=0;unit<PD_UNITS;unit++) {
+               PD.pi = & PD.pia;
+               PD.access = 0;
+               PD.changed = 1;
+               PD.capacity = 0;
+               PD.present = 0;
+               j = 0;
+               while ((j < PD_NAMELEN-2) && (PD.name[j]=name[j])) j++;
+               PD.name[j++] = 'a' + unit;
+               PD.name[j] = 0;
+               PD.alt_geom = DU[D_GEO];
+               PD.standby = DU[D_SBY];
+               if (DU[D_PRT]) pd_drive_count++;
+       }
+}
+
+int pd_init (void)
+
+{       int i;
+
+       if (disable) return -1;
+
+        if (register_blkdev(MAJOR_NR,name,&pd_fops)) {
+                printk("%s: unable to get major number %d\n",
+                        name,major);
+                return -1;
+        }
+        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+        read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
+        
+       pd_gendisk.major = major;
+       pd_gendisk.major_name = name;
+       pd_gendisk.next = gendisk_head;
+        gendisk_head = &pd_gendisk;
+
+        for(i=0;i<PD_DEVS;i++) pd_blocksizes[i] = 1024;
+        blksize_size[MAJOR_NR] = pd_blocksizes;
+
+        printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
+                name,name,PD_VERSION,major,cluster,nice);
+       
+        return 0;
+}
+
+static void pd_geninit (struct gendisk *ignored)
+
+{      pd_init_units();
+       pd_gendisk.nr_real = pd_detect();
+
+#ifdef MODULE
+        if (!pd_gendisk.nr_real) cleanup_module();
+#endif
+
+}
+
+static int pd_open (struct inode *inode, struct file *file)
+
+{       int unit = DEVICE_NR(inode->i_rdev);
+
+        if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
+
+        MOD_INC_USE_COUNT;
+
+        while (!pd_valid) sleep_on(&pd_wait_open);
+
+        PD.access++;
+
+        if (PD.removable) {
+               pd_media_check(unit);
+               pd_doorlock(unit,IDE_DOORLOCK);
+       }
+        return 0;
+}
+
+static int pd_ioctl(struct inode *inode,struct file *file,
+                    unsigned int cmd, unsigned long arg)
+
+{       struct hd_geometry *geo = (struct hd_geometry *) arg;
+        int dev, err, unit;
+
+        if ((!inode) || (!inode->i_rdev)) return -EINVAL;
+        dev = MINOR(inode->i_rdev);
+       unit = DEVICE_NR(inode->i_rdev);
+        if (dev >= PD_DEVS) return -EINVAL;
+       if (!PD.present) return -ENODEV;
+
+        switch (cmd) {
+            case HDIO_GETGEO:
+                if (!geo) return -EINVAL;
+                err = verify_area(VERIFY_WRITE,geo,sizeof(*geo));
+                if (err) return err;
+
+               if (PD.alt_geom) {
+                    put_user(PD.capacity/(PD_LOG_HEADS*PD_LOG_SECTS), 
+                               (short *) &geo->cylinders);
+                    put_user(PD_LOG_HEADS, (char *) &geo->heads);
+                    put_user(PD_LOG_SECTS, (char *) &geo->sectors);
+               } else {
+                    put_user(PD.cylinders, (short *) &geo->cylinders);
+                    put_user(PD.heads, (char *) &geo->heads);
+                    put_user(PD.sectors, (char *) &geo->sectors);
+               }
+                put_user(pd_hd[dev].start_sect,(long *)&geo->start);
+                return 0;
+            case BLKRASET:
+                if(!suser()) return -EACCES;
+                if(!(inode->i_rdev)) return -EINVAL;
+                if(arg > 0xff) return -EINVAL;
+                read_ahead[MAJOR(inode->i_rdev)] = arg;
+                return 0;
+            case BLKRAGET:
+                if (!arg) return -EINVAL;
+                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
+                if (err) return (err);
+                put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
+                return (0);
+            case BLKGETSIZE:
+                if (!arg) return -EINVAL;
+                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
+                if (err) return (err);
+                put_user(pd_hd[dev].nr_sects,(long *) arg);
+                return (0);
+            case BLKFLSBUF:
+                if(!suser())  return -EACCES;
+                if(!(inode->i_rdev)) return -EINVAL;
+                fsync_dev(inode->i_rdev);
+                invalidate_buffers(inode->i_rdev);
+                return 0;
+            case BLKRRPART:
+                return pd_revalidate(inode->i_rdev);
+            RO_IOCTLS(inode->i_rdev,arg);
+            default:
+                return -EINVAL;
+        }
+}
+
+static int pd_release (struct inode *inode, struct file *file)
+
+{       kdev_t devp;
+       int     unit;
+
+       struct super_block *sb;
+
+        devp = inode->i_rdev;
+       unit = DEVICE_NR(devp);
+
+       if ((unit >= PD_UNITS) || (PD.access <= 0)) 
+               return -EINVAL;
+
+       PD.access--;
+
+        if (!PD.access)  {
+                fsync_dev(devp);
+
+               sb = get_super(devp);
+               if (sb) invalidate_inodes(sb);
+
+                invalidate_buffers(devp);
+               if (PD.removable) pd_doorlock(unit,IDE_DOORUNLOCK);
+       }
+
+        MOD_DEC_USE_COUNT;
+
+       return 0;
+}
+
+static int pd_check_media( kdev_t dev)
+
+{       int r, unit;
+
+       unit = DEVICE_NR(dev);
+       if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
+        if (!PD.removable) return 0;
+       pd_media_check(unit);
+       r = PD.changed;
+       PD.changed = 0;
+       return r;
+}
+
+static int pd_revalidate(kdev_t dev)
+
+{       int p, unit, minor;
+        long flags;
+        kdev_t devp;
+
+       struct super_block *sb;
+
+        unit = DEVICE_NR(dev);
+        if ((unit >= PD_UNITS) || (!PD.present)) return -ENODEV;
+
+        save_flags(flags);
+        cli(); 
+        if (PD.access > 1) {
+                restore_flags(flags);
+                return -EBUSY;
+        }
+        pd_valid = 0;
+        restore_flags(flags);   
+
+        for (p=(PD_PARTNS-1);p>=0;p--) {
+               minor = p + unit*PD_PARTNS;
+                devp = MKDEV(MAJOR_NR, minor);
+                fsync_dev(devp);
+
+                sb = get_super(devp);
+                if (sb) invalidate_inodes(sb);
+
+                invalidate_buffers(devp);
+                pd_hd[minor].start_sect = 0;
+                pd_hd[minor].nr_sects = 0;
+        }
+
+       pd_identify(unit);
+        resetup_one_dev(&pd_gendisk,unit);
+
+        pd_valid = 1;
+        wake_up(&pd_wait_open);
+
+        return 0;
+}
+
+#ifdef MODULE
+
+/* Glue for modules ... */
+
+void    cleanup_module(void);
+
+int     init_module(void)
+
+{       int     err, unit;
+        long    flags;
+
+        save_flags(flags);
+        cli();
+
+        err = pd_init();
+        if (err) {
+            restore_flags(flags);
+            return err;
+        }
+
+       pd_geninit(&pd_gendisk);
+
+        if (!pd_gendisk.nr_real) {
+                restore_flags(flags);
+                return -1;
+        }
+
+        pd_valid = 0;
+       for (unit=0;unit<PD_UNITS;unit++) 
+          if (PD.present) resetup_one_dev(&pd_gendisk,unit);
+        pd_valid = 1;
+
+        restore_flags(flags);
+        return 0;
+}
+
+void    cleanup_module(void)
+
+{       struct gendisk **gdp;
+        long flags;
+       int unit;
+
+        save_flags(flags);
+        cli();
+
+        unregister_blkdev(MAJOR_NR,name);
+
+        for(gdp=&gendisk_head;*gdp;gdp=&((*gdp)->next))
+                if (*gdp == &pd_gendisk) break;
+        if (*gdp) *gdp = (*gdp)->next;
+
+       for (unit=0;unit<PD_UNITS;unit++) 
+          if (PD.present) pi_release(PI);
+
+        restore_flags(flags);
+}
+
+#endif
+
+#define        WR(c,r,v)       pi_write_regr(PI,c,r,v)
+#define        RR(c,r)         (pi_read_regr(PI,c,r))
+
+/*  ide command interface */
+
+static void pd_print_error( int unit, char * msg, int status )
+
+{       int     i;
+
+       printk("%s: %s: status = 0x%x =",PD.name,msg,status);
+        for(i=0;i<18;i++) if (status & (1<<i)) printk(" %s",pd_errs[i]);
+       printk("\n");
+}
+
+/*
+static void pd_reset( int unit )
+
+{       pi_connect(PI);
+       WR(1,6,4);
+        udelay(50);
+        WR(1,6,0);
+       pi_disconnect(PI);
+}
+*/
+
+#define DBMSG(msg)     NULL
+
+static int pd_wait_for( int unit, int w, char * msg )    /* polled wait */
+
+{       int     k, r, e;
+
+        k=0;
+        while(k < PD_SPIN) { 
+            r = RR(1,6);
+            k++;
+            if (((r & w) == w) && !(r & STAT_BUSY)) break;
+            udelay(PD_SPIN_DEL);
+        }
+        e = (RR(0,1)<<8) + RR(0,7);
+        if (k >= PD_SPIN)  e |= ERR_TMO;
+        if ((e & (STAT_ERR|ERR_TMO)) && (msg != NULL)) 
+               pd_print_error(unit,msg,e);
+        return e;
+}
+
+static void pd_send_command( int unit, int n, int s, int h, 
+                            int c0, int c1, int func )
+
+{
+        WR(0,6,0xa0+h);
+        WR(0,1,0);                /* the IDE task file */
+        WR(0,2,n);
+        WR(0,3,s);
+        WR(0,4,c0);
+        WR(0,5,c1);
+        WR(0,7,func);
+
+        udelay(1);
+}
+
+static void pd_ide_command( int unit, int func, int block, int count )
+
+/* Don't use this call if the capacity is zero. */
+
+{       int c1, c0, h, s;
+
+        s  = ( block % PD.sectors) + 1;
+        h  = ( block / PD.sectors) % PD.heads;
+        c0 = ( block / (PD.sectors*PD.heads)) % 256;
+        c1 = ( block / (PD.sectors*PD.heads*256));
+
+        pd_send_command(unit,count,s,h,c0,c1,func);
+}
+
+/* According to the ATA standard, the default CHS geometry should be
+   available following a reset.  Some Western Digital drives come up
+   in a mode where only LBA addresses are accepted until the device
+   parameters are initialised.
+*/
+
+static void pd_init_dev_parms( int unit )
+{       pi_connect(PI);
+        pd_wait_for(unit,0,DBMSG("before init_dev_parms"));
+        pd_send_command(unit,PD.sectors,0,PD.heads-1,0,0,IDE_INIT_DEV_PARMS);
+        udelay(300);
+        pd_wait_for(unit,0,"Initialise device parameters");
+        pi_disconnect(PI);
+}
+
+static void pd_doorlock( int unit, int func )
+
+{       pi_connect(PI);
+        if (pd_wait_for(unit,STAT_READY,"Lock") & STAT_ERR) {
+                pi_disconnect(PI);
+                return;
+        }
+        pd_send_command(unit,1,0,0,0,0,func);
+        pd_wait_for(unit,STAT_READY,"Lock done");
+        pi_disconnect(PI);
+}
+
+static void pd_media_check( int unit )
+
+{       int    r;
+
+        pi_connect(PI);
+        r = pd_wait_for(unit,STAT_READY,DBMSG("before media_check"));
+        if (!(r & STAT_ERR)) {
+                pd_send_command(unit,1,1,0,0,0,IDE_READ_VRFY);  
+                r = pd_wait_for(unit,STAT_READY,DBMSG("RDY after READ_VRFY"));
+        } else PD.changed = 1;   /* say changed if other error */
+        if (r & ERR_MC) {
+                PD.changed = 1;
+                pd_send_command(unit,1,0,0,0,0,IDE_ACKCHANGE);
+                pd_wait_for(unit,STAT_READY,DBMSG("RDY after ACKCHANGE"));
+               pd_send_command(unit,1,1,0,0,0,IDE_READ_VRFY);
+                r = pd_wait_for(unit,STAT_READY,DBMSG("RDY after VRFY"));
+        }
+        pi_disconnect(PI);
+
+}
+
+static void pd_standby_off( int unit )
+
+{       pi_connect(PI);
+        pd_wait_for(unit,0,DBMSG("before STANDBY"));
+        pd_send_command(unit,0,0,0,0,0,IDE_STANDBY);
+        pd_wait_for(unit,0,DBMSG("after STANDBY"));
+        pi_disconnect(PI);
+}
+
+#define  word_val(n) ((pd_scratch[2*n]&0xff)+256*(pd_scratch[2*n+1]&0xff))
+
+static int pd_identify( int unit )
+
+{       int    j;
+       char id[PD_ID_LEN+1];
+
+        pi_connect(PI);
+       WR(0,6,0xa0);
+        pd_wait_for(unit,0,DBMSG("before IDENT"));  
+        pd_send_command(unit,1,0,0,0,0,IDE_IDENTIFY);
+
+        if (pd_wait_for(unit,STAT_DRQ,DBMSG("IDENT DRQ")) & STAT_ERR) {
+                pi_disconnect(PI);
+                return 0;
+        }
+        pi_read_block(PI,pd_scratch,512);
+        pi_disconnect(PI);
+        PD.sectors = word_val(6);
+        PD.heads = word_val(3);
+        PD.cylinders  = word_val(1);
+        PD.capacity = PD.sectors*PD.heads*PD.cylinders;
+
+        for(j=0;j<PD_ID_LEN;j++) id[j^1] = pd_scratch[j+PD_ID_OFF];
+        j = PD_ID_LEN-1;
+        while ((j >= 0) && (id[j] <= 0x20)) j--;
+        j++; id[j] = 0;
+
+        PD.removable = (word_val(0) & 0x80);
+        printk("%s: %s, %d blocks [%dM], (%d/%d/%d), %s media\n",
+                    PD.name,id,PD.capacity,PD.capacity/2048,
+                    PD.cylinders,PD.heads,PD.sectors,
+                    PD.removable?"removable":"fixed");
+
+        if (PD.capacity) pd_init_dev_parms(unit);
+        if (!PD.standby) pd_standby_off(unit);
+
+       pd_hd[unit<<PD_BITS].nr_sects = PD.capacity;
+       pd_hd[unit<<PD_BITS].start_sect = 0;
+       
+        return 1;
+}
+
+static int pd_detect( void )
+
+{       long   flags;
+       int     k, unit;
+
+       k = 0;
+       if (pd_drive_count == 0) {  /* nothing spec'd - so autoprobe for 1 */
+           unit = 0;
+           if (pi_init(PI,1,-1,-1,-1,-1,-1,pd_scratch,
+                    PI_PD,verbose,PD.name)) {
+               save_flags(flags);
+               sti();
+               if (pd_identify(unit)) {
+                       PD.present = 1;
+                       k = 1;
+               } else pi_release(PI);
+               restore_flags(flags);
+           }
+
+       } else for (unit=0;unit<PD_UNITS;unit++) if (DU[D_PRT])
+           if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
+                       DU[D_PRO],DU[D_DLY],pd_scratch,
+                       PI_PD,verbose,PD.name)) {
+                save_flags(flags);
+                sti();
+                if (pd_identify(unit)) {
+                        PD.present = 1;
+                        k = unit+1;
+                } else pi_release(PI);
+                restore_flags(flags);
+            }
+
+/* We lie about the number of drives found, as the generic partition
+   scanner assumes that the drives are numbered sequentially from 0.
+   This can result in some bogus error messages if non-sequential
+   drive numbers are used.
+*/
+       
+       if (k) return k; 
+
+        printk("%s: no valid drive found\n",name);
+        return 0;
+}
+
+/* The i/o request engine */
+
+static int pd_ready( void )
+
+{      int unit = pd_unit;
+
+       return (!(RR(1,6) & STAT_BUSY)) ;
+}
+
+static void do_pd_request (void)
+
+{       struct buffer_head * bh;
+       struct request * req;
+       int     unit;
+
+        if (pd_busy) return;
+repeat:
+        if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+        INIT_REQUEST;
+
+        pd_dev = MINOR(CURRENT->rq_dev);
+       pd_unit = unit = DEVICE_NR(CURRENT->rq_dev);
+        pd_block = CURRENT->sector;
+        pd_count = CURRENT->nr_sectors;
+
+       bh = CURRENT->bh;
+       req = CURRENT;
+       if (bh->b_reqnext)
+               printk("%s: OUCH: b_reqnext != NULL\n",PD.name);
+
+        if ((pd_dev >= PD_DEVS) || 
+           ((pd_block+pd_count) > pd_hd[pd_dev].nr_sects)) {
+                end_request(0);
+                goto repeat;
+        }
+
+       pd_cmd = CURRENT->cmd;
+       pd_run = pd_count;
+        while ((pd_run <= cluster) &&
+              (req = req->next) && 
+              (pd_block+pd_run == req->sector) &&
+              (pd_cmd == req->cmd) &&
+              (pd_dev == MINOR(req->rq_dev)))
+                       pd_run += req->nr_sectors;
+
+       pd_poffs = pd_hd[pd_dev].start_sect;
+        pd_block += pd_poffs;
+        pd_buf = CURRENT->buffer;
+        pd_retries = 0;
+
+        if (pd_cmd == READ) pi_do_claimed(PI,do_pd_read);
+        else if (pd_cmd == WRITE) pi_do_claimed(PI,do_pd_write);
+        else {  end_request(0);
+                goto repeat;
+        }
+}
+
+static void pd_next_buf( int unit )
+
+{      cli();
+       end_request(1);
+       if (!pd_run) { sti(); return; }
+       
+/* paranoia */
+
+       if ((!CURRENT) ||
+           (CURRENT->cmd != pd_cmd) ||
+           (MINOR(CURRENT->rq_dev) != pd_dev) ||
+           (CURRENT->rq_status == RQ_INACTIVE) ||
+           (CURRENT->sector+pd_poffs != pd_block)) 
+               printk("%s: OUCH: request list changed unexpectedly\n",
+                       PD.name);
+
+       pd_count = CURRENT->nr_sectors;
+       pd_buf = CURRENT->buffer;
+       sti();
+}
+
+static void do_pd_read( void )
+
+{       int    unit = pd_unit;
+
+       pd_busy = 1;
+
+        sti();
+
+        pi_connect(PI);
+        if (pd_wait_for(unit,STAT_READY,"do_pd_read") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pd_retries < PD_MAX_RETRIES) {
+                        pd_retries++;
+                        pi_do_claimed(PI,do_pd_read);
+                       return;
+                }
+                end_request(0);
+                pd_busy = 0;
+                cli();
+                do_pd_request();
+                return;
+        }
+        pd_ide_command(unit,IDE_READ,pd_block,pd_run);
+        ps_set_intr(do_pd_read_drq,pd_ready,PD_TMO,nice);
+}
+
+static void do_pd_read_drq( void )
+
+{       int    unit = pd_unit;
+
+       sti();
+
+       while (1) {
+            if (pd_wait_for(unit,STAT_DRQ,"do_pd_read_drq") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pd_retries < PD_MAX_RETRIES) {
+                        pd_retries++;
+                        pi_do_claimed(PI,do_pd_read);
+                        return;
+                }
+                end_request(0);
+                pd_busy = 0;
+                cli();
+                do_pd_request();
+                return;
+            }
+            pi_read_block(PI,pd_buf,512);
+            pd_count--; pd_run--;
+            pd_buf += 512;
+           pd_block++;
+           if (!pd_run) break;
+           if (!pd_count) pd_next_buf(unit);
+        }
+        pi_disconnect(PI);
+        end_request(1);
+        pd_busy = 0;
+        cli();
+        do_pd_request();
+}
+
+static void do_pd_write( void )
+
+{       int    unit = pd_unit;
+
+       pd_busy = 1;
+
+        sti();
+
+        pi_connect(PI);
+        if (pd_wait_for(unit,STAT_READY,"do_pd_write") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pd_retries < PD_MAX_RETRIES) {
+                        pd_retries++;
+                       pi_do_claimed(PI,do_pd_write);
+                        return;
+                }
+                end_request(0);
+                pd_busy = 0;
+                cli();
+                do_pd_request();
+                return;
+        }
+        pd_ide_command(unit,IDE_WRITE,pd_block,pd_run);
+       while (1) {
+            if (pd_wait_for(unit,STAT_DRQ,"do_pd_write_drq") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pd_retries < PD_MAX_RETRIES) {
+                        pd_retries++;
+                        pi_do_claimed(PI,do_pd_write);
+                        return;
+                }
+                end_request(0);
+                pd_busy = 0;
+                cli();
+                do_pd_request();
+                return;
+            }
+            pi_write_block(PI,pd_buf,512);
+           pd_count--; pd_run--;
+           pd_buf += 512;
+           pd_block++;
+           if (!pd_run) break;
+           if (!pd_count) pd_next_buf(unit);
+       }
+        ps_set_intr(do_pd_write_done,pd_ready,PD_TMO,nice);
+}
+
+static void do_pd_write_done( void )
+
+{       int    unit = pd_unit;
+
+       sti();
+        if (pd_wait_for(unit,STAT_READY,"do_pd_write_done") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pd_retries < PD_MAX_RETRIES) {
+                        pd_retries++;
+                        pi_do_claimed(PI,do_pd_write);
+                        return;
+                }
+                end_request(0);
+                pd_busy = 0;
+                cli();
+                do_pd_request();
+                return;
+        }
+        pi_disconnect(PI);
+        end_request(1);
+        pd_busy = 0;
+        cli();
+        do_pd_request();
+}
+
+/* end of pd.c */
+
diff --git a/drivers/block/paride/pf.c b/drivers/block/paride/pf.c
new file mode 100644 (file)
index 0000000..00d629d
--- /dev/null
@@ -0,0 +1,1072 @@
+/* 
+        pf.c    (c) 1997  Grant R. Guenther <grant@torque.net>
+                          Under the terms of the GNU public license.
+
+        This is the high-level driver for parallel port ATAPI disk
+        drives based on chips supported by the paride module.
+
+        By default, the driver will autoprobe for a single parallel
+        port ATAPI disk drive, but if their individual parameters are
+        specified, the driver can handle up to 4 drives.
+
+        The behaviour of the pf driver can be altered by setting
+        some parameters from the insmod command line.  The following
+        parameters are adjustable:
+
+            drive0      These four arguments can be arrays of       
+            drive1      1-7 integers as follows:
+            drive2
+            drive3      <prt>,<pro>,<uni>,<mod>,<slv>,<lun>,<dly>
+
+                        Where,
+
+                <prt>   is the base of the parallel port address for
+                        the corresponding drive.  (required)
+
+                <pro>   is the protocol number for the adapter that
+                        supports this drive.  These numbers are
+                        logged by 'paride' when the protocol modules
+                        are initialised.  (0 if not given)
+
+                <uni>   for those adapters that support chained
+                        devices, this is the unit selector for the
+                        chain of devices on the given port.  It should
+                        be zero for devices that don't support chaining.
+                        (0 if not given)
+
+                <mod>   this can be -1 to choose the best mode, or one
+                        of the mode numbers supported by the adapter.
+                        (-1 if not given)
+
+                <slv>   ATAPI CDroms can be jumpered to master or slave.
+                        Set this to 0 to choose the master drive, 1 to
+                        choose the slave, -1 (the default) to choose the
+                        first drive found.
+
+               <lun>   Some ATAPI devices support multiple LUNs.
+                        One example is the ATAPI PD/CD drive from
+                        Matshita/Panasonic.  This device has a 
+                        CD drive on LUN 0 and a PD drive on LUN 1.
+                        By default, the driver will search for the
+                        first LUN with a supported device.  Set 
+                        this parameter to force it to use a specific
+                        LUN.  (default -1)
+
+                <dly>   some parallel ports require the driver to 
+                        go more slowly.  -1 sets a default value that
+                        should work with the chosen protocol.  Otherwise,
+                        set this to a small integer, the larger it is
+                        the slower the port i/o.  In some cases, setting
+                        this to zero will speed up the device. (default -1)
+
+           major       You may use this parameter to overide the
+                       default major number (47) that this driver
+                       will use.  Be sure to change the device
+                       name as well.
+
+           name        This parameter is a character string that
+                       contains the name the kernel will use for this
+                       device (in /proc output, for instance).
+                       (default "pf").
+
+            cluster     The driver will attempt to aggregate requests
+                        for adjacent blocks into larger multi-block
+                        clusters.  The maximum cluster size (in 512
+                        byte sectors) is set with this parameter.
+                        (default 64)
+
+            verbose     This parameter controls the amount of logging
+                        that is done while the driver probes for
+                        devices.  Set it to 0 for a quiet load, or 1 to
+                        see all the progress messages.  (default 0)
+
+           nice        This parameter controls the driver's use of
+                       idle CPU time, at the expense of some speed.
+
+        If this driver is built into the kernel, you can use kernel
+        the following command line parameters, with the same values
+        as the corresponding module parameters listed above:
+
+            pf.drive0
+            pf.drive1
+            pf.drive2
+            pf.drive3
+           pf.cluster
+            pf.nice
+
+        In addition, you can use the parameter pf.disable to disable
+        the driver entirely.
+
+*/
+
+#define PF_VERSION      "1.0"
+#define PF_MAJOR       47
+#define PF_NAME                "pf"
+#define PF_UNITS       4
+
+/* Here are things one can override from the insmod command.
+   Most are autoprobed by paride unless set here.  Verbose is on
+   by default.
+
+*/
+
+static int     verbose = 0;
+static int     major = PF_MAJOR;
+static char    *name = PF_NAME;
+static int      cluster = 64;
+static int      nice = 0;
+static int      disable = 0;
+
+static int drive0[7] = {0,0,0,-1,-1,-1,-1};
+static int drive1[7] = {0,0,0,-1,-1,-1,-1};
+static int drive2[7] = {0,0,0,-1,-1,-1,-1};
+static int drive3[7] = {0,0,0,-1,-1,-1,-1};
+
+static int (*drives[4])[7] = {&drive0,&drive1,&drive2,&drive3};
+static int pf_drive_count;
+
+#define D_PRT   0
+#define D_PRO   1
+#define D_UNI   2
+#define D_MOD   3
+#define D_SLV   4
+#define D_LUN   5
+#define D_DLY   6
+
+#define DU              (*drives[unit])
+
+/* end of parameters */
+
+
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/delay.h>
+#include <linux/genhd.h>
+#include <linux/hdreg.h>
+#include <linux/cdrom.h>
+
+#include <asm/uaccess.h>
+
+#ifndef MODULE
+
+#include "setup.h"
+
+static STT pf_stt[7] = {{"drive0",7,drive0},
+                        {"drive1",7,drive1},
+                        {"drive2",7,drive2},
+                        {"drive3",7,drive3},
+                       {"disable",1,&disable},
+                        {"cluster",1,&cluster},
+                        {"nice",1,&nice}};
+
+void pf_setup( char *str, int *ints)
+
+{       generic_setup(pf_stt,7,str);
+}
+
+#endif
+
+MODULE_PARM(verbose,"i");
+MODULE_PARM(major,"i");
+MODULE_PARM(name,"s");
+MODULE_PARM(cluster,"i");
+MODULE_PARM(nice,"i");
+MODULE_PARM(drive0,"1-7i");
+MODULE_PARM(drive1,"1-7i");
+MODULE_PARM(drive2,"1-7i");
+MODULE_PARM(drive3,"1-7i");
+
+#include "paride.h"
+
+/* set up defines for blk.h,  why don't all drivers do it this way ? */
+
+#define MAJOR_NR   major
+#define DEVICE_NAME "PF"
+#define DEVICE_REQUEST do_pf_request
+#define DEVICE_NR(device) MINOR(device)
+#define DEVICE_ON(device)
+#define DEVICE_OFF(device)
+
+#include <linux/blk.h>
+
+#include "pseudo.h"
+
+/* constants for faking geometry numbers */
+
+#define PF_FD_MAX      8192            /* use FD geometry under this size */
+#define PF_FD_HDS      2
+#define PF_FD_SPT      18
+#define PF_HD_HDS      64
+#define PF_HD_SPT      32
+
+#define PF_MAX_RETRIES  5
+#define PF_TMO          800             /* interrupt timeout in jiffies */
+#define PF_SPIN_DEL     50              /* spin delay in micro-seconds  */
+
+#define PF_SPIN         (10000/PF_SPIN_DEL)*PF_TMO  
+
+#define STAT_ERR        0x00001
+#define STAT_INDEX      0x00002
+#define STAT_ECC        0x00004
+#define STAT_DRQ        0x00008
+#define STAT_SEEK       0x00010
+#define STAT_WRERR      0x00020
+#define STAT_READY      0x00040
+#define STAT_BUSY       0x00080
+
+#define ATAPI_REQ_SENSE                0x03
+#define ATAPI_LOCK             0x1e
+#define ATAPI_DOOR             0x1b
+#define ATAPI_MODE_SENSE       0x5a
+#define ATAPI_CAPACITY         0x25
+#define ATAPI_IDENTIFY         0x12
+#define ATAPI_READ_10          0x28
+#define ATAPI_WRITE_10         0x2a
+
+int pf_init(void);
+#ifdef MODULE
+void cleanup_module( void );
+#endif
+static int pf_open(struct inode *inode, struct file *file);
+static void do_pf_request(void);
+static int pf_ioctl(struct inode *inode,struct file *file,
+                    unsigned int cmd, unsigned long arg);
+
+static int pf_release (struct inode *inode, struct file *file);
+
+static int pf_detect(void);
+static void do_pf_read(void);
+static void do_pf_write(void);
+static void do_pf_read_drq( void );
+static void do_pf_write_done( void );
+
+static int pf_identify (int unit);
+static void pf_lock(int unit, int func);
+static void pf_eject(int unit);
+static int pf_check_media(kdev_t dev);
+
+static int pf_blocksizes[PF_UNITS];
+
+#define PF_NM           0
+#define PF_RO           1
+#define PF_RW           2
+
+#define PF_NAMELEN      8
+
+struct pf_unit {
+       struct pi_adapter pia;    /* interface to paride layer */
+       struct pi_adapter *pi;
+       int removable;            /* removable media device  ?  */
+       int media_status;         /* media present ?  WP ? */
+       int drive;                /* drive */
+       int lun;
+       int access;               /* count of active opens ... */
+       int capacity;             /* Size of this volume in sectors */
+       int present;              /* device present ? */
+       char name[PF_NAMELEN];    /* pf0, pf1, ... */
+       };
+
+struct pf_unit pf[PF_UNITS];
+
+/*  'unit' must be defined in all functions - either as a local or a param */
+
+#define PF pf[unit]
+#define PI PF.pi
+
+static char pf_scratch[512];            /* scratch block buffer */
+
+/* the variables below are used mainly in the I/O request engine, which
+   processes only one request at a time.
+*/
+
+static int pf_retries = 0;              /* i/o error retry count */
+static int pf_busy = 0;                 /* request being processed ? */
+static int pf_block;                    /* address of next requested block */
+static int pf_count;                    /* number of blocks still to do */
+static int pf_run;                     /* sectors in current cluster */
+static int pf_cmd;                     /* current command READ/WRITE */
+static int pf_unit;                    /* unit of current request */
+static int pf_mask;                    /* stopper for pseudo-int */
+static char * pf_buf;                   /* buffer for request in progress */
+
+/* kernel glue structures */
+
+static struct file_operations pf_fops = {
+        NULL,                   /* lseek - default */
+        block_read,             /* read - general block-dev read */
+        block_write,            /* write - general block-dev write */
+        NULL,                   /* readdir - bad */
+        NULL,                   /* select */
+        pf_ioctl,               /* ioctl */
+        NULL,                   /* mmap */
+        pf_open,                /* open */
+        pf_release,             /* release */
+        block_fsync,            /* fsync */
+        NULL,                   /* fasync */
+        pf_check_media,         /* media change ? */
+        NULL                    /* revalidate new media */
+};
+
+void pf_init_units( void )
+
+{       int     unit, j;
+
+        pf_drive_count = 0;
+        for (unit=0;unit<PF_UNITS;unit++) {
+                PF.pi = & PF.pia;
+                PF.access = 0;
+                PF.media_status = PF_NM;
+                PF.capacity = 0;
+                PF.present = 0;
+               PF.drive = DU[D_SLV];
+               PF.lun = DU[D_LUN];
+                j = 0;
+                while ((j < PF_NAMELEN-2) && (PF.name[j]=name[j])) j++;
+                PF.name[j++] = '0' + unit;
+                PF.name[j] = 0;
+                if (DU[D_PRT]) pf_drive_count++;
+        }
+} 
+
+int pf_init (void)      /* preliminary initialisation */
+
+{       int i;
+
+       if (disable) return -1;
+
+       pf_init_units();
+
+       if (pf_detect()) return -1;
+       pf_busy = 0;
+
+        if (register_blkdev(MAJOR_NR,name,&pf_fops)) {
+                printk("pf_init: unable to get major number %d\n",
+                        major);
+                return -1;
+        }
+        blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+        read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
+        
+       for (i=0;i<PF_UNITS;i++) pf_blocksizes[i] = 1024;
+       blksize_size[MAJOR_NR] = pf_blocksizes;
+
+        return 0;
+}
+
+static int pf_open (struct inode *inode, struct file *file)
+
+{       int    unit = DEVICE_NR(inode->i_rdev);
+
+        if ((unit >= PF_UNITS) || (!PF.present)) return -ENODEV;
+
+        MOD_INC_USE_COUNT;
+
+       pf_identify(unit);
+
+       if (PF.media_status == PF_NM) {
+               MOD_DEC_USE_COUNT;
+               return -ENODEV;
+               }
+
+       if ((PF.media_status == PF_RO) && (file ->f_mode & 2)) {
+               MOD_DEC_USE_COUNT;
+               return -EROFS;
+               }
+
+        PF.access++;
+        if (PF.removable) pf_lock(unit,1);
+
+        return 0;
+}
+
+static int pf_ioctl(struct inode *inode,struct file *file,
+                    unsigned int cmd, unsigned long arg)
+
+{       int err, unit;
+       struct hd_geometry *geo = (struct hd_geometry *) arg;
+
+        if ((!inode) || (!inode->i_rdev)) return -EINVAL;
+        unit = DEVICE_NR(inode->i_rdev);
+        if (unit >= PF_UNITS) return -EINVAL;
+        if (!PF.present) return -ENODEV;
+
+        switch (cmd) {
+           case CDROMEJECT: 
+               if (PF.access == 1) {
+                       pf_eject(unit);
+                       return 0;
+                       }
+           case HDIO_GETGEO:
+                if (!geo) return -EINVAL;
+                err = verify_area(VERIFY_WRITE,geo,sizeof(*geo));
+                if (err) return err;
+                if (PF.capacity < PF_FD_MAX) {
+                    put_user(PF.capacity/(PF_FD_HDS*PF_FD_SPT),
+                                (short *) &geo->cylinders);
+                    put_user(PF_FD_HDS, (char *) &geo->heads);
+                    put_user(PF_FD_SPT, (char *) &geo->sectors);
+                } else {
+                    put_user(PF.capacity/(PF_HD_HDS*PF_HD_SPT), 
+                               (short *) &geo->cylinders);
+                    put_user(PF_HD_HDS, (char *) &geo->heads);
+                    put_user(PF_HD_SPT, (char *) &geo->sectors);
+                }
+                put_user(0,(long *)&geo->start);
+                return 0;
+            case BLKRASET:
+                if(!suser()) return -EACCES;
+                if(!(inode->i_rdev)) return -EINVAL;
+                if(arg > 0xff) return -EINVAL;
+                read_ahead[MAJOR(inode->i_rdev)] = arg;
+                return 0;
+            case BLKRAGET:
+                if (!arg) return -EINVAL;
+                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
+                if (err) return (err);
+                put_user(read_ahead[MAJOR(inode->i_rdev)],(long *) arg);
+                return (0);
+            case BLKGETSIZE:
+                if (!arg) return -EINVAL;
+                err = verify_area(VERIFY_WRITE,(long *) arg,sizeof(long));
+                if (err) return (err);
+                put_user(PF.capacity,(long *) arg);
+                return (0);
+            case BLKFLSBUF:
+                if(!suser())  return -EACCES;
+                if(!(inode->i_rdev)) return -EINVAL;
+                fsync_dev(inode->i_rdev);
+                invalidate_buffers(inode->i_rdev);
+                return 0;
+            RO_IOCTLS(inode->i_rdev,arg);
+            default:
+                return -EINVAL;
+        }
+}
+
+
+static int pf_release (struct inode *inode, struct file *file)
+
+{       kdev_t devp;
+       int     unit;
+
+       struct super_block *sb;
+
+        devp = inode->i_rdev;
+        unit = DEVICE_NR(devp);
+
+        if ((unit >= PF_UNITS) || (PF.access <= 0)) 
+                return -EINVAL;
+
+       PF.access--;
+
+       if (!PF.access) {
+                fsync_dev(devp);
+
+               sb = get_super(devp);
+               if (sb) invalidate_inodes(sb);
+
+                invalidate_buffers(devp);
+               if (PF.removable) pf_lock(unit,0);
+        }
+
+        MOD_DEC_USE_COUNT;
+
+       return 0;
+
+}
+
+static int pf_check_media( kdev_t dev)
+
+{       return 1;
+}
+
+#ifdef MODULE
+
+/* Glue for modules ... */
+
+void    cleanup_module(void);
+
+int     init_module(void)
+
+{       int     err;
+        long    flags;
+
+        save_flags(flags);
+        cli();
+
+        err = pf_init();
+
+        restore_flags(flags);
+        return err;
+}
+
+void    cleanup_module(void)
+
+{       long flags;
+       int unit;
+
+        save_flags(flags);
+        cli();
+
+        unregister_blkdev(MAJOR_NR,name);
+
+       for (unit=0;unit<PF_UNITS;unit++)
+         if (PF.present) pi_release(PI);
+       
+        restore_flags(flags);
+}
+
+#endif
+
+#define        WR(c,r,v)       pi_write_regr(PI,c,r,v)
+#define        RR(c,r)         (pi_read_regr(PI,c,r))
+
+#define LUN             (0x20*PF.lun)
+#define DRIVE           (0xa0+0x10*PF.drive)
+
+static int pf_wait( int unit, int go, int stop, char * fun, char * msg )
+
+{       int j, r, e, s, p;
+
+        j = 0;
+        while ((((r=RR(1,6))&go)||(stop&&(!(r&stop))))&&(j++<PF_SPIN))
+                udelay(PF_SPIN_DEL);
+
+        if ((r&(STAT_ERR&stop))||(j>=PF_SPIN)) {
+           s = RR(0,7);
+           e = RR(0,1);
+           p = RR(0,2);
+           if (j >= PF_SPIN) e |= 0x100;
+           if (fun) printk("%s: %s %s: alt=0x%x stat=0x%x err=0x%x"
+                           " loop=%d phase=%d\n",
+                            PF.name,fun,msg,r,s,e,j,p);
+           return (e<<8)+s;
+        }
+        return 0;
+}
+
+static int pf_command( int unit, char * cmd, int dlen, char * fun )
+
+{       pi_connect(PI);
+
+        WR(0,6,DRIVE);
+
+        if (pf_wait(unit,STAT_BUSY|STAT_DRQ,0,fun,"before command")) {
+                pi_disconnect(PI);
+                return -1;
+        }
+
+        WR(0,4,dlen % 256);
+        WR(0,5,dlen / 256);
+        WR(0,7,0xa0);          /* ATAPI packet command */
+
+        if (pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,fun,"command DRQ")) {
+                pi_disconnect(PI);
+                return -1;
+        }
+
+        if (RR(0,2) != 1) {
+           printk("%s: %s: command phase error\n",PF.name,fun);
+           pi_disconnect(PI);
+           return -1;
+        }
+
+        pi_write_block(PI,cmd,12);
+
+        return 0;
+}
+
+static int pf_completion( int unit, char * buf, char * fun )
+
+{       int r, s, n;
+
+        r = pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_READY|STAT_ERR,
+                       fun,"completion");
+
+        if ((RR(0,2)&2) && (RR(0,7)&STAT_DRQ)) { 
+                n = (RR(0,4)+256*RR(0,5));
+                pi_read_block(PI,buf,n);
+        }
+
+        s = pf_wait(unit,STAT_BUSY,STAT_READY|STAT_ERR,fun,"data done");
+
+        pi_disconnect(PI); 
+
+        return (r?r:s);
+}
+
+static void pf_req_sense( int unit, int quiet )
+
+{       char    rs_cmd[12] = { ATAPI_REQ_SENSE,LUN,0,0,16,0,0,0,0,0,0,0 };
+        char    buf[16];
+        int     r;
+
+        r = pf_command(unit,rs_cmd,16,"Request sense");
+        udelay(1000);
+        if (!r) pf_completion(unit,buf,"Request sense");
+
+        if ((!r)&&(!quiet)) 
+                printk("%s: Sense key: %x, ASC: %x, ASQ: %x\n",
+                       PF.name,buf[2]&0xf,buf[12],buf[13]);
+}
+
+static int pf_atapi( int unit, char * cmd, int dlen, char * buf, char * fun )
+
+{       int r;
+
+        r = pf_command(unit,cmd,dlen,fun);
+        udelay(1000);
+        if (!r) r = pf_completion(unit,buf,fun);
+        if (r) pf_req_sense(unit,!fun);
+        
+        return r;
+}
+
+#define DBMSG(msg)      NULL
+
+static void pf_lock(int unit, int func)
+
+{      char    lo_cmd[12] = { ATAPI_LOCK,LUN,0,0,func,0,0,0,0,0,0,0 };
+
+        pf_atapi(unit,lo_cmd,0,pf_scratch,func?"unlock":"lock");
+}
+
+
+static void pf_eject( int unit )
+
+{      char    ej_cmd[12] = { ATAPI_DOOR,LUN,0,0,2,0,0,0,0,0,0,0 };
+
+       pf_lock(unit,0);
+       pf_atapi(unit,ej_cmd,0,pf_scratch,"eject");
+}
+
+#define PF_RESET_TMO   30              /* in tenths of a second */
+
+static void pf_sleep( int cs )
+
+{       current->state = TASK_INTERRUPTIBLE;
+        current->timeout = jiffies + cs;
+        schedule();
+}
+
+
+static int pf_reset( int unit )
+
+/* the ATAPI standard actually specifies the contents of all 7 registers
+   after a reset, but the specification is ambiguous concerning the last
+   two bytes, and different drives interpret the standard differently.
+*/
+
+{      int     i, k, flg;
+       int     expect[5] = {1,1,1,0x14,0xeb};
+       long    flags;
+
+       pi_connect(PI);
+       WR(0,6,DRIVE);
+       WR(0,7,8);
+
+       save_flags(flags);
+       sti();
+
+       pf_sleep(2);
+
+        k = 0;
+        while ((k++ < PF_RESET_TMO) && (RR(1,6)&STAT_BUSY))
+                pf_sleep(10);
+
+       restore_flags(flags);
+
+       flg = 1;
+       for(i=0;i<5;i++) flg &= (RR(0,i+1) == expect[i]);
+
+       if (verbose) {
+               printk("%s: Reset (%d) signature = ",PF.name,k);
+               for (i=0;i<5;i++) printk("%3x",RR(0,i+1));
+               if (!flg) printk(" (incorrect)");
+               printk("\n");
+       }
+       
+       pi_disconnect(PI);
+       return flg-1;   
+}
+
+static void pf_mode_sense( int unit )
+
+{       char    ms_cmd[12] = { ATAPI_MODE_SENSE,LUN,0,0,0,0,0,0,8,0,0,0};
+       char    buf[8];
+
+        pf_atapi(unit,ms_cmd,8,buf,DBMSG("mode sense"));
+       PF.media_status = PF_RW;
+       if (buf[3] & 0x80) PF.media_status = PF_RO;
+}
+
+static void xs( char *buf, char *targ, int offs, int len )
+
+{      int     j,k,l;
+
+       j=0; l=0;
+       for (k=0;k<len;k++) 
+          if((buf[k+offs]!=0x20)||(buf[k+offs]!=l))
+               l=targ[j++]=buf[k+offs];
+       if (l==0x20) j--; targ[j]=0;
+}
+
+static int xl( char *buf, int offs )
+
+{      int     v,k;
+
+       v=0; 
+       for(k=0;k<4;k++) v=v*256+(buf[k+offs]&0xff);
+       return v;
+}
+
+static void pf_get_capacity( int unit )
+
+{      char    rc_cmd[12] = { ATAPI_CAPACITY,LUN,0,0,0,0,0,0,0,0,0,0};
+       char    buf[8];
+        int    bs;
+
+       if (pf_atapi(unit,rc_cmd,8,buf,DBMSG("get capacity"))) {
+               PF.media_status = PF_NM;
+               return;
+       }
+       PF.capacity = xl(buf,0) + 1;  
+       bs = xl(buf,4);
+       if (bs != 512) {
+               PF.capacity = 0;
+               if (verbose) printk("%s: Drive %d, LUN %d,"
+                                   " unsupported block size %d\n",
+                                   PF.name,PF.drive,PF.lun,bs);
+               }
+}
+
+static int pf_identify( int unit )
+
+{      int     dt, s;
+       char    *ms[2] = {"master","slave"};
+       char    mf[10], id[18];
+       char    id_cmd[12] = { ATAPI_IDENTIFY,LUN,0,0,36,0,0,0,0,0,0,0};
+       char    buf[36];
+
+        s = pf_atapi(unit,id_cmd,36,buf,"identify");
+       if (s) return -1;
+
+       dt = buf[0] & 0x1f;
+       if ((dt != 0) && (dt != 7)) {
+               if (verbose) 
+                  printk("%s: Drive %d, LUN %d, unsupported type %d\n",
+                               PF.name,PF.drive,PF.lun,dt);
+               return -1;
+               }
+
+       xs(buf,mf,8,8);
+       xs(buf,id,16,16);
+
+       PF.removable = (buf[1] & 0x80);
+
+       pf_mode_sense(unit);
+       pf_mode_sense(unit);
+       pf_mode_sense(unit);
+
+       pf_get_capacity(unit);
+
+        printk("%s: %s %s, %s LUN %d, type %d",
+               PF.name,mf,id,ms[PF.drive],PF.lun,dt);
+        if (PF.removable) printk(", removable");
+        if (PF.media_status == PF_NM) 
+                printk(", no media\n");
+        else {  if (PF.media_status == PF_RO) printk(", RO");
+                printk(", %d blocks\n",PF.capacity);
+        }
+
+       return 0;
+}
+
+static int pf_probe( int unit )
+
+/*     returns  0, with id set if drive is detected
+               -1, if drive detection failed
+*/
+
+{      if (PF.drive == -1) {
+          for (PF.drive=0;PF.drive<=1;PF.drive++)
+               if (!pf_reset(unit)) {
+                  if (PF.lun != -1) return pf_identify(unit);
+                  else for (PF.lun=0;PF.lun<8;PF.lun++) 
+                           if (!pf_identify(unit)) return 0;
+               }
+       } else {
+          if (pf_reset(unit)) return -1;
+          if (PF.lun != -1) return pf_identify(unit);
+          for (PF.lun=0;PF.lun<8;PF.lun++) 
+             if (!pf_identify(unit)) return 0;
+       }
+        return -1; 
+}
+
+static int pf_detect( void )
+
+{      int     k, unit;
+
+       printk("%s: %s version %s, major %d, cluster %d, nice %d\n",
+               name,name,PF_VERSION,major,cluster,nice);
+
+       k = 0;
+       if (pf_drive_count == 0) {
+           unit = 0;
+           if (pi_init(PI,1,-1,-1,-1,-1,-1,pf_scratch,
+                        PI_PF,verbose,PF.name)) {
+               if (!pf_probe(unit)) {
+                       PF.present = 1;
+                       k++;
+               } else pi_release(PI);
+           }
+
+       } else for (unit=0;unit<PF_UNITS;unit++) if (DU[D_PRT])
+           if (pi_init(PI,0,DU[D_PRT],DU[D_MOD],DU[D_UNI],
+                       DU[D_PRO],DU[D_DLY],pf_scratch,PI_PF,verbose,
+                       PF.name)) { 
+                if (!pf_probe(unit)) {
+                        PF.present = 1;
+                        k++;
+                } else pi_release(PI);
+            }
+
+       if (k) return 0;
+
+       printk("%s: No ATAPI disk detected\n",name);
+       return -1;
+}
+
+/* The i/o request engine */
+
+static int pf_start( int unit, int cmd, int b, int c )
+
+{      int     i;
+       char    io_cmd[12] = {cmd,LUN,0,0,0,0,0,0,0,0,0,0};
+
+       for(i=0;i<4;i++) { 
+          io_cmd[5-i] = b & 0xff;
+          b = b >> 8;
+       }
+       
+       io_cmd[8] = c & 0xff;
+       io_cmd[7] = (c >> 8) & 0xff;
+
+       i = pf_command(unit,io_cmd,c*512,"start i/o");
+
+        udelay(1000);
+
+       return i;       
+}
+
+static int pf_ready( void )
+
+{      int     unit = pf_unit;
+
+       return (((RR(1,6)&(STAT_BUSY|pf_mask)) == pf_mask));
+}
+
+static void do_pf_request (void)
+
+{       struct buffer_head * bh;
+       struct request * req;
+       int unit;
+
+        if (pf_busy) return;
+repeat:
+        if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
+        INIT_REQUEST;
+
+        pf_unit = unit = DEVICE_NR(CURRENT->rq_dev);
+        pf_block = CURRENT->sector;
+        pf_count = CURRENT->nr_sectors;
+
+       bh = CURRENT->bh;
+       req = CURRENT;
+       if (bh->b_reqnext)
+               printk("%s: OUCH: b_reqnext != NULL\n",PF.name);
+
+        if ((pf_unit >= PF_UNITS) || (pf_block+pf_count > PF.capacity)) {
+                end_request(0);
+                goto repeat;
+        }
+
+       pf_cmd = CURRENT->cmd;
+       pf_run = pf_count;
+        while ((pf_run <= cluster) &&
+              (req = req->next) && 
+              (pf_block+pf_run == req->sector) &&
+              (pf_cmd == req->cmd) &&
+              (pf_unit == DEVICE_NR(req->rq_dev)))
+                       pf_run += req->nr_sectors;
+
+        pf_buf = CURRENT->buffer;
+        pf_retries = 0;
+
+
+        if (pf_cmd == READ) pi_do_claimed(PI,do_pf_read);
+        else if (pf_cmd == WRITE) pi_do_claimed(PI,do_pf_write);
+        else {  end_request(0);
+                goto repeat;
+        }
+}
+
+static void pf_next_buf( int unit )
+
+{      cli();
+       end_request(1);
+       if (!pf_run) { sti(); return; }
+       
+/* paranoia */
+
+       if ((!CURRENT) ||
+           (CURRENT->cmd != pf_cmd) ||
+           (DEVICE_NR(CURRENT->rq_dev) != pf_unit) ||
+           (CURRENT->rq_status == RQ_INACTIVE) ||
+           (CURRENT->sector != pf_block)) 
+               printk("%s: OUCH: request list changed unexpectedly\n",
+                       PF.name);
+
+       pf_count = CURRENT->nr_sectors;
+       pf_buf = CURRENT->buffer;
+       sti();
+}
+
+static void do_pf_read( void )
+
+{       int    unit = pf_unit;
+
+       pf_busy = 1;
+
+        sti();
+
+       if (pf_start(unit,ATAPI_READ_10,pf_block,pf_run)) {
+                pi_disconnect(PI);
+                if (pf_retries < PF_MAX_RETRIES) {
+                        pf_retries++;
+                        pi_do_claimed(PI,do_pf_read);
+                       return;
+                }
+                end_request(0);
+                pf_busy = 0;
+                cli();
+                do_pf_request();
+                return;
+        }
+       pf_mask=STAT_DRQ;
+        ps_set_intr(do_pf_read_drq,pf_ready,PF_TMO,nice);
+}
+
+static void do_pf_read_drq( void )
+
+{       int    unit = pf_unit;
+
+       sti();
+       while (1) {
+            if (pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,
+                       "read block","completion") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pf_retries < PF_MAX_RETRIES) {
+                       pf_req_sense(unit,0);
+                        pf_retries++;
+                        pi_do_claimed(PI,do_pf_read);
+                        return;
+                }
+                end_request(0);
+                pf_busy = 0;
+                cli();
+                do_pf_request();
+                return;
+            }
+            pi_read_block(PI,pf_buf,512);
+            pf_count--; pf_run--;
+            pf_buf += 512;
+           pf_block++;
+           if (!pf_run) break;
+           if (!pf_count) pf_next_buf(unit);
+        }
+        pi_disconnect(PI);
+        end_request(1);
+        pf_busy = 0;
+        cli();
+        do_pf_request();
+}
+
+static void do_pf_write( void )
+
+{       int    unit = pf_unit;
+
+       pf_busy = 1;
+
+        sti();
+
+       if (pf_start(unit,ATAPI_WRITE_10,pf_block,pf_run)) {
+                pi_disconnect(PI);
+                if (pf_retries < PF_MAX_RETRIES) {
+                        pf_retries++;
+                        pi_do_claimed(PI,do_pf_write);
+                       return;
+                }
+                end_request(0);
+                pf_busy = 0;
+                cli();
+                do_pf_request();
+                return;
+        }
+
+       while (1) {
+            if (pf_wait(unit,STAT_BUSY,STAT_DRQ|STAT_ERR,
+                       "write block","data wait") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pf_retries < PF_MAX_RETRIES) {
+                        pf_retries++;
+                        pi_do_claimed(PI,do_pf_write);
+                        return;
+                }
+                end_request(0);
+                pf_busy = 0;
+                cli();
+                do_pf_request();
+                return;
+            }
+            pi_write_block(PI,pf_buf,512);
+           pf_count--; pf_run--;
+           pf_buf += 512;
+           pf_block++;
+           if (!pf_run) break;
+           if (!pf_count) pf_next_buf(unit);
+       }
+       pf_mask = 0;
+        ps_set_intr(do_pf_write_done,pf_ready,PF_TMO,nice);
+}
+
+static void do_pf_write_done( void )
+
+{       int    unit = pf_unit;
+
+       sti();
+        if (pf_wait(unit,STAT_BUSY,0,"write block","done") & STAT_ERR) {
+                pi_disconnect(PI);
+                if (pf_retries < PF_MAX_RETRIES) {
+                        pf_retries++;
+                       pi_do_claimed(PI,do_pf_write);
+                        return;
+                }
+                end_request(0);
+                pf_busy = 0;
+                cli();
+                do_pf_request();
+                return;
+        }
+        pi_disconnect(PI);
+        end_request(1);
+        pf_busy = 0;
+        cli();
+        do_pf_request();
+}
+
+/* end of pf.c */
+
diff --git a/drivers/block/paride/pseudo.h b/drivers/block/paride/pseudo.h
new file mode 100644 (file)
index 0000000..44c74c7
--- /dev/null
@@ -0,0 +1,138 @@
+/* 
+        pseudo.h    (c) 1997  Grant R. Guenther <grant@torque.net>
+                              Under the terms of the GNU public license.
+
+       This is the "pseudo-interrupt" logic for parallel port drivers.
+
+        This module is #included into each driver.  It makes one
+        function available:
+
+               ps_set_intr( void (*continuation)(void),
+                            int  (*ready)(void),
+                            int timeout,
+                            int nice )
+
+       Which will arrange for ready() to be evaluated frequently and
+       when either it returns true, or timeout jiffies have passed,
+       continuation() will be invoked.
+
+       If nice is true, the test will done approximately once a
+       jiffy.  If nice is 0, the test will also be done whenever
+       the scheduler runs (by adding it to a task queue).
+
+*/
+
+#include <linux/sched.h>
+#include <linux/timer.h>
+#include <linux/tqueue.h>
+
+static void ps_timer_int( unsigned long data);
+static void ps_tq_int( void *data);
+
+static int ps_use_tq = 1;
+static void (* ps_continuation)(void);
+static int (* ps_ready)(void);
+static int ps_then;
+static int ps_timeout;
+static int ps_timer_active = 0;
+static int ps_tq_active = 0;
+
+static struct timer_list ps_timer = {0,0,0,0,ps_timer_int};
+static struct tq_struct ps_tq = {0,0,ps_tq_int,NULL};
+
+static void ps_set_intr( void (*continuation)(void), 
+                        int (*ready)(void),
+                        int timeout, int nice )
+
+{       long   flags;
+
+       save_flags(flags); 
+       cli();
+
+       ps_continuation = continuation;
+       ps_ready = ready;
+        ps_then = jiffies;
+       ps_timeout = jiffies + timeout;
+       ps_use_tq = !nice;
+
+        if (ps_use_tq && !ps_tq_active) {
+#ifdef HAVE_DISABLE_HLT
+                disable_hlt();
+#endif
+               ps_tq_active = 1;
+                queue_task(&ps_tq,&tq_scheduler);
+       }
+
+        if (!ps_timer_active) {
+               ps_timer_active = 1;
+                ps_timer.expires = jiffies;
+                add_timer(&ps_timer);
+        }
+
+       restore_flags(flags);
+}
+
+static void ps_tq_int( void *data )
+
+{       void (*con)(void);
+       long flags;
+
+       save_flags(flags);
+       cli();
+
+        con = ps_continuation;
+
+#ifdef HAVE_DISABLE_HLT
+        enable_hlt();
+#endif
+
+        ps_tq_active = 0;
+
+        if (!con) {
+               restore_flags(flags);
+               return;
+       }
+        if (ps_ready() || (jiffies >= ps_timeout)) {
+                ps_continuation = NULL;
+               restore_flags(flags);
+                con();
+                return;
+                }
+
+#ifdef HAVE_DISABLE_HLT
+        disable_hlt();
+#endif
+
+        ps_tq_active = 1;
+       queue_task(&ps_tq,&tq_scheduler);
+       restore_flags(flags);
+}
+
+static void ps_timer_int( unsigned long data)
+
+{       void (*con)(void);
+       long    flags;
+
+       save_flags(flags);
+       cli();
+
+       con = ps_continuation;
+       ps_timer_active = 0;
+       if (!con) {
+               restore_flags(flags);
+               return;
+       }
+        if (ps_ready() || (jiffies >= ps_timeout)) {
+                ps_continuation = NULL;
+               restore_flags(flags);
+                con();
+               return;
+               }
+       ps_timer_active = 1;
+        ps_timer.expires = jiffies;
+        add_timer(&ps_timer);
+       restore_flags(flags);
+}
+
+/* end of pseudo.h */
+
diff --git a/drivers/block/paride/setup.h b/drivers/block/paride/setup.h
new file mode 100644 (file)
index 0000000..6d941cc
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+       setup.h    (c) 1997 Grant R. Guenther <grant@torque.net>
+                           Under the terms of the GNU public license.
+
+        This is a table driven setup function for kernel modules
+        using the module.variable=val,... command line notation.
+
+*/
+
+#include <linux/ctype.h>
+#include <linux/string.h>
+
+struct setup_tab_t {
+
+       char    *tag;   /* variable name */
+       int     size;   /* number of elements in array */
+       int     *iv;    /* pointer to variable */
+};
+
+typedef struct setup_tab_t STT;
+
+/*  t    is a table that describes the variables that can be set
+         by gen_setup
+    n    is the number of entries in the table
+    ss   is a string of the form:
+
+               <tag>=[<val>,...]<val>
+*/
+
+static void generic_setup( STT t[], int n, char *ss )
+
+{      int     j,k;
+
+       k = 0;
+       for (j=0;j<n;j++) {
+               k = strlen(t[j].tag);
+               if (strncmp(ss,t[j].tag,k) == 0) break;
+       }
+       if (j == n) return;
+
+       if (ss[k] == 0) {
+               t[j].iv[0] = 1;
+               return;
+       }
+
+       if (ss[k] != '=') return;
+       ss += (k+1);
+
+       k = 0;
+       while (ss && isdigit(*ss) && (k < t[j].size)) {
+               t[j].iv[k++] = simple_strtoul(ss,NULL,0);
+               if ((ss = strchr(ss,',')) != NULL) ss++;
+       }
+}
+
+/* end of setup.h */
index f88f597d822ef417624702952b34252c5796d9cf..5d3d3f37c474f46f76755c3eed29da43e5c6143a 100644 (file)
@@ -220,10 +220,10 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
         && !pcibios_read_config_dword(hwif->pci_bus, hwif->pci_fn, 0x20, &cfgbase) && cfgbase)
        {
                hwif->config_data = cfgbase & ~1;
-               printk("TRM290: chip config base at 0x%04x\n", hwif->config_data);
+               printk("TRM290: chip config base at 0x%04lx\n", hwif->config_data);
        } else {
-               hwif->config_data = 0x3df4;
-               printk("TRM290: using default config base at 0x%04x\n", hwif->config_data);
+               hwif->config_data = 0x3df0;
+               printk("TRM290: using default config base at 0x%04lx\n", hwif->config_data);
        }
 
        save_flags(flags);
@@ -241,7 +241,7 @@ __initfunc(void ide_init_trm290 (ide_hwif_t *hwif))
                hwif->irq = hwif->channel ? 15 : 14;    /* legacy mode */
        else if (!hwif->irq && hwif->mate && hwif->mate->irq)
                hwif->irq = hwif->mate->irq;            /* sharing IRQ with mate */
-       ide_setup_dma(hwif, (hwif->channel ? hwif->config_data ^ 0x0080 : hwif->config_data) + 4, 2);
+       ide_setup_dma(hwif, (hwif->config_data + 4) ^ (hwif->channel ? 0x0080 : 0x0000), 2);
        hwif->dmaproc = &trm290_dmaproc;
        hwif->selectproc = &trm290_selectproc;
        hwif->no_autodma = 1;                           /* play it safe for now */
index f07e65539f48674aa64a1f93760d91588b3b8d76..bc69156a4bc4a7b8c5e5ee7a562a181d06af9be7 100644 (file)
@@ -13,7 +13,6 @@ if [ "$CONFIG_SBPCD" = "y" ]; then
     fi
   fi
 fi
-tristate 'MicroSolutions backpack CDROM support' CONFIG_BPCD
 tristate 'Mitsumi (standard) [no XA/Multisession] CDROM support' CONFIG_MCD
 tristate 'Mitsumi [XA/MultiSession] CDROM support' CONFIG_MCDX
 tristate 'Optics Storage DOLPHIN 8000AT CDROM support' CONFIG_OPTCD
index 0f54a6e2d98433a10c47f4b600ce26634b7db3de..5681e2fe57365c07d98f39f4b9d82dc85e5998b2 100644 (file)
@@ -112,14 +112,6 @@ else
   endif
 endif #CONFIG_SJCD
 
-ifeq ($(CONFIG_BPCD),y)
-L_OBJS += bpcd.o
-else
-  ifeq ($(CONFIG_BPCD),m)
-  M_OBJS += bpcd.o
-  endif
-endif #CONFIG_BPCD
-
 ifeq ($(CONFIG_ISP16_CDI),y)
 L_OBJS += isp16.o
 else
diff --git a/drivers/cdrom/bpcd.c b/drivers/cdrom/bpcd.c
deleted file mode 100644 (file)
index 4ea0f66..0000000
+++ /dev/null
@@ -1,793 +0,0 @@
-/* 
-       bpcd.c  (c) 1996  Grant R. Guenther <grant@torque.net>
-                         Under the terms of the GNU public license.
-
-       bpcd.c is a driver for the MicroSolutions "backpack" CDrom,
-       an external parallel port device.  
-
-       There are apparently two versions of the backpack protocol.  This 
-        driver knows about the version 2 protocol - as is used in the 4x 
-       and 6x products.  There is no support for the sound hardware that
-        is included in some models.  It should not be difficult to add 
-        support for the ATAPI audio play functions and the corresponding 
-        ioctls.
-
-       The driver was developed by reverse engineering the protocol
-        and testing it on the backpack model 164550.  This model
-       is actually a stock ATAPI drive packaged with a custom 
-       ASIC that implements the IDE over parallel protocol.
-       I tested with a backpack that happened to contain a Goldstar
-        drive, but I've seen reports of Sony and Mitsumi drives as well.
-
-       bpcd.c can be compiled for version 1.2.13 of the Linux kernel
-        and for the 2.0 series.  (It should also work with most of the
-        later 1.3 kernels.)
-
-        If you have a copy of the driver that has not been integrated into
-        the kernel source tree, you can compile the driver manually, as a 
-        module.  Ensure that /usr/include/linux and /usr/include/asm are 
-       links to the correct include files for the target system.  Compile 
-        the driver with
-
-                cc -D__KERNEL__ -DMODULE -O2 -c bpcd.c
-
-        You must then load it with insmod.  If you are using
-        MODVERSIONS, add the following to the cc command:
-
-               -DMODVERSIONS -I /usr/include/linux/modversions.h
-
-       Before attempting to access the new driver, you will need to
-        create a new device special file.  The following commands will
-       do that for you:
-
-               mknod /dev/bpcd b 41 0
-               chown root:disk /dev/bpcd
-               chmod 660 /dev/bpcd
-
-       Afterward, you can mount a disk in the usual way:
-
-               mount -t iso9660 /dev/bpcd /cdrom
-
-       (assuming you have made a directory /cdrom to use as a
-        mount point).
-
-       The driver will attempt to detect which parallel port your
-        backpack is connected to.  If this fails for any reason, you
-        can override it by specifying a port on the LILO command line
-        (for built in drivers) or the insmod command (for drivers built
-        as modules).   If your drive is on the port at 0x3bc, you would
-        use one of these commands:
-
-               LILO:      bpcd=0x3bc
-
-               insmod:    insmod bpcd bp_base=0x3bc
-
-       The driver can detect if the parallel port supports 8-bit
-        transfers.  If so, it will use them.  You can force it to use
-        4-bit (nybble) mode by setting the variable bp_nybble to 1 on
-        an insmod command, or using the following LILO parameters:
-
-               bpcd=0x3bc,1
-
-       (you must specify the correct port address if you use this method.)
-
-       There is currently no support for EPP or ECP modes.  Also,
-        as far as I can tell, the MicroSolutions protocol does not
-        support interrupts in the 4-bit and 8-bit modes.
-
-       MicroSolutions' protocol allows for several drives to be
-        chained together off the same parallel port.  Currently, this
-        driver will recognise only one of them.  If you do have more
-        than one drive, it will choose the one with the lowest id number,
-        where the id number is the last two digits of the product's
-        serial number.
-
-       It is not currently possible to connect a printer to the chained
-        port on the BackPack and expect Linux to use both devices at once.
-
-       If you need to use this driver together with a printer on the
-        same port, build both the bpcd and lp drivers are modules.
-
-       Keep an eye on http://www.torque.net/bpcd.html for news and
-        other information about the driver.  If you have any problems
-        with this driver, please send me, grant@torque.net, some mail 
-        directly before posting into the newsgroups or mailing lists.
-
-*/
-
-#define        BP_VERSION      "0.14" 
-
-#define        BP_BASE         0       /* set to 0 for autoprobe */
-#define BP_REP         4
-
-#include <linux/version.h>
-#include <linux/module.h>
-
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/major.h>
-#include <linux/kernel.h>
-#include <linux/tqueue.h>
-#include <linux/delay.h>
-#include <linux/cdrom.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-
-#include <asm/system.h>
-#include <asm/io.h>
-#include <asm/uaccess.h>
-
-#ifndef BPCD_MAJOR
-#define BPCD_MAJOR   41        
-#endif
-
-#define MAJOR_NR BPCD_MAJOR
-
-/* set up defines for blk.h,  why don't all drivers do it this way ? */
-
-#define DEVICE_NAME "BackPack"
-#define DEVICE_REQUEST do_bp_request
-#define DEVICE_NR(device) (MINOR(device))
-#define DEVICE_ON(device)
-#define DEVICE_OFF(device)
-
-#include <linux/blk.h>
-
-#define BP_TMO            300          /* timeout in jiffies */
-#define BP_DELAY            50          /* spin delay in uS */
-
-#define BP_SPIN                (10000/BP_DELAY)*BP_TMO
-
-int bpcd_init(void);
-void bpcd_setup(char * str, int * ints);
-void cleanup_module( void );
-
-static int     bp_open(struct inode *inode, struct file *file);
-static void    do_bp_request(void);
-static void    do_bp_read(void);
-static int     bp_ioctl(struct inode *inode,struct file *file,
-                         unsigned int cmd, unsigned long arg);
-static int     bp_release (struct inode *inode, struct file *file);
-
-static int     bp_detect(void);
-static int      bp_lock(void);
-static void     bp_unlock(void);
-static void     bp_eject(void);
-static void     bp_interrupt(void *data);
-
-static int     bp_base = BP_BASE;
-static int     bp_rep = BP_REP;
-static int     bp_nybble = 0;          /* force 4-bit mode ? */
-
-static int      bp_unit_id;
-
-static int bp_access = 0;              /* count of active opens ... */
-static int bp_mode = 1;                        /* 4- or 8-bit mode */
-static int bp_busy = 0;                        /* request being processed ? */
-static int bp_timeout;                  /* "interrupt" loop limiter */
-static int bp_sector;                  /* address of next requested sector */
-static int bp_count;                   /* number of blocks still to do */
-static char * bp_buf;                  /* buffer for request in progress */
-static char bp_buffer[2048];           /* raw block buffer */
-static int bp_bufblk = -1;             /* block in buffer, in CD units,
-                                          -1 for nothing there */
-static  int    nyb_map[256];           /* decodes a nybble */
-static int     PortCache = 0;          /* cache of the control port */
-
-static struct tq_struct bp_tq = {0,0,bp_interrupt,NULL}; 
-
-/* kernel glue structures */
-
-static struct file_operations bp_fops = {
-       NULL,                   /* lseek - default */
-       block_read,             /* read - general block-dev read */
-       block_write,            /* write - general block-dev write */
-       NULL,                   /* readdir - bad */
-       NULL,                   /* poll */
-       bp_ioctl,               /* ioctl */
-       NULL,                   /* mmap */
-       bp_open,                /* open */
-       bp_release,             /* release */
-       block_fsync,            /* fsync */
-       NULL,                   /* fasync */
-       NULL,                   /* media change ? */
-       NULL                    /* revalidate new media */
-};
-
-
-/* the MicroSolutions protocol uses bits 3,4,5 & 7 of the status port to
-   deliver a nybble in 4 bit mode.  We use a table lookup to extract the
-   nybble value.  The following function initialises the table.
-*/
-
-__initfunc(static void init_nyb_map( void ))
-
-{      int     i, j;
-
-       for(i=0;i<256;i++) { 
-          j = (i >> 3) & 0x7;
-          if (i & 0x80) j |= 8;
-          nyb_map[i] = j;
-       }
-}
-
-__initfunc(int bpcd_init (void))       /* preliminary initialisation */
-
-{      init_nyb_map();
-
-        if (bp_detect()) return -1;
-
-       if (register_blkdev(MAJOR_NR,"bpcd",&bp_fops)) {
-               printk("bpcd: unable to get major number %d\n",MAJOR_NR);
-               return -1;
-       }
-       blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
-       read_ahead[MAJOR_NR] = 8;       /* 8 sector (4kB) read ahead */
-
-       return 0;
-}
-
-static int bp_open (struct inode *inode, struct file *file)
-
-{      
-       if (file->f_mode & 2) return -EROFS;  /* wants to write ? */
-
-       MOD_INC_USE_COUNT;
-
-       if (!bp_access)
-          if (bp_lock()) {
-               MOD_DEC_USE_COUNT;
-               return -ENXIO;
-          }
-       bp_access++;
-       return 0;
-}
-
-static void do_bp_request (void)
-
-{       if (bp_busy) return;
-        while (1) {
-           if ((!CURRENT) || (CURRENT->rq_status == RQ_INACTIVE)) return;
-           INIT_REQUEST;
-           if (CURRENT->cmd == READ) {
-               bp_sector = CURRENT->sector;
-               bp_count = CURRENT->nr_sectors;
-               bp_buf = CURRENT->buffer;
-               do_bp_read();
-               if (bp_busy) return;
-           } 
-           else end_request(0);
-       }
-}
-
-static int bp_ioctl(struct inode *inode,struct file *file,
-                   unsigned int cmd, unsigned long arg)
-
-/* we currently support only the EJECT ioctl. */
-
-{      switch (cmd) {
-            case CDROMEJECT: if (bp_access == 1) {
-                               bp_eject();
-                               return 0;
-                            }
-           default:
-               return -EINVAL;
-       }
-}
-
-static int bp_release (struct inode *inode, struct file *file)
-
-{      kdev_t  devp;
-
-       bp_access--;
-       if (!bp_access) { 
-           devp = inode->i_rdev;
-           fsync_dev(devp);
-           invalidate_inodes(devp);
-           invalidate_buffers(devp);
-           bp_unlock();
-       }
-       MOD_DEC_USE_COUNT;
-       return 0;
-}
-
-#ifdef MODULE
-
-/* Glue for modules ... */
-
-int    init_module(void)
-
-{      int     err;
-       long    flags;
-
-       save_flags(flags);
-       cli();
-
-       err = bpcd_init();
-
-       restore_flags(flags);
-       return err;
-}
-
-void   cleanup_module(void)
-
-{      long flags;
-
-       save_flags(flags);
-       cli();
-       unregister_blkdev(MAJOR_NR,"bpcd");
-       release_region(bp_base,3);
-       restore_flags(flags);
-}
-
-#else 
-
-/* bpcd_setup:  process lilo command parameters ...
-
-   syntax:     bpcd=base[,nybble[,rep]]
-*/
-
-__initfunc(void bpcd_setup(char *str, int *ints))
-
-{       if (ints[0] > 0) bp_base = ints[1];
-        if (ints[0] > 1) bp_nybble = ints[2];
-        if (ints[0] > 2) bp_rep = ints[3];
-} 
-
-#endif
-
-static void    out_p( short port, char byte)
-
-{       int i;
-
-       for(i=0;i<bp_rep;i++) outb(byte,bp_base+port);
-}
-
-static int     in_p( short port)
-
-{       int i;
-       char c;
-
-       for(i=0;i<bp_rep;i++) c=inb(bp_base+port);
-       c=inb(bp_base+port);
-       return c & 0xff;
-}
-
-/* Unlike other PP devices I've worked on, the backpack protocol seems
-   to be driven by *changes* in the values of certain bits on the control
-   port, rather than their absolute value.  Hence the unusual macros ...
-*/
-
-#define w0(byte)               out_p(0,byte)
-#define r0()                   (in_p(0) & 0xff)
-#define w1(byte)               out_p(1,byte)
-#define r1()                   (in_p(1) & 0xff)
-#define w2(byte)               out_p(2,byte) ; PortCache = byte
-#define t2(pat)                PortCache ^= pat; out_p(2,PortCache)
-#define e2()                   PortCache &= 0xfe; out_p(2,PortCache)
-#define o2()                   PortCache |= 1; out_p(2,PortCache)
-
-static int read_byte( void )
-
-{      int l, h;
-
-       t2(4); 
-       if (bp_mode == 2) return r0();
-       l = nyb_map[r1()];
-       t2(4);
-       h = nyb_map[r1()];
-       return (h << 4) + l;
-}
-
-static int read_regr( char regr )
-
-{       int r;
-
-               w0(regr & 0xf); w0(regr); t2(2);
-       if (bp_mode == 2) { e2(); t2(0x20); }
-       r = read_byte();
-       if (bp_mode == 2) { t2(1); t2(0x20); }
-       return r;
-}      
-
-static void write_regr( char regr, char val )
-
-{      w0(regr);
-       t2(2);
-       w0(val);
-       o2(); t2(4); t2(1);
-}
-
-static void write_cmd( char * cmd, int len )
-
-{      int i, f;
-
-       if (bp_mode == 2) f = 0x10; else f = 0;
-       write_regr(4,0x40|f);
-       w0(0x40); t2(2); t2(1);
-       i = 0;
-       while (i < len) {
-          w0(cmd[i++]); 
-          t2(4);
-       }
-       write_regr(4,f);
-}
-
-static void read_data( char * buf, int len )
-
-{      int i, f;
-
-       if (bp_mode == 2) f = 0x50; else f = 0x40;
-       write_regr(4,f);
-       w0(0x40); t2(2);
-       if (bp_mode == 2) t2(0x20);
-       for(i=0;i<len;i++) buf[i] = read_byte();
-       if (bp_mode == 2) { t2(1); t2(0x20); }
-}
-
-__initfunc(static int probe( int id ))
-
-{      int l, h, t;
-       int r = -1;
-
-       w2(4); w2(0xe); w2(0xec); w1(0x7f);
-       if ((r1() & 0xf8) != 0x78) return -1;
-       w0(255-id); w2(4); w0(id);
-       t2(8); t2(8); t2(8);
-       t2(2); t = (r1() & 0xf8);
-       if (t != 0x78) {
-               l = nyb_map[t];
-               t2(2); h = nyb_map[r1()];
-               t2(8);
-               r = 0;
-       }
-       w0(0); t2(2); w2(0x4c); w0(0x13);
-       return r;
-}
-       
-static void connect ( void  )
-
-{      int     f;
-
-       w0(0xff-bp_unit_id); w2(4); w0(bp_unit_id);
-       t2(8); t2(8); t2(8); 
-       t2(2); t2(2); t2(8);
-       if (bp_mode == 2) f = 0x10; else f = 0;
-       write_regr(4,f);
-       write_regr(5,8);
-       write_regr(0x46,0x10);
-       write_regr(0x4c,0x38);
-       write_regr(0x4d,0x88);
-       write_regr(0x46,0xa0);
-       write_regr(0x41,0);
-       write_regr(0x4e,8);
-}
-
-static void disconnect ( void )
-
-{      w0(0); t2(2); w2(0x4c);
-       if (bp_mode == 2) w0(0xff); else  w0(0x13);
-} 
-
-static int bp_wait_drq( char * lab, char * fun )
-
-{      int j, r, e;
-
-       j = 0;
-
-       while (1)  {
-               r = read_regr(0x47);
-               e = read_regr(0x41);
-               if ((r & 9) || (j++ >= BP_SPIN)) break;
-               udelay(BP_DELAY);
-       }
-
-       if ((j >= BP_SPIN) || (r & 1)) {
-           if (lab && fun) 
-                  printk("bpcd: %s (%s): %s status: %x error: %x\n",
-                         lab,fun,(j >= BP_SPIN)?"timeout, ":"",r,e);
-           return -1;
-       }
-       return 0;
-}
-
-static int bp_wait( char * lab, char * fun )
-
-{      int j, r, e;
-
-       j = 0;
-       while ((!(read_regr(0xb) & 0x80)) && (j++ < BP_SPIN)) udelay(BP_DELAY);
-        r = read_regr(0x47);
-       e = read_regr(0x41);
-       if ((j >= BP_SPIN) || (r & 1)) {
-           if (lab && fun) 
-                  printk("bpcd: %s (%s): %s status: %x error: %x\n",
-                         lab,fun,(j >= BP_SPIN)?"timeout, ":"",r,e);
-           return -1;
-       }
-       return 0;
-}
-
-static int bp_command( char * cmd, int dlen, char * fun )
-
-{      int     r;
-
-       connect();
-       write_regr(0x44,dlen % 256);
-       write_regr(0x45,dlen / 256);
-       write_regr(0x46,0xa0);          /* drive 0 */
-       write_regr(0x47,0xa0);          /* ATAPI packet command */
-       if ((r=bp_wait_drq("bp_command",fun))) {
-          disconnect();
-          return r;
-       }
-       write_cmd(cmd,12);
-       return 0;
-}
-
-static int bp_completion( char * fun )
-
-{      int r, n;
-
-       if (!(r=bp_wait("bp_completion",fun))) {
-           if (read_regr(0x42) == 2) {
-               n = (read_regr(0x44) + 256*read_regr(0x45));
-               read_data(bp_buffer,n);
-               r=bp_wait("transfer done",fun);
-           }
-       }
-       disconnect(); 
-       return r;
-}
-
-static int bp_atapi( char * cmd, int dlen, char * fun )
-
-{      int r;
-
-       if (!(r=bp_command(cmd,dlen,fun)))
-         r = bp_completion(fun);
-       return r;
-}
-
-static int bp_req_sense( char * msg )
-
-{      char    rs_cmd[12] = { 0x03,0,0,0,18,0,0,0,0,0,0,0 };
-       int r;
-
-       r = bp_atapi(rs_cmd,18,"request sense");
-       if (msg) printk("bpcd: %s:  sense key: %x, ASC: %x, ASQ: %x\n",msg,
-                        bp_buffer[2]&0xf, bp_buffer[12], bp_buffer[13]);
-       return r;
-}
-
-static int bp_lock(void)
-
-{      char    lo_cmd[12] = { 0x1e,0,0,0,1,0,0,0,0,0,0,0 };
-       char    cl_cmd[12] = { 0x1b,0,0,0,3,0,0,0,0,0,0,0 };
-
-       bp_atapi(cl_cmd,0,"close door");
-        if (bp_req_sense(NULL)) return -1;  /* check for disk */
-       bp_atapi(lo_cmd,0,NULL);
-       bp_req_sense(NULL);  /* in case there was a media change */
-       bp_atapi(lo_cmd,0,"lock door");
-       return 0;
-}
-
-static void bp_unlock( void)
-
-{      char    un_cmd[12] = { 0x1e,0,0,0,0,0,0,0,0,0,0,0 };
-
-       bp_atapi(un_cmd,0,"unlock door");
-}
-
-static void bp_eject( void)
-
-{      char    ej_cmd[12] = { 0x1b,0,0,0,2,0,0,0,0,0,0,0 };
-
-       bp_unlock();
-       bp_atapi(ej_cmd,0,"eject");
-}
-
-__initfunc(static int bp_reset( void ))
-
-/* the ATAPI standard actually specifies the contents of all 7 registers
-   after a reset, but the specification is ambiguous concerning the last
-   two bytes, and different drives interpret the standard differently.
-*/
-
-{      int     i, flg;
-       int     expect[5] = {1,1,1,0x14,0xeb};
-       long    flags;
-
-       connect();
-       write_regr(0x46,0xa0);
-       write_regr(0x47,8);
-
-       save_flags(flags);
-       sti();
-       udelay(500000);         /* delay 0.5 seconds */
-       restore_flags(flags);
-
-       flg = 1;
-       for(i=0;i<5;i++) flg &= (read_regr(i+0x41) == expect[i]);
-       
-       disconnect();
-       return flg-1;   
-}
-
-__initfunc(static int bp_identify( char * id ))
-
-{      int k;
-       char   id_cmd[12] = {0x12,0,0,0,36,0,0,0,0,0,0,0};
-
-       bp_bufblk = -1;
-        if (bp_atapi(id_cmd,36,"identify")) return -1;
-       for (k=0;k<16;k++) id[k] = bp_buffer[16+k];
-       id[16] = 0;
-       return 0;
-}
-
-__initfunc(static int bp_port_check( void ))   /* check for 8-bit port */
-
-{      int     r;
-
-        w2(0); 
-       w0(0x55); if (r0() != 0x55) return 0;
-       w0(0xaa); if (r0() != 0xaa) return 0;
-       w2(0x20); w0(0x55); r = r0(); w0(0xaa);
-       if (r0() == r) return 2;
-       if (r0() == 0xaa) return 1;
-       return 0;
-}
-
-__initfunc(static int bp_locate( void ))
-
-{      int     k;
-
-       for(k=0;k<100;k++) 
-         if (!probe(k)) {
-               bp_unit_id = k;
-               return 0;
-         }
-       return -1;
-}
-
-__initfunc(static int bp_do_detect( int autop ))
-
-{      char   id[18];
-
-       if (autop) bp_base = autop;
-
-       if (check_region(bp_base,3)) {
-               if (!autop) 
-                 printk("bpcd: Ports at 0x%x are not available\n",bp_base);
-               return -1;
-       }
-
-       bp_mode = bp_port_check();
-
-       if (!bp_mode) {
-               if (!autop)
-                 printk("bpcd: No parallel port at 0x%x\n",bp_base);
-               return -1;
-       }
-
-       if (bp_nybble) bp_mode = 1;
-
-       if (bp_locate()) {
-               if (!autop)
-                 printk("bpcd: Couldn't find a backpack adapter at 0x%x\n",
-                         bp_base);
-               return -1;
-       }
-
-       if (bp_reset()) {
-               if (!autop)
-                 printk("bpcd: Failed to reset CD drive\n");
-               return -1;
-       }
-
-       if (bp_identify(id)) {
-               if (!autop)
-                 printk("bpcd: ATAPI inquiry failed\n");
-               return -1;
-       }
-
-       request_region(bp_base,3,"bpcd");
-
-       printk("bpcd: Found %s, ID %d, using port 0x%x in %d-bit mode\n",
-              id,bp_unit_id,bp_base,4*bp_mode);
-
-       return 0;
-}
-
-/* If you know about some other weird parallel port base address,
-   add it here ....
-*/
-
-__initfunc(static int bp_detect( void ))
-
-{      if (bp_base) return bp_do_detect(0);
-       if (!bp_do_detect(0x378)) return 0;
-       if (!bp_do_detect(0x278)) return 0;
-       if (!bp_do_detect(0x3bc)) return 0;
-       printk("bpcd: Autoprobe failed\n");
-       return -1;
-}
-
-
-static void bp_transfer( void )
-
-{      int     k, o;
-
-       while (bp_count && (bp_sector/4 == bp_bufblk)) {
-               o = (bp_sector % 4) * 512;
-               for(k=0;k<512;k++) bp_buf[k] = bp_buffer[o+k];
-               bp_count--;
-               bp_buf += 512;
-               bp_sector++;
-       }
-}
-
-static void do_bp_read( void )
-
-{      int     b, i;
-       char    rd_cmd[12] = {0xa8,0,0,0,0,0,0,0,0,1,0,0};
-
-       bp_busy = 1;
-       bp_transfer();
-       if (!bp_count) {
-               end_request(1);
-               bp_busy = 0;
-               return;
-       }
-       sti();
-
-       bp_bufblk = bp_sector / 4;
-        b = bp_bufblk;
-       for(i=0;i<4;i++) { 
-          rd_cmd[5-i] = b & 0xff;
-          b = b >> 8;
-       }
-
-       if (bp_command(rd_cmd,2048,"read block")) {
-               bp_bufblk = -1; 
-               bp_busy = 0;
-               cli();
-               bp_req_sense("send read command");
-               end_request(0);
-               return;
-       }
-       bp_timeout = jiffies + BP_TMO;
-       queue_task(&bp_tq,&tq_scheduler); 
-}
-
-static void bp_interrupt( void *data)
-
-{      if (!(read_regr(0xb) & 0x80)) {
-               if (jiffies > bp_timeout) {
-                       bp_bufblk = -1;
-                       bp_busy = 0;
-                       bp_req_sense("interrupt timeout");
-                       end_request(0);
-                       do_bp_request();
-               }
-               queue_task(&bp_tq,&tq_scheduler); 
-               return;
-       }
-       sti();
-       if (bp_completion("read completion")) {
-               cli();
-               bp_busy = 0;
-               bp_bufblk = -1;
-               bp_req_sense("read completion");
-               end_request(0);
-               do_bp_request();
-       }
-       do_bp_read();
-       do_bp_request();
-}
-       
-/* end of bpcd.c */
index 4f1a2e87709d52d3c32a628d188adf8f4938c1cb..72079074f32ccac4f00793775752af1cbf9f04ba 100644 (file)
@@ -68,8 +68,8 @@
 #include <asm/uaccess.h>
 
 
-#define VERSION "$Id: cdrom.c,v 2.0 1997/11/20 01:58:03 erik Exp $"
-#define REVISION "revision 2.0"
+#define VERSION "$Id: cdrom.c,v 2.1 1997/12/28 15:11:47 david Exp $"
+#define REVISION "$Revision: 2.1 $"
 #define FM_WRITE       0x2                 /* file mode write bit */
 
 /* When VERBOSE_STATUS_INFO is not defined, the debugging printks don't 
@@ -177,7 +177,8 @@ int register_cdrom(struct cdrom_device_info *cdi)
        ENSURE(reset, CDC_RESET);
        ENSURE(audio_ioctl, CDC_PLAY_AUDIO);
        ENSURE(dev_ioctl, CDC_IOCTLS);
-       cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK | CDO_CHECK_TYPE;
+       cdi->options = CDO_AUTO_CLOSE | CDO_USE_FFLAGS | CDO_LOCK;
+                                       /* default compatibility mode */
        cdi->mc_flags = 0;
        cdo->n_minors = 0;
        cdinfo(CD_REG_UNREG, "drive \"/dev/%s\" registered\n", cdi->name);
@@ -305,15 +306,13 @@ int open_for_data(struct cdrom_device_info * cdi)
                ret=-ENOMEDIUM;
                goto clean_up_and_return;
        }
-#if 0
-       /* this breaks CD-Players which don't use O_NONBLOCK, workman
-        * for example, probably others too */
+       /* CD-Players which don't use O_NONBLOCK, workman
+        * for example, need bit CDO_CHECK_TYPE cleared! */
        if (cdi->options & CDO_CHECK_TYPE && tracks.data==0) {
                cdinfo(CD_OPEN, "bummer. wrong media type...\n"); 
                ret=-EMEDIUMTYPE;
                goto clean_up_and_return;
        }
-#endif
 
        cdinfo(CD_OPEN, "all seems well, opening the device...\n"); 
 
@@ -716,6 +715,10 @@ int cdrom_ioctl(struct inode *ip, struct file *fp,
           returns with the above, but this more clearly demonstrates
           the problem with the current interface.  Too bad this wasn't 
           designed to use bitmasks...         -Erik 
+
+          Well, now we have the option CDS_MIXED: a mixed-type CD. 
+          User level programmers might feel the ioctl is not very useful.
+                                               ---david
        */
        case CDROM_DISC_STATUS: {
                tracktype tracks;
@@ -725,11 +728,14 @@ int cdrom_ioctl(struct inode *ip, struct file *fp,
                        return(tracks.error);
 
                /* Policy mode on */
-               if (tracks.audio>0 && tracks.data==0 && tracks.cdi==0 && tracks.xa==0) 
-                       return CDS_AUDIO;
-               if (tracks.cdi>0) return CDS_XA_2_2;
-               if (tracks.xa>0) return CDS_XA_2_1;
-               if (tracks.data>0) return CDS_DATA_1;
+               if (tracks.audio > 0) {
+                       if (tracks.data==0 && tracks.cdi==0 && tracks.xa==0) 
+                               return CDS_AUDIO;
+                       else return CDS_MIXED;
+               }
+               if (tracks.cdi > 0) return CDS_XA_2_2;
+               if (tracks.xa > 0) return CDS_XA_2_1;
+               if (tracks.data > 0) return CDS_DATA_1;
                /* Policy mode off */
 
                cdinfo(CD_WARNING,"This disc doesn't have any tracks I recognise!\n");
index e699cfa8e001dab3feb67dc98a23cdbd4f99c833..e0409d3c70b6dcaba96536ab428123fc3addc9e8 100644 (file)
@@ -1,5 +1,6 @@
 /* cm206.c. A linux-driver for the cm206 cdrom player with cm260 adapter card.
-   Copyright (c) 1995, 1996 David van Leeuwen.
+   Copyright (c) 1995--1997 David A. van Leeuwen.
+   $Id: cm206.c,v 1.5 1997/12/26 11:02:51 david Exp $
    
      This program is free software; you can redistribute it and/or modify
      it under the terms of the GNU General Public License as published by
@@ -70,40 +71,84 @@ History:
              open only for ioctl operation, e.g., for operation of
              tray etc.
  4 apr 1996:  0.97 First implementation of layer between VFS and cdrom
-              driver, a Uniform interface. Much of the functionality
+              driver, a generic interface. Much of the functionality
              of cm206_open() and cm206_ioctl() is transferred to a
-             new file cdrom.c and its header cdrom.h. 
+             new file cdrom.c and its header ucdrom.h. 
 
              Upgrade to Linux kernel 1.3.78. 
 
  11 apr 1996  0.98 Upgrade to Linux kernel 1.3.85
               More code moved to cdrom.c
+             0.99 Some more small changes to decrease number
+             of oopses at module load; 
+ 27 jul 1996  0.100 Many hours of debugging, kernel change from 1.2.13
+             to 2.0.7 seems to have introduced some weird behavior
+             in (interruptible_)sleep_on(&cd->data): the process
+             seems to be woken without any explicit wake_up in my own
+             code. Patch to try 100x in case such untriggered wake_up's 
+             occur. 
 
-             0.99 Some more small changes to decrease number
-             of oopses at module load; 
-
-             Branch from here:
-
-             0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t
-             (emoenke) various typos found by others.  extra
-             module-load oops protection.
-
-             0.99.1.1 Initialization constant cdrom_dops.speed
-             changed from float (2.0) to int (2); Cli()-sti() pair
-             around cm260_reset() in module initialization code.
+ 28 jul 1996  0.101 Rewriting of the code that receives the command echo,
+             using a fifo to store echoed bytes. 
 
-             0.99.1.2 Changes literally as proposed by Scott Snyder
-             <snyder@d0sgif.fnal.gov>, which have to do mainly with
-             the poor minor support i had. The major new concept is
-             to change a cdrom driver's operations struct from the
-             capabilities struct. This reflects the fact that there
-             is one major for a driver, whilst there can be many
-             minors whith completely different capabilities.
+             Branch from 0.99:
+             0.99.1.0 Update to kernel release 2.0.10 dev_t -> kdev_t
+             (emoenke) various typos found by others.  extra
+             module-load oops protection.
+             0.99.1.1 Initialization constant cdrom_dops.speed
+             changed from float (2.0) to int (2); Cli()-sti() pair
+             around cm260_reset() in module initialization code.
+             0.99.1.2 Changes literally as proposed by Scott Snyder
+             <snyder@d0sgif.fnal.gov> for the 2.1 kernel line, which
+             have to do mainly with the poor minor support i had. The
+             major new concept is to change a cdrom driver's
+             operations struct from the capabilities struct. This
+             reflects the fact that there is one major for a driver,
+             whilst there can be many minors whith completely
+             different capabilities.
 
              0.99.1.3 More changes for operations/info separation.
 
              0.99.1.4 Added speed selection (someone had to do this
              first).
+
+  23 jan 1997 0.99.1.5 MODULE_PARMS call added.
+
+  23 jan 1997 0.100.1.2--0.100.1.5 following similar lines as 
+             0.99.1.1--0.99.1.5. I get too many complaints about the
+             drive making read errors. What't wrong with the 2.0+
+             kernel line? Why get i (and othe cm206 owners) weird
+             results? Why were things good in the good old 1.1--1.2 
+             era? Why don't i throw away the drive?
+
+ 2 feb 1997   0.102 Added `volatile' to values in cm206_struct. Seems to 
+             reduce many of the problems. Rewrote polling routines
+             to use fixed delays between polls. 
+             0.103 Changed printk behavior. 
+             0.104 Added a 0.100 -> 0.100.1.1 change
+
+11 feb 1997   0.105 Allow auto_probe during module load, disable
+              with module option "auto_probe=0". Moved some debugging
+             statements to lower priority. Implemented select_speed()
+             function. 
+
+13 feb 1997   1.0 Final version for 2.0 kernel line. 
+
+             All following changes will be for the 2.1 kernel line. 
+
+15 feb 1997   1.1 Keep up with kernel 2.1.26, merge in changes from 
+              cdrom.c 0.100.1.1--1.0. Add some more MODULE_PARMS. 
+
+14 sep 1997   1.2 Upgrade to Linux 2.1.55.  Added blksize_size[], patch
+              sent by James Bottomley <James.Bottomley@columbiasc.ncr.com>.
+
+21 dec 1997   1.4 Upgrade to Linux 2.1.72.  
+
  * 
  * Parts of the code are based upon lmscd.c written by Kai Petzke,
  * sbpcd.c written by Eberhard Moenkeberg, and mcd.c by Martin
@@ -123,8 +168,8 @@ History:
  * - Philips/LMS cm206 and cm226 product specification
  * - Philips/LMS cm260 product specification
  *
- *                       David van Leeuwen, david@tm.tno.nl.  */
-#define VERSION "$Id: cm206.c,v 0.99.1.4 1996/12/23 21:46:13 david Exp $"
+ * David van Leeuwen, david@tm.tno.nl.  */
+#define REVISION "$Revision: 1.5 $"
 
 #include <linux/module.h>      
 
@@ -140,6 +185,8 @@ History:
 #include <linux/malloc.h>
 #include <linux/init.h>
 
+/* #include <linux/ucdrom.h> */
+
 #include <asm/io.h>
 
 #define MAJOR_NR CM206_CDROM_MAJOR
@@ -147,7 +194,7 @@ History:
 
 #undef DEBUG
 #define STATISTICS             /* record times and frequencies of events */
-#undef AUTO_PROBE_MODULE
+#define AUTO_PROBE_MODULE
 #define USE_INSW
 
 #include "cm206.h"
@@ -160,15 +207,18 @@ static int auto_probe=1;  /* Yes, why not? */
 
 static int cm206_base = CM206_BASE;
 static int cm206_irq = CM206_IRQ; 
-MODULE_PARM(cm206_base, "i");
-MODULE_PARM(cm206_irq, "i");
+MODULE_PARM(cm206_base, "i");  /* base */
+MODULE_PARM(cm206_irq, "i");   /* irq */
+MODULE_PARM(cm206, "1-2i");    /* base,irq or irq,base */
+MODULE_PARM(auto_probe, "i");  /* auto probe base and irq */
 
-#define POLLOOP 10000
+#define POLLOOP 100            /* milliseconds */
 #define READ_AHEAD 1           /* defines private buffer, waste! */
 #define BACK_AHEAD 1           /* defines adapter-read ahead */
 #define DATA_TIMEOUT (3*HZ)    /* measured in jiffies (10 ms) */
 #define UART_TIMEOUT (5*HZ/100)
 #define DSB_TIMEOUT (7*HZ)     /* time for the slowest command to finish */
+#define UR_SIZE 4              /* uart receive buffer fifo size */
 
 #define LINUX_BLOCK_SIZE 512   /* WHERE is this defined? */
 #define RAW_SECTOR_SIZE 2352   /* ok, is also defined in cdrom.h */
@@ -181,13 +231,14 @@ MODULE_PARM(cm206_irq, "i");
                     cd->last_stat[st_ ## i] = cd->stat_counter++; \
                 }
 #else
-#define stats(i) (void) 0
+#define stats(i) (void) 0;
 #endif
 
-#ifdef DEBUG                   /* from lmscd.c */
-#define debug(a) printk a
+#define Debug(a) {printk (KERN_DEBUG); printk a;}
+#ifdef DEBUG
+#define debug(a) Debug(a)
 #else
-#define debug(a) (void) 0
+#define debug(a) (void) 0;
 #endif
 
 typedef unsigned char uch;     /* 8-bits */
@@ -197,21 +248,23 @@ struct toc_struct{                /* private copy of Table of Contents */
   uch track, fsm[3], q0;
 };
 
+static int cm206_blocksizes[1] = { 2048 };
+
 struct cm206_struct {
-  ush intr_ds;  /* data status read on last interrupt */
-  ush intr_ls;  /* uart line status read on last interrupt*/
-  uch intr_ur;                 /* uart receive buffer */
-  uch dsb, cc;  /* drive status byte and condition (error) code */
-  uch fool;
+  volatile ush intr_ds;                /* data status read on last interrupt */
+  volatile ush intr_ls;                /* uart line status read on last interrupt*/
+  volatile uch ur[UR_SIZE];    /* uart receive buffer fifo */
+  volatile uch ur_w, ur_r;     /* write/read buffer index */
+  volatile uch dsb, cc;         /* drive status byte and condition (error) code */
   int command;                 /* command to be written to the uart */
   int openfiles;
   ush sector[READ_AHEAD*RAW_SECTOR_SIZE/2]; /* buffered cd-sector */
-  int sector_first, sector_last;       /* range of these sector */
-  struct wait_queue * uart;    /* wait for interrupt */
+  int sector_first, sector_last; /* range of these sectors */
+  struct wait_queue * uart;    /* wait queues for interrupt */
   struct wait_queue * data;
   struct timer_list timer;     /* time-out */
   char timed_out;
-  signed char max_sectors;
+  signed char max_sectors;     /* number of sectors that fit in adapter mem */
   char wait_back;              /* we're waiting for a background-read */
   char background;             /* is a read going on in the background? */
   int adapter_first;           /* if so, that's the starting sector */
@@ -243,15 +296,20 @@ static struct cm206_struct * cd; /* the main memory structure */
 void send_command_polled(int command)
 {
   int loop=POLLOOP;
-  while (!(inw(r_line_status) & ls_transmitter_buffer_empty) && loop>0) 
+  while (!(inw(r_line_status) & ls_transmitter_buffer_empty) && loop>0) {
+    udelay(1000);              /* one millisec delay */
     --loop;
+  }
   outw(command, r_uart_transmit);
 }
 
 uch receive_echo_polled(void)
 {
   int loop=POLLOOP;
-  while (!(inw(r_line_status) & ls_receive_buffer_full) && loop>0) --loop;
+  while (!(inw(r_line_status) & ls_receive_buffer_full) && loop>0) {
+    udelay(1000);
+    --loop;
+  }
   return ((uch) inw(r_uart_receive));
 }
 
@@ -261,6 +319,15 @@ uch send_receive_polled(int command)
   return receive_echo_polled();
 }
 
+inline void clear_ur(void) {
+  if (cd->ur_r != cd->ur_w) {
+    debug(("Deleting bytes from fifo:"));
+    for(;cd->ur_r != cd->ur_w; cd->ur_r++, cd->ur_r %= UR_SIZE)
+      debug((" 0x%x", cd->ur[cd->ur_r]));
+    debug(("\n"));
+  }
+}
+
 /* The interrupt handler. When the cm260 generates an interrupt, very
    much care has to be taken in reading out the registers in the right
    order; in case of a receive_buffer_full interrupt, first the
@@ -282,18 +349,27 @@ static void cm206_interrupt(int sig, void *dev_id, struct pt_regs * regs)
                                       crc_error, sync_error, toc_ready 
                                       interrupts */
   cd->intr_ls = inw(r_line_status); /* resets overrun bit */
+  debug(("Intr, 0x%x 0x%x, %d\n", cd->intr_ds, cd->intr_ls, cd->background));
   if (cd->intr_ls & ls_attention) stats(attention);
   /* receive buffer full? */
   if (cd->intr_ls & ls_receive_buffer_full) {  
-    cd->intr_ur = inb(r_uart_receive); /* get order right! */
+    cd->ur[cd->ur_w] = inb(r_uart_receive); /* get order right! */
     cd->intr_ls = inw(r_line_status); /* resets rbf interrupt */
-    if (!cd->background && cd->uart) wake_up_interruptible(&cd->uart);
+    debug(("receiving #%d: 0x%x\n", cd->ur_w, cd->ur[cd->ur_w]));
+    cd->ur_w++; cd->ur_w %= UR_SIZE;
+    if (cd->ur_w == cd->ur_r) debug(("cd->ur overflow!\n"));
+    if (cd->uart && cd->background < 2) { 
+      del_timer(&cd->timer);
+      wake_up_interruptible(&cd->uart);
+    }
   }
   /* data ready in fifo? */
   else if (cd->intr_ds & ds_data_ready) { 
     if (cd->background) ++cd->adapter_last;
-    if ((cd->wait_back || !cd->background) && cd->data) 
+    if (cd->data && (cd->wait_back || !cd->background)) {
+      del_timer(&cd->timer);
       wake_up_interruptible(&cd->data);
+    }
     stats(data_ready);
   }
   /* ready to issue a write command? */
@@ -340,6 +416,7 @@ static void cm206_interrupt(int sig, void *dev_id, struct pt_regs * regs)
 void cm206_timeout(unsigned long who)
 {
   cd->timed_out = 1;
+  debug(("Timing out\n"));
   wake_up_interruptible((struct wait_queue **) who);
 }
 
@@ -347,9 +424,11 @@ void cm206_timeout(unsigned long who)
    happened */
 int sleep_or_timeout(struct wait_queue ** wait, int timeout)
 {
+  cd->timed_out=0;
   cd->timer.data=(unsigned long) wait;
   cd->timer.expires = jiffies + timeout;
   add_timer(&cd->timer);
+  debug(("going to sleep\n"));
   interruptible_sleep_on(wait);
   del_timer(&cd->timer);
   if (cd->timed_out) {
@@ -359,14 +438,15 @@ int sleep_or_timeout(struct wait_queue ** wait, int timeout)
   else return 0;
 }
 
-void cm206_delay(int jiffies) 
+void cm206_delay(int nr_jiffies) 
 {
   struct wait_queue * wait = NULL;
-  sleep_or_timeout(&wait, jiffies);
+  sleep_or_timeout(&wait, nr_jiffies);
 }
 
 void send_command(int command)
 {
+  debug(("Sending 0x%x\n", command));
   if (!(inw(r_line_status) & ls_transmitter_buffer_empty)) {
     cd->command = command;
     cli();                     /* don't interrupt before sleep */
@@ -378,19 +458,40 @@ void send_command(int command)
       stats(write_timeout);
       outw(command, r_uart_transmit);
     }
+    debug(("Write commmand delayed\n"));
   }
   else outw(command, r_uart_transmit);
 }
 
-uch receive_echo(void)
+uch receive_byte(int timeout)
 {
-  if (!(inw(r_line_status) & ls_receive_buffer_full) &&
-      sleep_or_timeout(&cd->uart, UART_TIMEOUT)) {
+  uch ret;
+  cli();
+  debug(("cli\n"));
+  ret = cd->ur[cd->ur_r];
+  if (cd->ur_r != cd->ur_w) {
+    sti();
+    debug(("returning #%d: 0x%x\n", cd->ur_r, cd->ur[cd->ur_r]));
+    cd->ur_r++; cd->ur_r %= UR_SIZE;
+    return ret;
+  } 
+  else if (sleep_or_timeout(&cd->uart, timeout)) { /* does sti() */
     debug(("Time out on receive-buffer\n"));
-    stats(receive_timeout);
-    return ((uch) inw(r_uart_receive));
+#ifdef STATISTICS
+    if (timeout==UART_TIMEOUT) stats(receive_timeout) /* no `;'! */
+    else stats(dsb_timeout);
+#endif
+    return 0xda;
   }
-  return cd->intr_ur;
+  ret = cd->ur[cd->ur_r];  
+  debug(("slept; returning #%d: 0x%x\n", cd->ur_r, cd->ur[cd->ur_r]));
+  cd->ur_r++; cd->ur_r %= UR_SIZE;
+  return ret;
+}
+
+inline uch receive_echo(void)
+{
+  return receive_byte(UART_TIMEOUT);
 }
 
 inline uch send_receive(int command)
@@ -399,20 +500,15 @@ inline uch send_receive(int command)
   return receive_echo();
 }
 
-uch wait_dsb(void)
+inline uch wait_dsb(void)
 {
-  if (!(inw(r_line_status) & ls_receive_buffer_full) &&
-      sleep_or_timeout(&cd->uart, DSB_TIMEOUT)) {
-    debug(("Time out on Drive Status Byte\n"));
-    stats(dsb_timeout);
-    return ((uch) inw(r_uart_receive));
-  }
-  return cd->intr_ur;
+  return receive_byte(DSB_TIMEOUT);
 }
 
 int type_0_command(int command, int expect_dsb)
 {
   int e;
+  clear_ur();
   if (command != (e=send_receive(command))) {
     debug(("command 0x%x echoed as 0x%x\n", command, e));
     stats(echo);
@@ -433,8 +529,8 @@ int type_1_command(int command, int bytes, uch * status) /* returns info */
   return 0;
 }  
 
-/* This function resets the adapter card. We'd better not do this too */
-/* often, because it tends to generate `lost interrupts.' */
+/* This function resets the adapter card. We'd better not do this too
+ * often, because it tends to generate `lost interrupts.' */
 void reset_cm260(void)
 {
   outw(dc_normal | dc_initialize | READ_AHEAD, r_data_control);
@@ -442,7 +538,7 @@ void reset_cm260(void)
   outw(dc_normal | READ_AHEAD, r_data_control);
 }
 
-/* fsm: frame-sec-min from linear address */
+/* fsm: frame-sec-min from linear address; one of many */
 void fsm(int lba, uch * fsm) 
 {
   fsm[0] = lba % 75;
@@ -466,20 +562,26 @@ int start_read(int start)
   int i, e;
 
   fsm(start, &read_sector[1]);
+  clear_ur();
   for (i=0; i<4; i++) 
     if (read_sector[i] != (e=send_receive(read_sector[i]))) {
       debug(("read_sector: %x echoes %x\n", read_sector[i], e));
       stats(echo);
-      return -1;
+      if (e==0xff) {           /* this seems to happen often */
+       e = receive_echo();
+       debug(("Second try %x\n", e));
+       if (e!=read_sector[i]) return -1;
+      }
     }
   return 0;
 }
 
 int stop_read(void)
 {
+  int e;
   type_0_command(c_stop,0);
-  if(receive_echo() != 0xff) {
-    debug(("c_stop didn't send 0xff\n"));
+  if((e=receive_echo()) != 0xff) {
+    debug(("c_stop didn't send 0xff, but 0x%x\n", e));
     stats(stop_0xff);
     return -1;
   }
@@ -515,8 +617,11 @@ void transport_data(int port, ush * dest, int count)
 }
 #endif
 
+
+#define MAX_TRIES 100
 int read_sector(int start)
 {
+  int tries=0;
   if (cd->background) {
     cd->background=0;
     cd->adapter_last = -1;     /* invalidate adapter memory */
@@ -525,12 +630,18 @@ int read_sector(int start)
   cd->fifo_overflowed=0;
   reset_cm260();               /* empty fifo etc. */
   if (start_read(start)) return -1;
-  if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) {
-    debug(("Read timed out sector 0x%x\n", start));
-    stats(read_timeout);
-    stop_read();
-    return -3;         
-  }
+  do {
+    if (sleep_or_timeout(&cd->data, DATA_TIMEOUT)) {
+      debug(("Read timed out sector 0x%x\n", start));
+      stats(read_timeout);
+      stop_read();
+      return -3;               
+    } 
+    tries++;
+  } while (cd->intr_ds & ds_fifo_empty && tries < MAX_TRIES);
+  if (tries>1) debug(("Took me some tries\n"))
+  else if (tries == MAX_TRIES) 
+    debug(("MAX_TRIES tries for read sector\n"));
   transport_data(r_fifo_output_buffer, cd->sector, 
                 READ_AHEAD*RAW_SECTOR_SIZE/2);
   if (read_background(start+READ_AHEAD,1)) stats(read_background);
@@ -569,16 +680,22 @@ void cm206_bh(void)
     cd->background=3;
     break;
   case 3:
-    if (cd->intr_ur != c_stop) {
-      debug(("cm206_bh: c_stop echoed 0x%x\n", cd->intr_ur));
-      stats(echo);
+    if (cd->ur_r != cd->ur_w) {
+      if (cd->ur[cd->ur_r] != c_stop) {
+       debug(("cm206_bh: c_stop echoed 0x%x\n", cd->ur[cd->ur_r]));
+       stats(echo);
+      }
+      cd->ur_r++; cd->ur_r %= UR_SIZE;
     }
     cd->background++;
     break;
   case 4:
-    if (cd->intr_ur != 0xff) {
-      debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->intr_ur));
-      stats(stop_0xff);
+    if (cd->ur_r != cd->ur_w) {
+      if (cd->ur[cd->ur_r] != 0xff) {
+       debug(("cm206_bh: c_stop reacted with 0x%x\n", cd->ur[cd->ur_r]));
+       stats(stop_0xff);
+      }
+      cd->ur_r++; cd->ur_r %= UR_SIZE;
     }
     cd->background=0;
   }
@@ -699,6 +816,7 @@ static void do_cm206_request(void)
     }
     error=0;
     for (i=0; i<CURRENT->nr_sectors; i++) {
+      int e1, e2;
       cd_sec_no = (CURRENT->sector+i)/BLOCKS_ISO; /* 4 times 512 bytes */
       quarter = (CURRENT->sector+i) % BLOCKS_ISO; 
       dest = CURRENT->buffer + i*LINUX_BLOCK_SIZE;
@@ -708,12 +826,14 @@ static void do_cm206_request(void)
          + (cd_sec_no-cd->sector_first)*RAW_SECTOR_SIZE;
        memcpy(dest, source, LINUX_BLOCK_SIZE); 
       }
-      else if (!try_adapter(cd_sec_no) || !read_sector(cd_sec_no)) {
+      else if (!(e1=try_adapter(cd_sec_no)) || 
+              !(e2=read_sector(cd_sec_no))) {
        source =  ((uch *) cd->sector)+16+quarter*LINUX_BLOCK_SIZE;
        memcpy(dest, source, LINUX_BLOCK_SIZE); 
       }
       else {
        error=1;
+       debug(("cm206_request: %d %d\n", e1, e2));
       }
     }
     end_request(!error);
@@ -758,21 +878,22 @@ inline uch normalize_track(uch track)
 
 /* This function does a binary search for track start. It records all
  * tracks seen in the process. Input $track$ must be between 1 and
- * #-of-tracks+1 */
+ * #-of-tracks+1.  Note that the start of the disc must be in toc[1].fsm. 
+ */
 int get_toc_lba(uch track)
 {
-  int max=74*60*75-150, min=0;
+  int max=74*60*75-150, min=fsm2lba(cd->toc[1].fsm);
   int i, lba, l, old_lba=0;
   uch * q = cd->q;
   uch ct;                      /* current track */
   int binary=0;
-  const skip = 3*60*75;
+  const skip = 3*60*75;                /* 3 minutes */
 
   for (i=track; i>0; i--) if (cd->toc[i].track) {
     min = fsm2lba(cd->toc[i].fsm);
     break;
   }
-  lba = min + skip;            /* 3 minutes */
+  lba = min + skip;
   do {
     seek(lba); 
     type_1_command(c_read_current_q, 10, q);
@@ -811,11 +932,11 @@ void update_toc_entry(uch track)
 int read_toc_header(struct cdrom_tochdr * hp)
 {
   if (!FIRST_TRACK) get_disc_status();
-  if (hp && DISC_STATUS & cds_all_audio) { /* all audio */
+  if (hp) { 
     int i;
     hp->cdth_trk0 = FIRST_TRACK;
-    hp->cdth_trk1 = LAST_TRACK;
-    cd->toc[1].track=1;                /* fill in first track position */
+    hp->cdth_trk1 = LAST_TRACK; 
+                               /* fill in first track position */
     for (i=0; i<3; i++) cd->toc[1].fsm[i] = cd->disc_status[3+i];
     update_toc_entry(LAST_TRACK+1);            /* find most entries */
     return 0;
@@ -988,7 +1109,7 @@ int cm206_media_changed(struct cdrom_device_info * cdi, int disc_nr)
   else return -EIO;
 }
 
-/* The new Uniform cdrom support. Routines should be concise, most of
+/* The new generic cdrom support. Routines should be concise, most of
    the logic should be in cdrom.c */
 
 /* returns number of times device is in use */
@@ -1019,6 +1140,24 @@ int cm206_drive_status(struct cdrom_device_info * cdi, int slot_nr)
   return CDS_DISC_OK;
 }
  
+/* gives current state of disc in drive */
+int cm206_disc_status(struct cdrom_device_info * cdi)
+{
+  uch xa;
+  get_drive_status();
+  if ((cd->dsb & dsb_not_useful) | !(cd->dsb & dsb_disc_present))
+    return CDS_NO_DISC;
+  get_disc_status();
+  if (DISC_STATUS & cds_all_audio) return CDS_AUDIO;
+  xa = DISC_STATUS >> 4;
+  switch (xa) {
+  case 0: return CDS_DATA_1;   /* can we detect CDS_DATA_2? */
+  case 1: return CDS_XA_2_1;   /* untested */
+  case 2: return CDS_XA_2_2;
+  }
+  return 0;
+}
+
 /* locks or unlocks door lock==1: lock; return 0 upon success */
 int cm206_lock_door(struct cdrom_device_info * cdi, int lock)
 {
@@ -1029,7 +1168,7 @@ int cm206_lock_door(struct cdrom_device_info * cdi, int lock)
 }
   
 /* Although a session start should be in LBA format, we return it in 
-   MSF format because it is slightly easier, and the new Uniform ioctl
+   MSF format because it is slightly easier, and the new generic ioctl
    will take care of the necessary conversion. */
 int cm206_get_last_session(struct cdrom_device_info * cdi, 
                           struct cdrom_multisession * mssp) 
@@ -1114,7 +1253,9 @@ static struct cdrom_device_ops cm206_dops = {
   cm206_audio_ioctl,           /* audio ioctl */
   cm206_ioctl,                 /* device-specific ioctl */
   CDC_CLOSE_TRAY | CDC_OPEN_TRAY | CDC_LOCK | CDC_MULTI_SESSION |
-    CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO, /* capability */
+    CDC_MEDIA_CHANGED | CDC_MCN | CDC_PLAY_AUDIO | CDC_SELECT_SPEED |
+    CDC_IOCTLS | CDC_DRIVE_STATUS, 
+    /* capability */
   1,                           /* number of minor devices */
 };
 
@@ -1206,7 +1347,7 @@ __initfunc(int cm206_init(void))
   uch e=0;
   long int size=sizeof(struct cm206_struct);
 
-  printk(KERN_INFO VERSION);
+  printk(KERN_INFO "cm206 cdrom driver " REVISION);
   cm206_base = probe_base_port(auto_probe ? 0 : cm206_base);
   if (!cm206_base) {
     printk(" can't find adapter!\n");
@@ -1233,14 +1374,14 @@ __initfunc(int cm206_init(void))
   /* Now, the problem here is that reset_cm260 can generate an
      interrupt. It seems that this can cause a kernel oops some time
      later. So we wait a while and `service' this interrupt. */
-  udelay(10);
+  udelay(1000);
   outw(dc_normal | READ_AHEAD, r_data_control);
   sti();
   printk(" using IRQ %d\n", cm206_irq);
 #endif
   if (send_receive_polled(c_drive_configuration) != c_drive_configuration) 
     {
-      printk(" drive not there\n");
+      printk(KERN_INFO " drive not there\n");
       cleanup(1);
       return -EIO;
     }
@@ -1257,16 +1398,17 @@ __initfunc(int cm206_init(void))
   }
   printk(".\n");
   if (register_blkdev(MAJOR_NR, "cm206", &cdrom_fops) != 0) {
-    printk("Cannot register for major %d!\n", MAJOR_NR);
+    printk(KERN_INFO "Cannot register for major %d!\n", MAJOR_NR);
     cleanup(3);
     return -EIO;
   }
   if (register_cdrom(&cm206_info) != 0) {
-    printk("Cannot register for cdrom %d!\n", MAJOR_NR);
+    printk(KERN_INFO "Cannot register for cdrom %d!\n", MAJOR_NR);
     cleanup(3);
     return -EIO;
   }    
   blk_dev[MAJOR_NR].request_fn = DEVICE_REQUEST;
+  blksize_size[MAJOR_NR] = cm206_blocksizes;
   read_ahead[MAJOR_NR] = 16;   /* reads ahead what? */
   init_bh(CM206_BH, cm206_bh);
 
@@ -1336,6 +1478,6 @@ __initfunc(void cm206_setup(char *s, int *p))
 #endif /* MODULE */
 /*
  * Local variables:
- * compile-command: "gcc -DMODULE -D__KERNEL__ -I. -I/usr/src/linux/include/linux -Wall -Wstrict-prototypes -O2 -m486 -c cm206.c -o cm206.o"
+ * compile-command: "gcc -D__KERNEL__ -I/usr/src/linux/include -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer -D__SMP__ -pipe -fno-strength-reduce -m486 -DCPU=486 -D__SMP__ -DMODULE -DMODVERSIONS -include /usr/src/linux/include/linux/modversions.h  -c -o cm206.o cm206.c"
  * End:
  */
index 13ac426700035375ee4f93d97db03528c6a5d87d..9855da1378c19d14de3be02bf95ea60cdb5422cb 100644 (file)
@@ -110,7 +110,7 @@ if [ "$CONFIG_ALPHA_BOOK1" = "y" ]; then
 fi
 tristate 'Video For Linux' CONFIG_VIDEO_DEV
 dep_tristate 'BT848 Video For Linux' CONFIG_VIDEO_BT848 $CONFIG_VIDEO_DEV
-#dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV
+dep_tristate 'Quickcam BW Video For Linux' CONFIG_VIDEO_BWQCAM $CONFIG_VIDEO_DEV
 dep_tristate 'Mediavision Pro Movie Studio Video For Linux' CONFIG_VIDEO_PMS $CONFIG_VIDEO_DEV
 tristate '/dev/nvram support' CONFIG_NVRAM
 tristate 'PC joystick support' CONFIG_JOYSTICK
index 219676143913cdf844f210d3a8b3be369d376cfd..61a09c639bf483452c60ac731bc960d4e1b8286e 100644 (file)
@@ -1270,7 +1270,7 @@ static int bttv_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.flags&=~(VIDEO_AUDIO_MUTE|VIDEO_AUDIO_MUTABLE);
                        v.flags|=VIDEO_AUDIO_MUTABLE;
                        strcpy(v.name,"TV");
-                       if(copy_to_user(&v,arg,sizeof(v)))
+                       if(copy_to_user(arg,&v,sizeof(v)))
                                return -EFAULT;
                        return 0;
                }
diff --git a/drivers/char/bw-qcam.c b/drivers/char/bw-qcam.c
new file mode 100644 (file)
index 0000000..a02c3c1
--- /dev/null
@@ -0,0 +1,877 @@
+/*
+ *    QuickCam Driver For Video4Linux.
+ *
+ *     This version only works as a module.
+ *
+ *     Video4Linux conversion work by Alan Cox.
+ */
+
+/* qcam-lib.c -- Library for programming with the Connectix QuickCam.
+ * See the included documentation for usage instructions and details
+ * of the protocol involved. */
+
+
+/* Version 0.5, August 4, 1996 */
+/* Version 0.7, August 27, 1996 */
+/* Version 0.9, November 17, 1996 */
+
+
+/******************************************************************
+
+Copyright (C) 1996 by Scott Laird
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+#include <linux/module.h>
+#include <linux/config.h>
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/kernel.h>
+#include <linux/malloc.h>
+#include <linux/mm.h>
+#include <linux/ioport.h>
+#include <asm/io.h>
+#include <linux/sched.h>
+#include <linux/videodev.h>
+#include <linux/version.h>
+#include <asm/uaccess.h>
+
+#include "bw-qcam.h"
+
+extern __inline__ int read_lpstatus(struct qcam_device *q)
+{
+       return inb_p(q->port+1);
+}
+
+extern __inline__ int read_lpcontrol(struct qcam_device *q)
+{
+       return inb_p(q->port+2);
+}
+
+extern __inline__ int read_lpdata(struct qcam_device *q)
+{
+       return inb_p(q->port);
+}
+
+extern __inline__ void write_lpdata(struct qcam_device *q, int d)
+{
+       outb_p(d, q->port);
+}
+
+extern __inline__ void write_lpcontrol(struct qcam_device *q,int d)
+{
+       outb(d, q->port+2);
+}
+
+static int qc_waithand(struct qcam_device *q, int val);
+static int qc_command(struct qcam_device *q, int command);
+static int qc_readparam(struct qcam_device *q);
+static int qc_setscanmode(struct qcam_device *q);
+static int qc_readbytes(struct qcam_device *q, char buffer[]);
+
+static struct video_device qcam_template;
+
+static int qc_calibrate(struct qcam_device *q)
+{
+       /*
+        *      Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
+        *      The white balance is an individiual value for each
+        *      quickcam.
+        */
+
+       int value;
+       int count = 0;
+
+       qc_command(q, 27);      /* AutoAdjustOffset */
+       qc_command(q, 0);       /* Dummy Parameter, ignored by the camera */
+
+       /* GetOffset (33) will read 255 until autocalibration */
+       /* is finished. After that, a value of 1-254 will be */
+       /* returned. */
+
+       do {
+               qc_command(q, 33);
+               value = qc_readparam(q);
+               udelay(1000);
+               schedule();
+               count++;
+       } while (value == 0xff && count<2048);
+
+       q->whitebal = value;
+       return value;
+}
+
+/* Initialize the QuickCam driver control structure.  This is where
+ * defaults are set for people who don't have a config file.*/
+
+static struct qcam_device *qcam_init(int port)
+{
+       struct qcam_device *q;
+       
+       if(check_region(port,3))
+       {
+               printk(KERN_ERR "qcam: I/O port 0x%03X in use.\n", port);
+               return NULL;
+       }
+       
+       q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
+       
+       memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
+
+       q->port = port;         /* Port 0 == Autoprobe */
+       q->port_mode = (QC_ANY | QC_NOTSET);
+       q->width = 320;
+       q->height = 240;
+       q->bpp = 4;
+       q->transfer_scale = 2;
+       q->contrast = 192;
+       q->brightness = 180;
+       q->whitebal = 105;
+       q->top = 1;
+       q->left = 14;
+       q->mode = -1;
+       return q;
+}
+
+
+/* qc_command is probably a bit of a misnomer -- it's used to send
+ * bytes *to* the camera.  Generally, these bytes are either commands
+ * or arguments to commands, so the name fits, but it still bugs me a
+ * bit.  See the documentation for a list of commands. */
+
+static int qc_command(struct qcam_device *q, int command)
+{
+       int n1, n2;
+       int cmd;
+
+       write_lpdata(q, command);
+       write_lpcontrol(q, 6);
+
+       n1 = qc_waithand(q, 1);
+
+       write_lpcontrol(q, 0xe);
+       n2 = qc_waithand(q, 0);
+
+       cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+       return cmd;
+}
+
+static int qc_readparam(struct qcam_device *q)
+{
+       int n1, n2;
+       int cmd;
+
+       write_lpcontrol(q, 6);
+       n1 = qc_waithand(q, 1);
+
+       write_lpcontrol(q, 0xe);
+       n2 = qc_waithand(q, 0);
+
+       cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+       return cmd;
+}
+
+/* qc_waithand busy-waits for a handshake signal from the QuickCam.
+ * Almost all communication with the camera requires handshaking. */
+
+static int qc_waithand(struct qcam_device *q, int val)
+{
+       int status;
+       int runs=0;
+
+       if (val)
+       {
+               while (!((status = read_lpstatus(q)) & 8))
+               {
+                       /* 1000 is enough spins on the I/O for all normal
+                          cases, at that point we start to poll slowly 
+                          until the camera wakes up */
+                          
+                       if(runs++>1000)
+                       {
+                               current->state=TASK_INTERRUPTIBLE;
+                               current->timeout = jiffies+HZ/10;
+                               schedule();
+                       }
+                       if(runs>1050)
+                               return -1;
+               }
+       }
+       else
+       {
+               while (((status = read_lpstatus(q)) & 8))
+               {
+                       /* 1000 is enough spins on the I/O for all normal
+                          cases, at that point we start to poll slowly 
+                          until the camera wakes up */
+                          
+                       if(runs++>1000)
+                       {
+                               current->state=TASK_INTERRUPTIBLE;
+                               current->timeout = jiffies+HZ/10;
+                               schedule();
+                       }
+                       if(runs++>1050) /* 5 seconds */
+                               return -1;
+               }
+       }
+
+       return status;
+}
+
+/* Waithand2 is used when the qcam is in bidirectional mode, and the
+ * handshaking signal is CamRdy2 (bit 0 of data reg) instead of CamRdy1
+ * (bit 3 of status register).  It also returns the last value read,
+ * since this data is useful. */
+
+static unsigned int qc_waithand2(struct qcam_device *q, int val)
+{
+       unsigned int status;
+       int runs=0;
+       
+       do 
+       {
+               status = read_lpdata(q);
+               /* 1000 is enough spins on the I/O for all normal
+                  cases, at that point we start to poll slowly 
+                  until the camera wakes up */
+                  
+               if(runs++>1000)
+               {
+                       current->state=TASK_INTERRUPTIBLE;
+                       current->timeout = jiffies+HZ/10;
+                       schedule();
+               }
+               if(runs++>1050) /* 5 seconds */
+                       return 0;
+       }
+       while ((status & 1) != val);
+
+       return status;
+}
+
+
+/* Try to detect a QuickCam.  It appears to flash the upper 4 bits of
+   the status register at 5-10 Hz.  This is only used in the autoprobe
+   code.  Be aware that this isn't the way Connectix detects the
+   camera (they send a reset and try to handshake), but this should be
+   almost completely safe, while their method screws up my printer if
+   I plug it in before the camera. */
+
+static int qc_detect(struct qcam_device *q)
+{
+       int reg, lastreg;
+       int count = 0;
+       int i;
+
+       lastreg = reg = read_lpstatus(q) & 0xf0;
+
+       for (i = 0; i < 300; i++) 
+       {
+               reg = read_lpstatus(q) & 0xf0;
+               if (reg != lastreg)
+                       count++;
+               lastreg = reg;
+               udelay(1000);
+       }
+
+       /* Be liberal in what you accept...  */
+
+       if (count > 30 && count < 200)
+               return 1;       /* found */
+       else
+               return 0;       /* not found */
+}
+
+
+/* Reset the QuickCam.  This uses the same sequence the Windows
+ * QuickPic program uses.  Someone with a bi-directional port should
+ * check that bi-directional mode is detected right, and then
+ * implement bi-directional mode in qc_readbyte(). */
+
+static void qc_reset(struct qcam_device *q)
+{
+       switch (q->port_mode & QC_FORCE_MASK) 
+       {
+               case QC_FORCE_UNIDIR:
+                       q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+                       break;
+
+               case QC_FORCE_BIDIR:
+                       q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+                       break;
+
+               case QC_ANY:
+                       write_lpcontrol(q, 0x20);
+                       write_lpdata(q, 0x75);
+       
+                       if (read_lpdata(q) != 0x75) {
+                               q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+                       } else {
+                               q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+                       }
+                       break;
+       }
+
+       write_lpcontrol(q, 0xb);
+       udelay(250);
+       write_lpcontrol(q, 0xe);
+       qc_setscanmode(q);              /* in case port_mode changed */
+}
+
+
+/* Decide which scan mode to use.  There's no real requirement that
+ * the scanmode match the resolution in q->height and q-> width -- the
+ * camera takes the picture at the resolution specified in the
+ * "scanmode" and then returns the image at the resolution specified
+ * with the resolution commands.  If the scan is bigger than the
+ * requested resolution, the upper-left hand corner of the scan is
+ * returned.  If the scan is smaller, then the rest of the image
+ * returned contains garbage. */
+
+static int qc_setscanmode(struct qcam_device *q)
+{
+       switch (q->transfer_scale) 
+       {
+               case 1:
+                       q->mode = 0;
+                       break;
+               case 2:
+                       q->mode = 4;
+                       break;
+               case 4:
+                       q->mode = 8;
+                       break;
+       }
+
+       switch (q->bpp) 
+       {
+               case 4:
+                       break;
+               case 6:
+                       q->mode += 2;
+                       break;
+       }
+
+       switch (q->port_mode & QC_MODE_MASK) 
+       {
+               case QC_BIDIR:
+                       q->mode += 1;
+                       break;
+               case QC_NOTSET:
+               case QC_UNIDIR:
+                       break;
+       }
+       return 0;
+}
+
+
+/* Reset the QuickCam and program for brightness, contrast,
+ * white-balance, and resolution. */
+
+void qc_set(struct qcam_device *q)
+{
+       int val;
+       int val2;
+
+       qc_reset(q);
+
+       /* Set the brightness.  Yes, this is repetitive, but it works.
+        * Shorter versions seem to fail subtly.  Feel free to try :-). */
+       /* I think the problem was in qc_command, not here -- bls */
+       
+       qc_command(q, 0xb);
+       qc_command(q, q->brightness);
+
+       val = q->height / q->transfer_scale;
+       qc_command(q, 0x11);
+       qc_command(q, val);
+       if ((q->port_mode & QC_MODE_MASK) == QC_UNIDIR && q->bpp == 6) {
+               /* The normal "transfers per line" calculation doesn't seem to work
+                  as expected here (and yet it works fine in qc_scan).  No idea
+                  why this case is the odd man out.  Fortunately, Laird's original
+                  working version gives me a good way to guess at working values.
+                  -- bls */
+               val = q->width;
+               val2 = q->transfer_scale * 4;
+       } else {
+               val = q->width * q->bpp;
+               val2 = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
+                   q->transfer_scale;
+       }
+       val = (val + val2 - 1) / val2;
+       qc_command(q, 0x13);
+       qc_command(q, val);
+
+       /* Setting top and left -- bls */
+       qc_command(q, 0xd);
+       qc_command(q, q->top);
+       qc_command(q, 0xf);
+       qc_command(q, q->left / 2);
+
+       qc_command(q, 0x19);
+       qc_command(q, q->contrast);
+       qc_command(q, 0x1f);
+       qc_command(q, q->whitebal);
+}
+
+
+/* Qc_readbytes reads some bytes from the QC and puts them in
+   the supplied buffer.  It returns the number of bytes read,
+   or -1 on error. */
+
+extern __inline__ int qc_readbytes(struct qcam_device *q, char buffer[])
+{
+       int ret=1;
+       unsigned int hi, lo;
+       unsigned int hi2, lo2;
+       static int state = 0;
+
+       if (buffer == NULL) 
+       {
+               state = 0;
+               return 0;
+       }
+       
+       switch (q->port_mode & QC_MODE_MASK) 
+       {
+               case QC_BIDIR:          /* Bi-directional Port */
+                       write_lpcontrol(q, 0x26);
+                       lo = (qc_waithand2(q, 1) >> 1);
+                       hi = (read_lpstatus(q) >> 3) & 0x1f;
+                       write_lpcontrol(q, 0x2e);
+                       lo2 = (qc_waithand2(q, 0) >> 1);
+                       hi2 = (read_lpstatus(q) >> 3) & 0x1f;
+                       switch (q->bpp) 
+                       {
+                               case 4:
+                                       buffer[0] = lo & 0xf;
+                                       buffer[1] = ((lo & 0x70) >> 4) | ((hi & 1) << 3);
+                                       buffer[2] = (hi & 0x1e) >> 1;
+                                       buffer[3] = lo2 & 0xf;
+                                       buffer[4] = ((lo2 & 0x70) >> 4) | ((hi2 & 1) << 3);
+                                       buffer[5] = (hi2 & 0x1e) >> 1;
+                                       ret = 6;
+                                       break;
+                               case 6:
+                                       buffer[0] = lo & 0x3f;
+                                       buffer[1] = ((lo & 0x40) >> 6) | (hi << 1);
+                                       buffer[2] = lo2 & 0x3f;
+                                       buffer[3] = ((lo2 & 0x40) >> 6) | (hi2 << 1);
+                                       ret = 4;
+                                       break;
+                       }
+                       break;
+
+               case QC_UNIDIR: /* Unidirectional Port */
+                       write_lpcontrol(q, 6);
+                       lo = (qc_waithand(q, 1) & 0xf0) >> 4;
+                       write_lpcontrol(q, 0xe);
+                       hi = (qc_waithand(q, 0) & 0xf0) >> 4;
+
+                       switch (q->bpp) 
+                       {
+                               case 4:
+                                       buffer[0] = lo;
+                                       buffer[1] = hi;
+                                       ret = 2;
+                                       break;
+                               case 6:
+                                       switch (state) 
+                                       {
+                                               case 0:
+                                                       buffer[0] = (lo << 2) | ((hi & 0xc) >> 2);
+                                                       q->saved_bits = (hi & 3) << 4;
+                                                       state = 1;
+                                                       ret = 1;
+                                                       break;
+                                               case 1:
+                                                       buffer[0] = lo | q->saved_bits;
+                                                       q->saved_bits = hi << 2;
+                                                       state = 2;
+                                                       ret = 1;
+                                                       break;
+                                               case 2:
+                                                       buffer[0] = ((lo & 0xc) >> 2) | q->saved_bits;
+                                                       buffer[1] = ((lo & 3) << 4) | hi;
+                                                       state = 0;
+                                                       ret = 2;
+                                                       break;
+                                       }
+                                       break;
+                       }
+                       break;
+       }
+       return ret;
+}
+
+/* requests a scan from the camera.  It sends the correct instructions
+ * to the camera and then reads back the correct number of bytes.  In
+ * previous versions of this routine the return structure contained
+ * the raw output from the camera, and there was a 'qc_convertscan'
+ * function that converted that to a useful format.  In version 0.3 I
+ * rolled qc_convertscan into qc_scan and now I only return the
+ * converted scan.  The format is just an one-dimensional array of
+ * characters, one for each pixel, with 0=black up to n=white, where
+ * n=2^(bit depth)-1.  Ask me for more details if you don't understand
+ * this. */
+
+long qc_capture(struct qcam_device * q, char *buf, unsigned long len)
+{
+       int i, j, k;
+       int bytes;
+       int linestotrans, transperline;
+       int divisor;
+       int pixels_per_line;
+       int pixels_read = 0;
+       int got=0;
+       char buffer[6];
+       int  shift=8-q->bpp;
+       char invert;
+
+       if (q->mode == -1) 
+               return -ENXIO;
+
+       qc_command(q, 0x7);
+       qc_command(q, q->mode);
+
+       if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) 
+       {
+               write_lpcontrol(q, 0x2e);       /* turn port around */
+               write_lpcontrol(q, 0x26);
+               (void) qc_waithand(q, 1);
+               write_lpcontrol(q, 0x2e);
+               (void) qc_waithand(q, 0);
+       }
+       
+       /* strange -- should be 15:63 below, but 4bpp is odd */
+       invert = (q->bpp == 4) ? 16 : 63;
+
+       linestotrans = q->height / q->transfer_scale;
+       pixels_per_line = q->width / q->transfer_scale;
+       transperline = q->width * q->bpp;
+       divisor = (((q->port_mode & QC_MODE_MASK) == QC_BIDIR) ? 24 : 8) *
+           q->transfer_scale;
+       transperline = (transperline + divisor - 1) / divisor;
+
+       for (i = 0; i < linestotrans; i++) 
+       {
+               for (pixels_read = j = 0; j < transperline; j++) 
+               {
+                       bytes = qc_readbytes(q, buffer);
+                       for (k = 0; k < bytes && (pixels_read + k) < pixels_per_line; k++) 
+                       {
+                               int o;
+                               if (buffer[k] == 0 && invert == 16) 
+                               {
+                                       /* 4bpp is odd (again) -- inverter is 16, not 15, but output
+                                          must be 0-15 -- bls */
+                                       buffer[k] = 16;
+                               }
+                               o=i*pixels_per_line + pixels_read + k;
+                               if(o<len)
+                               {
+                                       got++;
+                                       put_user((invert - buffer[k])<<shift, buf+o);
+                               }
+                       }
+                       pixels_read += bytes;
+               }
+               (void) qc_readbytes(q, 0);      /* reset state machine */
+       }
+
+       if ((q->port_mode & QC_MODE_MASK) == QC_BIDIR) 
+       {
+               write_lpcontrol(q, 2);
+               write_lpcontrol(q, 6);
+               udelay(3);
+               write_lpcontrol(q, 0xe);
+       }
+       if(got<len)
+               return got;
+       return len;
+}
+
+/*
+ *     Video4linux interfacing
+ */
+
+static int qcam_open(struct video_device *dev, int flags)
+{
+       MOD_INC_USE_COUNT;
+       return 0;
+}
+
+static void qcam_close(struct video_device *dev)
+{
+       MOD_DEC_USE_COUNT;
+}
+
+static int qcam_init_done(struct video_device *dev)
+{
+       return 0;
+}
+
+static long qcam_write(struct video_device *v, const char *buf, unsigned long count, int noblock)
+{
+       return -EINVAL;
+}
+
+static int qcam_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
+{
+       struct qcam_device *qcam=(struct qcam_device *)dev;
+       
+       switch(cmd)
+       {
+               case VIDIOCGCAP:
+               {
+                       struct video_capability b;
+                       strcpy(b.name, "Quickcam");
+                       b.type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_MONOCHROME;
+                       b.channels = 1;
+                       b.audios = 0;
+                       b.maxwidth = 320;
+                       b.maxheight = 240;
+                       b.minwidth = 80;
+                       b.minheight = 60;
+                       if(copy_to_user(arg, &b,sizeof(b)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCGCHAN:
+               {
+                       struct video_channel v;
+                       if(copy_from_user(&v, arg, sizeof(v)))
+                               return -EFAULT;
+                       if(v.channel!=0)
+                               return -EINVAL;
+                       v.flags=0;
+                       v.tuners=0;
+                       /* Good question.. its composite or SVHS so.. */
+                       v.type = VIDEO_TYPE_CAMERA;
+                       strcpy(v.name, "Camera");
+                       if(copy_to_user(arg, &v, sizeof(v)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCSCHAN:
+               {
+                       int v;
+                       if(copy_from_user(&v, arg,sizeof(v)))
+                               return -EFAULT;
+                       if(v!=0)
+                               return -EINVAL;
+                       return 0;
+               }
+               case VIDIOCGTUNER:
+               {
+                       struct video_tuner v;
+                       if(copy_from_user(&v, arg, sizeof(v))!=0)
+                               return -EFAULT;
+                       if(v.tuner)
+                               return -EINVAL;
+                       strcpy(v.name, "Format");
+                       v.rangelow=0;
+                       v.rangehigh=0;
+                       v.flags= 0;
+                       v.mode = VIDEO_MODE_AUTO;
+                       if(copy_to_user(arg,&v,sizeof(v))!=0)
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCSTUNER:
+               {
+                       struct video_tuner v;
+                       if(copy_from_user(&v, arg, sizeof(v))!=0)
+                               return -EFAULT;
+                       if(v.tuner)
+                               return -EINVAL;
+                       if(v.mode!=VIDEO_MODE_AUTO)
+                               return -EINVAL;
+                       return 0;
+               }
+               case VIDIOCGPICT:
+               {
+                       struct video_picture p;
+                       p.colour=0x8000;
+                       p.hue=0x8000;
+                       p.brightness=qcam->brightness<<8;
+                       p.contrast=qcam->contrast<<8;
+                       p.whiteness=qcam->whitebal<<8;
+                       p.depth=qcam->bpp;
+                       p.palette=VIDEO_PALETTE_GREY;
+                       if(copy_to_user(arg, &p, sizeof(p)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCSPICT:
+               {
+                       struct video_picture p;
+                       if(copy_from_user(&p, arg, sizeof(p)))
+                               return -EFAULT;
+                       if(p.palette!=VIDEO_PALETTE_GREY)
+                               return -EINVAL;
+                       if(p.depth!=4 && p.depth!=6)
+                               return -EINVAL;
+                       
+                       /*
+                        *      Now load the camera.
+                        */
+
+                       qcam->brightness = p.brightness>>8;
+                       qcam->contrast = p.contrast>>8;
+                       qcam->whitebal = p.whiteness>>8;
+                       qcam->bpp = p.depth;
+                       
+                       qc_setscanmode(qcam);
+                       return 0;
+               }
+               case VIDIOCSWIN:
+               {
+                       struct video_window vw;
+                       if(copy_from_user(&vw, arg,sizeof(vw)))
+                               return -EFAULT;
+                       if(vw.flags)
+                               return -EINVAL;
+                       if(vw.clipcount)
+                               return -EINVAL;
+                       if(vw.height<60||vw.height>240)
+                               return -EINVAL;
+                       if(vw.width<80||vw.width>320)
+                               return -EINVAL;
+                               
+                       qcam->width = 320;
+                       qcam->height = 240;
+                       qcam->transfer_scale = 4;
+                       
+                       if(vw.width>=160 && vw.height>=120)
+                       {
+                               qcam->transfer_scale = 2;
+                       }
+                       if(vw.width>=320 && vw.height>=240)
+                       {
+                               qcam->width = 320;
+                               qcam->height = 240;
+                               qcam->transfer_scale = 1;
+                       }
+                       qc_setscanmode(qcam);
+                       /* Ok we figured out what to use from our wide choice */
+                       return 0;
+               }
+               case VIDIOCGWIN:
+               {
+                       struct video_window vw;
+                       vw.x=0;
+                       vw.y=0;
+                       vw.width=qcam->width/qcam->transfer_scale;
+                       vw.height=qcam->height/qcam->transfer_scale;
+                       vw.chromakey=0;
+                       vw.flags=0;
+                       if(copy_to_user(arg, &vw, sizeof(vw)))
+                               return -EFAULT;
+                       return 0;
+               }
+               case VIDIOCCAPTURE:
+                       return -EINVAL;
+               case VIDIOCGFBUF:
+                       return -EINVAL;
+               case VIDIOCSFBUF:
+                       return -EINVAL;
+               case VIDIOCKEY:
+                       return 0;
+               case VIDIOCGFREQ:
+                       return -EINVAL;
+               case VIDIOCSFREQ:
+                       return -EINVAL;
+               case VIDIOCGAUDIO:
+                       return -EINVAL;
+               case VIDIOCSAUDIO:
+                       return -EINVAL;
+               default:
+                       return -ENOIOCTLCMD;
+       }
+       return 0;
+}
+
+static long qcam_read(struct video_device *v, char *buf, unsigned long count,  int noblock)
+{
+       struct qcam_device *qcam=(struct qcam_device *)v;
+       int len;
+       /* Probably should have a semaphore against multiple users */
+       qc_reset(qcam);
+       len=qc_capture(qcam, buf,count);
+       return len;
+}
+
+static struct video_device qcam_template=
+{
+       "Connectix Quickcam",
+       VID_TYPE_CAPTURE,
+       VID_HARDWARE_QCAM_BW,
+       qcam_open,
+       qcam_close,
+       qcam_read,
+       qcam_write,
+       qcam_ioctl,
+       NULL,
+       qcam_init_done,
+       NULL,
+       0,
+       0
+};
+
+
+int io=0x378;
+
+MODULE_PARM(io,"i");
+
+static struct qcam_device *qcam;
+
+int init_module(void)
+{
+       qcam=qcam_init(io);
+       if(qcam==NULL)
+               return -ENODEV;
+               
+       qc_reset(qcam);
+       
+       if(qc_detect(qcam)==0)
+       {
+               kfree(qcam);
+               return -ENODEV;
+       }
+       qc_calibrate(qcam);
+       
+       printk(KERN_INFO "Connectix Quickcam at 0x%03X\n", qcam->port);
+       
+       if(video_register_device(&qcam->vdev)==-1)
+               return -ENODEV;
+       return 0;
+}
+
+void cleanup_module(void)
+{
+       video_unregister_device(&qcam->vdev);
+       kfree(qcam);
+}
diff --git a/drivers/char/bw-qcam.h b/drivers/char/bw-qcam.h
new file mode 100644 (file)
index 0000000..22872be
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ *     Video4Linux bw-qcam driver
+ *
+ *     Derived from code..
+ */
+
+/******************************************************************
+
+Copyright (C) 1996 by Scott Laird
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
+OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+OTHER DEALINGS IN THE SOFTWARE.
+
+******************************************************************/
+
+/* One from column A... */
+#define QC_NOTSET 0
+#define QC_UNIDIR 1
+#define QC_BIDIR  2
+#define QC_SERIAL 3
+
+/* ... and one from column B */
+#define QC_ANY          0x00
+#define QC_FORCE_UNIDIR 0x10
+#define QC_FORCE_BIDIR  0x20
+#define QC_FORCE_SERIAL 0x30
+/* in the port_mode member */
+
+#define QC_MODE_MASK    0x07
+#define QC_FORCE_MASK   0x70
+
+#define MAX_HEIGHT 243
+#define MAX_WIDTH 336
+
+struct qcam_device {
+       struct video_device vdev;
+       int width, height;
+       int bpp;
+       int mode;
+       int contrast, brightness, whitebal;
+       int port;
+       int port_mode;
+       int transfer_scale;
+       int top, left;
+       unsigned int saved_bits;
+};
+
index b0383154239a8a261c813ee474126fe5b7909fc0..61837b461786edda2f13246f7ae4922e93f57356 100644 (file)
@@ -419,8 +419,8 @@ static void pms_swsense(short sense)
        }
        else if(decoder==PHILIPS1)
        {
-               i2c_write(0x42, 0x08, sense);
-               i2c_write(0x42, 0x09, sense);
+               i2c_write(0x42, 0x0A, sense);
+               i2c_write(0x42, 0x0B, sense);
        }
 }
 
@@ -428,13 +428,11 @@ static void pms_chromagain(short chroma)
 {
        if(decoder==PHILIPS2)
        {
-               i2c_write(0x8A, 0x0A, chroma);
-               i2c_write(0x8A, 0x0B, chroma);
+               i2c_write(0x8A, 0x11, chroma);
        }
        else if(decoder==PHILIPS1)
        {
-               i2c_write(0x42, 0x08, chroma);
-               i2c_write(0x42, 0x09, chroma);
+               i2c_write(0x42, 0x11, chroma);
        }
 }
 
@@ -522,21 +520,21 @@ static void pms_horzdeci(short decinum, short deciden)
                deciden=640;    /* 768 would be ideal */
        }
        
-       while(decinum%2==0 && deciden%2==0)
+       while(((decinum|deciden)&1)==0)
        {
-               decinum/=2;
-               deciden/=2;
+               decinum>>=1;
+               deciden>>=1;
        }
        while(deciden>32)
        {
-               deciden/=2;
-               decinum=(decinum+1)/2;
+               deciden>>=1;
+               decinum=(decinum+1)>>1;
        }
        if(deciden==32)
                deciden--;
                
        mvv_write(0x24, 0x80|deciden);
-       mvv_write(0x25, deciden);
+       mvv_write(0x25, decinum);
 }
 
 static void pms_resolution(short width, short height)
@@ -554,7 +552,7 @@ static void pms_resolution(short width, short height)
        {
                mvv_write(0x1A, 0xFC);
                mvv_write(0x1B, 0x00);
-               if(height>width)
+               if(height>fg_height)
                        pms_vertdeci(240,240);
                else
                        pms_vertdeci(fg_height,240);
@@ -576,12 +574,12 @@ static void pms_resolution(short width, short height)
        
        mvv_write(0x22, width+8);
        mvv_write(0x23, (width+8)>> 8);
-       
+
        if(standard==1)
                pms_horzdeci(width,640);
        else
                pms_horzdeci(width+8, 768);
-       
+
        mvv_write(0x30, mvv_read(0x30)&0xFE);
        mvv_write(0x08, mvv_read(0x08)|0x01);
        mvv_write(0x01, mvv_read(0x01)&0xFD);
@@ -610,73 +608,40 @@ static void pms_vcrinput(short input)
 
 static int pms_capture(struct pms_device *dev, char *buf, int rgb555, int count)
 {
-       char dump[16];
        int y;
-       int ww= dev->width, wh= dev->height;
-       int dinc, zz;
-       int dw=2*ww, loops;
-       unsigned char r8;
+       int dw = 2*dev->width;
+       char *src = (char *)bus_to_virt((void *)mem_base);
+
+       char tmp[dw+16]; /* using a temp buffer is faster than direct  */
+       int cnt = 0;
        int len=0;
-       
-       short *dst=(short *)buf;
-       short *src=(short *)bus_to_virt((void *)mem_base);
-       
-       if(wh>256)
-       {
-               dinc=2*ww; 
-               zz=wh/2; 
-               loops=2;
-       }
-       else
-       {
-               dinc=ww; 
-               zz=wh; 
-               loops=1;
-       }
-       
-       
-       r8=0x5;
-       if(rgb555)
-               r8|=0x20;
-               
-field_cap:
-       
-       mvv_write(0x08, r8);    /* Capture mode, Enable DRAM, PC enable */
-       
-       for(y=0;y<zz;y++)
-       {
-               int n;
-               
-               len+=16;
-               
-               /*
-                *      Avoid overrunning the given buffer      
-                */
-                
-               n=((char *)dst)-buf;            /* Bytes left in frame */
-               n=count-n;
-               if(n>dw)                        /* But only as many as needed */
-                       n=dw;
-               memcpy(dump, src, 16);          /* Junk */
-               if(n)
-                       copy_to_user(dst, src, n);      /* Data */
-               dst+=dinc;
-               *src=0;                         /* Synchronization */
-       }
-       
-       if(--loops>0)
+       unsigned char r8 = 0x5;  /* value for reg8  */
+
+       if (rgb555)
+               r8 |= 0x20; /* else use untranslated rgb = 565 */
+       mvv_write(0x08,r8); /* capture rgb555/565, init DRAM, PC enable */
+
+/*     printf("%d %d %d %d %d %x %x\n",width,height,voff,nom,den,mvv_buf); */
+  
+       for (y = 0; y < dev->height; y++ ) 
        {
-               mvv_write(0x14, mvv_read(0x14)|0xC0);   /* Other frame */
-               dst=(short *)buf+ww;
-               goto field_cap;
+               *src = 0;  /* synchronisiert neue Zeile */
+               memcpy(tmp, src, dw+16); /* discard 8 word   */
+               cnt -= dev->height;
+               while (cnt <= 0) 
+               { 
+                       /*
+                        *      Dont copy too far
+                        */
+                       int dt=dw;
+                       if(dt+len>count)
+                               dt=count-len;
+                       cnt += dev->height;
+                       copy_to_user(buf, tmp+16, dt);
+                       buf += dt;    
+                       len += dt;
+               }
        }
-       
-       /*
-        *      Set back to capture even frames
-        */
-        
-       if(wh>256)
-               mvv_write(0x14, (mvv_read(0x14)|0x80)&~0x40);
        return len;
 }
 
@@ -738,6 +703,17 @@ static int pms_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        v.tuners=1;
                        /* Good question.. its composite or SVHS so.. */
                        v.type = VIDEO_TYPE_CAMERA;
+                       switch(v.channel)
+                       {
+                               case 0:
+                                       strcpy(v.name, "Composite");break;
+                               case 1:
+                                       strcpy(v.name, "SVideo");break;
+                               case 2:
+                                       strcpy(v.name, "Composite(VCR)");break;
+                               case 3:
+                                       strcpy(v.name, "SVideo(VCR)");break;
+                       }
                        if(copy_to_user(arg, &v, sizeof(v)))
                                return -EFAULT;
                        return 0;
@@ -747,7 +723,7 @@ static int pms_ioctl(struct video_device *dev, unsigned int cmd, void *arg)
                        int v;
                        if(copy_from_user(&v, arg,sizeof(v)))
                                return -EFAULT;
-                       if(v<0 && v>3)
+                       if(v<0 || v>3)
                                return -EINVAL;
                        pms_videosource(v&1);
                        pms_vcrinput(v>>1);
@@ -974,7 +950,8 @@ static int init_mediavision(void)
                idec=1;
        else 
                idec=0;
-               
+
+       printk(KERN_INFO "PMS type is %d\n", idec);             
        if(idec==0)
                return -ENODEV; 
 
@@ -1050,7 +1027,7 @@ MODULE_PARM(mem_base,"i");
 
 int init_module(void)
 {
-       printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.01\n");
+       printk(KERN_INFO "Mediavision Pro Movie Studio driver 0.02\n");
        
        data_port = io_port +1;
        
@@ -1062,6 +1039,7 @@ int init_module(void)
        memcpy(&pms_device, &pms_template, sizeof(pms_template));
        pms_device.height=240;
        pms_device.width=320;
+       pms_swsense(75);
        pms_resolution(320,240);
        return video_register_device((struct video_device *)&pms_device);
 }
index 1c1beddabd93931319fa9cdeefbc982b4a3ebd97..c3408117612bad360180e697f886eb2146dd554d 100644 (file)
@@ -1548,12 +1548,16 @@ static int tty_ioctl(struct inode * inode, struct file * file,
                switch(cmd) {
                case TIOCSBRK:
                case TIOCCBRK:
-                       return tty->driver.ioctl(tty, file, cmd, arg);
+                       if (tty->driver.ioctl)
+                               return tty->driver.ioctl(tty, file, cmd, arg);
+                       return -EINVAL;
                        
                /* These two ioctl's always return success; even if */
                /* the driver doesn't support them. */
                case TCSBRK:
-               case TCSBRKP:                   
+               case TCSBRKP:
+                       if (!tty->driver.ioctl)
+                               return 0;
                        retval = tty->driver.ioctl(tty, file, cmd, arg);
                        if (retval == -ENOIOCTLCMD)
                                retval = 0;
index 77fb908fe6b59c0a81ff5b63113092bbc5038468..11e49a06e27681c7bc0d65dc21bf5bdf06e53fe8 100644 (file)
@@ -56,11 +56,6 @@ static int
 vcs_size(struct inode *inode)
 {
        int size;
-#ifdef CONFIG_MULTIMON
-       int currcons = MINOR(inode->i_rdev) & 127;
-       /* Multimon patch       */
-       if (!vc_cons[currcons].d) return 0;
-#endif
 #ifdef CONFIG_FB_CONSOLE
        int cons = MINOR(inode->i_rdev) & 127;
 
index 576cd2ae30dc908609b7f29dc5b29136d4641da4..5613d8b90e54beea9902d09ee858dd0578f042f1 100644 (file)
@@ -368,7 +368,7 @@ void cleanup_module(void)
 #ifdef CONFIG_WDT_501  
        misc_deregister(&temp_miscdev);
 #endif 
-       notifier_chain_unregister(&reboot_notifier_list, &wdt_notifier);
+       unregister_reboot_notifier(&wdt_notifier);
        release_region(io,8);
        free_irq(irq, NULL);
 }
@@ -388,7 +388,7 @@ __initfunc(int wdt_init(void))
        misc_register(&temp_miscdev);
 #endif 
        request_region(io, 8, "wdt501p");
-       notifier_chain_register(&reboot_notifier_list, &wdt_notifier);
+       register_reboot_notifier(&wdt_notifier);
        return 0;
 }
 
index a1866f07f0c8b1c8976269188b23c32dc3f3c6e9..8a4e5e72f2527276ea11a6b9eab120f806bba63a 100644 (file)
 #define __NO_VERSION__
 #include <linux/module.h>
 #include <linux/isdn.h>
-#include <linux/if_arp.h>
 #include <net/arp.h>
 #include <net/icmp.h>
+#if (LINUX_VERSION_CODE >= 0x020117)
+#include <linux/poll.h>
+#endif
 #include "isdn_common.h"
 #include "isdn_net.h"
 #ifdef CONFIG_ISDN_PPP
 #include "isdn_ppp.h"
 #endif
+#ifndef DEV_NUMBUFFS
+#include <net/pkt_sched.h>
+#endif
 
 /* Prototypes */
 
@@ -209,7 +214,9 @@ int isdn_net_force_dial_lp(isdn_net_local *);
 static int isdn_net_wildmat(char *s, char *p);
 static int isdn_net_start_xmit(struct sk_buff *, struct device *);
 static int isdn_net_xmit(struct device *, isdn_net_local *, struct sk_buff *);
+#ifdef DEV_NUMBUFFS
 static void dev_purge_queues(struct device *dev);      /* move this to net/core/dev.c */
+#endif
 
 char *isdn_net_revision = "$Revision: 1.44 $";
 
@@ -253,7 +260,7 @@ isdn_net_open(struct device *dev)
        /* Fill in the MAC-level header. */
        for (i = 0; i < ETH_ALEN - sizeof(u32); i++)
                dev->dev_addr[i] = 0xfc;
-       memcpy(&(dev->dev_addr[i]), &dev->pa_addr, sizeof(u32));
+       memset(&(dev->dev_addr[i]), 0, sizeof(u32));
 
        /* If this interface has slaves, start them also */
 
@@ -303,8 +310,18 @@ isdn_net_unbind_channel(isdn_net_local * lp)
                dev_kfree_skb(lp->sav_skb, FREE_WRITE);
                lp->sav_skb = NULL;
        }
+#ifdef DEV_NUMBUFFS
        if (!lp->master)        /* purge only for master device */
                dev_purge_queues(&lp->netdev->dev);
+#else
+       if (!lp->master) {      /* reset only master device */
+               /* Moral equivalent of dev_purge_queues():
+                  BEWARE! This chunk of code cannot be called from hardware
+                  interrupt handler. I hope it is true. --ANK
+                */
+               qdisc_reset(lp->netdev->dev.qdisc);
+       }
+#endif
        lp->dialstate = 0;
        dev->rx_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
        dev->st_netdev[isdn_dc2minor(lp->isdn_device, lp->isdn_channel)] = NULL;
@@ -990,7 +1007,6 @@ isdn_net_start_xmit(struct sk_buff *skb, struct device *ndev)
                ndev->trans_start = jiffies;
        }
        if (skb == NULL) {
-               dev_tint(ndev);
                return 0;
        }
        /* Avoid timer-based retransmission conflicts. */
@@ -1466,20 +1482,17 @@ isdn_net_init(struct device *ndev)
 #endif
        ndev->header_cache_update = NULL;
        ndev->mtu = 1500;
-       ndev->flags = IFF_NOARP;
-       ndev->family = AF_INET;
+       ndev->flags = IFF_NOARP|IFF_POINTOPOINT;
        ndev->type = ARPHRD_ETHER;
        ndev->addr_len = ETH_ALEN;
-       ndev->pa_addr = 0;
-       ndev->pa_brdaddr = 0;
-       ndev->pa_mask = 0;
-       ndev->pa_alen = 4;
 
        for (i = 0; i < ETH_ALEN; i++)
                ndev->broadcast[i] = 0xff;
 
+#ifdef DEV_NUMBUFFS
        for (i = 0; i < DEV_NUMBUFFS; i++)
                skb_queue_head_init(&ndev->buffs[i]);
+#endif
 
        /* The ISDN-specific entries in the device structure. */
        ndev->open = &isdn_net_open;
@@ -2247,7 +2260,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                                p->dev.hard_header_cache = NULL;
 #endif
                                p->dev.header_cache_update = NULL;
-                               p->dev.flags = IFF_NOARP;
+                               p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
                        } else {
                                p->dev.hard_header = isdn_net_header;
                                if (cfg->p_encap == ISDN_NET_ENCAP_ETHER) {
@@ -2265,7 +2278,7 @@ isdn_net_setcfg(isdn_net_ioctl_cfg * cfg)
                                        p->dev.hard_header_cache = NULL;
 #endif
                                        p->dev.header_cache_update = NULL;
-                                       p->dev.flags = IFF_NOARP;
+                                       p->dev.flags = IFF_NOARP|IFF_POINTOPOINT;
                                }
                        }
                }
@@ -2585,6 +2598,7 @@ isdn_net_rmall(void)
        return 0;
 }
 
+#ifdef DEV_NUMBUFFS
 /*
  * helper function to flush device queues
  * the better place would be net/core/dev.c
@@ -2600,3 +2614,4 @@ dev_purge_queues(struct device *dev)
        }
 
 }
+#endif
index 4b21f83f99c20d42aec1612c05bceb46c08b9570..8ba0d197d608ff9bbea730dd81ce49f5c33ea027 100644 (file)
@@ -2445,14 +2445,18 @@ isdn_tty_get_msnstr(char *n, char **p)
  * Get phone-number from modem-commandbuffer
  */
 static void
-isdn_tty_getdial(char *p, char *q)
+isdn_tty_getdial(char *p, char *q,int cnt)
 {
        int first = 1;
+       int limit=39;   /* MUST match the size in isdn_tty_parse to avoid
+                               buffer overflow */
 
-       while (strchr("0123456789,#.*WPTS-", *p) && *p) {
+       while (strchr("0123456789,#.*WPTS-", *p) && *p && --cnt>0) {
                if ((*p >= '0' && *p <= '9') || ((*p == 'S') && first))
                        *q++ = *p;
                p++;
+               if(!--limit)
+                       break;
                first = 0;
        }
        *q = 0;
@@ -2589,7 +2593,7 @@ isdn_tty_cmd_ATand(char **p, modem_info * info)
                                        m->mdmreg[i], ((i + 1) % 10) ? " " : "\r\n");
                                isdn_tty_at_cout(rb, info);
                        }
-                       sprintf(rb, "\r\nEAZ/MSN: %s\r\n",
+                       sprintf(rb, "\r\nEAZ/MSN: %.50s\r\n",
                                strlen(m->msn) ? m->msn : "None");
                        isdn_tty_at_cout(rb, info);
                        break;
@@ -3092,7 +3096,7 @@ isdn_tty_parse_at(modem_info * info)
                                break;
                        case 'D':
                                /* D - Dial */
-                               isdn_tty_getdial(++p, ds);
+                               isdn_tty_getdial(++p, ds, sizeof ds);
                                p += strlen(p);
                                if (!strlen(m->msn))
                                        isdn_tty_modem_result(10, info);
index 1b0afeb3f48046981de1bda1d2bf2a27d5808e6a..a6b4e58aa8f5bbf6d70337640667f4d0b9012c30 100644 (file)
@@ -15,7 +15,7 @@ fi
 tristate 'Dummy net driver support' CONFIG_DUMMY
 tristate 'EQL (serial line load balancing) support' CONFIG_EQUALIZER
 if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then
-  if [ "CONFIG_NETLINK_DEV" != "n" ]; then
+  if [ "$CONFIG_NETLINK_DEV" != "n" ]; then
      dep_tristate 'Ethertap network tap' CONFIG_ETHERTAP $CONFIG_NETLINK_DEV
   fi
 fi
index 4f1243b4e2d2f22b7618b7f7ea1dac77ce8e95c0..bd75b19f5fea35da5c4c4991d63a840c4cb24e5d 100644 (file)
@@ -36,7 +36,7 @@ static int rxdmacount = 0;
 static int rx_copybreak = 200;
 
 /* Maximum events (Rx packets, etc.) to handle at each interrupt. */
-static int max_interrupt_work = 20;
+static int max_interrupt_work = 200;
 
 #include <linux/config.h>
 #ifdef MODULE
index 1704b325d0b62a6fd478c7b054de838c9c907ad0..25fcd137ed01844a6ec118ef08d2cd7321757f1c 100644 (file)
@@ -392,18 +392,18 @@ static int par96_open(struct device *dev)
                return -ENXIO;
        }
        if (pp->irq < 0) {
-               printk(KERN_ERR "baycom_par: parport at 0x%x has no irq\n", pp->base);
+               printk(KERN_ERR "baycom_par: parport at 0x%lx has no irq\n", pp->base);
                return -ENXIO;
        }
        memset(&bc->modem, 0, sizeof(bc->modem));
        bc->hdrv.par.bitrate = 9600;
        if (!(bc->pdev = parport_register_device(pp, dev->name, par96_preempt, par96_wakeup, 
                                                 par96_interrupt, PARPORT_DEV_LURK, dev))) {
-               printk(KERN_ERR "baycom_par: cannot register parport at 0x%x\n", pp->base);
+               printk(KERN_ERR "baycom_par: cannot register parport at 0x%lx\n", pp->base);
                return -ENXIO;
        }
        if (parport_claim(bc->pdev)) {
-               printk(KERN_ERR "baycom_par: parport at 0x%x busy\n", pp->base);
+               printk(KERN_ERR "baycom_par: parport at 0x%lx busy\n", pp->base);
                parport_unregister_device(bc->pdev);
                return -EBUSY;
        }
index b071f8eda6012f181c04a372c9e7884802bd8978..8229001f128a1c90745e98661fc1c5c445a15ecf 100644 (file)
@@ -1,4 +1,3 @@
-
 # Makefile for linux/drivers/scsi
 #
 # Note! Dependencies are done automagically by 'make dep', which also
@@ -34,14 +33,13 @@ endif
 ifeq ($(CONFIG_SCSI),y)
   # We must attach scsi_syms.o to scsi.o, as otherwise there is nothing to
   # pull the object file from the archive.
-  SCSI=scsi.o
+  O_TARGET := scsi_n_syms.o
+  O_OBJS   := scsi.o
   ifeq ($(CONFIG_MODULES),y)
-    O_TARGET := scsi_n_syms.o
-    O_OBJS   := scsi.o scsi_error.o scsi_obsolete.o scsi_queue.o
     OX_OBJS  := scsi_syms.o
-    SCSI     := $(O_TARGET)
   endif
-  L_OBJS += $(SCSI) hosts.o scsi_ioctl.o constants.o scsicam.o
+  L_OBJS += scsi_n_syms.o hosts.o scsi_ioctl.o constants.o scsicam.o
+  L_OBJS += scsi_error.o scsi_obsolete.o scsi_queue.o
   ifeq ($(CONFIG_PROC_FS),y)
     L_OBJS += scsi_proc.o
   endif
index 4d1b095c2f5ffe021f10576fc6f4651f0c8dcffc..7507a582f93ff72018ebcc3676246139fa04df55 100644 (file)
@@ -403,6 +403,8 @@ unsigned int scsi_init(void);
 extern struct Scsi_Host * scsi_register(Scsi_Host_Template *, int j);
 extern void scsi_unregister(struct Scsi_Host * i);
 
+extern void scsi_mark_host_reset(struct Scsi_Host *Host);
+
 #define BLANK_HOST {"", 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
 
 struct Scsi_Device_Template
index 166830208cdad1b241e4f0d70030902c431f8830..cb4c989c450f933f3048e32c59d1bd607aa03059 100644 (file)
@@ -64,6 +64,7 @@ EXPORT_SYMBOL(scsi_request_queueable);
 EXPORT_SYMBOL(scsi_release_command);
 EXPORT_SYMBOL(print_Scsi_Cmnd);
 EXPORT_SYMBOL(scsi_block_when_processing_errors);
+EXPORT_SYMBOL(scsi_mark_host_reset);
 #if defined(CONFIG_SCSI_LOGGING) /* { */
 EXPORT_SYMBOL(scsi_logging_level);
 #endif
index 211b3ffe65257c5af826ab56a5c276310ceff141..c0a9aec50402c3eb513770cc8df752b7af26e141 100644 (file)
@@ -136,7 +136,7 @@ if [ "$CONFIG_SOFTOSS" = "y" ]; then
 fi
 
 dep_tristate 'FM synthesizer (YM3812/OPL-3) support' CONFIG_YM3812 $CONFIG_SOUND
-dep_tristate 'Loopback MIDI device support' CONFIG_VMIDI $CONFIG_VMIDI
+dep_tristate 'Loopback MIDI device support' CONFIG_VMIDI $CONFIG_SOUND
 
 if [ "$CONFIG_UART6850" = "y" ]; then
     hex 'I/O base for UART 6850 MIDI port (Unknown)' U6850_BASE 0
index bae682c9c22870cbddcfab9856df31db9d0c2cbc..9e4a5ae99a6944a8c1934befb48f302c58a71e9c 100644 (file)
@@ -41,7 +41,7 @@ M_OBJS   :=
 L_OBJS   :=
 
 ifeq ($(CONFIG_SOUND),y)
-  L_OBJS += soundcard.o dev_table.o sound_switch.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o audio.o dmabuf.o
+  L_OBJS += soundcard.o dev_table.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o audio.o dmabuf.o
 else
   ifeq ($(CONFIG_SOUND),m)
      M_OBJS += sound.o
@@ -238,8 +238,8 @@ sb.o: sb_audio.o sb_card.o sb_common.o sb_midi.o sb_mixer.o
 lowlevel/lowlevel.o:
        cd lowlevel; make
 
-sound.o: soundcard.o dev_table.o sound_switch.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o
-       ld -r -o sound.o soundcard.o dev_table.o sound_switch.o audio.o dmabuf.o \
+sound.o: soundcard.o dev_table.o audio.o dmabuf.o sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o midi_synth.o midibuf.o sound_firmware.o
+       ld -r -o sound.o soundcard.o dev_table.o audio.o dmabuf.o \
               sequencer.o sys_timer.o sound_timer.o lowlevel/lowlevel.o \
               midi_synth.o midibuf.o sound_firmware.o
        rm sound_syms.o
index 944ffab6a27cf6992d803bac0ebabe090afe4d36..267b7af17bde3b70163867d68583f690663acb2c 100644 (file)
@@ -21,6 +21,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 
 #include <linux/config.h>
 #include <linux/module.h>
@@ -121,7 +124,6 @@ static ad1848_info adev_info[MAX_AUDIO_DEV];
 
 static int      ad1848_open(int dev, int mode);
 static void     ad1848_close(int dev);
-static int      ad1848_ioctl(int dev, unsigned int cmd, caddr_t arg);
 static void     ad1848_output_block(int dev, unsigned long buf, int count, int intrflag);
 static void     ad1848_start_input(int dev, unsigned long buf, int count, int intrflag);
 static int      ad1848_prepare_for_output(int dev, int bsize, int bcount);
@@ -524,80 +526,74 @@ ad1848_mixer_reset(ad1848_info * devc)
                ad_write(devc, 26, ad_read(devc, 26) | 0x40);   /* Mute mono out */
 }
 
-static int
-ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+static int ad1848_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       ad1848_info    *devc = mixer_devs[dev]->devc;
-
-       if (cmd == SOUND_MIXER_PRIVATE1)
-         {
-                 int             val;
-
-                 val = *(int *) arg;
-
-                 if (val == 0xffff)
-                         return (*(int *) arg = devc->mixer_output_port);
-
-                 val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT);
-
-                 devc->mixer_output_port = val;
-                 val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT;      /* Always on */
-                 devc->mixer_output_port = val;
-
-                 if (val & AUDIO_SPEAKER)
-                         ad_write(devc, 26, ad_read(devc, 26) & ~0x40);        /* Unmute mono out */
-                 else
-                         ad_write(devc, 26, ad_read(devc, 26) | 0x40);         /* Mute mono out */
-
-                 return (*(int *) arg = devc->mixer_output_port);
-         }
-       if (((cmd >> 8) & 0xff) == 'M')
-         {
-                 int             val;
-
-                 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-                         switch (cmd & 0xff)
-                           {
-                           case SOUND_MIXER_RECSRC:
-                                   val = *(int *) arg;
-                                   return (*(int *) arg = ad1848_set_recmask(devc, val));
-                                   break;
-
-                           default:
-                                   val = *(int *) arg;
-                                   return (*(int *) arg = ad1848_mixer_set(devc, cmd & 0xff, val));
-                 } else
-                         switch (cmd & 0xff)   /*
-                                                * Return parameters
-                                                */
-                           {
-
-                           case SOUND_MIXER_RECSRC:
-                                   return (*(int *) arg = devc->recmask);
-                                   break;
-
-                           case SOUND_MIXER_DEVMASK:
-                                   return (*(int *) arg = devc->supported_devices);
-                                   break;
-
-                           case SOUND_MIXER_STEREODEVS:
-                                   if (devc->model == MD_C930)
-                                           return (*(int *) arg = devc->supported_devices);
-                                   else
-                                           return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
-                                   break;
-
-                           case SOUND_MIXER_RECMASK:
-                                   return (*(int *) arg = devc->supported_rec_devices);
-                                   break;
-
-                           case SOUND_MIXER_CAPS:
-                                   return (*(int *) arg = SOUND_CAP_EXCL_INPUT);
-                                   break;
-
+       ad1848_info *devc = mixer_devs[dev]->devc;
+       int val;
+
+       if (cmd == SOUND_MIXER_PRIVATE1) {
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+
+               if (val != 0xffff) {
+                       val &= (AUDIO_SPEAKER | AUDIO_HEADPHONE | AUDIO_LINE_OUT);
+                       devc->mixer_output_port = val;
+                       val |= AUDIO_HEADPHONE | AUDIO_LINE_OUT;        /* Always on */
+                       devc->mixer_output_port = val;
+                       if (val & AUDIO_SPEAKER)
+                               ad_write(devc, 26, ad_read(devc, 26) & ~0x40);  /* Unmute mono out */
+                       else
+                               ad_write(devc, 26, ad_read(devc, 26) | 0x40);           /* Mute mono out */
+               }
+               val = devc->mixer_output_port;
+               return __put_user(val, (int *)arg);
+       }
+       if (((cmd >> 8) & 0xff) == 'M') {
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               if (__get_user(val, (int *)arg))
+                                       return -EFAULT;
+                               val = ad1848_set_recmask(devc, val);
+                               return __put_user(val, (int *)arg);
+                               
                            default:
-                                   return (*(int *) arg = ad1848_mixer_get(devc, cmd & 0xff));
-                           }
+                               if (__get_user(val, (int *)arg))
+                                       return -EFAULT;
+                               val = ad1848_mixer_set(devc, cmd & 0xff, val);
+                               return __put_user(val, (int *)arg);
+                       } 
+               else
+                       switch (cmd & 0xff) {
+                               /*
+                                * Return parameters
+                                */
+                           
+                       case SOUND_MIXER_RECSRC:
+                               val = devc->recmask;
+                               return __put_user(val, (int *)arg);
+                               
+                       case SOUND_MIXER_DEVMASK:
+                               val = devc->supported_devices;
+                               return __put_user(val, (int *)arg);
+                               
+                       case SOUND_MIXER_STEREODEVS:
+                               val = devc->supported_devices;
+                               if (devc->model != MD_C930)
+                                       val &= ~(SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
+                               return __put_user(val, (int *)arg);
+                               
+                       case SOUND_MIXER_RECMASK:
+                               val = devc->supported_rec_devices;
+                               return __put_user(val, (int *)arg);
+
+                       case SOUND_MIXER_CAPS:
+                               return __put_user(SOUND_CAP_EXCL_INPUT, (int *)arg);
+
+                       default:
+                               val = ad1848_mixer_get(devc, cmd & 0xff);
+                               return __put_user(val, (int *)arg);
+                       }
        } else
                return -EINVAL;
 }
@@ -784,7 +780,7 @@ static struct audio_driver ad1848_audio_driver =
        ad1848_close,
        ad1848_output_block,
        ad1848_start_input,
-       ad1848_ioctl,
+       NULL,
        ad1848_prepare_for_input,
        ad1848_prepare_for_output,
        ad1848_halt,
@@ -873,12 +869,6 @@ ad1848_close(int dev)
        restore_flags(flags);
 }
 
-static int
-ad1848_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
-       return -EINVAL;
-}
-
 static void
 ad1848_output_block(int dev, unsigned long buf, int count, int intrflag)
 {
index 44be2e388f1ab44a53d669d2d2dd807e6f727dfc..8799f88cfb5f4bd8c1505c9f3ebf730a4f041d55 100644 (file)
@@ -11,6 +11,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 
 #include <linux/config.h>
 
@@ -345,197 +348,157 @@ int audio_read(int dev, struct fileinfo *file, char *buf, int count)
 }
 
 int audio_ioctl(int dev, struct fileinfo *file_must_not_be_used,
-           unsigned int cmd, caddr_t arg)
+               unsigned int cmd, caddr_t arg)
 {
-       int val;
+       int val, info, count;
+       unsigned long flags;
+       struct dma_buffparms *dmap;
 
        dev = dev >> 4;
 
-       if (((cmd >> 8) & 0xff) == 'C')
-       {
+       if (((cmd >> 8) & 0xff) == 'C') {
                if (audio_devs[dev]->coproc)    /* Coprocessor ioctl */
                        return audio_devs[dev]->coproc->ioctl(audio_devs[dev]->coproc->devc, cmd, arg, 0);
                /* else
-                       printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
+                       printk(KERN_DEBUG"/dev/dsp%d: No coprocessor for this device\n", dev); */
                return -ENXIO;
-       }
-       else switch (cmd)
-       {
-               case SNDCTL_DSP_SYNC:
-                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                               return 0;
-
-                       if (audio_devs[dev]->dmap_out->fragment_size == 0)
-                               return 0;
-                       sync_output(dev);
-                       DMAbuf_sync(dev);
-                       DMAbuf_reset(dev);
+       } else switch (cmd) {
+       case SNDCTL_DSP_SYNC:
+               if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
                        return 0;
-
-               case SNDCTL_DSP_POST:
-                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                               return 0;
-                       if (audio_devs[dev]->dmap_out->fragment_size == 0)
-                               return 0;
-                       audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
-                       sync_output(dev);
-                       dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
+               if (audio_devs[dev]->dmap_out->fragment_size == 0)
                        return 0;
+               sync_output(dev);
+               DMAbuf_sync(dev);
+               DMAbuf_reset(dev);
+               return 0;
 
-               case SNDCTL_DSP_RESET:
-                       audio_mode[dev] = AM_NONE;
-                       DMAbuf_reset(dev);
+       case SNDCTL_DSP_POST:
+               if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
                        return 0;
+               if (audio_devs[dev]->dmap_out->fragment_size == 0)
+                       return 0;
+               audio_devs[dev]->dmap_out->flags |= DMA_POST | DMA_DIRTY;
+               sync_output(dev);
+               dma_ioctl(dev, SNDCTL_DSP_POST, (caddr_t) 0);
+               return 0;
 
-               case SNDCTL_DSP_GETFMTS:
-                       return (*(int *) arg = audio_devs[dev]->format_mask);
-
-               case SNDCTL_DSP_SETFMT:
-                       val = *(int *) arg;
-                       return (*(int *) arg = set_format(dev, val));
-
-               case SNDCTL_DSP_GETISPACE:
-                       if (!(audio_devs[dev]->open_mode & OPEN_READ))
-                               return 0;
-                       if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-                               return -EBUSY;
-
-                       {
-                               audio_buf_info  info;
-
-                               int err = dma_ioctl(dev, cmd, (caddr_t) & info);
-
-                               if (err < 0)
-                                       return err;
-
-                               memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-                               return 0;
-                       }
-
-               case SNDCTL_DSP_GETOSPACE:
-                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                                 return -EPERM;
-                       if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
-                                 return -EBUSY;
-
-                       {
-                               audio_buf_info  info;
-
-                               int err = dma_ioctl(dev, cmd, (caddr_t) & info);
+       case SNDCTL_DSP_RESET:
+               audio_mode[dev] = AM_NONE;
+               DMAbuf_reset(dev);
+               return 0;
 
-                               if (err < 0)
-                                       return err;
+       case SNDCTL_DSP_GETFMTS:
+               val = audio_devs[dev]->format_mask;
+               return __put_user(val, (int *)arg);
 
-                               memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-                               return 0;
-                       }
+       case SNDCTL_DSP_SETFMT:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = set_format(dev, val);
+               return __put_user(val, (int *)arg);
 
-               case SNDCTL_DSP_NONBLOCK:
-                       dev_nblock[dev] = 1;
+       case SNDCTL_DSP_GETISPACE:
+               if (!(audio_devs[dev]->open_mode & OPEN_READ))
                        return 0;
+               if ((audio_mode[dev] & AM_WRITE) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+                       return -EBUSY;
+               return dma_ioctl(dev, cmd, arg);
+
+       case SNDCTL_DSP_GETOSPACE:
+               if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                       return -EPERM;
+               if ((audio_mode[dev] & AM_READ) && !(audio_devs[dev]->flags & DMA_DUPLEX))
+                       return -EBUSY;
+               return dma_ioctl(dev, cmd, arg);
+               
+       case SNDCTL_DSP_NONBLOCK:
+               dev_nblock[dev] = 1;
+               return 0;
 
-               case SNDCTL_DSP_GETCAPS:
-               {
-                       int info = 1;   /* Revision level of this ioctl() */
-
+       case SNDCTL_DSP_GETCAPS:
+                       info = 1 | DSP_CAP_MMAP;        /* Revision level of this ioctl() */
                        if (audio_devs[dev]->flags & DMA_DUPLEX &&
-                               audio_devs[dev]->open_mode == OPEN_READWRITE)
-                                       info |= DSP_CAP_DUPLEX;
-
+                           audio_devs[dev]->open_mode == OPEN_READWRITE)
+                               info |= DSP_CAP_DUPLEX;
                        if (audio_devs[dev]->coproc)
                                info |= DSP_CAP_COPROC;
-
                        if (audio_devs[dev]->d->local_qlen)     /* Device has hidden buffers */
                                info |= DSP_CAP_BATCH;
-
                        if (audio_devs[dev]->d->trigger)        /* Supports SETTRIGGER */
                                info |= DSP_CAP_TRIGGER;
-
-                       info |= DSP_CAP_MMAP;
-
-                       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-                       return 0;
-               }
-
-               case SOUND_PCM_WRITE_RATE:
-                       val = *(int *) arg;
-                       return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, val));
-
-               case SOUND_PCM_READ_RATE:
-                       return (*(int *) arg = audio_devs[dev]->d->set_speed(dev, 0));
-
-               case SNDCTL_DSP_STEREO:
-               {
-                       int n;
-
-                       n = *(int *) arg;
-                       if (n > 1)
-                       {
-/*                             printk(KERN_DENUG "sound: SNDCTL_DSP_STEREO called with invalid argument %d\n", n);*/
-                               return -EINVAL;
-                       }
-                       if (n < 0)
-                               return -EINVAL;
-
-                       return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, n + 1) - 1);
-               }
-
-               case SOUND_PCM_WRITE_CHANNELS:
-                       val = *(int *) arg;
-                       return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, val));
-
-               case SOUND_PCM_READ_CHANNELS:
-                       return (*(int *) arg = audio_devs[dev]->d->set_channels(dev, 0));
-
-               case SOUND_PCM_READ_BITS:
-                       return (*(int *) arg = audio_devs[dev]->d->set_bits(dev, 0));
-
-               case SNDCTL_DSP_SETDUPLEX:
-                       if (audio_devs[dev]->open_mode != OPEN_READWRITE)
-                               return -EPERM;
-                       if (audio_devs[dev]->flags & DMA_DUPLEX)
-                               return 0;
-                       else
-                               return -EIO;
-
-               case SNDCTL_DSP_PROFILE:
-                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                               audio_devs[dev]->dmap_out->applic_profile = *(int *) arg;
-                       if (audio_devs[dev]->open_mode & OPEN_READ)
-                               audio_devs[dev]->dmap_in->applic_profile = *(int *) arg;
-                       return 0;
-
-               case SNDCTL_DSP_GETODELAY:
-               {
-                       int count;
-                       unsigned long   flags;
-                       struct dma_buffparms *dmap = audio_devs[dev]->dmap_out;
-
-                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                               return -EINVAL;
-                       if (!(dmap->flags & DMA_ALLOC_DONE))
-                               return *(int *) arg = 0;
-
-                       save_flags (flags);
-                       cli ();
-                       /* Compute number of bytes that have been played */
-                       count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
-                       if (count < dmap->fragment_size && dmap->qhead != 0)
-                               count += dmap->bytes_in_use;    /* Pointer wrap not handled yet */
-                       count += dmap->byte_counter;
-
-                       /* Substract current count from the number of bytes written by app */
-                       count = dmap->user_counter - count;
-                       if (count < 0)
-                               count = 0;
-                       restore_flags (flags);
-
-                       return *(int *) arg = count;
-               }
-               break;
-
-               default:
-                       return dma_ioctl(dev, cmd, arg);
+                       return __put_user(info, (int *)arg);
+                       
+       case SOUND_PCM_WRITE_RATE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = audio_devs[dev]->d->set_speed(dev, val);
+               return __put_user(val, (int *)arg);
+
+       case SOUND_PCM_READ_RATE:
+               val = audio_devs[dev]->d->set_speed(dev, 0);
+               return __put_user(val, (int *)arg);
+               
+       case SNDCTL_DSP_STEREO:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val > 1 || val < 0)
+                       return -EINVAL;
+               val = audio_devs[dev]->d->set_channels(dev, val + 1) - 1;
+               return __put_user(val, (int *)arg);
+
+       case SOUND_PCM_WRITE_CHANNELS:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = audio_devs[dev]->d->set_channels(dev, val);
+               return __put_user(val, (int *)arg);
+
+       case SOUND_PCM_READ_CHANNELS:
+               val = audio_devs[dev]->d->set_channels(dev, 0);
+               return __put_user(val, (int *)arg);
+               
+       case SOUND_PCM_READ_BITS:
+               val = audio_devs[dev]->d->set_bits(dev, 0);
+               return __put_user(val, (int *)arg);
+
+       case SNDCTL_DSP_SETDUPLEX:
+               if (audio_devs[dev]->open_mode != OPEN_READWRITE)
+                       return -EPERM;
+               return (audio_devs[dev]->flags & DMA_DUPLEX) ? 0 : -EIO;
+
+       case SNDCTL_DSP_PROFILE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                       audio_devs[dev]->dmap_out->applic_profile = val;
+               if (audio_devs[dev]->open_mode & OPEN_READ)
+                       audio_devs[dev]->dmap_in->applic_profile = val;
+               return 0;
+               
+       case SNDCTL_DSP_GETODELAY:
+               dmap = audio_devs[dev]->dmap_out;
+               if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                       return -EINVAL;
+               if (!(dmap->flags & DMA_ALLOC_DONE))
+                       return __put_user(0, (int *)arg);
+               
+               save_flags (flags);
+               cli();
+               /* Compute number of bytes that have been played */
+               count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
+               if (count < dmap->fragment_size && dmap->qhead != 0)
+                       count += dmap->bytes_in_use;    /* Pointer wrap not handled yet */
+               count += dmap->byte_counter;
+               
+               /* Substract current count from the number of bytes written by app */
+               count = dmap->user_counter - count;
+               if (count < 0)
+                       count = 0;
+               restore_flags (flags);
+               return __put_user(count, (int *)arg);
+               
+       default:
+               return dma_ioctl(dev, cmd, arg);
        }
 }
 
@@ -676,14 +639,13 @@ void reorganize_buffers(int dev, struct dma_buffparms *dmap, int recording)
        dmap->flags |= DMA_ALLOC_DONE | DMA_EMPTY;
 }
 
-static int dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+static int dma_subdivide(int dev, struct dma_buffparms *dmap, int fact)
 {
-       if (fact == 0)
-       {
+       if (fact == 0) {
                fact = dmap->subdivision;
                if (fact == 0)
                        fact = 1;
-               return (*(int *) arg = fact);
+               return fact;
        }
        if (dmap->subdivision != 0 || dmap->fragment_size)      /* Too late to change */
                return -EINVAL;
@@ -695,10 +657,10 @@ static int dma_subdivide(int dev, struct dma_buffparms *dmap, caddr_t arg, int f
                return -EINVAL;
 
        dmap->subdivision = fact;
-       return (*(int *) arg = fact);
+       return fact;
 }
 
-static int dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, int fact)
+static int dma_set_fragment(int dev, struct dma_buffparms *dmap, int fact)
 {
        int bytes, count;
 
@@ -747,311 +709,223 @@ static int dma_set_fragment(int dev, struct dma_buffparms *dmap, caddr_t arg, in
                dmap->fragment_size /= 2;       /* Needs at least 2 buffers */
 
        dmap->subdivision = 1;  /* Disable SNDCTL_DSP_SUBDIVIDE */
-       if (arg)
-               return (*(int *) arg = bytes | ((count - 1) << 16));
-       else
-               return 0;
+       return bytes | ((count - 1) << 16);
 }
 
 int dma_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-
        struct dma_buffparms *dmap_out = audio_devs[dev]->dmap_out;
        struct dma_buffparms *dmap_in = audio_devs[dev]->dmap_in;
-
-       switch (cmd)
-       {
-
-               case SNDCTL_DSP_SUBDIVIDE:
-               {
-                       int             fact;
-                       int             ret = 0;
-
-                       fact = *(int *) arg;
-
-                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                               ret = dma_subdivide(dev, dmap_out, arg, fact);
-                       if (ret < 0)
-                                return ret;
-
-                       if (audio_devs[dev]->open_mode != OPEN_WRITE ||
-                               (audio_devs[dev]->flags & DMA_DUPLEX &&
-                               audio_devs[dev]->open_mode & OPEN_READ))
-                                       ret = dma_subdivide(dev, dmap_in, arg, fact);
-
+       struct dma_buffparms *dmap;
+       audio_buf_info info;
+       count_info cinfo;
+       int fact, ret, changed, bits, count, err;
+       unsigned long flags;
+
+       switch (cmd) {
+       case SNDCTL_DSP_SUBDIVIDE:
+               ret = 0;
+               if (__get_user(fact, (int *)arg))
+                       return -EFAULT;
+               if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                       ret = dma_subdivide(dev, dmap_out, fact);
+               if (ret < 0)
                        return ret;
-               }
-               break;
-
-               case SNDCTL_DSP_GETISPACE:
-               case SNDCTL_DSP_GETOSPACE:
-               {
-                       struct dma_buffparms *dmap = dmap_out;
-
-                       audio_buf_info *info = (audio_buf_info *) arg;
-
-                       if (cmd == SNDCTL_DSP_GETISPACE &&
-                               !(audio_devs[dev]->open_mode & OPEN_READ))
-                                       return -EINVAL;
-
-                       if (cmd == SNDCTL_DSP_GETOSPACE &&
-                               !(audio_devs[dev]->open_mode & OPEN_WRITE))
-                                       return -EINVAL;
-
-                       if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
-                               dmap = dmap_in;
-
-                       if (dmap->mapping_flags & DMA_MAP_MAPPED)
-                               return -EINVAL;
-
-                       if (!(dmap->flags & DMA_ALLOC_DONE))
-                               reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
-
-                       info->fragstotal = dmap->nbufs;
-
-                       if (cmd == SNDCTL_DSP_GETISPACE)
-                               info->fragments = dmap->qlen;
-                       else
-                       {
-                               if (!DMAbuf_space_in_queue(dev))
-                                       info->fragments = 0;
-                               else
-                               {
-                                       info->fragments = DMAbuf_space_in_queue(dev);
-                                       if (audio_devs[dev]->d->local_qlen)
-                                       {
-                                               int tmp = audio_devs[dev]->d->local_qlen(dev);
-
-                                               if (tmp && info->fragments)
-                                                       tmp--;  /*
-                                                                * This buffer has been counted twice
-                                                                */
-                                               info->fragments -= tmp;
-                                       }
-                               }
-                       }
-
-                       if (info->fragments < 0)
-                               info->fragments = 0;
-                       else if (info->fragments > dmap->nbufs)
-                               info->fragments = dmap->nbufs;
-
-                       info->fragsize = dmap->fragment_size;
-                       info->bytes = info->fragments * dmap->fragment_size;
-
-                       if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
-                               info->bytes -= dmap->counts[dmap->qhead];
-                       else
-                       {
-                               info->fragments = info->bytes / dmap->fragment_size;
-                               info->bytes -= dmap->user_counter % dmap->fragment_size;
-                       }
-               }
-               return 0;
-
-               case SNDCTL_DSP_SETTRIGGER:
-               {
-                       unsigned long flags;
-
-                       int bits;
-                       int changed;
-
-                       bits = *(int *) arg;
-                       bits &= audio_devs[dev]->open_mode;
-
-                       if (audio_devs[dev]->d->trigger == NULL)
-                               return -EINVAL;
-
-                       if (!(audio_devs[dev]->flags & DMA_DUPLEX))
-                               if ((bits & PCM_ENABLE_INPUT) && (bits & PCM_ENABLE_OUTPUT))
-                               {
-                                       /* printk(KERN_WARNING "Sound: Device doesn't have full duplex capability\n");*/
-                                       return -EINVAL;
-                               }
-                       save_flags(flags);
-                       cli();
-                       changed = audio_devs[dev]->enable_bits ^ bits;
-
-                       if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go)
-                       {
-                               int err;
-
-                               reorganize_buffers(dev, dmap_in, 1);
-
-                               if ((err = audio_devs[dev]->d->prepare_for_input(dev,
-                                       dmap_in->fragment_size, dmap_in->nbufs)) < 0)
-                                               return -err;
-
-                               dmap_in->dma_mode = DMODE_INPUT;
-                               audio_devs[dev]->enable_bits = bits;
-                               DMAbuf_activate_recording(dev, dmap_in);
-                       }
-                       
-                       if ((changed & bits) & PCM_ENABLE_OUTPUT &&
-                               (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
-                               audio_devs[dev]->go)
-                       {
-
-                               if (!(dmap_out->flags & DMA_ALLOC_DONE))
-                               {
-                                       reorganize_buffers(dev, dmap_out, 0);
+               if (audio_devs[dev]->open_mode != OPEN_WRITE ||
+                   (audio_devs[dev]->flags & DMA_DUPLEX &&
+                    audio_devs[dev]->open_mode & OPEN_READ))
+                       ret = dma_subdivide(dev, dmap_in, fact);
+               if (ret < 0)
+                       return ret;
+               return __put_user(ret, (int *)arg);
+
+       case SNDCTL_DSP_GETISPACE:
+       case SNDCTL_DSP_GETOSPACE:
+               dmap = dmap_out;
+               if (cmd == SNDCTL_DSP_GETISPACE && !(audio_devs[dev]->open_mode & OPEN_READ))
+                       return -EINVAL;
+               if (cmd == SNDCTL_DSP_GETOSPACE && !(audio_devs[dev]->open_mode & OPEN_WRITE))
+                       return -EINVAL;
+               if (cmd == SNDCTL_DSP_GETISPACE && audio_devs[dev]->flags & DMA_DUPLEX)
+                       dmap = dmap_in;
+               if (dmap->mapping_flags & DMA_MAP_MAPPED)
+                       return -EINVAL;
+               if (!(dmap->flags & DMA_ALLOC_DONE))
+                       reorganize_buffers(dev, dmap, (cmd == SNDCTL_DSP_GETISPACE));
+               info.fragstotal = dmap->nbufs;
+               if (cmd == SNDCTL_DSP_GETISPACE)
+                       info.fragments = dmap->qlen;
+               else {
+                       if (!DMAbuf_space_in_queue(dev))
+                               info.fragments = 0;
+                       else {
+                               info.fragments = DMAbuf_space_in_queue(dev);
+                               if (audio_devs[dev]->d->local_qlen) {
+                                       int tmp = audio_devs[dev]->d->local_qlen(dev);
+                                       if (tmp && info.fragments)
+                                               tmp--;  /*
+                                                        * This buffer has been counted twice
+                                                        */
+                                       info.fragments -= tmp;
                                }
-                               dmap_out->dma_mode = DMODE_OUTPUT;
-                               audio_devs[dev]->enable_bits = bits;
-                               dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
-                               DMAbuf_launch_output(dev, dmap_out);
                        }
-                       audio_devs[dev]->enable_bits = bits;
-                       
-                       if (changed && audio_devs[dev]->d->trigger)
-                       {
-                               audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
-                       }
-                       restore_flags(flags);
                }
-               /* Falls through... */
-
-               case SNDCTL_DSP_GETTRIGGER:
-                       return (*(int *) arg = audio_devs[dev]->enable_bits);
-
-               case SNDCTL_DSP_SETSYNCRO:
-
-                       if (!audio_devs[dev]->d->trigger)
-                               return -EINVAL;
-
-                       audio_devs[dev]->d->trigger(dev, 0);
-                       audio_devs[dev]->go = 0;
-                       return 0;
-                       break;
-
-               case SNDCTL_DSP_GETIPTR:
-               {
-                       count_info      info;
-                       unsigned long   flags;
-                       struct dma_buffparms *dmap = dmap_in;
-
-                       if (!(audio_devs[dev]->open_mode & OPEN_READ))
-                               return -EINVAL;
-
-                       save_flags(flags);
-                       cli();
-                       info.bytes = dmap->byte_counter;
-                       info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_INPUT) & ~3;
-                       if (info.ptr < dmap->fragment_size && dmap->qtail != 0)
-                               info.bytes += dmap->bytes_in_use;       /* Pointer wrap not handled yet */
-
-                       info.blocks = dmap->qlen;
-                       info.bytes += info.ptr;
-                       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-
-                       if (dmap->mapping_flags & DMA_MAP_MAPPED)
-                               dmap->qlen = 0; /* Reset interrupt counter */
-                       restore_flags(flags);
-                       return 0;
+               if (info.fragments < 0)
+                               info.fragments = 0;
+               else if (info.fragments > dmap->nbufs)
+                       info.fragments = dmap->nbufs;
+
+               info.fragsize = dmap->fragment_size;
+               info.bytes = info.fragments * dmap->fragment_size;
+
+               if (cmd == SNDCTL_DSP_GETISPACE && dmap->qlen)
+                       info.bytes -= dmap->counts[dmap->qhead];
+               else {
+                       info.fragments = info.bytes / dmap->fragment_size;
+                       info.bytes -= dmap->user_counter % dmap->fragment_size;
                }
-               break;
-
-               case SNDCTL_DSP_GETOPTR:
-               {
-                       count_info      info;
-                       unsigned long   flags;
-                       struct dma_buffparms *dmap = dmap_out;
-
-                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                               return -EINVAL;
-
-                       save_flags(flags);
-                       cli();
-                       info.bytes = dmap->byte_counter;
-                       info.ptr = DMAbuf_get_buffer_pointer(dev, dmap, DMODE_OUTPUT) & ~3;
-                       if (info.ptr < dmap->fragment_size && dmap->qhead != 0)
-                               info.bytes += dmap->bytes_in_use;       /* Pointer wrap not handled yet */
-                       info.blocks = dmap->qlen;
-                       info.bytes += info.ptr;
-                       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-
-                       if (dmap->mapping_flags & DMA_MAP_MAPPED)
-                               dmap->qlen = 0; /* Reset interrupt counter */
-
-                       restore_flags(flags);
-                       return 0;
-               }
-               break;
-
-               case SNDCTL_DSP_GETODELAY:
-               {
-                       int count;
-                       unsigned long   flags;
-                       struct dma_buffparms *dmap = dmap_out;
-
-                       if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
-                               return -EINVAL;
-                       if (!(dmap->flags & DMA_ALLOC_DONE))
-                               return (*(int *) arg = 0);
-
-                       save_flags(flags);
-                       cli();
-                       /* Compute number of bytes that have been played */
-                       count = DMAbuf_get_buffer_pointer (dev, dmap, DMODE_OUTPUT);
-                       if (count < dmap->fragment_size && dmap->qhead != 0)
-                               count += dmap->bytes_in_use;    /* Pointer wrap not handled yet */
-                       count += dmap->byte_counter;
-
-                       /* Substract current count from the number of bytes written by app */
-                       count = dmap->user_counter - count;
-                       if (count < 0)
-                               count = 0;
-                       restore_flags (flags);
-
-                       return (*(int *) arg = count);
+               return __copy_to_user(arg, &info, sizeof(info));
+
+       case SNDCTL_DSP_SETTRIGGER:
+               if (__get_user(bits, (int *)arg))
+                       return -EFAULT;
+               bits &= audio_devs[dev]->open_mode;
+               if (audio_devs[dev]->d->trigger == NULL)
+                       return -EINVAL;
+               if (!(audio_devs[dev]->flags & DMA_DUPLEX) && (bits & PCM_ENABLE_INPUT) &&
+                   (bits & PCM_ENABLE_OUTPUT))
+                       return -EINVAL;
+               save_flags(flags);
+               cli();
+               changed = audio_devs[dev]->enable_bits ^ bits;
+               if ((changed & bits) & PCM_ENABLE_INPUT && audio_devs[dev]->go) {
+                       reorganize_buffers(dev, dmap_in, 1);
+                       if ((err = audio_devs[dev]->d->prepare_for_input(dev,
+                                            dmap_in->fragment_size, dmap_in->nbufs)) < 0)
+                               return -err;
+                       dmap_in->dma_mode = DMODE_INPUT;
+                       audio_devs[dev]->enable_bits = bits;
+                       DMAbuf_activate_recording(dev, dmap_in);
                }
-
-               case SNDCTL_DSP_POST:
-                       if (audio_devs[dev]->dmap_out->qlen > 0)
-                               if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
-                                       DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
-                       return 0;
-
-               case SNDCTL_DSP_GETBLKSIZE:
-               {
-                       int             fragment_size;
-                       struct dma_buffparms *dmap = dmap_out;
-
-                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                               reorganize_buffers(dev, dmap_out,
-                                       (audio_devs[dev]->open_mode == OPEN_READ));
-                       if (audio_devs[dev]->open_mode != OPEN_WRITE ||
-                               (audio_devs[dev]->flags & DMA_DUPLEX &&
-                               audio_devs[dev]->open_mode & OPEN_READ))
-                                       reorganize_buffers(dev, dmap_in,
-                                               (audio_devs[dev]->open_mode == OPEN_READ));
-                       if (audio_devs[dev]->open_mode == OPEN_READ)
-                                       dmap = dmap_in;
-                       fragment_size = dmap->fragment_size;
-                       return (*(int *) arg = fragment_size);
+               if ((changed & bits) & PCM_ENABLE_OUTPUT &&
+                   (dmap_out->mapping_flags & DMA_MAP_MAPPED || dmap_out->qlen > 0) &&
+                   audio_devs[dev]->go) {
+                       if (!(dmap_out->flags & DMA_ALLOC_DONE))
+                               reorganize_buffers(dev, dmap_out, 0);
+                       dmap_out->dma_mode = DMODE_OUTPUT;
+                       audio_devs[dev]->enable_bits = bits;
+                       dmap_out->counts[dmap_out->qhead] = dmap_out->fragment_size;
+                       DMAbuf_launch_output(dev, dmap_out);
                }
+               audio_devs[dev]->enable_bits = bits;
+               if (changed && audio_devs[dev]->d->trigger)
+                       audio_devs[dev]->d->trigger(dev, bits * audio_devs[dev]->go);
+               restore_flags(flags);
+               /* Falls through... */
 
-               case SNDCTL_DSP_SETFRAGMENT:
-               {
-                       int  fact;
-                       int  ret = 0;
+       case SNDCTL_DSP_GETTRIGGER:
+               ret = audio_devs[dev]->enable_bits;
+               return __put_user(ret, (int *)arg);
 
-                       fact = *(int *) arg;
-                       if (audio_devs[dev]->open_mode & OPEN_WRITE)
-                               ret = dma_set_fragment(dev, dmap_out, arg, fact);
-                       if (ret < 0)
-                               return ret;
+       case SNDCTL_DSP_SETSYNCRO:
+               if (!audio_devs[dev]->d->trigger)
+                       return -EINVAL;
+               audio_devs[dev]->d->trigger(dev, 0);
+               audio_devs[dev]->go = 0;
+               return 0;
 
-                       if (audio_devs[dev]->open_mode != OPEN_WRITE ||
-                               (audio_devs[dev]->flags & DMA_DUPLEX &&
-                               audio_devs[dev]->open_mode & OPEN_READ))
-                               ret = dma_set_fragment(dev, dmap_in, arg, fact);
+       case SNDCTL_DSP_GETIPTR:
+               if (!(audio_devs[dev]->open_mode & OPEN_READ))
+                       return -EINVAL;
+               save_flags(flags);
+               cli();
+               cinfo.bytes = dmap_in->byte_counter;
+               cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_in, DMODE_INPUT) & ~3;
+               if (cinfo.ptr < dmap_in->fragment_size && dmap_in->qtail != 0)
+                       cinfo.bytes += dmap_in->bytes_in_use;   /* Pointer wrap not handled yet */
+               cinfo.blocks = dmap_in->qlen;
+               cinfo.bytes += cinfo.ptr;
+               if (dmap_in->mapping_flags & DMA_MAP_MAPPED)
+                       dmap_in->qlen = 0;      /* Reset interrupt counter */
+               restore_flags(flags);
+               return __copy_to_user(arg, &cinfo, sizeof(cinfo));
+
+       case SNDCTL_DSP_GETOPTR:
+               if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                       return -EINVAL;
+
+               save_flags(flags);
+               cli();
+               cinfo.bytes = dmap_out->byte_counter;
+               cinfo.ptr = DMAbuf_get_buffer_pointer(dev, dmap_out, DMODE_OUTPUT) & ~3;
+               if (cinfo.ptr < dmap_out->fragment_size && dmap_out->qhead != 0)
+                       cinfo.bytes += dmap_out->bytes_in_use;  /* Pointer wrap not handled yet */
+               cinfo.blocks = dmap_out->qlen;
+               cinfo.bytes += cinfo.ptr;
+               if (dmap_out->mapping_flags & DMA_MAP_MAPPED)
+                       dmap_out->qlen = 0;     /* Reset interrupt counter */
+               restore_flags(flags);
+               return __copy_to_user(arg, &cinfo, sizeof(cinfo));
+
+       case SNDCTL_DSP_GETODELAY:
+               if (!(audio_devs[dev]->open_mode & OPEN_WRITE))
+                       return -EINVAL;
+               if (!(dmap_out->flags & DMA_ALLOC_DONE))
+                       return __put_user(0, (int *)arg);
+               save_flags(flags);
+               cli();
+               /* Compute number of bytes that have been played */
+               count = DMAbuf_get_buffer_pointer (dev, dmap_out, DMODE_OUTPUT);
+               if (count < dmap_out->fragment_size && dmap_out->qhead != 0)
+                       count += dmap_out->bytes_in_use;        /* Pointer wrap not handled yet */
+               count += dmap_out->byte_counter;
+               /* Substract current count from the number of bytes written by app */
+               count = dmap_out->user_counter - count;
+               if (count < 0)
+                       count = 0;
+               restore_flags (flags);
+               return __put_user(count, (int *)arg);
+
+       case SNDCTL_DSP_POST:
+               if (audio_devs[dev]->dmap_out->qlen > 0)
+                       if (!(audio_devs[dev]->dmap_out->flags & DMA_ACTIVE))
+                               DMAbuf_launch_output(dev, audio_devs[dev]->dmap_out);
+               return 0;
 
+       case SNDCTL_DSP_GETBLKSIZE:
+               dmap = dmap_out;
+               if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                       reorganize_buffers(dev, dmap_out, (audio_devs[dev]->open_mode == OPEN_READ));
+               if (audio_devs[dev]->open_mode == OPEN_READ ||
+                   (audio_devs[dev]->flags & DMA_DUPLEX &&
+                    audio_devs[dev]->open_mode & OPEN_READ))
+                       reorganize_buffers(dev, dmap_in, (audio_devs[dev]->open_mode == OPEN_READ));
+               if (audio_devs[dev]->open_mode == OPEN_READ)
+                       dmap = dmap_in;
+               ret = dmap->fragment_size;
+               return __put_user(ret, (int *)arg);
+
+       case SNDCTL_DSP_SETFRAGMENT:
+               ret = 0;
+               if (__get_user(fact, (int *)arg))
+                       return -EFAULT;
+               if (audio_devs[dev]->open_mode & OPEN_WRITE)
+                       ret = dma_set_fragment(dev, dmap_out, fact);
+               if (ret < 0)
                        return ret;
-               }
-               break;
+               if (audio_devs[dev]->open_mode == OPEN_READ ||
+                   (audio_devs[dev]->flags & DMA_DUPLEX &&
+                    audio_devs[dev]->open_mode & OPEN_READ))
+                       ret = dma_set_fragment(dev, dmap_in, fact);
+               if (ret < 0)
+                       return ret;
+               if (!arg) /* don't know what this is good for, but preserve old semantics */
+                       return 0;
+               return __put_user(ret, (int *)arg);
 
-               default:
-                       return audio_devs[dev]->d->ioctl(dev, cmd, arg);
+       default:
+               if (!audio_devs[dev]->d->ioctl)
+                       return -EINVAL;
+               return audio_devs[dev]->d->ioctl(dev, cmd, arg);
        }
 }
index 32337560493b7d46e7f971e8f2028c2aa6aa75e7..cd62f4ac80aca41fb8aa1b95aa4e92d8acaedeba 100644 (file)
@@ -121,24 +121,38 @@ close_dmap(int dev, struct dma_buffparms *dmap, int chan)
 }
 
 
-static unsigned int
-default_set_bits(int dev, unsigned int bits)
+static unsigned int default_set_bits(int dev, unsigned int bits)
 {
-       return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t) & bits);
+       mm_segment_t fs = get_fs();
+       unsigned int r;
+
+       set_fs(get_ds());
+       r = audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SETFMT, (caddr_t)&bits);
+       set_fs(fs);
+       return r;
 }
 
-static int
-default_set_speed(int dev, int speed)
+static int default_set_speed(int dev, int speed)
 {
-       return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t) & speed);
+       mm_segment_t fs = get_fs();
+       int r;
+
+       set_fs(get_ds());
+       r = audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_SPEED, (caddr_t)&speed);
+       set_fs(fs);
+       return r;
 }
 
-static short
-default_set_channels(int dev, short channels)
+static short default_set_channels(int dev, short channels)
 {
-       int             c = channels;
-
-       return audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t) & c);
+       int c = channels;
+       mm_segment_t fs = get_fs();
+       short r;
+
+       set_fs(get_ds());
+       r = audio_devs[dev]->d->ioctl(dev, SNDCTL_DSP_CHANNELS, (caddr_t)&c);
+       set_fs(fs);
+       return r;
 }
 
 static void
index fdbde32fdc2dea1f251ddcbe3667f6ab6dd987ae..67e4d928dec8ad41b09366f565c4ae51e7648735 100644 (file)
@@ -175,12 +175,6 @@ gus_midi_end_read(int dev)
        return 0;
 }
 
-static int
-gus_midi_ioctl(int dev, unsigned cmd, caddr_t arg)
-{
-       return -EINVAL;
-}
-
 static void
 gus_midi_kick(int dev)
 {
@@ -218,7 +212,7 @@ static struct midi_operations gus_midi_operations =
        {0},
        gus_midi_open,
        gus_midi_close,
-       gus_midi_ioctl,
+       NULL, /* ioctl */
        gus_midi_out,
        gus_midi_start_read,
        gus_midi_end_read,
index c8320e95f99a7f969d9036b808520f486b4686b2..dfe63c7a1b380d4f8666d324557e1a8d4bdb31e8 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 
@@ -1107,34 +1110,27 @@ gus_wave_detect(int baseaddr)
        return 1;
 }
 
-static int
-guswave_ioctl(int dev,
-             unsigned int cmd, caddr_t arg)
+static int guswave_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
 
-       switch (cmd)
-         {
-         case SNDCTL_SYNTH_INFO:
-                 gus_info.nr_voices = nr_voices;
-                 memcpy((&((char *) arg)[0]), (char *) &gus_info, sizeof(gus_info));
-                 return 0;
-                 break;
+       switch (cmd) {
+       case SNDCTL_SYNTH_INFO:
+               gus_info.nr_voices = nr_voices;
+               return __copy_to_user(arg, &gus_info, sizeof(gus_info));
 
-         case SNDCTL_SEQ_RESETSAMPLES:
-                 reset_sample_memory();
-                 return 0;
-                 break;
+       case SNDCTL_SEQ_RESETSAMPLES:
+               reset_sample_memory();
+               return 0;
 
-         case SNDCTL_SEQ_PERCMODE:
-                 return 0;
-                 break;
+       case SNDCTL_SEQ_PERCMODE:
+               return 0;
 
-         case SNDCTL_SYNTH_MEMAVL:
-                 return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
+       case SNDCTL_SYNTH_MEMAVL:
+               return (gus_mem_size == 0) ? 0 : gus_mem_size - free_mem_ptr - 32;
 
-         default:
-                 return -EINVAL;
-         }
+       default:
+               return -EINVAL;
+       }
 }
 
 static int
@@ -2206,53 +2202,48 @@ gus_audio_set_bits(int bits)
        return bits;
 }
 
-static int
-gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
-       int             val;
-
-       switch (cmd)
-         {
-         case SOUND_PCM_WRITE_RATE:
-                 val = *(int *) arg;
-                 return (*(int *) arg = gus_audio_set_speed(val));
-                 break;
-
-         case SOUND_PCM_READ_RATE:
-                 return (*(int *) arg = gus_audio_speed);
-                 break;
-
-         case SNDCTL_DSP_STEREO:
-                 val = *(int *) arg;
-                 return (*(int *) arg = gus_audio_set_channels(val + 1) - 1);
-                 break;
-
-         case SOUND_PCM_WRITE_CHANNELS:
-                 val = *(int *) arg;
-                 return (*(int *) arg = gus_audio_set_channels(val));
-                 break;
-
-         case SOUND_PCM_READ_CHANNELS:
-                 return (*(int *) arg = gus_audio_channels);
-                 break;
-
-         case SNDCTL_DSP_SETFMT:
-                 val = *(int *) arg;
-                 return (*(int *) arg = gus_audio_set_bits(val));
-                 break;
-
-         case SOUND_PCM_READ_BITS:
-                 return (*(int *) arg = gus_audio_bits);
-
-         case SOUND_PCM_WRITE_FILTER:          /* NOT POSSIBLE */
-                 return (*(int *) arg = -EINVAL);
-                 break;
-
-         case SOUND_PCM_READ_FILTER:
-                 return (*(int *) arg = -EINVAL);
-                 break;
-
-         }
+static int gus_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+       int val;
+
+       switch (cmd) {
+       case SOUND_PCM_WRITE_RATE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = gus_audio_set_speed(val);
+               return __put_user(val, (int *)arg);
+
+       case SOUND_PCM_READ_RATE:
+               return __put_user(gus_audio_speed, (int *)arg);
+
+       case SNDCTL_DSP_STEREO:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = gus_audio_set_channels(val + 1) - 1;
+               return __put_user(val, (int *)arg);
+
+       case SOUND_PCM_WRITE_CHANNELS:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = gus_audio_set_channels(val);
+               return __put_user(val, (int *)arg);
+
+       case SOUND_PCM_READ_CHANNELS:
+               return __put_user(gus_audio_channels, (int *)arg);
+               
+       case SNDCTL_DSP_SETFMT:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               val = gus_audio_set_bits(val);
+               return __put_user(val, (int *)arg);
+               
+       case SOUND_PCM_READ_BITS:
+               return __put_user(gus_audio_bits, (int *)arg);
+               
+       case SOUND_PCM_WRITE_FILTER:            /* NOT POSSIBLE */
+       case SOUND_PCM_READ_FILTER:
+               return __put_user(-EINVAL, (int *)arg);
+       }
        return -EINVAL;
 }
 
@@ -2838,137 +2829,120 @@ set_input_volumes(void)
        restore_flags(flags);
 }
 
-int
-gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
 #define MIX_DEVS       (SOUND_MASK_MIC|SOUND_MASK_LINE| \
                         SOUND_MASK_SYNTH|SOUND_MASK_PCM)
-       if (((cmd >> 8) & 0xff) == 'M')
-         {
-                 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-                         switch (cmd & 0xff)
-                           {
-                           case SOUND_MIXER_RECSRC:
-                                   gus_recmask = *(int *) arg;
-                                   gus_recmask &= MIX_DEVS;
-                                   if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
-                                           gus_recmask = SOUND_MASK_MIC;
-                                   /* Note! Input volumes are updated during next open for recording */
-                                   return (*(int *) arg = gus_recmask);
-                                   break;
-
-                           case SOUND_MIXER_MIC:
-                                   {
-                                           int             vol;
-
-                                           vol = *(int *) arg;
-                                           vol &= 0xff;
-
-                                           if (vol < 0)
-                                                   vol = 0;
-                                           if (vol > 100)
-                                                   vol = 100;
-                                           gus_mic_vol = vol;
-                                           set_input_volumes();
-                                           return (*(int *) arg = vol | (vol << 8));
-                                   }
-                                   break;
-
-                           case SOUND_MIXER_LINE:
-                                   {
-                                           int             vol;
-
-                                           vol = *(int *) arg;
-                                           vol &= 0xff;
-
-                                           if (vol < 0)
-                                                   vol = 0;
-                                           if (vol > 100)
-                                                   vol = 100;
-                                           gus_line_vol = vol;
-                                           set_input_volumes();
-                                           return (*(int *) arg = vol | (vol << 8));
-                                   }
-                                   break;
-
-                           case SOUND_MIXER_PCM:
-                                   gus_pcm_volume = *(int *) arg;
-                                   gus_pcm_volume &= 0xff;
-                                   if (gus_pcm_volume < 0)
-                                           gus_pcm_volume = 0;
-                                   if (gus_pcm_volume > 100)
-                                           gus_pcm_volume = 100;
-                                   gus_audio_update_volume();
-                                   return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8));
-                                   break;
-
-                           case SOUND_MIXER_SYNTH:
-                                   {
-                                           int             voice;
-
-                                           gus_wave_volume = *(int *) arg;
-                                           gus_wave_volume &= 0xff;
-
-                                           if (gus_wave_volume < 0)
-                                                   gus_wave_volume = 0;
-                                           if (gus_wave_volume > 100)
-                                                   gus_wave_volume = 100;
-
-                                           if (active_device == GUS_DEV_WAVE)
-                                                   for (voice = 0; voice < nr_voices; voice++)
-                                                           dynamic_volume_change(voice);       /* Apply the new vol */
 
-                                           return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8));
-                                   }
-                                   break;
-
-                           default:
-                                   return -EINVAL;
-                 } else
-                         switch (cmd & 0xff)   /*
-                                                * Return parameters
-                                                */
-                           {
-
-                           case SOUND_MIXER_RECSRC:
-                                   return (*(int *) arg = gus_recmask);
-                                   break;
-
-                           case SOUND_MIXER_DEVMASK:
-                                   return (*(int *) arg = MIX_DEVS);
-                                   break;
+int gus_default_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+{
+       int vol, voice, val;
+
+       if (((cmd >> 8) & 0xff) == 'M') {
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               if (__get_user(gus_recmask, (int *)arg))
+                                       return -EFAULT;
+                               gus_recmask &= MIX_DEVS;
+                               if (!(gus_recmask & (SOUND_MASK_MIC | SOUND_MASK_LINE)))
+                                       gus_recmask = SOUND_MASK_MIC;
+                               /* Note! Input volumes are updated during next open for recording */
+                               return __put_user(gus_recmask, (int *)arg);
+
+                       case SOUND_MIXER_MIC:
+                               if (__get_user(vol, (int *)arg))
+                                       return -EFAULT;
+                               vol &= 0xff;
+                               if (vol < 0)
+                                       vol = 0;
+                               if (vol > 100)
+                                       vol = 100;
+                               gus_mic_vol = vol;
+                               set_input_volumes();
+                               vol |= (vol << 8);
+                               return __put_user(vol, (int *)arg);
+                               
+                       case SOUND_MIXER_LINE:
+                               if (__get_user(vol, (int *)arg))
+                                       return -EFAULT;
+                               vol &= 0xff;
+                               if (vol < 0)
+                                       vol = 0;
+                               if (vol > 100)
+                                       vol = 100;
+                               gus_line_vol = vol;
+                               set_input_volumes();
+                               vol |= (vol << 8);
+                               return __put_user(vol, (int *)arg);
+
+                       case SOUND_MIXER_PCM:
+                               if (__get_user(gus_pcm_volume, (int *)arg))
+                                       return -EFAULT;
+                               gus_pcm_volume &= 0xff;
+                               if (gus_pcm_volume < 0)
+                                       gus_pcm_volume = 0;
+                               if (gus_pcm_volume > 100)
+                                       gus_pcm_volume = 100;
+                               gus_audio_update_volume();
+                               gus_pcm_volume |= (gus_pcm_volume << 8);
+                               return __put_user(gus_pcm_volume, (int *)arg);
+
+                       case SOUND_MIXER_SYNTH:
+                               if (__get_user(gus_wave_volume, (int *)arg))
+                                       return -EFAULT;
+                               gus_wave_volume &= 0xff;
+                               if (gus_wave_volume < 0)
+                                       gus_wave_volume = 0;
+                               if (gus_wave_volume > 100)
+                                       gus_wave_volume = 100;
+                               if (active_device == GUS_DEV_WAVE)
+                                       for (voice = 0; voice < nr_voices; voice++)
+                                               dynamic_volume_change(voice);   /* Apply the new vol */
+                               gus_wave_volume |= (gus_wave_volume << 8);
+                               return __put_user(gus_wave_volume, (int *)arg);
+
+                       default:
+                               return -EINVAL;
+                       } else
+                               switch (cmd & 0xff) {
+                                       /*
+                                        * Return parameters
+                                        */
+                               case SOUND_MIXER_RECSRC:
+                                       return __put_user(gus_recmask, (int *)arg);
+                                       
+                               case SOUND_MIXER_DEVMASK:
+                                       return __put_user(MIX_DEVS, (int *)arg);
 
-                           case SOUND_MIXER_STEREODEVS:
-                                   return (*(int *) arg = 0);
-                                   break;
+                               case SOUND_MIXER_STEREODEVS:
+                                       return __put_user(0, (int *)arg);
 
-                           case SOUND_MIXER_RECMASK:
-                                   return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE);
-                                   break;
+                               case SOUND_MIXER_RECMASK:
+                                       val = SOUND_MASK_MIC | SOUND_MASK_LINE;
+                                       return __put_user(val, (int *)arg);
 
-                           case SOUND_MIXER_CAPS:
-                                   return (*(int *) arg = 0);
-                                   break;
+                               case SOUND_MIXER_CAPS:
+                                       return __put_user(0, (int *)arg);
 
-                           case SOUND_MIXER_MIC:
-                                   return (*(int *) arg = gus_mic_vol | (gus_mic_vol << 8));
-                                   break;
+                               case SOUND_MIXER_MIC:
+                                       val = gus_mic_vol | (gus_mic_vol << 8);
+                                       return __put_user(val, (int *)arg);
 
-                           case SOUND_MIXER_LINE:
-                                   return (*(int *) arg = gus_line_vol | (gus_line_vol << 8));
-                                   break;
+                               case SOUND_MIXER_LINE:
+                                       val = gus_line_vol | (gus_line_vol << 8);
+                                       return __put_user(val, (int *)arg);
 
-                           case SOUND_MIXER_PCM:
+                               case SOUND_MIXER_PCM:
+                                       val = ;
+                                       return __put_user(, (int *)arg);
                                    return (*(int *) arg = gus_pcm_volume | (gus_pcm_volume << 8));
                                    break;
 
-                           case SOUND_MIXER_SYNTH:
-                                   return (*(int *) arg = gus_wave_volume | (gus_wave_volume << 8));
-                                   break;
+                               case SOUND_MIXER_SYNTH:
+                                       return __put_user(gus_wave_volume | (gus_wave_volume << 8), (int *)arg);
 
-                           default:
-                                   return -EINVAL;
-                           }
+                               default:
+                                       return -EINVAL;
+                               }
        } else
                return -EINVAL;
 }
index 3c47f5a50177edb8ed1aa0ca87a0dd1033a3a256..fc4cd59cf1124dd6dee7d04df9f22ef016df4bc5 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 
@@ -115,79 +118,88 @@ static int set_volumes(int dev, int vol)
 
 static int ics2101_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       if (((cmd >> 8) & 0xff) == 'M')
-       {
-               if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               {
+       if (((cmd >> 8) & 0xff) == 'M') {
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
                        int val;
-
-                       val = *(int *) arg;
-
-                       switch (cmd & 0xff)
-                       {
-                               case SOUND_MIXER_RECSRC:
-                                       return gus_default_mixer_ioctl(dev, cmd, arg);
-
-                               case SOUND_MIXER_MIC:
-                                       return (*(int *) arg = set_volumes(DEV_MIC, val));
-
-                               case SOUND_MIXER_CD:
-                                       return (*(int *) arg = set_volumes(DEV_CD, val));
-
-                               case SOUND_MIXER_LINE:
-                                       return (*(int *) arg = set_volumes(DEV_LINE, val));
-
-                               case SOUND_MIXER_SYNTH:
-                                       return (*(int *) arg = set_volumes(DEV_GF1, val));
-
-                               case SOUND_MIXER_VOLUME:
-                                       return (*(int *) arg = set_volumes(DEV_VOL, val));
-
-                               default:
-                                       return -EINVAL;
+                       
+                       if (__get_user(val, (int *)arg))
+                               return -EFAULT;
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               return gus_default_mixer_ioctl(dev, cmd, arg);
+
+                       case SOUND_MIXER_MIC:
+                               val = set_volumes(DEV_MIC, val);
+                               break;
+                               
+                       case SOUND_MIXER_CD:
+                               val = set_volumes(DEV_CD, val);
+                               break;
+
+                       case SOUND_MIXER_LINE:
+                               val = set_volumes(DEV_LINE, val);
+                               break;
+
+                       case SOUND_MIXER_SYNTH:
+                               val = set_volumes(DEV_GF1, val);
+                               break;
+
+                       case SOUND_MIXER_VOLUME:
+                               val = set_volumes(DEV_VOL, val);
+                               break;
+
+                       default:
+                               return -EINVAL;
                        }
-               }
-               else
-               {
-                       switch (cmd & 0xff)     /*
-                                                * Return parameters
-                                                */
-                       {
-
-                               case SOUND_MIXER_RECSRC:
-                                       return gus_default_mixer_ioctl(dev, cmd, arg);
-
-                               case SOUND_MIXER_DEVMASK:
-                                       return (*(int *) arg = MIX_DEVS);
-
-                               case SOUND_MIXER_STEREODEVS:
-                                       return (*(int *) arg = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC);
-
-                               case SOUND_MIXER_RECMASK:
-                                       return (*(int *) arg = SOUND_MASK_MIC | SOUND_MASK_LINE);
-
-                               case SOUND_MIXER_CAPS:
-                                   return (*(int *) arg = 0);
-                                   break;
-
-                               case SOUND_MIXER_MIC:
-                                       return (*(int *) arg = volumes[DEV_MIC]);
-
-                               case SOUND_MIXER_LINE:
-                                       return (*(int *) arg = volumes[DEV_LINE]);
-
-                               case SOUND_MIXER_CD:
-                                       return (*(int *) arg = volumes[DEV_CD]);
-
-                               case SOUND_MIXER_VOLUME:
-                                       return (*(int *) arg = volumes[DEV_VOL]);
-
-                               case SOUND_MIXER_SYNTH:
-                                       return (*(int *) arg = volumes[DEV_GF1]);
-
-                               default:
-                                       return -EINVAL;
+                       return __put_user(val, (int *)arg);
+               } else {
+                       switch (cmd & 0xff) {
+                               /*
+                                * Return parameters
+                                */
+                       case SOUND_MIXER_RECSRC:
+                               return gus_default_mixer_ioctl(dev, cmd, arg);
+
+                       case SOUND_MIXER_DEVMASK:
+                               val = MIX_DEVS; 
+                               break;
+
+                       case SOUND_MIXER_STEREODEVS:
+                               val = SOUND_MASK_LINE | SOUND_MASK_CD | SOUND_MASK_SYNTH | SOUND_MASK_VOLUME | SOUND_MASK_MIC; 
+                               break;
+
+                       case SOUND_MIXER_RECMASK:
+                               val = SOUND_MASK_MIC | SOUND_MASK_LINE; 
+                               break;
+                               
+                       case SOUND_MIXER_CAPS:
+                               val = 0; 
+                               break;
+
+                       case SOUND_MIXER_MIC:
+                               val = volumes[DEV_MIC];
+                               break;
+                               
+                       case SOUND_MIXER_LINE:
+                               val = volumes[DEV_LINE];
+                               break;
+
+                       case SOUND_MIXER_CD:
+                               val = volumes[DEV_CD];
+                               break;
+
+                       case SOUND_MIXER_VOLUME:
+                               val = volumes[DEV_VOL];
+                               break;
+
+                       case SOUND_MIXER_SYNTH:
+                               val = volumes[DEV_GF1]; 
+                               break;
+
+                       default:
+                               return -EINVAL;
                        }
+                       return __put_user(val, (int *)arg);
                }
        }
        return -EINVAL;
index b123473cc59f06eecbf1ee3b02b9ea602add2319..6edb8552acb0d60cf2aaf7f44768b644a03090e3 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 #define USE_SEQ_MACROS
@@ -258,30 +261,23 @@ midi_synth_output(int dev)
         */
 }
 
-int
-midi_synth_ioctl(int dev,
-                unsigned int cmd, caddr_t arg)
+int midi_synth_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
        /*
         * int orig_dev = synth_devs[dev]->midi_dev;
         */
 
-       switch (cmd)
-         {
+       switch (cmd) {
 
-         case SNDCTL_SYNTH_INFO:
-                 memcpy((&((char *) arg)[0]), (char *) synth_devs[dev]->info, sizeof(struct synth_info));
+       case SNDCTL_SYNTH_INFO:
+               return __copy_to_user(arg, synth_devs[dev]->info, sizeof(struct synth_info));
+               
+       case SNDCTL_SYNTH_MEMAVL:
+               return 0x7fffffff;
 
-                 return 0;
-                 break;
-
-         case SNDCTL_SYNTH_MEMAVL:
-                 return 0x7fffffff;
-                 break;
-
-         default:
-                 return -EINVAL;
-         }
+       default:
+               return -EINVAL;
+       }
 }
 
 int
index a28476d920ed1041bcc4682b8ca87ba134dbdd37..16b1d6d2581af6e0d06759fa6221262c8e6ce3eb 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 #define MIDIBUF_C
@@ -451,39 +454,33 @@ MIDIbuf_read(int dev, struct fileinfo *file, char *buf, int count)
        return c;
 }
 
-int
-MIDIbuf_ioctl(int dev, struct fileinfo *file,
-             unsigned int cmd, caddr_t arg)
+int MIDIbuf_ioctl(int dev, struct fileinfo *file,
+                 unsigned int cmd, caddr_t arg)
 {
-       int             val;
+       int val;
 
        dev = dev >> 4;
-
-       if (((cmd >> 8) & 0xff) == 'C')
-         {
+       if (((cmd >> 8) & 0xff) == 'C') {
                  if (midi_devs[dev]->coproc)   /* Coprocessor ioctl */
                          return midi_devs[dev]->coproc->ioctl(midi_devs[dev]->coproc->devc, cmd, arg, 0);
-                 else
-                         printk("/dev/midi%d: No coprocessor for this device\n", dev);
-
+                 printk("/dev/midi%d: No coprocessor for this device\n", dev);
                  return -ENXIO;
        } else
-               switch (cmd)
-                 {
-
-                 case SNDCTL_MIDI_PRETIME:
-                         val = *(int *) arg;
-                         if (val < 0)
-                                 val = 0;
-
-                         val = (HZ * val) / 10;
-                         parms[dev].prech_timeout = val;
-                         return (*(int *) arg = val);
-                         break;
-
-                 default:
-                         return midi_devs[dev]->ioctl(dev, cmd, arg);
-                 }
+               switch (cmd) {
+               case SNDCTL_MIDI_PRETIME:
+                       if (__get_user(val, (int *)arg))
+                               return -EFAULT;
+                       if (val < 0)
+                               val = 0;
+                       val = (HZ * val) / 10;
+                       parms[dev].prech_timeout = val;
+                       return __put_user(val, (int *)arg);
+                       
+               default:
+                       if (!midi_devs[dev]->ioctl)
+                               return -EINVAL;
+                       return midi_devs[dev]->ioctl(dev, cmd, arg);
+               }
 }
 
 int
index cf00dc9e46f0a73b8e997feeff9018c573b0b9c8..830ffbd7de29fad562e75e0928688aa0700c0431 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -746,45 +749,34 @@ mpu401_end_read(int dev)
        return 0;
 }
 
-static int
-mpu401_ioctl(int dev, unsigned cmd, caddr_t arg)
+static int mpu401_ioctl(int dev, unsigned cmd, caddr_t arg)
 {
        struct mpu_config *devc;
-       int             val;
+       mpu_command_rec rec;
+       int val, ret;
 
        devc = &dev_conf[dev];
+       switch (cmd) {
+       case SNDCTL_MIDI_MPUMODE:
+               if (!(devc->capabilities & MPU_CAP_INTLG)) { /* No intelligent mode */
+                       printk("MPU-401: Intelligent mode not supported by the HW\n");
+                       return -EINVAL;
+               }
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               set_uart_mode(dev, devc, !val);
+               return 0;
 
-       switch (cmd)
-         {
-         case SNDCTL_MIDI_MPUMODE:
-                 if (!(devc->capabilities & MPU_CAP_INTLG))    /* No intelligent mode */
-                   {
-                           printk("MPU-401: Intelligent mode not supported by the HW\n");
-                           return -EINVAL;
-                   }
-                 val = *(int *) arg;
-                 set_uart_mode(dev, devc, !val);
-                 return 0;
-                 break;
-
-         case SNDCTL_MIDI_MPUCMD:
-                 {
-                         int             ret;
-                         mpu_command_rec rec;
-
-                         memcpy((char *) &rec, (&((char *) arg)[0]), sizeof(rec));
-
-                         if ((ret = mpu401_command(dev, &rec)) < 0)
-                                 return ret;
+       case SNDCTL_MIDI_MPUCMD:
+               if (__copy_from_user(&rec, arg, sizeof(rec)))
+                       return -EFAULT;
+               if ((ret = mpu401_command(dev, &rec)) < 0)
+                       return ret;
+               return __copy_to_user(arg, &rec, sizeof(rec));
 
-                         memcpy((&((char *) arg)[0]), (char *) &rec, sizeof(rec));
-                         return 0;
-                 }
-                 break;
-
-         default:
-                 return -EINVAL;
-         }
+       default:
+               return -EINVAL;
+       }
 }
 
 static void
index fd3cf911c92072e14d6c2e9ebb56b545f33c255d..8d50d6fab235f5dc04644fcb3be8a471fb3444bc 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -102,40 +105,33 @@ static void enter_4op_mode(void)
 
 static int opl3_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       switch (cmd)
-       {
-
-               case SNDCTL_FM_LOAD_INSTR:
-               {
-                       struct sbi_instrument ins;
-
-                       printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
-                       memcpy((char *) &ins, (&((char *) arg)[0]), sizeof(ins));
-
-                       if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR)
-                       {
-                               printk("FM Error: Invalid instrument number %d\n", ins.channel);
-                               return -EINVAL;
-                       }
-                       return store_instr(ins.channel, &ins);
+       struct sbi_instrument ins;
+       
+       switch (cmd) {
+       case SNDCTL_FM_LOAD_INSTR:
+               printk(KERN_WARNING "Warning: Obsolete ioctl(SNDCTL_FM_LOAD_INSTR) used. Fix the program.\n");
+               if (__copy_from_user(&ins, arg, sizeof(ins)))
+                       return -EFAULT;
+               if (ins.channel < 0 || ins.channel >= SBFM_MAXINSTR) {
+                       printk("FM Error: Invalid instrument number %d\n", ins.channel);
+                       return -EINVAL;
                }
+               return store_instr(ins.channel, &ins);
 
-               case SNDCTL_SYNTH_INFO:
-                       devc->fm_info.nr_voices = 
-                               (devc->nr_voice == 12) ? 6 : devc->nr_voice;
-                       memcpy((&((char *) arg)[0]), (char *) &devc->fm_info, sizeof(devc->fm_info));
-                       return 0;
+       case SNDCTL_SYNTH_INFO:
+               devc->fm_info.nr_voices = (devc->nr_voice == 12) ? 6 : devc->nr_voice;
+               return __copy_to_user(arg, &devc->fm_info, sizeof(devc->fm_info));
 
-               case SNDCTL_SYNTH_MEMAVL:
-                       return 0x7fffffff;
+       case SNDCTL_SYNTH_MEMAVL:
+               return 0x7fffffff;
 
-               case SNDCTL_FM_4OP_ENABLE:
-                       if (devc->model == 2)
-                               enter_4op_mode();
-                       return 0;
+       case SNDCTL_FM_4OP_ENABLE:
+               if (devc->model == 2)
+                       enter_4op_mode();
+               return 0;
 
-               default:
-                       return -EINVAL;
+       default:
+               return -EINVAL;
        }
 }
 
index 45b60fefd2876b081c431252b09f95ac6bfa2a37..72120b83be74a2c1e9b6f49b66929fec74a64442 100644 (file)
@@ -185,12 +185,6 @@ pas_midi_end_read(int dev)
        return 0;
 }
 
-static int
-pas_midi_ioctl(int dev, unsigned cmd, caddr_t arg)
-{
-       return -EINVAL;
-}
-
 static void
 pas_midi_kick(int dev)
 {
@@ -213,7 +207,7 @@ static struct midi_operations pas_midi_operations =
        {0},
        pas_midi_open,
        pas_midi_close,
-       pas_midi_ioctl,
+       NULL,
        pas_midi_out,
        pas_midi_start_read,
        pas_midi_end_read,
index 335e7dd39379ce80b7b24ce2b2d0fdd5af7dc88f..ae9d05ec837a558657c240adad9416302f63ebc2 100644 (file)
@@ -12,6 +12,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 #include "sound_config.h"
@@ -211,122 +214,97 @@ pas_mixer_reset(void)
        set_mode(0x04 | 0x01);
 }
 
-static int
-pas_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+static int pas_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
-
-       if (cmd == SOUND_MIXER_PRIVATE1)        /* Set loudness bit */
-         {
-                 int             level;
-
-                 level = *(int *) arg;
-
-                 if (level == -1)      /* Return current settings */
-                   {
-                           if (mode_control & 0x04)
-                                   return (*(int *) arg = 1);
-                           else
-                                   return (*(int *) arg = 0);
-                 } else
-                   {
-                           mode_control &= ~0x04;
-                           if (level)
-                                   mode_control |= 0x04;
-                           set_mode(mode_control);
-                           return (*(int *) arg = !!level);    /* 0 or 1 */
-                   }
-         }
-       if (cmd == SOUND_MIXER_PRIVATE2)        /* Set enhance bit */
-         {
-                 int             level;
+       int level, v;
 
-                 level = *(int *) arg;
-
-                 if (level == -1)      /* Return current settings */
-                   {
-                           if (!(mode_control & 0x03))
-                                   return (*(int *) arg = 0);
-                           return (*(int *) arg = ((mode_control & 0x03) + 1) * 20);
-                 } else
-                   {
-                           int             i = 0;
-
-                           level &= 0x7f;
-                           if (level)
-                                   i = (level / 20) - 1;
-
-                           mode_control &= ~0x03;
-                           mode_control |= i & 0x03;
-                           set_mode(mode_control);
-
-                           if (i)
-                                   i = (i + 1) * 20;
-
-                           return i;
-                   }
-         }
-       if (cmd == SOUND_MIXER_PRIVATE3)        /* Set mute bit */
-         {
-                 int             level;
-
-                 level = *(int *) arg;
-
-                 if (level == -1)      /* Return current settings */
-                   {
-                           return (*(int *) arg = !(pas_read(0x0B8A) & 0x20));
-                 } else
-                   {
-                           if (level)
-                                   pas_write(pas_read(0x0B8A) & (~0x20),
-                                             0x0B8A);
-                           else
-                                   pas_write(pas_read(0x0B8A) | 0x20,
-                                             0x0B8A);
-
-                           return !(pas_read(0x0B8A) & 0x20);
-                   }
-         }
-       if (((cmd >> 8) & 0xff) == 'M')
-         {
-                 int             v;
-
-                 v = *(int *) arg;
-
-                 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-                         return (*(int *) arg = pas_mixer_set(cmd & 0xff, v));
-                 else
-                   {
-
-                           switch (cmd & 0xff)
-                             {
-
-                             case SOUND_MIXER_RECSRC:
-                                     return (*(int *) arg = rec_devices);
-                                     break;
-
-                             case SOUND_MIXER_STEREODEVS:
-                                     return (*(int *) arg = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE));
-                                     break;
-
-                             case SOUND_MIXER_DEVMASK:
-                                     return (*(int *) arg = SUPPORTED_MIXER_DEVICES);
-                                     break;
-
-                             case SOUND_MIXER_RECMASK:
-                                     return (*(int *) arg = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES);
-                                     break;
-
-                             case SOUND_MIXER_CAPS:
-                                     return (*(int *) arg = 0);        /* No special capabilities */
-                                     break;
-
-
-                             default:
-                                     return (*(int *) arg = levels[cmd & 0xff]);
-                             }
-                   }
-         }
+       DEB(printk("pas2_mixer.c: int pas_mixer_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
+       if (cmd == SOUND_MIXER_PRIVATE1) { /* Set loudness bit */
+               if (__get_user(level, (int *)arg))
+                       return -EFAULT;
+               if (level == -1)  /* Return current settings */
+                       level = (mode_control & 0x04);
+               else {
+                       mode_control &= ~0x04;
+                       if (level)
+                               mode_control |= 0x04;
+                       set_mode(mode_control);
+               }
+               level = !!level;
+               return __put_user(level, (int *)arg);
+       }
+       if (cmd == SOUND_MIXER_PRIVATE2) { /* Set enhance bit */
+               if (__get_user(level, (int *)arg))
+                       return -EFAULT;
+               if (level == -1) { /* Return current settings */
+                       if (!(mode_control & 0x03))
+                               level = 0;
+                       else
+                               level = ((mode_control & 0x03) + 1) * 20;
+               } else {
+                       int i = 0;
+                       
+                       level &= 0x7f;
+                       if (level)
+                               i = (level / 20) - 1;
+                       mode_control &= ~0x03;
+                       mode_control |= i & 0x03;
+                       set_mode(mode_control);
+                       if (i)
+                               i = (i + 1) * 20;
+                       level = i;
+               }
+               return __put_user(level, (int *)arg);
+       }
+       if (cmd == SOUND_MIXER_PRIVATE3) { /* Set mute bit */
+               if (__get_user(level, (int *)arg))
+                       return -EFAULT;
+               if (level == -1)        /* Return current settings */
+                       level = = !(pas_read(0x0B8A) & 0x20);
+               else {
+                       if (level)
+                               pas_write(pas_read(0x0B8A) & (~0x20), 0x0B8A);
+                       else
+                               pas_write(pas_read(0x0B8A) | 0x20, 0x0B8A);
+
+                       level = !(pas_read(0x0B8A) & 0x20);
+               }
+               return __put_user(level, (int *)arg);
+       }
+       if (((cmd >> 8) & 0xff) == 'M') {
+               if (__get_user(v, (int *)arg))
+                       return -EFAULT;
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+                       v = pas_mixer_set(cmd & 0xff, v);
+               } else {
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               v = rec_devices;
+                               break;
+                               
+                       case SOUND_MIXER_STEREODEVS:
+                               v = SUPPORTED_MIXER_DEVICES & ~(SOUND_MASK_BASS | SOUND_MASK_TREBLE);
+                               break;
+                               
+                       case SOUND_MIXER_DEVMASK:
+                               v = SUPPORTED_MIXER_DEVICES;
+                               break;
+                               
+                       case SOUND_MIXER_RECMASK:
+                               v = POSSIBLE_RECORDING_DEVICES & SUPPORTED_MIXER_DEVICES;
+                               break;
+                               
+                       case SOUND_MIXER_CAPS:
+                               v = 0;  /* No special capabilities */
+                               break;
+                               
+                       default:
+                               v = levels[cmd & 0xff];
+                               break;
+                       }
+               }
+               return __put_user(v, (int *)arg);
+       }
        return -EINVAL;
 }
 
index 99e89716103be2cd3471e9cb1337da424ce21cea..c155dc3a673ad6c21f56a68c468e265d45d68205 100644 (file)
@@ -8,6 +8,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 #include "sound_config.h"
@@ -144,51 +147,53 @@ pcm_set_bits(int arg)
        return pcm_bits;
 }
 
-static int
-pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
+static int pas_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       int             val;
+       int val, ret;
 
        DEB(printk("pas2_pcm.c: static int pas_audio_ioctl(unsigned int cmd = %X, unsigned int arg = %X)\n", cmd, arg));
 
-       switch (cmd)
-         {
-         case SOUND_PCM_WRITE_RATE:
-                 val = *(int *) arg;
-                 return (*(int *) arg = pcm_set_speed(val));
-                 break;
-
-         case SOUND_PCM_READ_RATE:
-                 return (*(int *) arg = pcm_speed);
-                 break;
-
-         case SNDCTL_DSP_STEREO:
-                 val = *(int *) arg;
-                 return (*(int *) arg = pcm_set_channels(val + 1) - 1);
-                 break;
-
-         case SOUND_PCM_WRITE_CHANNELS:
-                 val = *(int *) arg;
-                 return (*(int *) arg = pcm_set_channels(val));
-                 break;
-
-         case SOUND_PCM_READ_CHANNELS:
-                 return (*(int *) arg = pcm_channels);
-                 break;
-
-         case SNDCTL_DSP_SETFMT:
-                 val = *(int *) arg;
-                 return (*(int *) arg = pcm_set_bits(val));
-                 break;
-
-         case SOUND_PCM_READ_BITS:
-                 return (*(int *) arg = pcm_bits);
-
-         default:
-                 return -EINVAL;
-         }
-
-       return -EINVAL;
+       switch (cmd) {
+       case SOUND_PCM_WRITE_RATE:
+               if (__get_user(val, (int *)arg)) 
+                       return -EFAULT;
+               ret = pcm_set_speed(val);
+               break;
+
+       case SOUND_PCM_READ_RATE:
+               ret = pcm_speed;
+               break;
+               
+       case SNDCTL_DSP_STEREO:
+               if (__get_user(val, (int *)arg)) 
+                       return -EFAULT;
+               ret = pcm_set_channels(val + 1) - 1;
+               break;
+
+       case SOUND_PCM_WRITE_CHANNELS:
+               if (__get_user(val, (int *)arg)) 
+                       return -EFAULT;
+               ret = pcm_set_channels(val);
+               break;
+
+       case SOUND_PCM_READ_CHANNELS:
+               ret = pcm_channels;
+               break;
+
+       case SNDCTL_DSP_SETFMT:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               ret = pcm_set_bits(val);
+               break;
+               
+       case SOUND_PCM_READ_BITS:
+               ret = pcm_bits;
+               break;
+  
+       default:
+               return -EINVAL;
+       }
+       return __put_user(ret, (int *)arg);
 }
 
 static void
index bbe1ab222cbf110a70b54ec9cac3bd72c3665c8b..838695abc1014f4df3602099e29b9051c351bc78 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -498,257 +501,177 @@ download_boot_block(void *dev_info, copr_buffer * buf)
        return 0;
 }
 
-static int
-pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local)
+static int pss_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local)
 {
+       copr_buffer *buf;
+       copr_msg *mbuf;
+       copr_debug_buf dbuf;
+       unsigned short tmp;
+       unsigned long flags;
+       unsigned short *data;
+       int i, err;
        /* printk( "PSS coproc ioctl %x %x %d\n",  cmd,  arg,  local); */
+       
+       switch (cmd) {
+       case SNDCTL_COPR_RESET:
+               pss_coproc_reset(dev_info);
+               return 0;
 
-       switch (cmd)
-         {
-         case SNDCTL_COPR_RESET:
-                 pss_coproc_reset(dev_info);
-                 return 0;
-                 break;
-
-         case SNDCTL_COPR_LOAD:
-                 {
-                         copr_buffer    *buf;
-                         int             err;
-
-                         buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
-                         if (buf == NULL)
-                                 return -ENOSPC;
-
-                         memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf));
-                         err = download_boot_block(dev_info, buf);
-                         vfree(buf);
-                         return err;
-                 }
-                 break;
-
-         case SNDCTL_COPR_SENDMSG:
-                 {
-                         copr_msg       *buf;
-                         unsigned long   flags;
-                         unsigned short *data;
-                         int             i;
-
-                         buf = (copr_msg *) vmalloc(sizeof(copr_msg));
-                         if (buf == NULL)
-                                 return -ENOSPC;
-
-                         memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf));
-
-                         data = (unsigned short *) (buf->data);
-
-                         save_flags(flags);
-                         cli();
-
-                         for (i = 0; i < buf->len; i++)
-                           {
-                                   if (!pss_put_dspword(devc, *data++))
-                                     {
-                                             restore_flags(flags);
-                                             buf->len = i;     /* feed back number of WORDs sent */
-                                             memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf));
-                                             vfree(buf);
-                                             return -EIO;
-                                     }
-                           }
-
-                         restore_flags(flags);
-                         vfree(buf);
-
-                         return 0;
-                 }
-                 break;
-
-
-         case SNDCTL_COPR_RCVMSG:
-                 {
-                         copr_msg       *buf;
-                         unsigned long   flags;
-                         unsigned short *data;
-                         unsigned int    i;
-                         int             err = 0;
-
-                         buf = (copr_msg *) vmalloc(sizeof(copr_msg));
-                         if (buf == NULL)
-                                 return -ENOSPC;
-
-
-                         data = (unsigned short *) buf->data;
-
-                         save_flags(flags);
-                         cli();
-
-                         for (i = 0; i < buf->len; i++)
-                           {
-                                   buf->len = i;       /* feed back number of WORDs read */
-                                   if (!pss_get_dspword(devc, data++))
-                                     {
-                                             if (i == 0)
-                                                     err = -EIO;
-                                             break;
-                                     }
-                           }
-
-                         restore_flags(flags);
-
-                         memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf));
-                         vfree(buf);
-
-                         return err;
-                 }
-                 break;
-
-
-         case SNDCTL_COPR_RDATA:
-                 {
-                         copr_debug_buf  buf;
-                         unsigned long   flags;
-                         unsigned short  tmp;
-
-                         memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf));
-
-                         save_flags(flags);
-                         cli();
-                         if (!pss_put_dspword(devc, 0x00d0))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff)))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         if (!pss_get_dspword(devc, &tmp))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         buf.parm1 = tmp;
-                         restore_flags(flags);
-
-                         memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf));
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_COPR_WDATA:
-                 {
-                         copr_debug_buf  buf;
-                         unsigned long   flags;
-                         unsigned short  tmp;
-
-                         memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf));
-
-                         save_flags(flags);
-                         cli();
-                         if (!pss_put_dspword(devc, 0x00d1))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff)))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         tmp = (unsigned int) buf.parm2 & 0xffff;
-                         if (!pss_put_dspword(devc, tmp))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         restore_flags(flags);
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_COPR_WCODE:
-                 {
-                         copr_debug_buf  buf;
-                         unsigned long   flags;
-                         unsigned short  tmp;
-
-                         memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf));
-
-                         save_flags(flags);
-                         cli();
-                         if (!pss_put_dspword(devc, 0x00d3))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff)))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         tmp = (unsigned int) buf.parm2 & 0x00ff;
-                         if (!pss_put_dspword(devc, tmp))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         tmp = ((unsigned int) buf.parm2 >> 8) & 0xffff;
-                         if (!pss_put_dspword(devc, tmp))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         restore_flags(flags);
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_COPR_RCODE:
-                 {
-                         copr_debug_buf  buf;
-                         unsigned long   flags;
-                         unsigned short  tmp;
-
-                         memcpy((char *) &buf, (&((char *) arg)[0]), sizeof(buf));
-
-                         save_flags(flags);
-                         cli();
-                         if (!pss_put_dspword(devc, 0x00d2))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         if (!pss_put_dspword(devc, (unsigned short) (buf.parm1 & 0xffff)))
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         if (!pss_get_dspword(devc, &tmp))     /* Read MSB */
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         buf.parm1 = tmp << 8;
-
-                         if (!pss_get_dspword(devc, &tmp))     /* Read LSB */
-                           {
-                                   restore_flags(flags);
-                                   return -EIO;
-                           }
-                         buf.parm1 |= tmp & 0x00ff;
-
-                         restore_flags(flags);
-
-                         memcpy((&((char *) arg)[0]), (char *) &buf, sizeof(buf));
-                         return 0;
-                 }
-                 break;
-
-         default:
-                 return -EINVAL;
-         }
+       case SNDCTL_COPR_LOAD:
+               buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+               if (buf == NULL)
+                       return -ENOSPC;
+               if (__copy_from_user(buf, arg, sizeof(copr_buffer))) {
+                       vfree(buf);
+                       return -EFAULT;
+               }
+               err = download_boot_block(dev_info, buf);
+               vfree(buf);
+               return err;
+               
+       case SNDCTL_COPR_SENDMSG:
+               mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+               if (mbuf == NULL)
+                       return -ENOSPC;
+               if (__copy_from_user(mbuf, arg, sizeof(copr_msg))) {
+                       vfree(mbuf);
+                       return -EFAULT;
+               }
+               data = (unsigned short *)(mbuf->data);
+               save_flags(flags);
+               cli();
+               for (i = 0; i < mbuf->len; i++) {
+                       if (!pss_put_dspword(devc, *data++)) {
+                               restore_flags(flags);
+                               mbuf->len = i;  /* feed back number of WORDs sent */
+                               err = __copy_to_user(arg, mbuf, sizeof(copr_msg));
+                               vfree(mbuf);
+                               return err ? err : -EIO;
+                       }
+               }
+               restore_flags(flags);
+               vfree(mbuf);
+               return 0;
 
+       case SNDCTL_COPR_RCVMSG:
+               err = 0;
+               mbuf = (copr_msg *)vmalloc(sizeof(copr_msg));
+               if (mbuf == NULL)
+                       return -ENOSPC;
+               data = (unsigned short *)mbuf->data;
+               save_flags(flags);
+               cli();
+               for (i = 0; i < mbuf->len; i++) {
+                       mbuf->len = i;  /* feed back number of WORDs read */
+                       if (!pss_get_dspword(devc, data++)) {
+                               if (i == 0)
+                                       err = -EIO;
+                               break;
+                       }
+               }
+               restore_flags(flags);
+               if (__copy_to_user(arg, mbuf, sizeof(copr_msg)))
+                       err = -EFAULT;
+               vfree(mbuf);
+               return err;
+               
+       case SNDCTL_COPR_RDATA:
+               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                       return -EFAULT;
+               save_flags(flags);
+               cli();
+               if (!pss_put_dspword(devc, 0x00d0)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               if (!pss_get_dspword(devc, &tmp)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               dbuf.parm1 = tmp;
+               restore_flags(flags);
+               return __copy_to_user(arg, &dbuf, sizeof(dbuf));
+               
+       case SNDCTL_COPR_WDATA:
+               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                       return -EFAULT;
+               save_flags(flags);
+               cli();
+               if (!pss_put_dspword(devc, 0x00d1)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               if (!pss_put_dspword(devc, (unsigned short) (dbuf.parm1 & 0xffff))) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               tmp = (unsigned int)dbuf.parm2 & 0xffff;
+               if (!pss_put_dspword(devc, tmp)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               restore_flags(flags);
+               return 0;
+               
+       case SNDCTL_COPR_WCODE:
+               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                       return -EFAULT;
+               save_flags(flags);
+               cli();
+               if (!pss_put_dspword(devc, 0x00d3)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               tmp = (unsigned int)dbuf.parm2 & 0x00ff;
+               if (!pss_put_dspword(devc, tmp)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               tmp = ((unsigned int)dbuf.parm2 >> 8) & 0xffff;
+               if (!pss_put_dspword(devc, tmp)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               restore_flags(flags);
+               return 0;
+               
+       case SNDCTL_COPR_RCODE:
+               if (__copy_from_user(&dbuf, arg, sizeof(dbuf)))
+                       return -EFAULT;
+               save_flags(flags);
+               cli();
+               if (!pss_put_dspword(devc, 0x00d2)) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               if (!pss_put_dspword(devc, (unsigned short)(dbuf.parm1 & 0xffff))) {
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               if (!pss_get_dspword(devc, &tmp)) { /* Read MSB */
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               dbuf.parm1 = tmp << 8;
+               if (!pss_get_dspword(devc, &tmp)) { /* Read LSB */
+                       restore_flags(flags);
+                       return -EIO;
+               }
+               dbuf.parm1 |= tmp & 0x00ff;
+               restore_flags(flags);
+               return __copy_to_user(arg, &dbuf, sizeof(dbuf));
+
+       default:
+               return -EINVAL;
+       }
        return -EINVAL;
 }
 
index 4efb4be2b5e94ccc96224c8dfdd9f270bf361f7a..fc28aa2391594cba3337141c3bf45a2a49f2eaed 100644 (file)
@@ -956,18 +956,13 @@ static void sb16_audio_trigger(int dev, int bits)
        devc->trigger_bits = bits;
 }
 
-static int sb_audio_ioctl(int dev, unsigned int cmd, caddr_t arg)
-{
-       return -EINVAL;
-}
-
 static struct audio_driver sb1_audio_driver =  /* SB1.x */
 {
        sb_audio_open,
        sb_audio_close,
        sb_set_output_parms,
        sb_set_input_parms,
-       sb_audio_ioctl,
+       NULL, /* ioctl */
        sb1_audio_prepare_for_input,
        sb1_audio_prepare_for_output,
        sb1_audio_halt_xfer,
index 57cdc59e325b0bc6b7d57f18d839b3de06980b5a..fddf74b7951ade0c916328c16a0329500f34a3f1 100644 (file)
@@ -34,10 +34,10 @@ int
 probe_sb(struct address_info *hw_config)
 {
        if (check_region(hw_config->io_base, 16))
-         {
-                 printk("\n\nsb_dsp.c: I/O port %x already in use\n\n", hw_config->io_base);
-                 return 0;
-         }
+       {
+               printk("\n\nsb_card.c: I/O port %x is already in use\n\n", hw_config->io_base);
+               return 0;
+       }
        return sb_dsp_detect(hw_config);
 }
 
@@ -85,37 +85,36 @@ static int      sbmpu = 0;
 
 void           *smw_free = NULL;
 
-int
-init_module(void)
+int init_module(void)
 {
-       printk("Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
+       printk(KERN_INFO "Soundblaster audio driver Copyright (C) by Hannu Savolainen 1993-1996\n");
 
        if (mad16 == 0 && trix == 0 && pas2 == 0)
-         {
-                 if (io == -1 || dma == -1 || irq == -1)
-                   {
-                           printk("I/O, IRQ, DMA and type are mandatory\n");
-                           return -EINVAL;
-                   }
-                 config.io_base = io;
-                 config.irq = irq;
-                 config.dma = dma;
-                 config.dma2 = dma16;
-                 config.card_subtype = type;
-
-                 if (!probe_sb(&config))
-                         return -ENODEV;
-                 attach_sb_card(&config);
+       {
+               if (io == -1 || dma == -1 || irq == -1)
+               {
+                       printk(KERN_ERR "I/O, IRQ, and DMA are mandatory\n");
+                       return -EINVAL;
+               }
+               config.io_base = io;
+               config.irq = irq;
+               config.dma = dma;
+               config.dma2 = dma16;
+               config.card_subtype = type;
+
+               if (!probe_sb(&config))
+                       return -ENODEV;
+               attach_sb_card(&config);
 #ifdef CONFIG_MIDI
-                 config_mpu.io_base = mpu_io;
-                 if (mpu_io && probe_sbmpu(&config_mpu))
-                         sbmpu = 1;
+               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);
+               if (sbmpu)
+                       attach_sbmpu(&config_mpu);
 #endif
-         }
+       }
        SOUND_LOCK;
        return 0;
 }
index 06acc19ef02372bd03a3b3505b157b99c0c0ff52..b08f8d43f0a1c091fce9ca7bb10b6746dc396e18 100644 (file)
@@ -128,10 +128,10 @@ sb_midi_end_read(int dev)
        return 0;
 }
 
-static int
-sb_midi_ioctl(int dev, unsigned cmd, caddr_t arg)
+/* why -EPERM and not -EINVAL?? */
+static int sb_midi_ioctl(int dev, unsigned cmd, caddr_t arg)
 {
-       return -EPERM;
+        return -EPERM;
 }
 
 void
index 6a7070e286871a512e87fb08076fcb2d7253ab99..9171360b33cf7b8a09006b7e5038d14241ad5ef7 100644 (file)
@@ -11,6 +11,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 
@@ -281,68 +284,61 @@ set_recmask(sb_devc * devc, int mask)
        return devc->recmask;
 }
 
-static int
-sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
+static int sb_mixer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       sb_devc        *devc = mixer_devs[dev]->devc;
-       int             val;
-
-/*
- * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1).
- */
-       if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16)
-         {
-                 int             tmp;
-
-                 tmp = *(int *) arg;
-
-                 sb_setmixer(devc, 0x43, (~tmp) & 0x01);
-                 return 0;
-         }
-       if (((cmd >> 8) & 0xff) == 'M')
-         {
-                 if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-                         switch (cmd & 0xff)
-                           {
-                           case SOUND_MIXER_RECSRC:
-                                   val = *(int *) arg;
-                                   return (*(int *) arg = set_recmask(devc, val));
-                                   break;
-
-                           default:
-
-                                   val = *(int *) arg;
-                                   return (*(int *) arg = sb_mixer_set(devc, cmd & 0xff, val));
+       sb_devc *devc = mixer_devs[dev]->devc;
+       int val, ret;
+
+       /*
+        * Use ioctl(fd, SOUND_MIXER_PRIVATE1, &mode) to turn AGC off (0) or on (1).
+        */
+       if (cmd == SOUND_MIXER_PRIVATE1 && devc->model == MDL_SB16) {
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               sb_setmixer(devc, 0x43, (~val) & 0x01);
+               return 0;
+       }
+       if (((cmd >> 8) & 0xff) == 'M') {
+               if (_SIOC_DIR(cmd) & _SIOC_WRITE) {
+                       if (__get_user(val, (int *)arg))
+                               return -EFAULT;
+                       switch (cmd & 0xff) {
+                       case SOUND_MIXER_RECSRC:
+                               ret = set_recmask(devc, val);
+                               break;
+
+                       default:
+                               ret = sb_mixer_set(devc, cmd & 0xff, val);
+                       }
                  } else
-                         switch (cmd & 0xff)
-                           {
-
-                           case SOUND_MIXER_RECSRC:
-                                   return (*(int *) arg = devc->recmask);
-                                   break;
-
-                           case SOUND_MIXER_DEVMASK:
-                                   return (*(int *) arg = devc->supported_devices);
-                                   break;
-
-                           case SOUND_MIXER_STEREODEVS:
-                                   if (devc->model == MDL_JAZZ || devc->model == MDL_SMW)
-                                           return (*(int *) arg = devc->supported_devices);
-                                   else
-                                           return (*(int *) arg = devc->supported_devices & ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX));
-                                   break;
-
-                           case SOUND_MIXER_RECMASK:
-                                   return (*(int *) arg = devc->supported_rec_devices);
-                                   break;
-
-                           case SOUND_MIXER_CAPS:
-                                   return (*(int *) arg = devc->mixer_caps);
-                                   break;
-
-                           default:
-                                   return (*(int *) arg = sb_mixer_get(devc, cmd & 0xff));
-                           }
+                         switch (cmd & 0xff) {
+                         case SOUND_MIXER_RECSRC:
+                                 ret = devc->recmask;
+                                 break;
+                                 
+                         case SOUND_MIXER_DEVMASK:
+                                 ret = devc->supported_devices;
+                                 break;
+                                 
+                         case SOUND_MIXER_STEREODEVS:
+                                 ret = devc->supported_devices;
+                                 if (devc->model != MDL_JAZZ && devc->model != MDL_SMW)
+                                         ret &= ~(SOUND_MASK_MIC | SOUND_MASK_SPEAKER | SOUND_MASK_IMIX);
+                                 break;
+                                 
+                         case SOUND_MIXER_RECMASK:
+                                 ret = devc->supported_rec_devices;
+                                 break;
+                                 
+                         case SOUND_MIXER_CAPS:
+                                 ret = devc->mixer_caps;
+                                 break;
+                                   
+                         default:
+                                 ret = sb_mixer_get(devc, cmd & 0xff);
+                                 break;
+                         }
+               return __put_user(ret, (int *)arg); 
        } else
                return -EINVAL;
 }
index fe18beea9a2f1e3b491ee44216105dfac4a29d9b..17247a9796491b2137eccf6c0d9dbc38ba8840d5 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 
@@ -1517,303 +1520,207 @@ seq_panic(void)
         */
 }
 
-int
-sequencer_ioctl(int dev, struct fileinfo *file,
-               unsigned int cmd, caddr_t arg)
+int sequencer_ioctl(int dev, struct fileinfo *file,
+                   unsigned int cmd, caddr_t arg)
 {
-       int             midi_dev, orig_dev, val;
-       int             mode = file->mode & O_ACCMODE;
+       int midi_dev, orig_dev, val, err;
+       int mode = file->mode & O_ACCMODE;
+       struct synth_info inf;
+       struct seq_event_rec event_rec;
+       unsigned long flags;
 
        orig_dev = dev = dev >> 4;
 
-       switch (cmd)
-         {
-         case SNDCTL_TMR_TIMEBASE:
-         case SNDCTL_TMR_TEMPO:
-         case SNDCTL_TMR_START:
-         case SNDCTL_TMR_STOP:
-         case SNDCTL_TMR_CONTINUE:
-         case SNDCTL_TMR_METRONOME:
-         case SNDCTL_TMR_SOURCE:
-
-                 if (seq_mode != SEQ_2)
-                         return -EINVAL;
-                 return tmr->ioctl(tmr_no, cmd, arg);
-                 break;
-
-         case SNDCTL_TMR_SELECT:
-
-                 if (seq_mode != SEQ_2)
-                         return -EINVAL;
-                 pending_timer = *(int *) arg;
-
-                 if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL)
-                   {
-                           pending_timer = -1;
-                           return -EINVAL;
-                   }
-                 return (*(int *) arg = pending_timer);
-                 break;
-
-         case SNDCTL_SEQ_PANIC:
-                 seq_panic();
-                 break;
-
-         case SNDCTL_SEQ_SYNC:
-
-                 if (mode == OPEN_READ)
-                         return 0;
-                 while (qlen > 0 && !signal_pending(current))
-                         seq_sync();
-                 if (qlen)
-                         return -EINTR;
-                 else
-                         return 0;
-                 break;
-
-         case SNDCTL_SEQ_RESET:
-
-                 seq_reset();
-                 return 0;
-                 break;
-
-         case SNDCTL_SEQ_TESTMIDI:
-                 midi_dev = *(int *) arg;
-                 if (midi_dev < 0 || midi_dev >= max_mididev)
-                         return -ENXIO;
-
-                 if (!midi_opened[midi_dev])
-                   {
-                           int             err, mode;
-
-                           mode = file->mode & O_ACCMODE;
-                           if ((err = midi_devs[midi_dev]->open(midi_dev, mode,
-                                                   sequencer_midi_input,
-                                            sequencer_midi_output)) < 0)
-                                   return err;
-                   }
-                 midi_opened[midi_dev] = 1;
-
-                 return 0;
-                 break;
-
-         case SNDCTL_SEQ_GETINCOUNT:
-                 if (mode == OPEN_WRITE)
-                         return 0;
-                 return (*(int *) arg = iqlen);
-                 break;
-
-         case SNDCTL_SEQ_GETOUTCOUNT:
-
-                 if (mode == OPEN_READ)
-                         return 0;
-                 return (*(int *) arg = SEQ_MAX_QUEUE - qlen);
-                 break;
-
-         case SNDCTL_SEQ_GETTIME:
-                 if (seq_mode == SEQ_2)
-                         return tmr->ioctl(tmr_no, cmd, arg);
-
-                 if (softsynthp != NULL)
-                         return (*(int *) arg = softsynthp(SSYN_GETTIME, 0, 0, 0));
-                 else
-                         return (*(int *) arg = jiffies - seq_time);
-                 break;
-
-         case SNDCTL_SEQ_CTRLRATE:
-                 /*
-                  * If *arg == 0, just return the current rate
-                  */
-                 if (seq_mode == SEQ_2)
-                         return tmr->ioctl(tmr_no, cmd, arg);
-
-                 val = *(int *) arg;
-                 if (val != 0)
-                         return -EINVAL;
-
-                 return (*(int *) arg = HZ);
-                 break;
-
-         case SNDCTL_SEQ_RESETSAMPLES:
-         case SNDCTL_SYNTH_REMOVESAMPLE:
-         case SNDCTL_SYNTH_CONTROL:
-                 {
-                         int             err;
-
-                         dev = *(int *) arg;
-                         if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL)
-                           {
-                                   return -ENXIO;
-                           }
-                         if (!(synth_open_mask & (1 << dev)) && !orig_dev)
-                           {
-                                   return -EBUSY;
-                           }
-                         err = synth_devs[dev]->ioctl(dev, cmd, arg);
-                         return err;
-                 }
-                 break;
-
-         case SNDCTL_SEQ_NRSYNTHS:
-                 return (*(int *) arg = max_synthdev);
-                 break;
-
-         case SNDCTL_SEQ_NRMIDIS:
-                 return (*(int *) arg = max_mididev);
-                 break;
-
-         case SNDCTL_SYNTH_MEMAVL:
-                 {
-                         int             dev;
-
-                         dev = *(int *) arg;
-
-                         if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL)
-                                 return -ENXIO;
-
-                         if (!(synth_open_mask & (1 << dev)) && !orig_dev)
-                                 return -EBUSY;
-
-                         return (*(int *) arg = synth_devs[dev]->ioctl(dev, cmd, arg));
-                 }
-                 break;
-
-         case SNDCTL_FM_4OP_ENABLE:
-                 {
-                         int             dev;
-
-                         dev = *(int *) arg;
-
-                         if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL)
-                                 return -ENXIO;
-
-                         if (!(synth_open_mask & (1 << dev)))
-                                 return -ENXIO;
-
-                         synth_devs[dev]->ioctl(dev, cmd, arg);
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_SYNTH_INFO:
-                 {
-                         struct synth_info inf;
-                         int             dev;
-
-                         memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf));
-                         dev = inf.device;
-
-                         if (dev < 0 || dev >= max_synthdev)
-                                 return -ENXIO;
-
-                         if (!(synth_open_mask & (1 << dev)) && !orig_dev)
-                                 return -EBUSY;
-
-                         return synth_devs[dev]->ioctl(dev, cmd, arg);
-                 }
-                 break;
-
-
-                 /* Like SYNTH_INFO but returns ID in the name field */
-         case SNDCTL_SYNTH_ID:
-                 {
-                         struct synth_info inf;
-                         int             dev;
-
-                         memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf));
-                         dev = inf.device;
-
-                         if (dev < 0 || dev >= max_synthdev)
-                                 return -ENXIO;
-
-                         if (!(synth_open_mask & (1 << dev)) && !orig_dev)
-                                 return -EBUSY;
-
-                         memcpy((char *) &inf, (char *) synth_devs[dev]->info, sizeof(inf));
-                         strcpy(inf.name, synth_devs[dev]->id);
-                         inf.device = dev;
-                         memcpy((&((char *) arg)[0]), (char *) &inf, sizeof(inf));
+       switch (cmd) {
+       case SNDCTL_TMR_TIMEBASE:
+       case SNDCTL_TMR_TEMPO:
+       case SNDCTL_TMR_START:
+       case SNDCTL_TMR_STOP:
+       case SNDCTL_TMR_CONTINUE:
+       case SNDCTL_TMR_METRONOME:
+       case SNDCTL_TMR_SOURCE:
+               if (seq_mode != SEQ_2)
+                       return -EINVAL;
+               return tmr->ioctl(tmr_no, cmd, arg);
+               
+       case SNDCTL_TMR_SELECT:
+               if (seq_mode != SEQ_2)
+                       return -EINVAL;
+               if (__get_user(pending_timer, (int *)arg))
+                       return -EFAULT;
+               if (pending_timer < 0 || pending_timer >= num_sound_timers || sound_timer_devs[pending_timer] == NULL) {
+                       pending_timer = -1;
+                       return -EINVAL;
+               }
+               return __put_user(pending_timer, (int *)arg);
+
+       case SNDCTL_SEQ_PANIC:
+               seq_panic();
+               break;
+               
+       case SNDCTL_SEQ_SYNC:
+               if (mode == OPEN_READ)
+                       return 0;
+               while (qlen > 0 && !signal_pending(current))
+                       seq_sync();
+               return qlen ? -EINTR : 0;
+               
+       case SNDCTL_SEQ_RESET:
+               seq_reset();
+               return 0;
+
+       case SNDCTL_SEQ_TESTMIDI:
+               if (__get_user(midi_dev, (int *)arg))
+                       return -EFAULT;
+               if (midi_dev < 0 || midi_dev >= max_mididev)
+                       return -ENXIO;
+               
+               if (!midi_opened[midi_dev] && 
+                   (err = midi_devs[midi_dev]->open(midi_dev, mode, sequencer_midi_input,
+                                                    sequencer_midi_output)) < 0)
+                       return err;
+               midi_opened[midi_dev] = 1;
+               return 0;
+
+       case SNDCTL_SEQ_GETINCOUNT:
+               if (mode == OPEN_WRITE)
+                       return 0;
+               return __put_user(iqlen,  (int *)arg);
+               
+       case SNDCTL_SEQ_GETOUTCOUNT:
+               if (mode == OPEN_READ)
                          return 0;
-                 }
-                 break;
-
-         case SNDCTL_SEQ_OUTOFBAND:
-                 {
-                         struct seq_event_rec event_rec;
-                         unsigned long   flags;
-
-                         memcpy((char *) &event_rec, (&((char *) arg)[0]), sizeof(event_rec));
-
-                         save_flags(flags);
-                         cli();
-                         play_event(event_rec.arr);
-                         restore_flags(flags);
-
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_MIDI_INFO:
-                 {
-                         struct midi_info inf;
-                         int             dev;
-                         char           *pp;
-
-                         memcpy((char *) &inf, (&((char *) arg)[0]), sizeof(inf));
-                         dev = inf.device;
-
-                         if (dev < 0 || dev >= max_mididev)
-                                 return -ENXIO;
-
-                         midi_devs[dev]->info.device = dev;
-                         pp = (char *) &midi_devs[dev]->info;
-                         memcpy((&((char *) arg)[0]), pp, sizeof(inf));
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_SEQ_THRESHOLD:
-                 {
-                         int             tmp;
-
-                         tmp = *(int *) arg;
-
-                         if (tmp < 1)
-                                 tmp = 1;
-                         if (tmp >= SEQ_MAX_QUEUE)
-                                 tmp = SEQ_MAX_QUEUE - 1;
-                         output_threshold = tmp;
-                         return 0;
-                 }
-                 break;
-
-         case SNDCTL_MIDI_PRETIME:
-                 {
-                         int             val;
-
-                         val = *(int *) arg;
-
-                         if (val < 0)
-                                 val = 0;
-
-                         val = (HZ * val) / 10;
-                         pre_event_timeout = val;
-                         return (*(int *) arg = val);
-                 }
-                 break;
-
-         default:
-                 if (mode == OPEN_READ)
-                         return -EIO;
-
-                 if (!synth_devs[0])
-                         return -ENXIO;
-                 if (!(synth_open_mask & (1 << 0)))
-                         return -ENXIO;
-                 return synth_devs[0]->ioctl(0, cmd, arg);
-                 break;
-         }
-
+               val = SEQ_MAX_QUEUE - qlen;
+               return __put_user(val, (int *)arg);
+               
+       case SNDCTL_SEQ_GETTIME:
+               if (seq_mode == SEQ_2)
+                       return tmr->ioctl(tmr_no, cmd, arg);
+               if (softsynthp != NULL)
+                       val = softsynthp(SSYN_GETTIME, 0, 0, 0);
+               else
+                       val = jiffies - seq_time;
+               return __put_user(val, (int *)arg);
+               
+       case SNDCTL_SEQ_CTRLRATE:
+               /*
+                * If *arg == 0, just return the current rate
+                */
+               if (seq_mode == SEQ_2)
+                       return tmr->ioctl(tmr_no, cmd, arg);
+               
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val != 0)
+                       return -EINVAL;
+               return __put_user(HZ, (int *)arg);
+
+       case SNDCTL_SEQ_RESETSAMPLES:
+       case SNDCTL_SYNTH_REMOVESAMPLE:
+       case SNDCTL_SYNTH_CONTROL:
+               if (__get_user(dev, (int *)arg))
+                       return -EFAULT;
+               if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL)
+                       return -ENXIO;
+               if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+                       return -EBUSY;
+               return synth_devs[dev]->ioctl(dev, cmd, arg);
+
+       case SNDCTL_SEQ_NRSYNTHS:
+               return __put_user(max_synthdev, (int *)arg);
+
+       case SNDCTL_SEQ_NRMIDIS:
+               return __put_user(max_mididev, (int *)arg);
+
+       case SNDCTL_SYNTH_MEMAVL:
+               if (__get_user(dev, (int *)arg))
+                       return -EFAULT;
+               if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL)
+                       return -ENXIO;
+               if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+                       return -EBUSY;
+               val = synth_devs[dev]->ioctl(dev, cmd, arg);
+               return __put_user(val, (int *)arg);
+
+       case SNDCTL_FM_4OP_ENABLE:
+               if (__get_user(dev, (int *)arg))
+                       return -EFAULT;
+               if (dev < 0 || dev >= num_synths || synth_devs[dev] == NULL)
+                       return -ENXIO;
+               if (!(synth_open_mask & (1 << dev)))
+                       return -ENXIO;
+               synth_devs[dev]->ioctl(dev, cmd, arg);
+               return 0;
+
+       case SNDCTL_SYNTH_INFO:
+               if (__get_user(dev, (int *)(&(((struct synth_info *)arg)->device))))
+                       return -EFAULT;
+               if (dev < 0 || dev >= max_synthdev)
+                       return -ENXIO;
+               if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+                       return -EBUSY;
+               return synth_devs[dev]->ioctl(dev, cmd, arg);
+               
+               /* Like SYNTH_INFO but returns ID in the name field */
+       case SNDCTL_SYNTH_ID:
+               if (__get_user(dev, (int *)(&(((struct synth_info *)arg)->device))))
+                       return -EFAULT;
+               if (dev < 0 || dev >= max_synthdev)
+                       return -ENXIO;
+               if (!(synth_open_mask & (1 << dev)) && !orig_dev)
+                       return -EBUSY;
+               memcpy(&inf, synth_devs[dev]->info, sizeof(inf));
+               strncpy(inf.name, synth_devs[dev]->id, sizeof(inf.name));
+               inf.device = dev;
+               return __copy_to_user(arg, &inf, sizeof(inf));
+               
+       case SNDCTL_SEQ_OUTOFBAND:
+               if (__copy_from_user(&event_rec, arg, sizeof(event_rec)))
+                       return -EFAULT;
+               save_flags(flags);
+               cli();
+               play_event(event_rec.arr);
+               restore_flags(flags);
+               return 0;
+                 
+       case SNDCTL_MIDI_INFO:
+               if (__get_user(dev, (int *)(&(((struct synth_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));
+               
+       case SNDCTL_SEQ_THRESHOLD:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val < 1)
+                       val = 1;
+               if (val >= SEQ_MAX_QUEUE)
+                       val = SEQ_MAX_QUEUE - 1;
+               output_threshold = val;
+               return 0;
+               
+       case SNDCTL_MIDI_PRETIME:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val < 0)
+                       val = 0;
+               val = (HZ * val) / 10;
+               pre_event_timeout = val;
+               return __put_user(val, (int *)arg);
+
+       default:
+               if (mode == OPEN_READ)
+                       return -EIO;
+               if (!synth_devs[0])
+                       return -ENXIO;
+               if (!(synth_open_mask & (1 << 0)))
+                       return -ENXIO;
+               if (!synth_devs[0]->ioctl)
+                       return -EINVAL;
+               return synth_devs[0]->ioctl(0, cmd, arg);
+       }
        return -EINVAL;
 }
 
index a47133a8a192aaa747e9d32c2dda1b1b97e66c7b..618f4b961f7f6e57545dfb48ff6beca26eb15286 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -114,6 +117,7 @@ static void     compute_step(int voice);
 static volatile int tmr_running = 0;
 static int      voice_limit = 24;
 
+
 static void
 set_max_voices(int nr)
 {
@@ -662,10 +666,11 @@ softsyn_callback(int dev, int parm)
 }
 #endif
 
-static void
-start_engine(softsyn_devc * devc)
+static void start_engine(softsyn_devc * devc)
 {
        struct dma_buffparms *dmap;
+       int trig, n;
+       mm_segment_t fs;
 
        if (!devc->audio_opened)
                if (softsyn_open(devc->synthdev, 0) < 0)
@@ -673,46 +678,37 @@ start_engine(softsyn_devc * devc)
 
        if (devc->audiodev >= num_audiodevs)
                return;
-
+       
        dmap = audio_devs[devc->audiodev]->dmap_out;
-
+       
        devc->usecs = 0;
        devc->next_event_usecs = ~0;
        devc->control_rate = 64;
        devc->control_counter = 0;
 
-       if (devc->engine_state == ES_STOPPED)
-         {
-                 int             trig, n = 0;
-
-                 trig = 0;
-                 dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t) & trig);
+       if (devc->engine_state == ES_STOPPED) {
+               n = trig = 0;
+               fs = get_fs();
+               set_fs(get_ds());
+               dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig);
 #ifdef POLLED_MODE
-                 ;
-
-                 {
-                         poll_timer.expires = (1) + jiffies;
-                         add_timer(&poll_timer);
-                 };            /* Start polling */
+               poll_timer.expires = (1) + jiffies;
+               add_timer(&poll_timer);
+               /* Start polling */
 #else
-                 dmap->audio_callback = softsyn_callback;
-                 dmap->qhead = dmap->qtail = dmap->qlen = 0;
+               dmap->audio_callback = softsyn_callback;
+               dmap->qhead = dmap->qtail = dmap->qlen = 0;
 #endif
-
-                 while (dmap->qlen < devc->max_playahead && n++ < 2)
-                         do_resample(0);
-
-                 devc->engine_state = ES_STARTED;
-                 last_resample_jiffies = jiffies;
-                 resample_counter = 0;
-
-                 trig = PCM_ENABLE_OUTPUT;
-                 if (dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER,
-                               (caddr_t) & trig) < 0)
-                   {
-                           printk("SoftOSS: Trigger failed\n");
-                   }
-         }
+               while (dmap->qlen < devc->max_playahead && n++ < 2)
+                       do_resample(0);
+               devc->engine_state = ES_STARTED;
+               last_resample_jiffies = jiffies;
+               resample_counter = 0;
+               trig = PCM_ENABLE_OUTPUT;
+               if (dma_ioctl(devc->audiodev, SNDCTL_DSP_SETTRIGGER, (caddr_t)&trig) < 0)
+                       printk(KERN_ERR "SoftOSS: Trigger failed\n");
+               set_fs(fs);
+       }
 }
 
 static void
@@ -760,34 +756,25 @@ softsynth_hook(int cmd, int parm1, int parm2, unsigned long parm3)
        return 0;
 }
 
-static int
-softsyn_ioctl(int dev,
-             unsigned int cmd, caddr_t arg)
+static int softsyn_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       switch (cmd)
-         {
-
-         case SNDCTL_SYNTH_INFO:
-                 softsyn_info.nr_voices = devc->maxvoice;
-
-                 memcpy((&((char *) arg)[0]), (char *) &softsyn_info, sizeof(softsyn_info));
-                 return 0;
-                 break;
-
-         case SNDCTL_SEQ_RESETSAMPLES:
-                 stop_engine(devc);
-                 reset_samples(devc);
-                 return 0;
-                 break;
+       switch (cmd) {
 
-         case SNDCTL_SYNTH_MEMAVL:
-                 return devc->ram_size - devc->ram_used;
-                 break;
+       case SNDCTL_SYNTH_INFO:
+               softsyn_info.nr_voices = devc->maxvoice;
+               return __copy_to_user(arg, &softsyn_info, sizeof(softsyn_info));
 
-         default:
-                 return -EINVAL;
-         }
+       case SNDCTL_SEQ_RESETSAMPLES:
+               stop_engine(devc);
+               reset_samples(devc);
+               return 0;
+                 
+       case SNDCTL_SYNTH_MEMAVL:
+               return devc->ram_size - devc->ram_used;
 
+       default:
+               return -EINVAL;
+       }
 }
 
 static int
@@ -994,12 +981,12 @@ softsyn_start_note(int dev, int voice, int note, int volume)
        return 0;
 }
 
-static int
-softsyn_open(int synthdev, int mode)
+static int softsyn_open(int synthdev, int mode)
 {
        int             err;
        extern int      softoss_dev;
        int             frags = 0x7fff0007;     /* fragment size of 128 bytes */
+       mm_segment_t fs;
 
        if (devc->audio_opened) /* Already opened */
                return 0;
@@ -1035,8 +1022,11 @@ softsyn_open(int synthdev, int mode)
 
        DDB(printk("SoftOSS: Using audio dev %d, speed %d, bits %d, channels %d\n", devc->audiodev, devc->speed, devc->bits, devc->channels));
 
+       fs = get_fs();
+       set_fs(get_ds());
        dma_ioctl(devc->audiodev, SNDCTL_DSP_SETFRAGMENT, (caddr_t) & frags);
        dma_ioctl(devc->audiodev, SNDCTL_DSP_GETBLKSIZE, (caddr_t) & devc->fragsize);
+       set_fs(fs);
 
        if (devc->bits != 16 || devc->channels != 2)
          {
@@ -1055,14 +1045,18 @@ softsyn_open(int synthdev, int mode)
        return 0;
 }
 
-static void
-softsyn_close(int synthdev)
+static void softsyn_close(int synthdev)
 {
+       mm_segment_t fs;
+
        devc->engine_state = ES_STOPPED;
 #ifdef POLLED_MODE
-       del_timer(&poll_timer);;
+       del_timer(&poll_timer);
 #endif
+       fs = get_fs();
+       set_fs(get_ds());
        dma_ioctl(devc->audiodev, SNDCTL_DSP_RESET, 0);
+       set_fs(fs);
        if (devc->audio_opened)
                audio_release((devc->audiodev << 4) | SND_DEV_DSP16, &devc->finfo);
        devc->audio_opened = 0;
index 0e7a1666ef49df90f48339ef0fe0535c7038be63..82053a4b42974e45f7dfc53b00c77c8782c1d14e 100644 (file)
@@ -99,14 +99,6 @@ void conf_printf2(char *name, int base, int irq, int dma, int dma2);
 int ioctl_in(caddr_t arg);
 int ioctl_out(caddr_t arg, int result);
 
-/*     From sound_switch.c     */
-int sound_read_sw (int dev, struct fileinfo *file, char *buf, int count);
-int sound_write_sw (int dev, struct fileinfo *file, const char *buf, int count);
-int sound_open_sw (int dev, struct fileinfo *file);
-void sound_release_sw (int dev, struct fileinfo *file);
-int sound_ioctl_sw (int dev, struct fileinfo *file,
-            unsigned int cmd, caddr_t arg);
-
 /*     From opl3.c     */
 int opl3_detect (int ioaddr, int *osp);
 int opl3_init(int ioaddr, int *osp);
diff --git a/drivers/sound/sound_switch.c b/drivers/sound/sound_switch.c
deleted file mode 100644 (file)
index 8e8c553..0000000
+++ /dev/null
@@ -1,734 +0,0 @@
-/*
- * sound/sound_switch.c
- *
- * The system call switch handler
- */
-/*
- * Copyright (C) by Hannu Savolainen 1993-1997
- *
- * OSS/Free for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
- * Version 2 (June 1991). See the "COPYING" file distributed with this software
- * for more info.
- */
-#include <linux/config.h>
-
-
-#include "sound_config.h"
-
-static int      in_use = 0;    /* Total # of open devices */
-unsigned long   seq_time = 0;  /* Time for /dev/sequencer */
-
-/*
- * Table for configurable mixer volume handling
- */
-static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
-static int      num_mixer_volumes = 0;
-
-/*
- * /dev/sndstatus -device
- */
-static char    *status_buf = NULL;
-static int      status_len, status_ptr;
-static int      status_busy = 0;
-
-int
-               *
-load_mixer_volumes(char *name, int *levels, int present)
-{
-       int             i, n;
-
-       for (i = 0; i < num_mixer_volumes; i++)
-               if (strcmp(name, mixer_vols[i].name) == 0)
-                 {
-                         if (present)
-                                 mixer_vols[i].num = i;
-                         return mixer_vols[i].levels;
-                 }
-       if (num_mixer_volumes >= MAX_MIXER_DEV)
-         {
-                 printk("Sound: Too many mixers (%s)\n", name);
-                 return levels;
-         }
-       n = num_mixer_volumes++;
-
-       strcpy(mixer_vols[n].name, name);
-
-       if (present)
-               mixer_vols[n].num = n;
-       else
-               mixer_vols[n].num = -1;
-
-       for (i = 0; i < 32; i++)
-               mixer_vols[n].levels[i] = levels[i];
-       return mixer_vols[n].levels;
-}
-
-static int
-set_mixer_levels(caddr_t arg)
-{
-       mixer_vol_table *buf = NULL;
-       int             err = 0;
-
-       if ((buf = (mixer_vol_table *) vmalloc(sizeof(mixer_vol_table))) == NULL)
-               return -ENOSPC;
-
-       memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf));
-
-       load_mixer_volumes(buf->name, buf->levels, 0);
-
-       memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf));
-       vfree(buf);
-
-       return err;
-}
-
-static int
-get_mixer_levels(caddr_t arg)
-{
-       mixer_vol_table *buf = NULL;
-       int             n, err = 0;
-
-       if ((buf = (mixer_vol_table *) vmalloc(sizeof(mixer_vol_table))) == NULL)
-               return -ENOSPC;
-
-       memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf));
-
-       n = buf->num;
-       if (n < 0 || n >= num_mixer_volumes)
-               err = -EINVAL;
-       else
-         {
-                 memcpy((char *) buf, (char *) &mixer_vols[n], sizeof(*buf));
-         }
-
-       memcpy((&((char *) arg)[0]), (char *) buf, sizeof(*buf));
-       vfree(buf);
-
-       return err;
-}
-
-static int
-put_status(char *s)
-{
-       int             l = strlen(s);
-
-       if (status_len + l >= 4000)
-               return 0;
-
-       memcpy(&status_buf[status_len], s, l);
-       status_len += l;
-
-       return 1;
-}
-
-static int
-put_status_int(unsigned int val, int radix)
-{
-       int             l, v;
-
-       static char     hx[] = "0123456789abcdef";
-       char            buf[11];
-
-       if (!val)
-               return put_status("0");
-
-       l = 0;
-       buf[10] = 0;
-
-       while (val)
-         {
-                 v = val % radix;
-                 val = val / radix;
-
-                 buf[9 - l] = hx[v];
-                 l++;
-         }
-
-       if (status_len + l >= 4000)
-               return 0;
-
-       memcpy(&status_buf[status_len], &buf[10 - l], l);
-       status_len += l;
-
-       return 1;
-}
-
-static void
-init_status(void)
-{
-       /*
-        * Write the status information to the status_buf and update status_len.
-        * There is a limit of 4000 bytes for the data.
-        */
-
-       int             i;
-
-       status_ptr = 0;
-
-#ifdef SOUND_UNAME_A
-       put_status("OSS/Free" SOUND_VERSION_STRING
-                  " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY ",\n"
-                  SOUND_UNAME_A ")"
-                  "\n");
-#else
-       put_status("OSS/Free:" SOUND_VERSION_STRING
-#if 0
-                  " (" SOUND_CONFIG_DATE " " SOUND_CONFIG_BY "@"
-                  SOUND_CONFIG_HOST "." SOUND_CONFIG_DOMAIN ")"
-#endif
-                  "\n");
-#endif
-
-#ifdef MODULE
-       put_status("Load type: Driver loaded as a module.\n");
-#else
-       put_status("Load type: Driver compiled into kernel\n");
-#endif
-       put_status("Kernel: ");
-       put_status(system_utsname.sysname);
-       put_status(" ");
-       put_status(system_utsname.nodename);
-       put_status(" ");
-       put_status(system_utsname.release);
-       put_status(" ");
-       put_status(system_utsname.version);
-       put_status(" ");
-       put_status(system_utsname.machine);
-       put_status("\n");
-
-
-       if (!put_status("Config options: "))
-               return;
-       if (!put_status_int(SELECTED_SOUND_OPTIONS, 16))
-               return;
-
-       if (!put_status("\n\nInstalled drivers: \n"))
-               return;
-
-       for (i = 0; i < num_sound_drivers; i++)
-               if (sound_drivers[i].card_type != 0)
-                 {
-                         if (!put_status("Type "))
-                                 return;
-                         if (!put_status_int(sound_drivers[i].card_type, 10))
-                                 return;
-                         if (!put_status(": "))
-                                 return;
-                         if (!put_status(sound_drivers[i].name))
-                                 return;
-
-                         if (!put_status("\n"))
-                                 return;
-                 }
-       if (!put_status("\nCard config: \n"))
-               return;
-
-       for (i = 0; i < num_sound_cards; i++)
-               if (snd_installed_cards[i].card_type != 0)
-                 {
-                         int             drv, tmp;
-
-                         if (!snd_installed_cards[i].enabled)
-                                 if (!put_status("("))
-                                         return;
-
-                         /*
-                          * if (!put_status_int(snd_installed_cards[i].card_type, 10)) return;
-                          * if (!put_status (": ")) return;
-                          */
-
-                         if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)
-                                 if (!put_status(sound_drivers[drv].name))
-                                         return;
-
-                         if (snd_installed_cards[i].config.io_base)
-                           {
-                                   if (!put_status(" at 0x"))
-                                           return;
-                                   if (!put_status_int(snd_installed_cards[i].config.io_base, 16))
-                                           return;
-                           }
-                         tmp = snd_installed_cards[i].config.irq;
-                         if (tmp != 0)
-                           {
-                                   if (!put_status(" irq "))
-                                           return;
-                                   if (tmp < 0)
-                                           tmp = -tmp;
-                                   if (!put_status_int(tmp, 10))
-                                           return;
-                           }
-                         if (snd_installed_cards[i].config.dma != -1)
-                           {
-                                   if (!put_status(" drq "))
-                                           return;
-                                   if (!put_status_int(snd_installed_cards[i].config.dma, 10))
-                                           return;
-                                   if (snd_installed_cards[i].config.dma2 != -1)
-                                     {
-                                             if (!put_status(","))
-                                                     return;
-                                             if (!put_status_int(snd_installed_cards[i].config.dma2, 10))
-                                                     return;
-                                     }
-                           }
-                         if (!snd_installed_cards[i].enabled)
-                                 if (!put_status(")"))
-                                         return;
-
-                         if (!put_status("\n"))
-                                 return;
-                 }
-       if (!sound_started)
-         {
-                 put_status("\n\n***** Sound driver not started *****\n\n");
-                 return;
-         }
-#ifndef CONFIG_AUDIO
-       if (!put_status("\nAudio devices: NOT ENABLED IN CONFIG\n"))
-               return;
-#else
-       if (!put_status("\nAudio devices:\n"))
-               return;
-
-       for (i = 0; i < num_audiodevs; i++)
-         {
-                 if (audio_devs[i] == NULL)
-                         continue;
-                 if (!put_status_int(i, 10))
-                         return;
-                 if (!put_status(": "))
-                         return;
-                 if (!put_status(audio_devs[i]->name))
-                         return;
-
-                 if (audio_devs[i]->flags & DMA_DUPLEX)
-                         if (!put_status(" (DUPLEX)"))
-                                 return;
-
-                 if (!put_status("\n"))
-                         return;
-         }
-#endif
-
-#ifndef CONFIG_SEQUENCER
-       if (!put_status("\nSynth devices: NOT ENABLED IN CONFIG\n"))
-               return;
-#else
-       if (!put_status("\nSynth devices:\n"))
-               return;
-
-       for (i = 0; i < num_synths; i++)
-         {
-                 if (synth_devs[i] == NULL)
-                         continue;
-                 if (!put_status_int(i, 10))
-                         return;
-                 if (!put_status(": "))
-                         return;
-                 if (!put_status(synth_devs[i]->info->name))
-                         return;
-                 if (!put_status("\n"))
-                         return;
-         }
-#endif
-
-#ifndef CONFIG_MIDI
-       if (!put_status("\nMidi devices: NOT ENABLED IN CONFIG\n"))
-               return;
-#else
-       if (!put_status("\nMidi devices:\n"))
-               return;
-
-       for (i = 0; i < num_midis; i++)
-         {
-                 if (midi_devs[i] == NULL)
-                         continue;
-                 if (!put_status_int(i, 10))
-                         return;
-                 if (!put_status(": "))
-                         return;
-                 if (!put_status(midi_devs[i]->info.name))
-                         return;
-                 if (!put_status("\n"))
-                         return;
-         }
-#endif
-
-#ifdef CONFIG_SEQUENCER
-       if (!put_status("\nTimers:\n"))
-               return;
-
-       for (i = 0; i < num_sound_timers; i++)
-         {
-                 if (sound_timer_devs[i] == NULL)
-                         continue;
-                 if (!put_status_int(i, 10))
-                         return;
-                 if (!put_status(": "))
-                         return;
-                 if (!put_status(sound_timer_devs[i]->info.name))
-                         return;
-                 if (!put_status("\n"))
-                         return;
-         }
-#endif
-
-       if (!put_status("\nMixers:\n"))
-               return;
-
-       for (i = 0; i < num_mixers; i++)
-         {
-                 if (mixer_devs[i] == NULL)
-                         continue;
-                 if (!put_status_int(i, 10))
-                         return;
-                 if (!put_status(": "))
-                         return;
-                 if (!put_status(mixer_devs[i]->name))
-                         return;
-                 if (!put_status("\n"))
-                         return;
-         }
-}
-
-static int
-read_status(char *buf, int count)
-{
-       /*
-        * Return at most 'count' bytes from the status_buf.
-        */
-       int             l, c;
-
-       l = count;
-       c = status_len - status_ptr;
-
-       if (l > c)
-               l = c;
-       if (l <= 0)
-               return 0;
-
-       {
-               char           *fixit = &status_buf[status_ptr];
-
-               copy_to_user(&(buf)[0], fixit, l);
-       };
-       status_ptr += l;
-
-       return l;
-}
-
-int
-sound_read_sw(int dev, struct fileinfo *file, char *buf, int count)
-{
-       DEB(printk("sound_read_sw(dev=%d, count=%d)\n", dev, count));
-
-       switch (dev & 0x0f)
-         {
-         case SND_DEV_STATUS:
-                 return read_status(buf, count);
-                 break;
-
-#ifdef CONFIG_AUDIO
-         case SND_DEV_DSP:
-         case SND_DEV_DSP16:
-         case SND_DEV_AUDIO:
-                 return audio_read(dev, file, buf, count);
-                 break;
-#endif
-
-#ifdef CONFIG_SEQUENCER
-         case SND_DEV_SEQ:
-         case SND_DEV_SEQ2:
-                 return sequencer_read(dev, file, buf, count);
-                 break;
-#endif
-
-#ifdef CONFIG_MIDI
-         case SND_DEV_MIDIN:
-                 return MIDIbuf_read(dev, file, buf, count);
-#endif
-
-         default:;
-         }
-
-       return -EINVAL;
-}
-
-int
-sound_write_sw(int dev, struct fileinfo *file, const char *buf, int count)
-{
-
-       DEB(printk("sound_write_sw(dev=%d, count=%d)\n", dev, count));
-
-
-       switch (dev & 0x0f)
-         {
-
-#ifdef CONFIG_SEQUENCER
-         case SND_DEV_SEQ:
-         case SND_DEV_SEQ2:
-                 return sequencer_write(dev, file, buf, count);
-                 break;
-#endif
-
-#ifdef CONFIG_AUDIO
-         case SND_DEV_DSP:
-         case SND_DEV_DSP16:
-         case SND_DEV_AUDIO:
-                 return audio_write(dev, file, buf, count);
-                 break;
-#endif
-
-#ifdef CONFIG_MIDI
-         case SND_DEV_MIDIN:
-                 return MIDIbuf_write(dev, file, buf, count);
-#endif
-
-         }
-
-       return -EINVAL;
-}
-
-int
-sound_open_sw(int dev, struct fileinfo *file)
-{
-       int             retval;
-
-       DEB(printk("sound_open_sw(dev=%d)\n", dev));
-
-       if ((dev >= SND_NDEVS) || (dev < 0))
-         {
-                 printk("Invalid minor device %d\n", dev);
-                 return -ENXIO;
-         }
-       switch (dev & 0x0f)
-         {
-         case SND_DEV_STATUS:
-                 if (status_busy)
-                         return -EBUSY;
-                 status_busy = 1;
-                 if ((status_buf = (char *) vmalloc(4000)) == NULL)
-                   {
-                           status_busy = 0;
-                           return -EIO;
-                   }
-                 status_len = status_ptr = 0;
-                 init_status();
-                 break;
-
-         case SND_DEV_CTL:
-                 if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
-                         return -ENXIO;
-                 return 0;
-                 break;
-
-#ifdef CONFIG_SEQUENCER
-         case SND_DEV_SEQ:
-         case SND_DEV_SEQ2:
-                 if ((retval = sequencer_open(dev, file)) < 0)
-                         return retval;
-                 break;
-#endif
-
-#ifdef CONFIG_MIDI
-         case SND_DEV_MIDIN:
-                 if ((retval = MIDIbuf_open(dev, file)) < 0)
-                         return retval;
-                 break;
-#endif
-
-#ifdef CONFIG_AUDIO
-         case SND_DEV_DSP:
-         case SND_DEV_DSP16:
-         case SND_DEV_AUDIO:
-                 if ((retval = audio_open(dev, file)) < 0)
-                         return retval;
-                 break;
-#endif
-
-         default:
-                 printk("Invalid minor device %d\n", dev);
-                 return -ENXIO;
-         }
-
-       in_use++;
-
-       return 0;
-}
-
-void
-sound_release_sw(int dev, struct fileinfo *file)
-{
-
-       DEB(printk("sound_release_sw(dev=%d)\n", dev));
-
-       switch (dev & 0x0f)
-         {
-         case SND_DEV_STATUS:
-                 if (status_buf)
-                         vfree(status_buf);
-                 status_buf = NULL;
-                 status_busy = 0;
-                 break;
-
-         case SND_DEV_CTL:
-                 break;
-
-#ifdef CONFIG_SEQUENCER
-         case SND_DEV_SEQ:
-         case SND_DEV_SEQ2:
-                 sequencer_release(dev, file);
-                 break;
-#endif
-
-#ifdef CONFIG_MIDI
-         case SND_DEV_MIDIN:
-                 MIDIbuf_release(dev, file);
-                 break;
-#endif
-
-#ifdef CONFIG_AUDIO
-         case SND_DEV_DSP:
-         case SND_DEV_DSP16:
-         case SND_DEV_AUDIO:
-                 audio_release(dev, file);
-                 break;
-#endif
-
-         default:
-                 printk("Sound error: Releasing unknown device 0x%02x\n", dev);
-         }
-       in_use--;
-}
-
-static int
-get_mixer_info(int dev, caddr_t arg)
-{
-       mixer_info      info;
-       int             i;
-
-       if (dev < 0 || dev >= num_mixers)
-               return -ENXIO;
-
-       strcpy(info.id, mixer_devs[dev]->id);
-       for (i = 0; i < 32 && mixer_devs[dev]->name; i++)
-               info.name[i] = mixer_devs[dev]->name[i];
-       info.name[i] = 0;
-       info.modify_counter = mixer_devs[dev]->modify_counter;
-
-       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-       return 0;
-}
-
-static int
-get_old_mixer_info(int dev, caddr_t arg)
-{
-       _old_mixer_info info;
-       int             i;
-
-       if (dev < 0 || dev >= num_mixers)
-               return -ENXIO;
-
-       strcpy(info.id, mixer_devs[dev]->id);
-       for (i = 0; i < 32 && mixer_devs[dev]->name; i++)
-               info.name[i] = mixer_devs[dev]->name[i];
-       info.name[i] = 0;
-
-       memcpy((&((char *) arg)[0]), (char *) &info, sizeof(info));
-       return 0;
-}
-
-static int
-sound_mixer_ioctl(int mixdev,
-                 unsigned int cmd, caddr_t arg)
-{
-       if (cmd == SOUND_MIXER_INFO)
-               return get_mixer_info(mixdev, arg);
-       if (cmd == SOUND_OLD_MIXER_INFO)
-               return get_old_mixer_info(mixdev, arg);
-
-       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               mixer_devs[mixdev]->modify_counter++;
-
-       return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
-}
-
-int
-sound_ioctl_sw(int dev, struct fileinfo *file,
-              unsigned int cmd, caddr_t arg)
-{
-       DEB(printk("sound_ioctl_sw(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
-
-       if (cmd == OSS_GETVERSION)
-               return (*(int *) arg = SOUND_VERSION);
-
-
-       if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0)       /* Mixer ioctl */
-               if ((dev & 0x0f) != SND_DEV_CTL)
-                 {
-                         int             dtype = dev & 0x0f;
-                         int             mixdev;
-
-                         switch (dtype)
-                           {
-#ifdef CONFIG_AUDIO
-                           case SND_DEV_DSP:
-                           case SND_DEV_DSP16:
-                           case SND_DEV_AUDIO:
-                                   mixdev = audio_devs[dev >> 4]->mixer_dev;
-                                   if (mixdev < 0 || mixdev >= num_mixers)
-                                           return -ENXIO;
-                                   return sound_mixer_ioctl(mixdev, cmd, arg);
-                                   break;
-#endif
-
-                           default:
-                                   return sound_mixer_ioctl(dev, cmd, arg);
-                           }
-                 }
-       switch (dev & 0x0f)
-         {
-
-         case SND_DEV_CTL:
-                 if (cmd == SOUND_MIXER_GETLEVELS)
-                         return get_mixer_levels(arg);
-                 if (cmd == SOUND_MIXER_SETLEVELS)
-                         return set_mixer_levels(arg);
-
-                 if (!num_mixers)
-                         return -ENXIO;
-
-                 dev = dev >> 4;
-
-                 if (dev >= num_mixers)
-                         return -ENXIO;
-
-                 return sound_mixer_ioctl(dev, cmd, arg);
-                 break;
-
-#ifdef CONFIG_SEQUENCER
-         case SND_DEV_SEQ:
-         case SND_DEV_SEQ2:
-                 return sequencer_ioctl(dev, file, cmd, arg);
-                 break;
-#endif
-
-#ifdef CONFIG_AUDIO
-         case SND_DEV_DSP:
-         case SND_DEV_DSP16:
-         case SND_DEV_AUDIO:
-                 return audio_ioctl(dev, file, cmd, arg);
-                 break;
-#endif
-
-#ifdef CONFIG_MIDI
-         case SND_DEV_MIDIN:
-                 return MIDIbuf_ioctl(dev, file, cmd, arg);
-                 break;
-#endif
-
-         }
-
-       return -EINVAL;
-}
index 78790d886ac9405a4e01136785953b55e74e826a..648a769a4543b2e6f7def59b4071112d5d8e42be 100644 (file)
@@ -13,6 +13,8 @@
 #include "sound_firmware.h"
 
 extern struct notifier_block *sound_locker;
+extern void sound_notifier_chain_register(struct notifier_block *);
+
 
 EXPORT_SYMBOL(mixer_devs);
 EXPORT_SYMBOL(audio_devs);
@@ -63,6 +65,7 @@ EXPORT_SYMBOL(sound_timer_syncinterval);
 
 /* Locking */
 EXPORT_SYMBOL(sound_locker);
+EXPORT_SYMBOL(sound_notifier_chain_register);
 
 /* MIDI symbols */
 EXPORT_SYMBOL(midi_devs);
@@ -86,3 +89,4 @@ EXPORT_SYMBOL(midi_synth_setup_voice);
 EXPORT_SYMBOL(midi_synth_send_sysex);
 EXPORT_SYMBOL(midi_synth_bender);
 EXPORT_SYMBOL(midi_synth_load_patch);
+
index 5fafccc42956724f54d500accb2abb1d3e910c59..267c015d7eb71943a0842b03e15d8c844ae6aaba 100644 (file)
@@ -1,5 +1,3 @@
-
-
 /*
  * sound/sound_timer.c
  */
@@ -10,6 +8,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 
@@ -187,86 +188,72 @@ timer_get_time(int dev)
        return curr_ticks;
 }
 
-static int
-timer_ioctl(int dev,
-           unsigned int cmd, caddr_t arg)
+static int timer_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       int             val;
-
-       switch (cmd)
-         {
-         case SNDCTL_TMR_SOURCE:
-                 return (*(int *) arg = TMR_INTERNAL);
-                 break;
-
-         case SNDCTL_TMR_START:
-                 tmr_reset();
-                 tmr_running = 1;
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_STOP:
-                 tmr_running = 0;
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_CONTINUE:
-                 tmr_running = 1;
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_TIMEBASE:
-                 val = *(int *) arg;
-
-                 if (val)
-                   {
-                           if (val < 1)
-                                   val = 1;
-                           if (val > 1000)
-                                   val = 1000;
-                           curr_timebase = val;
-                   }
-                 return (*(int *) arg = curr_timebase);
-                 break;
-
-         case SNDCTL_TMR_TEMPO:
-                 val = *(int *) arg;
-
-                 if (val)
-                   {
-                           if (val < 8)
-                                   val = 8;
-                           if (val > 250)
-                                   val = 250;
-                           tmr_offs = tmr_ctr;
-                           ticks_offs += tmr2ticks(tmr_ctr);
-                           tmr_ctr = 0;
-                           curr_tempo = val;
-                           reprogram_timer();
-                   }
-                 return (*(int *) arg = curr_tempo);
-                 break;
+       int val;
 
-         case SNDCTL_SEQ_CTRLRATE:
-                 val = *(int *) arg;
+       switch (cmd) {
+       case SNDCTL_TMR_SOURCE:
+               return __put_user(TMR_INTERNAL, (int *)arg);
 
-                 if (val != 0) /* Can't change */
-                         return -EINVAL;
-
-                 return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60);
-                 break;
-
-         case SNDCTL_SEQ_GETTIME:
-                 return (*(int *) arg = curr_ticks);
-                 break;
-
-         case SNDCTL_TMR_METRONOME:
-                 /* NOP */
-                 break;
+       case SNDCTL_TMR_START:
+               tmr_reset();
+               tmr_running = 1;
+               return 0;
+               
+       case SNDCTL_TMR_STOP:
+               tmr_running = 0;
+               return 0;
 
-         default:;
-         }
+       case SNDCTL_TMR_CONTINUE:
+               tmr_running = 1;
+               return 0;
 
+       case SNDCTL_TMR_TIMEBASE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val) {
+                       if (val < 1)
+                               val = 1;
+                       if (val > 1000)
+                               val = 1000;
+                       curr_timebase = val;
+               }
+               return __put_user(curr_timebase, (int *)arg);
+
+       case SNDCTL_TMR_TEMPO:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val) {
+                       if (val < 8)
+                               val = 8;
+                       if (val > 250)
+                               val = 250;
+                       tmr_offs = tmr_ctr;
+                       ticks_offs += tmr2ticks(tmr_ctr);
+                       tmr_ctr = 0;
+                       curr_tempo = val;
+                       reprogram_timer();
+               }
+               return __put_user(curr_tempo, (int *)arg);
+
+       case SNDCTL_SEQ_CTRLRATE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val != 0)   /* Can't change */
+                       return -EINVAL;
+               val = ((curr_tempo * curr_timebase) + 30) / 60;
+               return __put_user(val, (int *)arg);
+               
+       case SNDCTL_SEQ_GETTIME:
+               return __put_user(curr_ticks, (int *)arg);
+               
+       case SNDCTL_TMR_METRONOME:
+               /* NOP */
+               break;
+               
+       default:;
+       }
        return -EINVAL;
 }
 
index f6d17e4e83c1898b18237b3cee3a2de37b09a8fb..f439130f2bde30ac1e363e1d839d7a747f0855b7 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * linux/kernel/chr_drv/sound/soundcard.c
+ * linux/drivers/sound/soundcard.c
  *
  * Soundcard driver for Linux
  */
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ *                   integrated sound_switch.c and made /proc/sound (equals to /dev/sndstat,
+ *                   which should disappear in the near future)
+ */
 #include <linux/config.h>
 
 
@@ -27,6 +32,7 @@
 #include <linux/ioport.h>
 #endif                         /* __KERNEL__ */
 #include <linux/delay.h>
+#include <linux/proc_fs.h>
 
 #define SOUND_CORE
 
@@ -63,27 +69,342 @@ static char     dma_alloc_map[8] =
 #define DMA_MAP_BUSY           2
 
 
+static int in_use = 0;         /* Total # of open devices */
+unsigned long seq_time = 0;    /* Time for /dev/sequencer */
 
-static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+/*
+ * Table for configurable mixer volume handling
+ */
+static mixer_vol_table mixer_vols[MAX_MIXER_DEV];
+static int num_mixer_volumes = 0;
+
+
+int *load_mixer_volumes(char *name, int *levels, int present)
+{
+       int             i, n;
+
+       for (i = 0; i < num_mixer_volumes; i++)
+               if (strcmp(name, mixer_vols[i].name) == 0)
+                 {
+                         if (present)
+                                 mixer_vols[i].num = i;
+                         return mixer_vols[i].levels;
+                 }
+       if (num_mixer_volumes >= MAX_MIXER_DEV)
+         {
+                 printk("Sound: Too many mixers (%s)\n", name);
+                 return levels;
+         }
+       n = num_mixer_volumes++;
+
+       strcpy(mixer_vols[n].name, name);
+
+       if (present)
+               mixer_vols[n].num = n;
+       else
+               mixer_vols[n].num = -1;
+
+       for (i = 0; i < 32; i++)
+               mixer_vols[n].levels[i] = levels[i];
+       return mixer_vols[n].levels;
+}
+
+static int set_mixer_levels(caddr_t arg)
+{
+        /* mixer_vol_table is 174 bytes, so IMHO no reason to not allocate it on the stack */
+       mixer_vol_table buf;   
+
+       if (__copy_from_user(&buf, arg, sizeof(buf)))
+               return -EFAULT;
+       load_mixer_volumes(buf.name, buf.levels, 0);
+       return __copy_to_user(arg, &buf, sizeof(buf));
+}
+
+static int get_mixer_levels(caddr_t arg)
+{
+       int n;
+
+       if (__get_user(n, (int *)(&(((mixer_vol_table *)arg)->num))))
+               return -EFAULT;
+       if (n < 0 || n >= num_mixer_volumes)
+               return -EINVAL;
+       return __copy_to_user(arg, &mixer_vols[n], sizeof(mixer_vol_table));
+}
+
+static int sound_proc_get_info(char *buffer, char **start, off_t offset, int length, int inout)
 {
-       int             dev;
+       int len, i, drv;
+        off_t pos = 0;
+        off_t begin = 0;
 
-       dev = MINOR(file->f_dentry->d_inode->i_rdev);
+#ifdef MODULE
+#define MODULEPROCSTRING "Driver loaded as a module"
+#else
+#define MODULEPROCSTRING "Driver compiled into kernel"
+#endif
+       
+       len = sprintf(buffer, "OSS/Free:" SOUND_VERSION_STRING "\n"
+                     "Load type: " MODULEPROCSTRING "\n"
+                     "Kernel: %s %s %s %s %s\n"
+                     "Config options: %x\n\nInstalled drivers: \n", 
+                     system_utsname.sysname, system_utsname.nodename, system_utsname.release, 
+                     system_utsname.version, system_utsname.machine, SELECTED_SOUND_OPTIONS);
+       
+       for (i = 0; (i < num_sound_drivers) && (pos <= offset + length); i++) {
+               if (!sound_drivers[i].card_type)
+                       continue;
+               len += sprintf(buffer + len, "Type %d: %s\n", 
+                              sound_drivers[i].card_type, sound_drivers[i].name);
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+       len += sprintf(buffer + len, "\nCard config: \n");
+
+       for (i = 0; (i < num_sound_cards) && (pos <= offset + length); i++) {
+               if (!snd_installed_cards[i].card_type)
+                       continue;
+               if (!snd_installed_cards[i].enabled)
+                       len += sprintf(buffer + len, "(");
+               if ((drv = snd_find_driver(snd_installed_cards[i].card_type)) != -1)
+                       len += sprintf(buffer + len, "%s", sound_drivers[drv].name);
+               if (snd_installed_cards[i].config.io_base)
+                       len += sprintf(buffer + len, " at 0x%x", snd_installed_cards[i].config.io_base);
+               if (snd_installed_cards[i].config.irq != 0)
+                       len += sprintf(buffer + len, " irq %d", abs(snd_installed_cards[i].config.irq));
+               if (snd_installed_cards[i].config.dma != -1) {
+                       len += sprintf(buffer + len, " drq %d", snd_installed_cards[i].config.dma);
+                       if (snd_installed_cards[i].config.dma2 != -1)
+                               len += sprintf(buffer + len, ",%d", snd_installed_cards[i].config.dma2);
+               }
+               if (!snd_installed_cards[i].enabled)
+                       len += sprintf(buffer + len, ")");
+               len += sprintf(buffer + len, "\n");
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+       if (!sound_started)
+               len += sprintf(buffer + len, "\n\n***** Sound driver not started *****\n\n");
+#ifndef CONFIG_AUDIO
+       len += sprintf(buffer + len, "\nAudio devices: NOT ENABLED IN CONFIG\n");
+#else
+       len += sprintf(buffer + len, "\nAudio devices:\n");
+       for (i = 0; (i < num_audiodevs) && (pos <= offset + length); i++) {
+               if (audio_devs[i] == NULL)
+                       continue;
+               len += sprintf(buffer + len, "%d: %s%s\n", i, audio_devs[i]->name, 
+                              audio_devs[i]->flags & DMA_DUPLEX ? " (DUPLEX)" : "");
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+#endif
+
+#ifndef CONFIG_SEQUENCER
+       len += sprintf(buffer + len, "\nSynth devices: NOT ENABLED IN CONFIG\n");
+#else
+       len += sprintf(buffer + len, "\nSynth devices:\n");
+       for (i = 0; (i < num_synths) && (pos <= offset + length); i++) {
+               if (synth_devs[i] == NULL)
+                       continue;
+               len += sprintf(buffer + len, "%d: %s\n", i, synth_devs[i]->info->name);
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+#endif
+
+#ifndef CONFIG_MIDI
+       len += sprintf(buffer + len, "\nMidi devices: NOT ENABLED IN CONFIG\n");
+#else
+       len += sprintf(buffer + len, "\nMidi devices:\n");
+       for (i = 0; (i < num_midis) && (pos <= offset + length); i++) {
+               if (midi_devs[i] == NULL)
+                       continue;
+               len += sprintf(buffer + len, "%d: %s\n", i, midi_devs[i]->info.name);
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+#endif
+
+#ifdef CONFIG_SEQUENCER
+       len += sprintf(buffer + len, "\nTimers:\n");
+
+       for (i = 0; (i < num_sound_timers) && (pos <= offset + length); i++) {
+               if (sound_timer_devs[i] == NULL)
+                       continue;
+               len += sprintf(buffer + len, "%d: %s\n", i, sound_timer_devs[i]->info.name);
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+#endif
+
+       len += sprintf(buffer + len, "\nMixers:\n");
+       for (i = 0; (i < num_mixers) && (pos <= offset + length); i++) {
+               if (mixer_devs[i] == NULL)
+                       continue;
+               len += sprintf(buffer + len, "%d: %s\n", i, mixer_devs[i]->name);
+               pos = begin + len;
+               if (pos < offset) {
+                       len = 0;
+                       begin = pos;
+               }
+       }
+       *start = buffer + (offset - begin);
+       len -= (offset - begin);
+        if (len > length) 
+               len = length;
+        return len;
+}
+
+static struct proc_dir_entry proc_root_sound = {
+        PROC_SOUND, 5, "sound",
+        S_IFREG | S_IRUGO, 1, 0, 0,
+        0, NULL, sound_proc_get_info
+};
+
+#ifndef MIN
+#define MIN(a,b) (((a) < (b)) ? (a) : (b))
+#endif
+
+/* 4K page size but our output routines use some slack for overruns */
+#define PROC_BLOCK_SIZE (3*1024)
+
+/*
+ * basically copied from fs/proc/generic.c:proc_file_read 
+ * should be removed sometime in the future together with /dev/sndstat
+ * (a symlink /dev/sndstat -> /proc/sound will do as well)
+ */
+static ssize_t sndstat_file_read(struct file * file, char * buf, size_t nbytes, loff_t *ppos)
+{
+        char    *page;
+        ssize_t retval=0;
+        int     eof=0;
+        ssize_t n, count;
+        char    *start;
+
+        if (!(page = (char*) __get_free_page(GFP_KERNEL)))
+                return -ENOMEM;
+
+        while ((nbytes > 0) && !eof)
+        {
+                count = MIN(PROC_BLOCK_SIZE, nbytes);
+
+                start = NULL;
+               n = sound_proc_get_info(page, &start, *ppos, count, 0);
+               if (n < count)
+                       eof = 1;
+                        
+                if (!start) {
+                        /*
+                         * For proc files that are less than 4k
+                         */
+                        start = page + *ppos;
+                        n -= *ppos;
+                        if (n <= 0)
+                                break;
+                        if (n > count)
+                                n = count;
+                }
+                if (n == 0)
+                        break;  /* End of file */
+                if (n < 0) {
+                        if (retval == 0)
+                                retval = n;
+                        break;
+                }
+                
+                n -= copy_to_user(buf, start, n);       /* BUG ??? */
+                if (n == 0) {
+                        if (retval == 0)
+                                retval = -EFAULT;
+                        break;
+                }
+                
+                *ppos += n;     /* Move down the file */
+                nbytes -= n;
+                buf += n;
+                retval += n;
+        }
+        free_page((unsigned long) page);
+        return retval;
+}
+
+
+static ssize_t sound_read(struct file *file, char *buf, size_t count, loff_t *ppos)
+{
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
 
        files[dev].flags = file->f_flags;
+       DEB(printk("sound_read(dev=%d, count=%d)\n", dev, count));
+       switch (dev & 0x0f) {
+       case SND_DEV_STATUS:
+               return sndstat_file_read(file, buf, count, ppos);
+
+#ifdef CONFIG_AUDIO
+       case SND_DEV_DSP:
+       case SND_DEV_DSP16:
+       case SND_DEV_AUDIO:
+               return audio_read(dev, &files[dev], buf, count);
+#endif
+
+#ifdef CONFIG_SEQUENCER
+       case SND_DEV_SEQ:
+       case SND_DEV_SEQ2:
+               return sequencer_read(dev, &files[dev], buf, count);
+#endif
+
+#ifdef CONFIG_MIDI
+       case SND_DEV_MIDIN:
+               return MIDIbuf_read(dev, &files[dev], buf, count);
+#endif
 
-       return sound_read_sw(dev, &files[dev], buf, count);
+       default:;
+       }
+       return -EINVAL;
 }
 
 static ssize_t sound_write(struct file *file, const char *buf, size_t count, loff_t *ppos)
 {
-       int             dev;
-
-       dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
 
        files[dev].flags = file->f_flags;
+       DEB(printk("sound_write(dev=%d, count=%d)\n", dev, count));
+       switch (dev & 0x0f) {
+#ifdef CONFIG_SEQUENCER
+       case SND_DEV_SEQ:
+       case SND_DEV_SEQ2:
+               return sequencer_write(dev, &files[dev], buf, count);
+#endif
+
+#ifdef CONFIG_AUDIO
+       case SND_DEV_DSP:
+       case SND_DEV_DSP16:
+       case SND_DEV_AUDIO:
+               return audio_write(dev, &files[dev], buf, count);
+#endif
 
-       return sound_write_sw(dev, &files[dev], buf, count);
+#ifdef CONFIG_MIDI
+       case SND_DEV_MIDIN:
+               return MIDIbuf_write(dev, &files[dev], buf, count);
+#endif
+       }
+       return -EINVAL;
 }
 
 static long long sound_lseek(struct file *file, long long offset, int orig)
@@ -93,20 +414,17 @@ static long long sound_lseek(struct file *file, long long offset, int orig)
 
 static int sound_open(struct inode *inode, struct file *file)
 {
-       int             dev, retval;
+       int dev, retval;
        struct fileinfo tmp_file;
 
-       if (is_unloading)
-       {
-/*               printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
-                 return -EBUSY;
+       if (is_unloading) {
+               /* printk(KERN_ERR "Sound: Driver partially removed. Can't open device\n");*/
+               return -EBUSY;
        }
        dev = MINOR(inode->i_rdev);
-
-       if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS)
-       {
-/*               printk("SoundCard Error: The soundcard system has not been configured\n");*/
-                 return -ENXIO;
+       if (!soundcard_configured && dev != SND_DEV_CTL && dev != SND_DEV_STATUS) {
+               /* printk("SoundCard Error: The soundcard system has not been configured\n");*/
+               return -ENXIO;
        }
        tmp_file.mode = 0;
        tmp_file.flags = file->f_flags;
@@ -117,130 +435,259 @@ static int sound_open(struct inode *inode, struct file *file)
                tmp_file.mode = OPEN_READ;
        if ((tmp_file.flags & O_ACCMODE) == O_WRONLY)
                tmp_file.mode = OPEN_WRITE;
+       DEB(printk("sound_open(dev=%d)\n", dev));
+       if ((dev >= SND_NDEVS) || (dev < 0)) {
+               printk(KERN_ERR "Invalid minor device %d\n", dev);
+               return -ENXIO;
+       }
+       switch (dev & 0x0f) {
+       case SND_DEV_STATUS:
+               break;
+
+       case SND_DEV_CTL:
+               if ((dev & 0xf0) && ((dev & 0xf0) >> 4) >= num_mixers)
+                       return -ENXIO;
+               break;
+
+#ifdef CONFIG_SEQUENCER
+       case SND_DEV_SEQ:
+       case SND_DEV_SEQ2:
+               if ((retval = sequencer_open(dev, &tmp_file)) < 0)
+                       return retval;
+               break;
+#endif
 
-       if ((retval = sound_open_sw(dev, &tmp_file)) < 0)
-               return retval;
+#ifdef CONFIG_MIDI
+       case SND_DEV_MIDIN:
+               if ((retval = MIDIbuf_open(dev, &tmp_file)) < 0)
+                       return retval;
+               break;
+#endif
 
+#ifdef CONFIG_AUDIO
+       case SND_DEV_DSP:
+       case SND_DEV_DSP16:
+       case SND_DEV_AUDIO:
+               if ((retval = audio_open(dev, &tmp_file)) < 0)
+                       return retval;
+               break;
+#endif
+
+       default:
+               printk(KERN_ERR "Invalid minor device %d\n", dev);
+               return -ENXIO;
+       }
+       in_use++;
 #ifdef MODULE
        SOUND_INC_USE_COUNT;
 #endif
-
-       memcpy((char *) &files[dev], (char *) &tmp_file, sizeof(tmp_file));
-       return retval;
+       memcpy(&files[dev], &tmp_file, sizeof(tmp_file));
+       return 0;
 }
 
 static int sound_release(struct inode *inode, struct file *file)
 {
-       int             dev;
-
-       dev = MINOR(inode->i_rdev);
+       int dev = MINOR(inode->i_rdev);
 
        files[dev].flags = file->f_flags;
+       DEB(printk("sound_release(dev=%d)\n", dev));
+       switch (dev & 0x0f) {
+       case SND_DEV_STATUS:
+       case SND_DEV_CTL:
+               break;
+               
+#ifdef CONFIG_SEQUENCER
+       case SND_DEV_SEQ:
+       case SND_DEV_SEQ2:
+               sequencer_release(dev, &files[dev]);
+               break;
+#endif
+
+#ifdef CONFIG_MIDI
+       case SND_DEV_MIDIN:
+               MIDIbuf_release(dev, &files[dev]);
+               break;
+#endif
 
-       sound_release_sw(dev, &files[dev]);
+#ifdef CONFIG_AUDIO
+       case SND_DEV_DSP:
+       case SND_DEV_DSP16:
+       case SND_DEV_AUDIO:
+               audio_release(dev, &files[dev]);
+               break;
+#endif
+
+       default:
+               printk(KERN_ERR "Sound error: Releasing unknown device 0x%02x\n", dev);
+       }
+       in_use--;
 #ifdef MODULE
        SOUND_DEC_USE_COUNT;
 #endif
        return 0;
 }
 
-static int sound_ioctl(struct inode *inode, struct file *file,
-           unsigned int cmd, unsigned long arg)
+static int get_mixer_info(int dev, caddr_t arg)
 {
-       int             dev, err;
-       int             len = 0;
-       int             alloced = 0;
-       char           *ptr = (char *) arg;
+       mixer_info info;
+       int i;
 
-       dev = MINOR(inode->i_rdev);
+       if (dev < 0 || dev >= num_mixers)
+               return -ENXIO;
+       strcpy(info.id, mixer_devs[dev]->id);
+       for (i = 0; i < 32 && mixer_devs[dev]->name; i++)
+               info.name[i] = mixer_devs[dev]->name[i];
+       info.name[i] = 0;
+       info.modify_counter = mixer_devs[dev]->modify_counter;
+       if (__copy_to_user(arg, &info,  sizeof(info)))
+               return -EFAULT;
+       return 0;
+}
 
-       files[dev].flags = file->f_flags;
+static int get_old_mixer_info(int dev, caddr_t arg)
+{
+       _old_mixer_info info;
+       int             i;
 
-       if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0)
-       {
+       if (dev < 0 || dev >= num_mixers)
+               return -ENXIO;
+       strcpy(info.id, mixer_devs[dev]->id);
+       for (i = 0; i < 32 && mixer_devs[dev]->name; i++)
+               info.name[i] = mixer_devs[dev]->name[i];
+       info.name[i] = 0;
+       if (__copy_to_user(arg, &info,  sizeof(info)))
+               return -EFAULT;
+       return 0;
+}
+
+static int sound_mixer_ioctl(int mixdev, unsigned int cmd, caddr_t arg)
+{
+       if (cmd == SOUND_MIXER_INFO)
+               return get_mixer_info(mixdev, arg);
+       if (cmd == SOUND_OLD_MIXER_INFO)
+               return get_old_mixer_info(mixdev, arg);
+       if (_SIOC_DIR(cmd) & _SIOC_WRITE)
+               mixer_devs[mixdev]->modify_counter++;
+       if (!mixer_devs[mixdev]->ioctl)
+               return -EINVAL;
+       return mixer_devs[mixdev]->ioctl(mixdev, cmd, arg);
+}
+
+static int sound_ioctl(struct inode *inode, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       int err, len = 0, dtype, mixdev;
+       int dev = MINOR(inode->i_rdev);
+
+       files[dev].flags = file->f_flags;
+       if (_SIOC_DIR(cmd) != _SIOC_NONE && _SIOC_DIR(cmd) != 0) {
                /*
                 * Have to validate the address given by the process.
                 */
-
                len = _SIOC_SIZE(cmd);
                if (len < 1 || len > 65536 || arg == 0)
                        return -EFAULT;
-
-               ptr = vmalloc(len);
-               alloced = 1;
-               if (ptr == NULL)
-                       return -EFAULT;
-
                if (_SIOC_DIR(cmd) & _SIOC_WRITE)
-               {
-                       if ((err = verify_area(VERIFY_READ, (void *) arg, len)) < 0)
+                       if ((err = verify_area(VERIFY_READ, (void *)arg, len)) < 0)
                                return err;
-                       copy_from_user(ptr, (char *) arg, len);
-               }
                if (_SIOC_DIR(cmd) & _SIOC_READ)
-               {
-                       if ((err = verify_area(VERIFY_WRITE, (void *) arg, len)) < 0)
+                       if ((err = verify_area(VERIFY_WRITE, (void *)arg, len)) < 0)
                                return err;
-               }
        }
-       err = sound_ioctl_sw(dev, &files[dev], cmd, (caddr_t) ptr);
+       DEB(printk("sound_ioctl(dev=%d, cmd=0x%x, arg=0x%x)\n", dev, cmd, arg));
+       if (cmd == OSS_GETVERSION)
+               return __put_user(SOUND_VERSION, (int *)arg);
+       
+       if (((cmd >> 8) & 0xff) == 'M' && num_mixers > 0)       /* Mixer ioctl */
+               if ((dev & 0x0f) != SND_DEV_CTL) {
+                       dtype = dev & 0x0f;
+                       switch (dtype) {
+#ifdef CONFIG_AUDIO
+                       case SND_DEV_DSP:
+                       case SND_DEV_DSP16:
+                       case SND_DEV_AUDIO:
+                               mixdev = audio_devs[dev >> 4]->mixer_dev;
+                               if (mixdev < 0 || mixdev >= num_mixers)
+                                       return -ENXIO;
+                               return sound_mixer_ioctl(mixdev, cmd, (caddr_t)arg);
+#endif
+                               
+                       default:
+                               return sound_mixer_ioctl(dev, cmd, (caddr_t)arg);
+                       }
+               }
+       switch (dev & 0x0f) {
+       case SND_DEV_CTL:
+               if (cmd == SOUND_MIXER_GETLEVELS)
+                       return get_mixer_levels((caddr_t)arg);
+               if (cmd == SOUND_MIXER_SETLEVELS)
+                       return set_mixer_levels((caddr_t)arg);
+               if (!num_mixers)
+                       return -ENXIO;
+               dev = dev >> 4;
+               if (dev >= num_mixers)
+                       return -ENXIO;
+               return sound_mixer_ioctl(dev, cmd, (caddr_t)arg);
+               break;
+
+#ifdef CONFIG_SEQUENCER
+       case SND_DEV_SEQ:
+       case SND_DEV_SEQ2:
+               return sequencer_ioctl(dev, &files[dev], cmd, (caddr_t)arg);
+#endif
 
-       if (_SIOC_DIR(cmd) & _SIOC_READ)
-               copy_to_user((char *) arg, ptr, len);
+#ifdef CONFIG_AUDIO
+       case SND_DEV_DSP:
+       case SND_DEV_DSP16:
+       case SND_DEV_AUDIO:
+               return audio_ioctl(dev, &files[dev], cmd, (caddr_t)arg);
+               break;
+#endif
 
-       if (ptr != NULL && alloced)
-               vfree(ptr);
+#ifdef CONFIG_MIDI
+       case SND_DEV_MIDIN:
+               return MIDIbuf_ioctl(dev, &files[dev], cmd, (caddr_t)arg);
+               break;
+#endif
 
-       return ((err < 0) ? err : 0);
+       }
+       return -EINVAL;
 }
 
 static int sound_select(struct inode *inode, struct file *file, int sel_type, poll_table * wait)
 {
-       int             dev;
-
-       dev = MINOR(inode->i_rdev);
+       int dev = MINOR(inode->i_rdev);
 
        files[dev].flags = file->f_flags;
-
        DEB(printk("sound_select(dev=%d, type=0x%x)\n", dev, sel_type));
-
-       switch (dev & 0x0f)
-       {
+       switch (dev & 0x0f) {
 #if defined(CONFIG_SEQUENCER) || defined(MODULE)
-               case SND_DEV_SEQ:
-               case SND_DEV_SEQ2:
-                       return sequencer_select(dev, &files[dev], sel_type, wait);
-                       break;
+       case SND_DEV_SEQ:
+       case SND_DEV_SEQ2:
+               return sequencer_select(dev, &files[dev], sel_type, wait);
 #endif
 
 #if defined(CONFIG_MIDI)
-               case SND_DEV_MIDIN:
-                       return MIDIbuf_select(dev, &files[dev], sel_type, wait);
-                       break;
+       case SND_DEV_MIDIN:
+               return MIDIbuf_select(dev, &files[dev], sel_type, wait);
 #endif
 
 #if defined(CONFIG_AUDIO) || defined(MODULE)
-               case SND_DEV_DSP:
-               case SND_DEV_DSP16:
-               case SND_DEV_AUDIO:
-                       return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait);
-                       break;
+       case SND_DEV_DSP:
+       case SND_DEV_DSP16:
+       case SND_DEV_AUDIO:
+               return DMAbuf_select(dev >> 4, &files[dev], sel_type, wait);
 #endif
-
-               default:
-                       return 0;
        }
-
        return 0;
 }
 
 static unsigned int sound_poll(struct file *file, poll_table * wait)
 {
-       struct inode   *inode;
-       int             ret = 0;
+       struct inode *inode;
+       int ret = 0;
 
        inode = file->f_dentry->d_inode;
-
        if (sound_select(inode, file, SEL_IN, wait))
                ret |= POLLIN;
        if (sound_select(inode, file, SEL_OUT, wait))
@@ -250,11 +697,10 @@ static unsigned int sound_poll(struct file *file, poll_table * wait)
 
 static int sound_mmap(struct file *file, struct vm_area_struct *vma)
 {
-       int             dev, dev_class;
-       unsigned long   size;
+       int dev_class;
+       unsigned long size;
        struct dma_buffparms *dmap = NULL;
-
-       dev = MINOR(file->f_dentry->d_inode->i_rdev);
+       int dev = MINOR(file->f_dentry->d_inode->i_rdev);
 
        files[dev].flags = file->f_flags;
 
@@ -418,7 +864,9 @@ int init_module(void)
 
        if (sound_nblocks >= 1024)
                printk(KERN_ERR "Sound warning: Deallocation table was too small.\n");
-
+       
+       if (proc_register(&proc_root, &proc_root_sound))
+               printk(KERN_ERR "sound: registering /proc/sound failed\n");
        return 0;
 }
 
@@ -433,6 +881,8 @@ void cleanup_module(void)
        {
                return;
        }
+        if (proc_unregister(&proc_root, PROC_SOUND))
+               printk(KERN_ERR "sound: unregistering /proc/sound failed\n");
        if (chrdev_registered)
                unregister_chrdev(sound_major, "sound");
 
@@ -779,3 +1229,35 @@ void conf_printf2(char *name, int base, int irq, int dma, int dma2)
        }
        printk("\n");
 }
+
+/*
+ *     Module and lock management
+ */
+struct notifier_block *sound_locker=(struct notifier_block *)0;
+static int lock_depth = 0;
+
+#define SOUND_INC_USE_COUNT    do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0);
+#define SOUND_DEC_USE_COUNT    do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0);
+
+/*
+ *     When a sound module is registered we need to bring it to the current
+ *     lock level...
+ */
+void sound_notifier_chain_register(struct notifier_block *bl)
+{
+       int ct=0;
+       
+       notifier_chain_register(&sound_locker, bl);
+       /*
+        *      Normalise the lock count by calling the entry directly. We
+        *      have to call the module as it owns its own use counter
+        */
+       while(ct<lock_depth)
+       {
+               bl->notifier_call(bl, 1, 0);
+               ct++;
+       }
+}
+
index d590acc0b0fadc75b5e701ff6c2d100c2c858dba..25a05179615d866545b07d75f8bc3f06a25d61d7 100644 (file)
@@ -5,19 +5,21 @@
 
 #include <linux/notifier.h>
 
-#ifdef SOUND_CORE
+extern struct notifier_block *sound_locker;
+extern void sound_notifier_chain_register(struct notifier_block *);
+extern int lock_depth;
 
-struct notifier_block *sound_locker=(struct notifier_block *)0;
+#ifdef SOUND_CORE
 
-#define SOUND_INC_USE_COUNT    notifier_call_chain(&sound_locker, 1, 0)
-#define SOUND_DEC_USE_COUNT    notifier_call_chain(&sound_locker, 0, 0)
+#define SOUND_INC_USE_COUNT    do { notifier_call_chain(&sound_locker, 1, 0); lock_depth++; } while(0);
+#define SOUND_DEC_USE_COUNT    do { notifier_call_chain(&sound_locker, 0, 0); lock_depth--; } while(0);
 
 #else
 
-#define SOUND_LOCK             notifier_chain_register(&sound_locker, &sound_notifier)
+
+#define SOUND_LOCK             sound_notifier_chain_register(&sound_notifier); 
 #define SOUND_LOCK_END         notifier_chain_unregister(&sound_locker, &sound_notifier)
 
-extern struct notifier_block *sound_locker;
 
 
 static int my_notifier_call(struct notifier_block *b, unsigned long foo, void *bar)
index befd924d0b8fa50f7b6d1d3fc1feccac1ab053ca..480b309d0edd14aca353fe02788fbdec9631ae95 100644 (file)
@@ -10,6 +10,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 #include <linux/module.h>
 
@@ -570,36 +573,31 @@ download_boot_block(void *dev_info, copr_buffer * buf)
        return 0;
 }
 
-static int
-sscape_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local)
+static int sscape_coproc_ioctl(void *dev_info, unsigned int cmd, caddr_t arg, int local)
 {
+       copr_buffer *buf;
+       int err;
 
-       switch (cmd)
-         {
-         case SNDCTL_COPR_RESET:
-                 sscape_coproc_reset(dev_info);
-                 return 0;
-                 break;
-
-         case SNDCTL_COPR_LOAD:
-                 {
-                         copr_buffer    *buf;
-                         int             err;
-
-                         buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
-                         if (buf == NULL)
-                                 return -ENOSPC;
-                         memcpy((char *) buf, (&((char *) arg)[0]), sizeof(*buf));
-                         err = download_boot_block(dev_info, buf);
-                         vfree(buf);
-                         return err;
-                 }
-                 break;
-
-         default:
-                 return -EINVAL;
-         }
+       switch (cmd) {
+       case SNDCTL_COPR_RESET:
+               sscape_coproc_reset(dev_info);
+               return 0;
 
+       case SNDCTL_COPR_LOAD:
+               buf = (copr_buffer *) vmalloc(sizeof(copr_buffer));
+               if (buf == NULL)
+                       return -ENOSPC;
+               if (__copy_from_user(buf, arg, sizeof(copr_buffer))) {
+                       vfree(buf);
+                       return -EFAULT;
+               }
+               err = download_boot_block(dev_info, buf);
+               vfree(buf);
+               return err;
+               
+       default:
+               return -EINVAL;
+       }
 }
 
 static coproc_operations sscape_coproc_operations =
index 8097d1872f91c68eca6f8ae6004b9df2b026e5be..4d0456dd15a23cabfbd4e93ab58eae8f774a53bc 100644 (file)
@@ -11,6 +11,9 @@
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
  */
+/*
+ * Thomas Sailer   : ioctl code reworked (vmalloc/vfree removed)
+ */
 #include <linux/config.h>
 
 
@@ -184,94 +187,73 @@ def_tmr_get_time(int dev)
        return curr_ticks;
 }
 
-static int
-def_tmr_ioctl(int dev,
-             unsigned int cmd, caddr_t arg)
+/* same as sound_timer.c:timer_ioctl!? */
+static int def_tmr_ioctl(int dev, unsigned int cmd, caddr_t arg)
 {
-       switch (cmd)
-         {
-         case SNDCTL_TMR_SOURCE:
-                 return (*(int *) arg = TMR_INTERNAL);
-                 break;
+       int val;
 
-         case SNDCTL_TMR_START:
-                 tmr_reset();
-                 tmr_running = 1;
-                 return 0;
-                 break;
+       switch (cmd) {
+       case SNDCTL_TMR_SOURCE:
+               return __put_user(TMR_INTERNAL, (int *)arg);
 
-         case SNDCTL_TMR_STOP:
-                 tmr_running = 0;
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_CONTINUE:
-                 tmr_running = 1;
-                 return 0;
-                 break;
-
-         case SNDCTL_TMR_TIMEBASE:
-                 {
-                         int             val;
-
-                         val = *(int *) arg;
-
-                         if (val)
-                           {
-                                   if (val < 1)
-                                           val = 1;
-                                   if (val > 1000)
-                                           val = 1000;
-                                   curr_timebase = val;
-                           }
-                         return (*(int *) arg = curr_timebase);
-                 }
-                 break;
-
-         case SNDCTL_TMR_TEMPO:
-                 {
-                         int             val;
-
-                         val = *(int *) arg;
-
-                         if (val)
-                           {
-                                   if (val < 8)
-                                           val = 8;
-                                   if (val > 250)
-                                           val = 250;
-                                   tmr_offs = tmr_ctr;
-                                   ticks_offs += tmr2ticks(tmr_ctr);
-                                   tmr_ctr = 0;
-                                   curr_tempo = val;
-                           }
-                         return (*(int *) arg = curr_tempo);
-                 }
-                 break;
-
-         case SNDCTL_SEQ_CTRLRATE:
-                 {
-                         int             val;
-
-                         val = *(int *) arg;
-                         if (val != 0)         /* Can't change */
-                                 return -EINVAL;
-
-                         return (*(int *) arg = ((curr_tempo * curr_timebase) + 30) / 60);
-                 }
-                 break;
-
-         case SNDCTL_SEQ_GETTIME:
-                 return (*(int *) arg = curr_ticks);
-                 break;
+       case SNDCTL_TMR_START:
+               tmr_reset();
+               tmr_running = 1;
+               return 0;
 
-         case SNDCTL_TMR_METRONOME:
-                 /* NOP */
-                 break;
+       case SNDCTL_TMR_STOP:
+               tmr_running = 0;
+               return 0;
 
-         default:;
-         }
+       case SNDCTL_TMR_CONTINUE:
+               tmr_running = 1;
+               return 0;
 
+       case SNDCTL_TMR_TIMEBASE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val) {
+                       if (val < 1)
+                               val = 1;
+                       if (val > 1000)
+                               val = 1000;
+                       curr_timebase = val;
+               }
+               return __put_user(curr_timebase, (int *)arg);
+
+       case SNDCTL_TMR_TEMPO:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val) {
+                       if (val < 8)
+                               val = 8;
+                       if (val > 250)
+                               val = 250;
+                       tmr_offs = tmr_ctr;
+                       ticks_offs += tmr2ticks(tmr_ctr);
+                       tmr_ctr = 0;
+                       curr_tempo = val;
+                       reprogram_timer();
+               }
+               return __put_user(curr_tempo, (int *)arg);
+
+       case SNDCTL_SEQ_CTRLRATE:
+               if (__get_user(val, (int *)arg))
+                       return -EFAULT;
+               if (val != 0)   /* Can't change */
+                       return -EINVAL;
+               val = ((curr_tempo * curr_timebase) + 30) / 60;
+               return __put_user(val, (int *)arg);
+               
+       case SNDCTL_SEQ_GETTIME:
+               return __put_user(curr_ticks, (int *)arg);
+               
+       case SNDCTL_TMR_METRONOME:
+               /* NOP */
+               break;
+               
+       default:;
+       }
        return -EINVAL;
 }
 
index d32537abc0b22945762ac19022a3b0e3b38f6073..7293e9047396abdd07db7703544beb2c820bb43e 100644 (file)
@@ -186,12 +186,6 @@ uart401_end_read(int dev)
        return 0;
 }
 
-static int
-uart401_ioctl(int dev, unsigned cmd, caddr_t arg)
-{
-       return -EINVAL;
-}
-
 static void
 uart401_kick(int dev)
 {
@@ -214,7 +208,7 @@ static struct midi_operations uart401_operations =
        {0},
        uart401_open,
        uart401_close,
-       uart401_ioctl,
+       NULL, /* ioctl */
        uart401_out,
        uart401_start_read,
        uart401_end_read,
index 9285e40b1f893ee45af627740e81d3f402c49612..c3e75857bb19781e310930665d513b08dac50bd2 100644 (file)
@@ -1,6 +1,3 @@
-
-
-
 /*
  * sound/uart6850.c
  */
@@ -226,12 +223,6 @@ uart6850_end_read(int dev)
        return 0;
 }
 
-static int
-uart6850_ioctl(int dev, unsigned cmd, caddr_t arg)
-{
-       return -EINVAL;
-}
-
 static void
 uart6850_kick(int dev)
 {
@@ -256,7 +247,7 @@ static struct midi_operations uart6850_operations =
        {0},
        uart6850_open,
        uart6850_close,
-       uart6850_ioctl,
+       NULL, /* ioctl */
        uart6850_out,
        uart6850_start_read,
        uart6850_end_read,
index 8b9aba17f9f8eeff6e46810a92f5c40cc1cf8209..11537d3724ca33a2ff722098165a108d0b59332e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * sound/sb_dsp.c
+ * sound/v_midi.c
  *
  * The low level driver for the Sound Blaster DS chips.
  */
@@ -9,6 +9,7 @@
  * USS/Lite for Linux is distributed under the GNU GENERAL PUBLIC LICENSE (GPL)
  * Version 2 (June 1991). See the "COPYING" file distributed with this software
  * for more info.
+ * ??
  */
 #include <linux/config.h>
 #include <linux/module.h>
@@ -146,10 +147,10 @@ v_midi_end_read (int dev)
   return 0;
 }
 
-static int
-v_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
+/* why -EPERM and not -EINVAL?? */
+static int v_midi_ioctl (int dev, unsigned cmd, caddr_t arg)
 {
-  return -(EPERM);
+       return -EPERM;
 }
 
 
index 3710fcc9a095bc1031a4cfc4c414debf23c043b8..813ac2c4836cff206b26409c056354d24926a98b 100644 (file)
--- a/fs/exec.c
+++ b/fs/exec.c
@@ -518,7 +518,7 @@ int flush_old_exec(struct linux_binprm * bprm)
         * Release all of the old mmap stuff
         */
        retval = exec_mmap();
-       if (retval) goto flush_failed;
+       if (retval) goto mmap_failed;
 
        /* This is the point of no return */
        release_old_signals(oldsig);
@@ -546,6 +546,9 @@ int flush_old_exec(struct linux_binprm * bprm)
 
        return 0;
 
+mmap_failed:
+       if (current->sig != oldsig)
+               kfree(current->sig);
 flush_failed:
        current->sig = oldsig;
        return retval;
index d4945dc77588c873ae07882ad8e456af5021b5db..8913be26f855150c4ece21160b5e0a1a97a6761c 100644 (file)
@@ -411,7 +411,7 @@ static void nfs_dentry_delete(struct dentry *dentry)
                int error;
                
                dentry->d_flags &= ~DCACHE_NFSFS_RENAMED;
-#ifdef NFS_DEBUG
+#ifdef NFS_DEBUG_VERBOSE
 printk("nfs_dentry_delete: unlinking %s/%s\n",
 dentry->d_parent->d_name.name, dentry->d_name.name);
 #endif
@@ -647,34 +647,21 @@ static int nfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        if (dentry->d_name.len > NFS_MAXNAMLEN)
                goto out;
 
-       /* For some reason mode doesn't have the S_IFDIR flag ... */
-       mode |= S_IFDIR;
-       sattr.mode = mode;
+       sattr.mode = mode | S_IFDIR;
        sattr.uid = sattr.gid = sattr.size = (unsigned) -1;
        sattr.atime.seconds = sattr.mtime.seconds = (unsigned) -1;
 
        nfs_invalidate_dircache(dir);
        error = nfs_proc_mkdir(NFS_SERVER(dir), NFS_FH(dir),
                                dentry->d_name.name, &sattr, &fhandle, &fattr);
-       if (!error) {
-               /*
-                * Some AIX servers reportedly fail to fill out the fattr.
-                * Check for a bad mode value and complain, then drop the
-                * dentry to force a new lookup.
-                */
-               if (!S_ISDIR(fattr.mode)) {
-                       static int complain = 0;
-                       if (!complain++)
-                               printk("NFS: buggy server! fattr mode=%x\n",
-                                       fattr.mode);
-                       goto drop;
-               }
-               error = nfs_instantiate(dentry, &fhandle, &fattr);
-       }
-       if (error) {
-       drop:
-               d_drop(dentry);
-       }
+
+       /*
+        * Always drop the dentry, we can't always depend on
+        * the fattr returned by the server (AIX seems to be
+        * broken). We're better off doing another lookup than
+        * depending on potentially bogus information.
+        */
+       d_drop(dentry);
 out:
        return error;
 }
@@ -1109,10 +1096,8 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
         * First check whether the target is busy ... we can't
         * safely do _any_ rename if the target is in use.
         */
-       if (new_dentry->d_count > 1) {
-               if (new_inode && S_ISDIR(new_inode->i_mode))
-                       shrink_dcache_parent(new_dentry);
-       }
+       if (new_dentry->d_count > 1 && !list_empty(&new_dentry->d_subdirs))
+               shrink_dcache_parent(new_dentry);
        error = -EBUSY;
        if (new_dentry->d_count > 1) {
 #ifdef NFS_PARANOIA
@@ -1176,28 +1161,33 @@ new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
 
 do_rename:
        /*
-        * We must prevent any new references to the target while
-        * the rename is in progress, so we unhash the dentry.
+        * To prevent any new references to the target during the rename,
+        * we unhash the dentry and free the inode in advance.
         */
+#ifdef NFS_PARANOIA
+if (new_inode && 
+    new_inode->i_count > (S_ISDIR(new_inode->i_mode) ? 1 : new_inode->i_nlink))
+printk("nfs_rename: %s/%s inode busy?? i_count=%d, i_nlink=%d\n",
+new_dentry->d_parent->d_name.name, new_dentry->d_name.name,
+new_inode->i_count, new_inode->i_nlink);
+#endif
        if (!list_empty(&new_dentry->d_hash)) {
                d_drop(new_dentry);
                rehash = update;
        }
+       if (new_inode) {
+               d_delete(new_dentry);
+       }
+
        nfs_invalidate_dircache(new_dir);
        nfs_invalidate_dircache(old_dir);
        error = nfs_proc_rename(NFS_SERVER(old_dir),
                                NFS_FH(old_dir), old_dentry->d_name.name,
                                NFS_FH(new_dir), new_dentry->d_name.name);
-       if (rehash) {
-               d_add(new_dentry, new_inode);
-       }
-#ifdef NFS_PARANOIA
-if (new_dentry->d_count > 1)
-printk("nfs_rename: %s/%s busy after rename, d_count=%d\n",
-new_dentry->d_parent->d_name.name,new_dentry->d_name.name,new_dentry->d_count);
-#endif
        if (!error) {
                /* Update the dcache if needed */
+               if (rehash)
+                       d_add(new_dentry, NULL);
                if (update)
                        d_move(old_dentry, new_dentry);
        }
index 8b820e21b630579ef3c245869d5cc89efbd78ed6..a2924b53b697bbb13da7c6baff6b415e261e3a35 100644 (file)
@@ -2,9 +2,6 @@
 # Native language support configuration
 #
 
-mainmenu_option next_comment
-comment 'Native Language Support'
-
 # msdos and Joliet want NLS
 if [ "$CONFIG_JOLIET" = "y" -o "$CONFIG_FAT_FS" != "n" \
        -o "$CONFIG_NTFS_FS" != "n" ]; then
@@ -14,6 +11,8 @@ else
 fi
 
 if [ "$CONFIG_NLS" = "y" ]; then
+  mainmenu_option next_comment
+  comment 'Native Language Support'
   tristate 'Codepage 437'      CONFIG_NLS_CODEPAGE_437
   tristate 'Codepage 737'      CONFIG_NLS_CODEPAGE_737
   tristate 'Codepage 775'      CONFIG_NLS_CODEPAGE_775
@@ -40,6 +39,5 @@ if [ "$CONFIG_NLS" = "y" ]; then
   tristate 'NLS ISO 8859-8'    CONFIG_NLS_ISO8859_8
   tristate 'NLS ISO 8859-9'    CONFIG_NLS_ISO8859_9
   tristate 'NLS KOI8-R'        CONFIG_NLS_KOI8_R
+  endmenu
 fi
-
-endmenu
index 2c01b21daafdce03c6eb791c063063df956ae19b..bd753629980e81c5e489f6ec181650135652d235 100644 (file)
@@ -3,7 +3,7 @@
 O_TARGET := ntfs.o
 O_OBJS   := fs.o sysctl.o support.o util.o inode.o dir.o super.o attr.o
 M_OBJS   := $(O_TARGET)
-EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"971219\"
+EXTRA_CFLAGS = -DNTFS_IN_LINUX_KERNEL -DNTFS_VERSION=\"980101\"
 
 include $(TOPDIR)/Rules.make
 
index 3b246023ff6c192799baa8c1f984395a39e25e1a..838e5ea5da25ede3d9aaa5e1450cf12f2987a5f4 100644 (file)
@@ -731,6 +731,7 @@ int ntfs_getdir_unsorted(ntfs_inode *ino,ntfs_u32 *p_high,ntfs_u32* p_low,
                if(buf[byte] & bit)
                        break;
        }
+       ntfs_free(buf);
        return 0;
 }
 
index 6e263ef7f991262ca197e9440b98479aac21c2bd..18704ea5992f6ed3d31b5a79de0170a5207de947 100644 (file)
@@ -468,6 +468,9 @@ ntfs_create(struct inode* dir,struct dentry *d,int mode)
        /* It's not a directory */
        r->i_op=&ntfs_inode_operations_nobmap;
        r->i_mode=S_IFREG|S_IRUGO;
+#ifdef CONFIG_NTFS_RW
+       r->i_mode|=S_IWUGO;
+#endif
        r->i_mode &= ~vol->umask;
 
        d_instantiate(d,r);
@@ -654,9 +657,12 @@ static void ntfs_read_inode(struct inode* inode)
        {
                inode->i_op=can_mmap ? &ntfs_inode_operations : 
                        &ntfs_inode_operations_nobmap;
-               inode->i_mode=S_IFREG|S_IRUGO|S_IMMUTABLE;
                inode->i_mode=S_IFREG|S_IRUGO;
        }
+#ifdef CONFIG_NTFS_RW
+       if(!data || !data->compressed)
+               inode->i_mode|=S_IWUGO;
+#endif
        inode->i_mode &= ~vol->umask;
 }
 
@@ -873,7 +879,9 @@ ntfs_read_super_unl:
        unlock_super(sb);
        ntfs_debug(DEBUG_OTHER, "unlock_super\n");
 ntfs_read_super_vol:
+       #ifndef NTFS_IN_LINUX_KERNEL
        ntfs_free(vol);
+       #endif
 ntfs_read_super_dec:
        ntfs_debug(DEBUG_OTHER, "read_super: done\n");
        MOD_DEC_USE_COUNT;
index 615f3a60a811515022d4f3f42188fc0e43b067a7..65647c15442f7ddfa945ff906cea54038f9ae919 100644 (file)
@@ -850,8 +850,7 @@ void ntfs_decompress(unsigned char *dest, unsigned char *src, ntfs_size_t l)
        {
                head = NTFS_GETU16(src) & 0xFFF;
                /* high bit indicates that compression was performed */
-               comp = NTFS_GETU8(src) & 0x80;
-               comp = (head == 0xFFF);
+               comp = NTFS_GETU16(src) & 0x8000;
                src += 2;
                stop = src+head;
                bits = 0;
index 7643f77add367089aeeaceb8fb978cb5224e5f73..230432e5bd3f60c0c5726f6ef2d11c31505dc627 100644 (file)
@@ -43,6 +43,7 @@ void ntfs_debug(int mask, const char *fmt, ...)
        }
 }
 
+#ifndef ntfs_malloc
 /* Verbose kmalloc */
 void *ntfs_malloc(int size)
 {
@@ -53,27 +54,34 @@ void *ntfs_malloc(int size)
 
        return ret;
 }
+#endif
 
+#ifndef ntfs_free
 /* Verbose kfree() */
 void ntfs_free(void *block)
 {
         ntfs_debug(DEBUG_MALLOC, "Freeing memory at %p\n", block);
        kfree(block);
 }
+#endif
 #else
 void ntfs_debug(int mask, const char *fmt, ...)
 {
 }
 
+#ifndef ntfs_malloc
 void *ntfs_malloc(int size)
 {
        return kmalloc(size, GFP_KERNEL);
 }
+#endif
 
+#ifndef ntfs_free
 void ntfs_free(void *block)
 {
        kfree(block);
 }
+#endif
 #endif /* DEBUG */
 
 void ntfs_bzero(void *s, int n)
index 2ab2ab978b182896ebcf802bbe6401c8764572bd..b6def5c5639489922eed529ffdf4dd4d2f4f79e5 100644 (file)
 #define DEBUG_MALLOC   2
 
 void ntfs_debug(int mask, const char *fmt, ...);
+#ifdef NTFS_IN_LINUX_KERNEL
+#include <linux/slab.h>
+#define ntfs_malloc(size)  kmalloc(size,GFP_KERNEL)
+#define ntfs_free(ptr)     kfree(ptr)
+#else
 void *ntfs_malloc(int size);
 void ntfs_free(void *block);
+#endif
 void ntfs_bzero(void *s, int n);
 void *ntfs_memcpy(void *dest, const void *src, ntfs_size_t n);
 void *ntfs_memmove(void *dest, const void *src, ntfs_size_t n);
index f6f73ad1c06e53774de30b7f70ebac825ff5cbc8..260536842971eec84f48a812f9dd49509ef5f86b 100644 (file)
@@ -427,6 +427,14 @@ static int get_arg(int pid, char * buffer)
        return get_array(p, p->mm->arg_start, p->mm->arg_end, buffer);
 }
 
+/*
+ * These bracket the sleeping functions..
+ */
+extern void scheduling_functions_start_here(void);
+extern void scheduling_functions_end_here(void);
+#define first_sched    ((unsigned long) scheduling_functions_start_here)
+#define last_sched     ((unsigned long) scheduling_functions_end_here)
+
 static unsigned long get_wchan(struct task_struct *p)
 {
        if (!p || p == current || p->state == TASK_RUNNING)
@@ -445,8 +453,7 @@ static unsigned long get_wchan(struct task_struct *p)
                        if (ebp < stack_page || ebp >= 4092+stack_page)
                                return 0;
                        eip = *(unsigned long *) (ebp+4);
-                       if (eip < (unsigned long) interruptible_sleep_on
-                           || eip >= (unsigned long) add_timer)
+                       if (eip < first_sched || eip >= last_sched)
                                return eip;
                        ebp = *(unsigned long *) ebp;
                } while (count++ < 16);
@@ -466,7 +473,7 @@ static unsigned long get_wchan(struct task_struct *p)
            unsigned long pc;
 
            pc = thread_saved_pc(&p->tss);
-           if (pc >= (unsigned long) interruptible_sleep_on && pc < (unsigned long) add_timer) {
+           if (pc >= first_sched && pc < last_sched) {
                schedule_frame = ((unsigned long *)p->tss.ksp)[6];
                return ((unsigned long *)schedule_frame)[12];
            }
@@ -488,10 +495,7 @@ static unsigned long get_wchan(struct task_struct *p)
                            return 0;
                    pc = ((unsigned long *)fp)[1];
                /* FIXME: This depends on the order of these functions. */
-                   if ((pc < (unsigned long) __down
-                        || pc >= (unsigned long) add_timer)
-                       && (pc < (unsigned long) schedule
-                           || pc >= (unsigned long) sys_pause))
+                   if (pc < first_sched || pc >= last_sched)
                      return pc;
                    fp = *(unsigned long *) fp;
            } while (count++ < 16);
index 6664b6a6222802e100df6b05abf5adc823617bfd..b5c6aaf4017b7f7f78c716f953d654ddf8c2d53e 100644 (file)
@@ -173,6 +173,9 @@ static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
 
        len = qstr->len;
        name = qstr->name;
+       while (len && name[len-1] == '.')
+               len--;
+
        hash = init_name_hash();
        while (len--) {
                c = tolower(*name++);
@@ -193,14 +196,12 @@ static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
        /* A filename cannot end in '.' or we treat it like it has none */
        alen = a->len;
        blen = b->len;
-       if (alen != blen) {
-               if (a->name[alen-1] == '.')
-                       alen--;
-               if (b->name[blen-1] == '.')
-                       blen--;
-               if (alen != blen)
-                       return 1;
-       }
+       while (alen && a->name[alen-1] == '.')
+               alen--;
+       while (blen && b->name[blen-1] == '.')
+               blen--;
+       if (alen != blen)
+               return 1;
 
        return strnicmp(a->name, b->name, alen);
 }
@@ -966,11 +967,8 @@ static int vfat_readdir_cb(
                          vf->name, vf->len, name, name_len);
 #endif
 
-       /* Filenames cannot end in '.' or we treat like it has none */
        if (vf->len != name_len) {
-               if ((vf->len != name_len + 1) || (vf->name[name_len] != '.')) {
-                       return 0;
-               }
+               return 0;
        }
 
        s1 = name; s2 = vf->name;
index c67a92c04f957965754af36378c6e6096d667993..090950c9dbda641a201c6411906bdbad01a5d393 100644 (file)
@@ -172,7 +172,7 @@ struct thread_struct {
        _LDT(0),0, \
        0, 0x8000, \
        {~0, }, /* ioperm */ \
-       _TSS(0), 0, 0, 0, KERNEL_DS, \
+       _TSS(0), 0, 0, 0, (mm_segment_t) { 0 } /* obsolete */ , \
        { { 0, }, },  /* 387 state */ \
        NULL, 0, 0, 0, 0, 0 /* vm86_info */, \
 }
@@ -180,7 +180,7 @@ struct thread_struct {
 #define start_thread(regs, new_eip, new_esp) do {\
        unsigned long seg = __USER_DS; \
        __asm__("mov %w0,%%fs ; mov %w0,%%gs":"=r" (seg) :"0" (seg)); \
-       set_fs(MAKE_MM_SEG(seg)); \
+       set_fs(USER_DS); \
        regs->xds = seg; \
        regs->xes = seg; \
        regs->xss = seg; \
index bca5229ee9645697ccfa703d79374ffb7e2a5617..733f7764ea764df0b8ea171e795eec2b51a452b7 100644 (file)
  */
 
 #define MAKE_MM_SEG(s) ((mm_segment_t) { (s) })
-#define KERNEL_DS      MAKE_MM_SEG(0)
-#define USER_DS                MAKE_MM_SEG(3)
+
+
+#define KERNEL_DS      MAKE_MM_SEG(0xFFFFFFFF)
+#define USER_DS                MAKE_MM_SEG(0xC0000000)
 
 #define get_ds()       (KERNEL_DS)
-#define get_fs()       (current->tss.segment)
-#define set_fs(x)      (current->tss.segment = (x))
+#define get_fs()       (current->addr_limit)
+#define set_fs(x)      (current->addr_limit = (x))
 
 #define segment_eq(a,b)        ((a).seg == (b).seg)
 
+extern int __verify_write(const void *, unsigned long);
+
+#define __addr_ok(addr) ((unsigned long)(addr) < (current->addr_limit.seg))
 
 /*
- * Address Ok:
- *
- *                                  segment
- *                     00 (kernel)             11 (user)
- *
- * high                00      1                       1
- * two                 01      1                       1
- * bits of     10      1                       1
- * address     11      1                       0
+ * Uhhuh, this needs 33-bit arithmetic. We have a carry..
  */
-#define __addr_ok(x) \
-       ((((unsigned long)(x)>>30)&get_fs().seg) != 3)
+#define __range_ok(addr,size) ({ \
+       unsigned long flag,sum; \
+       asm("addl %3,%1 ; sbbl %0,%0; cmpl %1,%4; sbbl $0,%0" \
+               :"=&r" (flag), "=r" (sum) \
+               :"1" (addr),"g" (size),"g" (current->addr_limit.seg)); \
+       flag; })
 
-#define __user_ok(addr,size) \
-       ((size <= 0xC0000000UL) && (addr <= 0xC0000000UL - size))
-#define __kernel_ok \
-       (!get_fs().seg)
+#if CPU > 386
 
-extern int __verify_write(const void *, unsigned long);
+#define access_ok(type,addr,size) (__range_ok(addr,size) == 0)
 
-#if CPU > 386
-#define __access_ok(type,addr,size) \
-       (__kernel_ok || __user_ok(addr,size))
 #else
-#define __access_ok(type,addr,size) \
-       (__kernel_ok || (__user_ok(addr,size) && \
+
+#define access_ok(type,addr,size) ( (__range_ok(addr,size) == 0) && \
                         ((type) == VERIFY_READ || boot_cpu_data.wp_works_ok || \
-                         __verify_write((void *)(addr),(size)))))
-#endif /* CPU */
+                         __verify_write((void *)(addr),(size))))
 
-#define access_ok(type,addr,size) \
-       __access_ok((type),(unsigned long)(addr),(size))
+#endif /* CPU */
 
 extern inline int verify_area(int type, const void * addr, unsigned long size)
 {
index 9754f9384d64d02e4d7e7c1c98ad8ab59bcd14f4..81249e029dadb258e5194b26133b3ebb17bc7893 100644 (file)
@@ -1,15 +1,12 @@
 /*
  * The Linux BAYCOM driver for the Baycom serial 1200 baud modem
  * and the parallel 9600 baud modem
- * (C) 1997 by Thomas Sailer, HB9JNX/AE4WA
+ * (C) 1997-1998 by Thomas Sailer, HB9JNX/AE4WA
  */
 
 #ifndef _BAYCOM_H
 #define _BAYCOM_H
 
-#include <linux/sockios.h>
-#include <linux/if_ether.h>
-
 /* -------------------------------------------------------------------- */
 /*
  * structs for the IOCTL commands
index f41342b538fbd747590a0ead94f6a6f74a0366b5..8947f97df57d596bcf5f5594fb4142a9e9a271f9 100644 (file)
@@ -352,6 +352,7 @@ struct cdrom_blk
 #define CDS_DATA_2             102
 #define CDS_XA_2_1             103
 #define CDS_XA_2_2             104
+#define CDS_MIXED              105
 
 /* User-configurable behavior options for the uniform CD-ROM driver */
 #define CDO_AUTO_CLOSE         0x1     /* close tray on first open() */
index 535cdefdc5315fa3b477819c7797f80a024cda7f..8075af6a558a394e55a0c402393930236f028a95 100644 (file)
 #define CONFIG_SUN_PARTITION 1
 #endif
 
-/* These two have identical behaviour; use the second one if DOS fdisk gets
+/* These three have identical behaviour; use the second one if DOS fdisk gets
    confused about extended/logical partitions starting past cylinder 1023. */
 #define DOS_EXTENDED_PARTITION 5
 #define LINUX_EXTENDED_PARTITION 0x85
+#define WIN98_EXTENDED_PARTITION 0x0f
 
 #define DM6_PARTITION          0x54    /* has DDO: use xlated geom & offset */
 #define EZD_PARTITION          0x55    /* EZ-DRIVE:  same as DM6 (we think) */
index b321d292c8c64f86d2585f45e4d96ec76b98c1a1..d7d4609cb4ed2bc79778c72025f14eccb62ea10d 100644 (file)
@@ -1,20 +1,12 @@
 /*
  * hdlcdrv.h  -- HDLC packet radio network driver.
  * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
- * (C) 1996 by Thomas Sailer, HB9JNX/AE4WA
+ * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
  */
 
 #ifndef _HDLCDRV_H
 #define _HDLCDRV_H
 
-#include <linux/version.h>
-#include <linux/sockios.h>
-#include <linux/version.h>
-#if LINUX_VERSION_CODE < 0x20119
-#include <linux/if_ether.h>
-#endif
-#include <linux/netdevice.h>
-
 /* -------------------------------------------------------------------- */
 /*
  * structs for the IOCTL commands
@@ -43,9 +35,6 @@ struct hdlcdrv_old_channel_state {
        int ptt;
        int dcd;
        int ptt_keyed;
-#if LINUX_VERSION_CODE < 0x20100
-       struct enet_statistics stats;
-#endif
 };
 
 struct hdlcdrv_channel_state {
@@ -115,6 +104,9 @@ struct hdlcdrv_ioctl {
 
 #ifdef __KERNEL__
 
+#include <linux/netdevice.h>
+#include <linux/if.h>
+
 #define HDLCDRV_MAGIC      0x5ac6e778
 #define HDLCDRV_IFNAMELEN    6
 #define HDLCDRV_HDLCBUFFER  32 /* should be a power of 2 for speed reasons */
index bd98fb029be177954e627de2ac76c776d5b9d038..902fb0bc941e24773d9eadb73e9b938c5b9ef827 100644 (file)
@@ -132,6 +132,7 @@ struct ifreq
 #define        ifr_data        ifr_ifru.ifru_data      /* for use by interface */
 #define ifr_ifindex    ifr_ifru.ifru_ivalue    /* interface index      */
 #define ifr_bandwidth  ifr_ifru.ifru_ivalue    /* link bandwidth       */
+#define ifr_qlen       ifr_ifru.ifru_ivalue    /* Queue length         */
 
 /*
  * Structure used in SIOCGIFCONF request.
index fc0b09e0caec0441bc6b1571da5ec6dc7fe64e35..eeaf1b14ee61c00d41b39730a11a513ac688adc6 100644 (file)
@@ -52,7 +52,8 @@ enum root_directory_inos {
        PROC_SLABINFO,
        PROC_PARPORT,
        PROC_OMIRR, /* whether enabled or not */
-       PROC_PPC_HTAB
+       PROC_PPC_HTAB,
+       PROC_SOUND
 };
 
 enum pid_directory_inos {
index 1bbc7c006abaae66833a2c907819670fd58f3b7d..07b506f19fcd20cc4b9fd4c3ab6e60d6717ccec3 100644 (file)
@@ -182,6 +182,10 @@ struct task_struct {
        long counter;
        long priority;
        unsigned long flags;    /* per process flags, defined below */
+       mm_segment_t addr_limit;        /* thread address space:
+                                               0-0xBFFFFFFF for user-thead
+                                               0-0xFFFFFFFF for kernel-thread
+                                        */
        int sigpending;
        long debugreg[8];  /* Hardware debugging registers */
        struct exec_domain *exec_domain;
@@ -307,7 +311,7 @@ struct task_struct {
  * your own risk!. Base=0, limit=0x1fffff (=2MB)
  */
 #define INIT_TASK \
-/* state etc */        { 0,DEF_PRIORITY,DEF_PRIORITY,0,0, \
+/* state etc */        { 0,DEF_PRIORITY,DEF_PRIORITY,0,KERNEL_DS,0, \
 /* debugregs */ { 0, },            \
 /* exec domain */&default_exec_domain, \
 /* binfmt */   NULL, \
index 5465bc6b840cd87b80df8adabd6cb7ba41216c6a..4f41001aab5d11696086a46eb1259374f6e86685 100644 (file)
@@ -45,8 +45,8 @@
 #define SIOCSIFMEM     0x8920          /* set memory address (BSD)     */
 #define SIOCGIFMTU     0x8921          /* get MTU size                 */
 #define SIOCSIFMTU     0x8922          /* set MTU size                 */
-#define        SIOCSIFHWADDR   0x8924          /* set hardware address (NI)    */
-#define SIOCGIFENCAP   0x8925          /* get/set slip encapsulation   */
+#define        SIOCSIFHWADDR   0x8924          /* set hardware address         */
+#define SIOCGIFENCAP   0x8925          /* get/set encapsulations       */
 #define SIOCSIFENCAP   0x8926          
 #define SIOCGIFHWADDR  0x8927          /* Get hardware address         */
 #define SIOCGIFSLAVE   0x8929          /* Driver slaving support       */
 #define SIOCGIFBR      0x8940          /* Bridging support             */
 #define SIOCSIFBR      0x8941          /* Set bridging options         */
 
+#define SIOCGIFTXQLEN  0x8942          /* Get the tx queue length      */
+#define SIOCSIFTXQLEN  0x8943          /* Set the tx queue length      */
+
+
 /* ARP cache control calls. */
                    /*  0x8950 - 0x8952  * obsolete calls, don't re-use */
 #define SIOCDARP       0x8953          /* delete ARP table entry       */
index 43ad5e3a2969231e2c1b69fb8cce944f7ed3f7f8..10d0799d6e1ca48a4fc797d1acb68d7abd94dcac 100644 (file)
@@ -1,14 +1,11 @@
 /*
  * The Linux soundcard driver for 1200 baud and 9600 baud packet radio
- * (C) 1996 by Thomas Sailer, HB9JNX/AE4WA
+ * (C) 1996-1998 by Thomas Sailer, HB9JNX/AE4WA
  */
 
 #ifndef _SOUNDMODEM_H
 #define _SOUNDMODEM_H
 
-#include <linux/sockios.h>
-#include <linux/if_ether.h>
-
 /* -------------------------------------------------------------------- */
 /*
  * structs for the IOCTL commands
index e46500a9566dc1fd820f40f982180b1c245c2f19..38bdce509c5e2bf4ae5fdd4755289f8207233738 100644 (file)
@@ -892,7 +892,7 @@ extern __inline__ int sock_queue_rcv_skb(struct sock *sk, struct sk_buff *skb)
        if (sk->filter)
        {
                if (sk_filter(skb, sk->filter_data, sk->filter))
-                       return -1;      /* Toss packet */
+                       return -EPERM;  /* Toss packet */
        }
 #endif /* CONFIG_FILTER */
 
index a8e77e3ca35b24e37a330f6a9309434b3ccd1522..ddb07be522343b837284fdce5d6fe14955742231 100644 (file)
@@ -109,8 +109,14 @@ extern void xd_setup(char *str, int *ints);
 #ifdef CONFIG_BLK_DEV_IDE
 extern void ide_setup(char *);
 #endif
-#ifdef CONFIG_BLK_DEV_EZ
-extern void ez_setup(char *str, int *ints);
+#ifdef CONFIG_PARIDE_PD
+extern void pd_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_PARIDE_PF
+extern void pf_setup(char *str, int *ints);
+#endif
+#ifdef CONFIG_PARIDE_PCD
+extern void pcd_setup(char *str, int *ints);
 #endif
 extern void floppy_setup(char *str, int *ints);
 extern void st_setup(char *str, int *ints);
@@ -165,9 +171,6 @@ extern void sonycd535_setup(char *str, int *ints);
 #ifdef CONFIG_GSCD
 extern void gscd_setup(char *str, int *ints);
 #endif CONFIG_GSCD
-#ifdef CONFIG_BPCD
-extern void bpcd_setup(char *str, int *ints);
-#endif CONFIG_BPCD
 #ifdef CONFIG_CM206
 extern void cm206_setup(char *str, int *ints);
 #endif CONFIG_CM206
@@ -399,10 +402,6 @@ static struct dev_name_struct {
 #endif
 #ifdef CONFIG_BLK_DEV_PS2
        { "eda",     0x2400 },
-       { "eza",     0x2800 },
-#endif
-#ifdef CONFIG_BPCD
-       { "bpcd",    0x2900 },
 #endif
 #if CONFIG_APBLOCK
        { "apblock", APBLOCK_MAJOR << 8},
@@ -585,9 +584,6 @@ static struct kernel_param cooked_params[] __initdata = {
 #ifdef CONFIG_BLK_DEV_XD
        { "xd=", xd_setup },
 #endif
-#ifdef CONFIG_BLK_DEV_EZ
-       { "ez=", ez_setup },
-#endif
 #if defined(CONFIG_BLK_DEV_FD) || defined(CONFIG_AMIGA_FLOPPY) || defined(CONFIG_ATARI_FLOPPY)
        { "floppy=", floppy_setup },
 #endif
@@ -616,9 +612,6 @@ static struct kernel_param cooked_params[] __initdata = {
 #ifdef CONFIG_GSCD
        { "gscd=", gscd_setup },
 #endif CONFIG_GSCD
-#ifdef CONFIG_BPCD
-       { "bpcd=", bpcd_setup },
-#endif CONFIG_BPCD
 #ifdef CONFIG_CM206
        { "cm206=", cm206_setup },
 #endif CONFIG_CM206
@@ -723,6 +716,15 @@ static struct kernel_param raw_params[] __initdata = {
 #endif
 #ifdef CONFIG_IP_PNP
        { "ip=", ip_auto_config_setup },
+#endif
+#ifdef CONFIG_PARIDE_PD
+       { "pd.", pd_setup },
+#endif
+#ifdef CONFIG_PARIDE_PCD
+       { "pcd.", pcd_setup },
+#endif
+#ifdef CONFIG_PARIDE_PF
+       { "pf.", pf_setup },
 #endif
        { 0, 0 }
 };
index cfaea21165cb67039985797a846bb9f06a86b5c5..c83dec9b77f5c7a24b7eb5e319806517c31a1196 100644 (file)
@@ -104,6 +104,8 @@ struct task_struct * task[NR_TASKS] = {&init_task, };
 
 struct kernel_stat kstat = { 0 };
 
+void scheduling_functions_start_here(void) { }
+
 static inline void add_to_runqueue(struct task_struct * p)
 {
        if (p->policy != SCHED_OTHER || p->counter > current->counter + 3)
@@ -678,6 +680,8 @@ void sleep_on(struct wait_queue **p)
        __sleep_on(p,TASK_UNINTERRUPTIBLE);
 }
 
+void scheduling_functions_end_here(void) { }
+
 static inline void cascade_timers(struct timer_vec *tv)
 {
         /* cascade all the timers from tv up one level */
index 69a72de9d8bf337b1e6d859ba01e04a863ce9169..4ccd4264569eded31309b889dfa4a3b083143f14 100644 (file)
@@ -161,11 +161,13 @@ void free_pages(unsigned long addr, unsigned long order)
        change_bit((index) >> (1+(order)), (area)->map)
 #define CAN_DMA(x) (PageDMA(x))
 #define ADDRESS(x) (PAGE_OFFSET + ((x) << PAGE_SHIFT))
-#define RMQUEUE(order, dma) \
+#define RMQUEUE(order, maxorder, dma) \
 do { struct free_area_struct * area = free_area+order; \
      unsigned long new_order = order; \
-       do { struct page *prev = memory_head(area), *ret; \
-               while (memory_head(area) != (ret = prev->next)) { \
+       do { struct page *prev = memory_head(area), *ret = prev->next; \
+               while (memory_head(area) != ret) { \
+                       if (new_order >= maxorder && ret->next == prev) \
+                               break; \
                        if (!dma || CAN_DMA(ret)) { \
                                unsigned long map_nr = ret->map_nr; \
                                (prev->next = ret->next)->prev = prev; \
@@ -176,6 +178,7 @@ do { struct free_area_struct * area = free_area+order; \
                                return ADDRESS(map_nr); \
                        } \
                        prev = ret; \
+                       ret = ret->next; \
                } \
                new_order++; area++; \
        } while (new_order < NR_MEM_LISTS); \
@@ -196,11 +199,23 @@ do { unsigned long size = 1 << high; \
 
 unsigned long __get_free_pages(int priority, unsigned long order, int dma)
 {
-       unsigned long flags;
-       int reserved_pages;
+       unsigned long flags, maxorder;
 
        if (order >= NR_MEM_LISTS)
-               return 0;
+               goto nopage;
+
+       /*
+        * "maxorder" is the highest order number that we're allowed
+        * to empty in order to find a free page..
+        */
+       maxorder = order + NR_MEM_LISTS/3;
+       switch (priority) {
+       case GFP_ATOMIC:
+               maxorder = NR_MEM_LISTS;
+               /* fallthrough - no need to jump around */
+       case GFP_NFS:
+               maxorder += NR_MEM_LISTS/3;
+       }
 
        if (in_interrupt() && priority != GFP_ATOMIC) {
                static int count = 0;
@@ -211,19 +226,13 @@ unsigned long __get_free_pages(int priority, unsigned long order, int dma)
                }
        }
 
-       reserved_pages = 5;
-       if (priority != GFP_NFS)
-               reserved_pages = min_free_pages;
 repeat:
        spin_lock_irqsave(&page_alloc_lock, flags);
-       if ((priority==GFP_ATOMIC) || nr_free_pages > reserved_pages) {
-               RMQUEUE(order, dma);
-               spin_unlock_irqrestore(&page_alloc_lock, flags);
-               return 0;
-       }
+       RMQUEUE(order, maxorder, dma);
        spin_unlock_irqrestore(&page_alloc_lock, flags);
-       if (priority != GFP_BUFFER && try_to_free_page(priority, dma, 1))
+       if (priority != GFP_BUFFER && priority != GFP_ATOMIC && try_to_free_page(priority, dma, 1))
                goto repeat;
+nopage:
        return 0;
 }
 
index 61d9e7edf55961ab52e9c60b5abd82872dd5308d..551d266b6f8c22835136b273fc999f4bec95dc66 100644 (file)
@@ -1305,6 +1305,16 @@ static int dev_ifsioc(struct ifreq *ifr, unsigned int cmd)
                        ifr->ifr_ifindex = dev->ifindex;
                        return 0;
 
+               case SIOCGIFTXQLEN:
+                       ifr->ifr_qlen = dev->tx_queue_len;
+                       return 0;
+
+               case SIOCSIFTXQLEN:
+                       if(ifr->ifr_qlen<2 || ifr->ifr_qlen>1024)
+                               return -EINVAL;
+                       dev->tx_queue_len = ifr->ifr_qlen;
+                       return 0;
+
                /*
                 *      Unknown or private ioctl
                 */
@@ -1396,9 +1406,17 @@ int dev_ioctl(unsigned int cmd, void *arg)
                case SIOCGIFSLAVE:
                case SIOCGIFMAP:
                case SIOCGIFINDEX:
+               case SIOCGIFTXQLEN:
                        ret = dev_ifsioc(&ifr, cmd);
-                       if (!ret && copy_to_user(arg, &ifr, sizeof(struct ifreq)))
-                               return -EFAULT;
+                       if (!ret)
+                       {
+#ifdef CONFIG_NET_ALIAS
+                               if (colon)
+                                       *colon = ':';
+#endif
+                               if (copy_to_user(arg, &ifr, sizeof(struct ifreq)))
+                                       return -EFAULT;
+                       }
                        return ret;
 
                /*
@@ -1414,6 +1432,7 @@ int dev_ioctl(unsigned int cmd, void *arg)
                case SIOCSIFMAP:
                case SIOCSIFHWADDR:
                case SIOCSIFSLAVE:
+               case SIOCSIFTXQLEN:
                case SIOCADDMULTI:
                case SIOCDELMULTI:
                case SIOCSIFHWBROADCAST:
index 6b32abb89c69f3b1593bfffae2e7a6af5d000f51..cafbc61f2c8ba19328fef35d4157e6f72b308e61 100644 (file)
@@ -5,7 +5,7 @@
  *     Jay Schulist <Jay.Schulist@spacs.k12.wi.us>
  *
  * Based on the design of:
- *     - The Berkely Packet Filter
+ *     - The Berkeley Packet Filter
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
index 2f057ab4afb9032f4dcfb065927beda4b3898786..6704aff8ccd10d7a90f28cb922f7fc2a1e30a92f 100644 (file)
@@ -5,6 +5,7 @@ bool 'IP: multicasting' CONFIG_IP_MULTICAST
 bool 'IP: advanced router' CONFIG_IP_ADVANCED_ROUTER
 if [ "$CONFIG_IP_ADVANCED_ROUTER" = "y" ]; then
   define_bool CONFIG_RTNETLINK y       
+  define_bool CONFIG_NETLINK y
   bool 'IP: policy routing' CONFIG_IP_MULTIPLE_TABLES
   bool 'IP: equal cost multipath' CONFIG_IP_ROUTE_MULTIPATH
   bool 'IP: use TOS value as routing key' CONFIG_IP_ROUTE_TOS
index 8c75bce3e2438f7bba7de2ce05e86c6708db0b70..a6c465e59c86f77186b5ee85ff21264156638e55 100644 (file)
@@ -1467,6 +1467,14 @@ static inline struct sock *tcp_v4_hnd_req(struct sock *sk,struct sk_buff *skb)
 
 int tcp_v4_do_rcv(struct sock *sk, struct sk_buff *skb)
 {
+#ifdef CONFIG_FILTER
+       if (sk->filter)
+       {
+               if (sk_filter(skb, sk->filter_data, sk->filter))
+                       return -EPERM;  /* Toss packet */
+       }
+#endif /* CONFIG_FILTER */
+
        skb_set_owner_r(skb, sk);
 
        /*
index 206f5945b2e474359e5bcb6224951923f7bce0c9..586be364503b704c552b691f409ebfe1aa609aa4 100644 (file)
@@ -32,6 +32,9 @@
 # handling
 #
 # 101297 Michael Chastain (mec@shout.net) - remove sound driver cruft.
+#
+# 221297 Michael Chastain (mec@shout.net) - make define_bool actually
+# define its arguments so that later tests on them work right.
 #----------------------------------------------------------------------------
 
 
@@ -100,10 +103,10 @@ function comment () {
 }
 
 #
-# Don't need this yet, but we don't want to puke either.
+# Define a boolean to a specific value.
 #
 function define_bool () {
-       :       
+       eval $1=$2
 }
 
 #
@@ -432,7 +435,7 @@ function l_int () {
 
                        # Semantics of + and ? in GNU expr changed, so
                        # we avoid them:
-                       if expr "$answer" : '0$\|\(-[1-9]\|[0-9]\)[0-9]*$' >/dev/null
+                       if expr "$answer" : '0$\|-[1-9][0-9]*$\|[1-9][0-9]*$' >/dev/null
                        then
                                eval $2="$answer"
                        else
@@ -1178,7 +1181,7 @@ followed by the <SPACE BAR>.
 Press <?> for additional information about this option."
 
 inputbox_instructions_int="\
-Please enter a decimal value between 1 and 9999. \
+Please enter a decimal value. \
 Fractions will not be accepted.  \
 Use the <TAB> key to move from the input field to the buttons below it."
 
index 94d75ded617d0cb94fa3dabb28d4273d79b9f445..33f99fb09565656ebbe1808c0b3f08c53cacc77c 100644 (file)
@@ -158,7 +158,7 @@ Usage (const char *name)
 \n  --textbox   <file> <height> <width>\
 \n  --inputbox  <text> <height> <width> [<init>]\
 \n  --yesno     <text> <height> <width>\
-", name, name);
+\n", name, name);
     exit (-1);
 }